Optimizes explosions (very slightly) (#71763)

## About The Pull Request

We do two major things here.
First, instead of having every turf need to ask all the turfs in "front"
of it for its blast resistance, we have blast resistance carry back in a
cache, so they only need to ask the one directly in front of them.
Much faster, such wow

The other thing we do is totally remove the idea of "building" a turf's
explosion resistance. Instead, a turf's full resistance is stored on it
at all times.
We use an element to manage objects that want to block explosives, and
that's it simple as.
As an optimization, turfs handle block differently, using a system where
we imply that a turf's own block is just the initial of their
explosive_resistance, unless proven otherwise
This also saves a significant amount of time

To be honest with you, I did this mostly cause I wanted to well make
explosions faster
This doesn't really fufil that. They are faster, but not by much
The bulk of explosion cost comes from actually exploding things, rather
then figuring out what/how to delete.
This code is much faster for larger blastwave sizes, because calculating
protection is constant.

We save maybe 60% of propogate_blastwave, but unfortunately
propogate_blastwave for one maxcap on the top left of icebox's chapel is
only 28ms, so while 11ms is good, it's not everything I could want when
the cost of explosion/fire is 555ms.

I'm happy about it still tho, because doing things like this means I can
expand on how explosive blocking works without needing to make things
seriously expensive in here.
Also it's faster for meme admin explosions and mega burgers

## Why It's Good For The Game

Speeds up explosives slightly, opens the door to better blast resistance
projection
This commit is contained in:
LemonInTheDark
2023-01-09 22:29:03 -08:00
committed by GitHub
parent 612c041dbc
commit 858da9f19a
29 changed files with 284 additions and 190 deletions
@@ -11,3 +11,5 @@
/// When returned on a signal hooked to [COMSIG_ATOM_EXPLODE], [COMSIG_ATOM_INTERNAL_EXPLOSION], or [COMSIG_AREA_INTERNAL_EXPLOSION] it prevents the explosion from being propagated further.
#define COMSIG_CANCEL_EXPLOSION (1<<0)
/// from [/atom/movable/proc/set_explosion_resistance] : (old_block, new_block)
#define COMSIG_MOVABLE_EXPLOSION_BLOCK_CHANGED "explosion_block_changed"
-3
View File
@@ -18,9 +18,6 @@
/// Gibtonite will now explode
#define GIBTONITE_DETONATE 3
/// For object explosion block calculation
#define EXPLOSION_BLOCK_PROC -1
/// A wrapper for [/atom/proc/ex_act] to ensure that the explosion propagation and attendant signal are always handled.
#define EX_ACT(target, args...)\
if(!(target.flags_1 & PREVENT_CONTENTS_EXPLOSION_1)) { \
+1
View File
@@ -281,3 +281,4 @@ GLOBAL_LIST_INIT(book_types, typecacheof(list(
#define is_unassigned_job(job_type) (istype(job_type, /datum/job/unassigned))
#define isprojectilespell(thing) (istype(thing, /datum/action/cooldown/spell/pointed/projectile))
#define is_multi_tile_object(atom) (atom.bound_width > world.icon_size || atom.bound_height > world.icon_size)
+4
View File
@@ -237,5 +237,9 @@
#define GET_TRUE_DIST(a, b) (a == null || b == null) ? -1 : max(abs(a.x -b.x), abs(a.y-b.y), abs(a.z-b.z))
//We used to use linear regression to approximate the answer, but Mloc realized this was actually faster.
//And lo and behold, it is, and it's more accurate to boot.
#define CHEAP_HYPOTENUSE(Ax, Ay, Bx, By) (sqrt(abs(Ax - Bx) ** 2 + abs(Ay - By) ** 2)) //A squared + B squared = C squared
/// The number of cells in a taxicab circle (rasterized diamond) of radius X.
#define DIAMOND_AREA(X) (1 + 2*(X)*((X)+1))
+2
View File
@@ -517,6 +517,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_PARALYSIS "paralysis"
/// Used for limbs.
#define TRAIT_DISABLED_BY_WOUND "disabled-by-wound"
/// This movable atom has the explosive block element
#define TRAIT_BLOCKING_EXPLOSIVES "blocking_explosives"
/// Mobs with this trait can't send the mining shuttle console when used outside the station itself
#define TRAIT_FORBID_MINING_SHUTTLE_CONSOLE_OUTSIDE_STATION "forbid_mining_shuttle_console_outside_station"
-6
View File
@@ -11,12 +11,6 @@
return null
return format_text ? format_text(checked_area.name) : checked_area.name
//We used to use linear regression to approximate the answer, but Mloc realized this was actually faster.
//And lo and behold, it is, and it's more accurate to boot.
///Calculate the hypotenuse cheaply (this should be in maths.dm)
/proc/cheap_hypotenuse(Ax, Ay, Bx, By)
return sqrt(abs(Ax - Bx) ** 2 + abs(Ay - By) ** 2) //A squared + B squared = C squared
/** toggle_organ_decay
* inputs: first_object (object to start with)
* outputs:
+107 -139
View File
@@ -119,30 +119,31 @@ SUBSYSTEM_DEF(explosions)
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)
var/list/cached_exp_block = list()
for(var/turf/explode in prepare_explosion_turfs(max_range, epicenter))
wipe_colours += explode
var/our_x = explode.x
var/our_y = explode.y
var/dist = CHEAP_HYPOTENUSE(our_x, our_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(explode != epicenter)
var/our_block = cached_exp_block[get_step_towards(explode, epicenter)]
dist += our_block
cached_exp_block[explode] = our_block + explode.explosive_resistance
else
cached_exp_block[explode] = explode.explosive_resistance
dist = round(dist, 0.01)
if(dist < dev)
T.color = "red"
T.maptext = MAPTEXT("Dev")
explode.color = "red"
explode.maptext = MAPTEXT("[dist]")
else if (dist < heavy)
T.color = "yellow"
T.maptext = MAPTEXT("Heavy")
explode.color = "yellow"
explode.maptext = MAPTEXT("[dist]")
else if (dist < light)
T.color = "blue"
T.maptext = MAPTEXT("Light")
explode.color = "blue"
explode.maptext = MAPTEXT("[dist]")
else
continue
@@ -379,82 +380,77 @@ SUBSYSTEM_DEF(explosions)
for(var/mob/living/L in viewers(flash_range, epicenter))
L.flash_act()
var/list/affected_turfs = GatherSpiralTurfs(max_range, epicenter)
var/list/affected_turfs = prepare_explosion_turfs(max_range, epicenter)
var/reactionary = CONFIG_GET(flag/reactionary_explosions)
var/list/cached_exp_block
if(reactionary)
cached_exp_block = CaculateExplosionBlock(affected_turfs)
// this list is setup in the form position -> block for that position
// we assert that turfs will be processed closed to farthest, so we can build this as we go along
// This is gonna be an array, index'd by turfs
var/list/cached_exp_block = list()
//lists are guaranteed to contain at least 1 turf at this point
//we presuppose that we'll be iterating away from the epicenter
for(var/turf/explode as anything in affected_turfs)
var/our_x = explode.x
var/our_y = explode.y
var/dist = CHEAP_HYPOTENUSE(our_x, our_y, x0, y0)
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
// Using this pattern, block will flow out from blocking turfs, essentially caching the recursion
// This is safe because if get_step_towards is ever anything but caridnally off, it'll do a diagonal move
// So we always sample from a "loop" closer
// It's kind of behaviorly unimpressive that that's a problem for the future
if(reactionary)
var/turf/Trajectory = T
while(Trajectory != epicenter)
Trajectory = get_step_towards(Trajectory, epicenter)
dist += cached_exp_block[Trajectory]
if(explode == epicenter)
cached_exp_block[explode] = explode.explosive_resistance
else
var/our_block = cached_exp_block[get_step_towards(explode, epicenter)]
dist += our_block
cached_exp_block[explode] = our_block + explode.explosive_resistance
var/flame_dist = dist < flame_range
var/throw_dist = dist
var/severity = EXPLODE_NONE
if(dist < devastation_range)
dist = EXPLODE_DEVASTATE
severity = EXPLODE_DEVASTATE
else if(dist < heavy_impact_range)
dist = EXPLODE_HEAVY
severity = EXPLODE_HEAVY
else if(dist < light_impact_range)
dist = EXPLODE_LIGHT
else
dist = EXPLODE_NONE
severity = EXPLODE_LIGHT
if(T == epicenter) // Ensures explosives detonating from bags trigger other explosives in that bag
if(explode == 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.get_all_contents(ignore_flag_1 = PREVENT_CONTENTS_EXPLOSION_1)
if(isliving(A))
items -= A //Stops mobs from taking double damage from explosions originating from them/their turf, such as from projectiles
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)
for(var/atom/holder as anything in explode)
if (length(holder.contents) && !(holder.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 += holder.get_all_contents(ignore_flag_1 = PREVENT_CONTENTS_EXPLOSION_1)
if(isliving(holder))
items -= holder //Stops mobs from taking double damage from explosions originating from them/their turf, such as from projectiles
switch(severity)
if(EXPLODE_DEVASTATE)
SSexplosions.high_mov_atom += items
if(EXPLODE_HEAVY)
SSexplosions.med_mov_atom += items
if(EXPLODE_LIGHT)
SSexplosions.low_mov_atom += items
switch(severity)
if(EXPLODE_DEVASTATE)
SSexplosions.highturf += T
SSexplosions.highturf += explode
if(EXPLODE_HEAVY)
SSexplosions.medturf += T
SSexplosions.medturf += explode
if(EXPLODE_LIGHT)
SSexplosions.lowturf += T
SSexplosions.lowturf += explode
if(flame_dist && prob(40) && !isspaceturf(T) && !T.density)
flameturf += T
if(prob(40) && dist < flame_range && !isspaceturf(explode) && !explode.density)
flameturf += explode
//--- 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
if (explode.explosion_throw_details)
var/list/throwingturf = explode.explosion_throw_details
if (throwingturf[1] < max_range - dist)
throwingturf[1] = max_range - dist
throwingturf[2] = get_dir(epicenter, explode)
throwingturf[3] = max_range
else
T.explosion_throw_details = list(throw_range, throw_dir, max_range)
throwturf += T
explode.explosion_throw_details = list(max_range - dist, get_dir(epicenter, explode), max_range)
throwturf += explode
var/took = (REALTIMEOFDAY - started_at) / 10
@@ -572,68 +568,40 @@ SUBSYSTEM_DEF(explosions)
#undef FREQ_UPPER
#undef FREQ_LOWER
/datum/controller/subsystem/explosions/proc/GatherSpiralTurfs(range, turf/epicenter)
/// Returns a list of turfs in X range from the epicenter
/// Returns in a unique order, spiraling outwards
/// This is done to ensure our progressive cache of blast resistance is always valid
/// This is quite fast
/proc/prepare_explosion_turfs(range, turf/epicenter)
var/list/outlist = list()
var/center = epicenter
var/dist = range
if(!dist)
outlist += center
return outlist
// Add in the center
outlist += epicenter
var/turf/t_center = get_turf(center)
if(!t_center)
return outlist
var/our_x = epicenter.x
var/our_y = epicenter.y
var/our_z = epicenter.z
var/list/L = outlist
var/turf/T
var/y
var/x
var/c_dist = 1
L += t_center
var/max_x = world.maxx
var/max_y = world.maxy
for(var/i in 1 to range)
var/lowest_x = our_x - i
var/lowest_y = our_y - i
var/highest_x = our_x + i
var/highest_y = our_y + i
// top left to one before top right
if(highest_y <= max_y)
outlist += block(locate(max(lowest_x, 1), highest_y, our_z), locate(min(highest_x - 1, max_x), highest_y, our_z))
// top right to one before bottom right
if(highest_x <= max_x)
outlist += block(locate(highest_x, min(highest_y, max_y), our_z), locate(highest_x, max(lowest_y + 1, 1), our_z))
// bottom right to one before bottom left
if(lowest_y >= 1)
outlist += block(locate(min(highest_x, max_x), lowest_y, our_z), locate(max(lowest_x + 1, 1), lowest_y, our_z))
// bottom left to one before top left
if(lowest_x >= 1)
outlist += block(locate(lowest_x, max(lowest_y, 1), our_z), locate(lowest_x, min(highest_y - 1, max_y), our_z))
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
return outlist
/datum/controller/subsystem/explosions/fire(resumed = 0)
if (!is_exploding())
@@ -722,15 +690,15 @@ SUBSYSTEM_DEF(explosions)
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)
var/turf/explode = thing
var/list/details = explode.explosion_throw_details
explode.explosion_throw_details = null
if (length(details) != 3)
continue
var/throw_range = L[1]
var/throw_dir = L[2]
var/max_range = L[3]
for(var/atom/movable/A in T)
var/throw_range = details[1]
var/throw_dir = details[2]
var/max_range = details[3]
for(var/atom/movable/A in explode)
if(QDELETED(A))
continue
if(!A.anchored && A.move_resist != INFINITY)
+56
View File
@@ -0,0 +1,56 @@
/// Apply this element to a movable atom when you want it to block explosions
/// It will mirror the blocking down to that movable's turf, keeping explosion work cheap
/datum/element/blocks_explosives
/datum/element/blocks_explosives/Attach(datum/target)
if(!ismovable(target))
return
. = ..()
ADD_TRAIT(target, TRAIT_BLOCKING_EXPLOSIVES, TRAIT_GENERIC)
var/atom/movable/moving_target = target
RegisterSignal(moving_target, COMSIG_MOVABLE_MOVED, PROC_REF(blocker_moved))
RegisterSignal(moving_target, COMSIG_MOVABLE_EXPLOSION_BLOCK_CHANGED, PROC_REF(blocking_changed))
moving_target.explosive_resistance = moving_target.explosion_block
if(length(moving_target.locs) > 1)
for(var/atom/location as anything in moving_target.locs)
block_loc(location, moving_target.explosion_block)
else if(moving_target.loc)
block_loc(moving_target.loc, moving_target.explosion_block)
/datum/element/blocks_explosives/Detach(datum/source)
. = ..()
REMOVE_TRAIT(source, TRAIT_BLOCKING_EXPLOSIVES, TRAIT_GENERIC)
/// Call this when our blocking well, changes. we'll update our turf(s) with the details
/datum/element/blocks_explosives/proc/blocking_changed(atom/movable/target, old_block, new_block)
if(length(target.locs) > 1)
for(var/atom/location as anything in target.locs)
unblock_loc(location, old_block)
block_loc(location, new_block)
else if(target.loc)
unblock_loc(target.loc, old_block)
block_loc(target.loc, new_block)
/// Applies a block amount to a turf. proc for convenince
/datum/element/blocks_explosives/proc/block_loc(atom/location, block_amount)
location.explosive_resistance += block_amount
/// Removes a block amount from a turf. proc for convenince
/datum/element/blocks_explosives/proc/unblock_loc(atom/location, block_amount)
location.explosive_resistance -= block_amount
/// Essentially just blocking_changed except we remove from the old loc, and add to the new one
/datum/element/blocks_explosives/proc/blocker_moved(atom/movable/target, atom/old_loc, dir, forced, list/old_locs)
if(length(old_locs) > 1)
for(var/atom/location as anything in old_locs)
unblock_loc(location, target.explosion_block)
else if(old_loc)
unblock_loc(old_loc, target.explosion_block)
if(length(target.locs) > 1)
for(var/atom/location as anything in target.locs)
block_loc(location, target.explosion_block)
else if(target.loc)
block_loc(target.loc, target.explosion_block)
+6 -2
View File
@@ -39,8 +39,8 @@
///HUD images that this atom can provide.
var/list/hud_possible
///Value used to increment ex_act() if reactionary_explosions is on
var/explosion_block = 0
///How much this atom resists explosions by, in the end
var/explosive_resistance = 0
/**
* used to store the different colors on an atom
@@ -1850,6 +1850,10 @@
pixel_y = pixel_y + base_pixel_y - .
// Not a valid operation, turfs and movables handle block differently
/atom/proc/set_explosion_block(explosion_block)
return
/**
* Returns true if this atom has gravity for the passed in turf
*
+18 -1
View File
@@ -94,6 +94,11 @@
/// The degree of pressure protection that mobs in list/contents have from the external environment, between 0 and 1
var/contents_pressure_protection = 0
/// Value used to increment ex_act() if reactionary_explosions is on
/// How much we as a source block explosions by
/// Will not automatically apply to the turf below you, you need to apply /datum/element/block_explosives in conjunction with this
var/explosion_block = 0
/mutable_appearance/emissive_blocker
/mutable_appearance/emissive_blocker/New()
@@ -104,6 +109,11 @@
/atom/movable/Initialize(mapload)
. = ..()
#ifdef UNIT_TESTS
if(explosion_block && !HAS_TRAIT(src, TRAIT_BLOCKING_EXPLOSIVES))
stack_trace("[type] blocks explosives, but does not have the managing element applied")
#endif
switch(blocks_emissive)
if(EMISSIVE_BLOCK_GENERIC)
var/static/mutable_appearance/emissive_blocker/blocker = new()
@@ -515,7 +525,7 @@
if(set_dir_on_move && dir != direction && update_dir)
setDir(direction)
var/is_multi_tile_object = bound_width > 32 || bound_height > 32
var/is_multi_tile_object = is_multi_tile_object(src)
var/list/old_locs
if(is_multi_tile_object && isturf(loc))
@@ -1129,6 +1139,13 @@
return TRUE
/atom/movable/set_explosion_block(explosion_block)
var/old_block = src.explosion_block
explosive_resistance -= old_block
src.explosion_block = explosion_block
explosive_resistance += explosion_block
SEND_SIGNAL(src, COMSIG_MOVABLE_EXPLOSION_BLOCK_CHANGED, old_block, explosion_block)
/atom/movable/proc/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
set waitfor = FALSE
var/hitpush = TRUE
+17 -4
View File
@@ -57,6 +57,7 @@
acid = 70
/obj/machinery/door/Initialize(mapload)
AddElement(/datum/element/blocks_explosives)
. = ..()
set_init_door_layer()
update_freelook_sight()
@@ -72,7 +73,7 @@
//doors only block while dense though so we have to use the proc
real_explosion_block = explosion_block
explosion_block = EXPLOSION_BLOCK_PROC
update_explosive_block()
RegisterSignal(SSsecurity_level, COMSIG_SECURITY_LEVEL_CHANGED, PROC_REF(check_security_level))
var/static/list/loc_connections = list(
@@ -483,9 +484,6 @@
//if it blows up a wall it should blow up a door
return ..(severity ? min(EXPLODE_DEVASTATE, severity + 1) : EXPLODE_NONE, target)
/obj/machinery/door/GetExplosionBlock()
return density ? real_explosion_block : 0
/obj/machinery/door/power_change()
. = ..()
if(. && !(machine_stat & NOPOWER))
@@ -501,4 +499,19 @@
INVOKE_ASYNC(src, PROC_REF(open))
/obj/machinery/door/set_density(new_value)
. = ..()
update_explosive_block()
/obj/machinery/door/proc/update_explosive_block()
set_explosion_block(real_explosion_block)
// Kinda roundabout, essentially if we're dense, we respect real_explosion_block
// Otherwise, we block nothing
/obj/machinery/door/set_explosion_block(explosion_block)
real_explosion_block = explosion_block
if(density)
return ..()
return ..(0)
#undef DOOR_CLOSE_WAIT
+1 -1
View File
@@ -1008,7 +1008,7 @@ GLOBAL_VAR_INIT(icon_holographic_window, init_holographic_window())
if(istype(O))
var/x0 = O.x
var/y0 = O.y
var/contender = cheap_hypotenuse(start.x, start.y, x0, y0)
var/contender = CHEAP_HYPOTENUSE(start.x, start.y, x0, y0)
if(!winner)
winner = O
winning_dist = contender
+1
View File
@@ -210,6 +210,7 @@
acid = 100
/obj/structure/light_puzzle/Initialize(mapload)
AddElement(/datum/element/blocks_explosives)
. = ..()
var/generated_board = -1
while(generated_board in banned_combinations)
+4 -6
View File
@@ -40,6 +40,7 @@
acid = 100
/obj/structure/window/Initialize(mapload, direct)
AddElement(/datum/element/blocks_explosives)
. = ..()
if(direct)
setDir(direct)
@@ -55,9 +56,9 @@
setDir()
AddElement(/datum/element/can_barricade)
//windows only block while reinforced and fulltile, so we'll use the proc
real_explosion_block = explosion_block
explosion_block = EXPLOSION_BLOCK_PROC
//windows only block while reinforced and fulltile
if(!reinf || !fulltile)
set_explosion_block(0)
flags_1 |= ALLOW_DARK_PAINTS_1
RegisterSignal(src, COMSIG_OBJ_PAINTED, PROC_REF(on_painted))
@@ -424,9 +425,6 @@
return TRUE
/obj/structure/window/GetExplosionBlock()
return reinf && fulltile ? real_explosion_block : 0
/obj/structure/window/spawner/east
dir = EAST
+5
View File
@@ -78,6 +78,9 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
var/old_dynamic_lumcount = dynamic_lumcount
var/old_rcd_memory = rcd_memory
var/old_always_lit = always_lit
var/old_explosion_throw_details = explosion_throw_details
// We get just the bits of explosive_resistance that aren't the turf
var/old_explosive_resistance = explosive_resistance - get_explosive_block()
var/old_lattice_underneath = lattice_underneath
var/old_bp = blueprint_data
@@ -117,6 +120,8 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
new_turf.blueprint_data = old_bp
new_turf.rcd_memory = old_rcd_memory
new_turf.explosion_throw_details = old_explosion_throw_details
new_turf.explosive_resistance += old_explosive_resistance
lighting_corner_NE = old_lighting_corner_NE
lighting_corner_SE = old_lighting_corner_SE
+3 -3
View File
@@ -20,7 +20,7 @@
name = "wall"
desc = "Effectively impervious to conventional methods of destruction."
icon = 'icons/turf/walls.dmi'
explosion_block = 50
explosive_resistance = 50
/turf/closed/indestructible/rust_heretic_act()
return
@@ -280,7 +280,7 @@ INITIALIZE_IMMEDIATE(/turf/closed/indestructible/splashscreen)
desc = "A seemingly impenetrable wall."
icon = 'icons/turf/walls.dmi'
icon_state = "necro"
explosion_block = 50
explosive_resistance = 50
baseturfs = /turf/closed/indestructible/necropolis
/turf/closed/indestructible/necropolis/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir)
@@ -308,7 +308,7 @@ INITIALIZE_IMMEDIATE(/turf/closed/indestructible/splashscreen)
smoothing_flags = SMOOTH_BITMASK
smoothing_groups = SMOOTH_GROUP_CLOSED_TURFS + SMOOTH_GROUP_BOSS_WALLS
canSmoothWith = SMOOTH_GROUP_BOSS_WALLS
explosion_block = 50
explosive_resistance = 50
baseturfs = /turf/closed/indestructible/riveted/boss
/turf/closed/indestructible/riveted/boss/see_through
+8 -8
View File
@@ -15,7 +15,7 @@
base_icon_state = "gold_wall"
sheet_type = /obj/item/stack/sheet/mineral/gold
hardness = 65 //gold is soft
explosion_block = 0 //gold is a soft metal you dingus.
explosive_resistance = 0 //gold is a soft metal you dingus.
smoothing_groups = SMOOTH_GROUP_GOLD_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS
canSmoothWith = SMOOTH_GROUP_GOLD_WALLS
custom_materials = list(/datum/material/gold = 4000)
@@ -42,7 +42,7 @@
sheet_type = /obj/item/stack/sheet/mineral/diamond
hardness = 5 //diamond is very hard
slicing_duration = 200 //diamond wall takes twice as much time to slice
explosion_block = 3
explosive_resistance = 3
smoothing_flags = SMOOTH_BITMASK
smoothing_groups = SMOOTH_GROUP_DIAMOND_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS
canSmoothWith = SMOOTH_GROUP_DIAMOND_WALLS
@@ -72,7 +72,7 @@
base_icon_state = "sandstone_wall"
sheet_type = /obj/item/stack/sheet/mineral/sandstone
hardness = 50 //moh says this is apparently 6-7 on it's scale
explosion_block = 0
explosive_resistance = 0
smoothing_flags = SMOOTH_BITMASK
smoothing_groups = SMOOTH_GROUP_SANDSTONE_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS
canSmoothWith = SMOOTH_GROUP_SANDSTONE_WALLS
@@ -158,7 +158,7 @@
sheet_type = /obj/item/stack/sheet/mineral/wood
hardness = 80
turf_flags = IS_SOLID
explosion_block = 0
explosive_resistance = 0
smoothing_flags = SMOOTH_BITMASK
smoothing_groups = SMOOTH_GROUP_WOOD_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS
canSmoothWith = SMOOTH_GROUP_WOOD_WALLS
@@ -215,7 +215,7 @@
base_icon_state = "snow_wall"
smoothing_flags = SMOOTH_BITMASK
hardness = 80
explosion_block = 0
explosive_resistance = 0
slicing_duration = 30
sheet_type = /obj/item/stack/sheet/mineral/snow
canSmoothWith = null
@@ -236,7 +236,7 @@
sheet_type = /obj/item/stack/sheet/mineral/abductor
hardness = 10
slicing_duration = 200 //alien wall takes twice as much time to slice
explosion_block = 3
explosive_resistance = 3
smoothing_flags = SMOOTH_BITMASK | SMOOTH_DIAGONAL_CORNERS
smoothing_groups = SMOOTH_GROUP_ABDUCTOR_WALLS + SMOOTH_GROUP_WALLS + SMOOTH_GROUP_CLOSED_TURFS
canSmoothWith = SMOOTH_GROUP_ABDUCTOR_WALLS
@@ -250,7 +250,7 @@
icon = 'icons/turf/walls/shuttle_wall.dmi'
icon_state = "shuttle_wall-0"
base_icon_state = "shuttle_wall"
explosion_block = 3
explosive_resistance = 3
flags_1 = CAN_BE_DIRTY_1
flags_ricochet = RICOCHET_SHINY | RICOCHET_HARD
sheet_type = /obj/item/stack/sheet/mineral/titanium
@@ -314,7 +314,7 @@
icon = 'icons/turf/walls/plastitanium_wall.dmi'
icon_state = "plastitanium_wall-0"
base_icon_state = "plastitanium_wall"
explosion_block = 4
explosive_resistance = 4
sheet_type = /obj/item/stack/sheet/mineral/plastitanium
hardness = 25 //upgrade on titanium
smoothing_flags = SMOOTH_BITMASK | SMOOTH_DIAGONAL_CORNERS
+2 -2
View File
@@ -12,7 +12,7 @@
sheet_type = /obj/item/stack/sheet/plasteel
sheet_amount = 1
girder_type = /obj/structure/girder/reinforced
explosion_block = 2
explosive_resistance = 2
rad_insulation = RAD_HEAVY_INSULATION
heat_capacity = 312500 //a little over 5 cm thick , 312500 for 1 m by 2.5 m by 0.25 m plasteel wall. also indicates the temperature at wich the wall will melt (currently only able to melt with H/E pipes)
///Dismantled state, related to deconstruction.
@@ -233,7 +233,7 @@
icon = 'icons/turf/walls/plastitanium_wall.dmi'
icon_state = "plastitanium_wall-0"
base_icon_state = "plastitanium_wall"
explosion_block = 20
explosive_resistance = 20
sheet_type = /obj/item/stack/sheet/mineral/plastitanium
hardness = 25 //plastitanium
turf_flags = IS_SOLID
+2 -2
View File
@@ -6,7 +6,7 @@
icon = 'icons/turf/walls/wall.dmi'
icon_state = "wall-0"
base_icon_state = "wall"
explosion_block = 1
explosive_resistance = 1
thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT
heat_capacity = 62500 //a little over 5 cm thick , 62500 for 1 m by 2.5 m by 0.25 m iron wall. also indicates the temperature at wich the wall will melt (currently only able to melt with H/E pipes)
@@ -266,7 +266,7 @@
return null
/turf/closed/wall/acid_act(acidpwr, acid_volume)
if(explosion_block >= 2)
if(get_explosive_block() >= 2)
acidpwr = min(acidpwr, 50) //we reduce the power so strong walls never get melted.
return ..()
+1 -1
View File
@@ -5,7 +5,7 @@
dir = SOUTH
baseturfs = /turf/open/space/transit
flags_1 = NOJAUNT //This line goes out to every wizard that ever managed to escape the den. I'm sorry.
explosion_block = INFINITY
explosive_resistance = INFINITY
/turf/open/space/transit/Initialize(mapload)
. = ..()
+32
View File
@@ -92,6 +92,12 @@ GLOBAL_LIST_EMPTY(station_turfs)
/// Sorry for the mess
var/area/in_contents_of
#endif
/// How much explosive resistance this turf is providing to itself
/// Defaults to -1, interpreted as initial(explosive_resistance)
/// This is an optimization to prevent turfs from needing to set these on init
/// This would either be expensive, or impossible to manage. Let's just avoid it yes?
/// Never directly access this, use get_explosive_block() instead
var/inherent_explosive_resistance = -1
/turf/vv_edit_var(var_name, new_value)
var/static/list/banned_edits = list(NAMEOF_STATIC(src, x), NAMEOF_STATIC(src, y), NAMEOF_STATIC(src, z))
@@ -673,6 +679,26 @@ GLOBAL_LIST_EMPTY(station_turfs)
continue
movable_content.wash(clean_types)
/turf/set_density(new_value)
var/old_density = density
. = ..()
if(old_density == density)
return
if(old_density)
explosive_resistance -= get_explosive_block()
if(density)
explosive_resistance += get_explosive_block()
/// Wrapper around inherent_explosive_resistance
/// We assume this proc is cold, so we can move the "what is our block" into it
/turf/proc/get_explosive_block()
if(inherent_explosive_resistance != -1)
return inherent_explosive_resistance
if(explosive_resistance)
return initial(explosive_resistance)
return 0
/**
* Returns adjacent turfs to this turf that are reachable, in all cardinal directions
*
@@ -702,3 +728,9 @@ GLOBAL_LIST_EMPTY(station_turfs)
/turf/proc/TakeTemperature(temp)
temperature += temp
// I'm sorry, this is the only way that both makes sense and is cheap
/turf/set_explosion_block(explosion_block)
explosive_resistance -= get_explosive_block()
inherent_explosive_resistance = explosion_block
explosive_resistance += get_explosive_block()
@@ -32,6 +32,7 @@
overmind.blobstrain.on_gain()
update_appearance()
AddComponent(/datum/component/stationloving, FALSE, TRUE)
AddElement(/datum/element/blocks_explosives)
return ..()
/obj/structure/blob/special/core/Destroy()
@@ -16,6 +16,10 @@
fire = 90
acid = 90
/obj/structure/blob/shield/Initialize(mapload, owner_overmind)
AddElement(/datum/element/blocks_explosives)
return ..()
/obj/structure/blob/shield/scannerreport()
if(atmosblock)
return "Will prevent the spread of atmospheric changes."
+1 -1
View File
@@ -5,7 +5,7 @@
icon_state = "cordon"
invisibility = INVISIBILITY_ABSTRACT
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
explosion_block = INFINITY
explosive_resistance = INFINITY
rad_insulation = RAD_FULL_INSULATION
opacity = TRUE
density = TRUE
-1
View File
@@ -165,7 +165,6 @@
resistance_flags = NONE
species_exception = list(/datum/species/golem)
// Lemom todo: and here
/obj/item/clothing/suit/hazardvest/worn_overlays(mutable_appearance/standing, isinhands, icon_file)
. = ..()
if(!isinhands)
@@ -26,6 +26,7 @@
var/slicing_duration = 100
/obj/structure/tramwall/Initialize(mapload)
AddElement(/datum/element/blocks_explosives)
. = ..()
var/obj/item/stack/initialized_mineral = new mineral
set_custom_materials(initialized_mineral.mats_per_unit, mineral_amount)
@@ -230,7 +230,7 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999))
icon_state = "hotelwall"
smoothing_groups = SMOOTH_GROUP_CLOSED_TURFS + SMOOTH_GROUP_HOTEL_WALLS
canSmoothWith = SMOOTH_GROUP_HOTEL_WALLS
explosion_block = INFINITY
explosive_resistance = INFINITY
/turf/open/indestructible/hotelwood
desc = "Stylish dark wood with extra reinforcement. Secured firmly to the floor to prevent tampering."
@@ -250,7 +250,7 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999))
base_icon_state = "bluespace"
baseturfs = /turf/open/space/bluespace
flags_1 = NOJAUNT
explosion_block = INFINITY
explosive_resistance = INFINITY
var/obj/item/hilbertshotel/parentSphere
/turf/open/space/bluespace/Initialize(mapload)
@@ -269,7 +269,7 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999))
/turf/closed/indestructible/hoteldoor
name = "Hotel Door"
icon_state = "hoteldoor"
explosion_block = INFINITY
explosive_resistance = INFINITY
var/obj/item/hilbertshotel/parentSphere
/turf/closed/indestructible/hoteldoor/proc/promptExit(mob/living/user)
@@ -322,13 +322,7 @@
var/decrement = 1
var/atom/location = loc
if (reactionary)
if(location.density || !isturf(location))
decrement += location.explosion_block
for(var/obj/thing in location)
if (thing == src)
continue
var/the_block = thing.explosion_block
decrement += the_block == EXPLOSION_BLOCK_PROC ? thing.GetExplosionBlock() : the_block
decrement += location.explosive_resistance
range = max(range - decrement + 1, 0) // Already decremented by 1 in the parent. Exists so that if we pass through something with negative block it extends the range.
heavy_ex_range = max(heavy_ex_range - decrement, 0)
+1
View File
@@ -1079,6 +1079,7 @@
#include "code\datums\elements\beauty.dm"
#include "code\datums\elements\bed_tucking.dm"
#include "code\datums\elements\befriend_petting.dm"
#include "code\datums\elements\blocks_explosives.dm"
#include "code\datums\elements\bsa_blocker.dm"
#include "code\datums\elements\bump_click.dm"
#include "code\datums\elements\can_barricade.dm"