mirror of
https://github.com/yogstation13/Yogstation.git
synced 2025-02-26 09:04:50 +00:00
Refactors explosions (#26361)
This commit is contained in:
@@ -1079,18 +1079,17 @@ B --><-- A
|
|||||||
return L
|
return L
|
||||||
|
|
||||||
//similar function to RANGE_TURFS(), but will search spiralling outwards from the center (like the above, but only turfs)
|
//similar function to RANGE_TURFS(), but will search spiralling outwards from the center (like the above, but only turfs)
|
||||||
/proc/spiral_range_turfs(dist=0, center=usr, orange=0)
|
/proc/spiral_range_turfs(dist=0, center=usr, orange=0, list/outlist = list(), tick_checked)
|
||||||
|
outlist.Cut()
|
||||||
if(!dist)
|
if(!dist)
|
||||||
if(!orange)
|
outlist += center
|
||||||
return list(center)
|
return outlist
|
||||||
else
|
|
||||||
return list()
|
|
||||||
|
|
||||||
var/turf/t_center = get_turf(center)
|
var/turf/t_center = get_turf(center)
|
||||||
if(!t_center)
|
if(!t_center)
|
||||||
return list()
|
return outlist
|
||||||
|
|
||||||
var/list/L = list()
|
var/list/L = outlist
|
||||||
var/turf/T
|
var/turf/T
|
||||||
var/y
|
var/y
|
||||||
var/x
|
var/x
|
||||||
@@ -1128,6 +1127,8 @@ B --><-- A
|
|||||||
if(T)
|
if(T)
|
||||||
L += T
|
L += T
|
||||||
c_dist++
|
c_dist++
|
||||||
|
if(tick_checked)
|
||||||
|
CHECK_TICK
|
||||||
|
|
||||||
return L
|
return L
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,48 @@
|
|||||||
/proc/explosion(turf/epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog = 1, ignorecap = 0, flame_range, silent = 0, smoke = 1)
|
#define EXPLOSION_THROW_SPEED 4
|
||||||
set waitfor = 0
|
|
||||||
src = null //so we don't abort once src is deleted
|
GLOBAL_LIST_EMPTY(explosions)
|
||||||
|
//Against my better judgement, I will return the explosion datum
|
||||||
|
//If I see any GC errors for it I will find you
|
||||||
|
//and I will gib you
|
||||||
|
/proc/explosion(atom/epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog = TRUE, ignorecap = FALSE, flame_range = 0 , silent = FALSE, smoke = FALSE)
|
||||||
|
return new /datum/explosion(epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog, ignorecap, flame_range, silent, smoke)
|
||||||
|
|
||||||
|
//This datum creates 3 async tasks
|
||||||
|
//1 GatherSpiralTurfsProc runs spiral_range_turfs(tick_checked = TRUE) to populate the affected_turfs list
|
||||||
|
//2 CaculateExplosionBlock adds the blockings to the cached_exp_block list
|
||||||
|
//3 The main thread explodes the prepared turfs
|
||||||
|
|
||||||
|
/datum/explosion
|
||||||
|
var/explosion_id
|
||||||
|
var/started_at
|
||||||
|
var/running = TRUE
|
||||||
|
var/stopped = 0 //This is the number of threads stopped !DOESN'T COUNT THREAD 2!
|
||||||
|
var/static/id_counter = 0
|
||||||
|
|
||||||
|
#define EX_PREPROCESS_EXIT_CHECK \
|
||||||
|
if(!running) {\
|
||||||
|
stopped = 2;\
|
||||||
|
qdel(src);\
|
||||||
|
return;\
|
||||||
|
}
|
||||||
|
|
||||||
|
#define EX_PREPROCESS_CHECK_TICK \
|
||||||
|
if(TICK_CHECK) {\
|
||||||
|
stoplag();\
|
||||||
|
EX_PREPROCESS_EXIT_CHECK\
|
||||||
|
}
|
||||||
|
|
||||||
|
/datum/explosion/New(atom/epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog, ignorecap, flame_range, silent, smoke)
|
||||||
|
set waitfor = FALSE
|
||||||
|
|
||||||
|
var/id = ++id_counter
|
||||||
|
explosion_id = id
|
||||||
|
|
||||||
epicenter = get_turf(epicenter)
|
epicenter = get_turf(epicenter)
|
||||||
if(!epicenter)
|
if(!epicenter)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
GLOB.explosions += src
|
||||||
if(isnull(flame_range))
|
if(isnull(flame_range))
|
||||||
flame_range = light_impact_range
|
flame_range = light_impact_range
|
||||||
if(isnull(flash_range))
|
if(isnull(flash_range))
|
||||||
@@ -30,14 +68,13 @@
|
|||||||
//I would make this not ex_act the thing that triggered the explosion,
|
//I would make this not ex_act the thing that triggered the explosion,
|
||||||
//but everything that explodes gives us their loc or a get_turf()
|
//but everything that explodes gives us their loc or a get_turf()
|
||||||
//and somethings expect us to ex_act them so they can qdel()
|
//and somethings expect us to ex_act them so they can qdel()
|
||||||
sleep(1) //tldr, let the calling proc call qdel(src) before we explode
|
stoplag() //tldr, let the calling proc call qdel(src) before we explode
|
||||||
|
|
||||||
var/static/explosionid = 1
|
EX_PREPROCESS_EXIT_CHECK
|
||||||
var/id = explosionid++
|
|
||||||
var/start = world.timeofday
|
started_at = REALTIMEOFDAY
|
||||||
|
|
||||||
var/max_range = max(devastation_range, heavy_impact_range, light_impact_range, flame_range)
|
var/max_range = max(devastation_range, heavy_impact_range, light_impact_range, flame_range)
|
||||||
var/list/cached_exp_block = list()
|
|
||||||
|
|
||||||
if(adminlog)
|
if(adminlog)
|
||||||
message_admins("Explosion with size ([devastation_range], [heavy_impact_range], [light_impact_range], [flame_range]) in area: [get_area(epicenter)] [ADMIN_COORDJMP(epicenter)]")
|
message_admins("Explosion with size ([devastation_range], [heavy_impact_range], [light_impact_range], [flame_range]) in area: [get_area(epicenter)] [ADMIN_COORDJMP(epicenter)]")
|
||||||
@@ -53,23 +90,27 @@
|
|||||||
far_dist += heavy_impact_range * 5
|
far_dist += heavy_impact_range * 5
|
||||||
far_dist += devastation_range * 20
|
far_dist += devastation_range * 20
|
||||||
|
|
||||||
|
var/x0 = epicenter.x
|
||||||
|
var/y0 = epicenter.y
|
||||||
|
var/z0 = epicenter.z
|
||||||
|
|
||||||
if(!silent)
|
if(!silent)
|
||||||
var/frequency = get_rand_frequency()
|
var/frequency = get_rand_frequency()
|
||||||
var/ex_sound = get_sfx("explosion")
|
var/ex_sound = get_sfx("explosion")
|
||||||
for(var/mob/M in GLOB.player_list)
|
for(var/mob/M in GLOB.player_list)
|
||||||
// Double check for client
|
// Double check for client
|
||||||
if(M && M.client)
|
var/turf/M_turf = get_turf(M)
|
||||||
var/turf/M_turf = get_turf(M)
|
if(M_turf && M_turf.z == z0)
|
||||||
if(M_turf && M_turf.z == epicenter.z)
|
var/dist = get_dist(M_turf, epicenter)
|
||||||
var/dist = get_dist(M_turf, epicenter)
|
// If inside the blast radius + world.view - 2
|
||||||
// If inside the blast radius + world.view - 2
|
if(dist <= round(max_range + world.view - 2, 1))
|
||||||
if(dist <= round(max_range + world.view - 2, 1))
|
M.playsound_local(epicenter, ex_sound, 100, 1, frequency, falloff = 5)
|
||||||
M.playsound_local(epicenter, ex_sound, 100, 1, frequency, falloff = 5)
|
// You hear a far explosion if you're outside the blast radius. Small bombs shouldn't be heard all over the station.
|
||||||
// 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)
|
||||||
else if(dist <= far_dist)
|
var/far_volume = Clamp(far_dist, 30, 50) // Volume is based on explosion size and dist
|
||||||
var/far_volume = Clamp(far_dist, 30, 50) // Volume is based on explosion size and dist
|
far_volume += (dist <= far_dist * 0.5 ? 50 : 0) // add 50 volume if the mob is pretty close to the explosion
|
||||||
far_volume += (dist <= far_dist * 0.5 ? 50 : 0) // add 50 volume if the mob is pretty close to the explosion
|
M.playsound_local(epicenter, 'sound/effects/explosionfar.ogg', far_volume, 1, frequency, falloff = 5)
|
||||||
M.playsound_local(epicenter, 'sound/effects/explosionfar.ogg', far_volume, 1, frequency, falloff = 5)
|
EX_PREPROCESS_CHECK_TICK
|
||||||
|
|
||||||
//postpone processing for a bit
|
//postpone processing for a bit
|
||||||
var/postponeCycles = max(round(devastation_range/8),1)
|
var/postponeCycles = max(round(devastation_range/8),1)
|
||||||
@@ -77,66 +118,52 @@
|
|||||||
SSmachines.postpone(postponeCycles)
|
SSmachines.postpone(postponeCycles)
|
||||||
|
|
||||||
if(heavy_impact_range > 1)
|
if(heavy_impact_range > 1)
|
||||||
|
var/datum/effect_system/explosion/E
|
||||||
if(smoke)
|
if(smoke)
|
||||||
var/datum/effect_system/explosion/smoke/E = new/datum/effect_system/explosion/smoke()
|
E = new /datum/effect_system/explosion/smoke
|
||||||
E.set_up(epicenter)
|
|
||||||
E.start()
|
|
||||||
else
|
else
|
||||||
var/datum/effect_system/explosion/E = new/datum/effect_system/explosion()
|
E = new
|
||||||
E.set_up(epicenter)
|
E.set_up(epicenter)
|
||||||
E.start()
|
E.start()
|
||||||
|
|
||||||
var/x0 = epicenter.x
|
EX_PREPROCESS_CHECK_TICK
|
||||||
var/y0 = epicenter.y
|
|
||||||
var/z0 = epicenter.z
|
|
||||||
|
|
||||||
var/list/affected_turfs = spiral_range_turfs(max_range, epicenter)
|
|
||||||
|
|
||||||
if(config.reactionary_explosions)
|
|
||||||
for(var/turf/T in affected_turfs) // we cache the explosion block rating of every turf in the explosion area
|
|
||||||
cached_exp_block[T] = 0
|
|
||||||
if(T.density && T.explosion_block)
|
|
||||||
cached_exp_block[T] += T.explosion_block
|
|
||||||
|
|
||||||
for(var/obj/machinery/door/D in T)
|
|
||||||
if(D.density && D.explosion_block)
|
|
||||||
cached_exp_block[T] += D.explosion_block
|
|
||||||
|
|
||||||
for(var/obj/structure/window/W in T)
|
|
||||||
if(W.reinf && W.fulltile)
|
|
||||||
cached_exp_block[T] += W.explosion_block
|
|
||||||
|
|
||||||
for(var/obj/structure/blob/B in T)
|
|
||||||
cached_exp_block[T] += B.explosion_block
|
|
||||||
CHECK_TICK
|
|
||||||
|
|
||||||
//flash mobs
|
//flash mobs
|
||||||
if(flash_range)
|
if(flash_range)
|
||||||
for(var/mob/living/L in viewers(flash_range, epicenter))
|
for(var/mob/living/L in viewers(flash_range, epicenter))
|
||||||
L.flash_act()
|
L.flash_act()
|
||||||
|
|
||||||
CHECK_TICK
|
EX_PREPROCESS_CHECK_TICK
|
||||||
|
|
||||||
var/list/exploded_this_tick = list() //open turfs that need to be blocked off while we sleep
|
var/list/exploded_this_tick = list() //open turfs that need to be blocked off while we sleep
|
||||||
for(var/turf/T in affected_turfs)
|
var/list/affected_turfs = GatherSpiralTurfs(max_range, epicenter)
|
||||||
|
|
||||||
if (!T)
|
var/reactionary = config.reactionary_explosions
|
||||||
continue
|
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
|
||||||
|
|
||||||
|
var/iteration = 0
|
||||||
|
var/affTurfLen = affected_turfs.len
|
||||||
|
var/expBlockLen = cached_exp_block.len
|
||||||
|
for(var/TI in affected_turfs)
|
||||||
|
var/turf/T = TI
|
||||||
|
++iteration
|
||||||
var/init_dist = cheap_hypotenuse(T.x, T.y, x0, y0)
|
var/init_dist = cheap_hypotenuse(T.x, T.y, x0, y0)
|
||||||
var/dist = init_dist
|
var/dist = init_dist
|
||||||
|
|
||||||
if(config.reactionary_explosions)
|
if(reactionary)
|
||||||
var/turf/Trajectory = T
|
var/turf/Trajectory = T
|
||||||
while(Trajectory != epicenter)
|
while(Trajectory != epicenter)
|
||||||
Trajectory = get_step_towards(Trajectory, epicenter)
|
Trajectory = get_step_towards(Trajectory, epicenter)
|
||||||
dist += cached_exp_block[Trajectory]
|
dist += cached_exp_block[Trajectory]
|
||||||
|
|
||||||
var/flame_dist = 0
|
var/flame_dist = dist < flame_range
|
||||||
var/throw_dist = dist
|
var/throw_dist = dist
|
||||||
|
|
||||||
if(dist < flame_range)
|
|
||||||
flame_dist = 1
|
|
||||||
|
|
||||||
if(dist < devastation_range)
|
if(dist < devastation_range)
|
||||||
dist = 1
|
dist = 1
|
||||||
else if(dist < heavy_impact_range)
|
else if(dist < heavy_impact_range)
|
||||||
@@ -148,27 +175,61 @@
|
|||||||
|
|
||||||
//------- EX_ACT AND TURF FIRES -------
|
//------- EX_ACT AND TURF FIRES -------
|
||||||
|
|
||||||
if(T)
|
if(flame_dist && prob(40) && !isspaceturf(T) && !T.density)
|
||||||
if(flame_dist && prob(40) && !isspaceturf(T) && !T.density)
|
new /obj/effect/hotspot(T) //Mostly for ambience!
|
||||||
new /obj/effect/hotspot(T) //Mostly for ambience!
|
|
||||||
if(dist > 0)
|
if(dist > 0)
|
||||||
T.explosion_level = max(T.explosion_level, dist) //let the bigger one have it
|
T.explosion_level = max(T.explosion_level, dist) //let the bigger one have it
|
||||||
T.explosion_id = id
|
T.explosion_id = id
|
||||||
T.ex_act(dist)
|
T.ex_act(dist)
|
||||||
exploded_this_tick += T
|
exploded_this_tick += T
|
||||||
|
|
||||||
//--- THROW ITEMS AROUND ---
|
//--- THROW ITEMS AROUND ---
|
||||||
|
|
||||||
var/throw_dir = get_dir(epicenter,T)
|
var/throw_dir = get_dir(epicenter,T)
|
||||||
for(var/obj/item/I in T)
|
for(var/obj/item/I in T)
|
||||||
if(I && !I.anchored)
|
if(!I.anchored)
|
||||||
var/throw_range = rand(throw_dist, max_range)
|
var/throw_range = rand(throw_dist, max_range)
|
||||||
var/turf/throw_at = get_ranged_target_turf(I, throw_dir, throw_range)
|
var/turf/throw_at = get_ranged_target_turf(I, throw_dir, throw_range)
|
||||||
I.throw_speed = 4 //Temporarily change their throw_speed for embedding purposes (Reset when it finishes throwing, regardless of hitting anything)
|
I.throw_speed = EXPLOSION_THROW_SPEED //Temporarily change their throw_speed for embedding purposes (Reset when it finishes throwing, regardless of hitting anything)
|
||||||
I.throw_at(throw_at, throw_range, I.throw_speed)
|
I.throw_at(throw_at, throw_range, EXPLOSION_THROW_SPEED)
|
||||||
|
|
||||||
if(TICK_CHECK)
|
//wait for the lists to repop
|
||||||
|
var/break_condition
|
||||||
|
if(reactionary)
|
||||||
|
//If we've caught up to the density checker thread and there are no more turfs to process
|
||||||
|
break_condition = iteration == expBlockLen && iteration < affTurfLen
|
||||||
|
else
|
||||||
|
//If we've caught up to the turf gathering thread and it's still running
|
||||||
|
break_condition = iteration == affTurfLen && !stopped
|
||||||
|
|
||||||
|
if(break_condition || TICK_CHECK)
|
||||||
stoplag()
|
stoplag()
|
||||||
|
|
||||||
|
if(!running)
|
||||||
|
break
|
||||||
|
|
||||||
|
//update the trackers
|
||||||
|
affTurfLen = affected_turfs.len
|
||||||
|
expBlockLen = cached_exp_block.len
|
||||||
|
|
||||||
|
if(break_condition)
|
||||||
|
if(reactionary)
|
||||||
|
//until there are more block checked turfs than what we are currently at
|
||||||
|
//or the explosion has stopped
|
||||||
|
UNTIL(iteration < affTurfLen || !running)
|
||||||
|
else
|
||||||
|
//until there are more gathered turfs than what we are currently at
|
||||||
|
//or there are no more turfs to gather/the explosion has stopped
|
||||||
|
UNTIL(iteration < expBlockLen || stopped)
|
||||||
|
|
||||||
|
if(!running)
|
||||||
|
break
|
||||||
|
|
||||||
|
//update the trackers
|
||||||
|
affTurfLen = affected_turfs.len
|
||||||
|
expBlockLen = cached_exp_block.len
|
||||||
|
|
||||||
var/circumference = (PI * (init_dist + 4) * 2) //+4 to radius to prevent shit gaps
|
var/circumference = (PI * (init_dist + 4) * 2) //+4 to radius to prevent shit gaps
|
||||||
if(exploded_this_tick.len > circumference) //only do this every revolution
|
if(exploded_this_tick.len > circumference) //only do this every revolution
|
||||||
for(var/Unexplode in exploded_this_tick)
|
for(var/Unexplode in exploded_this_tick)
|
||||||
@@ -182,24 +243,67 @@
|
|||||||
UnexplodeT.explosion_level = 0
|
UnexplodeT.explosion_level = 0
|
||||||
exploded_this_tick.Cut()
|
exploded_this_tick.Cut()
|
||||||
|
|
||||||
var/took = (world.timeofday-start)/10
|
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
|
|
||||||
|
//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)
|
if(GLOB.Debug2)
|
||||||
log_world("## DEBUG: Explosion([x0],[y0],[z0])(d[devastation_range],h[heavy_impact_range],l[light_impact_range]): Took [took] seconds.")
|
log_world("## DEBUG: Explosion([x0],[y0],[z0])(d[devastation_range],h[heavy_impact_range],l[light_impact_range]): Took [took] seconds.")
|
||||||
|
|
||||||
//Machines which report explosions.
|
if(!stopped) //if we aren't in a hurry
|
||||||
for(var/array in GLOB.doppler_arrays)
|
//Machines which report explosions.
|
||||||
var/obj/machinery/doppler_array/A = array
|
for(var/array in GLOB.doppler_arrays)
|
||||||
A.sense_explosion(epicenter,devastation_range,heavy_impact_range,light_impact_range,took,orig_dev_range,orig_heavy_range,orig_light_range)
|
var/obj/machinery/doppler_array/A = array
|
||||||
|
A.sense_explosion(epicenter, devastation_range, heavy_impact_range, light_impact_range, took,orig_dev_range, orig_heavy_range, orig_light_range)
|
||||||
|
|
||||||
return 1
|
++stopped
|
||||||
|
qdel(src)
|
||||||
|
|
||||||
|
#undef EX_PREPROCESS_EXIT_CHECK
|
||||||
|
#undef EX_PREPROCESS_CHECK_TICK
|
||||||
|
|
||||||
|
//asyncly populate the affected_turfs list
|
||||||
|
/datum/explosion/proc/GatherSpiralTurfs(range, turf/epicenter)
|
||||||
|
set waitfor = FALSE
|
||||||
|
. = list()
|
||||||
|
spiral_range_turfs(range, epicenter, outlist = ., tick_checked = TRUE)
|
||||||
|
++stopped
|
||||||
|
|
||||||
/proc/secondaryexplosion(turf/epicenter, range)
|
/datum/explosion/proc/CaculateExplosionBlock(list/affected_turfs)
|
||||||
for(var/turf/tile in spiral_range_turfs(range, epicenter))
|
set waitfor = FALSE
|
||||||
tile.ex_act(2)
|
|
||||||
|
|
||||||
|
. = list()
|
||||||
|
var/processed = 0
|
||||||
|
while(!stopped && running)
|
||||||
|
var/I
|
||||||
|
for(I in (processed + 1) to affected_turfs.len) // we cache the explosion block rating of every turf in the explosion area
|
||||||
|
var/turf/T = affected_turfs[I]
|
||||||
|
var/current_exp_block = T.density ? T.explosion_block : 0
|
||||||
|
|
||||||
|
for(var/obj/machinery/door/D in T)
|
||||||
|
if(D.density)
|
||||||
|
current_exp_block += D.explosion_block
|
||||||
|
|
||||||
|
for(var/obj/structure/window/W in T)
|
||||||
|
if(W.reinf && W.fulltile)
|
||||||
|
current_exp_block += W.explosion_block
|
||||||
|
|
||||||
|
for(var/obj/structure/blob/B in T)
|
||||||
|
current_exp_block += B.explosion_block
|
||||||
|
|
||||||
|
.[T] = current_exp_block
|
||||||
|
|
||||||
|
if(TICK_CHECK)
|
||||||
|
break
|
||||||
|
|
||||||
|
processed = I
|
||||||
|
stoplag()
|
||||||
|
|
||||||
|
/datum/explosion/Destroy()
|
||||||
|
running = FALSE
|
||||||
|
if(stopped < 2) //wait for main thread and spiral_range thread
|
||||||
|
return QDEL_HINT_IWILLGC
|
||||||
|
GLOB.explosions -= src
|
||||||
|
return ..()
|
||||||
|
|
||||||
/client/proc/check_bomb_impacts()
|
/client/proc/check_bomb_impacts()
|
||||||
set name = "Check Bomb Impact"
|
set name = "Check Bomb Impact"
|
||||||
@@ -274,7 +274,6 @@
|
|||||||
return
|
return
|
||||||
|
|
||||||
/atom/proc/ex_act(severity, target)
|
/atom/proc/ex_act(severity, target)
|
||||||
set waitfor = FALSE
|
|
||||||
contents_explosion(severity, target)
|
contents_explosion(severity, target)
|
||||||
|
|
||||||
/atom/proc/blob_act(obj/structure/blob/B)
|
/atom/proc/blob_act(obj/structure/blob/B)
|
||||||
|
|||||||
@@ -217,6 +217,7 @@
|
|||||||
#include "code\datums\dna.dm"
|
#include "code\datums\dna.dm"
|
||||||
#include "code\datums\dog_fashion.dm"
|
#include "code\datums\dog_fashion.dm"
|
||||||
#include "code\datums\emotes.dm"
|
#include "code\datums\emotes.dm"
|
||||||
|
#include "code\datums\explosion.dm"
|
||||||
#include "code\datums\forced_movement.dm"
|
#include "code\datums\forced_movement.dm"
|
||||||
#include "code\datums\holocall.dm"
|
#include "code\datums\holocall.dm"
|
||||||
#include "code\datums\hud.dm"
|
#include "code\datums\hud.dm"
|
||||||
@@ -655,7 +656,6 @@
|
|||||||
#include "code\game\mecha\working\working.dm"
|
#include "code\game\mecha\working\working.dm"
|
||||||
#include "code\game\objects\buckling.dm"
|
#include "code\game\objects\buckling.dm"
|
||||||
#include "code\game\objects\empulse.dm"
|
#include "code\game\objects\empulse.dm"
|
||||||
#include "code\game\objects\explosion.dm"
|
|
||||||
#include "code\game\objects\items.dm"
|
#include "code\game\objects\items.dm"
|
||||||
#include "code\game\objects\obj_defense.dm"
|
#include "code\game\objects\obj_defense.dm"
|
||||||
#include "code\game\objects\objs.dm"
|
#include "code\game\objects\objs.dm"
|
||||||
|
|||||||
Reference in New Issue
Block a user