mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-28 23:58:07 +01:00
Optimizes qdel related things (slight init time savings) (#70729)
* Moves spawners and decals to a different init/delete scheme Rather then fully creating and then immediately deleting these things, we instead do the bare minimum. This is faster, if in theory more fragile. We should be safe since any errors should be caught in compile since this is very close to a "static" action. It does mean these atoms cannot use signals, etc. * Potentially saves init time, mostly cleans up a silly pattern We use sleeps and INVOKE_ASYNC to ensure that handing back turfs doesn't block a space reservation, but this by nature consumes up to the threshold and a bit more of whatever working block we were in. This is silly. Should just be a subsystem, so I made it one, with support for awaiting its finish if you want to * Optimizes garbage/proc/Queue slightly Queue takes about 1.6 seconds to process 26k items right now. The MASSIVE majority of this time is spent on using \ref This is because \ref returns a string, and that string requires being inserted into the global cache of strings we store What I'm doing is caching the result of ANY \ref on the datum it's applied to. This ensures previous uses will never decay from the string tree. This saves about 0.2 seconds of init
This commit is contained in:
@@ -13,3 +13,10 @@
|
||||
|
||||
/// subtypesof(), typesof() without the parent path
|
||||
#define subtypesof(typepath) ( typesof(typepath) - typepath )
|
||||
|
||||
/// Takes a datum as input, returns its ref string, or a cached version of it
|
||||
/// This allows us to cache \ref creation, which ensures it'll only ever happen once per datum, saving string tree time
|
||||
/// It is slightly less optimal then a []'d datum, but the cost is massively outweighed by the potential savings
|
||||
/// It will only work for datums mind, for datum reasons
|
||||
/// : because of the embedded typecheck
|
||||
#define text_ref(datum) (isdatum(datum) ? (datum:cached_ref ||= "\ref[datum]") : ("\ref[datum]"))
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
#define TYPEID_NORMAL_LIST "f"
|
||||
//helper macros
|
||||
#define GET_TYPEID(ref) ( ( (length(ref) <= 10) ? "TYPEID_NULL" : copytext(ref, 4, -7) ) )
|
||||
#define IS_NORMAL_LIST(L) (GET_TYPEID("\ref[L]") == TYPEID_NORMAL_LIST)
|
||||
#define IS_NORMAL_LIST(L) (GET_TYPEID(text_ref(L)) == TYPEID_NORMAL_LIST)
|
||||
|
||||
|
||||
|
||||
@@ -1181,7 +1181,7 @@ GLOBAL_LIST_EMPTY(friendly_animal_types)
|
||||
if(isicon(icon) && isfile(icon))
|
||||
//icons compiled in from 'icons/path/to/dmi_file.dmi' at compile time are weird and arent really /icon objects,
|
||||
///but they pass both isicon() and isfile() checks. theyre the easiest case since stringifying them gives us the path we want
|
||||
var/icon_ref = "\ref[icon]"
|
||||
var/icon_ref = text_ref(icon)
|
||||
var/locate_icon_string = "[locate(icon_ref)]"
|
||||
|
||||
icon_path = locate_icon_string
|
||||
@@ -1192,7 +1192,7 @@ GLOBAL_LIST_EMPTY(friendly_animal_types)
|
||||
// the rsc reference returned by fcopy_rsc() will be stringifiable to "icons/path/to/dmi_file.dmi"
|
||||
var/rsc_ref = fcopy_rsc(icon)
|
||||
|
||||
var/icon_ref = "\ref[rsc_ref]"
|
||||
var/icon_ref = text_ref(rsc_ref)
|
||||
|
||||
var/icon_path_string = "[locate(icon_ref)]"
|
||||
|
||||
@@ -1202,7 +1202,7 @@ GLOBAL_LIST_EMPTY(friendly_animal_types)
|
||||
var/rsc_ref = fcopy_rsc(icon)
|
||||
//if its the text path of an existing dmi file, the rsc reference returned by fcopy_rsc() will be stringifiable to a dmi path
|
||||
|
||||
var/rsc_ref_ref = "\ref[rsc_ref]"
|
||||
var/rsc_ref_ref = text_ref(rsc_ref)
|
||||
var/rsc_ref_string = "[locate(rsc_ref_ref)]"
|
||||
|
||||
icon_path = rsc_ref_string
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
"path" = value
|
||||
)
|
||||
|
||||
var/ref = "\ref[value]"
|
||||
var/ref = text_ref(value)
|
||||
var/existing_ref = seen_references[ref]
|
||||
if(existing_ref)
|
||||
return list(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* \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 && isdatum(thing) && (thing:datum_flags & DF_USE_TAG) && thing:tag ? "[thing:tag]" : "\ref[thing]")
|
||||
* #define REF(thing) (thing && isdatum(thing) && (thing:datum_flags & DF_USE_TAG) && thing:tag ? "[thing:tag]" : text_ref(thing))
|
||||
**/
|
||||
/proc/REF(input)
|
||||
if(isdatum(input))
|
||||
@@ -12,4 +12,4 @@
|
||||
thing.datum_flags &= ~DF_USE_TAG
|
||||
else
|
||||
return "\[[url_encode(thing.tag)]\]"
|
||||
return "\ref[input]"
|
||||
return text_ref(input)
|
||||
|
||||
@@ -207,7 +207,7 @@ SUBSYSTEM_DEF(garbage)
|
||||
var/type = D.type
|
||||
var/datum/qdel_item/I = items[type]
|
||||
|
||||
log_world("## TESTING: GC: -- \ref[D] | [type] was unable to be GC'd --")
|
||||
log_world("## TESTING: GC: -- [text_ref(D)] | [type] was unable to be GC'd --")
|
||||
#ifdef TESTING
|
||||
for(var/c in GLOB.admins) //Using testing() here would fill the logs with ADMIN_VV garbage
|
||||
var/client/admin = c
|
||||
@@ -249,7 +249,7 @@ SUBSYSTEM_DEF(garbage)
|
||||
HardDelete(D)
|
||||
return
|
||||
var/gctime = world.time
|
||||
var/refid = "\ref[D]"
|
||||
var/refid = text_ref(D)
|
||||
|
||||
D.gc_destroyed = gctime
|
||||
var/list/queue = queues[level]
|
||||
@@ -261,7 +261,7 @@ SUBSYSTEM_DEF(garbage)
|
||||
++delslasttick
|
||||
++totaldels
|
||||
var/type = D.type
|
||||
var/refID = "\ref[D]"
|
||||
var/refID = text_ref(D)
|
||||
|
||||
var/tick_usage = TICK_USAGE
|
||||
del(D)
|
||||
@@ -376,7 +376,7 @@ SUBSYSTEM_DEF(garbage)
|
||||
D.find_references() //This breaks ci. Consider it insurance against somehow pring reftracking on accident
|
||||
if (QDEL_HINT_IFFAIL_FINDREFERENCE) //qdel will, if REFERENCE_TRACKING is enabled and the object fails to collect, display all references to this object.
|
||||
SSgarbage.Queue(D)
|
||||
SSgarbage.reference_find_on_fail["\ref[D]"] = TRUE
|
||||
SSgarbage.reference_find_on_fail[text_ref(D)] = TRUE
|
||||
#endif
|
||||
else
|
||||
#ifdef TESTING
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
SUBSYSTEM_DEF(mapping)
|
||||
name = "Mapping"
|
||||
init_order = INIT_ORDER_MAPPING
|
||||
flags = SS_NO_FIRE
|
||||
runlevels = ALL
|
||||
|
||||
var/list/nuke_tiles = list()
|
||||
var/list/nuke_threats = list()
|
||||
@@ -54,6 +54,8 @@ SUBSYSTEM_DEF(mapping)
|
||||
var/list/turf/unused_turfs = list() //Not actually unused turfs they're unused but reserved for use for whatever requests them. "[zlevel_of_turf]" = list(turfs)
|
||||
var/list/datum/turf_reservations //list of turf reservations
|
||||
var/list/used_turfs = list() //list of turf = datum/turf_reservation
|
||||
/// List of lists of turfs to reserve
|
||||
var/list/lists_to_reserve = list()
|
||||
|
||||
var/list/reservation_ready = list()
|
||||
var/clearing_reserved_turfs = FALSE
|
||||
@@ -149,6 +151,33 @@ SUBSYSTEM_DEF(mapping)
|
||||
|
||||
return SS_INIT_SUCCESS
|
||||
|
||||
/datum/controller/subsystem/mapping/fire(resumed)
|
||||
// Cache for sonic speed
|
||||
var/list/unused_turfs = src.unused_turfs
|
||||
var/list/world_contents = GLOB.areas_by_type[world.area].contents
|
||||
var/list/lists_to_reserve = src.lists_to_reserve
|
||||
var/index = 0
|
||||
while(length(lists_to_reserve))
|
||||
var/list/packet = lists_to_reserve[index + 1]
|
||||
var/packetlen = length(packet)
|
||||
while(packetlen)
|
||||
if(MC_TICK_CHECK)
|
||||
lists_to_reserve.Cut(1, index)
|
||||
return
|
||||
var/turf/T = packet[packetlen]
|
||||
T.empty(RESERVED_TURF_TYPE, RESERVED_TURF_TYPE, null, TRUE)
|
||||
LAZYINITLIST(unused_turfs["[T.z]"])
|
||||
unused_turfs["[T.z]"] |= T
|
||||
T.flags_1 |= UNUSED_RESERVATION_TURF
|
||||
world_contents += T
|
||||
packet.len--
|
||||
packetlen = length(packet)
|
||||
|
||||
index++
|
||||
// If we're here, we're done with that lad
|
||||
lists_to_reserve.len--
|
||||
lists_to_reserve.Cut(1, index)
|
||||
|
||||
/datum/controller/subsystem/mapping/proc/calculate_default_z_level_gravities()
|
||||
for(var/z_level in 1 to length(z_list))
|
||||
calculate_z_level_gravity(z_level)
|
||||
@@ -646,15 +675,12 @@ GLOBAL_LIST_EMPTY(the_station_areas)
|
||||
reservation_ready["[z]"] = TRUE
|
||||
clearing_reserved_turfs = FALSE
|
||||
|
||||
/datum/controller/subsystem/mapping/proc/reserve_turfs(list/turfs)
|
||||
for(var/i in turfs)
|
||||
var/turf/T = i
|
||||
T.empty(RESERVED_TURF_TYPE, RESERVED_TURF_TYPE, null, TRUE)
|
||||
LAZYINITLIST(unused_turfs["[T.z]"])
|
||||
unused_turfs["[T.z]"] |= T
|
||||
T.flags_1 |= UNUSED_RESERVATION_TURF
|
||||
GLOB.areas_by_type[world.area].contents += T
|
||||
CHECK_TICK
|
||||
/// Schedules a group of turfs to be handed back to the reservation system's control
|
||||
/// If await is true, will sleep until the turfs are finished work
|
||||
/datum/controller/subsystem/mapping/proc/reserve_turfs(list/turfs, await = FALSE)
|
||||
lists_to_reserve += list(turfs)
|
||||
if(await)
|
||||
UNTIL(!length(turfs))
|
||||
|
||||
//DO NOT CALL THIS PROC DIRECTLY, CALL wipe_reservations().
|
||||
/datum/controller/subsystem/mapping/proc/do_wipe_turf_reservations()
|
||||
@@ -672,7 +698,7 @@ GLOBAL_LIST_EMPTY(the_station_areas)
|
||||
clearing |= used_turfs //used turfs is an associative list, BUT, reserve_turfs() can still handle it. If the code above works properly, this won't even be needed as the turfs would be freed already.
|
||||
unused_turfs.Cut()
|
||||
used_turfs.Cut()
|
||||
reserve_turfs(clearing)
|
||||
reserve_turfs(clearing, await = TRUE)
|
||||
|
||||
///Initialize all biomes, assoc as type || instance
|
||||
/datum/controller/subsystem/mapping/proc/initialize_biomes()
|
||||
|
||||
@@ -237,16 +237,16 @@ SUBSYSTEM_DEF(statpanels)
|
||||
list("CPU:", world.cpu),
|
||||
list("Instances:", "[num2text(world.contents.len, 10)]"),
|
||||
list("World Time:", "[world.time]"),
|
||||
list("Globals:", GLOB.stat_entry(), "\ref[GLOB]"),
|
||||
list("[config]:", config.stat_entry(), "\ref[config]"),
|
||||
list("Globals:", GLOB.stat_entry(), text_ref(GLOB)),
|
||||
list("[config]:", config.stat_entry(), text_ref(config)),
|
||||
list("Byond:", "(FPS:[world.fps]) (TickCount:[world.time/world.tick_lag]) (TickDrift:[round(Master.tickdrift,1)]([round((Master.tickdrift/(world.time/world.tick_lag))*100,0.1)]%)) (Internal Tick Usage: [round(MAPTICK_LAST_INTERNAL_TICK_USAGE,0.1)]%)"),
|
||||
list("Master Controller:", Master.stat_entry(), "\ref[Master]"),
|
||||
list("Failsafe Controller:", Failsafe.stat_entry(), "\ref[Failsafe]"),
|
||||
list("Master Controller:", Master.stat_entry(), text_ref(Master)),
|
||||
list("Failsafe Controller:", Failsafe.stat_entry(), text_ref(Failsafe)),
|
||||
list("","")
|
||||
)
|
||||
for(var/datum/controller/subsystem/sub_system as anything in Master.subsystems)
|
||||
mc_data[++mc_data.len] = list("\[[sub_system.state_letter()]][sub_system.name]", sub_system.stat_entry(), "\ref[sub_system]")
|
||||
mc_data[++mc_data.len] = list("Camera Net", "Cameras: [GLOB.cameranet.cameras.len] | Chunks: [GLOB.cameranet.chunks.len]", "\ref[GLOB.cameranet]")
|
||||
mc_data[++mc_data.len] = list("\[[sub_system.state_letter()]][sub_system.name]", sub_system.stat_entry(), text_ref(sub_system))
|
||||
mc_data[++mc_data.len] = list("Camera Net", "Cameras: [GLOB.cameranet.cameras.len] | Chunks: [GLOB.cameranet.chunks.len]", text_ref(GLOB.cameranet))
|
||||
|
||||
///immediately update the active statpanel tab of the target client
|
||||
/datum/controller/subsystem/statpanels/proc/immediate_send_stat_data(client/target)
|
||||
|
||||
@@ -505,8 +505,8 @@ SUBSYSTEM_DEF(timer)
|
||||
/datum/timedevent/proc/bucketJoin()
|
||||
// Generate debug-friendly name for timer
|
||||
var/static/list/bitfield_flags = list("TIMER_UNIQUE", "TIMER_OVERRIDE", "TIMER_CLIENT_TIME", "TIMER_STOPPABLE", "TIMER_NO_HASH_WAIT", "TIMER_LOOP")
|
||||
name = "Timer: [id] (\ref[src]), TTR: [timeToRun], wait:[wait] Flags: [jointext(bitfield_to_list(flags, bitfield_flags), ", ")], \
|
||||
callBack: \ref[callBack], callBack.object: [callBack.object]\ref[callBack.object]([getcallingtype()]), \
|
||||
name = "Timer: [id] ([text_ref(src)]), TTR: [timeToRun], wait:[wait] Flags: [jointext(bitfield_to_list(flags, bitfield_flags), ", ")], \
|
||||
callBack: [text_ref(callBack)], callBack.object: [callBack.object][text_ref(callBack.object)]([getcallingtype()]), \
|
||||
callBack.delegate:[callBack.delegate]([callBack.arguments ? callBack.arguments.Join(", ") : ""]), source: [source]"
|
||||
|
||||
if (bucket_joined)
|
||||
|
||||
@@ -42,7 +42,7 @@ SUBSYSTEM_DEF(vis_overlays)
|
||||
else
|
||||
overlay = _create_new_vis_overlay(icon, iconstate, layer, plane, dir, alpha, add_appearance_flags)
|
||||
overlay.cache_expiration = -1
|
||||
var/cache_id = "\ref[overlay]@{[world.time]}"
|
||||
var/cache_id = "[text_ref(overlay)]@{[world.time]}"
|
||||
vis_overlay_cache[cache_id] = overlay
|
||||
. = overlay
|
||||
thing.vis_contents += overlay
|
||||
|
||||
@@ -40,6 +40,11 @@
|
||||
/// Datum level flags
|
||||
var/datum_flags = NONE
|
||||
|
||||
/// A cached version of our \ref
|
||||
/// The brunt of \ref costs are in creating entries in the string tree (a tree of immutable strings)
|
||||
/// This avoids doing that more then once per datum by ensuring ref strings always have a reference to them after they're first pulled
|
||||
var/cached_ref
|
||||
|
||||
/// A weak reference to another datum
|
||||
var/datum/weakref/weak_reference
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
return ATAN2((b.y - a.y), (b.x - a.x))
|
||||
|
||||
/// For positions with map x/y/z and pixel x/y so you don't have to return lists. Could use addition/subtraction in the future I guess.
|
||||
/datum/position
|
||||
/datum/position
|
||||
var/x = 0
|
||||
var/y = 0
|
||||
var/z = 0
|
||||
@@ -68,7 +68,7 @@
|
||||
return new /datum/point(src)
|
||||
|
||||
/// A precise point on the map in absolute pixel locations based on world.icon_size. Pixels are FROM THE EDGE OF THE MAP!
|
||||
/datum/point
|
||||
/datum/point
|
||||
var/x = 0
|
||||
var/y = 0
|
||||
var/z = 0
|
||||
@@ -83,7 +83,7 @@
|
||||
return p
|
||||
|
||||
/// First argument can also be a /datum/position or /atom.
|
||||
/datum/point/New(_x, _y, _z, _pixel_x = 0, _pixel_y = 0)
|
||||
/datum/point/New(_x, _y, _z, _pixel_x = 0, _pixel_y = 0)
|
||||
if(istype(_x, /datum/position))
|
||||
var/datum/position/P = _x
|
||||
_x = P.x
|
||||
@@ -110,7 +110,7 @@
|
||||
|
||||
/datum/point/proc/debug_out()
|
||||
var/turf/T = return_turf()
|
||||
return "\ref[src] aX [x] aY [y] aZ [z] pX [return_px()] pY [return_py()] mX [T.x] mY [T.y] mZ [T.z]"
|
||||
return "[text_ref(src)] aX [x] aY [y] aZ [z] pX [return_px()] pY [return_py()] mX [T.x] mY [T.y] mZ [T.z]"
|
||||
|
||||
/datum/point/proc/move_atom_to_src(atom/movable/AM)
|
||||
AM.forceMove(return_turf())
|
||||
@@ -134,11 +134,11 @@
|
||||
|
||||
/datum/point/vector
|
||||
/// Pixels per iteration
|
||||
var/speed = 32
|
||||
var/speed = 32
|
||||
var/iteration = 0
|
||||
var/angle = 0
|
||||
/// Calculated x movement amounts to prevent having to do trig every step.
|
||||
var/mpx = 0
|
||||
var/mpx = 0
|
||||
/// Calculated y movement amounts to prevent having to do trig every step.
|
||||
var/mpy = 0
|
||||
var/starting_x = 0 //just like before, pixels from EDGE of map! This is set in initialize_location().
|
||||
@@ -158,7 +158,7 @@
|
||||
starting_z = z
|
||||
|
||||
/// Same effect as initiliaze_location, but without setting the starting_x/y/z
|
||||
/datum/point/vector/proc/set_location(tile_x, tile_y, tile_z, p_x = 0, p_y = 0)
|
||||
/datum/point/vector/proc/set_location(tile_x, tile_y, tile_z, p_x = 0, p_y = 0)
|
||||
if(!isnull(tile_x))
|
||||
x = ((tile_x - 1) * world.icon_size) + world.icon_size * 0.5 + p_x + 1
|
||||
if(!isnull(tile_y))
|
||||
|
||||
@@ -191,23 +191,23 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
|
||||
/datum/game_mode/dynamic/admin_panel()
|
||||
var/list/dat = list("<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><title>Game Mode Panel</title></head><body><h1><B>Game Mode Panel</B></h1>")
|
||||
dat += "Dynamic Mode <a href='?_src_=vars;[HrefToken()];Vars=[REF(src)]'>\[VV\]</a> <a href='?src=\ref[src];[HrefToken()]'>\[Refresh\]</a><BR>"
|
||||
dat += "Dynamic Mode <a href='?_src_=vars;[HrefToken()];Vars=[REF(src)]'>\[VV\]</a> <a href='?src=[text_ref(src)];[HrefToken()]'>\[Refresh\]</a><BR>"
|
||||
dat += "Threat Level: <b>[threat_level]</b><br/>"
|
||||
dat += "Budgets (Roundstart/Midrounds): <b>[initial_round_start_budget]/[threat_level - initial_round_start_budget]</b><br/>"
|
||||
|
||||
dat += "Midround budget to spend: <b>[mid_round_budget]</b> <a href='?src=\ref[src];[HrefToken()];adjustthreat=1'>\[Adjust\]</A> <a href='?src=\ref[src];[HrefToken()];threatlog=1'>\[View Log\]</a><br/>"
|
||||
dat += "Midround budget to spend: <b>[mid_round_budget]</b> <a href='?src=[text_ref(src)];[HrefToken()];adjustthreat=1'>\[Adjust\]</A> <a href='?src=[text_ref(src)];[HrefToken()];threatlog=1'>\[View Log\]</a><br/>"
|
||||
dat += "<br/>"
|
||||
dat += "Parameters: centre = [threat_curve_centre] ; width = [threat_curve_width].<br/>"
|
||||
dat += "Split parameters: centre = [roundstart_split_curve_centre] ; width = [roundstart_split_curve_width].<br/>"
|
||||
dat += "<i>On average, <b>[peaceful_percentage]</b>% of the rounds are more peaceful.</i><br/>"
|
||||
dat += "Forced extended: <a href='?src=\ref[src];[HrefToken()];forced_extended=1'><b>[GLOB.dynamic_forced_extended ? "On" : "Off"]</b></a><br/>"
|
||||
dat += "No stacking (only one round-ender): <a href='?src=\ref[src];[HrefToken()];no_stacking=1'><b>[GLOB.dynamic_no_stacking ? "On" : "Off"]</b></a><br/>"
|
||||
dat += "Stacking limit: [GLOB.dynamic_stacking_limit] <a href='?src=\ref[src];[HrefToken()];stacking_limit=1'>\[Adjust\]</A>"
|
||||
dat += "Forced extended: <a href='?src=[text_ref(src)];[HrefToken()];forced_extended=1'><b>[GLOB.dynamic_forced_extended ? "On" : "Off"]</b></a><br/>"
|
||||
dat += "No stacking (only one round-ender): <a href='?src=[text_ref(src)];[HrefToken()];no_stacking=1'><b>[GLOB.dynamic_no_stacking ? "On" : "Off"]</b></a><br/>"
|
||||
dat += "Stacking limit: [GLOB.dynamic_stacking_limit] <a href='?src=[text_ref(src)];[HrefToken()];stacking_limit=1'>\[Adjust\]</A>"
|
||||
dat += "<br/>"
|
||||
dat += "<A href='?src=\ref[src];[HrefToken()];force_latejoin_rule=1'>\[Force Next Latejoin Ruleset\]</A><br>"
|
||||
dat += "<A href='?src=[text_ref(src)];[HrefToken()];force_latejoin_rule=1'>\[Force Next Latejoin Ruleset\]</A><br>"
|
||||
if (forced_latejoin_rule)
|
||||
dat += {"<A href='?src=\ref[src];[HrefToken()];clear_forced_latejoin=1'>-> [forced_latejoin_rule.name] <-</A><br>"}
|
||||
dat += "<A href='?src=\ref[src];[HrefToken()];force_midround_rule=1'>\[Execute Midround Ruleset\]</A><br>"
|
||||
dat += {"<A href='?src=[text_ref(src)];[HrefToken()];clear_forced_latejoin=1'>-> [forced_latejoin_rule.name] <-</A><br>"}
|
||||
dat += "<A href='?src=[text_ref(src)];[HrefToken()];force_midround_rule=1'>\[Execute Midround Ruleset\]</A><br>"
|
||||
dat += "<br />"
|
||||
dat += "Executed rulesets: "
|
||||
if (executed_rules.len > 0)
|
||||
@@ -217,13 +217,13 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
|
||||
else
|
||||
dat += "none.<br>"
|
||||
dat += "<br>Injection Timers: (<b>[get_heavy_midround_injection_chance(dry_run = TRUE)]%</b> heavy midround chance)<BR>"
|
||||
dat += "Latejoin: [DisplayTimeText(latejoin_injection_cooldown-world.time)] <a href='?src=\ref[src];[HrefToken()];injectlate=1'>\[Now!\]</a><BR>"
|
||||
dat += "Latejoin: [DisplayTimeText(latejoin_injection_cooldown-world.time)] <a href='?src=[text_ref(src)];[HrefToken()];injectlate=1'>\[Now!\]</a><BR>"
|
||||
|
||||
var/next_injection = next_midround_injection()
|
||||
if (next_injection == INFINITY)
|
||||
dat += "All midrounds have been exhausted."
|
||||
else
|
||||
dat += "Midround: [DisplayTimeText(next_injection - world.time)] <a href='?src=\ref[src];[HrefToken()];injectmid=1'>\[Now!\]</a><BR>"
|
||||
dat += "Midround: [DisplayTimeText(next_injection - world.time)] <a href='?src=[text_ref(src)];[HrefToken()];injectmid=1'>\[Now!\]</a><BR>"
|
||||
|
||||
usr << browse(dat.Join(), "window=gamemode_panel;size=500x500")
|
||||
|
||||
|
||||
@@ -37,20 +37,29 @@
|
||||
layer = TURF_DECAL_LAYER
|
||||
anchored = TRUE
|
||||
|
||||
// This is with the intent of optimizing mapload
|
||||
// See spawners for more details since we use the same pattern
|
||||
// Basically rather then creating and deleting ourselves, why not just do the bare minimum?
|
||||
/obj/effect/turf_decal/Initialize(mapload)
|
||||
. = ..()
|
||||
SHOULD_CALL_PARENT(FALSE)
|
||||
if(flags_1 & INITIALIZED_1)
|
||||
stack_trace("Warning: [src]([type]) initialized multiple times!")
|
||||
flags_1 |= INITIALIZED_1
|
||||
|
||||
var/turf/T = loc
|
||||
if(!istype(T)) //you know this will happen somehow
|
||||
CRASH("Turf decal initialized in an object/nullspace")
|
||||
T.AddElement(/datum/element/decal, icon, icon_state, dir, null, null, alpha, color, null, FALSE, null)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/effect/turf_decal/Destroy(force)
|
||||
SHOULD_CALL_PARENT(FALSE)
|
||||
#ifdef UNIT_TESTS
|
||||
// If we don't do this, turf decals will end up stacking up on a tile, and break the overlay limit
|
||||
// I hate it too bestie
|
||||
/obj/effect/turf_decal/Destroy()
|
||||
if(GLOB.running_create_and_destroy)
|
||||
var/turf/T = loc
|
||||
T.RemoveElement(/datum/element/decal, icon, icon_state, dir, null, null, alpha, color, null, FALSE, null)
|
||||
return ..()
|
||||
#endif
|
||||
moveToNullspace()
|
||||
return QDEL_HINT_QUEUE
|
||||
|
||||
@@ -21,6 +21,23 @@
|
||||
/obj/effect/spawner
|
||||
name = "object spawner"
|
||||
|
||||
// Brief explanation:
|
||||
// Rather then setting up and then deleting spawners, we block all atomlike setup
|
||||
// and do the absolute bare minimum
|
||||
// This is with the intent of optimizing mapload
|
||||
/obj/effect/spawner/Initialize(mapload)
|
||||
SHOULD_CALL_PARENT(FALSE)
|
||||
if(flags_1 & INITIALIZED_1)
|
||||
stack_trace("Warning: [src]([type]) initialized multiple times!")
|
||||
flags_1 |= INITIALIZED_1
|
||||
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/effect/spawner/Destroy(force)
|
||||
SHOULD_CALL_PARENT(FALSE)
|
||||
moveToNullspace()
|
||||
return QDEL_HINT_QUEUE
|
||||
|
||||
/obj/effect/list_container
|
||||
name = "list container"
|
||||
|
||||
|
||||
@@ -6,16 +6,16 @@
|
||||
name = "bomb"
|
||||
icon = 'icons/hud/screen_gen.dmi'
|
||||
icon_state = "x"
|
||||
/* Gasmixes for tank_one and tank_two of the ttv respectively.
|
||||
/* Gasmixes for tank_one and tank_two of the ttv respectively.
|
||||
* Populated on /obj/effect/spawner/newbomb/Initialize, depopulated right after by the children procs.
|
||||
*/
|
||||
var/datum/gas_mixture/first_gasmix
|
||||
var/datum/gas_mixture/second_gasmix
|
||||
|
||||
/**
|
||||
/**
|
||||
* The part of code that actually spawns the bomb. Always call the parent's initialize first for subtypes of these.
|
||||
*
|
||||
* Arguments:
|
||||
* Arguments:
|
||||
* * assembly - An assembly typepath to add to the ttv.
|
||||
*/
|
||||
/obj/effect/spawner/newbomb/Initialize(mapload, assembly = null)
|
||||
@@ -33,7 +33,6 @@
|
||||
newassembly.on_attach()
|
||||
newassembly.holder = ttv
|
||||
ttv.update_appearance()
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/effect/spawner/newbomb/proc/calculate_pressure(datum/gas_mixture/gasmix, pressure)
|
||||
return pressure * gasmix.volume/(R_IDEAL_GAS_EQUATION*gasmix.temperature)
|
||||
@@ -85,7 +84,7 @@
|
||||
first_gasmix.assert_gas(/datum/gas/hypernoblium)
|
||||
first_gasmix.assert_gas(/datum/gas/tritium)
|
||||
second_gasmix.assert_gas(/datum/gas/oxygen)
|
||||
|
||||
|
||||
first_gasmix.gases[/datum/gas/hypernoblium][MOLES] = REACTION_OPPRESSION_THRESHOLD - 0.01
|
||||
first_gasmix.gases[/datum/gas/tritium][MOLES] = 0.5 * calculate_pressure(first_gasmix, TANK_LEAK_PRESSURE - 1)
|
||||
second_gasmix.gases[/datum/gas/oxygen][MOLES] = calculate_pressure(second_gasmix, TANK_LEAK_PRESSURE-1)
|
||||
|
||||
@@ -7,11 +7,10 @@
|
||||
var/list/items
|
||||
|
||||
/obj/effect/spawner/costume/Initialize(mapload)
|
||||
..()
|
||||
. = ..()
|
||||
if(items?.len)
|
||||
for(var/path in items)
|
||||
new path(loc)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/effect/spawner/costume/chicken
|
||||
name = "chicken costume spawner"
|
||||
|
||||
@@ -238,8 +238,7 @@
|
||||
|
||||
/obj/effect/spawner/random/entertainment/toy/Initialize(mapload)
|
||||
loot += GLOB.arcade_prize_pool
|
||||
. = ..()
|
||||
return INITIALIZE_HINT_QDEL
|
||||
return ..()
|
||||
|
||||
/obj/effect/spawner/random/entertainment/plushie
|
||||
name = "plushie spawner"
|
||||
|
||||
@@ -10,8 +10,7 @@
|
||||
|
||||
/obj/effect/spawner/random/maintenance/Initialize(mapload)
|
||||
loot = GLOB.maintenance_loot
|
||||
|
||||
. = ..()
|
||||
return ..()
|
||||
|
||||
/obj/effect/spawner/random/maintenance/proc/hide()
|
||||
invisibility = INVISIBILITY_OBSERVER
|
||||
|
||||
@@ -13,8 +13,6 @@
|
||||
var/loot_type_path
|
||||
/// The subtypes (this excludes the provided path) to combine with the loot list
|
||||
var/loot_subtype_path
|
||||
/// Whether the spawner should immediately spawn loot and cleanup on Initialize()
|
||||
var/spawn_on_init = TRUE
|
||||
/// How many items will be spawned
|
||||
var/spawn_loot_count = 1
|
||||
/// If the same item can be spawned twice
|
||||
@@ -32,14 +30,7 @@
|
||||
|
||||
/obj/effect/spawner/random/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
if(should_spawn_on_init())
|
||||
spawn_loot()
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/// Helper proc that returns TRUE if the spawner should spawn loot in Initialise() and FALSE otherwise. Override this to change spawning behaviour.
|
||||
/obj/effect/spawner/random/proc/should_spawn_on_init()
|
||||
return spawn_on_init
|
||||
spawn_loot()
|
||||
|
||||
///If the spawner has any loot defined, randomly picks some and spawns it. Does not cleanup the spawner.
|
||||
/obj/effect/spawner/random/proc/spawn_loot(lootcount_override)
|
||||
|
||||
@@ -10,13 +10,9 @@ again.
|
||||
|
||||
/obj/effect/spawner/structure/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
for(var/spawn_type in spawn_list)
|
||||
new spawn_type(loc)
|
||||
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
|
||||
//normal windows
|
||||
|
||||
/obj/effect/spawner/structure/window
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
var/announcement_time = 1200
|
||||
|
||||
/obj/effect/spawner/xeno_egg_delivery/Initialize(mapload)
|
||||
..()
|
||||
. = ..()
|
||||
var/turf/T = get_turf(src)
|
||||
|
||||
new /obj/structure/alien/egg(T)
|
||||
@@ -16,4 +16,3 @@
|
||||
log_game("An alien egg has been delivered to [AREACOORD(T)]")
|
||||
var/message = "Attention [station_name()], we have entrusted you with a research specimen in [get_area_name(T, TRUE)]. Remember to follow all safety precautions when dealing with the specimen."
|
||||
SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, /proc/_addtimer, CALLBACK(GLOBAL_PROC, /proc/print_command_report, message), announcement_time))
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
@@ -167,17 +167,16 @@
|
||||
color = "#00FF00"
|
||||
|
||||
/obj/effect/spawner/round_default_module/Initialize(mapload)
|
||||
..()
|
||||
. = ..()
|
||||
var/datum/ai_laws/default_laws = get_round_default_lawset()
|
||||
//try to spawn a law board, since they may have special functionality (asimov setting subjects)
|
||||
for(var/obj/item/ai_module/core/full/potential_lawboard as anything in subtypesof(/obj/item/ai_module/core/full))
|
||||
if(initial(potential_lawboard.law_id) != initial(default_laws.id))
|
||||
continue
|
||||
potential_lawboard = new potential_lawboard(loc)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
return
|
||||
//spawn the fallback instead
|
||||
new /obj/item/ai_module/core/round_default_fallback(loc)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
///When the default lawset spawner cannot find a module object to spawn, it will spawn this, and this sets itself to the round default.
|
||||
///This is so /datum/lawsets can be picked even if they have no module for themselves.
|
||||
|
||||
@@ -232,7 +232,7 @@
|
||||
"res_amount" = R.res_amount,
|
||||
"max_res_amount" = R.max_res_amount,
|
||||
"req_amount" = R.req_amount,
|
||||
"ref" = "\ref[R]",
|
||||
"ref" = text_ref(R),
|
||||
)
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart=1'>(Force Roundstart Rulesets)</A><br>"
|
||||
if (GLOB.dynamic_forced_roundstart_ruleset.len > 0)
|
||||
for(var/datum/dynamic_ruleset/roundstart/rule in GLOB.dynamic_forced_roundstart_ruleset)
|
||||
dat += {"<A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_remove=\ref[rule]'>-> [rule.name] <-</A><br>"}
|
||||
dat += {"<A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_remove=[text_ref(rule)]'>-> [rule.name] <-</A><br>"}
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_roundstart_clear=1'>(Clear Rulesets)</A><br>"
|
||||
dat += "<A href='?src=[REF(src)];[HrefToken()];f_dynamic_options=1'>(Dynamic mode options)</A><br>"
|
||||
dat += "<hr/>"
|
||||
|
||||
@@ -58,16 +58,16 @@
|
||||
|
||||
/obj/effect/sound_emitter/proc/edit_emitter(mob/user)
|
||||
var/dat = ""
|
||||
dat += "<b>Label:</b> <a href='?src=\ref[src];edit_label=1'>[maptext ? maptext : "No label set!"]</a><br>"
|
||||
dat += "<b>Label:</b> <a href='?src=[text_ref(src)];edit_label=1'>[maptext ? maptext : "No label set!"]</a><br>"
|
||||
dat += "<br>"
|
||||
dat += "<b>Sound File:</b> <a href='?src=\ref[src];edit_sound_file=1'>[sound_file ? sound_file : "No file chosen!"]</a><br>"
|
||||
dat += "<b>Volume:</b> <a href='?src=\ref[src];edit_volume=1'>[sound_volume]%</a><br>"
|
||||
dat += "<b>Sound File:</b> <a href='?src=[text_ref(src)];edit_sound_file=1'>[sound_file ? sound_file : "No file chosen!"]</a><br>"
|
||||
dat += "<b>Volume:</b> <a href='?src=[text_ref(src)];edit_volume=1'>[sound_volume]%</a><br>"
|
||||
dat += "<br>"
|
||||
dat += "<b>Mode:</b> <a href='?src=\ref[src];edit_mode=1'>[motus_operandi]</a><br>"
|
||||
dat += "<b>Mode:</b> <a href='?src=[text_ref(src)];edit_mode=1'>[motus_operandi]</a><br>"
|
||||
if(motus_operandi != SOUND_EMITTER_LOCAL)
|
||||
dat += "<b>Range:</b> <a href='?src=\ref[src];edit_range=1'>[emitter_range]</a>[emitter_range == SOUND_EMITTER_RADIUS ? "<a href='?src=\ref[src];edit_radius=1'>[play_radius]-tile radius</a>" : ""]<br>"
|
||||
dat += "<b>Range:</b> <a href='?src=[text_ref(src)];edit_range=1'>[emitter_range]</a>[emitter_range == SOUND_EMITTER_RADIUS ? "<a href='?src=[text_ref(src)];edit_radius=1'>[play_radius]-tile radius</a>" : ""]<br>"
|
||||
dat += "<br>"
|
||||
dat += "<a href='?src=\ref[src];play=1'>Play Sound</a> (interrupts other sound emitter sounds)"
|
||||
dat += "<a href='?src=[text_ref(src)];play=1'>Play Sound</a> (interrupts other sound emitter sounds)"
|
||||
var/datum/browser/popup = new(user, "emitter", "", 500, 600)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
. = ..()
|
||||
if(state)
|
||||
current_state = state
|
||||
LAZYADDASSOCLIST(SSlua.editors, "\ref[current_state]", src)
|
||||
LAZYADDASSOCLIST(SSlua.editors, text_ref(current_state), src)
|
||||
|
||||
/datum/lua_editor/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
@@ -32,7 +32,7 @@
|
||||
/datum/lua_editor/Destroy(force, ...)
|
||||
. = ..()
|
||||
if(current_state)
|
||||
LAZYREMOVEASSOC(SSlua.editors, "\ref[current_state]", src)
|
||||
LAZYREMOVEASSOC(SSlua.editors, text_ref(current_state), src)
|
||||
|
||||
/datum/lua_editor/ui_state(mob/user)
|
||||
return GLOB.debug_state
|
||||
@@ -107,16 +107,16 @@
|
||||
return TRUE
|
||||
var/datum/lua_state/new_state = new(state_name)
|
||||
SSlua.states += new_state
|
||||
LAZYREMOVEASSOC(SSlua.editors, "\ref[current_state]", src)
|
||||
LAZYREMOVEASSOC(SSlua.editors, text_ref(current_state), src)
|
||||
current_state = new_state
|
||||
LAZYADDASSOCLIST(SSlua.editors, "\ref[current_state]", src)
|
||||
LAZYADDASSOCLIST(SSlua.editors, text_ref(current_state), src)
|
||||
page = 0
|
||||
return TRUE
|
||||
if("switchState")
|
||||
var/state_index = params["index"]
|
||||
LAZYREMOVEASSOC(SSlua.editors, "\ref[current_state]", src)
|
||||
LAZYREMOVEASSOC(SSlua.editors, text_ref(current_state), src)
|
||||
current_state = SSlua.states[state_index]
|
||||
LAZYADDASSOCLIST(SSlua.editors, "\ref[current_state]", src)
|
||||
LAZYADDASSOCLIST(SSlua.editors, text_ref(current_state), src)
|
||||
page = 0
|
||||
return TRUE
|
||||
if("runCode")
|
||||
|
||||
@@ -95,7 +95,7 @@ GLOBAL_PROTECT(lua_usr)
|
||||
var/datum/weakref/weak_ref = path_element
|
||||
var/resolved = weak_ref.hard_resolve()
|
||||
if(!resolved)
|
||||
return list("status" = "errored", "param" = "Weakref in function path ([weak_ref] \ref[weak_ref]) resolved to null.", "name" = jointext(function, "."))
|
||||
return list("status" = "errored", "param" = "Weakref in function path ([weak_ref] [text_ref(weak_ref)]) resolved to null.", "name" = jointext(function, "."))
|
||||
new_function_path += resolved
|
||||
else
|
||||
new_function_path += path_element
|
||||
@@ -163,7 +163,7 @@ GLOBAL_PROTECT(lua_usr)
|
||||
__lua_kill_task(internal_id, task_info)
|
||||
|
||||
/datum/lua_state/proc/update_editors()
|
||||
var/list/editor_list = LAZYACCESS(SSlua.editors, "\ref[src]")
|
||||
var/list/editor_list = LAZYACCESS(SSlua.editors, text_ref(src))
|
||||
if(editor_list)
|
||||
for(var/datum/lua_editor/editor as anything in editor_list)
|
||||
SStgui.update_uis(editor)
|
||||
|
||||
@@ -104,11 +104,11 @@
|
||||
found_refs[varname] = TRUE
|
||||
continue //End early, don't want these logging
|
||||
#endif
|
||||
log_reftracker("Found [type] \ref[src] in [datum_container.type]'s \ref[datum_container] [varname] var. [container_name]")
|
||||
log_reftracker("Found [type] [text_ref(src)] in [datum_container.type]'s [text_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)
|
||||
DoSearchVar(variable, "[container_name] [text_ref(datum_container)] -> [varname] (list)", recursive_limit - 1, search_time)
|
||||
|
||||
else if(islist(potential_container))
|
||||
var/normal = IS_NORMAL_LIST(potential_container)
|
||||
@@ -124,7 +124,7 @@
|
||||
found_refs[potential_cache] = TRUE
|
||||
continue //End early, don't want these logging
|
||||
#endif
|
||||
log_reftracker("Found [type] \ref[src] in list [container_name].")
|
||||
log_reftracker("Found [type] [text_ref(src)] in list [container_name].")
|
||||
continue
|
||||
|
||||
var/assoc_val = null
|
||||
@@ -137,7 +137,7 @@
|
||||
found_refs[potential_cache] = TRUE
|
||||
continue //End early, don't want these logging
|
||||
#endif
|
||||
log_reftracker("Found [type] \ref[src] in list [container_name]\[[element_in_list]\]")
|
||||
log_reftracker("Found [type] [text_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
|
||||
@@ -151,7 +151,7 @@
|
||||
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
|
||||
SSgarbage.reference_find_on_fail[text_ref(src)] = TRUE
|
||||
qdel(src, force)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
var/icon_states_string
|
||||
for (var/an_icon_state in icon_states_list)
|
||||
if (!icon_states_string)
|
||||
icon_states_string = "[json_encode(an_icon_state)](\ref[an_icon_state])"
|
||||
icon_states_string = "[json_encode(an_icon_state)]([text_ref(an_icon_state)])"
|
||||
else
|
||||
icon_states_string += ", [json_encode(an_icon_state)](\ref[an_icon_state])"
|
||||
icon_states_string += ", [json_encode(an_icon_state)]([text_ref(an_icon_state)])"
|
||||
|
||||
stack_trace("[item] does not have a valid icon state, icon=[icon_file], icon_state=[json_encode(icon_state)](\ref[icon_state]), icon_states=[icon_states_string]")
|
||||
stack_trace("[item] does not have a valid icon state, icon=[icon_file], icon_state=[json_encode(icon_state)]([text_ref(icon_state)]), icon_states=[icon_states_string]")
|
||||
continue
|
||||
#endif
|
||||
|
||||
|
||||
@@ -55,14 +55,12 @@
|
||||
var/christmas_tree = /obj/structure/flora/tree/pine/xmas/presents
|
||||
|
||||
/obj/effect/spawner/xmastree/Initialize(mapload)
|
||||
..()
|
||||
. = ..()
|
||||
if((CHRISTMAS in SSevents.holidays) && christmas_tree)
|
||||
new christmas_tree(get_turf(src))
|
||||
else if((FESTIVE_SEASON in SSevents.holidays) && festive_tree)
|
||||
new festive_tree(get_turf(src))
|
||||
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/effect/spawner/xmastree/rdrod
|
||||
name = "festivus pole spawner"
|
||||
festive_tree = /obj/structure/festivus
|
||||
|
||||
@@ -55,7 +55,7 @@ Key procs
|
||||
/// Initializes, and copies in the languages from the current atom if available.
|
||||
/datum/language_holder/New(atom/_owner)
|
||||
if(_owner && QDELETED(_owner))
|
||||
CRASH("Langauge holder added to a qdeleting thing, what the fuck \ref[_owner]")
|
||||
CRASH("Langauge holder added to a qdeleting thing, what the fuck [text_ref(_owner)]")
|
||||
owner = _owner
|
||||
if(istype(owner, /datum/mind))
|
||||
var/datum/mind/M = owner
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
turf_type = /turf/open/space/transit
|
||||
|
||||
/datum/turf_reservation/proc/Release()
|
||||
var/v = reserved_turfs.Copy()
|
||||
for(var/i in reserved_turfs)
|
||||
reserved_turfs -= i
|
||||
SSmapping.used_turfs -= i
|
||||
INVOKE_ASYNC(SSmapping, /datum/controller/subsystem/mapping/proc/reserve_turfs, v)
|
||||
var/list/reserved_copy = reserved_turfs.Copy()
|
||||
SSmapping.used_turfs -= reserved_turfs
|
||||
reserved_turfs = list()
|
||||
// Makes the linter happy, even tho we don't await this
|
||||
INVOKE_ASYNC(SSmapping, /datum/controller/subsystem/mapping/proc/reserve_turfs, reserved_copy)
|
||||
|
||||
/datum/turf_reservation/proc/Reserve(width, height, zlevel)
|
||||
if(width > world.maxx || height > world.maxy || width < 1 || height < 1)
|
||||
|
||||
Reference in New Issue
Block a user