mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-30 00:29:02 +01:00
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:
@@ -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"
|
||||
|
||||
@@ -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)) { \
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
|
||||
*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ..()
|
||||
|
||||
|
||||
@@ -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)
|
||||
. = ..()
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user