mirror of
https://github.com/yogstation13/Yogstation.git
synced 2025-02-26 09:04:50 +00:00
TG performance tweaks - oh-god-please-kill-me-edition ASYNC / SLEEP BAD / Profiler (#10207)
* Im sleepy * Reee * oopsie Linter go brrrr * Update code/datums/components/storage/concrete/bag_of_holding.dm Co-authored-by: Nichlas Pihl <nichlas00100@gmail.com> * Update code/controllers/subsystem/air.dm Co-authored-by: Nichlas Pihl <nichlas00100@gmail.com>
This commit is contained in:
@@ -9,6 +9,8 @@
|
||||
#define CLEAN_IMPRESSIVE 5
|
||||
/// Cleans things spotless down to the atomic structure
|
||||
#define CLEAN_GOD 6
|
||||
/// Never cleaned
|
||||
#define CLEAN_NEVER 7
|
||||
|
||||
//How strong things have to be to wipe forensic evidence...
|
||||
#define CLEAN_STRENGTH_FINGERPRINTS CLEAN_IMPRESSIVE
|
||||
|
||||
@@ -478,3 +478,5 @@ GLOBAL_LIST_INIT(pda_styles, list(MONO, VT, ORBITRON, SHARE))
|
||||
#define ALIGNMENT_NEUT "neutral"
|
||||
#define ALIGNMENT_EVIL "evil"
|
||||
|
||||
// \ref behaviour got changed in 512 so this is necesary to replicate old behaviour.
|
||||
#define REF(thing) (istype(thing, /datum) && (thing:datum_flags & DF_USE_TAG) && thing:tag ? "[thing:tag]" : "\ref[thing]")
|
||||
@@ -98,6 +98,7 @@
|
||||
// Subsystems shutdown in the reverse of the order they initialize in
|
||||
// The numbers just define the ordering, they are meaningless otherwise.
|
||||
|
||||
#define INIT_ORDER_PROFILER 101
|
||||
#define INIT_ORDER_TITLE 100
|
||||
#define INIT_ORDER_GARBAGE 99
|
||||
#define INIT_ORDER_STATPANELS 98
|
||||
|
||||
@@ -174,11 +174,11 @@
|
||||
/proc/recursive_hear_check(O)
|
||||
var/list/processing_list = list(O)
|
||||
. = list()
|
||||
while(processing_list.len)
|
||||
var/atom/A = processing_list[1]
|
||||
var/i = 0
|
||||
while(i < length(processing_list))
|
||||
var/atom/A = processing_list[++i]
|
||||
if(A.flags_1 & HEAR_1)
|
||||
. += A
|
||||
processing_list.Cut(1, 2)
|
||||
processing_list += A.contents
|
||||
|
||||
/** recursive_organ_check
|
||||
@@ -264,10 +264,8 @@
|
||||
// Returns a list of hearers in view(R) from source (ignoring luminosity). Used in saycode.
|
||||
var/turf/T = get_turf(source)
|
||||
. = list()
|
||||
|
||||
if(!T)
|
||||
return
|
||||
|
||||
var/list/processing_list = list()
|
||||
if (R == 0) // if the range is zero, we know exactly where to look for, we can skip view
|
||||
processing_list += T.contents // We can shave off one iteration by assuming turfs cannot hear
|
||||
@@ -280,11 +278,11 @@
|
||||
processing_list += O
|
||||
T.luminosity = lum
|
||||
|
||||
while(processing_list.len) // recursive_hear_check inlined here
|
||||
var/atom/A = processing_list[1]
|
||||
var/i = 0
|
||||
while(i < length(processing_list)) // recursive_hear_check inlined here
|
||||
var/atom/A = processing_list[++i]
|
||||
if(A.flags_1 & HEAR_1)
|
||||
. += A
|
||||
processing_list.Cut(1, 2)
|
||||
processing_list += A.contents
|
||||
|
||||
/proc/get_mobs_in_radio_ranges(list/obj/item/radio/radios)
|
||||
|
||||
@@ -449,38 +449,38 @@ Turf and target are separate in case you want to teleport some distance from a t
|
||||
Gets all contents of contents and returns them all in a list.
|
||||
*/
|
||||
|
||||
/atom/proc/GetAllContents(var/T)
|
||||
/atom/proc/GetAllContents(T, ignore_flag_1)
|
||||
var/list/processing_list = list(src)
|
||||
var/list/assembled = list()
|
||||
if(T)
|
||||
while(processing_list.len)
|
||||
var/atom/A = processing_list[1]
|
||||
processing_list.Cut(1, 2)
|
||||
. = list()
|
||||
var/i = 0
|
||||
while(i < length(processing_list))
|
||||
var/atom/A = processing_list[++i]
|
||||
//Byond does not allow things to be in multiple contents, or double parent-child hierarchies, so only += is needed
|
||||
//This is also why we don't need to check against assembled as we go along
|
||||
processing_list += A.contents
|
||||
if(istype(A,T))
|
||||
assembled += A
|
||||
if (!(A.flags_1 & ignore_flag_1))
|
||||
processing_list += A.contents
|
||||
if(istype(A,T))
|
||||
. += A
|
||||
else
|
||||
while(processing_list.len)
|
||||
var/atom/A = processing_list[1]
|
||||
processing_list.Cut(1, 2)
|
||||
processing_list += A.contents
|
||||
assembled += A
|
||||
return assembled
|
||||
var/i = 0
|
||||
while(i < length(processing_list))
|
||||
var/atom/A = processing_list[++i]
|
||||
if (!(A.flags_1 & ignore_flag_1))
|
||||
processing_list += A.contents
|
||||
return processing_list
|
||||
|
||||
/atom/proc/GetAllContentsIgnoring(list/ignore_typecache)
|
||||
if(!length(ignore_typecache))
|
||||
return GetAllContents()
|
||||
var/list/processing = list(src)
|
||||
var/list/assembled = list()
|
||||
while(processing.len)
|
||||
var/atom/A = processing[1]
|
||||
processing.Cut(1,2)
|
||||
. = list()
|
||||
var/i = 0
|
||||
while(i < length(processing))
|
||||
var/atom/A = processing[++i]
|
||||
if(!ignore_typecache[A.type])
|
||||
processing += A.contents
|
||||
assembled += A
|
||||
return assembled
|
||||
. += A
|
||||
|
||||
//Step-towards method of determining whether one atom can see another. Similar to viewers()
|
||||
/proc/can_see(atom/source, atom/target, length=5) // I couldnt be arsed to do actual raycasting :I This is horribly inaccurate.
|
||||
@@ -1396,20 +1396,6 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
|
||||
|
||||
return "{[time_high]-[time_mid]-[GUID_VERSION][time_low]-[GUID_VARIANT][time_clock]-[node_id]}"
|
||||
|
||||
// \ref behaviour got changed in 512 so this is necesary to replicate old behaviour.
|
||||
// If it ever becomes necesary to get a more performant REF(), this lies here in wait
|
||||
// #define REF(thing) (thing && istype(thing, /datum) && (thing:datum_flags & DF_USE_TAG) && thing:tag ? "[thing:tag]" : "\ref[thing]")
|
||||
/proc/REF(input)
|
||||
if(istype(input, /datum))
|
||||
var/datum/thing = input
|
||||
if(thing.datum_flags & DF_USE_TAG)
|
||||
if(!thing.tag)
|
||||
stack_trace("A ref was requested of an object with DF_USE_TAG set but no tag: [thing]")
|
||||
thing.datum_flags &= ~DF_USE_TAG
|
||||
else
|
||||
return "\[[url_encode(thing.tag)]\]"
|
||||
return "\ref[input]"
|
||||
|
||||
// Makes a call in the context of a different usr
|
||||
// Use sparingly
|
||||
/world/proc/PushUsr(mob/M, datum/callback/CB, ...)
|
||||
|
||||
@@ -495,3 +495,5 @@
|
||||
/datum/config_entry/flag/everyone_is_donator
|
||||
|
||||
/datum/config_entry/string/centcom_ban_db // URL for the CentCom Galactic Ban DB API
|
||||
|
||||
/datum/config_entry/flag/auto_profile
|
||||
@@ -45,9 +45,9 @@
|
||||
return
|
||||
|
||||
//This is used so the mc knows when the subsystem sleeps. do not override.
|
||||
/datum/controller/subsystem/proc/ignite(resumed = 0)
|
||||
/datum/controller/subsystem/proc/ignite(resumed = FALSE)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
set waitfor = 0
|
||||
set waitfor = FALSE
|
||||
. = SS_SLEEPING
|
||||
fire(resumed)
|
||||
. = state
|
||||
@@ -62,7 +62,7 @@
|
||||
//previously, this would have been named 'process()' but that name is used everywhere for different things!
|
||||
//fire() seems more suitable. This is the procedure that gets called every 'wait' deciseconds.
|
||||
//Sleeping in here prevents future fires until returned.
|
||||
/datum/controller/subsystem/proc/fire(resumed = 0)
|
||||
/datum/controller/subsystem/proc/fire(resumed = FALSE)
|
||||
flags |= SS_NO_FIRE
|
||||
CRASH("Subsystem [src]([type]) does not fire() but did not set the SS_NO_FIRE flag. Please add the SS_NO_FIRE flag to any subsystem that doesn't fire so it doesn't get added to the processing list and waste cpu.")
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ SUBSYSTEM_DEF(air)
|
||||
flags = SS_BACKGROUND
|
||||
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
||||
|
||||
var/cached_cost = 0
|
||||
var/cost_turfs = 0
|
||||
var/cost_groups = 0
|
||||
var/cost_highpressure = 0
|
||||
@@ -85,74 +86,93 @@ SUBSYSTEM_DEF(air)
|
||||
resumed = FALSE
|
||||
currentpart = SSAIR_PIPENETS
|
||||
if(currentpart == SSAIR_PIPENETS || !resumed)
|
||||
timer = TICK_USAGE_REAL
|
||||
if(!resumed)
|
||||
cached_cost = 0
|
||||
process_pipenets(resumed)
|
||||
cost_pipenets = MC_AVERAGE(cost_pipenets, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
|
||||
cached_cost += TICK_USAGE_REAL - timer
|
||||
if(state != SS_RUNNING)
|
||||
return
|
||||
resumed = 0
|
||||
cost_pipenets = MC_AVERAGE(cost_pipenets, TICK_DELTA_TO_MS(cached_cost))
|
||||
resumed = FALSE
|
||||
currentpart = SSAIR_ATMOSMACHINERY
|
||||
|
||||
if(currentpart == SSAIR_ATMOSMACHINERY)
|
||||
timer = TICK_USAGE_REAL
|
||||
if(!resumed)
|
||||
cached_cost = 0
|
||||
process_atmos_machinery(resumed)
|
||||
cost_atmos_machinery = MC_AVERAGE(cost_atmos_machinery, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
|
||||
cached_cost += TICK_USAGE_REAL - timer
|
||||
if(state != SS_RUNNING)
|
||||
return
|
||||
resumed = 0
|
||||
cost_atmos_machinery = MC_AVERAGE(cost_atmos_machinery, TICK_DELTA_TO_MS(cached_cost))
|
||||
resumed = FALSE
|
||||
currentpart = SSAIR_EQUALIZE
|
||||
|
||||
if(currentpart == SSAIR_EQUALIZE)
|
||||
timer = TICK_USAGE_REAL
|
||||
if(!resumed)
|
||||
cached_cost = 0
|
||||
process_turf_equalize(resumed)
|
||||
cost_equalize = MC_AVERAGE(cost_equalize, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
|
||||
if(state != SS_RUNNING)
|
||||
return
|
||||
resumed = 0
|
||||
cost_equalize = MC_AVERAGE(cost_equalize, TICK_DELTA_TO_MS(cached_cost))
|
||||
resumed = FALSE
|
||||
currentpart = SSAIR_ACTIVETURFS
|
||||
|
||||
if(currentpart == SSAIR_ACTIVETURFS)
|
||||
timer = TICK_USAGE_REAL
|
||||
if(!resumed)
|
||||
cached_cost = 0
|
||||
process_active_turfs(resumed)
|
||||
cost_turfs = MC_AVERAGE(cost_turfs, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
|
||||
if(state != SS_RUNNING)
|
||||
return
|
||||
resumed = 0
|
||||
cost_turfs = MC_AVERAGE(cost_turfs, TICK_DELTA_TO_MS(cached_cost))
|
||||
resumed = FALSE
|
||||
currentpart = SSAIR_EXCITEDGROUPS
|
||||
|
||||
if(currentpart == SSAIR_EXCITEDGROUPS)
|
||||
timer = TICK_USAGE_REAL
|
||||
if(!resumed)
|
||||
cached_cost = 0
|
||||
process_excited_groups(resumed)
|
||||
cost_groups = MC_AVERAGE(cost_groups, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
|
||||
if(state != SS_RUNNING)
|
||||
return
|
||||
resumed = 0
|
||||
cost_groups = MC_AVERAGE(cost_groups, TICK_DELTA_TO_MS(cached_cost))
|
||||
resumed = FALSE
|
||||
currentpart = SSAIR_HIGHPRESSURE
|
||||
|
||||
if(currentpart == SSAIR_HIGHPRESSURE)
|
||||
timer = TICK_USAGE_REAL
|
||||
if(!resumed)
|
||||
cached_cost = 0
|
||||
process_high_pressure_delta(resumed)
|
||||
cost_highpressure = MC_AVERAGE(cost_highpressure, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
|
||||
if(state != SS_RUNNING)
|
||||
return
|
||||
resumed = 0
|
||||
cost_highpressure = MC_AVERAGE(cost_highpressure, TICK_DELTA_TO_MS(cached_cost))
|
||||
resumed = FALSE
|
||||
currentpart = SSAIR_HOTSPOTS
|
||||
|
||||
if(currentpart == SSAIR_HOTSPOTS)
|
||||
timer = TICK_USAGE_REAL
|
||||
if(!resumed)
|
||||
cached_cost = 0
|
||||
process_hotspots(resumed)
|
||||
cost_hotspots = MC_AVERAGE(cost_hotspots, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
|
||||
if(state != SS_RUNNING)
|
||||
return
|
||||
resumed = 0
|
||||
cost_hotspots = MC_AVERAGE(cost_hotspots, TICK_DELTA_TO_MS(cached_cost))
|
||||
resumed = FALSE
|
||||
currentpart = SSAIR_SUPERCONDUCTIVITY
|
||||
|
||||
if(currentpart == SSAIR_SUPERCONDUCTIVITY)
|
||||
timer = TICK_USAGE_REAL
|
||||
if(!resumed)
|
||||
cached_cost = 0
|
||||
process_super_conductivity(resumed)
|
||||
cost_superconductivity = MC_AVERAGE(cost_superconductivity, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
|
||||
if(state != SS_RUNNING)
|
||||
return
|
||||
resumed = 0
|
||||
cost_superconductivity = MC_AVERAGE(cost_superconductivity, TICK_DELTA_TO_MS(cached_cost))
|
||||
resumed = FALSE
|
||||
currentpart = SSAIR_REBUILD_PIPENETS
|
||||
|
||||
|
||||
|
||||
64
code/controllers/subsystem/profiler.dm
Normal file
64
code/controllers/subsystem/profiler.dm
Normal file
@@ -0,0 +1,64 @@
|
||||
#define PROFILER_FILENAME "profiler.json"
|
||||
|
||||
SUBSYSTEM_DEF(profiler)
|
||||
name = "Profiler"
|
||||
init_order = INIT_ORDER_PROFILER
|
||||
runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY
|
||||
wait = 3000
|
||||
flags = SS_NO_TICK_CHECK
|
||||
var/fetch_cost = 0
|
||||
var/write_cost = 0
|
||||
|
||||
/datum/controller/subsystem/profiler/stat_entry(msg)
|
||||
msg += "F:[round(fetch_cost,1)]ms"
|
||||
msg += "|W:[round(write_cost,1)]ms"
|
||||
..(msg)
|
||||
|
||||
/datum/controller/subsystem/profiler/Initialize()
|
||||
if(CONFIG_GET(flag/auto_profile))
|
||||
StartProfiling()
|
||||
else
|
||||
StopProfiling() //Stop the early start from world/New
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/profiler/fire()
|
||||
if(CONFIG_GET(flag/auto_profile))
|
||||
DumpFile()
|
||||
|
||||
/datum/controller/subsystem/profiler/Shutdown()
|
||||
if(CONFIG_GET(flag/auto_profile))
|
||||
DumpFile()
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/profiler/proc/StartProfiling()
|
||||
#if DM_BUILD < 1506 || DM_VERSION < 513
|
||||
stack_trace("Auto profiling unsupported on this byond version")
|
||||
CONFIG_SET(flag/auto_profile, FALSE)
|
||||
#else
|
||||
world.Profile(PROFILE_START)
|
||||
#endif
|
||||
|
||||
/datum/controller/subsystem/profiler/proc/StopProfiling()
|
||||
#if DM_BUILD >= 1506 && DM_VERSION >= 513
|
||||
world.Profile(PROFILE_STOP)
|
||||
#endif
|
||||
|
||||
/datum/controller/subsystem/profiler/proc/DumpFile()
|
||||
#if DM_BUILD < 1506 || DM_VERSION < 513
|
||||
stack_trace("Auto profiling unsupported on this byond version")
|
||||
CONFIG_SET(flag/auto_profile, FALSE)
|
||||
#else
|
||||
var/timer = TICK_USAGE_REAL
|
||||
var/current_profile_data = world.Profile(PROFILE_REFRESH,format="json")
|
||||
fetch_cost = MC_AVERAGE(fetch_cost, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
|
||||
CHECK_TICK
|
||||
if(!length(current_profile_data)) //Would be nice to have explicit proc to check this
|
||||
stack_trace("Warning, profiling stopped manually before dump.")
|
||||
var/json_file = file("[GLOB.log_directory]/[PROFILER_FILENAME]")
|
||||
if(fexists(json_file))
|
||||
fdel(json_file)
|
||||
timer = TICK_USAGE_REAL
|
||||
WRITE_FILE(json_file, current_profile_data)
|
||||
write_cost = MC_AVERAGE(write_cost, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
|
||||
WRITE_FILE(json_file, current_profile_data)
|
||||
#endif
|
||||
@@ -87,7 +87,7 @@
|
||||
owner.vomit()
|
||||
fail = TRUE
|
||||
if(2)
|
||||
owner.emote("cough")
|
||||
INVOKE_ASYNC(owner, /mob.proc/emote, "cough")
|
||||
owner.dizziness += 10
|
||||
fail = TRUE
|
||||
if(3)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
var/first_dir // This only stores the dir arg from init
|
||||
|
||||
/datum/component/decal/Initialize(_icon, _icon_state, _dir, _cleanable=CLEAN_GOD, _color, _layer=TURF_LAYER, _description, _alpha=255)
|
||||
/datum/component/decal/Initialize(_icon, _icon_state, _dir, _cleanable=CLEAN_NEVER, _color, _layer=TURF_LAYER, _description, _alpha=255)
|
||||
if(!isatom(parent) || !generate_appearance(_icon, _icon_state, _dir, _layer, _color, _alpha))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
first_dir = _dir
|
||||
@@ -19,7 +19,7 @@
|
||||
/datum/component/decal/RegisterWithParent()
|
||||
if(first_dir)
|
||||
RegisterSignal(parent, COMSIG_ATOM_DIR_CHANGE, .proc/rotate_react)
|
||||
if(cleanable)
|
||||
if(cleanable != CLEAN_NEVER)
|
||||
RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, .proc/clean_react)
|
||||
if(description)
|
||||
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/examine)
|
||||
|
||||
@@ -5,43 +5,47 @@
|
||||
var/list/obj/item/storage/backpack/holding/matching = typecache_filter_list(W.GetAllContents(), typecacheof(/obj/item/storage/backpack/holding))
|
||||
matching -= A
|
||||
if(istype(W, /obj/item/storage/backpack/holding) || matching.len)
|
||||
var/safety = alert(user, "Doing this will have extremely dire consequences for the station and its crew. Be sure you know what you're doing.", "Put in [A.name]?", "Abort", "Proceed")
|
||||
if(safety != "Proceed" || QDELETED(A) || QDELETED(W) || QDELETED(user) || !user.canUseTopic(A, BE_CLOSE, iscarbon(user)))
|
||||
return
|
||||
var/turf/loccheck = get_turf(A)
|
||||
if(is_reebe(loccheck.z))
|
||||
user.visible_message("<span class='warning'>An unseen force knocks [user] to the ground!</span>", "<span class='big_brass'>\"I think not!\"</span>")
|
||||
user.Paralyze(60)
|
||||
return
|
||||
if(istype(loccheck.loc, /area/fabric_of_reality))
|
||||
to_chat(user, "<span class='danger'>You can't do that here!</span>")
|
||||
to_chat(user, "<span class='danger'>The Bluespace interfaces of the two devices catastrophically malfunction!</span>")
|
||||
qdel(W)
|
||||
playsound(loccheck,'sound/effects/supermatter.ogg', 200, 1)
|
||||
|
||||
message_admins("[ADMIN_LOOKUPFLW(user)] detonated a bag of holding at [ADMIN_VERBOSEJMP(loccheck)].")
|
||||
log_game("[key_name(user)] detonated a bag of holding at [loc_name(loccheck)].")
|
||||
|
||||
for(var/turf/T in range(2,loccheck))
|
||||
if(istype(T, /turf/open/space/transit))
|
||||
continue
|
||||
for(var/atom/AT in T)
|
||||
AT.emp_act(EMP_HEAVY)
|
||||
if(istype(AT, /obj))
|
||||
var/obj/O = AT
|
||||
O.obj_break()
|
||||
if(istype(AT, /mob/living))
|
||||
var/mob/living/M = AT
|
||||
M.take_overall_damage(85)
|
||||
if(M.movement_type & FLYING)
|
||||
M.visible_message("<span class='danger'>The bluespace collapse crushes the air towards it, pulling [M] towards the ground...</span>")
|
||||
M.Paralyze(5, TRUE, TRUE) //Overrides stun absorbs.
|
||||
T.TerraformTurf(/turf/open/chasm/magic, /turf/open/chasm/magic)
|
||||
for(var/fabricarea in get_areas(/area/fabric_of_reality))
|
||||
var/area/fabric_of_reality/R = fabricarea
|
||||
R.origin = loccheck
|
||||
for (var/obj/structure/ladder/unbreakable/binary/ladder in GLOB.ladders)
|
||||
ladder.ActivateAlmonds()
|
||||
qdel(A)
|
||||
INVOKE_ASYNC(src, .proc/recursive_insertion, W, user)
|
||||
return
|
||||
. = ..()
|
||||
|
||||
/datum/component/storage/concrete/bluespace/bag_of_holding/proc/recursive_insertion(obj/item/W, mob/living/user)
|
||||
var/atom/A = parent
|
||||
var/safety = alert(user, "Doing this will have extremely dire consequences for the station and its crew. Be sure you know what you're doing.", "Put in [A.name]?", "Abort", "Proceed")
|
||||
if(safety != "Proceed" || QDELETED(A) || QDELETED(W) || QDELETED(user) || !user.canUseTopic(A, BE_CLOSE, iscarbon(user)))
|
||||
return
|
||||
var/turf/loccheck = get_turf_global(A)
|
||||
if(is_reebe(loccheck.z))
|
||||
user.visible_message("<span class='warning'>An unseen force knocks [user] to the ground!</span>", "<span class='big_brass'>\"I think not!\"</span>")
|
||||
user.Paralyze(60)
|
||||
return
|
||||
if(istype(loccheck.loc, /area/fabric_of_reality))
|
||||
to_chat(user, "<span class='danger'>You can't do that here!</span>")
|
||||
to_chat(user, "<span class='danger'>The Bluespace interfaces of the two devices catastrophically malfunction!</span>")
|
||||
qdel(W)
|
||||
playsound(loccheck,'sound/effects/supermatter.ogg', 200, 1)
|
||||
|
||||
message_admins("[ADMIN_LOOKUPFLW(user)] detonated a bag of holding at [ADMIN_VERBOSEJMP(loccheck)].")
|
||||
log_game("[key_name(user)] detonated a bag of holding at [loc_name(loccheck)].")
|
||||
|
||||
for(var/turf/T in range(2,loccheck))
|
||||
if(istype(T, /turf/open/space/transit))
|
||||
continue
|
||||
for(var/atom/AT in T)
|
||||
AT.emp_act(EMP_HEAVY)
|
||||
if(istype(AT, /obj))
|
||||
var/obj/O = AT
|
||||
O.obj_break()
|
||||
if(istype(AT, /mob/living))
|
||||
var/mob/living/M = AT
|
||||
M.take_overall_damage(85)
|
||||
if(M.movement_type & FLYING)
|
||||
M.visible_message("<span class='danger'>The bluespace collapse crushes the air towards it, pulling [M] towards the ground...</span>")
|
||||
M.Paralyze(5, TRUE, TRUE) //Overrides stun absorbs.
|
||||
T.TerraformTurf(/turf/open/chasm/magic, /turf/open/chasm/magic)
|
||||
for(var/fabricarea in get_areas(/area/fabric_of_reality))
|
||||
var/area/fabric_of_reality/R = fabricarea
|
||||
R.origin = loccheck
|
||||
for (var/obj/structure/ladder/unbreakable/binary/ladder in GLOB.ladders)
|
||||
ladder.ActivateAlmonds()
|
||||
qdel(A)
|
||||
|
||||
@@ -78,6 +78,8 @@
|
||||
SSticker.minds -= src
|
||||
if(islist(antag_datums))
|
||||
QDEL_LIST(antag_datums)
|
||||
current = null
|
||||
soulOwner = null
|
||||
return ..()
|
||||
|
||||
/datum/mind/proc/get_language_holder()
|
||||
|
||||
@@ -17,4 +17,4 @@
|
||||
return visual_indicators[type][1]
|
||||
|
||||
/datum/mutation/human/telekinesis/on_ranged_attack(atom/target)
|
||||
target.attack_tk(owner)
|
||||
INVOKE_ASYNC(target, /atom.proc/attack_tk, owner)
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
/datum/status_effect/crusher_damage //tracks the damage dealt to this mob by kinetic crushers
|
||||
id = "crusher_damage"
|
||||
duration = -1
|
||||
tick_interval = -1
|
||||
status_type = STATUS_EFFECT_UNIQUE
|
||||
alert_type = null
|
||||
var/total_damage = 0
|
||||
@@ -202,6 +203,7 @@
|
||||
/datum/status_effect/heldup
|
||||
id = "heldup"
|
||||
duration = -1
|
||||
tick_interval = -1
|
||||
status_type = STATUS_EFFECT_MULTIPLE
|
||||
alert_type = /obj/screen/alert/status_effect/heldup
|
||||
|
||||
@@ -214,6 +216,7 @@
|
||||
/datum/status_effect/holdup
|
||||
id = "holdup"
|
||||
duration = -1
|
||||
tick_interval = -1
|
||||
status_type = STATUS_EFFECT_UNIQUE
|
||||
alert_type = /obj/screen/alert/status_effect/holdup
|
||||
|
||||
|
||||
@@ -31,7 +31,8 @@
|
||||
var/obj/screen/alert/status_effect/A = owner.throw_alert(id, alert_type)
|
||||
A.attached_effect = src //so the alert can reference us, if it needs to
|
||||
linked_alert = A //so we can reference the alert, if we need to
|
||||
START_PROCESSING(SSfastprocess, src)
|
||||
if(duration > 0 || initial(tick_interval) > 0) //don't process if we don't care
|
||||
START_PROCESSING(SSfastprocess, src)
|
||||
return TRUE
|
||||
|
||||
/datum/status_effect/Destroy()
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
#define AI_WIRE_NORMAL 0
|
||||
#define AI_WIRE_DISABLED 1
|
||||
#define AI_WIRE_HACKED 2
|
||||
#define AI_WIRE_DISABLED_HACKED -1
|
||||
|
||||
/datum/wires/airlock
|
||||
holder_type = /obj/machinery/door/airlock
|
||||
proper_name = "Generic Airlock"
|
||||
@@ -98,16 +103,11 @@
|
||||
A.emergency = FALSE
|
||||
A.update_icon()
|
||||
if(WIRE_AI) // Pulse to disable WIRE_AI control for 10 ticks (follows same rules as cutting).
|
||||
if(A.aiControlDisabled == 0)
|
||||
A.aiControlDisabled = 1
|
||||
else if(A.aiControlDisabled == -1)
|
||||
A.aiControlDisabled = 2
|
||||
sleep(10)
|
||||
if(A)
|
||||
if(A.aiControlDisabled == 1)
|
||||
A.aiControlDisabled = 0
|
||||
else if(A.aiControlDisabled == 2)
|
||||
A.aiControlDisabled = -1
|
||||
if(A.aiControlDisabled == AI_WIRE_NORMAL)
|
||||
A.aiControlDisabled = AI_WIRE_DISABLED
|
||||
else if(A.aiControlDisabled == AI_WIRE_DISABLED_HACKED)
|
||||
A.aiControlDisabled = AI_WIRE_HACKED
|
||||
addtimer(CALLBACK(A, /obj/machinery/door/airlock.proc/reset_ai_wire), 1 SECONDS)
|
||||
if(WIRE_SHOCK) // Pulse to shock the door for 10 ticks.
|
||||
if(!A.secondsElectrified)
|
||||
A.set_electrified(MACHINE_DEFAULT_ELECTRIFY_TIME, usr)
|
||||
@@ -121,6 +121,12 @@
|
||||
A.lights = !A.lights
|
||||
A.update_icon()
|
||||
|
||||
/obj/machinery/door/airlock/proc/reset_ai_wire()
|
||||
if(aiControlDisabled == AI_WIRE_DISABLED)
|
||||
aiControlDisabled = AI_WIRE_NORMAL
|
||||
else if(aiControlDisabled == AI_WIRE_HACKED)
|
||||
aiControlDisabled = AI_WIRE_DISABLED_HACKED
|
||||
|
||||
/datum/wires/airlock/on_cut(wire, mend)
|
||||
var/obj/machinery/door/airlock/A = holder
|
||||
switch(wire)
|
||||
@@ -147,15 +153,15 @@
|
||||
A.bolt()
|
||||
if(WIRE_AI) // Cut to disable WIRE_AI control, mend to re-enable.
|
||||
if(mend)
|
||||
if(A.aiControlDisabled == 1) // 0 = normal, 1 = locked out, 2 = overridden by WIRE_AI, -1 = previously overridden by WIRE_AI
|
||||
A.aiControlDisabled = 0
|
||||
else if(A.aiControlDisabled == 2)
|
||||
A.aiControlDisabled = -1
|
||||
if(A.aiControlDisabled == AI_WIRE_DISABLED) // 0 = normal, 1 = locked out, 2 = overridden by WIRE_AI, -1 = previously overridden by WIRE_AI
|
||||
A.aiControlDisabled = AI_WIRE_NORMAL
|
||||
else if(A.aiControlDisabled == AI_WIRE_HACKED)
|
||||
A.aiControlDisabled = AI_WIRE_DISABLED_HACKED
|
||||
else
|
||||
if(A.aiControlDisabled == 0)
|
||||
A.aiControlDisabled = 1
|
||||
else if(A.aiControlDisabled == -1)
|
||||
A.aiControlDisabled = 2
|
||||
if(A.aiControlDisabled == AI_WIRE_NORMAL)
|
||||
A.aiControlDisabled = AI_WIRE_DISABLED
|
||||
else if(A.aiControlDisabled == AI_WIRE_DISABLED_HACKED)
|
||||
A.aiControlDisabled = AI_WIRE_HACKED
|
||||
if(WIRE_SHOCK) // Cut to shock the door, mend to unshock.
|
||||
if(mend)
|
||||
if(A.secondsElectrified)
|
||||
|
||||
@@ -152,8 +152,7 @@
|
||||
var/datum/component/slippery/slipper = GetComponent(/datum/component/slippery)
|
||||
slipper.Slip(src, hit_atom)
|
||||
if(thrownby && !caught)
|
||||
sleep(1)
|
||||
throw_at(thrownby, throw_range+2, throw_speed, null, TRUE)
|
||||
addtimer(CALLBACK(src, /atom/movable.proc/throw_at, thrownby, throw_range+2, throw_speed, null, TRUE), 1)
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON | INTERACT_MACHINE_REQUIRES_SILICON | INTERACT_MACHINE_OPEN
|
||||
|
||||
var/security_level = 0 //How much are wires secured
|
||||
var/aiControlDisabled = 0 //If 1, AI control is disabled until the AI hacks back in and disables the lock. If 2, the AI has bypassed the lock. If -1, the control is enabled but the AI had bypassed it earlier, so if it is disabled again the AI would have no trouble getting back in.
|
||||
var/aiControlDisabled = AI_WIRE_NORMAL //If 1, AI control is disabled until the AI hacks back in and disables the lock. If 2, the AI has bypassed the lock. If -1, the control is enabled but the AI had bypassed it earlier, so if it is disabled again the AI would have no trouble getting back in.
|
||||
var/hackProof = FALSE // if true, this door can't be hacked by the AI
|
||||
var/secondsMainPowerLost = 0 //The number of seconds until power is restored.
|
||||
var/secondsBackupPowerLost = 0 //The number of seconds until power is restored.
|
||||
@@ -475,10 +475,10 @@
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/door/airlock/proc/canAIControl(mob/user)
|
||||
return ((aiControlDisabled != 1) && !isAllPowerCut())
|
||||
return ((aiControlDisabled != AI_WIRE_DISABLED) && !isAllPowerCut())
|
||||
|
||||
/obj/machinery/door/airlock/proc/canAIHack()
|
||||
return ((aiControlDisabled==1) && (!hackProof) && (!isAllPowerCut()));
|
||||
return ((aiControlDisabled==AI_WIRE_DISABLED) && (!hackProof) && (!isAllPowerCut()));
|
||||
|
||||
/obj/machinery/door/airlock/hasPower()
|
||||
return ((!secondsMainPowerLost || !secondsBackupPowerLost) && !(stat & NOPOWER))
|
||||
@@ -835,7 +835,7 @@
|
||||
to_chat(user, "Transfer complete. Forcing airlock to execute program.")
|
||||
sleep(50)
|
||||
//disable blocked control
|
||||
aiControlDisabled = 2
|
||||
aiControlDisabled = AI_WIRE_HACKED
|
||||
to_chat(user, "Receiving control information from airlock.")
|
||||
sleep(10)
|
||||
//bring up airlock dialog
|
||||
|
||||
@@ -437,7 +437,7 @@
|
||||
damage_deflection = 30
|
||||
explosion_block = 3
|
||||
hackProof = TRUE
|
||||
aiControlDisabled = 1
|
||||
aiControlDisabled = AI_WIRE_DISABLED
|
||||
normal_integrity = 700
|
||||
security_level = 1
|
||||
|
||||
@@ -452,7 +452,7 @@
|
||||
overlays_file = 'icons/obj/doors/airlocks/cult/runed/overlays.dmi'
|
||||
assemblytype = /obj/structure/door_assembly/door_assembly_cult
|
||||
hackProof = TRUE
|
||||
aiControlDisabled = 1
|
||||
aiControlDisabled = AI_WIRE_DISABLED
|
||||
req_access = list(ACCESS_BLOODCULT)
|
||||
damage_deflection = 10
|
||||
var/openingoverlaytype = /obj/effect/temp_visual/cult/door
|
||||
@@ -557,7 +557,7 @@
|
||||
overlays_file = 'icons/obj/doors/airlocks/clockwork/overlays.dmi'
|
||||
anim_parts = "left=-13,0;right=13,0"
|
||||
hackProof = TRUE
|
||||
aiControlDisabled = 1
|
||||
aiControlDisabled = AI_WIRE_DISABLED
|
||||
req_access = list(ACCESS_CLOCKCULT)
|
||||
use_power = FALSE
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
|
||||
@@ -78,9 +78,11 @@
|
||||
controller.cycleClose(door)
|
||||
else
|
||||
controller.onlyClose(door)
|
||||
sleep(20)
|
||||
busy = FALSE
|
||||
update_icon()
|
||||
addtimer(CALLBACK(src, .proc/not_busy), 2 SECONDS)
|
||||
|
||||
/obj/machinery/doorButtons/access_button/proc/not_busy()
|
||||
busy = FALSE
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/doorButtons/access_button/update_icon()
|
||||
if(stat & NOPOWER)
|
||||
|
||||
@@ -25,11 +25,12 @@
|
||||
random_icon_states = list("xgib1", "xgib2", "xgib3", "xgib4", "xgib5", "xgib6")
|
||||
mergeable_decal = FALSE
|
||||
|
||||
/obj/effect/decal/cleanable/xenoblood/xgibs/proc/streak(list/directions)
|
||||
/obj/effect/decal/cleanable/xenoblood/xgibs/proc/streak(list/directions, mapload=FALSE)
|
||||
set waitfor = 0
|
||||
var/direction = pick(directions)
|
||||
for(var/i = 0, i < pick(1, 200; 2, 150; 3, 50), i++)
|
||||
sleep(2)
|
||||
if (!mapload)
|
||||
sleep(2)
|
||||
if(i > 0)
|
||||
new /obj/effect/decal/cleanable/xenoblood/xsplatter(loc)
|
||||
if(!step_to(src, get_step(src, direction), 0))
|
||||
|
||||
@@ -77,13 +77,14 @@
|
||||
playsound(loc, 'sound/effects/gib_step.ogg', HAS_TRAIT(L, TRAIT_LIGHT_STEP) ? 20 : 50, TRUE)
|
||||
. = ..()
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/proc/streak(list/directions)
|
||||
/obj/effect/decal/cleanable/blood/gibs/proc/streak(list/directions, mapload=FALSE)
|
||||
set waitfor = FALSE
|
||||
var/list/diseases = list()
|
||||
SEND_SIGNAL(src, COMSIG_GIBS_STREAK, directions, diseases)
|
||||
var/direction = pick(directions)
|
||||
for(var/i in 0 to pick(0, 200; 1, 150; 2, 50))
|
||||
sleep(2)
|
||||
if (!mapload)
|
||||
sleep(2)
|
||||
if(i > 0)
|
||||
new /obj/effect/decal/cleanable/blood/splatter(loc, diseases)
|
||||
if(!step_to(src, get_step(src, direction), 0))
|
||||
|
||||
@@ -11,15 +11,16 @@
|
||||
bloodiness = BLOOD_AMOUNT_PER_DECAL
|
||||
mergeable_decal = FALSE
|
||||
|
||||
/obj/effect/decal/cleanable/robot_debris/proc/streak(list/directions)
|
||||
/obj/effect/decal/cleanable/robot_debris/proc/streak(list/directions, mapload=FALSE)
|
||||
set waitfor = 0
|
||||
var/direction = pick(directions)
|
||||
for (var/i = 0, i < pick(1, 200; 2, 150; 3, 50), i++)
|
||||
sleep(2)
|
||||
if (!mapload)
|
||||
sleep(2)
|
||||
if (i > 0)
|
||||
if (prob(40))
|
||||
new /obj/effect/decal/cleanable/oil/streak(src.loc)
|
||||
else if (prob(10))
|
||||
else if (prob(10) && !mapload)
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
|
||||
@@ -45,4 +45,4 @@
|
||||
var/turf/T = loc
|
||||
if(!istype(T)) //you know this will happen somehow
|
||||
CRASH("Turf decal initialized in an object/nullspace")
|
||||
T.AddComponent(/datum/component/decal, icon, icon_state, dir, CLEAN_GOD, color, null, null, alpha)
|
||||
T.AddComponent(/datum/component/decal, icon, icon_state, dir, CLEAN_NEVER, color, null, null, alpha)
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
var/list/directions = gibdirections[i]
|
||||
if(isturf(loc))
|
||||
if(directions.len)
|
||||
gib.streak(directions)
|
||||
gib.streak(directions, mapload)
|
||||
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
|
||||
@@ -133,5 +133,4 @@
|
||||
if(trigger_item && istype(AM, specific_item) && !claimed)
|
||||
claimed = TRUE
|
||||
flick("laserbox_burn", AM)
|
||||
sleep(15)
|
||||
qdel(AM)
|
||||
QDEL_IN(AM, 15)
|
||||
|
||||
@@ -25,6 +25,12 @@ GLOBAL_VAR(restart_counter)
|
||||
*/
|
||||
/world/New()
|
||||
enable_debugger() //This does nothing if you aren't trying to debug
|
||||
|
||||
//Early profile for auto-profiler - will be stopped on profiler init if necessary.
|
||||
#if DM_VERSION >= 513 && DM_BUILD >= 1506
|
||||
world.Profile(PROFILE_START)
|
||||
#endif
|
||||
|
||||
log_world("World loaded at [time_stamp()]!")
|
||||
|
||||
SetupExternalRSC()
|
||||
|
||||
@@ -164,13 +164,9 @@
|
||||
if((temperature < FIRE_MINIMUM_TEMPERATURE_TO_EXIST) || (volume <= 1))
|
||||
qdel(src)
|
||||
return
|
||||
if(!location.air || (INSUFFICIENT(/datum/gas/plasma) && INSUFFICIENT(/datum/gas/tritium)) || INSUFFICIENT(/datum/gas/oxygen))
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
//Not enough to burn
|
||||
// god damn it previous coder you made the INSUFFICIENT macro for a fucking reason why didn't you use it here smh
|
||||
if((INSUFFICIENT(/datum/gas/plasma) && INSUFFICIENT(/datum/gas/tritium)) || INSUFFICIENT(/datum/gas/oxygen))
|
||||
//Not enough / nothing to burn
|
||||
if(!location.air || (INSUFFICIENT(/datum/gas/plasma) && INSUFFICIENT(/datum/gas/tritium)) || INSUFFICIENT(/datum/gas/oxygen))
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
|
||||
@@ -63,6 +63,8 @@
|
||||
|
||||
/obj/item/twohanded/required/kinetic_crusher/attack(mob/living/target, mob/living/carbon/user)
|
||||
var/datum/status_effect/crusher_damage/C = target.has_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING)
|
||||
if(!C)
|
||||
C = target.apply_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING)
|
||||
var/target_health = target.health
|
||||
..()
|
||||
for(var/t in trophies)
|
||||
@@ -97,6 +99,8 @@
|
||||
if(!CM || CM.hammer_synced != src || !L.remove_status_effect(STATUS_EFFECT_CRUSHERMARK))
|
||||
return
|
||||
var/datum/status_effect/crusher_damage/C = L.has_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING)
|
||||
if(!C)
|
||||
C = L.apply_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING)
|
||||
var/target_health = L.health
|
||||
for(var/t in trophies)
|
||||
var/obj/item/crusher_trophy/T = t
|
||||
|
||||
@@ -402,7 +402,7 @@
|
||||
|
||||
switch(rand(1,100)+modifier) //91-100=Nothing special happens
|
||||
if(-INFINITY to 0) //attack yourself
|
||||
I.attack(src,src)
|
||||
INVOKE_ASYNC(I, /obj/item.proc/attack, src, src)
|
||||
if(1 to 30) //throw it at yourself
|
||||
I.throw_impact(src)
|
||||
if(31 to 60) //Throw object in facing direction
|
||||
|
||||
@@ -245,7 +245,7 @@
|
||||
if(!illusion && (shock_damage * siemens_coeff >= 1) && prob(25))
|
||||
set_heartattack(FALSE)
|
||||
revive()
|
||||
emote("gasp")
|
||||
INVOKE_ASYNC(src, .proc/emote, "gasp")
|
||||
Jitter(100)
|
||||
SEND_SIGNAL(src, COMSIG_LIVING_MINOR_SHOCK)
|
||||
adjustOrganLoss(ORGAN_SLOT_BRAIN, 100, 199) //yogs end
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
losebreath = 0
|
||||
|
||||
if(!gibbed)
|
||||
emote("deathgasp")
|
||||
INVOKE_ASYNC(src, .proc/emote, "deathgasp")
|
||||
|
||||
. = ..()
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
if(losebreath >= 1) //You've missed a breath, take oxy damage
|
||||
losebreath--
|
||||
if(prob(10))
|
||||
emote("gasp")
|
||||
INVOKE_ASYNC(src, .proc/emote, "gasp")
|
||||
if(istype(loc, /obj/))
|
||||
var/obj/loc_as_obj = loc
|
||||
loc_as_obj.handle_internal_lifeform(src,0)
|
||||
@@ -172,7 +172,7 @@
|
||||
//OXYGEN
|
||||
if(O2_partialpressure < safe_oxy_min) //Not enough oxygen
|
||||
if(prob(20))
|
||||
emote("gasp")
|
||||
INVOKE_ASYNC(src, .proc/emote, "gasp")
|
||||
if(O2_partialpressure > 0)
|
||||
var/ratio = 1 - O2_partialpressure/safe_oxy_min
|
||||
adjustOxyLoss(min(5*ratio, 3))
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
if(prob(1))
|
||||
to_chat(src, "<span class='danger'>You mutate!</span>")
|
||||
easy_randmut(NEGATIVE+MINOR_NEGATIVE)
|
||||
emote("gasp")
|
||||
INVOKE_ASYNC(src, .proc/emote, "gasp")
|
||||
domutcheck()
|
||||
|
||||
if(radiation > RAD_MOB_MUTATE * 2 && prob(50))
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
/mob/living/simple_animal/bot/secbot/grievous/Initialize()
|
||||
. = ..()
|
||||
weapon = new baton_type(src)
|
||||
weapon.attack_self(src)
|
||||
INVOKE_ASYNC(weapon, /obj/item.proc/attack_self, src)
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/grievous/Destroy()
|
||||
QDEL_NULL(weapon)
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
var/robot_arm = /obj/item/bodypart/r_arm/robot
|
||||
|
||||
var/commissioned = FALSE // Will other (noncommissioned) bots salute this bot?
|
||||
var/can_salute = TRUE
|
||||
COOLDOWN_DECLARE(next_salute_check)
|
||||
var/salute_delay = 60 SECONDS
|
||||
|
||||
hud_possible = list(DIAG_STAT_HUD, DIAG_BOT_HUD, DIAG_HUD, DIAG_PATH_HUD = HUD_LIST_LIST) //Diagnostic HUD views
|
||||
@@ -257,12 +257,11 @@
|
||||
if(!on || client)
|
||||
return
|
||||
|
||||
if(!commissioned && can_salute)
|
||||
for(var/mob/living/simple_animal/bot/B in get_hearers_in_view(5, get_turf(src)))
|
||||
if(B.commissioned)
|
||||
visible_message("<b>[src]</b> performs an elaborate salute for [B]!")
|
||||
can_salute = FALSE
|
||||
addtimer(VARSET_CALLBACK(src, can_salute, TRUE), salute_delay)
|
||||
if(commissioned && COOLDOWN_FINISHED(src, next_salute_check))
|
||||
COOLDOWN_START(src, next_salute_check, salute_delay)
|
||||
for(var/mob/living/simple_animal/bot/B in view(5, src))
|
||||
if(!B.commissioned && B.on)
|
||||
visible_message("<b>[B]</b> performs an elaborate salute for [src]!")
|
||||
break
|
||||
|
||||
switch(mode) //High-priority overrides are processed first. Bots can do nothing else while under direct command.
|
||||
|
||||
@@ -305,7 +305,7 @@
|
||||
/mob/living/simple_animal/pet/dog/corgi/proc/place_on_head(obj/item/item_to_add, mob/user)
|
||||
|
||||
if(istype(item_to_add, /obj/item/grenade/plastic)) // last thing he ever wears, I guess
|
||||
item_to_add.afterattack(src,user,1)
|
||||
INVOKE_ASYNC(item_to_add, /obj/item.proc/afterattack, src, user, 1)
|
||||
return
|
||||
|
||||
if(inventory_head)
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
if(spawn_mecha_type)
|
||||
var/obj/mecha/M = new spawn_mecha_type (get_turf(src))
|
||||
if(istype(M))
|
||||
enter_mecha(M)
|
||||
INVOKE_ASYNC(src, .proc/enter_mecha, M)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/syndicate/mecha_pilot/proc/enter_mecha(obj/mecha/M)
|
||||
|
||||
@@ -45,7 +45,6 @@
|
||||
. = ..()
|
||||
if(internal_type && true_spawn)
|
||||
internal = new internal_type(src)
|
||||
apply_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING)
|
||||
ADD_TRAIT(src, TRAIT_NO_TELEPORT, MEGAFAUNA_TRAIT)
|
||||
for(var/action_type in attack_action_types)
|
||||
var/datum/action/innate/megafauna_attack/attack_action = new action_type()
|
||||
|
||||
@@ -22,10 +22,6 @@
|
||||
var/icon_aggro = null
|
||||
var/crusher_drop_mod = 25
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/Initialize(mapload)
|
||||
. = ..()
|
||||
apply_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING)
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/Aggro()
|
||||
..()
|
||||
if(vision_range == aggro_vision_range && icon_aggro)
|
||||
|
||||
@@ -407,7 +407,7 @@
|
||||
update()
|
||||
|
||||
/obj/machinery/light/proc/broken_sparks(start_only=FALSE)
|
||||
if(status == LIGHT_BROKEN && has_power())
|
||||
if(status == LIGHT_BROKEN && has_power() && Master.current_runlevel)
|
||||
if(!start_only)
|
||||
do_sparks(3, TRUE, src)
|
||||
var/delay = rand(BROKEN_SPARKS_MIN, BROKEN_SPARKS_MAX)
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
var/modifier = 0
|
||||
|
||||
/datum/chemical_reaction/reagent_explosion/on_reaction(datum/reagents/holder, created_volume)
|
||||
explode(holder, created_volume)
|
||||
|
||||
/datum/chemical_reaction/reagent_explosion/proc/explode(datum/reagents/holder, created_volume)
|
||||
var/turf/T = get_turf(holder.my_atom)
|
||||
var/inside_msg
|
||||
if(ismob(holder.my_atom))
|
||||
@@ -69,15 +72,16 @@
|
||||
R.stun(20)
|
||||
R.reveal(100)
|
||||
R.adjustHealth(50)
|
||||
sleep(20)
|
||||
for(var/mob/living/carbon/C in get_hearers_in_view(round(created_volume/20,1),get_turf(holder.my_atom))) //roughly 5 tiles with 100/100 potwat
|
||||
if(iscultist(C))
|
||||
to_chat(C, "<span class='userdanger'>The divine explosion sears you!</span>")
|
||||
C.Paralyze(40)
|
||||
C.adjust_fire_stacks(5)
|
||||
C.IgniteMob()
|
||||
addtimer(CALLBACK(src, .proc/divine_explosion, round(created_volume/48,1),get_turf(holder.my_atom)), 2 SECONDS)
|
||||
..()
|
||||
|
||||
/datum/chemical_reaction/reagent_explosion/potassium_explosion/holyboom/proc/divine_explosion(size, turf/T)
|
||||
for(var/mob/living/carbon/C in get_hearers_in_view(size,T))
|
||||
if(iscultist(C))
|
||||
to_chat(C, "<span class='userdanger'>The divine explosion sears you!</span>")
|
||||
C.Paralyze(40)
|
||||
C.adjust_fire_stacks(5)
|
||||
C.IgniteMob()
|
||||
|
||||
/datum/chemical_reaction/blackpowder
|
||||
name = "Black Powder"
|
||||
@@ -95,8 +99,7 @@
|
||||
mix_message = "<span class='boldannounce'>Sparks start flying around the black powder!</span>"
|
||||
|
||||
/datum/chemical_reaction/reagent_explosion/blackpowder_explosion/on_reaction(datum/reagents/holder, created_volume)
|
||||
sleep(rand(50,100))
|
||||
..()
|
||||
addtimer(CALLBACK(src, .proc/explode, holder, created_volume), rand(5,10) SECONDS)
|
||||
|
||||
/datum/chemical_reaction/thermite
|
||||
name = "Thermite"
|
||||
@@ -431,19 +434,22 @@
|
||||
var/T1 = created_volume * 20 //100 units : Zap 3 times, with powers 2000/5000/12000. Tesla revolvers have a power of 10000 for comparison.
|
||||
var/T2 = created_volume * 50
|
||||
var/T3 = created_volume * 120
|
||||
sleep(5)
|
||||
var/added_delay = 0.5 SECONDS
|
||||
if(created_volume >= 75)
|
||||
tesla_zap(holder.my_atom, 7, T1, tesla_flags)
|
||||
playsound(holder.my_atom, 'sound/machines/defib_zap.ogg', 50, 1)
|
||||
sleep(15)
|
||||
addtimer(CALLBACK(src, .proc/zappy_zappy, holder, T1), added_delay)
|
||||
added_delay += 1.5 SECONDS
|
||||
if(created_volume >= 40)
|
||||
tesla_zap(holder.my_atom, 7, T2, tesla_flags)
|
||||
playsound(holder.my_atom, 'sound/machines/defib_zap.ogg', 50, 1)
|
||||
sleep(15)
|
||||
addtimer(CALLBACK(src, .proc/zappy_zappy, holder, T2), added_delay)
|
||||
added_delay += 1.5 SECONDS
|
||||
if(created_volume >= 10) //10 units minimum for lightning, 40 units for secondary blast, 75 units for tertiary blast.
|
||||
tesla_zap(holder.my_atom, 7, T3, tesla_flags)
|
||||
playsound(holder.my_atom, 'sound/machines/defib_zap.ogg', 50, 1)
|
||||
..()
|
||||
addtimer(CALLBACK(src, .proc/zappy_zappy, holder, T3), added_delay)
|
||||
addtimer(CALLBACK(src, .proc/explode, holder, created_volume), added_delay)
|
||||
|
||||
/datum/chemical_reaction/reagent_explosion/teslium_lightning/proc/zappy_zappy(datum/reagents/holder, power)
|
||||
if(QDELETED(holder.my_atom))
|
||||
return
|
||||
tesla_zap(holder.my_atom, 7, power, tesla_flags)
|
||||
playsound(holder.my_atom, 'sound/machines/defib_zap.ogg', 50, TRUE)
|
||||
|
||||
/datum/chemical_reaction/reagent_explosion/teslium_lightning/heat
|
||||
id = "teslium_lightning2"
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
var/deletes_extract = TRUE
|
||||
|
||||
/datum/chemical_reaction/slime/on_reaction(datum/reagents/holder)
|
||||
use_slime_core(holder)
|
||||
|
||||
/datum/chemical_reaction/slime/proc/use_slime_core(datum/reagents/holder)
|
||||
SSblackbox.record_feedback("tally", "slime_cores_used", 1, "type")
|
||||
if(deletes_extract)
|
||||
delete_extract(holder)
|
||||
@@ -582,7 +585,9 @@
|
||||
required_other = TRUE
|
||||
|
||||
/datum/chemical_reaction/slime/slimestop/on_reaction(datum/reagents/holder)
|
||||
sleep(50)
|
||||
addtimer(CALLBACK(src, .proc/slime_stop, holder), 5 SECONDS)
|
||||
|
||||
/datum/chemical_reaction/slime/slimestop/proc/slime_stop(datum/reagents/holder)
|
||||
var/obj/item/slime_extract/sepia/extract = holder.my_atom
|
||||
var/turf/T = get_turf(holder.my_atom)
|
||||
new /obj/effect/timestop(T, null, null, null)
|
||||
@@ -592,7 +597,7 @@
|
||||
if(lastheld && !lastheld.equip_to_slot_if_possible(extract, SLOT_HANDS, disable_warning = TRUE))
|
||||
extract.forceMove(get_turf(lastheld))
|
||||
|
||||
..()
|
||||
use_slime_core(holder)
|
||||
|
||||
/datum/chemical_reaction/slime/slimecamera
|
||||
name = "Slime Camera"
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
/datum/status_effect/slimerecall
|
||||
id = "slime_recall"
|
||||
duration = -1 //Will be removed by the extract.
|
||||
tick_interval = -1
|
||||
alert_type = null
|
||||
var/interrupted = FALSE
|
||||
var/mob/target
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
var/obj/item/bodypart/affecting = C.get_bodypart(BODY_ZONE_CHEST)
|
||||
affecting.receive_damage(clamp(brute_dam/2 * affecting.body_damage_coeff, 15, 50), clamp(burn_dam/2 * affecting.body_damage_coeff, 0, 50)) //Damage the chest based on limb's existing damage
|
||||
C.visible_message("<span class='danger'><B>[C]'s [src.name] has been violently dismembered!</B></span>")
|
||||
C.emote("scream")
|
||||
INVOKE_ASYNC(C, /mob.proc/emote, "scream")
|
||||
SEND_SIGNAL(C, COMSIG_ADD_MOOD_EVENT, "dismembered", /datum/mood_event/dismembered)
|
||||
drop_limb()
|
||||
|
||||
|
||||
@@ -434,3 +434,5 @@ DEFAULT_VIEW_SQUARE 15x15
|
||||
## Uncomment to enable global ban DB using the provided URL. The API should expect to receive a ckey at the end of the URL.
|
||||
## More API details can be found here: https://centcom.melonmesa.com
|
||||
CENTCOM_BAN_DB https://centcom.melonmesa.com/ban/search
|
||||
|
||||
AUTO_PROFILE
|
||||
@@ -289,6 +289,7 @@
|
||||
#include "code\controllers\subsystem\pathfinder.dm"
|
||||
#include "code\controllers\subsystem\persistence.dm"
|
||||
#include "code\controllers\subsystem\ping.dm"
|
||||
#include "code\controllers\subsystem\profiler.dm"
|
||||
#include "code\controllers\subsystem\radiation.dm"
|
||||
#include "code\controllers\subsystem\radio.dm"
|
||||
#include "code\controllers\subsystem\research.dm"
|
||||
|
||||
Reference in New Issue
Block a user