diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm
index 4dc29d360b82..b824bd2a17b1 100644
--- a/code/__DEFINES/is_helpers.dm
+++ b/code/__DEFINES/is_helpers.dm
@@ -4,6 +4,8 @@
#define isatom(A) (isloc(A))
+#define isdatum(thing) (istype(thing, /datum))
+
#define isweakref(D) (istype(D, /datum/weakref))
//Turfs
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index 03796c87e897..e8975a1a6653 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -149,6 +149,13 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache)
//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]"))
+
//Gets the turf this atom inhabits
#define get_turf(A) (get_step(A, 0))
diff --git a/code/__DEFINES/typeids.dm b/code/__DEFINES/typeids.dm
index 3cf1b16e000b..5329164229d0 100644
--- a/code/__DEFINES/typeids.dm
+++ b/code/__DEFINES/typeids.dm
@@ -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)
diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm
index 126d93fe352a..38e540e996b9 100644
--- a/code/__HELPERS/icons.dm
+++ b/code/__HELPERS/icons.dm
@@ -1198,7 +1198,7 @@ GLOBAL_DATUM_INIT(dummySave, /savefile, new("tmp/dummySave.sav")) //Cache of ico
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
@@ -1209,7 +1209,7 @@ GLOBAL_DATUM_INIT(dummySave, /savefile, new("tmp/dummySave.sav")) //Cache of ico
// 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)]"
@@ -1219,7 +1219,7 @@ GLOBAL_DATUM_INIT(dummySave, /savefile, new("tmp/dummySave.sav")) //Cache of ico
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
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index ea9ceee0f417..ee495ee917d2 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -1363,11 +1363,13 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
return "{[time_high]-[time_mid]-[GUID_VERSION][time_low]-[GUID_VARIANT][time_clock]-[node_id]}"
-// \ref behaviour got changed in 512 so this is necesary to replicate old behaviour.
-// If it ever becomes necesary to get a more performant REF(), this lies here in wait
-// #define REF(thing) (thing && istype(thing, /datum) && (thing:datum_flags & DF_USE_TAG) && thing:tag ? "[thing:tag]" : "\ref[thing]")
+/**
+ * \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]" : text_ref(thing))
+**/
/proc/REF(input)
- if(istype(input, /datum))
+ if(isdatum(input))
var/datum/thing = input
if(thing.datum_flags & DF_USE_TAG)
if(!thing.tag)
@@ -1375,7 +1377,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
thing.datum_flags &= ~DF_USE_TAG
else
return "\[[url_encode(thing.tag)]\]"
- return "\ref[input]"
+ return text_ref(input)
// Makes a call in the context of a different usr
// Use sparingly
diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm
index 895a8c1685fc..b362a7ed4e62 100644
--- a/code/controllers/subsystem/garbage.dm
+++ b/code/controllers/subsystem/garbage.dm
@@ -221,7 +221,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
@@ -258,7 +258,7 @@ SUBSYSTEM_DEF(garbage)
return
var/queue_time = world.time
- var/refid = "\ref[D]"
+ var/refid = text_ref(D)
if (D.gc_destroyed <= 0)
D.gc_destroyed = queue_time
@@ -271,7 +271,7 @@ SUBSYSTEM_DEF(garbage)
++delslasttick
++totaldels
var/type = D.type
- var/refID = "\ref[D]"
+ var/refID = text_ref(D)
var/datum/qdel_item/I = items[type]
if (!force && I.qdel_flags & QDEL_ITEM_SUSPENDED_FOR_LAG)
@@ -389,7 +389,7 @@ SUBSYSTEM_DEF(garbage)
D.find_references()
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
diff --git a/code/controllers/subsystem/statpanel.dm b/code/controllers/subsystem/statpanel.dm
index ad13009760a0..1b844f168cf9 100644
--- a/code/controllers/subsystem/statpanel.dm
+++ b/code/controllers/subsystem/statpanel.dm
@@ -153,17 +153,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/ss in Master.subsystems)
- var/datum/controller/subsystem/sub_system = ss
- 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]")
+ 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(), 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))
mc_data_encoded = url_encode(json_encode(mc_data))
/atom/proc/remove_from_cache()
diff --git a/code/controllers/subsystem/timer.dm b/code/controllers/subsystem/timer.dm
index a37f7e1c0896..176f91cf5808 100644
--- a/code/controllers/subsystem/timer.dm
+++ b/code/controllers/subsystem/timer.dm
@@ -511,8 +511,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)
diff --git a/code/controllers/subsystem/vis_overlays.dm b/code/controllers/subsystem/vis_overlays.dm
index a4b0fccae437..6d134610f9f3 100644
--- a/code/controllers/subsystem/vis_overlays.dm
+++ b/code/controllers/subsystem/vis_overlays.dm
@@ -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
if(overlay == null)
diff --git a/code/datums/datum.dm b/code/datums/datum.dm
index e2f478ba7834..73aab2fb8ca8 100644
--- a/code/datums/datum.dm
+++ b/code/datums/datum.dm
@@ -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
diff --git a/code/datums/position_point_vector.dm b/code/datums/position_point_vector.dm
index 07fe0ed7652f..9675c337fcc8 100644
--- a/code/datums/position_point_vector.dm
+++ b/code/datums/position_point_vector.dm
@@ -22,7 +22,8 @@
/proc/angle_between_points(datum/point/a, datum/point/b)
return ATAN2((b.y - a.y), (b.x - a.x))
-/datum/position //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.
+/// 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
var/x = 0
var/y = 0
var/z = 0
@@ -66,7 +67,8 @@
/datum/position/proc/return_point()
return new /datum/point(src)
-/datum/point //A precise point on the map in absolute pixel locations based on world.icon_size. Pixels are FROM THE EDGE OF THE MAP!
+/// 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
var/x = 0
var/y = 0
var/z = 0
@@ -80,7 +82,8 @@
p.z = z
return p
-/datum/point/New(_x, _y, _z, _pixel_x = 0, _pixel_y = 0) //first argument can also be a /datum/position or /atom.
+/// First argument can also be a /datum/position or /atom.
+/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
@@ -107,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())
@@ -130,10 +133,13 @@
return MODULUS(y, world.icon_size) - 16 - 1
/datum/point/vector
- var/speed = 32 //pixels per iteration
+ /// Pixels per iteration
+ var/speed = 32
var/iteration = 0
var/angle = 0
- var/mpx = 0 //calculated x/y movement amounts to prevent having to do trig every step.
+ /// Calculated x movement amounts to prevent having to do trig every step.
+ 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().
var/starting_y = 0
@@ -151,6 +157,15 @@
starting_y = y
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)
+ if(!isnull(tile_x))
+ x = ((tile_x - 1) * world.icon_size) + world.icon_size * 0.5 + p_x + 1
+ if(!isnull(tile_y))
+ y = ((tile_y - 1) * world.icon_size) + world.icon_size * 0.5 + p_y + 1
+ if(!isnull(tile_z))
+ z = tile_z
+
/datum/point/vector/copy_to(datum/point/vector/v = new)
..(v)
v.speed = speed
diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm
index 3b139bba78e9..81cd538a7e45 100644
--- a/code/game/gamemodes/dynamic/dynamic.dm
+++ b/code/game/gamemodes/dynamic/dynamic.dm
@@ -111,22 +111,22 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
/datum/game_mode/dynamic/admin_panel()
var/list/dat = list("
Game Mode PanelGame Mode Panel
")
- dat += "Dynamic Mode \[VV\]\[Refresh\]
"
+ dat += "Dynamic Mode \[VV\]\[Refresh\]
"
dat += "Threat Level: [threat_level]
"
- dat += "Threat to Spend: [threat] \[Adjust\] \[View Log\]
"
+ dat += "Threat to Spend: [threat] \[Adjust\] \[View Log\]
"
dat += "
"
dat += "Parameters: centre = [GLOB.dynamic_curve_centre] ; width = [GLOB.dynamic_curve_width].
"
dat += "On average, [peaceful_percentage]% of the rounds are more peaceful.
"
- dat += "Forced extended: [GLOB.dynamic_forced_extended ? "On" : "Off"]
"
- dat += "Classic secret (only autotraitor): [GLOB.dynamic_classic_secret ? "On" : "Off"]
"
- dat += "No stacking (only one round-ender): [GLOB.dynamic_no_stacking ? "On" : "Off"]
"
- dat += "Stacking limit: [GLOB.dynamic_stacking_limit] \[Adjust\]"
+ dat += "Forced extended: [GLOB.dynamic_forced_extended ? "On" : "Off"]
"
+ dat += "Classic secret (only autotraitor): [GLOB.dynamic_classic_secret ? "On" : "Off"]
"
+ dat += "No stacking (only one round-ender): [GLOB.dynamic_no_stacking ? "On" : "Off"]
"
+ dat += "Stacking limit: [GLOB.dynamic_stacking_limit] \[Adjust\]"
dat += "
"
- dat += "\[Force Next Latejoin Ruleset\]
"
+ dat += "\[Force Next Latejoin Ruleset\]
"
if (forced_latejoin_rule)
- dat += {"-> [forced_latejoin_rule.name] <-
"}
- dat += "\[Execute Midround Ruleset\]
"
+ dat += {"-> [forced_latejoin_rule.name] <-
"}
+ dat += "\[Execute Midround Ruleset\]
"
dat += "
"
dat += "Executed rulesets: "
if (executed_rules.len > 0)
@@ -136,8 +136,8 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
else
dat += "none.
"
dat += "
Injection Timers: ([get_injection_chance(TRUE)]% chance)
"
- dat += "Latejoin: [(latejoin_injection_cooldown-world.time)>60*10 ? "[round((latejoin_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(latejoin_injection_cooldown-world.time)] seconds"] \[Now!\]
"
- dat += "Midround: [(midround_injection_cooldown-world.time)>60*10 ? "[round((midround_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(midround_injection_cooldown-world.time)] seconds"] \[Now!\]
"
+ dat += "Latejoin: [(latejoin_injection_cooldown-world.time)>60*10 ? "[round((latejoin_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(latejoin_injection_cooldown-world.time)] seconds"] \[Now!\]
"
+ dat += "Midround: [(midround_injection_cooldown-world.time)>60*10 ? "[round((midround_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(midround_injection_cooldown-world.time)] seconds"] \[Now!\]
"
usr << browse(dat.Join(), "window=gamemode_panel;size=500x500")
/datum/game_mode/dynamic/Topic(href, href_list)
diff --git a/code/game/machinery/airlock_cycle_control.dm b/code/game/machinery/airlock_cycle_control.dm
index 0b35bedebd05..76094e803cd3 100644
--- a/code/game/machinery/airlock_cycle_control.dm
+++ b/code/game/machinery/airlock_cycle_control.dm
@@ -167,7 +167,7 @@
var/maxpressure = (exterior_pressure && (cyclestate == AIRLOCK_CYCLESTATE_OUTCLOSING || cyclestate == AIRLOCK_CYCLESTATE_OUTOPENING || cyclestate == AIRLOCK_CYCLESTATE_OUTOPEN)) ? exterior_pressure : interior_pressure
var/pressure_bars = round(pressure / maxpressure * 5 + 0.01)
- var/new_overlays_hash = "[pressure_bars]-[cyclestate]-[buildstage]-[panel_open]-[machine_stat]-[shorted]-[locked]-\ref[vis_target]"
+ var/new_overlays_hash = "[pressure_bars]-[cyclestate]-[buildstage]-[panel_open]-[machine_stat]-[shorted]-[locked]-[text_ref(vis_target)]"
if(use_hash && new_overlays_hash == overlays_hash)
return ..()
overlays_hash = new_overlays_hash
@@ -645,7 +645,7 @@
"airlocks" = list(),
"skip_timer" = (world.time - skip_timer),
"skip_delay" = skip_delay,
- "vis_target" = "\ref[vis_target]"
+ "vis_target" = "[text_ref(vis_target)]"
)
if((locked && !user.has_unlimited_silicon_privilege) || (user.has_unlimited_silicon_privilege && aidisabled))
@@ -661,7 +661,7 @@
var/obj/machinery/atmospherics/components/unary/vent_pump/vent = V
data["vents"] += list(list(
"role" = vents[vent],
- "vent_id" = "\ref[vent]",
+ "vent_id" = "[text_ref(vent)]",
"name" = vent.name
))
for(var/A in airlocks)
@@ -683,7 +683,7 @@
data["airlocks"] += list(list(
"role" = airlocks[airlock],
- "airlock_id" = "\ref[airlock]",
+ "airlock_id" = "[text_ref(airlock)]",
"name" = airlock.name,
"access" = access_str
))
diff --git a/code/game/objects/effects/decals/decal.dm b/code/game/objects/effects/decals/decal.dm
index e375cfd1117e..eb5be990380f 100644
--- a/code/game/objects/effects/decals/decal.dm
+++ b/code/game/objects/effects/decals/decal.dm
@@ -46,15 +46,31 @@
var/detail_overlay
var/detail_color
-/obj/effect/turf_decal/Initialize()
- ..()
- return INITIALIZE_HINT_QDEL
+// 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
-/obj/effect/turf_decal/ComponentInitialize()
- . = ..()
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, FALSE, color, null, null, alpha, FALSE)
if(detail_overlay)
T.AddElement(/datum/element/decal, icon, detail_overlay, dir, FALSE, detail_color, null, null, alpha, appearance_flags)
+ 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
+ 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)
+#endif
+ moveToNullspace()
+ return QDEL_HINT_QUEUE
diff --git a/code/game/objects/effects/misc.dm b/code/game/objects/effects/misc.dm
index 6d5f840fcc68..b21c0b7073d5 100644
--- a/code/game/objects/effects/misc.dm
+++ b/code/game/objects/effects/misc.dm
@@ -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"
diff --git a/code/game/objects/effects/spawners/bombspawner.dm b/code/game/objects/effects/spawners/bombspawner.dm
index 914b910d9830..e1df4ff4ad18 100644
--- a/code/game/objects/effects/spawners/bombspawner.dm
+++ b/code/game/objects/effects/spawners/bombspawner.dm
@@ -37,8 +37,6 @@
V.update_appearance()
- return INITIALIZE_HINT_QDEL
-
/obj/effect/spawner/newbomb/timer/syndicate/Initialize()
temp_p = (OPTIMAL_TEMP_K_PLA_BURN_SCALE(pressure_p, pressure_o, temp_o)/2 + OPTIMAL_TEMP_K_PLA_BURN_RATIO(pressure_p, pressure_o, temp_o)/2) - T0C
. = ..()
diff --git a/code/game/objects/effects/spawners/bundle.dm b/code/game/objects/effects/spawners/bundle.dm
index 41faf88745b2..beb4a809ad03 100644
--- a/code/game/objects/effects/spawners/bundle.dm
+++ b/code/game/objects/effects/spawners/bundle.dm
@@ -7,11 +7,10 @@
var/list/items
/obj/effect/spawner/bundle/Initialize(mapload)
- ..()
+ . = ..()
if(items && items.len)
for(var/path in items)
new path(loc)
- return INITIALIZE_HINT_QDEL
/obj/effect/spawner/bundle/costume/chicken
name = "chicken costume spawner"
diff --git a/code/game/objects/effects/spawners/lootdrop.dm b/code/game/objects/effects/spawners/lootdrop.dm
index bedf2c894b03..04e7d81fd7dd 100644
--- a/code/game/objects/effects/spawners/lootdrop.dm
+++ b/code/game/objects/effects/spawners/lootdrop.dm
@@ -8,7 +8,7 @@
var/fan_out_items = FALSE //Whether the items should be distributed to offsets 0,1,-1,2,-2,3,-3.. This overrides pixel_x/y on the spawner itself
/obj/effect/spawner/lootdrop/Initialize(mapload)
- ..()
+ . = ..()
if(loot && loot.len)
var/loot_spawned = 0
while((lootcount-loot_spawned) && loot.len)
@@ -31,7 +31,6 @@
else
break // WS edit - Support spawn weights of 0 in loot tables and ruins
loot_spawned++
- return INITIALIZE_HINT_QDEL
/obj/effect/spawner/lootdrop/donkpockets
name = "donk pocket box spawner"
diff --git a/code/game/objects/effects/spawners/structure.dm b/code/game/objects/effects/spawners/structure.dm
index 9ce3411cc93a..ec893399630b 100644
--- a/code/game/objects/effects/spawners/structure.dm
+++ b/code/game/objects/effects/spawners/structure.dm
@@ -15,11 +15,8 @@ INITIALIZE_IMMEDIATE(/obj/effect/spawner/structure)
/obj/effect/spawner/structure/Initialize()
. = ..()
- if(spawn_list && spawn_list.len)
- for(var/I in spawn_list)
- new I(get_turf(src))
- return INITIALIZE_HINT_QDEL
-
+ for(var/spawn_type in spawn_list)
+ new spawn_type(loc)
//normal windows
diff --git a/code/game/objects/effects/spawners/traps.dm b/code/game/objects/effects/spawners/traps.dm
index 731b4efc1d98..0409d9944b9b 100644
--- a/code/game/objects/effects/spawners/traps.dm
+++ b/code/game/objects/effects/spawners/traps.dm
@@ -4,7 +4,6 @@
icon_state = "trap_rand"
/obj/effect/spawner/trap/Initialize(mapload)
- ..()
+ . = ..()
var/new_type = pick(subtypesof(/obj/structure/trap) - typesof(/obj/structure/trap/ctf))
new new_type(get_turf(src))
- return INITIALIZE_HINT_QDEL
diff --git a/code/game/objects/effects/spawners/xeno_egg_delivery.dm b/code/game/objects/effects/spawners/xeno_egg_delivery.dm
index d0e99d0f9036..99eac4828932 100644
--- a/code/game/objects/effects/spawners/xeno_egg_delivery.dm
+++ b/code/game/objects/effects/spawners/xeno_egg_delivery.dm
@@ -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
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index ec750eb66aca..0811e39fbe67 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -156,7 +156,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),
)
/**
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index a530012270ae..82cb857576c1 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -437,7 +437,7 @@
dat += "(Force Roundstart Rulesets)
"
if (GLOB.dynamic_forced_roundstart_ruleset.len > 0)
for(var/datum/dynamic_ruleset/roundstart/rule in GLOB.dynamic_forced_roundstart_ruleset)
- dat += {"-> [rule.name] <-
"}
+ dat += {"-> [rule.name] <-
"}
dat += "(Clear Rulesets)
"
dat += "(Dynamic mode options)
"
dat += "
"
diff --git a/code/modules/admin/sound_emitter.dm b/code/modules/admin/sound_emitter.dm
index 2c930034967f..bdf2a4e6aa34 100644
--- a/code/modules/admin/sound_emitter.dm
+++ b/code/modules/admin/sound_emitter.dm
@@ -58,16 +58,16 @@
/obj/effect/sound_emitter/proc/edit_emitter(mob/user)
var/dat = ""
- dat += "Label: [maptext ? maptext : "No label set!"]
"
+ dat += "Label: [maptext ? maptext : "No label set!"]
"
dat += "
"
- dat += "Sound File: [sound_file ? sound_file : "No file chosen!"]
"
- dat += "Volume: [sound_volume]%
"
+ dat += "Sound File: [sound_file ? sound_file : "No file chosen!"]
"
+ dat += "Volume: [sound_volume]%
"
dat += "
"
- dat += "Mode: [motus_operandi]
"
+ dat += "Mode: [motus_operandi]
"
if(motus_operandi != SOUND_EMITTER_LOCAL)
- dat += "Range: [emitter_range][emitter_range == SOUND_EMITTER_RADIUS ? "[play_radius]-tile radius" : ""]
"
+ dat += "Range: [emitter_range][emitter_range == SOUND_EMITTER_RADIUS ? "[play_radius]-tile radius" : ""]
"
dat += "
"
- dat += "Play Sound (interrupts other sound emitter sounds)"
+ dat += "Play Sound (interrupts other sound emitter sounds)"
var/datum/browser/popup = new(user, "emitter", "", 500, 600)
popup.set_content(dat)
popup.open()
diff --git a/code/modules/admin/view_variables/reference_tracking.dm b/code/modules/admin/view_variables/reference_tracking.dm
index 69d3a5d1541b..a9a84986416d 100644
--- a/code/modules/admin/view_variables/reference_tracking.dm
+++ b/code/modules/admin/view_variables/reference_tracking.dm
@@ -106,11 +106,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)
@@ -126,7 +126,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
@@ -139,7 +139,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
@@ -153,7 +153,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
diff --git a/code/modules/antagonists/borer/borer.dm b/code/modules/antagonists/borer/borer.dm
index 4fc5a6aab8f1..ca9b6af1b106 100644
--- a/code/modules/antagonists/borer/borer.dm
+++ b/code/modules/antagonists/borer/borer.dm
@@ -136,7 +136,7 @@ GLOBAL_VAR_INIT(total_borer_hosts_needed, 3)
. = ..()
generation = gen
if(is_team_borer)
- notify_ghosts("A cortical borer has been created in [get_area(src)]!", enter_link = "(Click to enter)", source = src, action = NOTIFY_ATTACK)
+ notify_ghosts("A cortical borer has been created in [get_area(src)]!", enter_link = "(Click to enter)", source = src, action = NOTIFY_ATTACK)
var/numeral = rand(1000, 9999)
real_name = "Cortical Borer [numeral]"
truename = "[borer_names[min(generation, borer_names.len)]] [numeral]"
@@ -200,7 +200,7 @@ GLOBAL_VAR_INIT(total_borer_hosts_needed, 3)
chemicals -= C.chemuse
log_game("[src]/([src.ckey]) has injected [C.chemname] ([C.chem]) into their host [victim]/([victim.ckey])")
- src << output(chemicals, "ViewBorer\ref[src]Chems.browser:update_chemicals")
+ src << output(chemicals, "ViewBorer[text_ref(src)]Chems.browser:update_chemicals")
..()
@@ -235,7 +235,7 @@ GLOBAL_VAR_INIT(total_borer_hosts_needed, 3)
if(statpanel("Status"))
stat(null, "Chemicals: [chemicals]")
- src << output(chemicals, "ViewBorer\ref[src]Chems.browser:update_chemicals")
+ src << output(chemicals, "ViewBorer[text_ref(src)]Chems.browser:update_chemicals")
/mob/living/simple_animal/borer/verb/Communicate()
set category = "Borer"
@@ -484,13 +484,13 @@ GLOBAL_VAR_INIT(total_borer_hosts_needed, 3)
for(var/datum in typesof(/datum/borer_chem))
var/datum/borer_chem/C = new datum()
if(C.chem)
- content += "[C.chemname] ([C.quantity]u, takes [C.chemuse] chemical) [C.chem_desc] |
"
+ content += "[C.chemname] ([C.quantity]u, takes [C.chemuse] chemical) [C.chem_desc] |
"
content += ""
var/html = get_html_template(content)
- usr << browse(null, "window=ViewBorer\ref[src]Chems;size=600x800")
- usr << browse(html, "window=ViewBorer\ref[src]Chems;size=600x800")
+ usr << browse(null, "window=ViewBorer[text_ref(src)]Chems;size=600x800")
+ usr << browse(html, "window=ViewBorer[text_ref(src)]Chems;size=600x800")
return
diff --git a/code/modules/events/holiday/xmas.dm b/code/modules/events/holiday/xmas.dm
index f1a36affcd3b..f38d21b868c4 100644
--- a/code/modules/events/holiday/xmas.dm
+++ b/code/modules/events/holiday/xmas.dm
@@ -49,15 +49,13 @@
var/festive_tree = /obj/structure/flora/tree/pine/xmas
var/christmas_tree = /obj/structure/flora/tree/pine/xmas/presents
-/obj/effect/spawner/xmastree/Initialize()
- ..()
+/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
diff --git a/code/modules/language/language_holder.dm b/code/modules/language/language_holder.dm
index 1f42ec424706..61570535cbbf 100644
--- a/code/modules/language/language_holder.dm
+++ b/code/modules/language/language_holder.dm
@@ -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
diff --git a/code/modules/mob/say_vr.dm b/code/modules/mob/say_vr.dm
index 83bb19a33882..d2e6a4f0dda2 100644
--- a/code/modules/mob/say_vr.dm
+++ b/code/modules/mob/say_vr.dm
@@ -10,28 +10,22 @@
set src in usr
if(usr != src)
- usr << "No."
+ to_chat(usr, span_warning("You can't set someone else's flavour text!"))
var/msg = sanitize(input(usr,"Set the flavor text in your 'examine' verb. Can also be used for OOC notes about your character.","Flavor Text",html_decode(flavor_text)) as message|null)
- if(msg) //WS edit - "Cancel" does not clear flavor text
+ if(msg)
msg = copytext(msg, 1, MAX_MESSAGE_LEN)
msg = html_encode(msg)
flavor_text = msg
-/mob/proc/warn_flavor_changed()
- if(flavor_text && flavor_text != "") // don't spam people that don't use it!
- src << "OOC Warning:
"
- src << "Your flavor text is likely out of date! Change"
-
/mob/proc/print_flavor_text()
if(flavor_text && flavor_text != "")
var/msg = replacetext(flavor_text, "\n", " ")
if(length(msg) <= 100)
return "[msg]"
else
- return "[copytext(msg, 1, 97)]... More..."
-
+ return "[copytext(msg, 1, 97)]... More..."
/mob/proc/get_top_level_mob()
if(istype(src.loc,/mob)&&src.loc!=src)