Merge pull request #15097 from LetterN/generic-housekeeping-pr
Generic syncs
This commit is contained in:
@@ -195,7 +195,7 @@ GLOBAL_PROTECT(admin_verbs_debug)
|
||||
// #endif
|
||||
/datum/admins/proc/create_or_modify_area,
|
||||
/datum/admins/proc/fixcorruption,
|
||||
#ifdef REFERENCE_TRACKING
|
||||
#ifdef EXTOOLS_REFERENCE_TRACKING
|
||||
/datum/admins/proc/view_refs,
|
||||
/datum/admins/proc/view_del_failures,
|
||||
#endif
|
||||
|
||||
@@ -2862,7 +2862,7 @@
|
||||
return
|
||||
|
||||
if(!CONFIG_GET(string/centcom_ban_db))
|
||||
to_chat(usr, "<span class='warning'>Centcom Galactic Ban DB is disabled!</span>")
|
||||
to_chat(usr, span_warning("Centcom Galactic Ban DB is disabled!"))
|
||||
return
|
||||
|
||||
var/ckey = href_list["centcomlookup"]
|
||||
@@ -2889,8 +2889,19 @@
|
||||
dat += "<center><b>0 bans detected for [ckey]</b></center>"
|
||||
else
|
||||
bans = json_decode(response["body"])
|
||||
dat += "<center><b>[bans.len] ban\s detected for [ckey]</b></center>"
|
||||
|
||||
//Ignore bans from non-whitelisted sources, if a whitelist exists
|
||||
var/list/valid_sources
|
||||
if(CONFIG_GET(string/centcom_source_whitelist))
|
||||
valid_sources = splittext(CONFIG_GET(string/centcom_source_whitelist), ",")
|
||||
dat += "<center><b>Bans detected for [ckey]</b></center>"
|
||||
else
|
||||
//Ban count is potentially inaccurate if they're using a whitelist
|
||||
dat += "<center><b>[bans.len] ban\s detected for [ckey]</b></center>"
|
||||
|
||||
for(var/list/ban in bans)
|
||||
if(valid_sources && !(ban["sourceName"] in valid_sources))
|
||||
continue
|
||||
dat += "<b>Server: </b> [sanitize(ban["sourceName"])]<br>"
|
||||
dat += "<b>RP Level: </b> [sanitize(ban["sourceRoleplayLevel"])]<br>"
|
||||
dat += "<b>Type: </b> [sanitize(ban["type"])]<br>"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#ifdef REFERENCE_TRACKING
|
||||
#ifdef EXTOOLS_REFERENCE_TRACKING
|
||||
|
||||
GLOBAL_LIST_EMPTY(deletion_failures)
|
||||
|
||||
@@ -102,29 +102,21 @@ GLOBAL_LIST_EMPTY(deletion_failures)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef LEGACY_REFERENCE_TRACKING
|
||||
#ifdef REFERENCE_TRACKING
|
||||
|
||||
/datum/verb/legacy_find_refs()
|
||||
set category = "Debug"
|
||||
set name = "Find References"
|
||||
set src in world
|
||||
|
||||
find_references_legacy(FALSE)
|
||||
|
||||
|
||||
/datum/proc/find_references_legacy(skip_alert)
|
||||
/datum/proc/find_references(skip_alert)
|
||||
running_find_references = type
|
||||
if(usr?.client)
|
||||
if(usr.client.running_find_references)
|
||||
testing("CANCELLED search for references to a [usr.client.running_find_references].")
|
||||
log_reftracker("CANCELLED search for references to a [usr.client.running_find_references].")
|
||||
usr.client.running_find_references = null
|
||||
running_find_references = null
|
||||
//restart the garbage collector
|
||||
SSgarbage.can_fire = TRUE
|
||||
SSgarbage.next_fire = world.time + world.tick_lag
|
||||
SSgarbage.update_nextfire(reset_time = TRUE)
|
||||
return
|
||||
|
||||
if(!skip_alert && alert("Running this will lock everything up for about 5 minutes. Would you like to begin the search?", "Find References", "Yes", "No") != "Yes")
|
||||
if(!skip_alert && tgui_alert(usr,"Running this will lock everything up for about 5 minutes. Would you like to begin the search?", "Find References", list("Yes", "No")) != "Yes")
|
||||
running_find_references = null
|
||||
return
|
||||
|
||||
@@ -134,92 +126,122 @@ GLOBAL_LIST_EMPTY(deletion_failures)
|
||||
if(usr?.client)
|
||||
usr.client.running_find_references = type
|
||||
|
||||
testing("Beginning search for references to a [type].")
|
||||
last_find_references = world.time
|
||||
log_reftracker("Beginning search for references to a [type].")
|
||||
|
||||
var/starting_time = world.time
|
||||
|
||||
//Time to search the whole game for our ref
|
||||
DoSearchVar(GLOB, "GLOB") //globals
|
||||
log_reftracker("Finished searching globals")
|
||||
|
||||
DoSearchVar(GLOB) //globals
|
||||
for(var/datum/thing in world) //atoms (don't beleive its lies)
|
||||
DoSearchVar(thing, "World -> [thing]")
|
||||
DoSearchVar(thing, "World -> [thing.type]", search_time = starting_time)
|
||||
log_reftracker("Finished searching atoms")
|
||||
|
||||
for(var/datum/thing) //datums
|
||||
DoSearchVar(thing, "World -> [thing]")
|
||||
DoSearchVar(thing, "Datums -> [thing.type]", search_time = starting_time)
|
||||
log_reftracker("Finished searching datums")
|
||||
|
||||
//Warning, attempting to search clients like this will cause crashes if done on live. Watch yourself
|
||||
for(var/client/thing) //clients
|
||||
DoSearchVar(thing, "World -> [thing]")
|
||||
DoSearchVar(thing, "Clients -> [thing.type]", search_time = starting_time)
|
||||
log_reftracker("Finished searching clients")
|
||||
|
||||
log_reftracker("Completed search for references to a [type].")
|
||||
|
||||
testing("Completed search for references to a [type].")
|
||||
if(usr?.client)
|
||||
usr.client.running_find_references = null
|
||||
running_find_references = null
|
||||
|
||||
//restart the garbage collector
|
||||
SSgarbage.can_fire = TRUE
|
||||
SSgarbage.next_fire = world.time + world.tick_lag
|
||||
SSgarbage.update_nextfire(reset_time = TRUE)
|
||||
|
||||
/datum/proc/DoSearchVar(potential_container, container_name, recursive_limit = 64, search_time = world.time)
|
||||
#ifdef REFERENCE_TRACKING_DEBUG
|
||||
if(!found_refs && SSgarbage.should_save_refs)
|
||||
found_refs = list()
|
||||
#endif
|
||||
|
||||
/datum/verb/qdel_then_find_references()
|
||||
set category = "Debug"
|
||||
set name = "qdel() then Find References"
|
||||
set src in world
|
||||
|
||||
qdel(src, TRUE) //force a qdel
|
||||
if(!running_find_references)
|
||||
find_references_legacy(TRUE)
|
||||
|
||||
|
||||
/datum/verb/qdel_then_if_fail_find_references()
|
||||
set category = "Debug"
|
||||
set name = "qdel() then Find References if GC failure"
|
||||
set src in world
|
||||
|
||||
qdel_and_find_ref_if_fail(src, TRUE)
|
||||
|
||||
|
||||
/datum/proc/DoSearchVar(potential_container, container_name, recursive_limit = 64)
|
||||
if(usr?.client && !usr.client.running_find_references)
|
||||
return
|
||||
|
||||
if(!recursive_limit)
|
||||
log_reftracker("Recursion limit reached. [container_name]")
|
||||
return
|
||||
|
||||
if(istype(potential_container, /datum))
|
||||
var/datum/datum_container = potential_container
|
||||
if(datum_container.last_find_references == last_find_references)
|
||||
return
|
||||
|
||||
datum_container.last_find_references = last_find_references
|
||||
var/list/vars_list = datum_container.vars
|
||||
|
||||
for(var/varname in vars_list)
|
||||
if (varname == "vars")
|
||||
continue
|
||||
var/variable = vars_list[varname]
|
||||
|
||||
if(variable == src)
|
||||
testing("Found [type] \ref[src] in [datum_container.type]'s [varname] var. [container_name]")
|
||||
|
||||
else if(islist(variable))
|
||||
DoSearchVar(variable, "[container_name] -> list", recursive_limit - 1)
|
||||
|
||||
else if(islist(potential_container))
|
||||
var/normal = IS_NORMAL_LIST(potential_container)
|
||||
for(var/element_in_list in potential_container)
|
||||
if(element_in_list == src)
|
||||
testing("Found [type] \ref[src] in list [container_name].")
|
||||
|
||||
else if(element_in_list && !isnum(element_in_list) && normal && potential_container[element_in_list] == src)
|
||||
testing("Found [type] \ref[src] in list [container_name]\[[element_in_list]\]")
|
||||
|
||||
else if(islist(element_in_list))
|
||||
DoSearchVar(element_in_list, "[container_name] -> list", recursive_limit - 1)
|
||||
|
||||
//Check each time you go down a layer. This makes it a bit slow, but it won't effect the rest of the game at all
|
||||
#ifndef FIND_REF_NO_CHECK_TICK
|
||||
CHECK_TICK
|
||||
#endif
|
||||
|
||||
if(istype(potential_container, /datum))
|
||||
var/datum/datum_container = potential_container
|
||||
if(datum_container.last_find_references == search_time)
|
||||
return
|
||||
|
||||
datum_container.last_find_references = search_time
|
||||
var/list/vars_list = datum_container.vars
|
||||
|
||||
for(var/varname in vars_list)
|
||||
#ifndef FIND_REF_NO_CHECK_TICK
|
||||
CHECK_TICK
|
||||
#endif
|
||||
if (varname == "vars" || varname == "vis_locs") //Fun fact, vis_locs don't count for references
|
||||
continue
|
||||
var/variable = vars_list[varname]
|
||||
|
||||
if(variable == src)
|
||||
#ifdef REFERENCE_TRACKING_DEBUG
|
||||
if(SSgarbage.should_save_refs)
|
||||
found_refs[varname] = TRUE
|
||||
#endif
|
||||
log_reftracker("Found [type] \ref[src] in [datum_container.type]'s \ref[datum_container] [varname] var. [container_name]")
|
||||
continue
|
||||
|
||||
if(islist(variable))
|
||||
DoSearchVar(variable, "[container_name] \ref[datum_container] -> [varname] (list)", recursive_limit - 1, search_time)
|
||||
|
||||
else if(islist(potential_container))
|
||||
var/normal = IS_NORMAL_LIST(potential_container)
|
||||
var/list/potential_cache = potential_container
|
||||
for(var/element_in_list in potential_cache)
|
||||
#ifndef FIND_REF_NO_CHECK_TICK
|
||||
CHECK_TICK
|
||||
#endif
|
||||
//Check normal entrys
|
||||
if(element_in_list == src)
|
||||
#ifdef REFERENCE_TRACKING_DEBUG
|
||||
if(SSgarbage.should_save_refs)
|
||||
found_refs[potential_cache] = TRUE
|
||||
#endif
|
||||
log_reftracker("Found [type] \ref[src] in list [container_name].")
|
||||
continue
|
||||
|
||||
var/assoc_val = null
|
||||
if(!isnum(element_in_list) && normal)
|
||||
assoc_val = potential_cache[element_in_list]
|
||||
//Check assoc entrys
|
||||
if(assoc_val == src)
|
||||
#ifdef REFERENCE_TRACKING_DEBUG
|
||||
if(SSgarbage.should_save_refs)
|
||||
found_refs[potential_cache] = TRUE
|
||||
#endif
|
||||
log_reftracker("Found [type] \ref[src] in list [container_name]\[[element_in_list]\]")
|
||||
continue
|
||||
//We need to run both of these checks, since our object could be hiding in either of them
|
||||
//Check normal sublists
|
||||
if(islist(element_in_list))
|
||||
DoSearchVar(element_in_list, "[container_name] -> [element_in_list] (list)", recursive_limit - 1, search_time)
|
||||
//Check assoc sublists
|
||||
if(islist(assoc_val))
|
||||
DoSearchVar(potential_container[element_in_list], "[container_name]\[[element_in_list]\] -> [assoc_val] (list)", recursive_limit - 1, search_time)
|
||||
|
||||
/proc/qdel_and_find_ref_if_fail(datum/thing_to_del, force = FALSE)
|
||||
SSgarbage.reference_find_on_fail[REF(thing_to_del)] = TRUE
|
||||
qdel(thing_to_del, force)
|
||||
thing_to_del.qdel_and_find_ref_if_fail(force)
|
||||
|
||||
/datum/proc/qdel_and_find_ref_if_fail(force = FALSE)
|
||||
SSgarbage.reference_find_on_fail["\ref[src]"] = TRUE
|
||||
qdel(src, force)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
usr.client.debug_variables(src)
|
||||
return
|
||||
|
||||
#ifdef REFERENCE_TRACKING
|
||||
#ifdef EXTOOLS_REFERENCE_TRACKING
|
||||
if(href_list[VV_HK_VIEW_REFERENCES])
|
||||
var/datum/D = locate(href_list[VV_HK_TARGET])
|
||||
if(!D)
|
||||
|
||||
@@ -3,21 +3,21 @@
|
||||
/datum/asset/simple/tgui_common
|
||||
keep_local_name = TRUE
|
||||
assets = list(
|
||||
"tgui-common.bundle.js" = 'tgui/public/tgui-common.bundle.js',
|
||||
"tgui-common.bundle.js" = file("tgui/public/tgui-common.bundle.js"),
|
||||
)
|
||||
|
||||
/datum/asset/simple/tgui
|
||||
keep_local_name = TRUE
|
||||
assets = list(
|
||||
"tgui.bundle.js" = 'tgui/public/tgui.bundle.js',
|
||||
"tgui.bundle.css" = 'tgui/public/tgui.bundle.css',
|
||||
"tgui.bundle.js" = file("tgui/public/tgui.bundle.js"),
|
||||
"tgui.bundle.css" = file("tgui/public/tgui.bundle.css"),
|
||||
)
|
||||
|
||||
/datum/asset/simple/tgui_panel
|
||||
keep_local_name = TRUE
|
||||
assets = list(
|
||||
"tgui-panel.bundle.js" = 'tgui/public/tgui-panel.bundle.js',
|
||||
"tgui-panel.bundle.css" = 'tgui/public/tgui-panel.bundle.css',
|
||||
"tgui-panel.bundle.js" = file("tgui/public/tgui-panel.bundle.js"),
|
||||
"tgui-panel.bundle.css" = file("tgui/public/tgui-panel.bundle.css"),
|
||||
)
|
||||
|
||||
/datum/asset/simple/headers
|
||||
@@ -168,10 +168,12 @@
|
||||
|
||||
/datum/asset/simple/namespaced/tgfont
|
||||
assets = list(
|
||||
"tgfont.eot" = 'tgui/packages/tgfont/dist/tgfont.eot',
|
||||
"tgfont.woff2" = 'tgui/packages/tgfont/dist/tgfont.woff2',
|
||||
"tgfont.eot" = file("tgui/packages/tgfont/dist/tgfont.eot"),
|
||||
"tgfont.woff2" = file("tgui/packages/tgfont/dist/tgfont.woff2"),
|
||||
)
|
||||
parents = list(
|
||||
"tgfont.css" = file("tgui/packages/tgfont/dist/tgfont.css"),
|
||||
)
|
||||
parents = list("tgfont.css" = 'tgui/packages/tgfont/dist/tgfont.css')
|
||||
|
||||
/datum/asset/spritesheet/chat
|
||||
name = "chat"
|
||||
|
||||
@@ -641,6 +641,18 @@ Since Ramadan is an entire month that lasts 29.5 days on average, the start and
|
||||
/datum/holiday/easter/getStationPrefix()
|
||||
return pick("Fluffy","Bunny","Easter","Egg")
|
||||
|
||||
/datum/holiday/ianbirthday
|
||||
name = "Ian's Birthday" //github.com/tgstation/tgstation/commit/de7e4f0de0d568cd6e1f0d7bcc3fd34700598acb
|
||||
begin_month = SEPTEMBER
|
||||
begin_day = 9
|
||||
end_day = 10
|
||||
|
||||
/datum/holiday/ianbirthday/greet()
|
||||
return "Happy birthday, Ian!"
|
||||
|
||||
/datum/holiday/ianbirthday/getStationPrefix()
|
||||
return pick("Ian", "Corgi", "Erro")
|
||||
|
||||
//Random citadel thing for halloween species
|
||||
/proc/force_enable_halloween_species()
|
||||
var/list/oldlist = SSevents.holidays
|
||||
|
||||
@@ -8,61 +8,73 @@
|
||||
..()
|
||||
return late ? INITIALIZE_HINT_LATELOAD : INITIALIZE_HINT_QDEL
|
||||
|
||||
|
||||
//airlock helpers
|
||||
/obj/effect/mapping_helpers/airlock
|
||||
layer = DOOR_HELPER_LAYER
|
||||
|
||||
/obj/effect/mapping_helpers/airlock/Initialize(mapload)
|
||||
. = ..()
|
||||
if(!mapload)
|
||||
log_mapping("[src] spawned outside of mapload!")
|
||||
return
|
||||
var/obj/machinery/door/airlock/airlock = locate(/obj/machinery/door/airlock) in loc
|
||||
if(!airlock)
|
||||
log_mapping("[src] failed to find an airlock at [AREACOORD(src)]")
|
||||
else
|
||||
payload(airlock)
|
||||
|
||||
/obj/effect/mapping_helpers/airlock/proc/payload(obj/machinery/door/airlock/payload)
|
||||
return
|
||||
|
||||
/obj/effect/mapping_helpers/airlock/cyclelink_helper
|
||||
name = "airlock cyclelink helper"
|
||||
icon_state = "airlock_cyclelink_helper"
|
||||
|
||||
/obj/effect/mapping_helpers/airlock/cyclelink_helper/Initialize(mapload)
|
||||
. = ..()
|
||||
if(!mapload)
|
||||
log_mapping("[src] spawned outside of mapload!")
|
||||
return
|
||||
var/obj/machinery/door/airlock/airlock = locate(/obj/machinery/door/airlock) in loc
|
||||
if(airlock)
|
||||
if(airlock.cyclelinkeddir)
|
||||
log_mapping("[src] at [AREACOORD(src)] tried to set [airlock] cyclelinkeddir, but it's already set!")
|
||||
else
|
||||
airlock.cyclelinkeddir = dir
|
||||
/obj/effect/mapping_helpers/airlock/cyclelink_helper/payload(obj/machinery/door/airlock/airlock)
|
||||
if(airlock.cyclelinkeddir)
|
||||
log_mapping("[src] at [AREACOORD(src)] tried to set [airlock] cyclelinkeddir, but it's already set!")
|
||||
else
|
||||
log_mapping("[src] failed to find an airlock at [AREACOORD(src)]")
|
||||
airlock.cyclelinkeddir = dir
|
||||
|
||||
/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi
|
||||
name = "airlock multi-cyclelink helper"
|
||||
icon_state = "airlock_multicyclelink_helper"
|
||||
var/cycle_id
|
||||
|
||||
/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi/payload(obj/machinery/door/airlock/airlock)
|
||||
if(airlock.closeOtherId)
|
||||
log_mapping("[src] at [AREACOORD(src)] tried to set [airlock] closeOtherId, but it's already set!")
|
||||
else
|
||||
airlock.closeOtherId = cycle_id
|
||||
|
||||
/obj/effect/mapping_helpers/airlock/locked
|
||||
name = "airlock lock helper"
|
||||
icon_state = "airlock_locked_helper"
|
||||
|
||||
/obj/effect/mapping_helpers/airlock/locked/Initialize(mapload)
|
||||
. = ..()
|
||||
if(!mapload)
|
||||
log_mapping("[src] spawned outside of mapload!")
|
||||
return
|
||||
var/obj/machinery/door/airlock/airlock = locate(/obj/machinery/door/airlock) in loc
|
||||
if(airlock)
|
||||
if(airlock.locked)
|
||||
log_mapping("[src] at [AREACOORD(src)] tried to bolt [airlock] but it's already locked!")
|
||||
else
|
||||
airlock.locked = TRUE
|
||||
/obj/effect/mapping_helpers/airlock/locked/payload(obj/machinery/door/airlock/airlock)
|
||||
if(airlock.locked)
|
||||
log_mapping("[src] at [AREACOORD(src)] tried to bolt [airlock] but it's already locked!")
|
||||
else
|
||||
log_mapping("[src] failed to find an airlock at [AREACOORD(src)]")
|
||||
airlock.locked = TRUE
|
||||
|
||||
|
||||
/obj/effect/mapping_helpers/airlock/unres
|
||||
name = "airlock unresctricted side helper"
|
||||
icon_state = "airlock_unres_helper"
|
||||
|
||||
/obj/effect/mapping_helpers/airlock/unres/Initialize(mapload)
|
||||
. = ..()
|
||||
if(!mapload)
|
||||
log_mapping("[src] spawned outside of mapload!")
|
||||
return
|
||||
var/obj/machinery/door/airlock/airlock = locate(/obj/machinery/door/airlock) in loc
|
||||
if(airlock)
|
||||
airlock.unres_sides ^= dir
|
||||
/obj/effect/mapping_helpers/airlock/unres/payload(obj/machinery/door/airlock/airlock)
|
||||
airlock.unres_sides ^= dir
|
||||
|
||||
/obj/effect/mapping_helpers/airlock/abandoned
|
||||
name = "airlock abandoned helper"
|
||||
icon_state = "airlock_abandoned"
|
||||
|
||||
/obj/effect/mapping_helpers/airlock/abandoned/payload(obj/machinery/door/airlock/airlock)
|
||||
if(airlock.abandoned)
|
||||
log_mapping("[src] at [AREACOORD(src)] tried to make [airlock] abandoned but it's already abandoned!")
|
||||
else
|
||||
log_mapping("[src] failed to find an airlock at [AREACOORD(src)]")
|
||||
airlock.abandoned = TRUE
|
||||
|
||||
|
||||
//needs to do its thing before spawn_rivers() is called
|
||||
@@ -79,9 +91,11 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava)
|
||||
//This helper applies components to things on the map directly.
|
||||
/obj/effect/mapping_helpers/component_injector
|
||||
name = "Component Injector"
|
||||
icon_state = "component"
|
||||
late = TRUE
|
||||
var/target_type
|
||||
var/target_name
|
||||
var/all = FALSE //Will inject into all fitting the criteria if true, otherwise first found
|
||||
var/target_type //Will inject into atoms of this type
|
||||
var/target_name //Will inject into atoms with this name
|
||||
var/component_type
|
||||
|
||||
//Late init so everything is likely ready and loaded (no warranty)
|
||||
@@ -98,8 +112,11 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava)
|
||||
continue
|
||||
var/cargs = build_args()
|
||||
A._AddComponent(cargs)
|
||||
if(!all)
|
||||
qdel(src)
|
||||
return
|
||||
if(all)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
/obj/effect/mapping_helpers/component_injector/proc/build_args()
|
||||
return list(component_type)
|
||||
@@ -115,3 +132,276 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava)
|
||||
CRASH("Wrong disease type passed in.")
|
||||
var/datum/disease/D = new disease_type()
|
||||
return list(component_type,D)
|
||||
|
||||
// /obj/effect/mapping_helpers/component_injector/areabound
|
||||
// name = "Areabound Injector"
|
||||
// icon_state = "component_areabound"
|
||||
// component_type = /datum/component/areabound
|
||||
// target_type = /atom/movable
|
||||
|
||||
/obj/effect/mapping_helpers/dead_body_placer
|
||||
name = "Dead Body placer"
|
||||
late = TRUE
|
||||
icon_state = "deadbodyplacer"
|
||||
var/bodycount = 2 //number of bodies to spawn
|
||||
|
||||
/obj/effect/mapping_helpers/dead_body_placer/LateInitialize()
|
||||
var/area/a = get_area(src)
|
||||
var/list/trays = list()
|
||||
for (var/i in a.contents)
|
||||
if (istype(i, /obj/structure/bodycontainer/morgue))
|
||||
trays += i
|
||||
if(!trays.len)
|
||||
log_mapping("[src] at [x],[y] could not find any morgues.")
|
||||
return
|
||||
for (var/i = 1 to bodycount)
|
||||
var/obj/structure/bodycontainer/morgue/j = pick(trays)
|
||||
var/mob/living/carbon/human/h = new /mob/living/carbon/human(j, 1)
|
||||
h.death()
|
||||
for (var/part in h.internal_organs) //randomly remove organs from each body, set those we keep to be in stasis
|
||||
if (prob(40))
|
||||
qdel(part)
|
||||
else
|
||||
var/obj/item/organ/O = part
|
||||
O.organ_flags |= ORGAN_FROZEN
|
||||
j.update_appearance()
|
||||
qdel(src)
|
||||
|
||||
|
||||
//On Ian's birthday, the hop's office is decorated.
|
||||
/obj/effect/mapping_helpers/ianbirthday
|
||||
name = "Ian's Bday Helper"
|
||||
late = TRUE
|
||||
icon_state = "iansbdayhelper"
|
||||
var/balloon_clusters = 2
|
||||
|
||||
/obj/effect/mapping_helpers/ianbirthday/LateInitialize()
|
||||
if(locate(/datum/holiday/ianbirthday) in SSevents.holidays)
|
||||
birthday()
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/mapping_helpers/ianbirthday/proc/birthday()
|
||||
var/area/a = get_area(src)
|
||||
var/list/table = list()//should only be one aka the front desk, but just in case...
|
||||
var/list/openturfs = list()
|
||||
|
||||
//confetti and a corgi balloon! (and some list stuff for more decorations)
|
||||
for(var/thing in a.contents)
|
||||
if(istype(thing, /obj/structure/table/reinforced))
|
||||
table += thing
|
||||
if(isopenturf(thing))
|
||||
// new /obj/effect/decal/cleanable/confetti(thing)
|
||||
// if(locate(/obj/structure/bed/dogbed/ian) in thing)
|
||||
// new /obj/item/toy/balloon/corgi(thing)
|
||||
// else
|
||||
openturfs += thing
|
||||
|
||||
//cake + knife to cut it!
|
||||
if(length(table))
|
||||
var/turf/food_turf = get_turf(pick(table))
|
||||
new /obj/item/kitchen/knife(food_turf)
|
||||
var/obj/item/reagent_containers/food/snacks/store/cake/birthday/iancake = new(food_turf)
|
||||
iancake.desc = "Happy birthday, Ian!"
|
||||
// remind me to give ian proper baloons!
|
||||
//some balloons! this picks an open turf and pops a few balloons in and around that turf, yay.
|
||||
// for(var/i in 1 to balloon_clusters)
|
||||
// var/turf/clusterspot = pick_n_take(openturfs)
|
||||
// new /obj/item/toy/balloon(clusterspot)
|
||||
// var/balloons_left_to_give = 3 //the amount of balloons around the cluster
|
||||
// var/list/dirs_to_balloon = GLOB.cardinals.Copy()
|
||||
// while(balloons_left_to_give > 0)
|
||||
// balloons_left_to_give--
|
||||
// var/chosen_dir = pick_n_take(dirs_to_balloon)
|
||||
// var/turf/balloonstep = get_step(clusterspot, chosen_dir)
|
||||
// var/placed = FALSE
|
||||
// if(isopenturf(balloonstep))
|
||||
// var/obj/item/toy/balloon/B = new(balloonstep)//this clumps the cluster together
|
||||
// placed = TRUE
|
||||
// if(chosen_dir == NORTH)
|
||||
// B.pixel_y -= 10
|
||||
// if(chosen_dir == SOUTH)
|
||||
// B.pixel_y += 10
|
||||
// if(chosen_dir == EAST)
|
||||
// B.pixel_x -= 10
|
||||
// if(chosen_dir == WEST)
|
||||
// B.pixel_x += 10
|
||||
// if(!placed)
|
||||
// new /obj/item/toy/balloon(clusterspot)
|
||||
//remind me to add wall decor!
|
||||
|
||||
/obj/effect/mapping_helpers/ianbirthday/admin//so admins may birthday any room
|
||||
name = "generic birthday setup"
|
||||
icon_state = "bdayhelper"
|
||||
|
||||
/obj/effect/mapping_helpers/ianbirthday/admin/LateInitialize()
|
||||
birthday()
|
||||
qdel(src)
|
||||
|
||||
//Ian, like most dogs, loves a good new years eve party.
|
||||
/obj/effect/mapping_helpers/iannewyear
|
||||
name = "Ian's New Years Helper"
|
||||
late = TRUE
|
||||
icon_state = "iansnewyrshelper"
|
||||
|
||||
/obj/effect/mapping_helpers/iannewyear/LateInitialize()
|
||||
if(SSevents.holidays && SSevents.holidays[NEW_YEAR])
|
||||
fireworks()
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/mapping_helpers/iannewyear/proc/fireworks()
|
||||
var/area/a = get_area(src)
|
||||
var/list/table = list()//should only be one aka the front desk, but just in case...
|
||||
var/list/openturfs = list()
|
||||
|
||||
for(var/thing in a.contents)
|
||||
if(istype(thing, /obj/structure/table/reinforced))
|
||||
table += thing
|
||||
else if(isopenturf(thing))
|
||||
if(locate(/obj/structure/bed/dogbed/ian) in thing)
|
||||
new /obj/item/clothing/head/festive(thing)
|
||||
var/obj/item/reagent_containers/food/drinks/bottle/champagne/iandrink = new(thing)
|
||||
iandrink.name = "dog champagne"
|
||||
iandrink.pixel_y += 8
|
||||
iandrink.pixel_x += 8
|
||||
else
|
||||
openturfs += thing
|
||||
|
||||
var/turf/fireworks_turf = get_turf(pick(table))
|
||||
var/obj/item/storage/box/matches/matchbox = new(fireworks_turf)
|
||||
matchbox.pixel_y += 8
|
||||
matchbox.pixel_x -= 3
|
||||
// new /obj/item/storage/box/fireworks/dangerous(fireworks_turf) //dangerous version for extra holiday memes.
|
||||
|
||||
//lets mappers place notes on airlocks with custom info or a pre-made note from a path
|
||||
/obj/effect/mapping_helpers/airlock_note_placer
|
||||
name = "Airlock Note Placer"
|
||||
late = TRUE
|
||||
icon_state = "airlocknoteplacer"
|
||||
var/note_info //for writing out custom notes without creating an extra paper subtype
|
||||
var/note_name //custom note name
|
||||
var/note_path //if you already have something wrote up in a paper subtype, put the path here
|
||||
|
||||
/obj/effect/mapping_helpers/airlock_note_placer/LateInitialize()
|
||||
var/turf/turf = get_turf(src)
|
||||
if(note_path && !istype(note_path, /obj/item/paper)) //don't put non-paper in the paper slot thank you
|
||||
log_mapping("[src] at [x],[y] had an improper note_path path, could not place paper note.")
|
||||
qdel(src)
|
||||
if(locate(/obj/machinery/door/airlock) in turf)
|
||||
var/obj/machinery/door/airlock/found_airlock = locate(/obj/machinery/door/airlock) in turf
|
||||
if(note_path)
|
||||
found_airlock.note = note_path
|
||||
found_airlock.update_appearance()
|
||||
qdel(src)
|
||||
if(note_info)
|
||||
var/obj/item/paper/paper = new /obj/item/paper(src)
|
||||
if(note_name)
|
||||
paper.name = note_name
|
||||
paper.info = "[note_info]"
|
||||
found_airlock.note = paper
|
||||
paper.forceMove(found_airlock)
|
||||
found_airlock.update_appearance()
|
||||
qdel(src)
|
||||
log_mapping("[src] at [x],[y] had no note_path or note_info, cannot place paper note.")
|
||||
qdel(src)
|
||||
log_mapping("[src] at [x],[y] could not find an airlock on current turf, cannot place paper note.")
|
||||
qdel(src)
|
||||
|
||||
//This helper applies traits to things on the map directly.
|
||||
/obj/effect/mapping_helpers/trait_injector
|
||||
name = "Trait Injector"
|
||||
icon_state = "trait"
|
||||
late = TRUE
|
||||
///Will inject into all fitting the criteria if false, otherwise first found.
|
||||
var/first_match_only = TRUE
|
||||
///Will inject into atoms of this type.
|
||||
var/target_type
|
||||
///Will inject into atoms with this name.
|
||||
var/target_name
|
||||
///Name of the trait, in the lower-case text (NOT the upper-case define) form.
|
||||
var/trait_name
|
||||
|
||||
//Late init so everything is likely ready and loaded (no warranty)
|
||||
/obj/effect/mapping_helpers/trait_injector/LateInitialize()
|
||||
if(!GLOB.trait_name_map)
|
||||
GLOB.trait_name_map = generate_trait_name_map()
|
||||
if(!GLOB.trait_name_map.Find(trait_name))
|
||||
CRASH("Wrong trait in [type] - [trait_name] is not a trait")
|
||||
var/turf/target_turf = get_turf(src)
|
||||
var/matches_found = 0
|
||||
for(var/a in target_turf.GetAllContents())
|
||||
var/atom/atom_on_turf = a
|
||||
if(atom_on_turf == src)
|
||||
continue
|
||||
if(target_name && atom_on_turf.name != target_name)
|
||||
continue
|
||||
if(target_type && !istype(atom_on_turf,target_type))
|
||||
continue
|
||||
ADD_TRAIT(atom_on_turf, trait_name, MAPPING_HELPER_TRAIT)
|
||||
matches_found++
|
||||
if(first_match_only)
|
||||
qdel(src)
|
||||
return
|
||||
if(!matches_found)
|
||||
stack_trace("Trait mapper found no targets at ([x], [y], [z]). First Match Only: [first_match_only ? "true" : "false"] target type: [target_type] | target name: [target_name] | trait name: [trait_name]")
|
||||
qdel(src)
|
||||
|
||||
/// Fetches an external dmi and applies to the target object
|
||||
/obj/effect/mapping_helpers/custom_icon
|
||||
name = "Custom Icon Helper"
|
||||
icon_state = "trait"
|
||||
late = TRUE
|
||||
///Will inject into all fitting the criteria if false, otherwise first found.
|
||||
var/first_match_only = TRUE
|
||||
///Will inject into atoms of this type.
|
||||
var/target_type
|
||||
///Will inject into atoms with this name.
|
||||
var/target_name
|
||||
/// This is the var tha will be set with the fetched icon. In case you want to set some secondary icon sheets like inhands and such.
|
||||
var/target_variable = "icon"
|
||||
/// This should return raw dmi in response to http get request. For example: "https://github.com/tgstation/SS13-sprites/raw/master/mob/medu.dmi?raw=true"
|
||||
var/icon_url
|
||||
|
||||
/obj/effect/mapping_helpers/custom_icon/LateInitialize()
|
||||
///TODO put this injector stuff under common root
|
||||
var/I = fetch_icon(icon_url)
|
||||
var/turf/target_turf = get_turf(src)
|
||||
var/matches_found = 0
|
||||
for(var/a in target_turf.GetAllContents())
|
||||
var/atom/atom_on_turf = a
|
||||
if(atom_on_turf == src)
|
||||
continue
|
||||
if(target_name && atom_on_turf.name != target_name)
|
||||
continue
|
||||
if(target_type && !istype(atom_on_turf,target_type))
|
||||
continue
|
||||
atom_on_turf.vars[target_variable] = I
|
||||
matches_found++
|
||||
if(first_match_only)
|
||||
qdel(src)
|
||||
return
|
||||
if(!matches_found)
|
||||
stack_trace("[src] found no targets at ([x], [y], [z]). First Match Only: [first_match_only ? "true" : "false"] target type: [target_type] | target name: [target_name]")
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/mapping_helpers/custom_icon/proc/fetch_icon(url)
|
||||
var/static/icon_cache = list()
|
||||
var/static/query_in_progress = FALSE //We're using a single tmp file so keep it linear.
|
||||
if(query_in_progress)
|
||||
UNTIL(!query_in_progress)
|
||||
if(icon_cache[url])
|
||||
return icon_cache[url]
|
||||
log_asset("Custom Icon Helper fetching dmi from: [url]")
|
||||
var/datum/http_request/request = new()
|
||||
var/file_name = "tmp/custom_map_icon.dmi"
|
||||
request.prepare(RUSTG_HTTP_METHOD_GET, url , "", "", file_name)
|
||||
query_in_progress = TRUE
|
||||
request.begin_async()
|
||||
UNTIL(request.is_complete())
|
||||
var/datum/http_response/response = request.into_response()
|
||||
if(response.errored || response.status_code != 200)
|
||||
query_in_progress = FALSE
|
||||
CRASH("Failed to fetch mapped custom icon from url [url], code: [response.status_code], error: [response.error]")
|
||||
var/icon/I = new(file_name)
|
||||
icon_cache[url] = I
|
||||
query_in_progress = FALSE
|
||||
return I
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/baseturf_helper/proc/replace_baseturf(turf/thing)
|
||||
var/list/baseturf_cache = thing.baseturfs
|
||||
if(length(baseturf_cache))
|
||||
if(length(thing.baseturfs))
|
||||
var/list/baseturf_cache = thing.baseturfs.Copy()
|
||||
for(var/i in baseturf_cache)
|
||||
if(baseturf_to_replace[i])
|
||||
baseturf_cache -= i
|
||||
@@ -44,6 +44,8 @@
|
||||
else
|
||||
thing.PlaceOnBottom(null, baseturf)
|
||||
|
||||
|
||||
|
||||
/obj/effect/baseturf_helper/space
|
||||
name = "space baseturf editor"
|
||||
baseturf = /turf/open/space
|
||||
@@ -79,4 +81,3 @@
|
||||
/obj/effect/baseturf_helper/lava_land/surface
|
||||
name = "lavaland baseturf editor"
|
||||
baseturf = /turf/open/lava/smooth/lava_land_surface
|
||||
|
||||
|
||||
@@ -32,47 +32,79 @@
|
||||
/// Intended to be used in the manner of `TEST_FOCUS(/datum/unit_test/math)`
|
||||
#define TEST_FOCUS(test_path) ##test_path { focus = TRUE; }
|
||||
|
||||
/// Constants indicating unit test completion status
|
||||
#define UNIT_TEST_PASSED 0
|
||||
#define UNIT_TEST_FAILED 1
|
||||
#define UNIT_TEST_SKIPPED 2
|
||||
|
||||
#define TEST_DEFAULT 1
|
||||
#define TEST_DEL_WORLD INFINITY
|
||||
|
||||
/// A trait source when adding traits through unit tests
|
||||
#define TRAIT_SOURCE_UNIT_TESTS "unit_tests"
|
||||
|
||||
#include "anchored_mobs.dm"
|
||||
#include "bespoke_id.dm"
|
||||
#include "binary_insert.dm"
|
||||
// #include "bloody_footprints.dm"
|
||||
// #include "breath.dm"
|
||||
// #include "card_mismatch.dm"
|
||||
#include "chain_pull_through_space.dm"
|
||||
// #include "combat.dm"
|
||||
#include "component_tests.dm"
|
||||
// #include "connect_loc.dm"
|
||||
// #include "confusion.dm"
|
||||
// #include "crayons.dm"
|
||||
// #include "create_and_destroy.dm"
|
||||
// #include "designs.dm"
|
||||
// #include "dynamic_ruleset_sanity.dm"
|
||||
// #include "egg_glands.dm"
|
||||
// #include "emoting.dm"
|
||||
// #include "food_edibility_check.dm"
|
||||
// #include "greyscale_config.dm"
|
||||
// #include "heretic_knowledge.dm"
|
||||
// #include "holidays.dm"
|
||||
#include "initialize_sanity.dm"
|
||||
// #include "hydroponics_harvest.dm"
|
||||
// #include "keybinding_init.dm"
|
||||
#include "machine_disassembly.dm"
|
||||
#include "medical_wounds.dm"
|
||||
#include "merge_type.dm"
|
||||
// #include "metabolizing.dm"
|
||||
// #include "ntnetwork_tests.dm"
|
||||
// #include "outfit_sanity.dm"
|
||||
// #include "pills.dm"
|
||||
// #include "plantgrowth_tests.dm"
|
||||
// #include "projectiles.dm"
|
||||
// #include "rcd.dm"
|
||||
#include "reagent_id_typos.dm"
|
||||
// #include "reagent_mod_expose.dm"
|
||||
// #include "reagent_mod_procs.dm"
|
||||
#include "reagent_recipe_collisions.dm"
|
||||
#include "resist.dm"
|
||||
// #include "say.dm"
|
||||
// #include "security_officer_distribution.dm"
|
||||
// #include "serving_tray.dm"
|
||||
// #include "siunit.dm"
|
||||
#include "spawn_humans.dm"
|
||||
#include "spawn_mobs.dm"
|
||||
// #include "species_whitelists.dm"
|
||||
// #include "stomach.dm"
|
||||
// #include "strippable.dm"
|
||||
#include "subsystem_init.dm"
|
||||
#include "surgeries.dm"
|
||||
#include "teleporters.dm"
|
||||
#include "tgui_create_message.dm"
|
||||
#include "timer_sanity.dm"
|
||||
#include "unit_test.dm"
|
||||
// #include "wizard.dm"
|
||||
|
||||
/// CIT TESTS
|
||||
#include "character_saving.dm"
|
||||
|
||||
#ifdef REFERENCE_TRACKING //Don't try and parse this file if ref tracking isn't turned on. IE: don't parse ref tracking please mr linter
|
||||
#include "find_reference_sanity.dm"
|
||||
#endif
|
||||
|
||||
#undef TEST_ASSERT
|
||||
#undef TEST_ASSERT_EQUAL
|
||||
#undef TEST_ASSERT_NOTEQUAL
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/datum/unit_test/chain_pull_through_space
|
||||
var/turf/open/space/space_tile
|
||||
var/turf/claimed_tile
|
||||
var/claimed_tile
|
||||
var/mob/living/carbon/human/alice
|
||||
var/mob/living/carbon/human/bob
|
||||
var/mob/living/carbon/human/charlie
|
||||
@@ -9,25 +9,25 @@
|
||||
..()
|
||||
|
||||
// Create a space tile that goes to another z-level
|
||||
claimed_tile = run_loc_bottom_left
|
||||
claimed_tile = run_loc_floor_bottom_left.type
|
||||
|
||||
space_tile = new(locate(run_loc_bottom_left.x, run_loc_bottom_left.y, run_loc_bottom_left.z))
|
||||
space_tile = new(locate(run_loc_floor_bottom_left.x, run_loc_floor_bottom_left.y, run_loc_floor_bottom_left.z))
|
||||
space_tile.destination_x = 100
|
||||
space_tile.destination_y = 100
|
||||
space_tile.destination_z = 5
|
||||
|
||||
// Create our list of humans, all adjacent to one another
|
||||
alice = new(locate(run_loc_bottom_left.x + 2, run_loc_bottom_left.y, run_loc_bottom_left.z))
|
||||
alice = new(locate(run_loc_floor_bottom_left.x + 2, run_loc_floor_bottom_left.y, run_loc_floor_bottom_left.z))
|
||||
alice.name = "Alice"
|
||||
|
||||
bob = new(locate(run_loc_bottom_left.x + 3, run_loc_bottom_left.y, run_loc_bottom_left.z))
|
||||
bob = new(locate(run_loc_floor_bottom_left.x + 3, run_loc_floor_bottom_left.y, run_loc_floor_bottom_left.z))
|
||||
bob.name = "Bob"
|
||||
|
||||
charlie = new(locate(run_loc_bottom_left.x + 4, run_loc_bottom_left.y, run_loc_bottom_left.z))
|
||||
charlie = new(locate(run_loc_floor_bottom_left.x + 4, run_loc_floor_bottom_left.y, run_loc_floor_bottom_left.z))
|
||||
charlie.name = "Charlie"
|
||||
|
||||
/datum/unit_test/chain_pull_through_space/Destroy()
|
||||
space_tile.copyTurf(claimed_tile)
|
||||
space_tile.ChangeTurf(claimed_tile)
|
||||
qdel(alice)
|
||||
qdel(bob)
|
||||
qdel(charlie)
|
||||
@@ -40,14 +40,14 @@
|
||||
bob.start_pulling(charlie)
|
||||
|
||||
// Walk normally to the left, make sure we're still a chain
|
||||
alice.Move(locate(run_loc_bottom_left.x + 1, run_loc_bottom_left.y, run_loc_bottom_left.z))
|
||||
if (bob.x != run_loc_bottom_left.x + 2)
|
||||
alice.Move(locate(run_loc_floor_bottom_left.x + 1, run_loc_floor_bottom_left.y, run_loc_floor_bottom_left.z))
|
||||
if (bob.x != run_loc_floor_bottom_left.x + 2)
|
||||
return Fail("During normal move, Bob was not at the correct x ([bob.x])")
|
||||
if (charlie.x != run_loc_bottom_left.x + 3)
|
||||
if (charlie.x != run_loc_floor_bottom_left.x + 3)
|
||||
return Fail("During normal move, Charlie was not at the correct x ([charlie.x])")
|
||||
|
||||
// We're going through the space turf now that should teleport us
|
||||
alice.Move(run_loc_bottom_left)
|
||||
alice.Move(run_loc_floor_bottom_left)
|
||||
if (alice.z != space_tile.destination_z)
|
||||
return Fail("Alice did not teleport to the destination z-level. Current location: ([alice.x], [alice.y], [alice.z])")
|
||||
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
///Used to test the completeness of the reference finder proc.
|
||||
/datum/unit_test/find_reference_sanity
|
||||
|
||||
/atom/movable/ref_holder
|
||||
var/atom/movable/ref_test/test
|
||||
var/list/test_list = list()
|
||||
var/list/test_assoc_list = list()
|
||||
|
||||
/atom/movable/ref_holder/Destroy()
|
||||
test = null
|
||||
test_list.Cut()
|
||||
test_assoc_list.Cut()
|
||||
return ..()
|
||||
|
||||
/atom/movable/ref_test
|
||||
var/atom/movable/ref_test/self_ref
|
||||
|
||||
/atom/movable/ref_test/Destroy(force)
|
||||
self_ref = null
|
||||
return ..()
|
||||
|
||||
/datum/unit_test/find_reference_sanity/Run()
|
||||
var/atom/movable/ref_test/victim = allocate(/atom/movable/ref_test)
|
||||
var/atom/movable/ref_holder/testbed = allocate(/atom/movable/ref_holder)
|
||||
SSgarbage.should_save_refs = TRUE
|
||||
|
||||
//Sanity check
|
||||
victim.DoSearchVar(testbed, "Sanity Check", search_time = 1) //We increment search time to get around an optimization
|
||||
TEST_ASSERT(!victim.found_refs.len, "The ref-tracking tool found a ref where none existed")
|
||||
SSgarbage.should_save_refs = FALSE
|
||||
|
||||
/datum/unit_test/find_reference_baseline/Run()
|
||||
var/atom/movable/ref_test/victim = allocate(/atom/movable/ref_test)
|
||||
var/atom/movable/ref_holder/testbed = allocate(/atom/movable/ref_holder)
|
||||
SSgarbage.should_save_refs = TRUE
|
||||
|
||||
//Set up for the first round of tests
|
||||
testbed.test = victim
|
||||
testbed.test_list += victim
|
||||
testbed.test_assoc_list["baseline"] = victim
|
||||
|
||||
victim.DoSearchVar(testbed, "First Run", search_time = 2)
|
||||
|
||||
TEST_ASSERT(victim.found_refs["test"], "The ref-tracking tool failed to find a regular value")
|
||||
TEST_ASSERT(victim.found_refs[testbed.test_list], "The ref-tracking tool failed to find a list entry")
|
||||
TEST_ASSERT(victim.found_refs[testbed.test_assoc_list], "The ref-tracking tool failed to find an assoc list value")
|
||||
SSgarbage.should_save_refs = FALSE
|
||||
|
||||
/datum/unit_test/find_reference_exotic/Run()
|
||||
var/atom/movable/ref_test/victim = allocate(/atom/movable/ref_test)
|
||||
var/atom/movable/ref_holder/testbed = allocate(/atom/movable/ref_holder)
|
||||
SSgarbage.should_save_refs = TRUE
|
||||
|
||||
//Second round, bit harder this time
|
||||
testbed.overlays += victim
|
||||
testbed.vis_contents += victim
|
||||
testbed.test_assoc_list[victim] = TRUE
|
||||
|
||||
victim.DoSearchVar(testbed, "Second Run", search_time = 3)
|
||||
|
||||
//This is another sanity check
|
||||
TEST_ASSERT(!victim.found_refs[testbed.overlays], "The ref-tracking tool found an overlays entry? That shouldn't be possible")
|
||||
TEST_ASSERT(victim.found_refs[testbed.vis_contents], "The ref-tracking tool failed to find a vis_contents entry")
|
||||
TEST_ASSERT(victim.found_refs[testbed.test_assoc_list], "The ref-tracking tool failed to find an assoc list key")
|
||||
SSgarbage.should_save_refs = FALSE
|
||||
|
||||
/datum/unit_test/find_reference_esoteric/Run()
|
||||
var/atom/movable/ref_test/victim = allocate(/atom/movable/ref_test)
|
||||
var/atom/movable/ref_holder/testbed = allocate(/atom/movable/ref_holder)
|
||||
SSgarbage.should_save_refs = TRUE
|
||||
|
||||
//Let's get a bit esoteric
|
||||
victim.self_ref = victim
|
||||
var/list/to_find = list(victim)
|
||||
testbed.test_list += list(to_find)
|
||||
var/list/to_find_assoc = list(victim)
|
||||
testbed.test_assoc_list["Nesting"] = to_find_assoc
|
||||
|
||||
victim.DoSearchVar(victim, "Third Run Self", search_time = 4)
|
||||
victim.DoSearchVar(testbed, "Third Run Testbed", search_time = 4)
|
||||
TEST_ASSERT(victim.found_refs["self_ref"], "The ref-tracking tool failed to find a self reference")
|
||||
TEST_ASSERT(victim.found_refs[to_find], "The ref-tracking tool failed to find a nested list entry")
|
||||
TEST_ASSERT(victim.found_refs[to_find_assoc], "The ref-tracking tool failed to find a nested assoc list entry")
|
||||
SSgarbage.should_save_refs = FALSE
|
||||
|
||||
/datum/unit_test/find_reference_null_key_entry/Run()
|
||||
var/atom/movable/ref_test/victim = allocate(/atom/movable/ref_test)
|
||||
var/atom/movable/ref_holder/testbed = allocate(/atom/movable/ref_holder)
|
||||
SSgarbage.should_save_refs = TRUE
|
||||
|
||||
//Calm before the storm
|
||||
testbed.test_assoc_list = list(null = victim)
|
||||
|
||||
victim.DoSearchVar(testbed, "Fourth Run", search_time = 5)
|
||||
TEST_ASSERT(testbed.test_assoc_list, "The ref-tracking tool failed to find a null key'd assoc list entry")
|
||||
|
||||
/datum/unit_test/find_reference_assoc_investigation/Run()
|
||||
var/atom/movable/ref_test/victim = allocate(/atom/movable/ref_test)
|
||||
var/atom/movable/ref_holder/testbed = allocate(/atom/movable/ref_holder)
|
||||
SSgarbage.should_save_refs = TRUE
|
||||
|
||||
//Let's do some more complex assoc list investigation
|
||||
var/list/to_find_in_key = list(victim)
|
||||
testbed.test_assoc_list[to_find_in_key] = list("memes")
|
||||
var/list/to_find_null_assoc_nested = list(victim)
|
||||
testbed.test_assoc_list[null] = to_find_null_assoc_nested
|
||||
|
||||
victim.DoSearchVar(testbed, "Fifth Run", search_time = 6)
|
||||
TEST_ASSERT(victim.found_refs[to_find_in_key], "The ref-tracking tool failed to find a nested assoc list key")
|
||||
TEST_ASSERT(victim.found_refs[to_find_null_assoc_nested], "The ref-tracking tool failed to find a null key'd nested assoc list entry")
|
||||
SSgarbage.should_save_refs = FALSE
|
||||
@@ -1,11 +0,0 @@
|
||||
/datum/unit_test/initialize_sanity/Run()
|
||||
if(length(SSatoms.BadInitializeCalls))
|
||||
Fail("Bad Initialize() calls detected. Please read logs.")
|
||||
var/list/init_failures_to_text = list(
|
||||
"[BAD_INIT_QDEL_BEFORE]" = "Qdeleted Before Initialized",
|
||||
"[BAD_INIT_DIDNT_INIT]" = "Did Not Initialize",
|
||||
"[BAD_INIT_SLEPT]" = "Initialize() Slept",
|
||||
"[BAD_INIT_NO_HINT]" = "No Initialize() Hint Returned",
|
||||
)
|
||||
for(var/failure in SSatoms.BadInitializeCalls)
|
||||
log_world("[failure]: [init_failures_to_text["[SSatoms.BadInitializeCalls[failure]]"]]") // You like stacked brackets?
|
||||
@@ -1,23 +0,0 @@
|
||||
/// Test to verify message mods are parsed correctly
|
||||
/datum/unit_test/get_message_mods
|
||||
var/mob/host_mob
|
||||
|
||||
/datum/unit_test/get_message_mods/Run()
|
||||
host_mob = allocate(/mob/living/carbon/human)
|
||||
|
||||
test("Hello", "Hello", list())
|
||||
test(";HELP", "HELP", list(MODE_HEADSET = TRUE))
|
||||
test(";%Never gonna give you up", "Never gonna give you up", list(MODE_HEADSET = TRUE, MODE_SING = TRUE))
|
||||
test(".s Gun plz", "Gun plz", list(RADIO_KEY = RADIO_KEY_SECURITY, RADIO_EXTENSION = RADIO_CHANNEL_SECURITY))
|
||||
test("...What", "...What", list())
|
||||
|
||||
/datum/unit_test/get_message_mods/proc/test(message, expected_message, list/expected_mods)
|
||||
var/list/mods = list()
|
||||
TEST_ASSERT_EQUAL(host_mob.get_message_mods(message, mods), expected_message, "Chopped message was not what we expected. Message: [message]")
|
||||
|
||||
for (var/mod_key in mods)
|
||||
TEST_ASSERT_EQUAL(mods[mod_key], expected_mods[mod_key], "The value for [mod_key] was not what we expected. Message: [message]")
|
||||
expected_mods -= mod_key
|
||||
|
||||
if (expected_mods.len)
|
||||
Fail("Some message mods were expected, but were not returned by get_message_mods: [json_encode(expected_mods)]. Message: [message]")
|
||||
@@ -1,5 +1,5 @@
|
||||
/datum/unit_test/spawn_humans/Run()
|
||||
var/locs = block(run_loc_bottom_left, run_loc_top_right)
|
||||
var/locs = block(run_loc_floor_bottom_left, run_loc_floor_top_right)
|
||||
|
||||
for(var/I in 1 to 5)
|
||||
new /mob/living/carbon/human(pick(locs))
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
///Unit test that spawns all mobs that can be spawned by golden slimes
|
||||
/datum/unit_test/spawn_mobs
|
||||
|
||||
/datum/unit_test/spawn_mobs/Run()
|
||||
for(var/_animal in typesof(/mob/living/simple_animal))
|
||||
var/mob/living/simple_animal/animal = _animal
|
||||
if (initial(animal.gold_core_spawnable) == HOSTILE_SPAWN || initial(animal.gold_core_spawnable) == FRIENDLY_SPAWN)
|
||||
allocate(_animal)
|
||||
@@ -1,8 +1,8 @@
|
||||
/datum/unit_test/auto_teleporter_linking/Run()
|
||||
// Put down the teleporter machinery
|
||||
var/obj/machinery/teleport/hub/hub = allocate(/obj/machinery/teleport/hub)
|
||||
var/obj/machinery/computer/teleporter/computer = allocate(/obj/machinery/computer/teleporter, locate(run_loc_bottom_left.x + 2, run_loc_bottom_left.y, run_loc_bottom_left.z))
|
||||
var/obj/machinery/teleport/station/station = allocate(/obj/machinery/teleport/station, locate(run_loc_bottom_left.x + 1, run_loc_bottom_left.y, run_loc_bottom_left.z))
|
||||
var/obj/machinery/computer/teleporter/computer = allocate(/obj/machinery/computer/teleporter, locate(run_loc_floor_bottom_left.x + 2, run_loc_floor_bottom_left.y, run_loc_floor_bottom_left.z))
|
||||
var/obj/machinery/teleport/station/station = allocate(/obj/machinery/teleport/station, locate(run_loc_floor_bottom_left.x + 1, run_loc_floor_bottom_left.y, run_loc_floor_bottom_left.z))
|
||||
|
||||
TEST_ASSERT_EQUAL(hub.power_station, station, "Hub didn't link to the station")
|
||||
TEST_ASSERT_EQUAL(station.teleporter_console, computer, "Station didn't link to the teleporter console")
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/// Test that `TGUI_CREATE_MESSAGE` is correctly implemented
|
||||
/datum/unit_test/tgui_create_message
|
||||
|
||||
/datum/unit_test/tgui_create_message/Run()
|
||||
var/type = "something/here"
|
||||
var/list/payload = list(
|
||||
"name" = "Terry McTider",
|
||||
"heads_caved" = 100,
|
||||
"accomplishments" = list(
|
||||
"nothing",
|
||||
"literally nothing",
|
||||
list(
|
||||
"something" = "just kidding",
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
var/message = TGUI_CREATE_MESSAGE(type, payload)
|
||||
|
||||
// Ensure consistent output to compare by performing a round-trip.
|
||||
var/output = json_encode(json_decode(url_decode(message)))
|
||||
|
||||
var/expected = json_encode(list(
|
||||
"type" = type,
|
||||
"payload" = payload,
|
||||
))
|
||||
|
||||
TEST_ASSERT_EQUAL(expected, output, "TGUI_CREATE_MESSAGE didn't round trip properly")
|
||||
@@ -7,7 +7,7 @@ Call Fail() to fail the test (You should specify a reason)
|
||||
|
||||
You may use /New() and /Destroy() for setup/teardown respectively
|
||||
|
||||
You can use the run_loc_bottom_left and run_loc_top_right to get turfs for testing
|
||||
You can use the run_loc_floor_bottom_left and run_loc_floor_top_right to get turfs for testing
|
||||
|
||||
*/
|
||||
|
||||
@@ -19,39 +19,46 @@ GLOBAL_VAR(test_log)
|
||||
//Bit of metadata for the future maybe
|
||||
var/list/procs_tested
|
||||
|
||||
/// The bottom left turf of the testing zone
|
||||
var/turf/run_loc_bottom_left
|
||||
|
||||
/// The top right turf of the testing zone
|
||||
var/turf/run_loc_top_right
|
||||
|
||||
/// The type of turf to allocate for the testing zone
|
||||
var/test_turf_type = /turf/open/floor/plasteel
|
||||
/// The bottom left floor turf of the testing zone
|
||||
var/turf/run_loc_floor_bottom_left
|
||||
|
||||
/// The top right floor turf of the testing zone
|
||||
var/turf/run_loc_floor_top_right
|
||||
///The priority of the test, the larger it is the later it fires
|
||||
var/priority = TEST_DEFAULT
|
||||
//internal shit
|
||||
var/focus = FALSE
|
||||
var/succeeded = TRUE
|
||||
var/list/allocated
|
||||
var/list/fail_reasons
|
||||
|
||||
var/static/datum/turf_reservation/turf_reservation
|
||||
var/static/datum/turf_reservation/reservation
|
||||
|
||||
/proc/cmp_unit_test_priority(datum/unit_test/a, datum/unit_test/b)
|
||||
return initial(a.priority) - initial(b.priority)
|
||||
|
||||
/datum/unit_test/New()
|
||||
if (isnull(turf_reservation))
|
||||
turf_reservation = SSmapping.RequestBlockReservation(5, 5)
|
||||
if (isnull(reservation))
|
||||
reservation = SSmapping.RequestBlockReservation(5, 5)
|
||||
|
||||
for (var/turf/reserved_turf in turf_reservation.reserved_turfs)
|
||||
reserved_turf.ChangeTurf(test_turf_type)
|
||||
for (var/turf/reserved_turf in reservation.reserved_turfs)
|
||||
reserved_turf.ChangeTurf(/turf/open/floor/plasteel)
|
||||
|
||||
allocated = new
|
||||
run_loc_bottom_left = locate(turf_reservation.bottom_left_coords[1], turf_reservation.bottom_left_coords[2], turf_reservation.bottom_left_coords[3])
|
||||
run_loc_top_right = locate(turf_reservation.top_right_coords[1], turf_reservation.top_right_coords[2], turf_reservation.top_right_coords[3])
|
||||
run_loc_floor_bottom_left = locate(reservation.bottom_left_coords[1], reservation.bottom_left_coords[2], reservation.bottom_left_coords[3])
|
||||
run_loc_floor_top_right = locate(reservation.top_right_coords[1], reservation.top_right_coords[2], reservation.top_right_coords[3])
|
||||
|
||||
TEST_ASSERT(isfloorturf(run_loc_floor_bottom_left), "run_loc_floor_bottom_left was not a floor ([run_loc_floor_bottom_left])")
|
||||
TEST_ASSERT(isfloorturf(run_loc_floor_top_right), "run_loc_floor_top_right was not a floor ([run_loc_floor_top_right])")
|
||||
|
||||
/datum/unit_test/Destroy()
|
||||
//clear the test area
|
||||
for(var/atom/movable/AM in block(run_loc_bottom_left, run_loc_top_right))
|
||||
qdel(AM)
|
||||
QDEL_LIST(allocated)
|
||||
// clear the test area
|
||||
for (var/turf/turf in block(locate(1, 1, run_loc_floor_bottom_left.z), locate(world.maxx, world.maxy, run_loc_floor_bottom_left.z)))
|
||||
for (var/content in turf.contents)
|
||||
if (istype(content, /obj/effect/landmark))
|
||||
continue
|
||||
qdel(content)
|
||||
return ..()
|
||||
|
||||
/datum/unit_test/proc/Run()
|
||||
@@ -70,44 +77,64 @@ GLOBAL_VAR(test_log)
|
||||
/datum/unit_test/proc/allocate(type, ...)
|
||||
var/list/arguments = args.Copy(2)
|
||||
if (!arguments.len)
|
||||
arguments = list(run_loc_bottom_left)
|
||||
arguments = list(run_loc_floor_bottom_left)
|
||||
else if (arguments[1] == null)
|
||||
arguments[1] = run_loc_bottom_left
|
||||
arguments[1] = run_loc_floor_bottom_left
|
||||
var/instance = new type(arglist(arguments))
|
||||
allocated += instance
|
||||
return instance
|
||||
|
||||
/proc/RunUnitTest(test_path, list/test_results)
|
||||
var/datum/unit_test/test = new test_path
|
||||
|
||||
GLOB.current_test = test
|
||||
var/duration = REALTIMEOFDAY
|
||||
|
||||
test.Run()
|
||||
|
||||
duration = REALTIMEOFDAY - duration
|
||||
GLOB.current_test = null
|
||||
GLOB.failed_any_test |= !test.succeeded
|
||||
|
||||
var/list/log_entry = list("[test.succeeded ? "PASS" : "FAIL"]: [test_path] [duration / 10]s")
|
||||
var/list/fail_reasons = test.fail_reasons
|
||||
|
||||
for(var/J in 1 to LAZYLEN(fail_reasons))
|
||||
log_entry += "\tREASON #[J]: [fail_reasons[J]]"
|
||||
var/message = log_entry.Join("\n")
|
||||
log_test(message)
|
||||
|
||||
test_results[test_path] = list("status" = test.succeeded ? UNIT_TEST_PASSED : UNIT_TEST_FAILED, "message" = message, "name" = test_path)
|
||||
|
||||
qdel(test)
|
||||
|
||||
/proc/RunUnitTests()
|
||||
CHECK_TICK
|
||||
|
||||
var/tests_to_run = subtypesof(/datum/unit_test)
|
||||
var/list/tests_to_run = subtypesof(/datum/unit_test)
|
||||
for (var/_test_to_run in tests_to_run)
|
||||
var/datum/unit_test/test_to_run = _test_to_run
|
||||
if (initial(test_to_run.focus))
|
||||
tests_to_run = list(test_to_run)
|
||||
break
|
||||
|
||||
for(var/I in tests_to_run)
|
||||
var/datum/unit_test/test = new I
|
||||
tests_to_run = sortTim(tests_to_run, /proc/cmp_unit_test_priority)
|
||||
|
||||
GLOB.current_test = test
|
||||
var/duration = REALTIMEOFDAY
|
||||
var/list/test_results = list()
|
||||
|
||||
test.Run()
|
||||
for(var/unit_path in tests_to_run)
|
||||
CHECK_TICK //We check tick first because the unit test we run last may be so expensive that checking tick will lock up this loop forever
|
||||
RunUnitTest(unit_path, test_results)
|
||||
|
||||
duration = REALTIMEOFDAY - duration
|
||||
GLOB.current_test = null
|
||||
GLOB.failed_any_test |= !test.succeeded
|
||||
|
||||
var/list/log_entry = list("[test.succeeded ? "PASS" : "FAIL"]: [I] [duration / 10]s")
|
||||
var/list/fail_reasons = test.fail_reasons
|
||||
|
||||
qdel(test)
|
||||
|
||||
for(var/J in 1 to LAZYLEN(fail_reasons))
|
||||
log_entry += "\tREASON #[J]: [fail_reasons[J]]"
|
||||
log_test(log_entry.Join("\n"))
|
||||
|
||||
CHECK_TICK
|
||||
var/file_name = "data/unit_tests.json"
|
||||
fdel(file_name)
|
||||
file(file_name) << json_encode(test_results)
|
||||
|
||||
SSticker.force_ending = TRUE
|
||||
//We have to call this manually because del_text can preceed us, and SSticker doesn't fire in the post game
|
||||
SSticker.ready_for_reboot = TRUE
|
||||
SSticker.standard_reboot()
|
||||
|
||||
// /datum/map_template/unit_tests
|
||||
// name = "Unit Tests Zone"
|
||||
// mappath = "_maps/templates/unit_tests.dmm"
|
||||
|
||||
Reference in New Issue
Block a user