mirror of
https://github.com/yogstation13/Yogstation.git
synced 2025-02-26 09:04:50 +00:00
[Port] Explosions Subsystem Test 1 (#10202)
* Explosions Subsystem Test 1 * Fucking linter * Fucking TG Are Dents * SCREW OFF LINTER
This commit is contained in:
@@ -36,6 +36,9 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
|
||||
var/sleep_delta = 1
|
||||
|
||||
///Only run ticker subsystems for the next n ticks.
|
||||
var/skip_ticks = 0
|
||||
|
||||
var/make_runtime = 0
|
||||
|
||||
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.
|
||||
|
||||
//now do the actual stuff
|
||||
if (!queue_head || !(iteration % 3))
|
||||
if (!skip_ticks)
|
||||
var/checking_runlevel = current_runlevel
|
||||
if(cached_runlevel != checking_runlevel)
|
||||
//resechedule subsystems
|
||||
@@ -388,6 +391,8 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
|
||||
iteration++
|
||||
last_run = world.time
|
||||
if (skip_ticks)
|
||||
skip_ticks--
|
||||
src.sleep_delta = MC_AVERAGE_FAST(src.sleep_delta, sleep_delta)
|
||||
current_ticklimit = TICK_LIMIT_RUNNING
|
||||
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_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
|
||||
//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
|
||||
@@ -590,14 +599,16 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
log_world("MC: SoftReset: Finished.")
|
||||
. = 1
|
||||
|
||||
|
||||
/datum/controller/master/proc/laggy_byond_map_update_incoming()
|
||||
if (!skip_ticks)
|
||||
skip_ticks = 1
|
||||
|
||||
/datum/controller/master/stat_entry()
|
||||
if(!statclick)
|
||||
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("Master Controller:", statclick.update("(TickRate:[Master.processing]) (Iteration:[Master.iteration])"))
|
||||
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]) (TickLimit: [round(Master.current_ticklimit, 0.1)])"))
|
||||
|
||||
/datum/controller/master/StartLoadingMap()
|
||||
//disallow more than one map to load at once, multithreading it will just cause race conditions
|
||||
|
||||
@@ -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)
|
||||
name = "Atmospherics"
|
||||
init_order = INIT_ORDER_AIR
|
||||
@@ -21,12 +12,14 @@ SUBSYSTEM_DEF(air)
|
||||
var/cost_hotspots = 0
|
||||
var/cost_superconductivity = 0
|
||||
var/cost_pipenets = 0
|
||||
var/cost_rebuilds = 0
|
||||
var/cost_atmos_machinery = 0
|
||||
var/cost_equalize = 0
|
||||
|
||||
var/list/active_turfs = list()
|
||||
var/list/hotspots = list()
|
||||
var/list/networks = list()
|
||||
var/list/pipenets_needing_rebuilt = list()
|
||||
var/list/obj/machinery/atmos_machinery = list()
|
||||
var/list/pipe_init_dirs_cache = list()
|
||||
|
||||
@@ -39,7 +32,7 @@ SUBSYSTEM_DEF(air)
|
||||
|
||||
|
||||
var/list/currentrun = list()
|
||||
var/currentpart = SSAIR_PIPENETS
|
||||
var/currentpart = SSAIR_REBUILD_PIPENETS
|
||||
|
||||
var/map_loading = TRUE
|
||||
var/list/queued_for_activation
|
||||
@@ -55,6 +48,7 @@ SUBSYSTEM_DEF(air)
|
||||
msg += "HS:[round(cost_hotspots,1)]|"
|
||||
msg += "SC:[round(cost_superconductivity,1)]|"
|
||||
msg += "PN:[round(cost_pipenets,1)]|"
|
||||
msg += "RB:[round(cost_rebuilds,1)]|"
|
||||
msg += "AM:[round(cost_atmos_machinery,1)]"
|
||||
msg += "} "
|
||||
msg += "AT:[active_turfs.len]|"
|
||||
@@ -79,7 +73,17 @@ SUBSYSTEM_DEF(air)
|
||||
|
||||
/datum/controller/subsystem/air/fire(resumed = 0)
|
||||
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)
|
||||
process_pipenets(resumed)
|
||||
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)
|
||||
return
|
||||
resumed = 0
|
||||
currentpart = SSAIR_PIPENETS
|
||||
currentpart = SSAIR_REBUILD_PIPENETS
|
||||
|
||||
|
||||
|
||||
@@ -168,6 +172,9 @@ SUBSYSTEM_DEF(air)
|
||||
if(MC_TICK_CHECK)
|
||||
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)
|
||||
var/seconds = wait * 0.1
|
||||
@@ -430,12 +437,4 @@ SUBSYSTEM_DEF(air)
|
||||
pipe_init_dirs_cache[type]["[dir]"] = temp.GetInitDirections()
|
||||
qdel(temp)
|
||||
|
||||
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
|
||||
return pipe_init_dirs_cache[type]["[dir]"]
|
||||
564
code/controllers/subsystem/explosions.dm
Normal file
564
code/controllers/subsystem/explosions.dm
Normal 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
|
||||
@@ -341,10 +341,12 @@ SUBSYSTEM_DEF(ticker)
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/station_explosion_detonation(atom/bomb)
|
||||
if(bomb) //BOOM
|
||||
var/turf/epi = bomb.loc
|
||||
qdel(bomb)
|
||||
if(epi)
|
||||
explosion(epi, 0, 256, 512, 0, TRUE, TRUE, 0, TRUE)
|
||||
for(var/T in GLOB.station_turfs)
|
||||
if(prob(33))
|
||||
SSexplosions.highturf += T
|
||||
else
|
||||
SSexplosions.medturf += T
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/create_characters()
|
||||
for(var/mob/dead/new_player/player in GLOB.player_list)
|
||||
|
||||
Reference in New Issue
Block a user