[Port] Explosions Subsystem Test 1 (#10202)

* Explosions Subsystem Test 1

* Fucking linter

* Fucking TG Are Dents

* SCREW OFF LINTER
This commit is contained in:
Jamie D
2020-10-28 17:54:13 +00:00
committed by GitHub
parent ea8d16d34d
commit 0dd6fae119
85 changed files with 968 additions and 631 deletions

View File

@@ -1,11 +1,16 @@
/// Percentage of tick to leave for master controller to run
#define MAPTICK_MC_MIN_RESERVE 70
/// internal_tick_usage is updated every tick by extools
#define MAPTICK_LAST_INTERNAL_TICK_USAGE ((GLOB.internal_tick_usage / world.tick_lag) * 100)
/// Tick limit while running normally /// Tick limit while running normally
#define TICK_LIMIT_RUNNING 80 #define TICK_BYOND_RESERVE 2
#define TICK_LIMIT_RUNNING (max(100 - TICK_BYOND_RESERVE - MAPTICK_LAST_INTERNAL_TICK_USAGE, MAPTICK_MC_MIN_RESERVE))
/// Tick limit used to resume things in stoplag /// Tick limit used to resume things in stoplag
#define TICK_LIMIT_TO_RUN 70 #define TICK_LIMIT_TO_RUN 70
/// Tick limit for MC while running /// Tick limit for MC while running
#define TICK_LIMIT_MC 70 #define TICK_LIMIT_MC 70
/// Tick limit while initializing /// Tick limit while initializing
#define TICK_LIMIT_MC_INIT_DEFAULT 98 #define TICK_LIMIT_MC_INIT_DEFAULT (100 - TICK_BYOND_RESERVE)
/// for general usage of tick_usage /// for general usage of tick_usage
#define TICK_USAGE world.tick_usage #define TICK_USAGE world.tick_usage

View File

@@ -38,7 +38,8 @@
#define COMSIG_GLOB_MOB_DEATH "!mob_death" #define COMSIG_GLOB_MOB_DEATH "!mob_death"
/// global living say plug - use sparingly: (mob/speaker , message) /// global living say plug - use sparingly: (mob/speaker , message)
#define COMSIG_GLOB_LIVING_SAY_SPECIAL "!say_special" #define COMSIG_GLOB_LIVING_SAY_SPECIAL "!say_special"
/// called after an explosion happened : (epicenter, devastation_range, heavy_impact_range, light_impact_range, took, orig_dev_range, orig_heavy_range, orig_light_range)
#define COMSIG_GLOB_EXPLOSION "!explosion"
// signals from globally accessible objects // signals from globally accessible objects
/// from SSsun when the sun changes position : (azimuth) /// from SSsun when the sun changes position : (azimuth)
#define COMSIG_SUN_MOVED "sun_moved" #define COMSIG_SUN_MOVED "sun_moved"

View File

@@ -43,6 +43,8 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
#define INITIALIZED_1 (1<<14) #define INITIALIZED_1 (1<<14)
/// was this spawned by an admin? used for stat tracking stuff. /// was this spawned by an admin? used for stat tracking stuff.
#define ADMIN_SPAWNED_1 (1<<15) #define ADMIN_SPAWNED_1 (1<<15)
/// should not get harmed if this gets caught by an explosion?
#define PREVENT_CONTENTS_EXPLOSION_1 (1<<16)
//turf-only flags //turf-only flags
#define NOJAUNT_1 (1<<0) #define NOJAUNT_1 (1<<0)

View File

@@ -135,6 +135,7 @@
#define INIT_ORDER_MINOR_MAPPING -40 #define INIT_ORDER_MINOR_MAPPING -40
#define INIT_ORDER_PATH -50 #define INIT_ORDER_PATH -50
#define INIT_ORDER_DISCORD -60 #define INIT_ORDER_DISCORD -60
#define INIT_ORDER_EXPLOSIONS -69
#define INIT_ORDER_PERSISTENCE -95 #define INIT_ORDER_PERSISTENCE -95
#define INIT_ORDER_DEMO -99 // To avoid a bunch of changes related to initialization being written, do this last #define INIT_ORDER_DEMO -99 // To avoid a bunch of changes related to initialization being written, do this last
#define INIT_ORDER_CHAT -100 //Should be last to ensure chat remains smooth during init. #define INIT_ORDER_CHAT -100 //Should be last to ensure chat remains smooth during init.
@@ -169,6 +170,7 @@
#define FIRE_PRIORITY_ATMOS_ADJACENCY 300 #define FIRE_PRIORITY_ATMOS_ADJACENCY 300
#define FIRE_PRIORITY_CHAT 400 #define FIRE_PRIORITY_CHAT 400
#define FIRE_PRIORITY_OVERLAYS 500 #define FIRE_PRIORITY_OVERLAYS 500
#define FIRE_PRIORITY_EXPLOSIONS 666
#define FIRE_PRIORITY_INPUT 1000 // This must always always be the max highest priority. Player input must never be lost. #define FIRE_PRIORITY_INPUT 1000 // This must always always be the max highest priority. Player input must never be lost.
// SS runlevels // SS runlevels
@@ -212,3 +214,21 @@
if(isturf(A)){SSdemo.mark_turf(A);}\ if(isturf(A)){SSdemo.mark_turf(A);}\
if(isobj(A) || ismob(A)){SSdemo.mark_dirty(A);}\ if(isobj(A) || ismob(A)){SSdemo.mark_dirty(A);}\
} }
// Air subsystem subtasks
#define SSAIR_PIPENETS 1
#define SSAIR_ATMOSMACHINERY 2
#define SSAIR_EQUALIZE 3
#define SSAIR_ACTIVETURFS 4
#define SSAIR_EXCITEDGROUPS 5
#define SSAIR_HIGHPRESSURE 6
#define SSAIR_HOTSPOTS 7
#define SSAIR_SUPERCONDUCTIVITY 8
#define SSAIR_REBUILD_PIPENETS 9
// Explosion Subsystem subtasks
#define SSEXPLOSIONS_MOVABLES 1
#define SSEXPLOSIONS_TURFS 2
#define SSEXPLOSIONS_THROWS 3

View File

@@ -18,3 +18,5 @@ GLOBAL_LIST_EMPTY(powernets)
GLOBAL_VAR_INIT(bsa_unlock, FALSE) //BSA unlocked by head ID swipes GLOBAL_VAR_INIT(bsa_unlock, FALSE) //BSA unlocked by head ID swipes
GLOBAL_LIST_EMPTY(player_details) // ckey -> /datum/player_details GLOBAL_LIST_EMPTY(player_details) // ckey -> /datum/player_details
GLOBAL_VAR_INIT(internal_tick_usage, 0.2 * world.tick_lag)

View File

@@ -36,6 +36,9 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
var/sleep_delta = 1 var/sleep_delta = 1
///Only run ticker subsystems for the next n ticks.
var/skip_ticks = 0
var/make_runtime = 0 var/make_runtime = 0
var/initializations_finished_with_no_players_logged_in //I wonder what this could be? var/initializations_finished_with_no_players_logged_in //I wonder what this could be?
@@ -342,7 +345,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
new/datum/controller/failsafe() // (re)Start the failsafe. new/datum/controller/failsafe() // (re)Start the failsafe.
//now do the actual stuff //now do the actual stuff
if (!queue_head || !(iteration % 3)) if (!skip_ticks)
var/checking_runlevel = current_runlevel var/checking_runlevel = current_runlevel
if(cached_runlevel != checking_runlevel) if(cached_runlevel != checking_runlevel)
//resechedule subsystems //resechedule subsystems
@@ -388,6 +391,8 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
iteration++ iteration++
last_run = world.time last_run = world.time
if (skip_ticks)
skip_ticks--
src.sleep_delta = MC_AVERAGE_FAST(src.sleep_delta, sleep_delta) src.sleep_delta = MC_AVERAGE_FAST(src.sleep_delta, sleep_delta)
current_ticklimit = TICK_LIMIT_RUNNING current_ticklimit = TICK_LIMIT_RUNNING
if (processing * sleep_delta <= world.tick_lag) if (processing * sleep_delta <= world.tick_lag)
@@ -455,6 +460,10 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
queue_node_flags = queue_node.flags queue_node_flags = queue_node.flags
queue_node_priority = queue_node.queued_priority queue_node_priority = queue_node.queued_priority
if (!(queue_node_flags & SS_TICKER) && skip_ticks)
queue_node = queue_node.queue_next
continue
//super special case, subsystems where we can't make them pause mid way through //super special case, subsystems where we can't make them pause mid way through
//if we can't run them this tick (without going over a tick) //if we can't run them this tick (without going over a tick)
//we bump up their priority and attempt to run them next tick //we bump up their priority and attempt to run them next tick
@@ -590,14 +599,16 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
log_world("MC: SoftReset: Finished.") log_world("MC: SoftReset: Finished.")
. = 1 . = 1
/datum/controller/master/proc/laggy_byond_map_update_incoming()
if (!skip_ticks)
skip_ticks = 1
/datum/controller/master/stat_entry() /datum/controller/master/stat_entry()
if(!statclick) if(!statclick)
statclick = new/obj/effect/statclick/debug(null, "Initializing...", src) statclick = new/obj/effect/statclick/debug(null, "Initializing...", src)
stat("Byond:", "(FPS:[world.fps]) (TickCount:[world.time/world.tick_lag]) (TickDrift:[round(Master.tickdrift,1)]([round((Master.tickdrift/(world.time/world.tick_lag))*100,0.1)]%))") stat("Byond:", "(FPS:[world.fps]) (TickCount:[world.time/world.tick_lag]) (TickDrift:[round(Master.tickdrift,1)]([round((Master.tickdrift/(world.time/world.tick_lag))*100,0.1)]%)) (Internal Tick Usage: [round(MAPTICK_LAST_INTERNAL_TICK_USAGE,0.1)]%)")
stat("Master Controller:", statclick.update("(TickRate:[Master.processing]) (Iteration:[Master.iteration])")) stat("Master Controller:", statclick.update("(TickRate:[Master.processing]) (Iteration:[Master.iteration]) (TickLimit: [round(Master.current_ticklimit, 0.1)])"))
/datum/controller/master/StartLoadingMap() /datum/controller/master/StartLoadingMap()
//disallow more than one map to load at once, multithreading it will just cause race conditions //disallow more than one map to load at once, multithreading it will just cause race conditions

View File

@@ -1,12 +1,3 @@
#define SSAIR_PIPENETS 1
#define SSAIR_ATMOSMACHINERY 2
#define SSAIR_EQUALIZE 3
#define SSAIR_ACTIVETURFS 4
#define SSAIR_EXCITEDGROUPS 5
#define SSAIR_HIGHPRESSURE 6
#define SSAIR_HOTSPOTS 7
#define SSAIR_SUPERCONDUCTIVITY 8
SUBSYSTEM_DEF(air) SUBSYSTEM_DEF(air)
name = "Atmospherics" name = "Atmospherics"
init_order = INIT_ORDER_AIR init_order = INIT_ORDER_AIR
@@ -21,12 +12,14 @@ SUBSYSTEM_DEF(air)
var/cost_hotspots = 0 var/cost_hotspots = 0
var/cost_superconductivity = 0 var/cost_superconductivity = 0
var/cost_pipenets = 0 var/cost_pipenets = 0
var/cost_rebuilds = 0
var/cost_atmos_machinery = 0 var/cost_atmos_machinery = 0
var/cost_equalize = 0 var/cost_equalize = 0
var/list/active_turfs = list() var/list/active_turfs = list()
var/list/hotspots = list() var/list/hotspots = list()
var/list/networks = list() var/list/networks = list()
var/list/pipenets_needing_rebuilt = list()
var/list/obj/machinery/atmos_machinery = list() var/list/obj/machinery/atmos_machinery = list()
var/list/pipe_init_dirs_cache = list() var/list/pipe_init_dirs_cache = list()
@@ -39,7 +32,7 @@ SUBSYSTEM_DEF(air)
var/list/currentrun = list() var/list/currentrun = list()
var/currentpart = SSAIR_PIPENETS var/currentpart = SSAIR_REBUILD_PIPENETS
var/map_loading = TRUE var/map_loading = TRUE
var/list/queued_for_activation var/list/queued_for_activation
@@ -55,6 +48,7 @@ SUBSYSTEM_DEF(air)
msg += "HS:[round(cost_hotspots,1)]|" msg += "HS:[round(cost_hotspots,1)]|"
msg += "SC:[round(cost_superconductivity,1)]|" msg += "SC:[round(cost_superconductivity,1)]|"
msg += "PN:[round(cost_pipenets,1)]|" msg += "PN:[round(cost_pipenets,1)]|"
msg += "RB:[round(cost_rebuilds,1)]|"
msg += "AM:[round(cost_atmos_machinery,1)]" msg += "AM:[round(cost_atmos_machinery,1)]"
msg += "} " msg += "} "
msg += "AT:[active_turfs.len]|" msg += "AT:[active_turfs.len]|"
@@ -79,7 +73,17 @@ SUBSYSTEM_DEF(air)
/datum/controller/subsystem/air/fire(resumed = 0) /datum/controller/subsystem/air/fire(resumed = 0)
var/timer = TICK_USAGE_REAL var/timer = TICK_USAGE_REAL
if(currentpart == SSAIR_REBUILD_PIPENETS)
var/list/pipenet_rebuilds = pipenets_needing_rebuilt
for(var/thing in pipenet_rebuilds)
var/obj/machinery/atmospherics/AT = thing
AT.build_network()
cost_rebuilds = MC_AVERAGE(cost_rebuilds, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
pipenets_needing_rebuilt.Cut()
if(state != SS_RUNNING)
return
resumed = FALSE
currentpart = SSAIR_PIPENETS
if(currentpart == SSAIR_PIPENETS || !resumed) if(currentpart == SSAIR_PIPENETS || !resumed)
process_pipenets(resumed) process_pipenets(resumed)
cost_pipenets = MC_AVERAGE(cost_pipenets, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) cost_pipenets = MC_AVERAGE(cost_pipenets, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
@@ -149,7 +153,7 @@ SUBSYSTEM_DEF(air)
if(state != SS_RUNNING) if(state != SS_RUNNING)
return return
resumed = 0 resumed = 0
currentpart = SSAIR_PIPENETS currentpart = SSAIR_REBUILD_PIPENETS
@@ -168,6 +172,9 @@ SUBSYSTEM_DEF(air)
if(MC_TICK_CHECK) if(MC_TICK_CHECK)
return return
/datum/controller/subsystem/air/proc/add_to_rebuild_queue(atmos_machine)
if(istype(atmos_machine, /obj/machinery/atmospherics))
pipenets_needing_rebuilt += atmos_machine
/datum/controller/subsystem/air/proc/process_atmos_machinery(resumed = 0) /datum/controller/subsystem/air/proc/process_atmos_machinery(resumed = 0)
var/seconds = wait * 0.1 var/seconds = wait * 0.1
@@ -430,12 +437,4 @@ SUBSYSTEM_DEF(air)
pipe_init_dirs_cache[type]["[dir]"] = temp.GetInitDirections() pipe_init_dirs_cache[type]["[dir]"] = temp.GetInitDirections()
qdel(temp) qdel(temp)
return pipe_init_dirs_cache[type]["[dir]"] return pipe_init_dirs_cache[type]["[dir]"]
#undef SSAIR_PIPENETS
#undef SSAIR_ATMOSMACHINERY
#undef SSAIR_ACTIVETURFS
#undef SSAIR_EXCITEDGROUPS
#undef SSAIR_HIGHPRESSURE
#undef SSAIR_HOTSPOTS
#undef SSAIR_SUPERCONDUCTIVITY

View File

@@ -0,0 +1,564 @@
#define EXPLOSION_THROW_SPEED 4
GLOBAL_LIST_EMPTY(explosions)
SUBSYSTEM_DEF(explosions)
name = "Explosions"
init_order = INIT_ORDER_EXPLOSIONS
priority = FIRE_PRIORITY_EXPLOSIONS
wait = 1
flags = SS_TICKER|SS_NO_INIT
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
var/cost_lowturf = 0
var/cost_medturf = 0
var/cost_highturf = 0
var/cost_flameturf = 0
var/cost_throwturf = 0
var/cost_low_mov_atom = 0
var/cost_med_mov_atom = 0
var/cost_high_mov_atom = 0
var/list/lowturf = list()
var/list/medturf = list()
var/list/highturf = list()
var/list/flameturf = list()
var/list/throwturf = list()
var/list/low_mov_atom = list()
var/list/med_mov_atom = list()
var/list/high_mov_atom = list()
var/list/explosions = list()
var/currentpart = SSAIR_PIPENETS
/datum/controller/subsystem/explosions/stat_entry(msg)
msg += "C:{"
msg += "LT:[round(cost_lowturf,1)]|"
msg += "MT:[round(cost_medturf,1)]|"
msg += "HT:[round(cost_highturf,1)]|"
msg += "FT:[round(cost_flameturf,1)]||"
msg += "LO:[round(cost_low_mov_atom,1)]|"
msg += "MO:[round(cost_med_mov_atom,1)]|"
msg += "HO:[round(cost_high_mov_atom,1)]|"
msg += "TO:[round(cost_throwturf,1)]"
msg += "} "
msg += "AMT:{"
msg += "LT:[lowturf.len]|"
msg += "MT:[medturf.len]|"
msg += "HT:[highturf.len]|"
msg += "FT:[flameturf.len]||"
msg += "LO:[low_mov_atom.len]|"
msg += "MO:[med_mov_atom.len]|"
msg += "HO:[high_mov_atom.len]|"
msg += "TO:[throwturf.len]"
msg += "} "
return ..()
#define SSEX_TURF "turf"
#define SSEX_OBJ "obj"
/datum/controller/subsystem/explosions/proc/is_exploding()
return (lowturf.len || medturf.len || highturf.len || flameturf.len || throwturf.len || low_mov_atom.len || med_mov_atom.len || high_mov_atom.len)
/datum/controller/subsystem/explosions/proc/wipe_turf(turf/T)
lowturf -= T
medturf -= T
highturf -= T
flameturf -= T
throwturf -= T
/client/proc/check_bomb_impacts()
set name = "Check Bomb Impact"
set category = "Debug"
var/newmode = alert("Use reactionary explosions?","Check Bomb Impact", "Yes", "No")
var/turf/epicenter = get_turf(mob)
if(!epicenter)
return
var/dev = 0
var/heavy = 0
var/light = 0
var/list/choices = list("Small Bomb","Medium Bomb","Big Bomb","Custom Bomb")
var/choice = input("Bomb Size?") in choices
switch(choice)
if(null)
return 0
if("Small Bomb")
dev = 1
heavy = 2
light = 3
if("Medium Bomb")
dev = 2
heavy = 3
light = 4
if("Big Bomb")
dev = 3
heavy = 5
light = 7
if("Custom Bomb")
dev = input("Devastation range (Tiles):") as num
heavy = input("Heavy impact range (Tiles):") as num
light = input("Light impact range (Tiles):") as num
var/max_range = max(dev, heavy, light)
var/x0 = epicenter.x
var/y0 = epicenter.y
var/list/wipe_colours = list()
for(var/turf/T in spiral_range_turfs(max_range, epicenter))
wipe_colours += T
var/dist = cheap_hypotenuse(T.x, T.y, x0, y0)
if(newmode == "Yes")
var/turf/TT = T
while(TT != epicenter)
TT = get_step_towards(TT,epicenter)
if(TT.density)
dist += TT.explosion_block
for(var/obj/O in T)
var/the_block = O.explosion_block
dist += the_block == EXPLOSION_BLOCK_PROC ? O.GetExplosionBlock() : the_block
if(dist < dev)
T.color = "red"
T.maptext = "Dev"
else if (dist < heavy)
T.color = "yellow"
T.maptext = "Heavy"
else if (dist < light)
T.color = "blue"
T.maptext = "Light"
else
continue
addtimer(CALLBACK(GLOBAL_PROC, .proc/wipe_color_and_text, wipe_colours), 100)
/proc/wipe_color_and_text(list/atom/wiping)
for(var/i in wiping)
var/atom/A = i
A.color = null
A.maptext = ""
/proc/dyn_explosion(turf/epicenter, power, flash_range, adminlog = TRUE, ignorecap = TRUE, flame_range = 0, 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)
// Using default dyn_ex scale:
// 100 explosion power is a (5, 10, 20) explosion.
// 75 explosion power is a (4, 8, 17) explosion.
// 50 explosion power is a (3, 7, 14) explosion.
// 25 explosion power is a (2, 5, 10) explosion.
// 10 explosion power is a (1, 3, 6) explosion.
// 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)
. = 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)
epicenter = get_turf(epicenter)
if(!epicenter)
return
if(isnull(flame_range))
flame_range = light_impact_range
if(isnull(flash_range))
flash_range = devastation_range
// Archive the uncapped explosion for the doppler array
var/orig_dev_range = devastation_range
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)
//Zlevel specific bomb cap multiplier
var/cap_multiplier = SSmapping.level_trait(epicenter.z, ZTRAIT_BOMBCAP_MULTIPLIER)
if (isnull(cap_multiplier))
cap_multiplier = 1
if(!ignorecap)
devastation_range = min(GLOB.MAX_EX_DEVESTATION_RANGE * cap_multiplier, devastation_range)
heavy_impact_range = min(GLOB.MAX_EX_HEAVY_RANGE * cap_multiplier, heavy_impact_range)
light_impact_range = min(GLOB.MAX_EX_LIGHT_RANGE * cap_multiplier, light_impact_range)
flash_range = min(GLOB.MAX_EX_FLASH_RANGE * cap_multiplier, flash_range)
flame_range = min(GLOB.MAX_EX_FLAME_RANGE * cap_multiplier, flame_range)
var/max_range = max(devastation_range, heavy_impact_range, light_impact_range, flame_range)
var/started_at = REALTIMEOFDAY
if(adminlog)
message_admins("Explosion with size ([devastation_range], [heavy_impact_range], [light_impact_range], [flame_range]) in [ADMIN_VERBOSEJMP(epicenter)]")
log_game("Explosion with size ([devastation_range], [heavy_impact_range], [light_impact_range], [flame_range]) in [loc_name(epicenter)]")
var/x0 = epicenter.x
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)))
// 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!
// Calculate far explosion sound range. Only allow the sound effect for heavy/devastating explosions.
// 3/7/14 will calculate to 80 + 35
var/far_dist = 0
far_dist += heavy_impact_range * 15
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)
if(heavy_impact_range > 1)
var/datum/effect_system/explosion/E
if(smoke)
E = new /datum/effect_system/explosion/smoke
else
E = new
E.set_up(epicenter)
E.start()
//flash mobs
if(flash_range)
for(var/mob/living/L in viewers(flash_range, epicenter))
L.flash_act()
var/list/affected_turfs = GatherSpiralTurfs(max_range, epicenter)
var/reactionary = CONFIG_GET(flag/reactionary_explosions)
var/list/cached_exp_block
if(reactionary)
cached_exp_block = CaculateExplosionBlock(affected_turfs)
//lists are guaranteed to contain at least 1 turf at this point
for(var/TI in affected_turfs)
var/turf/T = TI
var/init_dist = cheap_hypotenuse(T.x, T.y, x0, y0)
var/dist = init_dist
if(reactionary)
var/turf/Trajectory = T
while(Trajectory != epicenter)
Trajectory = get_step_towards(Trajectory, epicenter)
dist += cached_exp_block[Trajectory]
var/flame_dist = dist < flame_range
var/throw_dist = dist
if(dist < devastation_range)
dist = EXPLODE_DEVASTATE
else if(dist < heavy_impact_range)
dist = EXPLODE_HEAVY
else if(dist < light_impact_range)
dist = EXPLODE_LIGHT
else
dist = EXPLODE_NONE
if(T == epicenter) // Ensures explosives detonating from bags trigger other explosives in that bag
var/list/items = list()
for(var/I in T)
var/atom/A = I
if (length(A.contents) && !(A.flags_1 & PREVENT_CONTENTS_EXPLOSION_1)) //The atom/contents_explosion() proc returns null if the contents ex_acting has been handled by the atom, and TRUE if it hasn't.
items += A.GetAllContents()
for(var/thing in items)
var/atom/movable/movable_thing = thing
if(QDELETED(movable_thing))
continue
switch(dist)
if(EXPLODE_DEVASTATE)
SSexplosions.high_mov_atom += movable_thing
if(EXPLODE_HEAVY)
SSexplosions.med_mov_atom += movable_thing
if(EXPLODE_LIGHT)
SSexplosions.low_mov_atom += movable_thing
switch(dist)
if(EXPLODE_DEVASTATE)
SSexplosions.highturf += T
if(EXPLODE_HEAVY)
SSexplosions.medturf += T
if(EXPLODE_LIGHT)
SSexplosions.lowturf += T
if(flame_dist && prob(40) && !isspaceturf(T) && !T.density)
flameturf += T
//--- THROW ITEMS AROUND ---
var/throw_dir = get_dir(epicenter,T)
var/throw_range = max_range-throw_dist
var/list/throwingturf = T.explosion_throw_details
if (throwingturf)
if (throwingturf[1] < throw_range)
throwingturf[1] = throw_range
throwingturf[2] = throw_dir
throwingturf[3] = max_range
else
T.explosion_throw_details = list(throw_range, throw_dir, max_range)
throwturf += T
var/took = (REALTIMEOFDAY - started_at) / 10
//You need to press the DebugGame verb to see these now....they were getting annoying and we've collected a fair bit of data. Just -test- changes to explosion code using this please so we can compare
if(GLOB.Debug2)
log_world("## DEBUG: Explosion([x0],[y0],[z0])(d[devastation_range],h[heavy_impact_range],l[light_impact_range]): Took [took] seconds.")
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)
#undef CREAK_DELAY
#undef DEVASTATION_PROB
#undef HEAVY_IMPACT_PROB
#undef FAR_UPPER
#undef FAR_LOWER
#undef PROB_SOUND
#undef SHAKE_CLAMP
#undef FREQ_UPPER
#undef FREQ_LOWER
/datum/controller/subsystem/explosions/proc/GatherSpiralTurfs(range, turf/epicenter)
var/list/outlist = list()
var/center = epicenter
var/dist = range
if(!dist)
outlist += center
return outlist
var/turf/t_center = get_turf(center)
if(!t_center)
return outlist
var/list/L = outlist
var/turf/T
var/y
var/x
var/c_dist = 1
L += t_center
while( c_dist <= dist )
y = t_center.y + c_dist
x = t_center.x - c_dist + 1
for(x in x to t_center.x+c_dist)
T = locate(x,y,t_center.z)
if(T)
L += T
y = t_center.y + c_dist - 1
x = t_center.x + c_dist
for(y in t_center.y-c_dist to y)
T = locate(x,y,t_center.z)
if(T)
L += T
y = t_center.y - c_dist
x = t_center.x + c_dist - 1
for(x in t_center.x-c_dist to x)
T = locate(x,y,t_center.z)
if(T)
L += T
y = t_center.y - c_dist + 1
x = t_center.x - c_dist
for(y in y to t_center.y+c_dist)
T = locate(x,y,t_center.z)
if(T)
L += T
c_dist++
. = L
/datum/controller/subsystem/explosions/proc/CaculateExplosionBlock(list/affected_turfs)
. = list()
var/I
for(I in 1 to affected_turfs.len) // we cache the explosion block rating of every turf in the explosion area
var/turf/T = affected_turfs[I]
var/current_exp_block = T.density ? T.explosion_block : 0
for(var/obj/O in T)
var/the_block = O.explosion_block
current_exp_block += the_block == EXPLOSION_BLOCK_PROC ? O.GetExplosionBlock() : the_block
.[T] = current_exp_block
/datum/controller/subsystem/explosions/fire(resumed = 0)
if (!is_exploding())
return
var/timer
Master.current_ticklimit = TICK_LIMIT_RUNNING //force using the entire tick if we need it.
if(currentpart == SSEXPLOSIONS_TURFS)
currentpart = SSEXPLOSIONS_MOVABLES
timer = TICK_USAGE_REAL
var/list/low_turf = lowturf
lowturf = list()
for(var/thing in low_turf)
var/turf/turf_thing = thing
turf_thing.explosion_level = max(turf_thing.explosion_level, EXPLODE_LIGHT)
turf_thing.ex_act(EXPLODE_LIGHT)
cost_lowturf = MC_AVERAGE(cost_lowturf, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
timer = TICK_USAGE_REAL
var/list/med_turf = medturf
medturf = list()
for(var/thing in med_turf)
var/turf/turf_thing = thing
turf_thing.explosion_level = max(turf_thing.explosion_level, EXPLODE_HEAVY)
turf_thing.ex_act(EXPLODE_HEAVY)
cost_medturf = MC_AVERAGE(cost_medturf, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
timer = TICK_USAGE_REAL
var/list/high_turf = highturf
highturf = list()
for(var/thing in high_turf)
var/turf/turf_thing = thing
turf_thing.explosion_level = max(turf_thing.explosion_level, EXPLODE_DEVASTATE)
turf_thing.ex_act(EXPLODE_DEVASTATE)
cost_highturf = MC_AVERAGE(cost_highturf, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
timer = TICK_USAGE_REAL
var/list/flame_turf = flameturf
flameturf = list()
for(var/thing in flame_turf)
if(thing)
var/turf/T = thing
new /obj/effect/hotspot(T) //Mostly for ambience!
cost_flameturf = MC_AVERAGE(cost_flameturf, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
if (low_turf.len || med_turf.len || high_turf.len)
Master.laggy_byond_map_update_incoming()
if(currentpart == SSEXPLOSIONS_MOVABLES)
currentpart = SSEXPLOSIONS_THROWS
timer = TICK_USAGE_REAL
var/list/local_high_mov_atom = high_mov_atom
high_mov_atom = list()
for(var/thing in local_high_mov_atom)
var/atom/movable/movable_thing = thing
if(QDELETED(movable_thing))
continue
movable_thing.ex_act(EXPLODE_DEVASTATE)
cost_high_mov_atom = MC_AVERAGE(cost_high_mov_atom, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
timer = TICK_USAGE_REAL
var/list/local_med_mov_atom = med_mov_atom
med_mov_atom = list()
for(var/thing in local_med_mov_atom)
var/atom/movable/movable_thing = thing
if(QDELETED(movable_thing))
continue
movable_thing.ex_act(EXPLODE_HEAVY)
cost_med_mov_atom = MC_AVERAGE(cost_med_mov_atom, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
timer = TICK_USAGE_REAL
var/list/local_low_mov_atom = low_mov_atom
low_mov_atom = list()
for(var/thing in local_low_mov_atom)
var/atom/movable/movable_thing = thing
if(QDELETED(movable_thing))
continue
movable_thing.ex_act(EXPLODE_LIGHT)
cost_low_mov_atom = MC_AVERAGE(cost_low_mov_atom, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
if (currentpart == SSEXPLOSIONS_THROWS)
currentpart = SSEXPLOSIONS_TURFS
timer = TICK_USAGE_REAL
var/list/throw_turf = throwturf
throwturf = list()
for (var/thing in throw_turf)
if (!thing)
continue
var/turf/T = thing
var/list/L = T.explosion_throw_details
T.explosion_throw_details = null
if (length(L) != 3)
continue
var/throw_range = L[1]
var/throw_dir = L[2]
var/max_range = L[3]
for(var/atom/movable/A in T)
if(!A.anchored && A.move_resist != INFINITY)
var/atom_throw_range = rand(throw_range, max_range)
var/turf/throw_at = get_ranged_target_turf(A, throw_dir, atom_throw_range)
A.throw_at(throw_at, atom_throw_range, EXPLOSION_THROW_SPEED, quickstart = FALSE)
cost_throwturf = MC_AVERAGE(cost_throwturf, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
currentpart = SSEXPLOSIONS_TURFS

View File

@@ -341,10 +341,12 @@ SUBSYSTEM_DEF(ticker)
/datum/controller/subsystem/ticker/proc/station_explosion_detonation(atom/bomb) /datum/controller/subsystem/ticker/proc/station_explosion_detonation(atom/bomb)
if(bomb) //BOOM if(bomb) //BOOM
var/turf/epi = bomb.loc
qdel(bomb) qdel(bomb)
if(epi) for(var/T in GLOB.station_turfs)
explosion(epi, 0, 256, 512, 0, TRUE, TRUE, 0, TRUE) if(prob(33))
SSexplosions.highturf += T
else
SSexplosions.medturf += T
/datum/controller/subsystem/ticker/proc/create_characters() /datum/controller/subsystem/ticker/proc/create_characters()
for(var/mob/dead/new_player/player in GLOB.player_list) for(var/mob/dead/new_player/player in GLOB.player_list)

View File

@@ -1,419 +0,0 @@
#define EXPLOSION_THROW_SPEED 4
GLOBAL_LIST_EMPTY(explosions)
//Against my better judgement, I will return the explosion datum
//If I see any GC errors for it I will find you
//and I will gib you
/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)
return new /datum/explosion(epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog, ignorecap, flame_range, silent, smoke)
//This datum creates 3 async tasks
//1 GatherSpiralTurfsProc runs spiral_range_turfs(tick_checked = TRUE) to populate the affected_turfs list
//2 CaculateExplosionBlock adds the blockings to the cached_exp_block list
//3 The main thread explodes the prepared turfs
/datum/explosion
var/explosion_id
var/atom/explosion_source
var/started_at
var/running = TRUE
var/stopped = 0 //This is the number of threads stopped !DOESN'T COUNT THREAD 2!
var/static/id_counter = 0
#define EX_PREPROCESS_EXIT_CHECK \
if(!running) {\
stopped = 2;\
qdel(src);\
return;\
}
#define EX_PREPROCESS_CHECK_TICK \
if(TICK_CHECK) {\
stoplag();\
EX_PREPROCESS_EXIT_CHECK\
}
/datum/explosion/New(atom/epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog, ignorecap, flame_range, silent, smoke)
set waitfor = FALSE
var/id = ++id_counter
explosion_id = id
explosion_source = epicenter
epicenter = get_turf(epicenter)
if(!epicenter)
return
GLOB.explosions += src
if(isnull(flame_range))
flame_range = light_impact_range
if(isnull(flash_range))
flash_range = devastation_range
// Archive the uncapped explosion for the doppler array
var/orig_dev_range = devastation_range
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)
//Zlevel specific bomb cap multiplier
var/cap_multiplier = SSmapping.level_trait(epicenter.z, ZTRAIT_BOMBCAP_MULTIPLIER)
if (isnull(cap_multiplier))
cap_multiplier = 1
if(!ignorecap)
devastation_range = min(GLOB.MAX_EX_DEVESTATION_RANGE * cap_multiplier, devastation_range)
heavy_impact_range = min(GLOB.MAX_EX_HEAVY_RANGE * cap_multiplier, heavy_impact_range)
light_impact_range = min(GLOB.MAX_EX_LIGHT_RANGE * cap_multiplier, light_impact_range)
flash_range = min(GLOB.MAX_EX_FLASH_RANGE * cap_multiplier, flash_range)
flame_range = min(GLOB.MAX_EX_FLAME_RANGE * cap_multiplier, flame_range)
//DO NOT REMOVE THIS STOPLAG, IT BREAKS THINGS
//not sleeping causes us to ex_act() the thing that triggered the explosion
//doing that might cause it to trigger another explosion
//this is bad
//I would make this not ex_act the thing that triggered the explosion,
//but everything that explodes gives us their loc or a get_turf()
//and somethings expect us to ex_act them so they can qdel()
stoplag() //tldr, let the calling proc call qdel(src) before we explode
EX_PREPROCESS_EXIT_CHECK
started_at = REALTIMEOFDAY
var/max_range = max(devastation_range, heavy_impact_range, light_impact_range, flame_range)
if(adminlog)
if(SSticker.current_state != GAME_STATE_FINISHED) //don't bother alerting admins after the game has ended, but we still log it in the game log
message_admins("Explosion with size ([devastation_range], [heavy_impact_range], [light_impact_range], [flame_range]) in [ADMIN_VERBOSEJMP(epicenter)]")
log_game("Explosion with size ([devastation_range], [heavy_impact_range], [light_impact_range], [flame_range]) in [loc_name(epicenter)]")
var/x0 = epicenter.x
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)))
// 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!
// Calculate far explosion sound range. Only allow the sound effect for heavy/devastating explosions.
// 3/7/14 will calculate to 80 + 35
var/far_dist = 0
far_dist += heavy_impact_range * 5
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')
for(var/mob/M in GLOB.player_list)
// 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, falloff = 5, 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, 30, 50) // Volume is based on explosion size and dist
far_volume += (dist <= far_dist * 0.5 ? 50 : 0) // add 50 volume if the mob is pretty close to the explosion
M.playsound_local(epicenter, null, far_volume, 1, frequency, falloff = 5, S = far_explosion_sound)
if(baseshakeamount > 0)
shake_camera(M, 10, clamp(baseshakeamount*0.25, 0, 2.5))
EX_PREPROCESS_CHECK_TICK
//postpone processing for a bit
var/postponeCycles = max(round(devastation_range/8),1)
SSlighting.postpone(postponeCycles)
SSmachines.postpone(postponeCycles)
if(heavy_impact_range > 1)
var/datum/effect_system/explosion/E
if(smoke)
E = new /datum/effect_system/explosion/smoke
else
E = new
E.set_up(epicenter)
E.start()
EX_PREPROCESS_CHECK_TICK
//flash mobs
if(flash_range)
for(var/mob/living/L in viewers(flash_range, epicenter))
L.flash_act()
EX_PREPROCESS_CHECK_TICK
var/list/exploded_this_tick = list() //open turfs that need to be blocked off while we sleep
var/list/affected_turfs = GatherSpiralTurfs(max_range, epicenter)
var/reactionary = CONFIG_GET(flag/reactionary_explosions)
var/list/cached_exp_block = list()
if(reactionary)
cached_exp_block = CaculateExplosionBlock(affected_turfs)
//lists are guaranteed to contain at least 1 turf at this point
var/iteration = 0
var/affTurfLen = affected_turfs.len
var/expBlockLen = cached_exp_block.len
for(var/TI in affected_turfs)
var/turf/T = TI
++iteration
var/init_dist = cheap_hypotenuse(T.x, T.y, x0, y0)
var/dist = init_dist
if(reactionary)
var/turf/Trajectory = T
while(Trajectory != epicenter)
Trajectory = get_step_towards(Trajectory, epicenter)
dist += cached_exp_block[Trajectory]
var/flame_dist = dist < flame_range
var/throw_dist = dist
if(dist < devastation_range)
dist = EXPLODE_DEVASTATE
else if(dist < heavy_impact_range)
dist = EXPLODE_HEAVY
else if(dist < light_impact_range)
dist = EXPLODE_LIGHT
else
dist = EXPLODE_NONE
//------- EX_ACT AND TURF FIRES -------
if(T == epicenter) // Ensures explosives detonating from bags trigger other explosives in that bag
var/list/items = list()
for(var/I in T)
var/atom/A = I
if (!A.prevent_content_explosion()) //The atom/contents_explosion() proc returns null if the contents ex_acting has been handled by the atom, and TRUE if it hasn't.
items += A.GetAllContents()
for(var/O in items)
var/atom/A = O
if(!QDELETED(A))
A.ex_act(dist)
if(flame_dist && prob(40) && !isspaceturf(T) && !T.density)
new /obj/effect/hotspot(T) //Mostly for ambience!
if(dist > EXPLODE_NONE)
T.explosion_level = max(T.explosion_level, dist) //let the bigger one have it
T.explosion_id = id
T.ex_act(dist)
exploded_this_tick += T
//--- THROW ITEMS AROUND ---
var/throw_dir = get_dir(epicenter,T)
for(var/obj/item/I in T)
if(!I.anchored)
var/throw_range = rand(throw_dist, max_range)
var/turf/throw_at = get_ranged_target_turf(I, throw_dir, throw_range)
I.throw_at(throw_at, throw_range, EXPLOSION_THROW_SPEED)
//wait for the lists to repop
var/break_condition
if(reactionary)
//If we've caught up to the density checker thread and there are no more turfs to process
break_condition = iteration == expBlockLen && iteration < affTurfLen
else
//If we've caught up to the turf gathering thread and it's still running
break_condition = iteration == affTurfLen && !stopped
if(break_condition || TICK_CHECK)
stoplag()
if(!running)
break
//update the trackers
affTurfLen = affected_turfs.len
expBlockLen = cached_exp_block.len
if(break_condition)
if(reactionary)
//until there are more block checked turfs than what we are currently at
//or the explosion has stopped
UNTIL(iteration < affTurfLen || !running)
else
//until there are more gathered turfs than what we are currently at
//or there are no more turfs to gather/the explosion has stopped
UNTIL(iteration < expBlockLen || stopped)
if(!running)
break
//update the trackers
affTurfLen = affected_turfs.len
expBlockLen = cached_exp_block.len
var/circumference = (PI * (init_dist + 4) * 2) //+4 to radius to prevent shit gaps
if(exploded_this_tick.len > circumference) //only do this every revolution
for(var/Unexplode in exploded_this_tick)
var/turf/UnexplodeT = Unexplode
UnexplodeT.explosion_level = 0
exploded_this_tick.Cut()
//unfuck the shit
for(var/Unexplode in exploded_this_tick)
var/turf/UnexplodeT = Unexplode
UnexplodeT.explosion_level = 0
exploded_this_tick.Cut()
var/took = (REALTIMEOFDAY - started_at) / 10
//You need to press the DebugGame verb to see these now....they were getting annoying and we've collected a fair bit of data. Just -test- changes to explosion code using this please so we can compare
if(GLOB.Debug2)
log_world("## DEBUG: Explosion([x0],[y0],[z0])(d[devastation_range],h[heavy_impact_range],l[light_impact_range]): Took [took] seconds.")
if(running) //if we aren't in a hurry
//Machines which report explosions.
for(var/array in GLOB.doppler_arrays)
var/obj/machinery/doppler_array/A = array
A.sense_explosion(epicenter, devastation_range, heavy_impact_range, light_impact_range, took,orig_dev_range, orig_heavy_range, orig_light_range)
++stopped
qdel(src)
#undef EX_PREPROCESS_EXIT_CHECK
#undef EX_PREPROCESS_CHECK_TICK
//asyncly populate the affected_turfs list
/datum/explosion/proc/GatherSpiralTurfs(range, turf/epicenter)
set waitfor = FALSE
. = list()
spiral_range_turfs(range, epicenter, outlist = ., tick_checked = TRUE)
++stopped
/datum/explosion/proc/CaculateExplosionBlock(list/affected_turfs)
set waitfor = FALSE
. = list()
var/processed = 0
while(running)
var/I
for(I in (processed + 1) to affected_turfs.len) // we cache the explosion block rating of every turf in the explosion area
var/turf/T = affected_turfs[I]
var/current_exp_block = T.density ? T.explosion_block : 0
for(var/obj/O in T)
var/the_block = O.explosion_block
current_exp_block += the_block == EXPLOSION_BLOCK_PROC ? O.GetExplosionBlock() : the_block
.[T] = current_exp_block
if(TICK_CHECK)
break
processed = I
stoplag()
/datum/explosion/Destroy()
running = FALSE
if(stopped < 2) //wait for main thread and spiral_range thread
return QDEL_HINT_IWILLGC
GLOB.explosions -= src
explosion_source = null
return ..()
/client/proc/check_bomb_impacts()
set name = "Check Bomb Impact"
set category = "Debug"
var/newmode = alert("Use reactionary explosions?","Check Bomb Impact", "Yes", "No")
var/turf/epicenter = get_turf(mob)
if(!epicenter)
return
var/dev = 0
var/heavy = 0
var/light = 0
var/list/choices = list("Small Bomb","Medium Bomb","Big Bomb","Custom Bomb")
var/choice = input("Bomb Size?") in choices
switch(choice)
if(null)
return 0
if("Small Bomb")
dev = 1
heavy = 2
light = 3
if("Medium Bomb")
dev = 2
heavy = 3
light = 4
if("Big Bomb")
dev = 3
heavy = 5
light = 7
if("Custom Bomb")
dev = input("Devastation range (Tiles):") as num
heavy = input("Heavy impact range (Tiles):") as num
light = input("Light impact range (Tiles):") as num
var/max_range = max(dev, heavy, light)
var/x0 = epicenter.x
var/y0 = epicenter.y
var/list/wipe_colours = list()
for(var/turf/T in spiral_range_turfs(max_range, epicenter))
wipe_colours += T
var/dist = cheap_hypotenuse(T.x, T.y, x0, y0)
if(newmode == "Yes")
var/turf/TT = T
while(TT != epicenter)
TT = get_step_towards(TT,epicenter)
if(TT.density)
dist += TT.explosion_block
for(var/obj/O in T)
var/the_block = O.explosion_block
dist += the_block == EXPLOSION_BLOCK_PROC ? O.GetExplosionBlock() : the_block
if(dist < dev)
T.color = "red"
T.maptext = "Dev"
else if (dist < heavy)
T.color = "yellow"
T.maptext = "Heavy"
else if (dist < light)
T.color = "blue"
T.maptext = "Light"
else
continue
addtimer(CALLBACK(GLOBAL_PROC, .proc/wipe_color_and_text, wipe_colours), 100)
/proc/wipe_color_and_text(list/atom/wiping)
for(var/i in wiping)
var/atom/A = i
A.color = null
A.maptext = ""
/proc/dyn_explosion(turf/epicenter, power, flash_range, adminlog = TRUE, ignorecap = TRUE, flame_range = 0, 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)
// Using default dyn_ex scale:
// 100 explosion power is a (5, 10, 20) explosion.
// 75 explosion power is a (4, 8, 17) explosion.
// 50 explosion power is a (3, 7, 14) explosion.
// 25 explosion power is a (2, 5, 10) explosion.
// 10 explosion power is a (1, 3, 6) explosion.
// 5 explosion power is a (0, 1, 3) explosion.
// 1 explosion power is a (0, 0, 1) explosion.

View File

@@ -501,10 +501,6 @@
to_chat(user, "<span class='warning'>You can't move while buckled to [src]!</span>") to_chat(user, "<span class='warning'>You can't move while buckled to [src]!</span>")
return return
/// Return true if this atoms contents should not have ex_act called on ex_act
/atom/proc/prevent_content_explosion()
return FALSE
/// Handle what happens when your contents are exploded by a bomb /// Handle what happens when your contents are exploded by a bomb
/atom/proc/contents_explosion(severity, target) /atom/proc/contents_explosion(severity, target)
return //For handling the effects of explosions on contents that would not normally be effected return //For handling the effects of explosions on contents that would not normally be effected

View File

@@ -597,12 +597,12 @@
step(src, AM.dir) step(src, AM.dir)
..() ..()
/atom/movable/proc/safe_throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = MOVE_FORCE_STRONG) /atom/movable/proc/safe_throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = MOVE_FORCE_STRONG, quickstart = TRUE)
if((force < (move_resist * MOVE_FORCE_THROW_RATIO)) || (move_resist == INFINITY)) if((force < (move_resist * MOVE_FORCE_THROW_RATIO)) || (move_resist == INFINITY))
return return
return throw_at(target, range, speed, thrower, spin, diagonals_first, callback, force) return throw_at(target, range, speed, thrower, spin, diagonals_first, callback, force)
/atom/movable/proc/throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = MOVE_FORCE_STRONG) //If this returns FALSE then callback will not be called. /atom/movable/proc/throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = MOVE_FORCE_STRONG, quickstart = TRUE) //If this returns FALSE then callback will not be called.
. = FALSE . = FALSE
if (!target || speed <= 0) if (!target || speed <= 0)
return return
@@ -684,7 +684,8 @@
SSthrowing.processing[src] = TT SSthrowing.processing[src] = TT
if (SSthrowing.state == SS_PAUSED && length(SSthrowing.currentrun)) if (SSthrowing.state == SS_PAUSED && length(SSthrowing.currentrun))
SSthrowing.currentrun[src] = TT SSthrowing.currentrun[src] = TT
TT.tick() if (quickstart)
TT.tick()
/atom/movable/proc/handle_buckled_mob_movement(newloc, direct, glide_size_override) /atom/movable/proc/handle_buckled_mob_movement(newloc, direct, glide_size_override)
for(var/m in buckled_mobs) for(var/m in buckled_mobs)

View File

@@ -138,7 +138,7 @@
var/datum/component/slippery/slipper = GetComponent(/datum/component/slippery) var/datum/component/slippery/slipper = GetComponent(/datum/component/slippery)
slipper.signal_enabled = active slipper.signal_enabled = active
/obj/item/shield/energy/bananium/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force) /obj/item/shield/energy/bananium/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, quickstart = TRUE)
if(active) if(active)
if(iscarbon(thrower)) if(iscarbon(thrower))
var/mob/living/carbon/C = thrower var/mob/living/carbon/C = thrower

View File

@@ -143,15 +143,29 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
/obj/effect/meteor/proc/ram_turf(turf/T) /obj/effect/meteor/proc/ram_turf(turf/T)
//first bust whatever is in the turf //first bust whatever is in the turf
for(var/atom/A in T) for(var/thing in T)
if(A != src) if(thing == src)
if(isliving(A)) continue
A.visible_message("<span class='warning'>[src] slams into [A].</span>", "<span class='userdanger'>[src] slams into you!.</span>") if(isliving(thing))
A.ex_act(hitpwr) var/mob/living/living_thing = thing
living_thing.visible_message("<span class='warning'>[src] slams into [living_thing].</span>", "<span class='userdanger'>[src] slams into you!.</span>")
switch(hitpwr)
if(EXPLODE_DEVASTATE)
SSexplosions.high_mov_atom += thing
if(EXPLODE_HEAVY)
SSexplosions.med_mov_atom += thing
if(EXPLODE_LIGHT)
SSexplosions.low_mov_atom += thing
//then, ram the turf if it still exists //then, ram the turf if it still exists
if(T) if(T)
T.ex_act(hitpwr) switch(hitpwr)
if(EXPLODE_DEVASTATE)
SSexplosions.highturf += T
if(EXPLODE_HEAVY)
SSexplosions.medturf += T
if(EXPLODE_LIGHT)
SSexplosions.lowturf += T

View File

@@ -1311,7 +1311,7 @@
var/obj/structure/window/killthis = (locate(/obj/structure/window) in get_turf(src)) var/obj/structure/window/killthis = (locate(/obj/structure/window) in get_turf(src))
if(killthis) if(killthis)
killthis.ex_act(EXPLODE_HEAVY)//Smashin windows SSexplosions.med_mov_atom += killthis
operating = TRUE operating = TRUE
update_icon(AIRLOCK_CLOSING, 1) update_icon(AIRLOCK_CLOSING, 1)

View File

@@ -14,15 +14,11 @@ GLOBAL_LIST_EMPTY(doppler_arrays)
/obj/machinery/doppler_array/Initialize() /obj/machinery/doppler_array/Initialize()
. = ..() . = ..()
GLOB.doppler_arrays += src RegisterSignal(SSdcs, COMSIG_GLOB_EXPLOSION, .proc/sense_explosion)
/obj/machinery/doppler_array/ComponentInitialize() /obj/machinery/doppler_array/ComponentInitialize()
AddComponent(/datum/component/simple_rotation,ROTATION_ALTCLICK | ROTATION_CLOCKWISE,null,null,CALLBACK(src,.proc/rot_message)) AddComponent(/datum/component/simple_rotation,ROTATION_ALTCLICK | ROTATION_CLOCKWISE,null,null,CALLBACK(src,.proc/rot_message))
/obj/machinery/doppler_array/Destroy()
GLOB.doppler_arrays -= src
return ..()
/obj/machinery/doppler_array/examine(mob/user) /obj/machinery/doppler_array/examine(mob/user)
..() ..()
to_chat(user, "<span class='notice'>Its dish is facing to the [dir2text(dir)].</span>") to_chat(user, "<span class='notice'>Its dish is facing to the [dir2text(dir)].</span>")
@@ -48,8 +44,8 @@ GLOBAL_LIST_EMPTY(doppler_arrays)
to_chat(user, "<span class='notice'>You adjust [src]'s dish to face to the [dir2text(dir)].</span>") to_chat(user, "<span class='notice'>You adjust [src]'s dish to face to the [dir2text(dir)].</span>")
playsound(src, 'sound/items/screwdriver2.ogg', 50, 1) playsound(src, 'sound/items/screwdriver2.ogg', 50, 1)
/obj/machinery/doppler_array/proc/sense_explosion(turf/epicenter,devastation_range,heavy_impact_range,light_impact_range, /obj/machinery/doppler_array/proc/sense_explosion(datum/source, turf/epicenter, devastation_range, heavy_impact_range, light_impact_range,
took,orig_dev_range,orig_heavy_range,orig_light_range) took, orig_dev_range, orig_heavy_range, orig_light_range)
if(stat & NOPOWER) if(stat & NOPOWER)
return FALSE return FALSE
var/turf/zone = get_turf(src) var/turf/zone = get_turf(src)
@@ -57,7 +53,7 @@ GLOBAL_LIST_EMPTY(doppler_arrays)
return FALSE return FALSE
if(next_announce > world.time) if(next_announce > world.time)
return return FALSE
next_announce = world.time + cooldown next_announce = world.time + cooldown
var/distance = get_dist(epicenter, zone) var/distance = get_dist(epicenter, zone)
@@ -65,11 +61,11 @@ GLOBAL_LIST_EMPTY(doppler_arrays)
if(distance > max_dist) if(distance > max_dist)
return FALSE return FALSE
if(!(direct & dir) && !integrated) if(!(direct & dir))
return FALSE return FALSE
var/list/messages = list("Explosive disturbance detected.", \ var/list/messages = list("Explosive disturbance detected.",
"Epicenter at: grid ([epicenter.x],[epicenter.y]). Temporal displacement of tachyons: [took] seconds.", \ "Epicenter at: grid ([epicenter.x],[epicenter.y]). Temporal displacement of tachyons: [took] seconds.", \
"Factual: Epicenter radius: [devastation_range]. Outer radius: [heavy_impact_range]. Shockwave radius: [light_impact_range].") "Factual: Epicenter radius: [devastation_range]. Outer radius: [heavy_impact_range]. Shockwave radius: [light_impact_range].")
@@ -77,14 +73,8 @@ GLOBAL_LIST_EMPTY(doppler_arrays)
if(devastation_range < orig_dev_range || heavy_impact_range < orig_heavy_range || light_impact_range < orig_light_range) if(devastation_range < orig_dev_range || heavy_impact_range < orig_heavy_range || light_impact_range < orig_light_range)
messages += "Theoretical: Epicenter radius: [orig_dev_range]. Outer radius: [orig_heavy_range]. Shockwave radius: [orig_light_range]." messages += "Theoretical: Epicenter radius: [orig_dev_range]. Outer radius: [orig_heavy_range]. Shockwave radius: [orig_light_range]."
if(integrated) for(var/message in messages)
var/obj/item/clothing/head/helmet/space/hardsuit/helm = loc say(message)
if(!helm || !istype(helm, /obj/item/clothing/head/helmet/space/hardsuit))
return FALSE
helm.display_visor_message("Explosion detected! Epicenter: [devastation_range], Outer: [heavy_impact_range], Shock: [light_impact_range]")
else
for(var/message in messages)
say(message)
return TRUE return TRUE
/obj/machinery/doppler_array/powered() /obj/machinery/doppler_array/powered()
@@ -100,22 +90,16 @@ GLOBAL_LIST_EMPTY(doppler_arrays)
else else
icon_state = "[initial(icon_state)]-off" icon_state = "[initial(icon_state)]-off"
//Portable version, built into EOD equipment. It simply provides an explosion's three damage levels.
/obj/machinery/doppler_array/integrated
name = "integrated tachyon-doppler module"
integrated = TRUE
max_dist = 21 //Should detect most explosions in hearing range.
use_power = NO_POWER_USE
/obj/machinery/doppler_array/research /obj/machinery/doppler_array/research
name = "tachyon-doppler research array" name = "tachyon-doppler research array"
desc = "A specialized tachyon-doppler bomb detection array that uses the results of the highest yield of explosions for research." desc = "A specialized tachyon-doppler bomb detection array that uses the results of the highest yield of explosions for research."
var/datum/techweb/linked_techweb var/datum/techweb/linked_techweb
/obj/machinery/doppler_array/research/sense_explosion(turf/epicenter, dev, heavy, light, time, orig_dev, orig_heavy, orig_light) //probably needs a way to ignore admin explosives later on /obj/machinery/doppler_array/research/sense_explosion(datum/source, turf/epicenter, devastation_range, heavy_impact_range, light_impact_range,
took, orig_dev_range, orig_heavy_range, orig_light_range) //probably needs a way to ignore admin explosives later on
. = ..() . = ..()
if(!.) if(!.)
return FALSE return
if(!istype(linked_techweb)) if(!istype(linked_techweb))
say("Warning: No linked research system!") say("Warning: No linked research system!")
return return
@@ -124,14 +108,14 @@ GLOBAL_LIST_EMPTY(doppler_arrays)
/*****The Point Calculator*****/ /*****The Point Calculator*****/
if(orig_light < 10) if(orig_light_range < 10)
say("Explosion not large enough for research calculations.") say("Explosion not large enough for research calculations.")
return return
else if(orig_light >= INFINITY) // Colton-proofs the doppler array else if(orig_light_range >= INFINITY) // Colton-proofs the doppler array
say("WARNING: INFINITE DENSITY OF TACHYONS DETECTED.") say("WARNING: INFINITE DENSITY OF TACHYONS DETECTED.")
point_gain = TOXINS_RESEARCH_MAX point_gain = TOXINS_RESEARCH_MAX
else else
point_gain = (TOXINS_RESEARCH_MAX * orig_light) / (orig_light + TOXINS_RESEARCH_LAMBDA)//New yogs function has the limit built into it because l'Hopital's rule point_gain = (TOXINS_RESEARCH_MAX * orig_light_range) / (orig_light_range + TOXINS_RESEARCH_LAMBDA)//New yogs function has the limit built into it because l'Hopital's rule
/*****The Point Capper*****/ /*****The Point Capper*****/

View File

@@ -133,10 +133,22 @@
severity++ severity++
for(var/X in equipment) for(var/X in equipment)
var/obj/item/mecha_parts/mecha_equipment/ME = X var/obj/item/mecha_parts/mecha_equipment/ME = X
ME.ex_act(severity,target) switch(severity)
if(EXPLODE_DEVASTATE)
SSexplosions.high_mov_atom += ME
if(EXPLODE_HEAVY)
SSexplosions.med_mov_atom += ME
if(EXPLODE_LIGHT)
SSexplosions.low_mov_atom += ME
for(var/Y in trackers) for(var/Y in trackers)
var/obj/item/mecha_parts/mecha_tracking/MT = Y var/obj/item/mecha_parts/mecha_tracking/MT = Y
MT.ex_act(severity, target) switch(severity)
if(EXPLODE_DEVASTATE)
SSexplosions.high_mov_atom += MT
if(EXPLODE_HEAVY)
SSexplosions.med_mov_atom += MT
if(EXPLODE_LIGHT)
SSexplosions.low_mov_atom += MT
if(occupant) if(occupant)
occupant.ex_act(severity,target) occupant.ex_act(severity,target)

View File

@@ -316,7 +316,7 @@
if(target && !target.stat) if(target && !target.stat)
O.throw_at(target, 7, 5) O.throw_at(target, 7, 5)
else else
O.ex_act(EXPLODE_HEAVY) SSexplosions.med_mov_atom += O
/obj/effect/anomaly/bhole/proc/grav(r, ex_act_force, pull_chance, turf_removal_chance) /obj/effect/anomaly/bhole/proc/grav(r, ex_act_force, pull_chance, turf_removal_chance)
for(var/t = -r, t < r, t++) for(var/t = -r, t < r, t++)
@@ -335,7 +335,13 @@
if(prob(pull_chance)) if(prob(pull_chance))
for(var/obj/O in T.contents) for(var/obj/O in T.contents)
if(O.anchored) if(O.anchored)
O.ex_act(ex_act_force) switch(ex_act_force)
if(EXPLODE_DEVASTATE)
SSexplosions.high_mov_atom += O
if(EXPLODE_HEAVY)
SSexplosions.med_mov_atom += O
if(EXPLODE_LIGHT)
SSexplosions.low_mov_atom += O
else else
step_towards(O,src) step_towards(O,src)
for(var/mob/living/M in T.contents) for(var/mob/living/M in T.contents)
@@ -343,4 +349,10 @@
//Damaging the turf //Damaging the turf
if( T && prob(turf_removal_chance) ) if( T && prob(turf_removal_chance) )
T.ex_act(ex_act_force) switch(ex_act_force)
if(EXPLODE_DEVASTATE)
SSexplosions.highturf += T
if(EXPLODE_HEAVY)
SSexplosions.medturf += T
if(EXPLODE_LIGHT)
SSexplosions.lowturf += T

View File

@@ -542,10 +542,12 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
itempush = 0 //too light to push anything itempush = 0 //too light to push anything
return hit_atom.hitby(src, 0, itempush, throwingdatum=throwingdatum) return hit_atom.hitby(src, 0, itempush, throwingdatum=throwingdatum)
/obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force) /obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, quickstart = TRUE)
if(HAS_TRAIT(src, TRAIT_NODROP))
return
thrownby = thrower thrownby = thrower
callback = CALLBACK(src, .proc/after_throw, callback) //replace their callback with our own callback = CALLBACK(src, .proc/after_throw, callback) //replace their callback with our own
. = ..(target, range, speed, thrower, spin, diagonals_first, callback, force) . = ..(target, range, speed, thrower, spin, diagonals_first, callback, force, quickstart = quickstart)
/obj/item/proc/after_throw(datum/callback/callback) /obj/item/proc/after_throw(datum/callback/callback)
@@ -800,11 +802,6 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
dropped(M) dropped(M)
return ..() return ..()
/obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=TRUE, diagonals_first = FALSE, var/datum/callback/callback)
if(HAS_TRAIT(src, TRAIT_NODROP))
return
return ..()
/obj/item/proc/canStrip(mob/stripper, mob/owner) /obj/item/proc/canStrip(mob/stripper, mob/owner)
SHOULD_BE_PURE(TRUE) SHOULD_BE_PURE(TRUE)
return !HAS_TRAIT(src, TRAIT_NODROP) return !HAS_TRAIT(src, TRAIT_NODROP)

View File

@@ -339,7 +339,7 @@
gender = NEUTER gender = NEUTER
var/immobilize = 0 var/immobilize = 0
/obj/item/restraints/legcuffs/bola/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback) /obj/item/restraints/legcuffs/bola/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, quickstart = TRUE)
if(!..()) if(!..())
return return
playsound(src.loc,'sound/weapons/bolathrow.ogg', 75, 1) playsound(src.loc,'sound/weapons/bolathrow.ogg', 75, 1)

View File

@@ -19,9 +19,14 @@
return FALSE return FALSE
/obj/item/storage/contents_explosion(severity, target) /obj/item/storage/contents_explosion(severity, target)
for(var/atom/A in contents) for(var/thing in contents)
A.ex_act(severity, target) switch(severity)
CHECK_TICK if(EXPLODE_DEVASTATE)
SSexplosions.high_mov_atom += thing
if(EXPLODE_HEAVY)
SSexplosions.med_mov_atom += thing
if(EXPLODE_LIGHT)
SSexplosions.low_mov_atom += thing
/obj/item/storage/canStrip(mob/who) /obj/item/storage/canStrip(mob/who)
. = ..() . = ..()

View File

@@ -617,7 +617,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
if(homerun_ready) if(homerun_ready)
user.visible_message("<span class='userdanger'>It's a home run!</span>") user.visible_message("<span class='userdanger'>It's a home run!</span>")
target.throw_at(throw_target, rand(8,10), 14, user) target.throw_at(throw_target, rand(8,10), 14, user)
target.ex_act(EXPLODE_HEAVY) SSexplosions.medturf += throw_target
playsound(get_turf(src), 'sound/weapons/homerun.ogg', 100, 1) playsound(get_turf(src), 'sound/weapons/homerun.ogg', 100, 1)
homerun_ready = 0 homerun_ready = 0
return return

View File

@@ -168,7 +168,7 @@
return take_damage(M.force*3, mech_damtype, "melee", play_soundeffect, get_dir(src, M)) // multiplied by 3 so we can hit objs hard but not be overpowered against mobs. return take_damage(M.force*3, mech_damtype, "melee", play_soundeffect, get_dir(src, M)) // multiplied by 3 so we can hit objs hard but not be overpowered against mobs.
/obj/singularity_act() /obj/singularity_act()
ex_act(EXPLODE_DEVASTATE) SSexplosions.high_mov_atom += src
if(src && !QDELETED(src)) if(src && !QDELETED(src))
qdel(src) qdel(src)
return 2 return 2

View File

@@ -80,7 +80,7 @@
SEND_SIGNAL(src, COMSIG_OBJ_SETANCHORED, anchorvalue) SEND_SIGNAL(src, COMSIG_OBJ_SETANCHORED, anchorvalue)
anchored = anchorvalue anchored = anchorvalue
/obj/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force) /obj/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, quickstart = TRUE)
..() ..()
if(obj_flags & FROZEN) if(obj_flags & FROZEN)
visible_message("<span class='danger'>[src] shatters into a million pieces!</span>") visible_message("<span class='danger'>[src] shatters into a million pieces!</span>")

View File

@@ -534,8 +534,14 @@ GLOBAL_LIST_EMPTY(lockers)
req_access += pick(get_all_accesses()) req_access += pick(get_all_accesses())
/obj/structure/closet/contents_explosion(severity, target) /obj/structure/closet/contents_explosion(severity, target)
for(var/atom/A in contents) for(var/thing in contents)
A.ex_act(severity, target) switch(severity)
if(EXPLODE_DEVASTATE)
SSexplosions.high_mov_atom += thing
if(EXPLODE_HEAVY)
SSexplosions.med_mov_atom += thing
if(EXPLODE_LIGHT)
SSexplosions.low_mov_atom += thing
CHECK_TICK CHECK_TICK
/obj/structure/closet/singularity_act() /obj/structure/closet/singularity_act()

View File

@@ -33,7 +33,13 @@
/obj/structure/extinguisher_cabinet/contents_explosion(severity, target) /obj/structure/extinguisher_cabinet/contents_explosion(severity, target)
if(stored_extinguisher) if(stored_extinguisher)
stored_extinguisher.ex_act(severity, target) switch(severity)
if(EXPLODE_DEVASTATE)
SSexplosions.high_mov_atom += stored_extinguisher
if(EXPLODE_HEAVY)
SSexplosions.med_mov_atom += stored_extinguisher
if(EXPLODE_LIGHT)
SSexplosions.low_mov_atom += stored_extinguisher
/obj/structure/extinguisher_cabinet/handle_atom_del(atom/A) /obj/structure/extinguisher_cabinet/handle_atom_del(atom/A)
if(A == stored_extinguisher) if(A == stored_extinguisher)

View File

@@ -95,9 +95,14 @@
update_icon() update_icon()
/obj/structure/guncase/contents_explosion(severity, target) /obj/structure/guncase/contents_explosion(severity, target)
for(var/atom/A in contents) for(var/thing in contents)
A.ex_act(severity++, target) switch(severity)
CHECK_TICK if(EXPLODE_DEVASTATE)
SSexplosions.high_mov_atom += thing
if(EXPLODE_HEAVY)
SSexplosions.med_mov_atom += thing
if(EXPLODE_LIGHT)
SSexplosions.low_mov_atom += thing
/obj/structure/guncase/shotgun /obj/structure/guncase/shotgun
name = "shotgun locker" name = "shotgun locker"

View File

@@ -56,8 +56,14 @@
empty_pod() empty_pod()
/obj/structure/transit_tube_pod/contents_explosion(severity, target) /obj/structure/transit_tube_pod/contents_explosion(severity, target)
for(var/atom/movable/AM in contents) for(var/thing in contents)
AM.ex_act(severity, target) switch(severity)
if(EXPLODE_DEVASTATE)
SSexplosions.high_mov_atom += thing
if(EXPLODE_HEAVY)
SSexplosions.med_mov_atom += thing
if(EXPLODE_LIGHT)
SSexplosions.low_mov_atom += thing
/obj/structure/transit_tube_pod/singularity_pull(S, current_size) /obj/structure/transit_tube_pod/singularity_pull(S, current_size)
..() ..()

View File

@@ -124,6 +124,10 @@
soundin = pick('sound/effects/glassbr1.ogg','sound/effects/glassbr2.ogg','sound/effects/glassbr3.ogg') soundin = pick('sound/effects/glassbr1.ogg','sound/effects/glassbr2.ogg','sound/effects/glassbr3.ogg')
if ("explosion") if ("explosion")
soundin = pick('sound/effects/explosion1.ogg','sound/effects/explosion2.ogg') soundin = pick('sound/effects/explosion1.ogg','sound/effects/explosion2.ogg')
if ("explosion_creaking")
soundin = pick('sound/effects/explosioncreak1.ogg', 'sound/effects/explosioncreak2.ogg')
if ("hull_creaking")
soundin = pick('sound/effects/creak1.ogg', 'sound/effects/creak2.ogg', 'sound/effects/creak3.ogg')
if ("sparks") if ("sparks")
soundin = pick('sound/effects/sparks1.ogg','sound/effects/sparks2.ogg','sound/effects/sparks3.ogg','sound/effects/sparks4.ogg') soundin = pick('sound/effects/sparks1.ogg','sound/effects/sparks2.ogg','sound/effects/sparks3.ogg','sound/effects/sparks4.ogg')
if ("rustle") if ("rustle")

View File

@@ -56,6 +56,14 @@
icon_regular_floor = icon_state icon_regular_floor = icon_state
if(mapload && prob(33)) if(mapload && prob(33))
MakeDirty() MakeDirty()
if(is_station_level(z))
GLOB.station_turfs += src
/turf/open/floor/Destroy()
if(is_station_level(z))
GLOB.station_turfs -= src
..()
/turf/open/floor/ex_act(severity, target) /turf/open/floor/ex_act(severity, target)
var/shielded = is_shielded() var/shielded = is_shielded()

View File

@@ -273,14 +273,8 @@
fixed_underlay = list("space"=1) fixed_underlay = list("space"=1)
/turf/closed/wall/mineral/plastitanium/explosive/ex_act(severity) /turf/closed/wall/mineral/plastitanium/explosive/ex_act(severity)
var/datum/explosion/acted_explosion = null var/obj/item/bombcore/large/bombcore = new(get_turf(src))
for(var/datum/explosion/E in GLOB.explosions) bombcore.detonate()
if(E.explosion_id == explosion_id)
acted_explosion = E
break
if(acted_explosion && istype(acted_explosion.explosion_source, /obj/item/bombcore))
var/obj/item/bombcore/large/bombcore = new(get_turf(src))
bombcore.detonate()
..() ..()
//have to copypaste this code //have to copypaste this code

View File

@@ -35,6 +35,16 @@
var/list/dent_decals var/list/dent_decals
/turf/closed/wall/Initialize(mapload)
. = ..()
if(is_station_level(z))
GLOB.station_turfs += src
/turf/closed/wall/Destroy()
if(is_station_level(z))
GLOB.station_turfs -= src
..()
/turf/closed/wall/examine(mob/user) /turf/closed/wall/examine(mob/user)
. += ..() . += ..()
. += deconstruction_hints(user) . += deconstruction_hints(user)

View File

@@ -1,3 +1,5 @@
GLOBAL_LIST_EMPTY(station_turfs)
/turf /turf
icon = 'icons/turf/floors.dmi' icon = 'icons/turf/floors.dmi'
level = 1 level = 1
@@ -23,6 +25,7 @@
var/explosion_level = 0 //for preventing explosion dodging var/explosion_level = 0 //for preventing explosion dodging
var/explosion_id = 0 var/explosion_id = 0
var/list/explosion_throw_details
var/requires_activation //add to air processing after initialize? var/requires_activation //add to air processing after initialize?
var/changing_turf = FALSE var/changing_turf = FALSE
@@ -249,8 +252,6 @@
/turf/Entered(atom/movable/AM) /turf/Entered(atom/movable/AM)
..() ..()
if(explosion_level && AM.ex_check(explosion_id))
AM.ex_act(explosion_level)
// If an opaque movable atom moves around we need to potentially update visibility. // If an opaque movable atom moves around we need to potentially update visibility.
if (AM.opacity) if (AM.opacity)
@@ -415,25 +416,19 @@
/turf/proc/is_shielded() /turf/proc/is_shielded()
/turf/contents_explosion(severity, target) /turf/contents_explosion(severity, target)
var/affecting_level for(var/thing in contents)
if(severity == 1) var/atom/movable/movable_thing = thing
affecting_level = 1 if(QDELETED(movable_thing))
else if(is_shielded()) continue
affecting_level = 3 if(!movable_thing.ex_check(explosion_id))
else if(intact) continue
affecting_level = 2 switch(severity)
else if(EXPLODE_DEVASTATE)
affecting_level = 1 SSexplosions.high_mov_atom += movable_thing
if(EXPLODE_HEAVY)
for(var/V in contents) SSexplosions.med_mov_atom += movable_thing
var/atom/A = V if(EXPLODE_LIGHT)
if(!QDELETED(A) && A.level >= affecting_level) SSexplosions.low_mov_atom += movable_thing
if(ismovable(A))
var/atom/movable/AM = A
if(!AM.ex_check(explosion_id))
continue
A.ex_act(severity, target)
CHECK_TICK
/turf/narsie_act(force, ignore_mobs, probability = 20) /turf/narsie_act(force, ignore_mobs, probability = 20)
. = (prob(probability) || force) . = (prob(probability) || force)

View File

@@ -42,5 +42,5 @@
/obj/effect/clockwork/servant_blocker/ex_act(severity, target) /obj/effect/clockwork/servant_blocker/ex_act(severity, target)
return return
/obj/effect/clockwork/servant_blocker/safe_throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = MOVE_FORCE_STRONG) /obj/effect/clockwork/servant_blocker/safe_throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = MOVE_FORCE_STRONG, quickstart = TRUE)
return return

View File

@@ -136,7 +136,7 @@
. = ..() . = ..()
setDir(t) setDir(t)
/obj/item/assembly/infra/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, gentle = FALSE) /obj/item/assembly/infra/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, gentle = FALSE, quickstart = TRUE)
. = ..() . = ..()
olddir = dir olddir = dir

View File

@@ -63,6 +63,9 @@ GLOBAL_LIST_EMPTY(pipeimages)
nullifyNode(i) nullifyNode(i)
SSair.atmos_machinery -= src SSair.atmos_machinery -= src
if(SSair.currentpart == SSAIR_ATMOSMACHINERY)
SSair.currentrun -= src
SSair.pipenets_needing_rebuilt -= src
dropContents() dropContents()
if(pipe_vision_img) if(pipe_vision_img)

View File

@@ -84,7 +84,7 @@
/obj/machinery/atmospherics/components/binary/circulator/update_icon() /obj/machinery/atmospherics/components/binary/circulator/update_icon()
cut_overlays() cut_overlays()
if(anchored) if(anchored)
for(var/direction in GLOB.cardinals) for(var/direction in GLOB.cardinals)
if(!(direction & initialize_directions)) if(!(direction & initialize_directions))
@@ -120,7 +120,7 @@
add_overlay("circ-panel") add_overlay("circ-panel")
set_light(0) set_light(0)
return return
icon_state = "circ-assembled-[flipped]" icon_state = "circ-assembled-[flipped]"
if(!is_operational()) if(!is_operational())
@@ -150,7 +150,7 @@
/obj/machinery/atmospherics/components/binary/circulator/wrench_act(mob/living/user, obj/item/I) /obj/machinery/atmospherics/components/binary/circulator/wrench_act(mob/living/user, obj/item/I)
if(user.a_intent == INTENT_HARM) if(user.a_intent == INTENT_HARM)
return return
if(!panel_open) if(!panel_open)
to_chat(user, "<span class='warning'>Open the panel first!</span>") to_chat(user, "<span class='warning'>Open the panel first!</span>")
return TRUE return TRUE
@@ -186,7 +186,7 @@
if(node2) if(node2)
node2.atmosinit() node2.atmosinit()
node2.addMember(src) node2.addMember(src)
build_network() SSair.add_to_rebuild_queue(src)
update_icon() update_icon()
@@ -211,7 +211,7 @@
/obj/machinery/atmospherics/components/binary/circulator/multitool_act(mob/living/user, obj/item/I) /obj/machinery/atmospherics/components/binary/circulator/multitool_act(mob/living/user, obj/item/I)
if(user.a_intent == INTENT_HARM) if(user.a_intent == INTENT_HARM)
return return
if(generator) if(generator)
to_chat(user, "<span class='warning'>Disconnect [generator] first!</span>") to_chat(user, "<span class='warning'>Disconnect [generator] first!</span>")
return TRUE return TRUE
@@ -283,4 +283,3 @@
generator.kill_circs() generator.kill_circs()
generator.update_icon() generator.update_icon()
..() ..()

View File

@@ -144,7 +144,8 @@
var/datum/pipeline/parent = parents[i] var/datum/pipeline/parent = parents[i]
if(!parent) if(!parent)
WARNING("Component is missing a pipenet! Rebuilding...") WARNING("Component is missing a pipenet! Rebuilding...")
build_network() SSair.add_to_rebuild_queue(src)
parent = parents[i]
parent.update = 1 parent.update = 1
/obj/machinery/atmospherics/components/returnPipenets() /obj/machinery/atmospherics/components/returnPipenets()

View File

@@ -81,7 +81,13 @@
/obj/machinery/atmospherics/components/unary/cryo_cell/contents_explosion(severity, target) /obj/machinery/atmospherics/components/unary/cryo_cell/contents_explosion(severity, target)
..() ..()
if(beaker) if(beaker)
beaker.ex_act(severity, target) switch(severity)
if(EXPLODE_DEVASTATE)
SSexplosions.high_mov_atom += beaker
if(EXPLODE_HEAVY)
SSexplosions.med_mov_atom += beaker
if(EXPLODE_LIGHT)
SSexplosions.low_mov_atom += beaker
/obj/machinery/atmospherics/components/unary/cryo_cell/handle_atom_del(atom/A) /obj/machinery/atmospherics/components/unary/cryo_cell/handle_atom_del(atom/A)
..() ..()
@@ -453,7 +459,7 @@
if(node) if(node)
node.atmosinit() node.atmosinit()
node.addMember(src) node.addMember(src)
build_network() SSair.add_to_rebuild_queue(src)
/obj/machinery/atmospherics/components/unary/cryo_cell/CtrlClick(mob/user) /obj/machinery/atmospherics/components/unary/cryo_cell/CtrlClick(mob/user)
if(!user.canUseTopic(src, !issilicon(user))) if(!user.canUseTopic(src, !issilicon(user)))

View File

@@ -103,7 +103,7 @@
if(node) if(node)
node.atmosinit() node.atmosinit()
node.addMember(src) node.addMember(src)
build_network() SSair.add_to_rebuild_queue(src)
return TRUE return TRUE
/obj/machinery/atmospherics/components/unary/thermomachine/ui_status(mob/user) /obj/machinery/atmospherics/components/unary/thermomachine/ui_status(mob/user)

View File

@@ -37,7 +37,7 @@
nodes = list() nodes = list()
for(var/obj/machinery/atmospherics/A in needs_nullifying) for(var/obj/machinery/atmospherics/A in needs_nullifying)
A.disconnect(src) A.disconnect(src)
A.build_network() SSair.add_to_rebuild_queue(A)
/obj/machinery/atmospherics/pipe/layer_manifold/proc/get_all_connected_nodes() /obj/machinery/atmospherics/pipe/layer_manifold/proc/get_all_connected_nodes()
return front_nodes + back_nodes + nodes return front_nodes + back_nodes + nodes
@@ -141,4 +141,3 @@
/obj/machinery/atmospherics/pipe/layer_manifold/visible /obj/machinery/atmospherics/pipe/layer_manifold/visible
level = PIPE_VISIBLE_LEVEL level = PIPE_VISIBLE_LEVEL
layer = GAS_PIPE_VISIBLE_LAYER layer = GAS_PIPE_VISIBLE_LAYER

View File

@@ -27,7 +27,7 @@
var/obj/machinery/atmospherics/oldN = nodes[i] var/obj/machinery/atmospherics/oldN = nodes[i]
..() ..()
if(oldN) if(oldN)
oldN.build_network() SSair.add_to_rebuild_queue(oldN)
/obj/machinery/atmospherics/pipe/destroy_network() /obj/machinery/atmospherics/pipe/destroy_network()
QDEL_NULL(parent) QDEL_NULL(parent)

View File

@@ -210,7 +210,7 @@
pump = new(src, FALSE) pump = new(src, FALSE)
pump.on = TRUE pump.on = TRUE
pump.stat = 0 pump.stat = 0
pump.build_network() SSair.add_to_rebuild_queue(pump)
/obj/machinery/portable_atmospherics/canister/Initialize() /obj/machinery/portable_atmospherics/canister/Initialize()
. = ..() . = ..()

View File

@@ -20,7 +20,7 @@
pump = new(src, FALSE) pump = new(src, FALSE)
pump.on = TRUE pump.on = TRUE
pump.stat = 0 pump.stat = 0
pump.build_network() SSair.add_to_rebuild_queue(pump)
/obj/machinery/portable_atmospherics/pump/Destroy() /obj/machinery/portable_atmospherics/pump/Destroy()
var/turf/T = get_turf(src) var/turf/T = get_turf(src)

View File

@@ -73,7 +73,7 @@ GLOBAL_DATUM(the_gateway, /obj/machinery/gateway/centerstation)
/obj/machinery/gateway/proc/toggleon(mob/user) /obj/machinery/gateway/proc/toggleon(mob/user)
return FALSE return FALSE
/obj/machinery/gateway/safe_throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = MOVE_FORCE_STRONG) /obj/machinery/gateway/safe_throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = MOVE_FORCE_STRONG, quickstart = TRUE)
return return
/obj/machinery/gateway/centerstation/Initialize() /obj/machinery/gateway/centerstation/Initialize()

View File

@@ -15,6 +15,7 @@
armor = list("melee" = 30, "bullet" = 50, "laser" = 50, "energy" = 100, "bomb" = 100, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 80) armor = list("melee" = 30, "bullet" = 50, "laser" = 50, "energy" = 100, "bomb" = 100, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 80)
anchored = TRUE //So it cant slide around after landing anchored = TRUE //So it cant slide around after landing
anchorable = FALSE anchorable = FALSE
flags_1 = PREVENT_CONTENTS_EXPLOSION_1
//*****NOTE*****: Many of these comments are similarly described in centcom_podlauncher.dm. If you change them here, please consider doing so in the centcom podlauncher code as well! //*****NOTE*****: Many of these comments are similarly described in centcom_podlauncher.dm. If you change them here, please consider doing so in the centcom podlauncher code as well!
var/adminNamed = FALSE //Determines whether or not the pod has been named by an admin. If true, the pod's name will not get overridden when the style of the pod changes (changing the style of the pod normally also changes the name+desc) var/adminNamed = FALSE //Determines whether or not the pod has been named by an admin. If true, the pod's name will not get overridden when the style of the pod changes (changing the style of the pod normally also changes the name+desc)
var/bluespace = FALSE //If true, the pod deletes (in a shower of sparks) after landing var/bluespace = FALSE //If true, the pod deletes (in a shower of sparks) after landing
@@ -111,9 +112,6 @@
/obj/structure/closet/supplypod/contents_explosion() //Supplypods also protect their contents from the harmful effects of fucking exploding. /obj/structure/closet/supplypod/contents_explosion() //Supplypods also protect their contents from the harmful effects of fucking exploding.
return return
/obj/structure/closet/supplypod/prevent_content_explosion() //Useful for preventing epicenter explosions from damaging contents
return TRUE
/obj/structure/closet/supplypod/toggle(mob/living/user) //Supplypods shouldn't be able to be manually opened under any circumstances, as the open() proc generates supply order datums /obj/structure/closet/supplypod/toggle(mob/living/user) //Supplypods shouldn't be able to be manually opened under any circumstances, as the open() proc generates supply order datums
return return

View File

@@ -94,7 +94,7 @@
candy_cooldown = world.time+1200 candy_cooldown = world.time+1200
else else
to_chat(user, "You just took a candy corn! You should wait a couple minutes, lest you burn through your stash.") to_chat(user, "You just took a candy corn! You should wait a couple minutes, lest you burn through your stash.")
/obj/item/clothing/head/det_hat/evil /obj/item/clothing/head/det_hat/evil
name = "suspicious fedora" name = "suspicious fedora"
icon_state = "syndicate_fedora" icon_state = "syndicate_fedora"
@@ -123,14 +123,14 @@
icon_state = "syndicate_fedora" icon_state = "syndicate_fedora"
attack_verb = list("poked", "tipped") attack_verb = list("poked", "tipped")
hitsound = 'sound/weapons/genhit.ogg' hitsound = 'sound/weapons/genhit.ogg'
/obj/item/clothing/head/det_hat/evil/throw_impact(atom/hit_atom,) /obj/item/clothing/head/det_hat/evil/throw_impact(atom/hit_atom,)
if(iscarbon(src.loc)) if(iscarbon(src.loc))
return ..() return ..()
throw_at(thrownby, throw_range+3, throw_speed, null) throw_at(thrownby, throw_range+3, throw_speed, null)
..() ..()
/obj/item/clothing/head/det_hat/evil/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force) /obj/item/clothing/head/det_hat/evil/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, quickstart = TRUE)
if(iscarbon(thrower)) if(iscarbon(thrower))
var/mob/living/carbon/C = thrower var/mob/living/carbon/C = thrower
C.throw_mode_on() C.throw_mode_on()

View File

@@ -489,12 +489,13 @@
resistance_flags = ACID_PROOF | FIRE_PROOF resistance_flags = ACID_PROOF | FIRE_PROOF
max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT
armor = list("melee" = 30, "bullet" = 5, "laser" = 10, "energy" = 5, "bomb" = 100, "bio" = 100, "rad" = 60, "fire" = 60, "acid" = 80) armor = list("melee" = 30, "bullet" = 5, "laser" = 10, "energy" = 5, "bomb" = 100, "bio" = 100, "rad" = 60, "fire" = 60, "acid" = 80)
var/obj/machinery/doppler_array/integrated/bomb_radar var/explosion_detection_dist = 21
clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | SCAN_REAGENTS clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | SCAN_REAGENTS
actions_types = list(/datum/action/item_action/toggle_helmet_light, /datum/action/item_action/toggle_research_scanner) actions_types = list(/datum/action/item_action/toggle_helmet_light, /datum/action/item_action/toggle_research_scanner)
/obj/item/clothing/head/helmet/space/hardsuit/rd/Initialize() /obj/item/clothing/head/helmet/space/hardsuit/rd/Initialize()
. = ..() . = ..()
RegisterSignal(SSdcs, COMSIG_GLOB_EXPLOSION, .proc/sense_explosion)
/obj/item/clothing/head/helmet/space/hardsuit/rd/equipped(mob/living/carbon/human/user, slot) /obj/item/clothing/head/helmet/space/hardsuit/rd/equipped(mob/living/carbon/human/user, slot)
..() ..()
@@ -508,6 +509,15 @@
var/datum/atom_hud/DHUD = GLOB.huds[DATA_HUD_DIAGNOSTIC_BASIC] var/datum/atom_hud/DHUD = GLOB.huds[DATA_HUD_DIAGNOSTIC_BASIC]
DHUD.remove_hud_from(user) DHUD.remove_hud_from(user)
/obj/item/clothing/head/helmet/space/hardsuit/rd/proc/sense_explosion(datum/source, turf/epicenter, devastation_range, heavy_impact_range,
light_impact_range, took, orig_dev_range, orig_heavy_range, orig_light_range)
var/turf/T = get_turf(src)
if(T.z != epicenter.z)
return
if(get_dist(epicenter, T) > explosion_detection_dist)
return
display_visor_message("Explosion detected! Epicenter: [devastation_range], Outer: [heavy_impact_range], Shock: [light_impact_range]")
/obj/item/clothing/suit/space/hardsuit/rd /obj/item/clothing/suit/space/hardsuit/rd
icon_state = "hardsuit-rd" icon_state = "hardsuit-rd"
name = "prototype hardsuit" name = "prototype hardsuit"

View File

@@ -49,6 +49,7 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
pull_force = INFINITY pull_force = INFINITY
density = TRUE density = TRUE
anchored = TRUE anchored = TRUE
flags_1 = PREVENT_CONTENTS_EXPLOSION_1
var/mob/living/wizard var/mob/living/wizard
var/z_original = 0 var/z_original = 0
var/destination var/destination
@@ -100,9 +101,6 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
walk(src,0) walk(src,0)
walk_towards(src, destination, 1) walk_towards(src, destination, 1)
/obj/structure/closet/supplypod/prevent_content_explosion()
return TRUE
/obj/effect/immovablerod/ex_act(severity, target) /obj/effect/immovablerod/ex_act(severity, target)
return 0 return 0
@@ -126,7 +124,10 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
if(isturf(clong) || isobj(clong)) if(isturf(clong) || isobj(clong))
if(clong.density) if(clong.density)
clong.ex_act(EXPLODE_HEAVY) if(isturf(clong))
SSexplosions.medturf += clong
if(isobj(clong))
SSexplosions.med_mov_atom += clong
else if(isliving(clong)) else if(isliving(clong))
penetrate(clong) penetrate(clong)

View File

@@ -34,6 +34,6 @@
explosion(get_turf(P), 0, 0, 2) explosion(get_turf(P), 0, 0, 2)
// Only a level 1 explosion actually damages the machine // Only a level 1 explosion actually damages the machine
// at all // at all
P.ex_act(EXPLODE_DEVASTATE) SSexplosions.high_mov_atom += P
else else
P.emp_act(EMP_HEAVY) P.emp_act(EMP_HEAVY)

View File

@@ -146,7 +146,13 @@
quality = NEGATIVE quality = NEGATIVE
/datum/spacevine_mutation/aggressive_spread/on_spread(obj/structure/spacevine/holder, turf/target) /datum/spacevine_mutation/aggressive_spread/on_spread(obj/structure/spacevine/holder, turf/target)
target.ex_act(severity, null, src) // vine immunity handled at /mob/ex_act switch(severity)
if(EXPLODE_DEVASTATE)
SSexplosions.highturf += target
if(EXPLODE_HEAVY)
SSexplosions.medturf += target
if(EXPLODE_LIGHT)
SSexplosions.lowturf += target
/datum/spacevine_mutation/aggressive_spread/on_buckle(obj/structure/spacevine/holder, mob/living/buckled) /datum/spacevine_mutation/aggressive_spread/on_buckle(obj/structure/spacevine/holder, mob/living/buckled)
buckled.ex_act(severity, null, src) buckled.ex_act(severity, null, src)

View File

@@ -179,7 +179,7 @@
/obj/machinery/bsa/full/proc/fire(mob/user, turf/bullseye) /obj/machinery/bsa/full/proc/fire(mob/user, turf/bullseye)
var/turf/point = get_front_turf() var/turf/point = get_front_turf()
for(var/turf/T in getline(get_step(point,dir),get_target_turf())) for(var/turf/T in getline(get_step(point,dir),get_target_turf()))
T.ex_act(EXPLODE_DEVASTATE) SSexplosions.highturf += T //also fucks everything else on the turf
point.Beam(get_target_turf(),icon_state="bsa_beam",time=50,maxdistance = world.maxx) //ZZZAP point.Beam(get_target_turf(),icon_state="bsa_beam",time=50,maxdistance = world.maxx) //ZZZAP
new /obj/effect/temp_visual/bsa_splash(point, dir) new /obj/effect/temp_visual/bsa_splash(point, dir)
if(user.client) if(user.client)

View File

@@ -150,7 +150,7 @@
for(var/turf/T in linked) for(var/turf/T in linked)
if(prob(30)) if(prob(30))
do_sparks(2, 1, T) do_sparks(2, 1, T)
T.ex_act(EXPLODE_LIGHT) SSexplosions.lowturf += T
T.hotspot_expose(1000,500,1) T.hotspot_expose(1000,500,1)
if(!(obj_flags & EMAGGED)) if(!(obj_flags & EMAGGED))

View File

@@ -33,6 +33,17 @@
beaker = null beaker = null
update_icon() update_icon()
/obj/machinery/biogenerator/contents_explosion(severity, target)
..()
if(beaker)
switch(severity)
if(EXPLODE_DEVASTATE)
SSexplosions.high_mov_atom += beaker
if(EXPLODE_HEAVY)
SSexplosions.med_mov_atom += beaker
if(EXPLODE_LIGHT)
SSexplosions.low_mov_atom += beaker
/obj/machinery/biogenerator/RefreshParts() /obj/machinery/biogenerator/RefreshParts()
var/E = 0 var/E = 0
var/P = 0 var/P = 0

View File

@@ -102,7 +102,7 @@
return Leap(AM) return Leap(AM)
return 0 return 0
/obj/item/clothing/mask/facehugger/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback) /obj/item/clothing/mask/facehugger/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, quickstart = TRUE)
if(!..()) if(!..())
return return
if(stat == CONSCIOUS) if(stat == CONSCIOUS)

View File

@@ -415,9 +415,14 @@
switch (severity) switch (severity)
if (EXPLODE_DEVASTATE) if (EXPLODE_DEVASTATE)
if(bomb_armor < EXPLODE_GIB_THRESHOLD) //gibs the mob if their bomb armor is lower than EXPLODE_GIB_THRESHOLD if(bomb_armor < EXPLODE_GIB_THRESHOLD) //gibs the mob if their bomb armor is lower than EXPLODE_GIB_THRESHOLD
for(var/I in contents) for(var/thing in contents)
var/atom/A = I switch(severity)
A.ex_act(severity) if(EXPLODE_DEVASTATE)
SSexplosions.high_mov_atom += thing
if(EXPLODE_HEAVY)
SSexplosions.med_mov_atom += thing
if(EXPLODE_LIGHT)
SSexplosions.low_mov_atom += thing
gib() gib()
return return
else else

View File

@@ -177,7 +177,7 @@
for(var/obj/item/I in M.held_items) for(var/obj/item/I in M.held_items)
if(!istype(M, /obj/item/clothing)) if(!istype(M, /obj/item/clothing))
if(prob(I.block_chance*2)) if(prob(I.block_chance*2))
return return
/mob/living/get_photo_description(obj/item/camera/camera) /mob/living/get_photo_description(obj/item/camera/camera)
var/list/mob_details = list() var/list/mob_details = list()
@@ -591,7 +591,7 @@
if(pulling) if(pulling)
update_pull_movespeed() update_pull_movespeed()
. = ..() . = ..()
if(pulledby && moving_diagonally != FIRST_DIAG_STEP && get_dist(src, pulledby) > 1 && (pulledby != moving_from_pull))//separated from our puller and not in the middle of a diagonal move. if(pulledby && moving_diagonally != FIRST_DIAG_STEP && get_dist(src, pulledby) > 1 && (pulledby != moving_from_pull))//separated from our puller and not in the middle of a diagonal move.
@@ -960,7 +960,7 @@
return TRUE return TRUE
return FALSE return FALSE
/mob/living/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback) /mob/living/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, quickstart = TRUE)
stop_pulling() stop_pulling()
. = ..() . = ..()

View File

@@ -14,6 +14,7 @@
rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
deathsound = 'sound/voice/borg_deathsound.ogg' deathsound = 'sound/voice/borg_deathsound.ogg'
speech_span = SPAN_ROBOT speech_span = SPAN_ROBOT
flags_1 = PREVENT_CONTENTS_EXPLOSION_1 | HEAR_1
var/datum/ai_laws/laws = null//Now... THEY ALL CAN ALL HAVE LAWS var/datum/ai_laws/laws = null//Now... THEY ALL CAN ALL HAVE LAWS
var/last_lawchange_announce = 0 var/last_lawchange_announce = 0
@@ -72,9 +73,6 @@
/mob/living/silicon/contents_explosion(severity, target) /mob/living/silicon/contents_explosion(severity, target)
return return
/mob/living/silicon/prevent_content_explosion()
return TRUE
/mob/living/silicon/proc/cancelAlarm() /mob/living/silicon/proc/cancelAlarm()
return return
@@ -331,7 +329,7 @@
return return
if(world.time < client.crew_manifest_delay) if(world.time < client.crew_manifest_delay)
return return
client.crew_manifest_delay = world.time + (1 SECONDS) client.crew_manifest_delay = world.time + (1 SECONDS)
var/datum/browser/popup = new(src, "airoster", "Crew Manifest", 387, 420) var/datum/browser/popup = new(src, "airoster", "Crew Manifest", 387, 420)
popup.set_content(GLOB.data_core.get_manifest_html()) popup.set_content(GLOB.data_core.get_manifest_html())

View File

@@ -474,7 +474,10 @@ Difficulty: Hard
/mob/living/simple_animal/hostile/megafauna/bubblegum/Bump(atom/A) /mob/living/simple_animal/hostile/megafauna/bubblegum/Bump(atom/A)
if(charging) if(charging)
if(isturf(A) || isobj(A) && A.density) if(isturf(A) || isobj(A) && A.density)
A.ex_act(EXPLODE_HEAVY) if(isobj(A))
SSexplosions.med_mov_atom += A
else
SSexplosions.medturf += A
DestroySurroundings() DestroySurroundings()
if(isliving(A)) if(isliving(A))
var/mob/living/L = A var/mob/living/L = A

View File

@@ -259,7 +259,10 @@ Difficulty: Very Hard
/obj/item/projectile/colossus/on_hit(atom/target, blocked = FALSE) /obj/item/projectile/colossus/on_hit(atom/target, blocked = FALSE)
. = ..() . = ..()
if(isturf(target) || isobj(target)) if(isturf(target) || isobj(target))
target.ex_act(EXPLODE_HEAVY) if(isobj(target))
SSexplosions.med_mov_atom += target
else
SSexplosions.medturf += target
/obj/item/gps/internal/colossus /obj/item/gps/internal/colossus
icon_state = null icon_state = null

View File

@@ -28,6 +28,7 @@
mob_size = MOB_SIZE_HUGE mob_size = MOB_SIZE_HUGE
layer = LARGE_MOB_LAYER //Looks weird with them slipping under mineral walls and cameras and shit otherwise layer = LARGE_MOB_LAYER //Looks weird with them slipping under mineral walls and cameras and shit otherwise
mouse_opacity = MOUSE_OPACITY_OPAQUE // Easier to click on in melee, they're giant targets anyway mouse_opacity = MOUSE_OPACITY_OPAQUE // Easier to click on in melee, they're giant targets anyway
flags_1 = PREVENT_CONTENTS_EXPLOSION_1
var/list/crusher_loot var/list/crusher_loot
var/elimination = FALSE var/elimination = FALSE
var/anger_modifier = 0 var/anger_modifier = 0
@@ -67,9 +68,6 @@
return return
return ..() return ..()
/mob/living/simple_animal/hostile/megafauna/prevent_content_explosion()
return TRUE
/mob/living/simple_animal/hostile/megafauna/death(gibbed, var/list/force_grant) /mob/living/simple_animal/hostile/megafauna/death(gibbed, var/list/force_grant)
if(health > 0) if(health > 0)
return return

View File

@@ -142,7 +142,13 @@
// Minor explosions are mostly mitigitated by casing. // Minor explosions are mostly mitigitated by casing.
/obj/machinery/modular_computer/ex_act(severity) /obj/machinery/modular_computer/ex_act(severity)
if(cpu) if(cpu)
cpu.ex_act(severity) switch(severity)
if(EXPLODE_DEVASTATE)
SSexplosions.high_mov_atom += cpu
if(EXPLODE_HEAVY)
SSexplosions.med_mov_atom += cpu
if(EXPLODE_LIGHT)
SSexplosions.low_mov_atom += cpu
..() ..()
// EMPs are similar to explosions, but don't cause physical damage to the casing. Instead they screw up the components // EMPs are similar to explosions, but don't cause physical damage to the casing. Instead they screw up the components

View File

@@ -95,8 +95,8 @@
add_fingerprint(user) add_fingerprint(user)
/obj/item/paperplane/throw_at(atom/target, range, speed, mob/thrower, spin=FALSE, diagonals_first = FALSE, datum/callback/callback) /obj/item/paperplane/throw_at(atom/target, range, speed, mob/thrower, spin=FALSE, diagonals_first = FALSE, datum/callback/callback, quickstart = TRUE)
. = ..(target, range, speed, thrower, FALSE, diagonals_first, callback) . = ..(target, range, speed, thrower, FALSE, diagonals_first, callback, quickstart = TRUE)
/obj/item/paperplane/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) /obj/item/paperplane/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
if(iscarbon(hit_atom)) if(iscarbon(hit_atom))

View File

@@ -10,6 +10,7 @@
righthand_file = 'icons/mob/inhands/equipment/briefcase_righthand.dmi' righthand_file = 'icons/mob/inhands/equipment/briefcase_righthand.dmi'
resistance_flags = FLAMMABLE resistance_flags = FLAMMABLE
var/persistence_id var/persistence_id
flags_1 = PREVENT_CONTENTS_EXPLOSION_1
/obj/item/storage/photo_album/Initialize() /obj/item/storage/photo_album/Initialize()
. = ..() . = ..()

View File

@@ -150,7 +150,7 @@
/obj/item/stock_parts/cell/blob_act(obj/structure/blob/B) /obj/item/stock_parts/cell/blob_act(obj/structure/blob/B)
ex_act(EXPLODE_DEVASTATE) SSexplosions.high_mov_atom += src
/obj/item/stock_parts/cell/proc/get_electrocute_damage() /obj/item/stock_parts/cell/proc/get_electrocute_damage()
if(charge >= 1000) if(charge >= 1000)

View File

@@ -27,7 +27,7 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
var/sprite_number = 0 var/sprite_number = 0
/obj/machinery/gravity_generator/safe_throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = MOVE_FORCE_STRONG) /obj/machinery/gravity_generator/safe_throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = MOVE_FORCE_STRONG, quickstart = TRUE)
return FALSE return FALSE
/obj/machinery/gravity_generator/ex_act(severity, target) /obj/machinery/gravity_generator/ex_act(severity, target)

View File

@@ -77,6 +77,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
icon_state = "darkmatter" icon_state = "darkmatter"
density = TRUE density = TRUE
anchored = TRUE anchored = TRUE
flags_1 = PREVENT_CONTENTS_EXPLOSION_1
var/uid = 1 var/uid = 1
var/static/gl_uid = 1 var/static/gl_uid = 1
light_range = 4 light_range = 4
@@ -879,9 +880,6 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
/obj/machinery/power/supermatter_crystal/contents_explosion(severity, target) /obj/machinery/power/supermatter_crystal/contents_explosion(severity, target)
return return
/obj/machinery/power/supermatter_crystal/prevent_content_explosion()
return TRUE
/obj/machinery/power/supermatter_crystal/engine /obj/machinery/power/supermatter_crystal/engine
is_main_engine = TRUE is_main_engine = TRUE

View File

@@ -473,7 +473,7 @@
var/turf/closed/wall/W = target var/turf/closed/wall/W = target
W.dismantle_wall(TRUE, TRUE) W.dismantle_wall(TRUE, TRUE)
else else
target.ex_act(EXPLODE_HEAVY) SSexplosions.medturf += target
return TRUE return TRUE
if(ismovable(target)) if(ismovable(target))
var/atom/movable/AM = target var/atom/movable/AM = target

View File

@@ -148,7 +148,13 @@
if(prob(wallbreak_chance)) if(prob(wallbreak_chance))
W.dismantle_wall(TRUE, TRUE) W.dismantle_wall(TRUE, TRUE)
else else
loc.ex_act(amount_destruction) switch(amount_destruction)
if(EXPLODE_DEVASTATE)
SSexplosions.highturf += loc
if(EXPLODE_HEAVY)
SSexplosions.medturf += loc
if(EXPLODE_LIGHT)
SSexplosions.lowturf += loc
else else
qdel(src) qdel(src)

View File

@@ -91,7 +91,10 @@
/obj/item/projectile/beam/pulse/on_hit(atom/target, blocked = FALSE) /obj/item/projectile/beam/pulse/on_hit(atom/target, blocked = FALSE)
. = ..() . = ..()
if (!QDELETED(target) && (isturf(target) || istype(target, /obj/structure/))) if (!QDELETED(target) && (isturf(target) || istype(target, /obj/structure/)))
target.ex_act(EXPLODE_HEAVY) if(isobj(target))
SSexplosions.med_mov_atom += target
else
SSexplosions.medturf += target
/obj/item/projectile/beam/pulse/shotgun /obj/item/projectile/beam/pulse/shotgun
damage = 40 damage = 40

View File

@@ -11,7 +11,10 @@
if(A == firer) if(A == firer)
forceMove(A.loc) forceMove(A.loc)
return return
A.ex_act(EXPLODE_HEAVY) if(isobj(A))
SSexplosions.med_mov_atom += A
else if(isturf(A))
SSexplosions.medturf += A
playsound(src.loc, 'sound/effects/meteorimpact.ogg', 40, 1) playsound(src.loc, 'sound/effects/meteorimpact.ogg', 40, 1)
for(var/mob/M in urange(10, src)) for(var/mob/M in urange(10, src))
if(!M.stat) if(!M.stat)

View File

@@ -152,7 +152,13 @@
/obj/machinery/chem_dispenser/contents_explosion(severity, target) /obj/machinery/chem_dispenser/contents_explosion(severity, target)
..() ..()
if(beaker) if(beaker)
beaker.ex_act(severity, target) switch(severity)
if(EXPLODE_DEVASTATE)
SSexplosions.high_mov_atom += beaker
if(EXPLODE_HEAVY)
SSexplosions.med_mov_atom += beaker
if(EXPLODE_LIGHT)
SSexplosions.low_mov_atom += beaker
/obj/machinery/chem_dispenser/handle_atom_del(atom/A) /obj/machinery/chem_dispenser/handle_atom_del(atom/A)
..() ..()

View File

@@ -53,9 +53,21 @@
/obj/machinery/chem_master/contents_explosion(severity, target) /obj/machinery/chem_master/contents_explosion(severity, target)
..() ..()
if(beaker) if(beaker)
beaker.ex_act(severity, target) switch(severity)
if(EXPLODE_DEVASTATE)
SSexplosions.high_mov_atom += beaker
if(EXPLODE_HEAVY)
SSexplosions.med_mov_atom += beaker
if(EXPLODE_LIGHT)
SSexplosions.low_mov_atom += beaker
if(bottle) if(bottle)
bottle.ex_act(severity, target) switch(severity)
if(EXPLODE_DEVASTATE)
SSexplosions.high_mov_atom += bottle
if(EXPLODE_HEAVY)
SSexplosions.med_mov_atom += bottle
if(EXPLODE_LIGHT)
SSexplosions.low_mov_atom += bottle
/obj/machinery/chem_master/handle_atom_del(atom/A) /obj/machinery/chem_master/handle_atom_del(atom/A)
..() ..()

View File

@@ -46,7 +46,13 @@
/obj/machinery/reagentgrinder/contents_explosion(severity, target) /obj/machinery/reagentgrinder/contents_explosion(severity, target)
if(container) if(container)
container.ex_act(severity, target) switch(severity)
if(EXPLODE_DEVASTATE)
SSexplosions.high_mov_atom += container
if(EXPLODE_HEAVY)
SSexplosions.med_mov_atom += container
if(EXPLODE_LIGHT)
SSexplosions.low_mov_atom += container
/obj/machinery/reagentgrinder/RefreshParts() /obj/machinery/reagentgrinder/RefreshParts()
speed = 1 speed = 1

View File

@@ -19,8 +19,14 @@
return ..() return ..()
/obj/structure/bigDelivery/contents_explosion(severity, target) /obj/structure/bigDelivery/contents_explosion(severity, target)
for(var/atom/movable/AM in contents) for(var/thing in contents)
AM.ex_act() switch(severity)
if(EXPLODE_DEVASTATE)
SSexplosions.high_mov_atom += thing
if(EXPLODE_HEAVY)
SSexplosions.med_mov_atom += thing
if(EXPLODE_LIGHT)
SSexplosions.low_mov_atom += thing
/obj/structure/bigDelivery/attackby(obj/item/W, mob/user, params) /obj/structure/bigDelivery/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/destTagger)) if(istype(W, /obj/item/destTagger))
@@ -84,8 +90,14 @@
var/sortTag = 0 var/sortTag = 0
/obj/item/smallDelivery/contents_explosion(severity, target) /obj/item/smallDelivery/contents_explosion(severity, target)
for(var/atom/movable/AM in contents) for(var/thing in contents)
AM.ex_act() switch(severity)
if(EXPLODE_DEVASTATE)
SSexplosions.high_mov_atom += thing
if(EXPLODE_HEAVY)
SSexplosions.med_mov_atom += thing
if(EXPLODE_LIGHT)
SSexplosions.low_mov_atom += thing
/obj/item/smallDelivery/attack_self(mob/user) /obj/item/smallDelivery/attack_self(mob/user)
user.temporarilyRemoveItemFromInventory(src, TRUE) user.temporarilyRemoveItemFromInventory(src, TRUE)

View File

@@ -69,6 +69,7 @@ All ShuttleMove procs go here
/turf/proc/afterShuttleMove(turf/oldT, rotation) /turf/proc/afterShuttleMove(turf/oldT, rotation)
//Dealing with the turf we left behind //Dealing with the turf we left behind
oldT.TransferComponents(src) oldT.TransferComponents(src)
SSexplosions.wipe_turf(src)
var/shuttle_boundary = baseturfs.Find(/turf/baseturf_skipover/shuttle) var/shuttle_boundary = baseturfs.Find(/turf/baseturf_skipover/shuttle)
if(shuttle_boundary) if(shuttle_boundary)
oldT.ScrapeAway(baseturfs.len - shuttle_boundary + 1) oldT.ScrapeAway(baseturfs.len - shuttle_boundary + 1)
@@ -251,7 +252,7 @@ All ShuttleMove procs go here
A.atmosinit() A.atmosinit()
if(A.returnPipenet()) if(A.returnPipenet())
A.addMember(src) A.addMember(src)
build_network() SSair.add_to_rebuild_queue(src)
else else
// atmosinit() calls update_icon(), so we don't need to call it // atmosinit() calls update_icon(), so we don't need to call it
update_icon() update_icon()

View File

@@ -287,7 +287,7 @@
var/mob/living/M = AM var/mob/living/M = AM
M.Paralyze(stun_amt) M.Paralyze(stun_amt)
to_chat(M, "<span class='userdanger'>You're thrown back by [user]!</span>") to_chat(M, "<span class='userdanger'>You're thrown back by [user]!</span>")
AM.safe_throw_at(throwtarget, ((clamp((maxthrow - (clamp(distfromcaster - 2, 0, distfromcaster))), 3, maxthrow))), 1,user, force = repulse_force)//So stuff gets tossed around at the same time. AM.safe_throw_at(throwtarget, ((clamp((maxthrow - (clamp(distfromcaster - 2, 0, distfromcaster))), 3, maxthrow))), 1,user, force = repulse_force, quickstart = TRUE)//So stuff gets tossed around at the same time.
/obj/effect/proc_holder/spell/aoe_turf/repulse/xeno //i fixed conflicts only to find out that this is in the WIZARD file instead of the xeno file?! /obj/effect/proc_holder/spell/aoe_turf/repulse/xeno //i fixed conflicts only to find out that this is in the WIZARD file instead of the xeno file?!
name = "Tail Sweep" name = "Tail Sweep"
@@ -364,7 +364,7 @@
M.electrocute_act(80, src, illusion = 1) M.electrocute_act(80, src, illusion = 1)
qdel(src) qdel(src)
/obj/item/spellpacket/lightningbolt/throw_at(atom/target, range, speed, mob/thrower, spin=TRUE, diagonals_first = FALSE, datum/callback/callback, force = INFINITY) /obj/item/spellpacket/lightningbolt/throw_at(atom/target, range, speed, mob/thrower, spin=TRUE, diagonals_first = FALSE, datum/callback/callback, force = INFINITY, quickstart = TRUE)
. = ..() . = ..()
if(ishuman(thrower)) if(ishuman(thrower))
var/mob/living/carbon/human/H = thrower var/mob/living/carbon/human/H = thrower

View File

@@ -115,7 +115,7 @@
var/mob/living/silicon/borg = target var/mob/living/silicon/borg = target
borg.adjustBruteLoss(melee_damage_lower) borg.adjustBruteLoss(melee_damage_lower)
return ..() return ..()
/mob/living/simple_animal/hostile/swarmer/MiddleClickOn(atom/A) /mob/living/simple_animal/hostile/swarmer/MiddleClickOn(atom/A)
. = ..() . = ..()
if(!LAZYLEN(dronelist)) if(!LAZYLEN(dronelist))
@@ -199,7 +199,7 @@
new /obj/effect/temp_visual/swarmer/disintegration(get_turf(target)) new /obj/effect/temp_visual/swarmer/disintegration(get_turf(target))
do_attack_animation(target) do_attack_animation(target)
changeNext_move(CLICK_CD_MELEE) changeNext_move(CLICK_CD_MELEE)
target.ex_act(EXPLODE_LIGHT) SSexplosions.low_mov_atom += target
/** /**
* Called when a swarmer attempts to teleport a living entity away * Called when a swarmer attempts to teleport a living entity away
@@ -220,9 +220,9 @@
if(!do_mob(src, target, 30)) if(!do_mob(src, target, 30))
return return
teleport_target(target) teleport_target(target)
/mob/living/simple_animal/hostile/swarmer/proc/teleport_target(mob/living/target) /mob/living/simple_animal/hostile/swarmer/proc/teleport_target(mob/living/target)
var/turf/open/floor/safe_turf = find_safe_turf(zlevels = z, extended_safety_checks = TRUE) var/turf/open/floor/safe_turf = find_safe_turf(zlevels = z, extended_safety_checks = TRUE)
@@ -416,7 +416,7 @@
// TODO get swarmers their own colour rather than just boldtext // TODO get swarmers their own colour rather than just boldtext
if(message) if(message)
swarmer_chat(message) swarmer_chat(message)
/** /**
* Removes a drone from the swarmer's list. * Removes a drone from the swarmer's list.
* *
@@ -440,7 +440,7 @@ mob/living/simple_animal/hostile/swarmer/proc/remove_drone(mob/drone, force)
AIStatus = AI_ON AIStatus = AI_ON
melee_damage_lower = 30 melee_damage_lower = 30
melee_damage_upper = 30 melee_damage_upper = 30
/obj/item/projectile/beam/disabler/swarmer/on_hit(atom/target, blocked = FALSE) /obj/item/projectile/beam/disabler/swarmer/on_hit(atom/target, blocked = FALSE)
. = ..() . = ..()
if(!.) if(!.)

BIN
sound/effects/creak1.ogg Normal file

Binary file not shown.

BIN
sound/effects/creak2.ogg Normal file

Binary file not shown.

BIN
sound/effects/creak3.ogg Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -266,6 +266,7 @@
#include "code\controllers\subsystem\disease.dm" #include "code\controllers\subsystem\disease.dm"
#include "code\controllers\subsystem\economy.dm" #include "code\controllers\subsystem\economy.dm"
#include "code\controllers\subsystem\events.dm" #include "code\controllers\subsystem\events.dm"
#include "code\controllers\subsystem\explosions.dm"
#include "code\controllers\subsystem\fire_burning.dm" #include "code\controllers\subsystem\fire_burning.dm"
#include "code\controllers\subsystem\garbage.dm" #include "code\controllers\subsystem\garbage.dm"
#include "code\controllers\subsystem\icon_smooth.dm" #include "code\controllers\subsystem\icon_smooth.dm"
@@ -337,7 +338,6 @@
#include "code\datums\embedding_behavior.dm" #include "code\datums\embedding_behavior.dm"
#include "code\datums\emotes.dm" #include "code\datums\emotes.dm"
#include "code\datums\ert.dm" #include "code\datums\ert.dm"
#include "code\datums\explosion.dm"
#include "code\datums\forced_movement.dm" #include "code\datums\forced_movement.dm"
#include "code\datums\holocall.dm" #include "code\datums\holocall.dm"
#include "code\datums\http.dm" #include "code\datums\http.dm"

View File

@@ -57,7 +57,7 @@
throw_at(thrownby, throw_range+3, throw_speed, null) throw_at(thrownby, throw_range+3, throw_speed, null)
..() ..()
/obj/item/toy/boomerang/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force) /obj/item/toy/boomerang/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, quickstart = TRUE)
if(iscarbon(thrower)) if(iscarbon(thrower))
var/mob/living/carbon/C = thrower var/mob/living/carbon/C = thrower
C.throw_mode_on() C.throw_mode_on()