diff --git a/code/__DEFINES/cooldowns.dm b/code/__DEFINES/cooldowns.dm
index 2510db0fbfe..979839224b5 100644
--- a/code/__DEFINES/cooldowns.dm
+++ b/code/__DEFINES/cooldowns.dm
@@ -61,7 +61,7 @@
#define COOLDOWN_DECLARE(cd_index) var/##cd_index = 0
-#define COOLDOWN_START(cd_source, cd_index, cd_time) (cd_source.cd_index = world.time + cd_time)
+#define COOLDOWN_START(cd_source, cd_index, cd_time) (cd_source.cd_index = world.time + (cd_time))
//Returns true if the cooldown has run its course, false otherwise
#define COOLDOWN_FINISHED(cd_source, cd_index) (cd_source.cd_index < world.time)
diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm
index 916483d1088..76f58732032 100644
--- a/code/__DEFINES/mobs.dm
+++ b/code/__DEFINES/mobs.dm
@@ -389,3 +389,9 @@
#define FLAVOR_TEXT_GOOD "good" //ie do not cause evil
#define FLAVOR_TEXT_NONE "none"
#define FLAVOR_TEXT_GOAL_ANTAG "blob" //is antag, but should work towards its goals
+<<<<<<< HEAD
+=======
+
+//Saves a proc call, life is suffering. If who has no targets_from var, we assume it's just who
+#define GET_TARGETS_FROM(who) (who.targets_from ? who.get_targets_from() : who)
+>>>>>>> e260143132 (Port harddel fixes, as well as "Fixes stasis bed runtimes" (#4598))
diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm
index b26e7adce92..11a6d692ce5 100644
--- a/code/__DEFINES/subsystems.dm
+++ b/code/__DEFINES/subsystems.dm
@@ -85,6 +85,9 @@
///Call qdel on the atom after intialization
#define INITIALIZE_HINT_QDEL 2
+///Call qdel with a force of TRUE after initialization
+#define INITIALIZE_HINT_QDEL_FORCE 3
+
///type and all subtypes should always immediately call Initialize in New()
#define INITIALIZE_IMMEDIATE(X) ##X/New(loc, ...){\
..();\
diff --git a/code/__HELPERS/_logging.dm b/code/__HELPERS/_logging.dm
index 13acbef8e1c..f8ed5fd70b1 100644
--- a/code/__HELPERS/_logging.dm
+++ b/code/__HELPERS/_logging.dm
@@ -35,6 +35,11 @@
SEND_TEXT(world.log, text)
#endif
+#ifdef REFERENCE_TRACKING_LOG
+#define log_reftracker(msg) log_world("## REF SEARCH [msg]")
+#else
+#define log_reftracker(msg)
+#endif
/* Items with ADMINPRIVATE prefixed are stripped from public logs. */
/proc/log_admin(text)
diff --git a/code/_compile_options.dm b/code/_compile_options.dm
index 67ddf05702c..f96dcd3ae1d 100644
--- a/code/_compile_options.dm
+++ b/code/_compile_options.dm
@@ -22,6 +22,9 @@
//#define LEGACY_REFERENCE_TRACKING
#ifdef LEGACY_REFERENCE_TRACKING
+///Should we be logging our findings or not
+#define REFERENCE_TRACKING_LOG
+
///Use the legacy reference on things hard deleting by default.
//#define GC_FAILURE_HARD_LOOKUP
#ifdef GC_FAILURE_HARD_LOOKUP
diff --git a/code/_onclick/hud/radial.dm b/code/_onclick/hud/radial.dm
index 39926a52eab..53b50f93256 100644
--- a/code/_onclick/hud/radial.dm
+++ b/code/_onclick/hud/radial.dm
@@ -9,6 +9,17 @@ GLOBAL_LIST_EMPTY(radial_menus)
plane = ABOVE_HUD_PLANE
var/datum/radial_menu/parent
+/atom/movable/screen/radial/proc/set_parent(new_value)
+ if(parent)
+ UnregisterSignal(parent, COMSIG_PARENT_QDELETING)
+ parent = new_value
+ if(parent)
+ RegisterSignal(parent, COMSIG_PARENT_QDELETING, .proc/handle_parent_del)
+
+/atom/movable/screen/radial/proc/handle_parent_del()
+ SIGNAL_HANDLER
+ set_parent(null)
+
/atom/movable/screen/radial/slice
icon_state = "radial_slice"
var/choice
@@ -132,7 +143,7 @@ GLOBAL_LIST_EMPTY(radial_menus)
for(var/i in 1 to elements_to_add) //Create all elements
var/atom/movable/screen/radial/slice/new_element = new /atom/movable/screen/radial/slice
new_element.tooltips = use_tooltips
- new_element.parent = src
+ new_element.set_parent(src)
elements += new_element
var/page = 1
@@ -222,7 +233,7 @@ GLOBAL_LIST_EMPTY(radial_menus)
/datum/radial_menu/New()
close_button = new
- close_button.parent = src
+ close_button.set_parent(src)
/datum/radial_menu/proc/Reset()
choices.Cut()
diff --git a/code/_onclick/hud/radial_persistent.dm b/code/_onclick/hud/radial_persistent.dm
index e7f7c664ad7..1c46ecee56d 100644
--- a/code/_onclick/hud/radial_persistent.dm
+++ b/code/_onclick/hud/radial_persistent.dm
@@ -26,7 +26,7 @@
/datum/radial_menu/persistent/New()
close_button = new /atom/movable/screen/radial/persistent/center
- close_button.parent = src
+ close_button.set_parent(src)
/datum/radial_menu/persistent/element_chosen(choice_id,mob/user)
diff --git a/code/controllers/subsystem/atoms.dm b/code/controllers/subsystem/atoms.dm
index 6aa97c2a643..f139d4692b1 100644
--- a/code/controllers/subsystem/atoms.dm
+++ b/code/controllers/subsystem/atoms.dm
@@ -97,6 +97,9 @@ SUBSYSTEM_DEF(atoms)
if(INITIALIZE_HINT_QDEL)
qdel(A)
qdeleted = TRUE
+ if(INITIALIZE_HINT_QDEL_FORCE)
+ qdel(A, force = TRUE)
+ qdeleted = TRUE
else
BadInitializeCalls[the_type] |= BAD_INIT_NO_HINT
diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm
index 5a14185f84c..b0d189b638b 100644
--- a/code/controllers/subsystem/garbage.dm
+++ b/code/controllers/subsystem/garbage.dm
@@ -148,29 +148,36 @@ SUBSYSTEM_DEF(garbage)
// Something's still referring to the qdel'd object.
fail_counts[level]++
+
+ #ifdef REFERENCE_TRACKING
+ var/ref_searching = FALSE
+ #endif
+
switch (level)
if (GC_QUEUE_CHECK)
#ifdef REFERENCE_TRACKING
D.find_references()
#elif defined(LEGACY_REFERENCE_TRACKING)
if(reference_find_on_fail[refID])
- D.find_references_legacy()
+ INVOKE_ASYNC(D, /datum/proc/find_references_legacy)
+ ref_searching = TRUE
#ifdef GC_FAILURE_HARD_LOOKUP
else
- D.find_references_legacy()
+ INVOKE_ASYNC(D, /datum/proc/find_references_legacy)
+ ref_searching = TRUE
#endif
reference_find_on_fail -= refID
#endif
var/type = D.type
var/datum/qdel_item/I = items[type]
- #ifdef TESTING
+
log_world("## TESTING: GC: -- \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
if(!check_rights_for(admin, R_ADMIN))
continue
to_chat(admin, "## TESTING: GC: -- [ADMIN_VV(D)] | [type] was unable to be GC'd --")
- testing("GC: -- \ref[src] | [type] was unable to be GC'd --")
#endif
#ifdef REFERENCE_TRACKING
GLOB.deletion_failures += D //It should no longer be bothered by the GC, manual deletion only.
@@ -185,6 +192,11 @@ SUBSYSTEM_DEF(garbage)
Queue(D, level+1)
+ #ifdef REFERENCE_TRACKING
+ if(ref_searching)
+ return
+ #endif
+
if (MC_TICK_CHECK)
return
if (count)
diff --git a/code/datums/browser.dm b/code/datums/browser.dm
index ee9ef86bea3..fb458d353b1 100644
--- a/code/datums/browser.dm
+++ b/code/datums/browser.dm
@@ -4,7 +4,7 @@
var/window_id // window_id is used as the window name for browse and onclose
var/width = 0
var/height = 0
- var/atom/ref = null
+ var/datum/weakref/ref = null
var/window_options = "can_close=1;can_minimize=1;can_maximize=0;can_resize=1;titlebar=1;" // window option is set using window_id
var/stylesheets[0]
var/scripts[0]
@@ -17,6 +17,7 @@
/datum/browser/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null)
user = nuser
+ RegisterSignal(user, COMSIG_PARENT_QDELETING, .proc/user_deleted)
window_id = nwindow_id
if (ntitle)
title = format_text(ntitle)
@@ -25,7 +26,11 @@
if (nheight)
height = nheight
if (nref)
- ref = nref
+ ref = WEAKREF(nref)
+
+/datum/browser/proc/user_deleted(datum/source)
+ SIGNAL_HANDLER
+ user = null
/datum/browser/proc/add_head_content(nhead_content)
head_content = nhead_content
@@ -111,8 +116,13 @@
/datum/browser/proc/setup_onclose()
set waitfor = 0 //winexists sleeps, so we don't need to.
for (var/i in 1 to 10)
- if (user && winexists(user, window_id))
- onclose(user, window_id, ref)
+ if (user?.client && winexists(user, window_id))
+ var/atom/send_ref
+ if(ref)
+ send_ref = ref.resolve()
+ if(!send_ref)
+ ref = null
+ onclose(user, window_id, send_ref)
break
/datum/browser/proc/close()
diff --git a/code/datums/components/squeak.dm b/code/datums/components/squeak.dm
index fed8ab28408..af8af255364 100644
--- a/code/datums/components/squeak.dm
+++ b/code/datums/components/squeak.dm
@@ -66,7 +66,7 @@
if(istype(AM, /obj/effect/dummy/phased_mob)) //don't squeek if they're in a phased/jaunting container.
return
var/atom/current_parent = parent
- if(isturf(current_parent.loc))
+ if(isturf(current_parent?.loc))
play_squeak()
/datum/component/squeak/proc/use_squeak()
diff --git a/code/datums/components/storage/storage.dm b/code/datums/components/storage/storage.dm
index f56547b779a..5e1cf86b30e 100644
--- a/code/datums/components/storage/storage.dm
+++ b/code/datums/components/storage/storage.dm
@@ -366,20 +366,27 @@
M.client.screen |= boxes
M.client.screen |= closer
M.client.screen |= real_location.contents
- M.active_storage = src
+ M.set_active_storage(src)
LAZYOR(is_using, M)
+ RegisterSignal(M, COMSIG_PARENT_QDELETING, .proc/mob_deleted)
return TRUE
+/datum/component/storage/proc/mob_deleted(datum/source)
+ SIGNAL_HANDLER
+ hide_from(source)
+
/datum/component/storage/proc/hide_from(mob/M)
+ if(M.active_storage == src)
+ M.set_active_storage(null)
+ LAZYREMOVE(is_using, M)
+
+ UnregisterSignal(M, COMSIG_PARENT_QDELETING)
if(!M.client)
return TRUE
var/atom/real_location = real_location()
M.client.screen -= boxes
M.client.screen -= closer
M.client.screen -= real_location.contents
- if(M.active_storage == src)
- M.active_storage = null
- LAZYREMOVE(is_using, M)
return TRUE
/datum/component/storage/proc/close(mob/M)
@@ -451,6 +458,7 @@
cansee |= M
else
LAZYREMOVE(is_using, M)
+ UnregisterSignal(M, COMSIG_PARENT_QDELETING)
return cansee
//Tries to dump content
diff --git a/code/datums/dash_weapon.dm b/code/datums/dash_weapon.dm
index 7f5cf721930..8c8639d1383 100644
--- a/code/datums/dash_weapon.dm
+++ b/code/datums/dash_weapon.dm
@@ -6,7 +6,6 @@
var/current_charges = 1
var/max_charges = 1
var/charge_rate = 250
- var/mob/living/carbon/human/holder
var/obj/item/dashing_item
var/dash_sound = 'sound/magic/blink.ogg'
var/recharge_sound = 'sound/magic/charge.ogg'
@@ -17,7 +16,10 @@
/datum/action/innate/dash/Grant(mob/user, obj/dasher)
. = ..()
dashing_item = dasher
- holder = user
+
+/datum/action/innate/dash/Destroy()
+ dashing_item = null
+ return ..()
/datum/action/innate/dash/IsAvailable()
if(current_charges > 0)
@@ -26,7 +28,7 @@
return FALSE
/datum/action/innate/dash/Activate()
- dashing_item.attack_self(holder) //Used to toggle dash behavior in the dashing item
+ dashing_item.attack_self(owner) //Used to toggle dash behavior in the dashing item
/datum/action/innate/dash/proc/Teleport(mob/user, atom/target)
if(!IsAvailable())
@@ -39,14 +41,14 @@
var/obj/spot2 = new phasein(get_turf(user), user.dir)
spot1.Beam(spot2,beam_effect,time=20)
current_charges--
- holder.update_action_buttons_icon()
+ owner.update_action_buttons_icon()
addtimer(CALLBACK(src, .proc/charge), charge_rate)
else
to_chat(user, "You cannot dash here!")
/datum/action/innate/dash/proc/charge()
current_charges = CLAMP(current_charges + 1, 0, max_charges)
- holder.update_action_buttons_icon()
+ owner.update_action_buttons_icon()
if(recharge_sound)
playsound(dashing_item, recharge_sound, 50, 1)
- to_chat(holder, "[src] now has [current_charges]/[max_charges] charges.")
+ to_chat(owner, "[src] now has [current_charges]/[max_charges] charges.")
diff --git a/code/datums/hud.dm b/code/datums/hud.dm
index f38d9f65bda..0cda7290d47 100644
--- a/code/datums/hud.dm
+++ b/code/datums/hud.dm
@@ -104,6 +104,7 @@ GLOBAL_LIST_INIT(huds, list(
/datum/atom_hud/proc/unregister_mob(datum/source, force)
SIGNAL_HANDLER
remove_hud_from(source, TRUE)
+ remove_from_hud(source)
/datum/atom_hud/proc/show_hud_images_after_cooldown(M)
if(queued_to_see[M])
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 6afd8794aca..5da0fa7ca6c 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -88,8 +88,22 @@
qdel(i)
antag_datums = null
QDEL_NULL(language_holder)
+ set_current(null)
return ..()
+/datum/mind/proc/set_current(mob/new_current)
+ if(new_current && QDELING(new_current))
+ CRASH("Tried to set a mind's current var to a qdeleted mob, what the fuck")
+ if(current)
+ UnregisterSignal(src, COMSIG_PARENT_QDELETING)
+ current = new_current
+ if(current)
+ RegisterSignal(src, COMSIG_PARENT_QDELETING, .proc/clear_current)
+
+/datum/mind/proc/clear_current(datum/source)
+ SIGNAL_HANDLER
+ set_current(null)
+
/datum/mind/proc/get_language_holder()
if(!language_holder)
language_holder = new (src)
@@ -108,13 +122,13 @@
key = new_character.key
if(new_character.mind) //disassociate any mind currently in our new body's mind variable
- new_character.mind.current = null
+ new_character.mind.set_current(null)
var/datum/atom_hud/antag/hud_to_transfer = antag_hud//we need this because leave_hud() will clear this list
var/mob/living/old_current = current
if(current)
current.transfer_observers_to(new_character) //transfer anyone observing the old character to the new one
- current = new_character //associate ourself with our new body
+ set_current(new_character) //associate ourself with our new body
new_character.mind = src //and associate our new body with ourself
for(var/a in antag_datums) //Makes sure all antag datums effects are applied in the new body
var/datum/antagonist/A = a
@@ -726,7 +740,7 @@
SSticker.minds += mind
if(!mind.name)
mind.name = real_name
- mind.current = src
+ mind.set_current(src)
/mob/living/carbon/mind_initialize()
..()
diff --git a/code/game/gamemodes/clown_ops/clown_weapons.dm b/code/game/gamemodes/clown_ops/clown_weapons.dm
index 01f1b88f919..f96e4d18217 100644
--- a/code/game/gamemodes/clown_ops/clown_weapons.dm
+++ b/code/game/gamemodes/clown_ops/clown_weapons.dm
@@ -160,8 +160,9 @@
if(iscarbon(hit_atom) && !caught)//if they are a carbon and they didn't catch it
var/datum/component/slippery/slipper = GetComponent(/datum/component/slippery)
slipper.Slip(src, hit_atom)
- if(thrownby && !caught)
- addtimer(CALLBACK(src, /atom/movable.proc/throw_at, thrownby, throw_range+2, throw_speed, null, TRUE), 1)
+ var/mob/thrown_by = thrownby?.resolve()
+ if(thrown_by && !caught)
+ addtimer(CALLBACK(src, /atom/movable.proc/throw_at, thrown_by, throw_range+2, throw_speed, null, TRUE), 1)
else
return ..()
diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm
index cb2cb4fd628..3aa370c078c 100644
--- a/code/game/gamemodes/objective.dm
+++ b/code/game/gamemodes/objective.dm
@@ -17,6 +17,11 @@ GLOBAL_LIST_EMPTY(objectives)
if(text)
explanation_text = text
+//Apparently objectives can be qdel'd. Learn a new thing every day
+/datum/objective/Destroy()
+ GLOB.objectives -= src
+ return ..()
+
/datum/objective/proc/get_owners() // Combine owner and team into a single list.
. = (team && team.members) ? team.members.Copy() : list()
if(owner)
diff --git a/code/game/machinery/camera/tracking.dm b/code/game/machinery/camera/tracking.dm
index bf1b84fe5d4..767cb90abad 100644
--- a/code/game/machinery/camera/tracking.dm
+++ b/code/game/machinery/camera/tracking.dm
@@ -49,9 +49,9 @@
track.namecounts[name] = 1
if(ishuman(L))
- track.humans[name] = L
+ track.humans[name] = WEAKREF(L)
else
- track.others[name] = L
+ track.others[name] = WEAKREF(L)
var/list/targets = sortList(track.humans) + sortList(track.others)
@@ -67,9 +67,9 @@
if(!track.initialized)
trackable_mobs()
- var/mob/target = (isnull(track.humans[target_name]) ? track.others[target_name] : track.humans[target_name])
+ var/datum/weakref/target = (isnull(track.humans[target_name]) ? track.others[target_name] : track.humans[target_name])
- ai_actual_track(target)
+ ai_actual_track(target.resolve())
/mob/living/silicon/ai/proc/ai_actual_track(mob/living/target)
if(!istype(target))
diff --git a/code/game/machinery/computer/Operating.dm b/code/game/machinery/computer/Operating.dm
index 13c5d45a80a..32c55ae451b 100644
--- a/code/game/machinery/computer/Operating.dm
+++ b/code/game/machinery/computer/Operating.dm
@@ -7,7 +7,7 @@
icon_screen = "crew"
icon_keyboard = "med_key"
circuit = /obj/item/circuitboard/computer/operating
- var/mob/living/carbon/human/patient
+
var/obj/structure/table/optable/table
var/obj/machinery/stasis/sbed
var/list/advanced_surgeries = list()
@@ -21,11 +21,11 @@
/obj/machinery/computer/operating/Destroy()
for(var/direction in GLOB.cardinals)
- table = locate(/obj/structure/table/optable, get_step(src, direction))
+ table = locate(/obj/structure/table/optable) in get_step(src, direction)
if(table && table.computer == src)
table.computer = null
else
- sbed = locate(/obj/machinery/stasis, get_step(src, direction))
+ sbed = locate(/obj/machinery/stasis) in get_step(src, direction)
if(sbed && sbed.op_computer == src)
sbed.op_computer = null
. = ..()
@@ -50,12 +50,12 @@
/obj/machinery/computer/operating/proc/find_table()
for(var/direction in GLOB.cardinals)
- table = locate(/obj/structure/table/optable, get_step(src, direction))
+ table = locate(/obj/structure/table/optable) in get_step(src, direction)
if(table)
table.computer = src
break
else
- sbed = locate(/obj/machinery/stasis, get_step(src, direction))
+ sbed = locate(/obj/machinery/stasis) in get_step(src, direction)
if(sbed)
sbed.op_computer = src
break
@@ -80,17 +80,24 @@
surgery["desc"] = initial(S.desc)
surgeries += list(surgery)
data["surgeries"] = surgeries
- data["patient"] = null
+
+ //If there's no patient just hop to it yeah?
+ if(!table && !sbed)
+ data["patient"] = null
+ return data
+
+ var/mob/living/carbon/human/patient
+
if(table)
data["table"] = table
- if(!table.check_patient())
+ if(!table.check_eligible_patient())
return data
data["patient"] = list()
patient = table.patient
else
if(sbed)
data["table"] = sbed
- if(!sbed.check_patient())
+ if(!ishuman(sbed.occupant) && !ismonkey(sbed.occupant))
return data
data["patient"] = list()
patient = sbed.occupant
diff --git a/code/game/machinery/launch_pad.dm b/code/game/machinery/launch_pad.dm
index afe87add691..cc4686b78ec 100644
--- a/code/game/machinery/launch_pad.dm
+++ b/code/game/machinery/launch_pad.dm
@@ -43,7 +43,8 @@
update_indicator()
/obj/machinery/launchpad/Destroy()
- qdel(hud_list[DIAG_LAUNCHPAD_HUD])
+ for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds)
+ diag_hud.remove_from_hud(src)
return ..()
/obj/machinery/launchpad/examine(mob/user)
@@ -257,9 +258,9 @@
/obj/machinery/launchpad/briefcase/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/launchpad_remote))
var/obj/item/launchpad_remote/L = I
- if(L.pad == src) //do not attempt to link when already linked
+ if(L.pad == WEAKREF(src)) //do not attempt to link when already linked
return ..()
- L.pad = src
+ L.pad = WEAKREF(src)
to_chat(user, "You link [src] to [L].")
else
return ..()
@@ -296,9 +297,9 @@
/obj/item/storage/briefcase/launchpad/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/launchpad_remote))
var/obj/item/launchpad_remote/L = I
- if(L.pad == src.pad) //do not attempt to link when already linked
+ if(L.pad == WEAKREF(src.pad)) //do not attempt to link when already linked
return ..()
- L.pad = src.pad
+ L.pad = WEAKREF(src.pad)
to_chat(user, "You link [pad] to [L].")
else
return ..()
@@ -310,11 +311,12 @@
icon_state = "folder"
w_class = WEIGHT_CLASS_SMALL
var/sending = TRUE
- var/obj/machinery/launchpad/briefcase/pad
+ //A weakref to our linked pad
+ var/datum/weakref/pad
/obj/item/launchpad_remote/Initialize(mapload, pad) //remote spawns linked to the briefcase pad
. = ..()
- src.pad = pad
+ src.pad = WEAKREF(pad)
/obj/item/launchpad_remote/attack_self(mob/user)
. = ..()
@@ -335,16 +337,17 @@
/obj/item/launchpad_remote/ui_data(mob/user)
var/list/data = list()
- data["has_pad"] = pad ? TRUE : FALSE
- if(pad)
- data["pad_closed"] = pad.closed
- if(!pad || pad.closed)
+ var/obj/machinery/launchpad/briefcase/our_pad = pad.resolve()
+ data["has_pad"] = our_pad ? TRUE : FALSE
+ if(our_pad)
+ data["pad_closed"] = our_pad.closed
+ if(!our_pad || our_pad.closed)
return data
- data["pad_name"] = pad.display_name
- data["range"] = pad.range
- data["x"] = pad.x_offset
- data["y"] = pad.y_offset
+ data["pad_name"] = our_pad.display_name
+ data["range"] = our_pad.range
+ data["x"] = our_pad.x_offset
+ data["y"] = our_pad.y_offset
return data
/obj/item/launchpad_remote/proc/teleport(mob/user, obj/machinery/launchpad/pad)
@@ -359,18 +362,22 @@
/obj/item/launchpad_remote/ui_act(action, params)
if(..())
return
+ var/obj/machinery/launchpad/briefcase/our_pad = pad.resolve()
+ if(!our_pad)
+ pad = null
+ return TRUE
switch(action)
if("set_pos")
var/new_x = text2num(params["x"])
var/new_y = text2num(params["y"])
- pad.set_offset(new_x, new_y)
+ our_pad.set_offset(new_x, new_y)
. = TRUE
if("move_pos")
var/plus_x = text2num(params["x"])
var/plus_y = text2num(params["y"])
- pad.set_offset(
- x = pad.x_offset + plus_x,
- y = pad.y_offset + plus_y
+ our_pad.set_offset(
+ x = our_pad.x_offset + plus_x,
+ y = our_pad.y_offset + plus_y
)
. = TRUE
if("rename")
@@ -378,16 +385,16 @@
var/new_name = params["name"]
if(!new_name)
return
- pad.display_name = new_name
+ our_pad.display_name = new_name
if("remove")
. = TRUE
if(usr && alert(usr, "Are you sure?", "Unlink Launchpad", "I'm Sure", "Abort") != "Abort")
pad = null
if("launch")
sending = TRUE
- teleport(usr, pad)
+ teleport(usr, our_pad)
. = TRUE
if("pull")
sending = FALSE
- teleport(usr, pad)
+ teleport(usr, our_pad)
. = TRUE
diff --git a/code/game/machinery/stasis.dm b/code/game/machinery/stasis.dm
index 5b586c4d182..0ffe8aa21f1 100644
--- a/code/game/machinery/stasis.dm
+++ b/code/game/machinery/stasis.dm
@@ -22,7 +22,7 @@
/obj/machinery/stasis/Initialize()
. = ..()
for(var/direction in GLOB.cardinals)
- op_computer = locate(/obj/machinery/computer/operating, get_step(src, direction))
+ op_computer = locate(/obj/machinery/computer/operating) in get_step(src, direction)
if(op_computer)
op_computer.sbed = src
break
@@ -123,12 +123,6 @@
chill_out(L)
update_icon()
-/obj/machinery/stasis/proc/check_patient()
- if(occupant)
- return TRUE
- else
- return FALSE
-
/obj/machinery/stasis/post_unbuckle_mob(mob/living/L)
thaw_them(L)
if(L == occupant)
diff --git a/code/game/objects/effects/anomalies.dm b/code/game/objects/effects/anomalies.dm
index 589de20766c..7f2144adfcd 100644
--- a/code/game/objects/effects/anomalies.dm
+++ b/code/game/objects/effects/anomalies.dm
@@ -54,7 +54,7 @@
/obj/effect/anomaly/Destroy()
GLOB.poi_list.Remove(src)
STOP_PROCESSING(SSobj, src)
- qdel(countdown)
+ QDEL_NULL(countdown)
return ..()
/obj/effect/anomaly/proc/anomalyEffect(delta_time)
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 320681b517a..628dc7c5b4e 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -120,7 +120,8 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
/// list() of species types, if a species cannot put items in a certain slot, but species type is in list, it will be able to wear that item
var/list/species_exception = null
- var/mob/thrownby = null
+ ///A weakref to the mob who threw the item
+ var/datum/weakref/thrownby = null
mouse_drag_pointer = MOUSE_ACTIVE_POINTER //the icon to indicate this object is being dragged
@@ -739,11 +740,10 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
/obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, quickstart = TRUE)
if(HAS_TRAIT(src, TRAIT_NODROP))
return
- thrownby = thrower
+ thrownby = WEAKREF(thrower)
callback = CALLBACK(src, .proc/after_throw, callback) //replace their callback with our own
. = ..(target, range, speed, thrower, spin, diagonals_first, callback, force, quickstart = quickstart)
-
/obj/item/proc/after_throw(datum/callback/callback)
if (callback) //call the original callback
. = callback.Invoke()
diff --git a/code/game/objects/items/chrono_eraser.dm b/code/game/objects/items/chrono_eraser.dm
index 53f3490e660..b7d40fb0011 100644
--- a/code/game/objects/items/chrono_eraser.dm
+++ b/code/game/objects/items/chrono_eraser.dm
@@ -133,6 +133,10 @@
if(istype(C))
gun = C.gun
+/obj/item/projectile/energy/chrono_beam/Destroy()
+ gun = null
+ return ..()
+
/obj/item/projectile/energy/chrono_beam/on_hit(atom/target)
if(target && gun && isliving(target))
var/obj/structure/chrono_field/F = new(target.loc, target, gun)
@@ -151,7 +155,9 @@
gun = loc
. = ..()
-
+/obj/item/ammo_casing/energy/chrono_beam/Destroy()
+ gun = null
+ return ..()
diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm
index afd321b8a6f..7694e7c015d 100644
--- a/code/game/objects/items/devices/transfer_valve.dm
+++ b/code/game/objects/items/devices/transfer_valve.dm
@@ -16,6 +16,10 @@
var/valve_open = FALSE
var/toggle = TRUE
+/obj/item/transfer_valve/Destroy()
+ attached_device = null
+ return ..()
+
/obj/item/transfer_valve/IsAssemblyHolder()
return TRUE
diff --git a/code/game/objects/items/dice.dm b/code/game/objects/items/dice.dm
index 157aeb25567..7043741244d 100644
--- a/code/game/objects/items/dice.dm
+++ b/code/game/objects/items/dice.dm
@@ -182,8 +182,10 @@
diceroll(user)
/obj/item/dice/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
- diceroll(thrownby)
- . = ..()
+ var/mob/thrown_by = thrownby?.resolve()
+ if(thrown_by)
+ diceroll(thrown_by)
+ return ..()
/obj/item/dice/proc/diceroll(mob/user)
result = roll(sides)
diff --git a/code/game/objects/items/implants/implant_track.dm b/code/game/objects/items/implants/implant_track.dm
index d0455905eb9..4370bf908b2 100644
--- a/code/game/objects/items/implants/implant_track.dm
+++ b/code/game/objects/items/implants/implant_track.dm
@@ -2,8 +2,12 @@
name = "tracking implant"
desc = "Track with this."
activated = FALSE
- var/lifespan_postmortem = 6000 //for how many deciseconds after user death will the implant work?
- var/allow_teleport = TRUE //will people implanted with this act as teleporter beacons?
+ ///for how many deciseconds after user death will the implant work?
+ var/lifespan_postmortem = 6000
+ ///will people implanted with this act as teleporter beacons?
+ var/allow_teleport = TRUE
+ ///The id of the timer that's qdeleting us
+ var/timerid
/obj/item/implant/tracking/c38
name = "TRAC implant"
@@ -13,7 +17,11 @@
/obj/item/implant/tracking/c38/Initialize()
. = ..()
- QDEL_IN(src, lifespan)
+ timerid = QDEL_IN(src, lifespan)
+
+/obj/item/implant/tracking/c38/Destroy()
+ deltimer(timerid)
+ return ..()
/obj/item/implant/tracking/New()
..()
diff --git a/code/game/objects/items/melee/energy.dm b/code/game/objects/items/melee/energy.dm
index c3a4800ad23..59e5a51472b 100644
--- a/code/game/objects/items/melee/energy.dm
+++ b/code/game/objects/items/melee/energy.dm
@@ -267,6 +267,10 @@
spark_system.set_up(5, 0, src)
spark_system.attach(src)
+/obj/item/melee/transforming/energy/blade/Destroy()
+ QDEL_NULL(spark_system)
+ return ..()
+
/obj/item/melee/transforming/energy/blade/transform_weapon(mob/living/user, supress_message_text)
return
diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm
index 616a05bdd29..1805f2d146e 100644
--- a/code/game/objects/items/melee/misc.dm
+++ b/code/game/objects/items/melee/misc.dm
@@ -316,7 +316,7 @@
if(!iscarbon(user))
target.LAssailant = null
else
- target.LAssailant = user
+ target.LAssailant = WEAKREF(user)
cooldown_check = world.time + cooldown
else
var/wait_desc = get_wait_description()
diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm
index bf2498090d6..cf50599462a 100644
--- a/code/game/objects/structures/tables_racks.dm
+++ b/code/game/objects/structures/tables_racks.dm
@@ -494,7 +494,7 @@
/obj/structure/table/optable/Initialize()
. = ..()
for(var/direction in GLOB.cardinals)
- computer = locate(/obj/machinery/computer/operating, get_step(src, direction))
+ computer = locate(/obj/machinery/computer/operating) in get_step(src, direction)
if(computer)
computer.table = src
break
@@ -508,17 +508,34 @@
pushed_mob.forceMove(loc)
pushed_mob.set_resting(TRUE, TRUE)
visible_message("[user] has laid [pushed_mob] on [src].")
- check_patient()
+ get_patient()
-/obj/structure/table/optable/proc/check_patient()
- var/mob/living/carbon/human/M = locate(/mob/living/carbon/human, loc)
+/obj/structure/table/optable/proc/get_patient()
+ var/mob/living/carbon/M = locate(/mob/living/carbon) in loc
if(M)
if(M.resting)
- patient = M
- return TRUE
+ set_patient(M)
else
- patient = null
+ set_patient(null)
+
+/obj/structure/table/optable/proc/set_patient(new_patient)
+ if(patient)
+ UnregisterSignal(patient, COMSIG_PARENT_QDELETING)
+ patient = new_patient
+ if(patient)
+ RegisterSignal(patient, COMSIG_PARENT_QDELETING, .proc/patient_deleted)
+
+/obj/structure/table/optable/proc/patient_deleted(datum/source)
+ SIGNAL_HANDLER
+ set_patient(null)
+
+/obj/structure/table/optable/proc/check_eligible_patient()
+ get_patient()
+ if(!patient)
return FALSE
+ if(ishuman(patient) || ismonkey(patient))
+ return TRUE
+ return FALSE
/*
* Racks
diff --git a/code/game/objects/structures/traps.dm b/code/game/objects/structures/traps.dm
index 2c209ead993..18b795196bf 100644
--- a/code/game/objects/structures/traps.dm
+++ b/code/game/objects/structures/traps.dm
@@ -108,6 +108,12 @@
time_between_triggers = 10
flare_message = "[src] snaps shut!"
+/obj/structure/trap/stun/hunter/Destroy()
+ if(!QDELETED(stored_item))
+ qdel(stored_item)
+ stored_item = null
+ return ..()
+
/obj/structure/trap/stun/hunter/Crossed(atom/movable/AM)
if(isliving(AM))
var/mob/living/L = AM
@@ -161,7 +167,9 @@
forceMove(stored_trap)//moves item into trap
/obj/item/bountytrap/Destroy()
- qdel(stored_trap)
+ if(!QDELETED(stored_trap))
+ qdel(stored_trap)
+ stored_trap = null
QDEL_NULL(radio)
QDEL_NULL(spark_system)
. = ..()
diff --git a/code/modules/antagonists/abductor/equipment/gland.dm b/code/modules/antagonists/abductor/equipment/gland.dm
index 9f7fc96c4d8..cbda7198281 100644
--- a/code/modules/antagonists/abductor/equipment/gland.dm
+++ b/code/modules/antagonists/abductor/equipment/gland.dm
@@ -145,8 +145,8 @@
owner.vomit(20)
var/mob/living/simple_animal/slime/Slime = new(get_turf(owner), "grey")
- Slime.Friends = list(owner)
- Slime.Leader = owner
+ Slime.set_friends(list(owner))
+ Slime.set_leader(owner)
/obj/item/organ/heart/gland/mindshock
true_name = "neural crosstalk uninhibitor"
diff --git a/code/modules/antagonists/blob/blobstrains/_blobstrain.dm b/code/modules/antagonists/blob/blobstrains/_blobstrain.dm
index faf4a22f08e..34b82011cd1 100644
--- a/code/modules/antagonists/blob/blobstrains/_blobstrain.dm
+++ b/code/modules/antagonists/blob/blobstrains/_blobstrain.dm
@@ -22,6 +22,10 @@ GLOBAL_LIST_INIT(valid_blobstrains, subtypesof(/datum/blobstrain) - list(/datum/
stack_trace("blobstrain created without overmind")
overmind = new_overmind
+/datum/blobstrain/Destroy()
+ overmind = null
+ return ..()
+
/datum/blobstrain/proc/on_gain()
overmind.color = complementary_color
for(var/BL in GLOB.blobs)
diff --git a/code/modules/antagonists/blob/overmind.dm b/code/modules/antagonists/blob/overmind.dm
index b77644cd062..b728b2877e8 100644
--- a/code/modules/antagonists/blob/overmind.dm
+++ b/code/modules/antagonists/blob/overmind.dm
@@ -174,6 +174,7 @@ GLOBAL_LIST_EMPTY(blob_nodes)
SSticker.force_ending = 1
/mob/camera/blob/Destroy()
+ QDEL_NULL(blobstrain)
for(var/BL in GLOB.blobs)
var/obj/structure/blob/B = BL
if(B && B.overmind == src)
diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm
index b9ed924c557..417bacb66ee 100644
--- a/code/modules/antagonists/cult/cult_items.dm
+++ b/code/modules/antagonists/cult/cult_items.dm
@@ -117,7 +117,16 @@
linked_action = new(src)
AddComponent(/datum/component/butchering, 50, 80)
+<<<<<<< HEAD
/obj/item/twohanded/required/cult_bastard/examine(mob/user)
+=======
+/obj/item/cult_bastard/Destroy()
+ QDEL_NULL(jaunt)
+ QDEL_NULL(linked_action)
+ return ..()
+
+/obj/item/cult_bastard/examine(mob/user)
+>>>>>>> e260143132 (Port harddel fixes, as well as "Fixes stasis bed runtimes" (#4598))
. = ..()
if(contents.len)
. += "There are [contents.len] souls trapped within the sword's core."
@@ -194,7 +203,7 @@
phaseout = /obj/effect/temp_visual/dir_setting/cult/phase/out
/datum/action/innate/dash/cult/IsAvailable()
- if(iscultist(holder) && current_charges)
+ if(iscultist(owner) && current_charges)
return TRUE
else
return FALSE
diff --git a/code/modules/antagonists/disease/disease_disease.dm b/code/modules/antagonists/disease/disease_disease.dm
index 2909aac4d37..c9d976d6766 100644
--- a/code/modules/antagonists/disease/disease_disease.dm
+++ b/code/modules/antagonists/disease/disease_disease.dm
@@ -13,6 +13,7 @@
/datum/disease/advance/sentient_disease/Destroy()
. = ..()
+ overmind = null
GLOB.sentient_disease_instances -= src
/datum/disease/advance/sentient_disease/remove_disease()
diff --git a/code/modules/antagonists/disease/disease_mob.dm b/code/modules/antagonists/disease/disease_mob.dm
index 8c2e4ef1b0b..757c5b2cb93 100644
--- a/code/modules/antagonists/disease/disease_mob.dm
+++ b/code/modules/antagonists/disease/disease_mob.dm
@@ -73,10 +73,12 @@ the new instance inside the host to be updated to the template's stats.
/mob/camera/disease/Destroy()
. = ..()
QDEL_NULL(adaptation_menu_action)
+ disease_template = null
for(var/V in GLOB.sentient_disease_instances)
var/datum/disease/advance/sentient_disease/S = V
if(S.overmind == src)
S.overmind = null
+ browser = null
/mob/camera/disease/Login()
..()
diff --git a/code/modules/antagonists/slaughter/slaughter.dm b/code/modules/antagonists/slaughter/slaughter.dm
index 1fcf3956e1a..cdd47e9a4f7 100644
--- a/code/modules/antagonists/slaughter/slaughter.dm
+++ b/code/modules/antagonists/slaughter/slaughter.dm
@@ -49,7 +49,7 @@
deathmessage = "screams in anger as it collapses into a puddle of viscera!"
/mob/living/simple_animal/slaughter/Initialize()
- ..()
+ . = ..()
var/obj/effect/proc_holder/spell/bloodcrawl/bloodspell = new
AddSpell(bloodspell)
if(istype(loc, /obj/effect/dummy/phased_mob/slaughter))
diff --git a/code/modules/assembly/assembly.dm b/code/modules/assembly/assembly.dm
index 730e47b39af..a6ad3c3f10b 100644
--- a/code/modules/assembly/assembly.dm
+++ b/code/modules/assembly/assembly.dm
@@ -29,6 +29,10 @@
var/next_activate = 0 //When we're next allowed to activate - for spam control
var/activate_delay = 30
+/obj/item/assembly/Destroy()
+ holder = null
+ return ..()
+
/obj/item/assembly/get_part_rating()
return 1
diff --git a/code/modules/assembly/flash.dm b/code/modules/assembly/flash.dm
index 9ce9f93682b..053cb0d9ccd 100644
--- a/code/modules/assembly/flash.dm
+++ b/code/modules/assembly/flash.dm
@@ -336,19 +336,22 @@
desc = "A high-powered photon projector implant normally used for lighting purposes, but also doubles as a flashbulb weapon. Self-repair protocols fix the flashbulb if it ever burns out."
var/flashcd = 20
var/overheat = 0
- var/obj/item/organ/cyberimp/arm/flash/I = null
+ //Wearef to our arm
+ var/datum/weakref/arm
/obj/item/assembly/flash/armimplant/burn_out()
- if(I?.owner)
- to_chat(I.owner, "Your photon projector implant overheats and deactivates!")
- I.Retract()
+ var/obj/item/organ/cyberimp/arm/flash/real_arm = arm.resolve()
+ if(real_arm?.owner)
+ to_chat(real_arm.owner, "Your photon projector implant overheats and deactivates!")
+ real_arm.Retract()
overheat = TRUE
addtimer(CALLBACK(src, .proc/cooldown), flashcd * 2)
/obj/item/assembly/flash/armimplant/try_use_flash(mob/user = null)
if(overheat)
- if(I?.owner)
- to_chat(I.owner, "Your photon projector is running too hot to be used again so quickly!")
+ var/obj/item/organ/cyberimp/arm/flash/real_arm = arm.resolve()
+ if(real_arm?.owner)
+ to_chat(real_arm.owner, "Your photon projector is running too hot to be used again so quickly!")
return FALSE
overheat = TRUE
addtimer(CALLBACK(src, .proc/cooldown), flashcd)
diff --git a/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm b/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm
index 1f6fa821752..5eb7c439d92 100644
--- a/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm
+++ b/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm
@@ -24,11 +24,11 @@
return 1
/obj/machinery/portable_atmospherics/Destroy()
- SSair.atmos_machinery -= src
-
disconnect()
qdel(air_contents)
air_contents = null
+
+ SSair.atmos_machinery -= src
return ..()
diff --git a/code/modules/awaymissions/capture_the_flag.dm b/code/modules/awaymissions/capture_the_flag.dm
index 53786b3f663..24d99faa023 100644
--- a/code/modules/awaymissions/capture_the_flag.dm
+++ b/code/modules/awaymissions/capture_the_flag.dm
@@ -39,12 +39,16 @@
. = ..()
if(!reset)
reset = new reset_path(get_turf(src))
+ reset.flag = src
/obj/item/twohanded/ctf/process()
if(is_ctf_target(loc)) //don't reset from someone's hands.
return PROCESS_KILL
if(world.time > reset_cooldown)
- forceMove(get_turf(src.reset))
+ var/turf/our_turf = get_turf(src.reset)
+ if(!our_turf)
+ return TRUE
+ forceMove(our_turf)
for(var/mob/M in GLOB.player_list)
var/area/mob_area = get_area(M)
if(istype(mob_area, /area/ctf))
@@ -112,6 +116,13 @@
icon_state = "banner"
desc = "This is where a banner with Nanotrasen's logo on it would go."
layer = LOW_ITEM_LAYER
+ var/obj/item/ctf/flag
+
+/obj/effect/ctf/flag_reset/Destroy()
+ if(flag)
+ flag.reset = null
+ flag = null
+ return ..()
/obj/effect/ctf/flag_reset/red
name = "red flag landmark"
@@ -643,6 +654,13 @@
for(var/obj/machinery/capture_the_flag/CTF in GLOB.machines)
CTF.dead_barricades += src
+/obj/effect/ctf/dead_barricade/Destroy()
+ for(var/obj/machinery/capture_the_flag/CTF in GLOB.machines)
+ //if(CTF.game_id != game_id)
+ // continue
+ CTF.dead_barricades -= src
+ return ..()
+
/obj/effect/ctf/dead_barricade/proc/respawn()
if(!QDELETED(src))
new /obj/structure/barricade/security/ctf(get_turf(src))
diff --git a/code/modules/awaymissions/mission_code/Cabin.dm b/code/modules/awaymissions/mission_code/Cabin.dm
index 0c14d884c8c..c9ba3a6897a 100644
--- a/code/modules/awaymissions/mission_code/Cabin.dm
+++ b/code/modules/awaymissions/mission_code/Cabin.dm
@@ -45,7 +45,7 @@
var/active = 1
/obj/structure/firepit/Initialize()
- ..()
+ . = ..()
toggleFirepit()
/obj/structure/firepit/interact(mob/living/user)
diff --git a/code/modules/awaymissions/mission_code/TheFactory.dm b/code/modules/awaymissions/mission_code/TheFactory.dm
index dee081baacb..1e8f9a6a734 100644
--- a/code/modules/awaymissions/mission_code/TheFactory.dm
+++ b/code/modules/awaymissions/mission_code/TheFactory.dm
@@ -222,7 +222,7 @@
/mob/living/simple_animal/hostile/proc/summon_backup_nosound(distance, exact_faction_match)
do_alert_animation(src)
- for(var/mob/living/simple_animal/hostile/M in oview(distance, targets_from))
+ for(var/mob/living/simple_animal/hostile/M in oview(distance, GET_TARGETS_FROM(src)))
if(faction_check_mob(M, TRUE))
if(M.AIStatus == AI_OFF)
return
diff --git a/code/modules/cargo/supplypod.dm b/code/modules/cargo/supplypod.dm
index 4c0e03eb4fc..272edbfdc9b 100644
--- a/code/modules/cargo/supplypod.dm
+++ b/code/modules/cargo/supplypod.dm
@@ -463,17 +463,19 @@
return
glow_effect.layer = LOW_ITEM_LAYER
glow_effect.fadeAway(delays[POD_OPENING])
- remove_glow()
+ //Trust the signals
/obj/structure/closet/supplypod/proc/remove_glow()
SIGNAL_HANDLER
UnregisterSignal(glow_effect, COMSIG_PARENT_QDELETING)
+ vis_contents -= glow_effect
glow_effect = null
/obj/structure/closet/supplypod/Destroy()
open_pod(src, broken = TRUE) //Lets dump our contents by opening up
deleteRubble()
- endGlow()
+ //Trust the signals even harder
+ qdel(glow_effect)
return ..()
//------------------------------------TEMPORARY_VISUAL-------------------------------------//
diff --git a/code/modules/client/verbs/suicide.dm b/code/modules/client/verbs/suicide.dm
index 5af546dfce8..c2943b1c67c 100644
--- a/code/modules/client/verbs/suicide.dm
+++ b/code/modules/client/verbs/suicide.dm
@@ -3,9 +3,9 @@
/mob/proc/set_suicide(suicide_state)
suiciding = suicide_state
if(suicide_state)
- GLOB.suicided_mob_list += src
+ add_to_mob_suicide_list()
else
- GLOB.suicided_mob_list -= src
+ remove_from_mob_suicide_list()
/mob/living/carbon/set_suicide(suicide_state) //you thought that box trick was pretty clever, didn't you? well now hardmode is on, boyo.
. = ..()
diff --git a/code/modules/clothing/head/misc.dm b/code/modules/clothing/head/misc.dm
index 39492b0f40c..1f531b36242 100644
--- a/code/modules/clothing/head/misc.dm
+++ b/code/modules/clothing/head/misc.dm
@@ -142,7 +142,7 @@
if(!ishuman(user))
return
var/mob/living/carbon/human/H = user
- if(H.get_item_by_slot(ITEM_SLOT_HEAD) == src)
+ if(H.get_item_by_slot(ITEM_SLOT_HEAD) == src && !QDELETED(src)) //This can be called as a part of destroy
user.remove_language(/datum/language/piratespeak/, TRUE, TRUE, LANGUAGE_HAT)
to_chat(user, "You can no longer speak like a pirate.")
diff --git a/code/modules/clothing/masks/gasmask.dm b/code/modules/clothing/masks/gasmask.dm
index 4a32564d9b6..7ecd65228bd 100644
--- a/code/modules/clothing/masks/gasmask.dm
+++ b/code/modules/clothing/masks/gasmask.dm
@@ -34,7 +34,7 @@
/obj/item/clothing/mask/gas/welding/up
/obj/item/clothing/mask/gas/welding/up/Initialize()
- ..()
+ . = ..()
visor_toggling()
// ********************************************************************
diff --git a/code/modules/clothing/spacesuits/chronosuit.dm b/code/modules/clothing/spacesuits/chronosuit.dm
index 0d62c611818..d295e6dca48 100644
--- a/code/modules/clothing/spacesuits/chronosuit.dm
+++ b/code/modules/clothing/spacesuits/chronosuit.dm
@@ -65,6 +65,7 @@
/obj/item/clothing/suit/space/chronos/Destroy()
dropped()
+ QDEL_NULL(teleport_now)
return ..()
/obj/item/clothing/suit/space/chronos/emp_act(severity)
@@ -328,6 +329,10 @@
check_flags = AB_CHECK_CONSCIOUS //|AB_CHECK_INSIDE
var/obj/item/clothing/suit/space/chronos/chronosuit = null
+/datum/action/innate/chrono_teleport/Destroy()
+ chronosuit = null
+ return ..()
+
/datum/action/innate/chrono_teleport/IsAvailable()
return (chronosuit && chronosuit.activated && chronosuit.camera && !chronosuit.teleporting)
diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm
index 306866ad04c..d6317ca1e32 100644
--- a/code/modules/clothing/spacesuits/hardsuit.dm
+++ b/code/modules/clothing/spacesuits/hardsuit.dm
@@ -27,6 +27,9 @@
START_PROCESSING(SSobj, src)
/obj/item/clothing/head/helmet/space/hardsuit/Destroy()
+ if(!QDELETED(suit))
+ qdel(suit)
+ suit = null
QDEL_NULL(soundloop)
STOP_PROCESSING(SSobj, src)
return ..()
@@ -110,7 +113,6 @@
var/obj/item/tank/jetpack/suit/jetpack = null
pocket_storage_component_path = null
-
/obj/item/clothing/suit/space/hardsuit/Initialize()
if(jetpack && ispath(jetpack))
jetpack = new jetpack(src)
@@ -878,6 +880,7 @@
/datum/action/item_action/toggle_beacon,
/datum/action/item_action/toggle_beacon_frequency
)
+ jetpack = /obj/item/tank/jetpack/suit
/obj/item/clothing/suit/space/hardsuit/shielded/syndi/multitool_act(mob/living/user, obj/item/I)
. = ..()
@@ -896,10 +899,6 @@
to_chat(user, "You update the hardsuit's hardware, changing back the shield's color to red.")
user.update_inv_wear_suit()
-/obj/item/clothing/suit/space/hardsuit/shielded/syndi/Initialize()
- jetpack = new /obj/item/tank/jetpack/suit(src)
- . = ..()
-
/obj/item/clothing/suit/space/hardsuit/shielded/syndi/ui_action_click(mob/user, datum/actiontype)
switch(actiontype.type)
if(/datum/action/item_action/toggle_helmet)
diff --git a/code/modules/clothing/suits/toggles.dm b/code/modules/clothing/suits/toggles.dm
index dd7608adbc8..39f2dcfb647 100644
--- a/code/modules/clothing/suits/toggles.dm
+++ b/code/modules/clothing/suits/toggles.dm
@@ -130,10 +130,11 @@
. = ..()
/obj/item/clothing/suit/space/hardsuit/Destroy()
- if(helmet)
+ if(!QDELETED(helmet))
helmet.suit = null
qdel(helmet)
- qdel(jetpack)
+ helmet = null
+ QDEL_NULL(jetpack)
return ..()
/obj/item/clothing/head/helmet/space/hardsuit/Destroy()
diff --git a/code/modules/clothing/under/accessories.dm b/code/modules/clothing/under/accessories.dm
index 8ce36829cbd..137518c9a56 100755
--- a/code/modules/clothing/under/accessories.dm
+++ b/code/modules/clothing/under/accessories.dm
@@ -12,6 +12,10 @@
var/datum/component/storage/detached_pockets
var/attachment_slot = CHEST
+/obj/item/clothing/accessory/Destroy()
+ set_detached_pockets(null)
+ return ..()
+
/obj/item/clothing/accessory/proc/can_attach_accessory(obj/item/clothing/U, mob/user)
if(!attachment_slot || (U && U.body_parts_covered & attachment_slot))
return TRUE
@@ -24,7 +28,7 @@
if(SEND_SIGNAL(U, COMSIG_CONTAINS_STORAGE))
return FALSE
U.TakeComponent(storage)
- detached_pockets = storage
+ set_detached_pockets(storage)
U.attached_accessory = src
forceMove(U)
layer = FLOAT_LAYER
@@ -67,6 +71,17 @@
U.attached_accessory = null
U.accessory_overlay = null
+/obj/item/clothing/accessory/proc/set_detached_pockets(new_pocket)
+ if(detached_pockets)
+ UnregisterSignal(detached_pockets, COMSIG_PARENT_QDELETING)
+ detached_pockets = new_pocket
+ if(detached_pockets)
+ RegisterSignal(detached_pockets, COMSIG_PARENT_QDELETING, .proc/handle_pockets_del)
+
+/obj/item/clothing/accessory/proc/handle_pockets_del(datum/source)
+ SIGNAL_HANDLER
+ set_detached_pockets(null)
+
/obj/item/clothing/accessory/proc/on_uniform_equip(obj/item/clothing/under/U, user)
return
diff --git a/code/modules/events/wizard/greentext.dm b/code/modules/events/wizard/greentext.dm
index 82e72df3b9d..569e026e7ac 100644
--- a/code/modules/events/wizard/greentext.dm
+++ b/code/modules/events/wizard/greentext.dm
@@ -83,7 +83,8 @@
if(!(resistance_flags & ON_FIRE) && !force)
return QDEL_HINT_LETMELIVE
- SSticker.round_end_events -= roundend_callback
+ LAZYREMOVE(SSticker.round_end_events, roundend_callback)
+ roundend_callback = null //This ought to free the callback datum, and prevent us from harddeling
GLOB.poi_list.Remove(src)
for(var/i in GLOB.player_list)
var/mob/M = i
diff --git a/code/modules/fields/timestop.dm b/code/modules/fields/timestop.dm
index bc5502438f9..9d410a43a0b 100644
--- a/code/modules/fields/timestop.dm
+++ b/code/modules/fields/timestop.dm
@@ -42,7 +42,7 @@
timestop()
/obj/effect/timestop/Destroy()
- qdel(chronofield)
+ QDEL_NULL(chronofield)
playsound(src, 'sound/magic/timeparadox2.ogg', 75, TRUE, frequency = -1) //reverse!
return ..()
diff --git a/code/modules/guardian/guardian.dm b/code/modules/guardian/guardian.dm
index 998aad3c529..1ae6ae323f0 100644
--- a/code/modules/guardian/guardian.dm
+++ b/code/modules/guardian/guardian.dm
@@ -342,9 +342,10 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
return loc != summoner?.current
/mob/living/simple_animal/hostile/guardian/Shoot(atom/targeted_atom)
- if( QDELETED(targeted_atom) || targeted_atom == targets_from.loc || targeted_atom == targets_from )
+ var/atom/target_from = GET_TARGETS_FROM(src)
+ if( QDELETED(targeted_atom) || targeted_atom == target_from.loc || targeted_atom == target_from )
return
- var/turf/startloc = get_turf(targets_from)
+ var/turf/startloc = get_turf(target_from)
var/obj/item/projectile/P = new /obj/item/projectile/guardian(startloc)
playsound(src, projectilesound, 100, 1)
P.color = guardiancolor
@@ -355,7 +356,7 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
P.yo = targeted_atom.y - startloc.y
P.xo = targeted_atom.x - startloc.x
if(AIStatus != AI_ON)//Don't want mindless mobs to have their movement screwed up firing in space
- newtonian_move(get_dir(targeted_atom, targets_from))
+ newtonian_move(get_dir(targeted_atom, target_from))
P.original = targeted_atom
P.preparePixelProjectile(targeted_atom, src)
P.fire()
diff --git a/code/modules/holodeck/holo_effect.dm b/code/modules/holodeck/holo_effect.dm
index 3161c9c7ec4..5e1f2109de3 100644
--- a/code/modules/holodeck/holo_effect.dm
+++ b/code/modules/holodeck/holo_effect.dm
@@ -28,31 +28,36 @@
/obj/effect/holodeck_effect/cards
icon = 'icons/obj/toy.dmi'
icon_state = "deck_nanotrasen_full"
- var/obj/item/toy/cards/deck/D
+ var/obj/item/toy/cards/deck/deck
/obj/effect/holodeck_effect/cards/activate(var/obj/machinery/computer/holodeck/HC)
- D = new(loc)
+ deck = new(loc)
safety(!(HC.obj_flags & EMAGGED))
- D.holo = HC
- return D
+ deck.holo = HC
+ RegisterSignal(deck, COMSIG_PARENT_QDELETING, .proc/handle_card_delete)
+ return deck
+
+/obj/effect/holodeck_effect/cards/proc/handle_card_delete(datum/source)
+ SIGNAL_HANDLER
+ deck = null
/obj/effect/holodeck_effect/cards/safety(active)
- if(!D)
+ if(!deck)
return
if(active)
- D.card_hitsound = null
- D.card_force = 0
- D.card_throwforce = 0
- D.card_throw_speed = 3
- D.card_throw_range = 7
- D.card_attack_verb = list("attacked")
+ deck.card_hitsound = null
+ deck.card_force = 0
+ deck.card_throwforce = 0
+ deck.card_throw_speed = 3
+ deck.card_throw_range = 7
+ deck.card_attack_verb = list("attacked")
else
- D.card_hitsound = 'sound/weapons/bladeslice.ogg'
- D.card_force = 5
- D.card_throwforce = 10
- D.card_throw_speed = 3
- D.card_throw_range = 7
- D.card_attack_verb = list("attacked", "sliced", "diced", "slashed", "cut")
+ deck.card_hitsound = 'sound/weapons/bladeslice.ogg'
+ deck.card_force = 5
+ deck.card_throwforce = 10
+ deck.card_throw_speed = 3
+ deck.card_throw_range = 7
+ deck.card_attack_verb = list("attacked", "sliced", "diced", "slashed", "cut")
/obj/effect/holodeck_effect/sparks/activate(var/obj/machinery/computer/holodeck/HC)
@@ -76,24 +81,29 @@
/obj/effect/holodeck_effect/mobspawner
var/mobtype = /mob/living/simple_animal/hostile/carp/holocarp
- var/mob/mob = null
+ var/mob/our_mob = null
/obj/effect/holodeck_effect/mobspawner/activate(var/obj/machinery/computer/holodeck/HC)
if(islist(mobtype))
mobtype = pick(mobtype)
- mob = new mobtype(loc)
- mob.flags_1 |= HOLOGRAM_1
+ our_mob = new mobtype(loc)
+ our_mob.flags_1 |= HOLOGRAM_1
// these vars are not really standardized but all would theoretically create stuff on death
- for(var/v in list("butcher_results","corpse","weapon1","weapon2","blood_volume") & mob.vars)
- mob.vars[v] = null
- return mob
+ for(var/v in list("butcher_results","corpse","weapon1","weapon2","blood_volume") & our_mob.vars)
+ our_mob.vars[v] = null
+ RegisterSignal(our_mob, COMSIG_PARENT_QDELETING, .proc/handle_mob_delete)
+ return our_mob
/obj/effect/holodeck_effect/mobspawner/deactivate(var/obj/machinery/computer/holodeck/HC)
- if(mob)
- HC.derez(mob)
+ if(our_mob)
+ HC.derez(our_mob)
qdel(src)
+/obj/effect/holodeck_effect/mobspawner/proc/handle_mob_delete(datum/source)
+ SIGNAL_HANDLER
+ our_mob = null
+
/obj/effect/holodeck_effect/mobspawner/pet
mobtype = list(
/mob/living/simple_animal/butterfly, /mob/living/simple_animal/chick/holo,
@@ -117,3 +127,24 @@
/obj/effect/holodeck_effect/mobspawner/penguin_baby
mobtype = /mob/living/simple_animal/pet/penguin/baby
+<<<<<<< HEAD
+=======
+
+/obj/effect/holodeck_effect/mobspawner/cat
+ mobtype = /mob/living/simple_animal/pet/cat
+
+/obj/effect/holodeck_effect/mobspawner/butterfly
+ mobtype = /mob/living/simple_animal/butterfly
+
+/obj/effect/holodeck_effect/mobspawner/clown
+ mobtype = list (/mob/living/simple_animal/hostile/retaliate/clown = 10,
+ /mob/living/simple_animal/hostile/retaliate/clown/banana = 6, /mob/living/simple_animal/hostile/retaliate/clown/honkling = 6,
+ /mob/living/simple_animal/hostile/retaliate/clown/fleshclown = 3, /mob/living/simple_animal/hostile/retaliate/clown/longface = 3,
+ /mob/living/simple_animal/hostile/retaliate/clown/mutant = 1, /mob/living/simple_animal/hostile/retaliate/clown/mutant/blob = 1)
+
+/obj/effect/holodeck_effect/mobspawner/psycho
+ mobtype = list (/mob/living/simple_animal/hostile/psycho/regular = 9,
+ /mob/living/simple_animal/hostile/psycho/muzzle = 3,
+ /mob/living/simple_animal/hostile/psycho/fast = 3,
+ /mob/living/simple_animal/hostile/psycho/trap = 1)
+>>>>>>> e260143132 (Port harddel fixes, as well as "Fixes stasis bed runtimes" (#4598))
diff --git a/code/modules/language/language_holder.dm b/code/modules/language/language_holder.dm
index 6485f34d61d..00b1013f4af 100644
--- a/code/modules/language/language_holder.dm
+++ b/code/modules/language/language_holder.dm
@@ -53,7 +53,9 @@ Key procs
var/atom/owner
/// Initializes, and copies in the languages from the current atom if available.
-/datum/language_holder/New(_owner)
+/datum/language_holder/New(atom/_owner)
+ if(_owner && QDELING(_owner))
+ CRASH("Langauge holder added to a qdeleting thing, what the fuck \ref[_owner]")
owner = _owner
if(istype(owner, /datum/mind))
var/datum/mind/M = owner
diff --git a/code/modules/lighting/lighting_source.dm b/code/modules/lighting/lighting_source.dm
index 24d757c6c47..d12a129e89f 100644
--- a/code/modules/lighting/lighting_source.dm
+++ b/code/modules/lighting/lighting_source.dm
@@ -67,7 +67,8 @@
source_atom = null
source_turf = null
pixel_turf = null
- . = ..()
+
+ return ..()
// Yes this doesn't align correctly on anything other than 4 width tabs.
// If you want it to go switch everybody to elastic tab stops.
diff --git a/code/modules/mining/laborcamp/laborstacker.dm b/code/modules/mining/laborcamp/laborstacker.dm
index d179ab9a943..85fdbf54e82 100644
--- a/code/modules/mining/laborcamp/laborstacker.dm
+++ b/code/modules/mining/laborcamp/laborstacker.dm
@@ -18,9 +18,12 @@ GLOBAL_LIST(labor_sheet_values)
/obj/machinery/mineral/labor_claim_console/Initialize()
. = ..()
- Radio = new/obj/item/radio(src)
+ Radio = new /obj/item/radio(src)
Radio.listening = FALSE
locate_stacking_machine()
+ //If we can't find a stacking machine end it all ok?
+ if(!stacking_machine)
+ return INITIALIZE_HINT_QDEL
if(!GLOB.labor_sheet_values)
var/sheet_list = list()
@@ -31,6 +34,13 @@ GLOBAL_LIST(labor_sheet_values)
sheet_list += list(list("ore" = initial(sheet.name), "value" = initial(sheet.point_value)))
GLOB.labor_sheet_values = sortList(sheet_list, /proc/cmp_sheet_list)
+/obj/machinery/mineral/labor_claim_console/Destroy()
+ QDEL_NULL(Radio)
+ if(stacking_machine)
+ stacking_machine.console = null
+ stacking_machine = null
+ return ..()
+
/proc/cmp_sheet_list(list/a, list/b)
return a["value"] - b["value"]
@@ -114,9 +124,7 @@ GLOBAL_LIST(labor_sheet_values)
/obj/machinery/mineral/labor_claim_console/proc/locate_stacking_machine()
stacking_machine = locate(/obj/machinery/mineral/stacking_machine, get_step(src, machinedir))
if(stacking_machine)
- stacking_machine.CONSOLE = src
- else
- qdel(src)
+ stacking_machine.console = src
/obj/machinery/mineral/labor_claim_console/emag_act(mob/user)
if(!(obj_flags & EMAGGED))
diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm
index 5a38b942a8a..2ac4f789b60 100644
--- a/code/modules/mining/lavaland/necropolis_chests.dm
+++ b/code/modules/mining/lavaland/necropolis_chests.dm
@@ -359,6 +359,12 @@
var/obj/item/warp_cube/linked
var/teleporting = FALSE
+/obj/item/warp_cube/Destroy()
+ if(!QDELETED(linked))
+ qdel(linked)
+ linked = null
+ return ..()
+
/obj/item/warp_cube/attack_self(mob/user)
if(!linked)
to_chat(user, "[src] fizzles uselessly.")
diff --git a/code/modules/mining/machine_stacking.dm b/code/modules/mining/machine_stacking.dm
index 51d6d9c3b43..47ae34b5fbc 100644
--- a/code/modules/mining/machine_stacking.dm
+++ b/code/modules/mining/machine_stacking.dm
@@ -14,7 +14,13 @@
. = ..()
machine = locate(/obj/machinery/mineral/stacking_machine, get_step(src, machinedir))
if (machine)
- machine.CONSOLE = src
+ machine.console = src
+
+/obj/machinery/mineral/stacking_unit_console/Destroy()
+ if(machine)
+ machine.console = null
+ machine = null
+ return ..()
/obj/machinery/mineral/stacking_unit_console/ui_interact(mob/user)
. = ..()
@@ -74,7 +80,7 @@
circuit = /obj/item/circuitboard/machine/stacking_machine
input_dir = EAST
output_dir = WEST
- var/obj/machinery/mineral/stacking_unit_console/CONSOLE
+ var/obj/machinery/mineral/stacking_unit_console/console
var/stk_types = list()
var/stk_amt = list()
var/stack_list[0] //Key: Type. Value: Instance of type.
@@ -88,7 +94,9 @@
materials = AddComponent(/datum/component/remote_materials, "stacking", mapload, FALSE, mapload && force_connect)
/obj/machinery/mineral/stacking_machine/Destroy()
- CONSOLE = null
+ if(console)
+ console.machine = null
+ console = null
materials = null
return ..()
@@ -108,8 +116,8 @@
/obj/machinery/mineral/stacking_machine/multitool_act(mob/living/user, obj/item/multitool/M)
if(istype(M))
if(istype(M.buffer, /obj/machinery/mineral/stacking_unit_console))
- CONSOLE = M.buffer
- CONSOLE.machine = src
+ console = M.buffer
+ console.machine = src
to_chat(user, "You link [src] to the console in [M]'s buffer.")
return TRUE
diff --git a/code/modules/mob/dead/new_player/login.dm b/code/modules/mob/dead/new_player/login.dm
index 734e5a59b03..97e97bb31e0 100644
--- a/code/modules/mob/dead/new_player/login.dm
+++ b/code/modules/mob/dead/new_player/login.dm
@@ -4,8 +4,8 @@
client.set_db_player_flags()
if(!mind)
mind = new /datum/mind(key)
- mind.active = 1
- mind.current = src
+ mind.active = TRUE
+ mind.set_current(src)
..()
diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm
index 921fe3cc853..72e3793fa11 100644
--- a/code/modules/mob/living/blood.dm
+++ b/code/modules/mob/living/blood.dm
@@ -166,7 +166,6 @@
if(blood_id == /datum/reagent/blood) //actual blood reagent
var/blood_data = list()
//set the blood data
- blood_data["donor"] = src
blood_data["viruses"] = list()
for(var/thing in diseases)
diff --git a/code/modules/mob/living/brain/brain.dm b/code/modules/mob/living/brain/brain.dm
index 37ff6bd4ffc..b570e906e81 100644
--- a/code/modules/mob/living/brain/brain.dm
+++ b/code/modules/mob/living/brain/brain.dm
@@ -29,9 +29,10 @@
if(stat!=DEAD) //If not dead.
death(1) //Brains can die again. AND THEY SHOULD AHA HA HA HA HA HA
if(mind) //You aren't allowed to return to brains that don't exist
- mind.current = null
+ mind.set_current(null)
ghostize() //Ghostize checks for key so nothing else is necessary.
container = null
+ QDEL_NULL(stored_dna)
return ..()
/mob/living/brain/update_mobility()
diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm
index b5c9a410906..fc9d3d22b8d 100644
--- a/code/modules/mob/living/brain/brain_item.dm
+++ b/code/modules/mob/living/brain/brain_item.dm
@@ -197,6 +197,9 @@
if(brainmob)
QDEL_NULL(brainmob)
QDEL_LIST(traumas)
+
+ if(owner?.mind) //You aren't allowed to return to brains that don't exist
+ owner.mind.set_current(null)
return ..()
/obj/item/organ/brain/on_life()
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 430a8ca967b..9ad68bdf4c4 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -41,6 +41,7 @@
/mob/living/carbon/human/Destroy()
QDEL_NULL(physiology)
+ QDEL_LIST(bioware)
return ..()
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 8236ae53904..e3b58e798e6 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -142,7 +142,7 @@
if(istype(AM, /obj/item))
I = AM
throwpower = I.throwforce
- if(I.thrownby == src) //No throwing stuff at yourself to trigger hit reactions
+ if(I.thrownby == WEAKREF(src)) //No throwing stuff at yourself to trigger hit reactions
return ..()
if(check_shields(AM, throwpower, "\the [AM.name]", THROWN_PROJECTILE_ATTACK))
hitpush = FALSE
diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm
index 4a32c7e3f10..f19ff833fa9 100644
--- a/code/modules/mob/living/carbon/human/species_types/golems.dm
+++ b/code/modules/mob/living/carbon/human/species_types/golems.dm
@@ -440,7 +440,7 @@
var/obj/item/I
if(istype(AM, /obj/item))
I = AM
- if(I.thrownby == H) //No throwing stuff at yourself to trigger the teleport
+ if(I.thrownby == WEAKREF(H)) //No throwing stuff at yourself to trigger the teleport
return 0
else
reactive_teleport(H)
@@ -564,7 +564,7 @@
var/obj/item/I
if(istype(AM, /obj/item))
I = AM
- if(I.thrownby == H) //No throwing stuff at yourself to make bananas
+ if(I.thrownby == WEAKREF(H)) //No throwing stuff at yourself to make bananas
return 0
else
new/obj/item/grown/bananapeel/specialpeel(get_turf(H))
diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
index 985f9ca02b2..d5d5955daaa 100644
--- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
@@ -414,18 +414,25 @@
var/datum/action/innate/use_extract/major/extract_major
var/extract_cooldown = 0
+//Species datums don't normally implement destroy, but JELLIES SUCK ASS OUT OF A STEEL STRAW
+/datum/species/jelly/luminescent/Destroy(force, ...)
+ current_extract = null
+ QDEL_NULL(glow)
+ QDEL_NULL(integrate_extract)
+ QDEL_NULL(extract_major)
+ QDEL_NULL(extract_minor)
+ return ..()
+
+
/datum/species/jelly/luminescent/on_species_loss(mob/living/carbon/C)
..()
if(current_extract)
current_extract.forceMove(C.drop_location())
current_extract = null
- qdel(glow)
- if(integrate_extract)
- integrate_extract.Remove(C)
- if(extract_minor)
- extract_minor.Remove(C)
- if(extract_major)
- extract_major.Remove(C)
+ QDEL_NULL(glow)
+ QDEL_NULL(integrate_extract)
+ QDEL_NULL(extract_major)
+ QDEL_NULL(extract_minor)
/datum/species/jelly/luminescent/on_species_gain(mob/living/carbon/C, datum/species/old_species)
..()
@@ -468,13 +475,9 @@
button_icon_state = "slimeconsume"
icon_icon = 'icons/mob/actions/actions_slime.dmi'
background_icon_state = "bg_alien"
- var/datum/species/jelly/luminescent/species
-
-/datum/action/innate/integrate_extract/New(_species)
- ..()
- species = _species
/datum/action/innate/integrate_extract/proc/update_name()
+ var/datum/species/jelly/luminescent/species = target
if(!species || !species.current_extract)
name = "Integrate Extract"
desc = "Eat a slime extract to use its properties."
@@ -483,6 +486,7 @@
desc = "Eject your current slime extract."
/datum/action/innate/integrate_extract/UpdateButtonIcon(status_only, force)
+ var/datum/species/jelly/luminescent/species = target
if(!species || !species.current_extract)
button_icon_state = "slimeconsume"
else
@@ -491,11 +495,13 @@
/datum/action/innate/integrate_extract/ApplyIcon(atom/movable/screen/movable/action_button/current_button, force)
..(current_button, TRUE)
+ var/datum/species/jelly/luminescent/species = target
if(species?.current_extract)
current_button.add_overlay(mutable_appearance(species.current_extract.icon, species.current_extract.icon_state))
/datum/action/innate/integrate_extract/Activate()
var/mob/living/carbon/human/H = owner
+ var/datum/species/jelly/luminescent/species = target
if(!is_species(H, /datum/species/jelly/luminescent) || !species)
return
CHECK_DNA_AND_SPECIES(H)
@@ -531,25 +537,23 @@
icon_icon = 'icons/mob/actions/actions_slime.dmi'
background_icon_state = "bg_alien"
var/activation_type = SLIME_ACTIVATE_MINOR
- var/datum/species/jelly/luminescent/species
-
-/datum/action/innate/use_extract/New(_species)
- ..()
- species = _species
/datum/action/innate/use_extract/IsAvailable()
if(..())
+ var/datum/species/jelly/luminescent/species = target
if(species && species.current_extract && (world.time > species.extract_cooldown))
return TRUE
return FALSE
/datum/action/innate/use_extract/ApplyIcon(atom/movable/screen/movable/action_button/current_button, force)
..(current_button, TRUE)
+ var/datum/species/jelly/luminescent/species = owner
if(species && species.current_extract)
current_button.add_overlay(mutable_appearance(species.current_extract.icon, species.current_extract.icon_state))
/datum/action/innate/use_extract/Activate()
var/mob/living/carbon/human/H = owner
+ var/datum/species/jelly/luminescent/species = owner
if(!is_species(H, /datum/species/jelly/luminescent) || !species)
return
CHECK_DNA_AND_SPECIES(H)
@@ -576,22 +580,33 @@
var/datum/action/innate/link_minds/link_minds
var/list/mob/living/linked_mobs = list()
var/list/datum/action/innate/linked_speech/linked_actions = list()
- var/mob/living/carbon/human/slimelink_owner
+ var/datum/weakref/slimelink_owner
var/current_link_id = 0
+//Species datums don't normally implement destroy, but JELLIES SUCK ASS OUT OF A STEEL STRAW
+/datum/species/jelly/stargazer/Destroy()
+ for(var/mob/living/link_to_clear as anything in linked_mobs)
+ unlink_mob(link_to_clear)
+ linked_mobs.Cut()
+ QDEL_NULL(project_thought)
+ QDEL_NULL(link_minds)
+ slimelink_owner = null
+ return ..()
+
/datum/species/jelly/stargazer/on_species_loss(mob/living/carbon/C)
..()
- for(var/M in linked_mobs)
- unlink_mob(M)
+ for(var/mob/living/link_to_clear as anything in linked_mobs)
+ unlink_mob(link_to_clear)
if(project_thought)
- project_thought.Remove(C)
+ QDEL_NULL(project_thought)
if(link_minds)
- link_minds.Remove(C)
+ QDEL_NULL(link_minds)
+ slimelink_owner = null
/datum/species/jelly/stargazer/spec_death(gibbed, mob/living/carbon/human/H)
..()
- for(var/M in linked_mobs)
- unlink_mob(M)
+ for(var/mob/living/link_to_clear as anything in linked_mobs)
+ unlink_mob(link_to_clear)
/datum/species/jelly/stargazer/on_species_gain(mob/living/carbon/C, datum/species/old_species)
..()
@@ -599,7 +614,7 @@
project_thought.Grant(C)
link_minds = new(src)
link_minds.Grant(C)
- slimelink_owner = C
+ slimelink_owner = WEAKREF(C)
link_mob(C)
/datum/species/jelly/stargazer/proc/link_mob(mob/living/M)
@@ -607,14 +622,18 @@
return FALSE
if(HAS_TRAIT(M, TRAIT_MINDSHIELD)) //mindshield implant, no dice
return FALSE
+ var/mob/living/carbon/human/owner = slimelink_owner.resolve()
if(istype(M.get_item_by_slot(ITEM_SLOT_HEAD), /obj/item/clothing/head/foilhat))
- to_chat(M, "[slimelink_owner.real_name]'s no-good syndicate mind-slime is blocked by your protective headgear!")
+ if(owner)
+ to_chat(M, "[owner.real_name]'s no-good syndicate mind-slime is blocked by your protective headgear!")
return FALSE
if(M in linked_mobs)
return FALSE
+ if(!owner)
+ return FALSE
linked_mobs.Add(M)
- to_chat(M, "You are now connected to [slimelink_owner.real_name]'s Slime Link.")
+ to_chat(M, "You are now connected to [owner.real_name]'s Slime Link.")
var/datum/action/innate/linked_speech/action = new(src)
linked_actions.Add(action)
action.Grant(M)
@@ -626,9 +645,12 @@
return
var/datum/action/innate/linked_speech/action = linked_actions[link_id]
action.Remove(M)
- to_chat(M, "You are no longer connected to [slimelink_owner.real_name]'s Slime Link.")
+ var/mob/living/carbon/human/owner = slimelink_owner.resolve()
+ if(owner)
+ to_chat(M, "You are no longer connected to [owner.real_name]'s Slime Link.")
linked_mobs -= M
linked_actions -= action
+ qdel(action)
/datum/action/innate/linked_speech
name = "Slimelink"
@@ -636,14 +658,10 @@
button_icon_state = "link_speech"
icon_icon = 'icons/mob/actions/actions_slime.dmi'
background_icon_state = "bg_alien"
- var/datum/species/jelly/stargazer/species
-
-/datum/action/innate/linked_speech/New(_species)
- ..()
- species = _species
/datum/action/innate/linked_speech/Activate()
var/mob/living/carbon/human/H = owner
+ var/datum/species/jelly/stargazer/species = target
if(!species || !(H in species.linked_mobs))
to_chat(H, "The link seems to have been severed...")
Remove(H)
@@ -660,9 +678,11 @@
species.unlink_mob(H)
return
- if(message)
- var/msg = "\[[species.slimelink_owner.real_name]'s Slime Link\] [H]: [message]"
- log_directed_talk(H, species.slimelink_owner, msg, LOG_SAY, "slime link")
+ var/mob/living/carbon/human/star_owner = species.slimelink_owner.resolve()
+
+ if(message && star_owner)
+ var/msg = "\[[star_owner.real_name]'s Slime Link\] [H]: [message]"
+ log_directed_talk(H, star_owner, msg, LOG_SAY, "slime link")
for(var/X in species.linked_mobs)
var/mob/living/M = X
if(QDELETED(M) || M.stat == DEAD)
@@ -715,11 +735,6 @@
button_icon_state = "mindlink"
icon_icon = 'icons/mob/actions/actions_slime.dmi'
background_icon_state = "bg_alien"
- var/datum/species/jelly/stargazer/species
-
-/datum/action/innate/link_minds/New(_species)
- ..()
- species = _species
/datum/action/innate/link_minds/Activate()
var/mob/living/carbon/human/H = owner
@@ -732,6 +747,7 @@
return
var/mob/living/target = H.pulling
+ var/datum/species/jelly/stargazer/species = target
to_chat(H, "You begin linking [target]'s mind to yours...")
to_chat(target, "You feel a foreign presence within your mind...")
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 5c4373a4d2a..644abbad204 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -307,7 +307,7 @@
if(!iscarbon(src))
M.LAssailant = null
else
- M.LAssailant = usr
+ M.LAssailant = WEAKREF(usr)
if(isliving(M))
var/mob/living/L = M
//Share diseases that are spread by touch
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index abce98f4b03..ef4c4893c3d 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -94,8 +94,9 @@
"You're hit by [I]!")
var/armor = run_armor_check(zone, "melee", "Your armor has protected your [parse_zone(zone)].", "Your armor has softened hit to your [parse_zone(zone)].",I.armour_penetration)
apply_damage(I.throwforce, dtype, zone, armor)
- if(I.thrownby)
- log_combat(I.thrownby, src, "threw and hit", I)
+ var/mob/thrown_by = I.thrownby?.resolve()
+ if(thrown_by)
+ log_combat(thrown_by, src, "threw and hit", I)
else
return 1
else
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 218ac4e3adc..ef8c5c083b7 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -440,9 +440,11 @@
trackeable += track.humans + track.others
var/list/target = list()
for(var/I in trackeable)
- var/mob/M = trackeable[I]
- if(M.name == string)
- target += M
+ var/datum/weakref/to_resolve = trackeable[I]
+ var/mob/to_track = to_resolve.resolve()
+ if(!to_track || to_track.name != string)
+ continue
+ target += to_track
if(name == string)
target += src
if(target.len)
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 6da4b714648..f1c7fcc87ff 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -190,12 +190,12 @@
if(T && istype(radio) && istype(radio.keyslot))
radio.keyslot.forceMove(T)
radio.keyslot = null
- qdel(wires)
- qdel(module)
- qdel(eye_lights)
- wires = null
- module = null
- eye_lights = null
+ QDEL_NULL(wires)
+ QDEL_NULL(eye_lights)
+ QDEL_NULL(inv1)
+ QDEL_NULL(inv2)
+ QDEL_NULL(inv3)
+ QDEL_NULL(spark_system)
cell = null
return ..()
diff --git a/code/modules/mob/living/simple_animal/bot/honkbot.dm b/code/modules/mob/living/simple_animal/bot/honkbot.dm
index 1f5305e617b..73bd2b58831 100644
--- a/code/modules/mob/living/simple_animal/bot/honkbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/honkbot.dm
@@ -159,8 +159,9 @@ Maintenance panel panel is [open ? "opened" : "closed"]"},
if(istype(AM, /obj/item))
playsound(src, honksound, 50, TRUE, -1)
var/obj/item/I = AM
- if(I.throwforce < health && I.thrownby && (istype(I.thrownby, /mob/living/carbon/human)))
- var/mob/living/carbon/human/H = I.thrownby
+ var/mob/thrown_by = I.thrownby?.resolve()
+ if(I.throwforce < health && thrown_by && (istype(thrown_by, /mob/living/carbon/human)))
+ var/mob/living/carbon/human/H = thrown_by
retaliate(H)
..()
diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm
index 2970f3da114..cbb130e619a 100644
--- a/code/modules/mob/living/simple_animal/bot/secbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/secbot.dm
@@ -223,8 +223,9 @@ Auto Patrol: []"},
/mob/living/simple_animal/bot/secbot/hitby(atom/movable/AM, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
if(istype(AM, /obj/item))
var/obj/item/I = AM
- if(I.throwforce < src.health && I.thrownby && ishuman(I.thrownby))
- var/mob/living/carbon/human/H = I.thrownby
+ var/mob/thrown_by = I.thrownby?.resolve()
+ if(I.throwforce < src.health && thrown_by && ishuman(thrown_by))
+ var/mob/living/carbon/human/H = thrown_by
retaliate(H)
..()
diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm
index 892a7b5e6c3..b21e2d7fc23 100644
--- a/code/modules/mob/living/simple_animal/constructs.dm
+++ b/code/modules/mob/living/simple_animal/constructs.dm
@@ -41,6 +41,7 @@
var/can_repair_constructs = FALSE
var/can_repair_self = FALSE
var/runetype
+ var/datum/action/innate/cult/create_rune/our_rune
var/holy = FALSE
chat_color = "#FF6262"
mobchatspan = "cultmobsay"
@@ -66,12 +67,16 @@
S.action.button.moved = "6:[pos],4:-2"
spellnum++
if(runetype)
- var/datum/action/innate/cult/create_rune/CR = new runetype(src)
- CR.Grant(src)
+ our_rune = new runetype(src)
+ our_rune.Grant(src)
var/pos = 2+spellnum*31
- CR.button.screen_loc = "6:[pos],4:-2"
- CR.button.moved = "6:[pos],4:-2"
+ our_rune.button.screen_loc = "6:[pos],4:-2"
+ our_rune.button.moved = "6:[pos],4:-2"
+/mob/living/simple_animal/hostile/construct/Destroy()
+ QDEL_NULL(our_rune)
+ return ..()
+
/mob/living/simple_animal/hostile/construct/Login()
..()
to_chat(src, playstyle_string)
@@ -448,15 +453,11 @@
background_icon_state = "bg_demon"
buttontooltipstyle = "cult"
button_icon_state = "cult_mark"
- var/mob/living/simple_animal/hostile/construct/harvester/the_construct
-
-/datum/action/innate/seek_prey/Grant(var/mob/living/C)
- the_construct = C
- ..()
/datum/action/innate/seek_prey/Activate()
if(GLOB.cult_narsie == null)
return
+ var/mob/living/simple_animal/hostile/construct/harvester/the_construct = owner
if(the_construct.seeking)
desc = "None can hide from Nar'Sie, activate to track a survivor attempting to flee the red harvest!"
button_icon_state = "cult_mark"
diff --git a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
index fb7c800af7e..ae69d07864b 100644
--- a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
+++ b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
@@ -50,7 +50,7 @@
Retaliate()
if(enemies.len && prob(10))
- enemies = list()
+ clear_enemies()
LoseTarget()
src.visible_message("[src] calms down.")
if(stat == CONSCIOUS)
diff --git a/code/modules/mob/living/simple_animal/friendly/snake.dm b/code/modules/mob/living/simple_animal/friendly/snake.dm
index eee06ede1c0..5b070d075c2 100644
--- a/code/modules/mob/living/simple_animal/friendly/snake.dm
+++ b/code/modules/mob/living/simple_animal/friendly/snake.dm
@@ -42,9 +42,10 @@
/mob/living/simple_animal/hostile/retaliate/poison/snake/ListTargets(atom/the_target)
+ var/atom/target_from = GET_TARGETS_FROM(src)
var/list/living_mobs = list()
var/list/mice = list()
- for(var/mob/living/HM in oview(vision_range, targets_from))
+ for(var/mob/living/HM in oview(vision_range, target_from))
//Yum a tasty mouse
if(istype(HM, /mob/living/simple_animal/mouse))
mice += HM
diff --git a/code/modules/mob/living/simple_animal/hostile/bees.dm b/code/modules/mob/living/simple_animal/hostile/bees.dm
index 4c70eab0987..6fdfa7438b6 100644
--- a/code/modules/mob/living/simple_animal/hostile/bees.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bees.dm
@@ -89,7 +89,8 @@
return ..()
else
. = list() // The following code is only very slightly slower than just returning oview(vision_range, targets_from), but it saves us much more work down the line
- var/list/searched_for = oview(vision_range, targets_from)
+ var/atom/target_from = GET_TARGETS_FROM(src)
+ var/list/searched_for = oview(vision_range, target_from)
for(var/obj/A in searched_for)
. += A
for(var/mob/A in searched_for)
diff --git a/code/modules/mob/living/simple_animal/hostile/cat_butcher.dm b/code/modules/mob/living/simple_animal/hostile/cat_butcher.dm
index e93e3093b16..0f20b19a88c 100644
--- a/code/modules/mob/living/simple_animal/hostile/cat_butcher.dm
+++ b/code/modules/mob/living/simple_animal/hostile/cat_butcher.dm
@@ -152,8 +152,9 @@
for(var/pos_targ in Targets)
Targets[pos_targ] = 1
var/atom/A = pos_targ
- var/target_dist = get_dist(targets_from, target)
- var/possible_target_distance = get_dist(targets_from, A)
+ var/atom/target_from = GET_TARGETS_FROM(src)
+ var/target_dist = get_dist(target_from, target)
+ var/possible_target_distance = get_dist(target_from, A)
if(target_dist < max(possible_target_distance, 3))
Targets -= A
for(var/pos_targ in Targets)
diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
index 8b5edaf1e6f..ebab54c114f 100644
--- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
+++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
@@ -362,6 +362,8 @@
action_icon = 'icons/mob/actions/actions_animal.dmi'
action_icon_state = "wrap_0"
action_background_icon_state = "bg_alien"
+ //Set this to false since we're our own action, for some reason
+ has_action = FALSE
/obj/effect/proc_holder/wrap/Initialize()
. = ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm
index 5af8c5e4f69..0421393f0bf 100644
--- a/code/modules/mob/living/simple_animal/hostile/hostile.dm
+++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm
@@ -46,8 +46,9 @@
var/stat_attack = CONSCIOUS //Mobs with stat_attack to UNCONSCIOUS will attempt to attack things that are unconscious, Mobs with stat_attack set to DEAD will attempt to attack the dead.
var/stat_exclusive = FALSE //Mobs with this set to TRUE will exclusively attack things defined by stat_attack, stat_attack DEAD means they will only attack corpses
var/attack_same = 0 //Set us to 1 to allow us to attack our own faction
- //Use set_targets_from to modify this var
- var/atom/targets_from = null //all range/attack/etc. calculations should be done from this atom, defaults to the mob itself, useful for Vehicles and such
+ //Use GET_TARGETS_FROM(mob) to access this
+ //Attempting to call GET_TARGETS_FROM(mob) when this var is null will just return mob as a base
+ var/datum/weakref/targets_from //all range/attack/etc. calculations should be done from the atom this weakrefs, useful for Vehicles and such.
var/attack_all_objects = FALSE //if true, equivalent to having a wanted_objects list containing ALL objects.
var/lose_patience_timer_id //id for a timer to call LoseTarget(), used to stop mobs fixating on a target they can't reach
@@ -55,14 +56,9 @@
/mob/living/simple_animal/hostile/Initialize()
. = ..()
-
- if(!targets_from)
- set_targets_from(src)
wanted_objects = typecacheof(wanted_objects)
-
/mob/living/simple_animal/hostile/Destroy()
- set_targets_from(null)
//We can't use losetarget here because fucking cursed blobs override it to do nothing the motherfuckers
GiveTarget(null)
return ..()
@@ -82,7 +78,8 @@
EscapeConfinement()
if(AICanContinue(possible_targets))
- if(!QDELETED(target) && !targets_from.Adjacent(target))
+ var/atom/target_from = GET_TARGETS_FROM(src)
+ if(!QDELETED(target) && !target_from.Adjacent(target))
DestroyPathToTarget()
if(!MoveToTarget(possible_targets)) //if we lose our target
if(AIShouldSleep(possible_targets)) // we try to acquire a new one
@@ -132,14 +129,15 @@
//////////////HOSTILE MOB TARGETTING AND AGGRESSION////////////
/mob/living/simple_animal/hostile/proc/ListTargets() //Step 1, find out what we can see
+ var/atom/target_from = GET_TARGETS_FROM(src)
if(!search_objects)
var/static/target_list = typecacheof(list(/obj/machinery/porta_turret, /obj/mecha)) //mobs are handled via ismob(A)
. = list()
- for(var/atom/A as() in dview(vision_range, get_turf(targets_from), SEE_INVISIBLE_MINIMUM))
+ for(var/atom/A as() in dview(vision_range, get_turf(target_from), SEE_INVISIBLE_MINIMUM))
if((ismob(A) && A != src) || target_list[A.type])
. += A
else
- . = oview(vision_range, targets_from)
+ . = oview(vision_range, target_from)
/mob/living/simple_animal/hostile/proc/FindTarget(var/list/possible_targets, var/HasTargetsList = 0)//Step 2, filter down possible targets to things we actually care about
. = list()
@@ -177,10 +175,11 @@
/mob/living/simple_animal/hostile/proc/PickTarget(list/Targets)//Step 3, pick amongst the possible, attackable targets
if(target != null)//If we already have a target, but are told to pick again, calculate the lowest distance between all possible, and pick from the lowest distance targets
+ var/atom/target_from = GET_TARGETS_FROM(src)
for(var/pos_targ in Targets)
var/atom/A = pos_targ
- var/target_dist = get_dist(targets_from, target)
- var/possible_target_distance = get_dist(targets_from, A)
+ var/target_dist = get_dist(target_from, target)
+ var/possible_target_distance = get_dist(target_from, A)
if(target_dist < possible_target_distance)
Targets -= A
if(!Targets.len)//We didnt find nothin!
@@ -261,7 +260,8 @@
GainPatience()
/mob/living/simple_animal/hostile/proc/CheckAndAttack()
- if(target && targets_from && isturf(targets_from.loc) && target.Adjacent(targets_from) && !incapacitated())
+ var/atom/target_from = GET_TARGETS_FROM(src)
+ if(target && isturf(target_from.loc) && target.Adjacent(target_from) && !incapacitated())
AttackingTarget()
/mob/living/simple_animal/hostile/proc/MoveToTarget(list/possible_targets)//Step 5, handle movement between us and our target
@@ -269,14 +269,15 @@
if(!target || !CanAttack(target))
LoseTarget()
return 0
+ var/atom/target_from = GET_TARGETS_FROM(src)
if(target in possible_targets)
var/turf/T = get_turf(src)
if(target.get_virtual_z_level() != T.get_virtual_z_level())
LoseTarget()
return 0
- var/target_distance = get_dist(targets_from,target)
+ var/target_distance = get_dist(target_from,target)
if(ranged) //We ranged? Shoot at em
- if(!target.Adjacent(targets_from) && ranged_cooldown <= world.time) //But make sure they're not in range for a melee attack and our range attack is off cooldown
+ if(!target.Adjacent(target_from) && ranged_cooldown <= world.time) //But make sure they're not in range for a melee attack and our range attack is off cooldown
OpenFire(target)
if(!Process_Spacemove()) //Drifting
walk(src,0)
@@ -289,7 +290,7 @@
else
Goto(target,move_to_delay,minimum_distance)
if(target)
- if(targets_from && isturf(targets_from.loc) && target.Adjacent(targets_from)) //If they're next to us, attack
+ if(isturf(target_from.loc) && target.Adjacent(target_from)) //If they're next to us, attack
MeleeAction()
else
if(rapid_melee > 1 && target_distance <= melee_queue_distance)
@@ -298,7 +299,7 @@
return 1
return 0
if(environment_smash)
- if(target.loc != null && get_dist(targets_from, target.loc) <= vision_range) //We can't see our target, but he's in our vision range still
+ if(target.loc != null && get_dist(target_from, target.loc) <= vision_range) //We can't see our target, but he's in our vision range still
if(ranged_ignores_vision && ranged_cooldown <= world.time) //we can't see our target... but we can fire at them!
OpenFire(target)
if((environment_smash & ENVIRONMENT_SMASH_WALLS) || (environment_smash & ENVIRONMENT_SMASH_RWALLS)) //If we're capable of smashing through walls, forget about vision completely after finding our target
@@ -364,7 +365,8 @@
/mob/living/simple_animal/hostile/proc/summon_backup(distance, exact_faction_match)
do_alert_animation(src)
playsound(loc, 'sound/machines/chime.ogg', 50, 1, -1)
- for(var/mob/living/simple_animal/hostile/M in oview(distance, targets_from))
+ var/atom/target_from = GET_TARGETS_FROM(src)
+ for(var/mob/living/simple_animal/hostile/M in oview(distance, target_from))
if(faction_check_mob(M, TRUE))
if(M.AIStatus == AI_OFF)
return
@@ -398,9 +400,10 @@
/mob/living/simple_animal/hostile/proc/Shoot(atom/targeted_atom)
- if( QDELETED(targeted_atom) || targeted_atom == targets_from.loc || targeted_atom == targets_from )
+ var/atom/target_from = GET_TARGETS_FROM(src)
+ if(QDELETED(targeted_atom) || targeted_atom == target_from.loc || targeted_atom == target_from )
return
- var/turf/startloc = get_turf(targets_from)
+ var/turf/startloc = get_turf(target_from)
if(casingtype)
var/obj/item/ammo_casing/casing = new casingtype(startloc)
playsound(src, projectilesound, 100, 1)
@@ -414,7 +417,7 @@
P.yo = targeted_atom.y - startloc.y
P.xo = targeted_atom.x - startloc.x
if(AIStatus != AI_ON)//Don't want mindless mobs to have their movement screwed up firing in space
- newtonian_move(get_dir(targeted_atom, targets_from))
+ newtonian_move(get_dir(targeted_atom, target_from))
P.original = targeted_atom
P.preparePixelProjectile(targeted_atom, src)
P.fire()
@@ -442,15 +445,16 @@
dodging = TRUE
/mob/living/simple_animal/hostile/proc/DestroyObjectsInDirection(direction)
- var/turf/T = get_step(targets_from, direction)
+ var/atom/target_from = GET_TARGETS_FROM(src)
+ var/turf/T = get_step(target_from, direction)
if(QDELETED(T))
return
- if(T.Adjacent(targets_from))
+ if(T.Adjacent(target_from))
if(CanSmashTurfs(T))
T.attack_animal(src)
return
for(var/obj/O in T.contents)
- if(!O.Adjacent(targets_from))
+ if(!O.Adjacent(target_from))
continue
if((ismachinery(O) || isstructure(O)) && O.density && environment_smash >= ENVIRONMENT_SMASH_STRUCTURES && !O.IsObscured())
O.attack_animal(src)
@@ -459,7 +463,8 @@
/mob/living/simple_animal/hostile/proc/DestroyPathToTarget()
if(environment_smash)
EscapeConfinement()
- var/dir_to_target = get_dir(targets_from, target)
+ var/atom/target_from = GET_TARGETS_FROM(src)
+ var/dir_to_target = get_dir(target_from, target)
var/dir_list = list()
if(dir_to_target in GLOB.diagonals) //it's diagonal, so we need two directions to hit
for(var/direction in GLOB.cardinals)
@@ -479,18 +484,19 @@
/mob/living/simple_animal/hostile/proc/EscapeConfinement()
+ var/atom/target_from = GET_TARGETS_FROM(src)
if(buckled)
buckled.attack_animal(src)
- if(!isturf(targets_from.loc) && targets_from.loc != null)//Did someone put us in something?
- var/atom/A = targets_from.loc
+ if(!isturf(target_from.loc) && target_from.loc != null)//Did someone put us in something?
+ var/atom/A = target_from.loc
A.attack_animal(src)//Bang on it till we get out
-
/mob/living/simple_animal/hostile/proc/FindHidden()
if(istype(target.loc, /obj/structure/closet) || istype(target.loc, /obj/machinery/disposal) || istype(target.loc, /obj/machinery/sleeper))
var/atom/A = target.loc
+ var/atom/target_from = GET_TARGETS_FROM(src)
Goto(A,move_to_delay,minimum_distance)
- if(A.Adjacent(targets_from))
+ if(A.Adjacent(target_from))
A.attack_animal(src)
return 1
@@ -576,6 +582,7 @@
else if (M.loc.type in hostile_machines)
. += M.loc
+<<<<<<< HEAD
/mob/living/simple_animal/hostile/proc/set_targets_from(atom/target_from)
if(targets_from)
UnregisterSignal(targets_from, COMSIG_PARENT_QDELETING)
@@ -587,6 +594,14 @@
SIGNAL_HANDLER
if(targets_from != src)
set_targets_from(src)
+=======
+/mob/living/simple_animal/hostile/proc/get_targets_from()
+ var/atom/target_from = targets_from.resolve()
+ if(!target_from)
+ targets_from = null
+ return src
+ return target_from
+>>>>>>> e260143132 (Port harddel fixes, as well as "Fixes stasis bed runtimes" (#4598))
/mob/living/simple_animal/hostile/proc/handle_target_del(datum/source)
SIGNAL_HANDLER
diff --git a/code/modules/mob/living/simple_animal/hostile/jungle/mook.dm b/code/modules/mob/living/simple_animal/hostile/jungle/mook.dm
index 229bd68907e..27ebb186ef1 100644
--- a/code/modules/mob/living/simple_animal/hostile/jungle/mook.dm
+++ b/code/modules/mob/living/simple_animal/hostile/jungle/mook.dm
@@ -90,9 +90,10 @@
if(target && !stat && attack_state == MOOK_ATTACK_ACTIVE)
melee_damage = 15
var/mob_direction = get_dir(src,target)
+ var/atom/target_from = GET_TARGETS_FROM(src)
if(get_dist(src,target) > 1)
step(src,mob_direction)
- if(targets_from && isturf(targets_from.loc) && target.Adjacent(targets_from) && isliving(target))
+ if(isturf(target_from.loc) && target.Adjacent(target_from) && isliving(target))
var/mob/living/L = target
L.attack_animal(src)
return
diff --git a/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm b/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm
index 9c99dc54be9..7568e3702b1 100644
--- a/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm
@@ -73,7 +73,7 @@
return 0
LoseTarget() //Target was our mecha, so null it out
M.aimob_enter_mech(src)
- set_targets_from(M)
+ targets_from = WEAKREF(M)
allow_movement_on_non_turfs = TRUE //duh
var/do_ranged = 0
for(var/equip in mecha.equipment)
@@ -99,7 +99,7 @@
mecha.aimob_exit_mech(src)
allow_movement_on_non_turfs = FALSE
- set_targets_from(src)
+ targets_from = null
//Find a new mecha
wanted_objects = typecacheof(/obj/mecha/combat, TRUE)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
index 8c58c8a835f..8cb95163c30 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
@@ -526,7 +526,7 @@ Difficulty: Hard
true_spawn = FALSE
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/Initialize()
- ..()
+ . = ..()
toggle_ai(AI_OFF)
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/charge(var/atom/chargeat = target, var/delay = 3, var/chargepast = 2)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
index d0277a81135..9f5e597658d 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
@@ -261,6 +261,9 @@ Difficulty: Very Hard
SSexplosions.medturf += target
+//There can only ever be one blackbox, and we want to know if there already is one when we spawn
+GLOBAL_DATUM(blackbox, /obj/machinery/smartfridge/black_box)
+
//Black Box
/obj/machinery/smartfridge/black_box
@@ -290,11 +293,9 @@ Difficulty: Very Hard
/obj/machinery/smartfridge/black_box/Initialize()
. = ..()
- var/static/obj/machinery/smartfridge/black_box/current
- if(current && current != src)
- qdel(src, force=TRUE)
- return
- current = src
+ if(GLOB.blackbox != src)
+ return INITIALIZE_HINT_QDEL_FORCE
+ GLOB.blackbox = src
ReadMemory()
/obj/machinery/smartfridge/black_box/process()
@@ -339,6 +340,8 @@ Difficulty: Very Hard
/obj/machinery/smartfridge/black_box/Destroy(force = FALSE)
if(force)
+ if(GLOB.blackbox == src)
+ GLOB.blackbox = null
for(var/thing in src)
qdel(thing)
return ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
index 1d5f27b9004..332eafa8772 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
@@ -79,7 +79,6 @@ Difficulty: Hard
var/did_reset = TRUE //if we timed out, returned to our beacon, and healed some
var/list/kill_phrases = list("Wsyvgi sj irivkc xettih. Vitemvmrk...", "Irivkc wsyvgi jsyrh. Vitemvmrk...", "Jyip jsyrh. Egxmzexmrk vitemv gcgpiw...", "Kix fiex. Liepmrk...")
var/list/target_phrases = list("Xevkix psgexih.", "Iriqc jsyrh.", "Eguymvih xevkix.")
- var/list/stored_nearby = list() // stores people nearby the hierophant when it enters the death animation
mobchatspan = "hierosay"
@@ -406,6 +405,7 @@ Difficulty: Hard
blinking = TRUE //we do a fancy animation, release a huge burst(), and leave our staff.
visible_message("\"Mrmxmexmrk wipj-hiwxvygx wiuyirgi...\"")
visible_message("[src] shrinks, releasing a massive burst of energy!")
+ var/list/stored_nearby = list()
for(var/mob/living/L in oviewers(7,src))
stored_nearby += L // store the people to grant the achievements to once we die
hierophant_burst(null, get_turf(src), 10)
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm
index 297583db771..4ffbb0d0d43 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm
@@ -44,7 +44,8 @@
/mob/living/simple_animal/hostile/asteroid/basilisk/GiveTarget(new_target)
if(..()) //we have a target
- if(isliving(target) && !target.Adjacent(targets_from) && ranged_cooldown <= world.time)//No more being shot at point blank or spammed with RNG beams
+ var/atom/target_from = GET_TARGETS_FROM(src)
+ if(isliving(target) && !target.Adjacent(target_from) && ranged_cooldown <= world.time)//No more being shot at point blank or spammed with RNG beams
OpenFire(target)
/mob/living/simple_animal/hostile/asteroid/basilisk/ex_act(severity, target)
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm
index 497957994c2..11008b4c1b3 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm
@@ -69,19 +69,18 @@ While using this makes the system rely on OnFire, it still gives options for tim
icon_icon = 'icons/mob/actions/actions_elites.dmi'
button_icon_state = ""
background_icon_state = "bg_default"
- var/mob/living/simple_animal/hostile/asteroid/elite/M
var/chosen_message
var/chosen_attack_num = 0
/datum/action/innate/elite_attack/Grant(mob/living/L)
if(istype(L, /mob/living/simple_animal/hostile/asteroid/elite))
- M = L
return ..()
return FALSE
/datum/action/innate/elite_attack/Activate()
- M.chosen_attack = chosen_attack_num
- to_chat(M, chosen_message)
+ var/mob/living/simple_animal/hostile/asteroid/elite/elite_owner = owner
+ elite_owner.chosen_attack = chosen_attack_num
+ to_chat(elite_owner, chosen_message)
/mob/living/simple_animal/hostile/asteroid/elite/updatehealth()
. = ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/herald.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/herald.dm
index 65b42ec8c83..99bf3ec3f15 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/herald.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/herald.dm
@@ -200,7 +200,7 @@
var/mob/living/simple_animal/hostile/asteroid/elite/herald/my_master = null
/mob/living/simple_animal/hostile/asteroid/elite/herald/mirror/Initialize()
- ..()
+ . = ..()
toggle_ai(AI_OFF)
/mob/living/simple_animal/hostile/asteroid/elite/herald/mirror/Destroy()
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm
index eb438442e07..dfb54ec7586 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm
@@ -7,7 +7,7 @@
if(L.is_conscious())
return L
else
- enemies -= L
+ remove_enemy(L)
else if(ismecha(A))
var/obj/mecha/M = A
if(M.occupant)
@@ -25,19 +25,38 @@
if(isliving(A))
var/mob/living/M = A
if(attack_same || !faction_check_mob(M))
- enemies |= M
+ add_enemy(M)
if(istype(M, /mob/living/simple_animal/hostile/retaliate))
var/mob/living/simple_animal/hostile/retaliate/H = M
if(attack_same && H.attack_same)
- H.enemies |= enemies
+ H.add_enemies(enemies)
else if(ismecha(A))
var/obj/mecha/M = A
if(M.occupant)
- enemies |= M
- enemies |= M.occupant
+ add_enemy(M)
+ add_enemy(M.occupant)
return FALSE
/mob/living/simple_animal/hostile/retaliate/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
. = ..()
if(. > 0 && stat == CONSCIOUS)
Retaliate()
+
+/mob/living/simple_animal/hostile/retaliate/proc/add_enemy(new_enemy)
+ RegisterSignal(new_enemy, COMSIG_PARENT_QDELETING, .proc/remove_enemy, override = TRUE)
+ enemies |= new_enemy
+
+/mob/living/simple_animal/hostile/retaliate/proc/add_enemies(new_enemies)
+ for(var/new_enemy in new_enemies)
+ RegisterSignal(new_enemy, COMSIG_PARENT_QDELETING, .proc/remove_enemy, override = TRUE)
+ enemies |= new_enemy
+
+/mob/living/simple_animal/hostile/retaliate/proc/clear_enemies()
+ for(var/enemy in enemies)
+ UnregisterSignal(enemy, COMSIG_PARENT_QDELETING)
+ enemies.Cut()
+
+/mob/living/simple_animal/hostile/retaliate/proc/remove_enemy(datum/enemy_to_remove)
+ SIGNAL_HANDLER
+ UnregisterSignal(enemy_to_remove, COMSIG_PARENT_QDELETING)
+ enemies -= enemy_to_remove
diff --git a/code/modules/mob/living/simple_animal/slime/life.dm b/code/modules/mob/living/simple_animal/slime/life.dm
index 63add9b766f..47e38f95378 100644
--- a/code/modules/mob/living/simple_animal/slime/life.dm
+++ b/code/modules/mob/living/simple_animal/slime/life.dm
@@ -59,7 +59,7 @@
step_to(src, Target)
else
special_process = FALSE
- Target = null
+ set_target(null)
reset_processing()
@@ -154,11 +154,10 @@
if(M.stat == DEAD)
if(client)
to_chat(src, "This subject does not have a strong enough life energy anymore...")
- else if(!rabid && !attacked && M.LAssailant && prob(50))
- if(M.LAssailant in Friends)
- ++Friends[M.LAssailant]
- else
- Friends[M.LAssailant] = 1
+ else if(!rabid && !attacked)
+ var/mob/last_to_hurt = M.LAssailant?.resolve()
+ if(last_to_hurt && last_to_hurt != M && prob(50))
+ add_friendship(last_to_hurt, 1)
//we go rabid after finishing to feed on a human with a client.
if(M.client && ishuman(M))
rabid = 1
@@ -169,7 +168,7 @@
layer = initial(layer)
qdel(M)
- Target = null
+ set_target(null)
special_process = FALSE
Feedstop()
return
@@ -250,7 +249,7 @@
--target_patience
if (target_patience <= 0 || SStun > world.time || Discipline || attacked || docile)
target_patience = 0
- Target = null
+ set_target(null)
special_process = FALSE
var/hungry = 0
@@ -263,7 +262,7 @@
if(hungry == 2)
if(Friends.len > 0 && prob(1))
var/mob/nofriend = pick(Friends)
- --Friends[nofriend]
+ add_friendship(nofriend, -1)
if(!Target)
if(will_hunt() && hungry || attacked || rabid)
@@ -279,9 +278,9 @@
if(ishuman(L))
if(!Discipline && prob(5) || attacked || rabid)
- Target = L
+ set_target(L)
else
- Target = L
+ set_target(L)
if(Target)
target_patience = rand(5,7)
@@ -353,13 +352,13 @@
if (Leader == who) // Already following him
to_say = pick("Yes...", "Lead...", "Follow...")
else if (Friends[who] > Friends[Leader]) // VIVA
- Leader = who
+ set_leader(who)
to_say = "Yes... I follow [who]..."
else
to_say = "No... I follow [Leader]..."
else
if (Friends[who] >= SLIME_FRIENDSHIP_FOLLOW)
- Leader = who
+ set_leader(who)
to_say = "I follow..."
else // Not friendly enough
to_say = pick("No...", "I no follow...")
@@ -367,27 +366,27 @@
if (buckled) // We are asked to stop feeding
if (Friends[who] >= SLIME_FRIENDSHIP_STOPEAT)
Feedstop()
- Target = null
+ set_target(null)
if (Friends[who] < SLIME_FRIENDSHIP_STOPEAT_NOANGRY)
- --Friends[who]
+ add_friendship(who, -1)
to_say = "Grrr..." // I'm angry but I do it
else
to_say = "Fine..."
else if (Target) // We are asked to stop chasing
if (Friends[who] >= SLIME_FRIENDSHIP_STOPCHASE)
- Target = null
+ set_target(null)
if (Friends[who] < SLIME_FRIENDSHIP_STOPCHASE_NOANGRY)
- --Friends[who]
+ add_friendship(who, -1)
to_say = "Grrr..." // I'm angry but I do it
else
to_say = "Fine..."
else if (Leader) // We are asked to stop following
if (Leader == who)
to_say = "Yes... I stay..."
- Leader = null
+ set_leader(null)
else
if (Friends[who] > Friends[Leader])
- Leader = null
+ set_leader(null)
to_say = "Yes... I stop..."
else
to_say = "No... keep follow..."
@@ -409,7 +408,7 @@
to_say = "No... won't stay..."
else if (findtext(phrase, "attack"))
if (rabid && prob(20))
- Target = who
+ set_target(who)
special_process = TRUE
to_say = "ATTACK!?!?"
else if (Friends[who] >= SLIME_FRIENDSHIP_ATTACK)
@@ -417,14 +416,14 @@
if (findtext(phrase, lowertext(L.name)))
if (isslime(L))
to_say = "NO... [L] slime friend"
- --Friends[who] //Don't ask a slime to attack its friend
+ add_friendship(who, -1) //Don't ask a slime to attack its friend
else if(!Friends[L] || Friends[L] < 1)
- Target = L
+ set_target(L)
special_process = TRUE
to_say = "Ok... I attack [Target]"
else
to_say = "No... like [L] ..."
- --Friends[who] //Don't ask a slime to attack its friend
+ add_friendship(who, -1) //Don't ask a slime to attack its friend
break
else
to_say = "No... no listen"
diff --git a/code/modules/mob/living/simple_animal/slime/powers.dm b/code/modules/mob/living/simple_animal/slime/powers.dm
index 8d0bd5c1758..f2b091c3098 100644
--- a/code/modules/mob/living/simple_animal/slime/powers.dm
+++ b/code/modules/mob/living/simple_animal/slime/powers.dm
@@ -253,7 +253,7 @@
GLOB.poi_list |= M
M.master = master
LAZYADD(GLOB.mob_spawners["[master.real_name]'s slime"], M)
- M.Friends = Friends.Copy()
+ M.set_friends(Friends)
if(step_away)
step_away(M,src)
M.mutation_chance = clamp(mutation_chance+(rand(5,-5)),0,100)
diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm
index cfabb085abc..f5a3220cb94 100644
--- a/code/modules/mob/living/simple_animal/slime/slime.dm
+++ b/code/modules/mob/living/simple_animal/slime/slime.dm
@@ -1,3 +1,4 @@
+#define SLIME_CARES_ABOUT(to_check) (to_check && (to_check == Target || to_check == Leader || (to_check in Friends)))
/mob/living/simple_animal/slime
name = "grey baby slime (123)"
icon = 'icons/mob/slimes.dmi'
@@ -112,6 +113,12 @@
if(transformeffects & SLIME_EFFECT_LIGHT_PINK)
set_playable()
+/mob/living/simple_animal/slime/Destroy()
+ set_target(null)
+ set_leader(null)
+ clear_friends()
+ return ..()
+
/mob/living/simple_animal/slime/proc/set_colour(new_colour)
colour = new_colour
update_name()
@@ -356,10 +363,7 @@
if(S.next_step(user,user.a_intent))
return 1
if(istype(W, /obj/item/stack/sheet/mineral/plasma) && !stat) //Let's you feed slimes plasma.
- if (user in Friends)
- ++Friends[user]
- else
- Friends[user] = 1
+ add_friendship(user, 1)
to_chat(user, "You feed the slime the plasma. It chirps happily.")
var/obj/item/stack/sheet/mineral/plasma/S = W
S.use(1)
@@ -430,7 +434,7 @@
adjustBruteLoss(new_damage)
if(!client)
if(Target) // Like cats
- Target = null
+ set_target(null)
++Discipline
return
@@ -475,8 +479,7 @@
if(Discipline == 1)
attacked = 0
- if(Target)
- Target = null
+ set_target(null)
if(buckled)
Feedstop(silent = TRUE) //we unbuckle the slime from the mob it latched onto.
bucklestrength = initial(bucklestrength)
@@ -537,3 +540,55 @@
/mob/living/simple_animal/slime/rainbow/Initialize(mapload, new_colour="rainbow", new_is_adult)
. = ..(mapload, new_colour, new_is_adult)
+
+/mob/living/simple_animal/slime/proc/set_target(new_target)
+ var/old_target = Target
+ Target = new_target
+ if(old_target && !SLIME_CARES_ABOUT(old_target))
+ UnregisterSignal(old_target, COMSIG_PARENT_QDELETING)
+ if(Target)
+ RegisterSignal(Target, COMSIG_PARENT_QDELETING, .proc/clear_memories_of, override = TRUE)
+
+/mob/living/simple_animal/slime/proc/set_leader(new_leader)
+ var/old_leader = Leader
+ Leader = new_leader
+ if(old_leader && !SLIME_CARES_ABOUT(old_leader))
+ UnregisterSignal(old_leader, COMSIG_PARENT_QDELETING)
+ if(Leader)
+ RegisterSignal(Leader, COMSIG_PARENT_QDELETING, .proc/clear_memories_of, override = TRUE)
+
+/mob/living/simple_animal/slime/proc/add_friendship(new_friend, amount = 1)
+ if(!Friends[new_friend])
+ Friends[new_friend] = 0
+ Friends[new_friend] += amount
+ if(new_friend)
+ RegisterSignal(new_friend, COMSIG_PARENT_QDELETING, .proc/clear_memories_of, override = TRUE)
+
+/mob/living/simple_animal/slime/proc/set_friendship(new_friend, amount = 1)
+ Friends[new_friend] = amount
+ if(new_friend)
+ RegisterSignal(new_friend, COMSIG_PARENT_QDELETING, .proc/clear_memories_of, override = TRUE)
+
+/mob/living/simple_animal/slime/proc/remove_friend(friend)
+ Friends -= friend
+ if(friend && !SLIME_CARES_ABOUT(friend))
+ UnregisterSignal(friend, COMSIG_PARENT_QDELETING)
+
+/mob/living/simple_animal/slime/proc/set_friends(new_buds)
+ clear_friends()
+ for(var/mob/friend as anything in new_buds)
+ set_friendship(friend, new_buds[friend])
+
+/mob/living/simple_animal/slime/proc/clear_friends()
+ for(var/mob/friend as anything in Friends)
+ remove_friend(friend)
+
+/mob/living/simple_animal/slime/proc/clear_memories_of(datum/source)
+ SIGNAL_HANDLER
+ if(source == Target)
+ set_target(null)
+ if(source == Leader)
+ set_leader(null)
+ remove_friend(source)
+
+#undef SLIME_CARES_ABOUT
diff --git a/code/modules/mob/logout.dm b/code/modules/mob/logout.dm
index 18dd11f1bb9..0f21607b201 100644
--- a/code/modules/mob/logout.dm
+++ b/code/modules/mob/logout.dm
@@ -3,10 +3,7 @@
SStgui.on_logout(src)
unset_machine()
remove_from_player_list()
- if(client?.movingmob) //In the case the client was transferred to another mob and not deleted.
- client.movingmob.client_mobs_in_contents -= src
- UNSETEMPTY(client.movingmob.client_mobs_in_contents)
- client.movingmob = null
+ clear_client_in_contents()
..()
if(loc)
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 1254db09f05..2852907f22a 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -16,14 +16,19 @@
*
* qdels any client colours in place on this mob
*
+ * Clears any refs to the mob inside its current location
+ *
* Ghostizes the client attached to this mob
*
+ * If our mind still exists, clear its current var to prevent harddels
+ *
* Parent call
*/
/mob/Destroy()//This makes sure that mobs with clients/keys are not just deleted from the game.
remove_from_mob_list()
remove_from_dead_mob_list()
remove_from_alive_mob_list()
+ remove_from_mob_suicide_list()
focus = null
for (var/alert in alerts)
clear_alert(alert, TRUE)
@@ -35,7 +40,10 @@
for(var/cc in client_colours)
qdel(cc)
client_colours = null
+ clear_client_in_contents() //Gotta do this here as well as Logout, since client will be null by the time it gets there, cause of that ghostize
ghostize()
+ if(mind?.current == src) //Let's just be safe yeah? This will occasionally be cleared, but not always. Can't do it with ghostize without changing behavior
+ mind.set_current(null)
QDEL_LIST(mob_spell_list)
for(var/datum/action/A as() in actions)
if(istype(A.target, /obj/effect/proc_holder))
@@ -1271,3 +1279,21 @@
SEND_SIGNAL(src, COMSIG_MOB_STATCHANGE, new_stat)
. = stat
stat = new_stat
+
+/mob/proc/set_active_storage(new_active_storage)
+ if(active_storage)
+ UnregisterSignal(active_storage, COMSIG_PARENT_QDELETING)
+ active_storage = new_active_storage
+ if(active_storage)
+ RegisterSignal(active_storage, COMSIG_PARENT_QDELETING, .proc/active_storage_deleted)
+
+/mob/proc/active_storage_deleted(datum/source)
+ SIGNAL_HANDLER
+ set_active_storage(null)
+
+///Clears the client in contents list of our current "eye". Prevents hard deletes
+/mob/proc/clear_client_in_contents()
+ if(client?.movingmob) //In the case the client was transferred to another mob and not deleted.
+ client.movingmob.client_mobs_in_contents -= src
+ UNSETEMPTY(client.movingmob.client_mobs_in_contents)
+ client.movingmob = null
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index 51a980849f5..ac4a4052601 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -150,8 +150,8 @@
/// Can this mob enter shuttles
var/move_on_shuttle = 1
- ///The last mob/living/carbon to push/drag/grab this mob (exclusively used by slimes friend recognition)
- var/mob/living/carbon/LAssailant = null
+ ///A weakref to the last mob/living/carbon to push/drag/grab this mob (exclusively used by slimes friend recognition)
+ var/datum/weakref/LAssailant = null
/**
* construct spells and mime spells.
diff --git a/code/modules/mob/mob_lists.dm b/code/modules/mob/mob_lists.dm
index bd47d511e1d..e09f2a5e523 100644
--- a/code/modules/mob/mob_lists.dm
+++ b/code/modules/mob/mob_lists.dm
@@ -22,6 +22,13 @@
if(client)
remove_from_current_living_players()
+///Adds a mob reference to the list of all suicided mobs
+/mob/proc/add_to_mob_suicide_list()
+ GLOB.suicided_mob_list += src
+
+///Removes a mob references from the list of all suicided mobs
+/mob/proc/remove_from_mob_suicide_list()
+ GLOB.suicided_mob_list -= src
///Adds the mob reference to the list of all the dead mobs. If mob is cliented, it adds it to the list of all dead player-mobs.
/mob/proc/add_to_dead_mob_list()
diff --git a/code/modules/modular_computers/NTNet/NTNRC/conversation.dm b/code/modules/modular_computers/NTNet/NTNRC/conversation.dm
index 20ad05b8e37..cf1b9bb28cd 100644
--- a/code/modules/modular_computers/NTNet/NTNRC/conversation.dm
+++ b/code/modules/modular_computers/NTNet/NTNRC/conversation.dm
@@ -16,6 +16,8 @@
/datum/ntnet_conversation/Destroy()
if(SSnetworks.station_network)
SSnetworks.station_network.chat_channels.Remove(src)
+ for(var/datum/computer_file/program/chatclient/chatterbox in clients)
+ purge_client(chatterbox)
return ..()
/datum/ntnet_conversation/proc/add_message(message, username)
@@ -35,12 +37,18 @@
/datum/ntnet_conversation/proc/add_client(datum/computer_file/program/chatclient/C)
if(!istype(C))
return
+ C.conversations |= src
clients.Add(C)
add_status_message("[C.username] has joined the channel.")
// No operator, so we assume the channel was empty. Assign this user as operator.
if(!operator)
changeop(C)
+//Clear all of our references to a client, used for client deletion
+/datum/ntnet_conversation/proc/purge_client(datum/computer_file/program/chatclient/forget)
+ remove_client(forget)
+ forget.conversations -= src
+
/datum/ntnet_conversation/proc/remove_client(datum/computer_file/program/chatclient/C)
if(!istype(C) || !(C in clients))
return
diff --git a/code/modules/modular_computers/computers/machinery/console_presets.dm b/code/modules/modular_computers/computers/machinery/console_presets.dm
index 4b09436796c..3e40d5a686a 100644
--- a/code/modules/modular_computers/computers/machinery/console_presets.dm
+++ b/code/modules/modular_computers/computers/machinery/console_presets.dm
@@ -25,8 +25,6 @@
/obj/machinery/modular_computer/console/preset/proc/install_programs()
return
-
-
// ===== ENGINEERING CONSOLE =====
/obj/machinery/modular_computer/console/preset/engineering
console_department = "Engineering"
diff --git a/code/modules/modular_computers/file_system/programs/ntnrc_client.dm b/code/modules/modular_computers/file_system/programs/ntnrc_client.dm
index 9422788afed..76dd8039e6f 100644
--- a/code/modules/modular_computers/file_system/programs/ntnrc_client.dm
+++ b/code/modules/modular_computers/file_system/programs/ntnrc_client.dm
@@ -19,10 +19,18 @@
var/list/channel_history = list()
var/operator_mode = FALSE // Channel operator mode
var/netadmin_mode = FALSE // Administrator mode (invisible to other users + bypasses passwords)
+ //A list of all the converstations we're a part of
+ var/list/datum/ntnet_conversation/conversations = list()
/datum/computer_file/program/chatclient/New()
username = "DefaultUser[rand(100, 999)]"
+/datum/computer_file/program/chatclient/Destroy()
+ for(var/datum/ntnet_conversation/discussion as anything in conversations)
+ discussion.purge_client(src)
+ conversations.Cut()
+ return ..()
+
/datum/computer_file/program/chatclient/ui_act(action, params)
if(..())
return
diff --git a/code/modules/modular_computers/file_system/programs/sm_monitor.dm b/code/modules/modular_computers/file_system/programs/sm_monitor.dm
index b7c5be50425..e814aff4fdd 100644
--- a/code/modules/modular_computers/file_system/programs/sm_monitor.dm
+++ b/code/modules/modular_computers/file_system/programs/sm_monitor.dm
@@ -31,12 +31,15 @@
refresh()
/datum/computer_file/program/supermatter_monitor/kill_program(forced = FALSE)
- active = null
+ for(var/supermatter in supermatters)
+ clear_supermatter(supermatter)
supermatters = null
..()
// Refreshes list of active supermatter crystals
/datum/computer_file/program/supermatter_monitor/proc/refresh()
+ for(var/supermatter in supermatters)
+ clear_supermatter(supermatter)
supermatters = list()
var/turf/T = get_turf(ui_host())
if(!T)
@@ -46,9 +49,7 @@
if (!isturf(S.loc) || !(is_station_level(S.z) || is_mining_level(S.z) || S.get_virtual_z_level() == T.get_virtual_z_level()))
continue
supermatters.Add(S)
-
- if(!(active in supermatters))
- active = null
+ RegisterSignal(S, COMSIG_PARENT_QDELETING, .proc/react_to_del)
/datum/computer_file/program/supermatter_monitor/proc/get_status()
. = SUPERMATTER_INACTIVE
@@ -124,3 +125,13 @@
if(S.uid == newuid)
active = S
return TRUE
+
+/datum/computer_file/program/supermatter_monitor/proc/react_to_del(datum/source)
+ SIGNAL_HANDLER
+ clear_supermatter(source)
+
+/datum/computer_file/program/supermatter_monitor/proc/clear_supermatter(matter)
+ supermatters -= matter
+ if(matter == active)
+ active = null
+ UnregisterSignal(matter, COMSIG_PARENT_QDELETING)
diff --git a/code/modules/modular_computers/hardware/hard_drive.dm b/code/modules/modular_computers/hardware/hard_drive.dm
index e03ace05a5e..8577827dc7a 100644
--- a/code/modules/modular_computers/hardware/hard_drive.dm
+++ b/code/modules/modular_computers/hardware/hard_drive.dm
@@ -117,7 +117,7 @@
return null
/obj/item/computer_hardware/hard_drive/Destroy()
- stored_files = null
+ QDEL_LIST(stored_files)
return ..()
/obj/item/computer_hardware/hard_drive/Initialize()
diff --git a/code/modules/ninja/suit/suit.dm b/code/modules/ninja/suit/suit.dm
index 75f7604717f..d79742c99fe 100644
--- a/code/modules/ninja/suit/suit.dm
+++ b/code/modules/ninja/suit/suit.dm
@@ -76,6 +76,11 @@ Contents:
cell.name = "black power cell"
cell.icon_state = "bscell"
+/obj/item/clothing/suit/space/space_ninja/Destroy()
+ QDEL_NULL(spark_system)
+ QDEL_NULL(cell)
+ return ..()
+
//Simply deletes all the attachments and self, killing all related procs.
/obj/item/clothing/suit/space/space_ninja/proc/terminate()
qdel(n_hood)
diff --git a/code/modules/projectiles/ammunition/energy/portal.dm b/code/modules/projectiles/ammunition/energy/portal.dm
index ec1f067080d..3d560158a7a 100644
--- a/code/modules/projectiles/ammunition/energy/portal.dm
+++ b/code/modules/projectiles/ammunition/energy/portal.dm
@@ -4,7 +4,8 @@
harmful = FALSE
fire_sound = 'sound/weapons/pulse3.ogg'
select_name = "blue"
- var/obj/item/gun/energy/wormhole_projector/gun
+ //Weakref to the gun that shot us
+ var/datum/weakref/gun
/obj/item/ammo_casing/energy/wormhole/orange
projectile_type = /obj/item/projectile/beam/wormhole/orange
@@ -12,7 +13,7 @@
/obj/item/ammo_casing/energy/wormhole/Initialize(mapload, obj/item/gun/energy/wormhole_projector/wh)
. = ..()
- gun = wh
+ gun = WEAKREF(wh)
/obj/item/ammo_casing/energy/wormhole/throw_proj()
. = ..()
diff --git a/code/modules/projectiles/guns/energy/laser_gatling.dm b/code/modules/projectiles/guns/energy/laser_gatling.dm
index 3ff4c1b5684..bf852f7b1af 100644
--- a/code/modules/projectiles/guns/energy/laser_gatling.dm
+++ b/code/modules/projectiles/guns/energy/laser_gatling.dm
@@ -23,6 +23,9 @@
START_PROCESSING(SSobj, src)
/obj/item/minigunpack/Destroy()
+ if(!QDELETED(gun))
+ qdel(gun)
+ gun = null
STOP_PROCESSING(SSobj, src)
return ..()
@@ -133,6 +136,12 @@
return ..()
+/obj/item/gun/energy/minigun/Destroy()
+ if(!QDELETED(ammo_pack))
+ qdel(ammo_pack)
+ ammo_pack = null
+ return ..()
+
/obj/item/gun/energy/minigun/attack_self(mob/living/user)
return
diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm
index 8976f200b3d..00faa65624f 100644
--- a/code/modules/projectiles/guns/energy/special.dm
+++ b/code/modules/projectiles/guns/energy/special.dm
@@ -258,10 +258,10 @@
for(var/i in 1 to ammo_type.len)
var/obj/item/ammo_casing/energy/wormhole/W = ammo_type[i]
if(istype(W))
- W.gun = src
+ W.gun = WEAKREF(src)
var/obj/item/projectile/beam/wormhole/WH = W.BB
if(istype(WH))
- WH.gun = src
+ WH.gun = WEAKREF(src)
/obj/item/gun/energy/wormhole_projector/process_chamber()
..()
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index 42257883f5c..d25d25bcd28 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -553,6 +553,8 @@
else if(T != loc)
step_towards(src, T)
hitscan_last = loc
+ if(QDELETED(src))
+ return
if(!hitscanning && !forcemoved)
pixel_x = trajectory.return_px() - trajectory.mpx * trajectory_multiplier * SSprojectiles.global_iterations_per_move
pixel_y = trajectory.return_py() - trajectory.mpy * trajectory_multiplier * SSprojectiles.global_iterations_per_move
@@ -685,13 +687,14 @@
finalize_hitscan_and_generate_tracers()
STOP_PROCESSING(SSprojectiles, src)
cleanup_beam_segments()
- qdel(trajectory)
+ if(trajectory)
+ QDEL_NULL(trajectory)
return ..()
/obj/item/projectile/proc/cleanup_beam_segments()
QDEL_LIST_ASSOC(beam_segments)
beam_segments = list()
- qdel(beam_index)
+ QDEL_NULL(beam_index)
/obj/item/projectile/proc/finalize_hitscan_and_generate_tracers(impacting = TRUE)
if(trajectory && beam_index)
diff --git a/code/modules/projectiles/projectile/special/curse.dm b/code/modules/projectiles/projectile/special/curse.dm
index 2598c439706..0e0eaa1f21a 100644
--- a/code/modules/projectiles/projectile/special/curse.dm
+++ b/code/modules/projectiles/projectile/special/curse.dm
@@ -36,7 +36,7 @@
/obj/item/projectile/curse_hand/Destroy()
if(arm)
arm.End()
- arm = null
+ QDEL_NULL(arm)
if(CHECK_BITFIELD(movement_type, UNSTOPPABLE))
playsound(src, 'sound/effects/curse3.ogg', 25, 1, -1)
var/turf/T = get_step(src, dir)
diff --git a/code/modules/projectiles/projectile/special/wormhole.dm b/code/modules/projectiles/projectile/special/wormhole.dm
index c7fa6c644ff..075db9472c9 100644
--- a/code/modules/projectiles/projectile/special/wormhole.dm
+++ b/code/modules/projectiles/projectile/special/wormhole.dm
@@ -5,7 +5,8 @@
damage = 0
nodamage = TRUE
pass_flags = PASSGLASS | PASSTABLE | PASSGRILLE | PASSMOB
- var/obj/item/gun/energy/wormhole_projector/gun
+ //Weakref to the thing that shot us
+ var/datum/weakref/gun
color = "#33CCFF"
tracer_type = /obj/effect/projectile/tracer/wormhole
impact_type = /obj/effect/projectile/impact/wormhole
@@ -24,7 +25,8 @@
/obj/item/projectile/beam/wormhole/on_hit(atom/target)
- if(!gun)
+ var/obj/item/gun/energy/wormhole_projector/projector = gun.resolve()
+ if(!projector)
qdel(src)
return
- gun.create_portal(src, get_turf(src))
+ projector.create_portal(src, get_turf(src))
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index ce858ec91e0..53245185a7b 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -1,5 +1,5 @@
/datum/reagent/blood
- data = list("donor"=null,"viruses"=null,"blood_DNA"=null,"blood_type"=null,"resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null,"cloneable"=null,"factions"=null,"quirks"=null)
+ data = list("viruses"=null,"blood_DNA"=null,"blood_type"=null,"resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null,"cloneable"=null,"factions"=null,"quirks"=null)
name = "Blood"
color = "#C80000" // rgb: 200, 0, 0
metabolization_rate = 5 //fast rate so it disappears fast.
diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm
index 311e04d7b80..683e9e54772 100644
--- a/code/modules/reagents/reagent_containers.dm
+++ b/code/modules/reagents/reagent_containers.dm
@@ -87,12 +87,14 @@
/obj/item/reagent_containers/proc/bartender_check(atom/target)
. = FALSE
- if(target.CanPass(src, get_turf(src)) && thrownby && HAS_TRAIT(thrownby, TRAIT_BOOZE_SLIDER))
+ var/mob/thrown_by = thrownby?.resolve()
+ if(target.CanPass(src, get_turf(src)) && thrown_by && HAS_TRAIT(thrown_by, TRAIT_BOOZE_SLIDER))
. = TRUE
/obj/item/reagent_containers/proc/SplashReagents(atom/target, thrown = FALSE)
if(!reagents || !reagents.total_volume || !spillable)
return
+ var/mob/thrown_by = thrownby?.resolve()
if(ismob(target) && target.reagents)
if(thrown)
@@ -105,7 +107,7 @@
R += "[A.type] ([num2text(A.volume)]),"
if(thrownby)
- log_combat(thrownby, M, "splashed", R)
+ log_combat(thrown_by, M, "splashed", R)
reagents.reaction(target, TOUCH)
else if(bartender_check(target) && thrown)
@@ -113,10 +115,10 @@
return
else
- if(isturf(target) && reagents.reagent_list.len && thrownby)
- log_combat(thrownby, target, "splashed (thrown) [english_list(reagents.reagent_list)]", "in [AREACOORD(target)]")
- log_game("[key_name(thrownby)] splashed (thrown) [english_list(reagents.reagent_list)] on [target] in [AREACOORD(target)].")
- message_admins("[ADMIN_LOOKUPFLW(thrownby)] splashed (thrown) [english_list(reagents.reagent_list)] on [target] in [ADMIN_VERBOSEJMP(target)].")
+ if(isturf(target) && reagents.reagent_list.len && thrown_by)
+ log_combat(thrown_by, target, "splashed (thrown) [english_list(reagents.reagent_list)]", "in [AREACOORD(target)]")
+ log_game("[key_name(thrown_by)] splashed (thrown) [english_list(reagents.reagent_list)] on [target] in [AREACOORD(target)].")
+ message_admins("[ADMIN_LOOKUPFLW(thrown_by)] splashed (thrown) [english_list(reagents.reagent_list)] on [target] in [ADMIN_VERBOSEJMP(target)].")
visible_message("[src] spills its contents all over [target].")
reagents.reaction(target, TOUCH)
if(QDELETED(src))
diff --git a/code/modules/reagents/reagent_containers/blood_pack.dm b/code/modules/reagents/reagent_containers/blood_pack.dm
index bce6ebeb4d4..3a686b76958 100644
--- a/code/modules/reagents/reagent_containers/blood_pack.dm
+++ b/code/modules/reagents/reagent_containers/blood_pack.dm
@@ -12,7 +12,7 @@
/obj/item/reagent_containers/blood/Initialize()
. = ..()
if(blood_type != null)
- reagents.add_reagent(unique_blood ? unique_blood : /datum/reagent/blood, 200, list("donor"=null,"viruses"=null,"blood_DNA"=null,"blood_type"=blood_type,"resistances"=null,"trace_chem"=null))
+ reagents.add_reagent(unique_blood ? unique_blood : /datum/reagent/blood, 200, list("viruses"=null,"blood_DNA"=null,"blood_type"=blood_type,"resistances"=null,"trace_chem"=null))
update_icon()
/obj/item/reagent_containers/blood/on_reagent_change(changetype)
diff --git a/code/modules/reagents/reagent_containers/borghydro.dm b/code/modules/reagents/reagent_containers/borghydro.dm
index 9175fd650cc..7011be0db7b 100644
--- a/code/modules/reagents/reagent_containers/borghydro.dm
+++ b/code/modules/reagents/reagent_containers/borghydro.dm
@@ -44,9 +44,9 @@ Borg Hypospray
/obj/item/reagent_containers/borghypo/Destroy()
STOP_PROCESSING(SSobj, src)
+ QDEL_LIST(reagent_list)
return ..()
-
/obj/item/reagent_containers/borghypo/process(delta_time) //Every [recharge_time] seconds, recharge some reagents for the cyborg
charge_timer += delta_time
if(charge_timer >= recharge_time)
diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm
index d276c339317..b09a2235ebe 100644
--- a/code/modules/recycling/disposal/bin.dm
+++ b/code/modules/recycling/disposal/bin.dm
@@ -137,7 +137,7 @@
else
target.visible_message("[user] has placed [target] in [src].", "[user] has placed you in [src].")
log_combat(user, target, "stuffed", addition="into [src]")
- target.LAssailant = user
+ target.LAssailant = WEAKREF(user)
update_icon()
/obj/machinery/disposal/relaymove(mob/user)
diff --git a/code/modules/research/nanites/nanite_chamber.dm b/code/modules/research/nanites/nanite_chamber.dm
index 13b50c6b0fc..ece40e19773 100644
--- a/code/modules/research/nanites/nanite_chamber.dm
+++ b/code/modules/research/nanites/nanite_chamber.dm
@@ -11,7 +11,6 @@
idle_power_usage = 300
active_power_usage = 1200
- var/obj/machinery/computer/nanite_chamber_control/console
var/locked = FALSE
var/breakout_time = 1200
var/scan_level
diff --git a/code/modules/research/nanites/nanite_chamber_computer.dm b/code/modules/research/nanites/nanite_chamber_computer.dm
index b73c6253ab6..d6caf584aac 100644
--- a/code/modules/research/nanites/nanite_chamber_computer.dm
+++ b/code/modules/research/nanites/nanite_chamber_computer.dm
@@ -2,7 +2,6 @@
name = "nanite chamber control console"
desc = "Controls a connected nanite chamber. Can inoculate nanites, load programs, and analyze existing nanite swarms."
var/obj/machinery/nanite_chamber/chamber
- var/obj/item/disk/nanite_program/disk
icon_screen = "nanite_chamber_control"
circuit = /obj/item/circuitboard/computer/nanite_chamber_control
@@ -17,8 +16,7 @@
var/C = locate(/obj/machinery/nanite_chamber, get_step(src, direction))
if(C)
var/obj/machinery/nanite_chamber/NC = C
- chamber = NC
- NC.console = src
+ set_connected_chamber(NC)
/obj/machinery/computer/nanite_chamber_control/interact()
if(!chamber)
@@ -102,3 +100,14 @@
log_combat(usr, chamber.occupant, "injected", null, "with nanites via [src]")
chamber.occupant.investigate_log("was injected with nanites by [key_name(usr)] via [src] at [AREACOORD(src)].", INVESTIGATE_NANITES)
. = TRUE
+
+/obj/machinery/computer/nanite_chamber_control/proc/set_connected_chamber(new_chamber)
+ if(chamber)
+ UnregisterSignal(chamber, COMSIG_PARENT_QDELETING)
+ chamber = new_chamber
+ if(chamber)
+ RegisterSignal(chamber, COMSIG_PARENT_QDELETING, .proc/react_to_chamber_del)
+
+/obj/machinery/computer/nanite_chamber_control/proc/react_to_chamber_del(datum/source)
+ SIGNAL_HANDLER
+ set_connected_chamber(null)
diff --git a/code/modules/research/nanites/nanite_programs.dm b/code/modules/research/nanites/nanite_programs.dm
index 7c6d64e9b2b..2a4142bb35c 100644
--- a/code/modules/research/nanites/nanite_programs.dm
+++ b/code/modules/research/nanites/nanite_programs.dm
@@ -77,6 +77,9 @@
on_mob_remove()
if(nanites)
nanites.programs -= src
+ for(var/datum/nanite_rule/rule as anything in rules)
+ rule.remove()
+ rules.Cut()
return ..()
/datum/nanite_program/proc/copy()
diff --git a/code/modules/research/nanites/nanite_programs/utility.dm b/code/modules/research/nanites/nanite_programs/utility.dm
index 8eccc0d481b..66c041d6628 100644
--- a/code/modules/research/nanites/nanite_programs/utility.dm
+++ b/code/modules/research/nanites/nanite_programs/utility.dm
@@ -326,7 +326,7 @@
/datum/nanite_program/dermal_button/on_mob_remove()
. = ..()
- qdel(button)
+ QDEL_NULL(button)
/datum/nanite_program/dermal_button/proc/press()
if(activated)
diff --git a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
index 3eea59c696d..c5bc034cba4 100644
--- a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
+++ b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
@@ -467,7 +467,7 @@
for(var/mob/living/simple_animal/slime/S in viewers(1, owner))
if(!(owner in S.Friends))
to_chat(owner, "[linked_extract] pulses gently as it communicates with [S].")
- S.Friends[owner] = 1
+ S.set_friendship(owner, 1)
return ..()
/datum/status_effect/stabilized/orange
diff --git a/code/modules/research/xenobiology/crossbreeding/burning.dm b/code/modules/research/xenobiology/crossbreeding/burning.dm
index 948e5bbaa6a..e817d7b84e4 100644
--- a/code/modules/research/xenobiology/crossbreeding/burning.dm
+++ b/code/modules/research/xenobiology/crossbreeding/burning.dm
@@ -34,7 +34,7 @@ Burning extracts:
/obj/item/slimecross/burning/grey/do_effect(mob/user)
var/mob/living/simple_animal/slime/S = new(get_turf(user),"grey")
S.visible_message("A baby slime emerges from [src], and it nuzzles [user] before burbling hungrily!")
- S.Friends[user] = 20 //Gas, gas, gas
+ S.set_friendship(user, 20) //Gas, gas, gas
S.bodytemperature = T0C + 400 //We gonna step on the gas.
S.set_nutrition(S.get_hunger_nutrition()) //Tonight, we fight!
..()
@@ -198,10 +198,10 @@ Burning extracts:
for(var/mob/living/simple_animal/slime/S in hearers(7, get_turf(user)))
if(user in S.Friends)
var/friendliness = S.Friends[user]
- S.Friends = list()
- S.Friends[user] = friendliness
+ S.clear_friends()
+ S.set_friendship(user, friendliness)
else
- S.Friends = list()
+ S.clear_friends()
S.rabid = 1
S.visible_message("The [S] is driven into a dangerous frenzy!")
..()
diff --git a/code/modules/research/xenobiology/xenobio_camera.dm b/code/modules/research/xenobiology/xenobio_camera.dm
index cf3cb3d240a..5459617ef65 100644
--- a/code/modules/research/xenobiology/xenobio_camera.dm
+++ b/code/modules/research/xenobiology/xenobio_camera.dm
@@ -238,7 +238,7 @@
if(X.monkeys >= 1)
var/mob/living/carbon/monkey/food = new /mob/living/carbon/monkey(remote_eye.loc, TRUE, owner)
if (!QDELETED(food))
- food.LAssailant = C
+ food.LAssailant = WEAKREF(C)
X.monkeys--
X.monkeys = round(X.monkeys, 0.1) //Prevents rounding errors
to_chat(owner, "[X] now has [X.monkeys] monkeys stored.")
@@ -440,7 +440,7 @@
if(X.monkeys >= 1)
var/mob/living/carbon/monkey/food = new /mob/living/carbon/monkey(T, TRUE, C)
if (!QDELETED(food))
- food.LAssailant = C
+ food.LAssailant = WEAKREF(C)
X.monkeys--
X.monkeys = round(X.monkeys, 0.1) //Prevents rounding errors
to_chat(C, "[X] now has [X.monkeys] monkeys stored.")
diff --git a/code/modules/ruins/objects_and_mobs/ash_walker_den.dm b/code/modules/ruins/objects_and_mobs/ash_walker_den.dm
index 30d03404ebf..7024ed91772 100644
--- a/code/modules/ruins/objects_and_mobs/ash_walker_den.dm
+++ b/code/modules/ruins/objects_and_mobs/ash_walker_den.dm
@@ -17,17 +17,26 @@
var/faction = list("ashwalker")
var/meat_counter = 6
var/datum/team/ashwalkers/ashies
+ var/datum/linked_objective
/obj/structure/lavaland/ash_walker/Initialize()
.=..()
ashies = new /datum/team/ashwalkers()
var/datum/objective/protect_object/objective = new
objective.set_target(src)
+ linked_objective = objective
ashies.objectives += objective
for(var/datum/mind/M in ashies.members)
log_objective(M, objective.explanation_text)
START_PROCESSING(SSprocessing, src)
+/obj/structure/lavaland/ash_walker/Destroy()
+ ashies.objectives -= linked_objective
+ ashies = null
+ QDEL_NULL(linked_objective)
+ STOP_PROCESSING(SSprocessing, src)
+ return ..()
+
/obj/structure/lavaland/ash_walker/deconstruct(disassembled)
new /obj/item/assembly/signaler/anomaly (get_step(loc, pick(GLOB.alldirs)))
new /obj/effect/collapse(loc)
diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm
index 31ac823bbf0..955c6e69896 100644
--- a/code/modules/shuttle/emergency.dm
+++ b/code/modules/shuttle/emergency.dm
@@ -737,6 +737,11 @@
SSshuttle.emergency = current_emergency
SSshuttle.backup_shuttle = src
+/obj/docking_port/mobile/emergency/backup/Destroy(force)
+ if(SSshuttle.backup_shuttle == src)
+ SSshuttle.backup_shuttle = null
+ return ..()
+
/obj/docking_port/mobile/emergency/shuttle_build/register()
. = ..()
initiate_docking(SSshuttle.getDock("emergency_home"))
diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm
index a25963393e3..efc273c04f7 100644
--- a/code/modules/shuttle/shuttle.dm
+++ b/code/modules/shuttle/shuttle.dm
@@ -783,8 +783,16 @@
var/range = (engine_coeff * max(width, height))
var/long_range = range * 2.5
var/atom/distant_source
- if(LAZYLEN(engine_list))
- distant_source = engine_list[1]
+ var/list/engines = list()
+ for(var/datum/weakref/engine in engine_list)
+ var/obj/structure/shuttle/engine/real_engine = engine.resolve()
+ if(!real_engine)
+ engine_list -= engine
+ continue
+ engines += real_engine
+
+ if(LAZYLEN(engines))
+ distant_source = engines[1]
else
for(var/A in areas)
distant_source = locate(/obj/machinery/door) in A
@@ -798,11 +806,11 @@
M.playsound_local(distant_source, "sound/effects/[selected_sound]_distance.ogg", 100, falloff = 20)
else if(dist_far <= range)
var/source
- if(engine_list.len == 0)
+ if(engines.len == 0)
source = distant_source
else
var/closest_dist = 10000
- for(var/obj/O in engine_list)
+ for(var/obj/O in engines)
var/dist_near = get_dist(M, O)
if(dist_near < closest_dist)
source = O
@@ -828,7 +836,7 @@
var/area/shuttle/areaInstance = thing
for(var/obj/structure/shuttle/engine/E in areaInstance.contents)
if(!QDELETED(E))
- engine_list += E
+ engine_list += WEAKREF(E)
. += E.engine_power
for(var/obj/machinery/shuttle/engine/E in areaInstance.contents)
if(!QDELETED(E))
diff --git a/code/modules/spells/spell.dm b/code/modules/spells/spell.dm
index 309b6ec7060..1bcf9306d68 100644
--- a/code/modules/spells/spell.dm
+++ b/code/modules/spells/spell.dm
@@ -20,6 +20,12 @@
if(has_action)
action = new base_action(src)
+/obj/effect/proc_holder/Destroy()
+ if(!QDELETED(action))
+ qdel(action)
+ action = null
+ return ..()
+
/obj/effect/proc_holder/proc/on_gain(mob/living/user)
return
diff --git a/code/modules/surgery/organs/augments_arms.dm b/code/modules/surgery/organs/augments_arms.dm
index ea5468ea9a1..8cce69a6fae 100644
--- a/code/modules/surgery/organs/augments_arms.dm
+++ b/code/modules/surgery/organs/augments_arms.dm
@@ -211,7 +211,7 @@
. = ..()
if(locate(/obj/item/assembly/flash/armimplant) in items_list)
var/obj/item/assembly/flash/armimplant/F = locate(/obj/item/assembly/flash/armimplant) in items_list
- F.I = src
+ F.arm = WEAKREF(src)
/obj/item/organ/cyberimp/arm/baton
name = "arm electrification implant"
@@ -227,7 +227,7 @@
. = ..()
if(locate(/obj/item/assembly/flash/armimplant) in items_list)
var/obj/item/assembly/flash/armimplant/F = locate(/obj/item/assembly/flash/armimplant) in items_list
- F.I = src
+ F.arm = WEAKREF(src)
/obj/item/organ/cyberimp/arm/surgery
name = "surgical toolset implant"
diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm
index 581ed62a95a..00f444d16bd 100644
--- a/code/modules/vending/_vending.dm
+++ b/code/modules/vending/_vending.dm
@@ -64,7 +64,7 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
var/vend_ready = TRUE
///Next world time to send a purchase message
var/purchase_message_cooldown
- ///Last mob to shop with us
+ ///The ref of the last mob to shop with us
var/last_shopper
var/tilted = FALSE
var/tiltable = TRUE
@@ -777,10 +777,11 @@ GLOBAL_LIST_EMPTY(vending_products)
var/datum/bank_account/D = SSeconomy.get_dep_account(payment_department)
if(D)
D.adjust_money(price_to_use)
- if(last_shopper != usr || purchase_message_cooldown < world.time)
+ if(last_shopper != REF(usr) || purchase_message_cooldown < world.time)
say("Thank you for shopping with [src]!")
purchase_message_cooldown = world.time + 5 SECONDS
- last_shopper = usr
+ //This is not the best practice, but it's safe enough here since the chances of two people using a machine with the same ref in 5 seconds is fuck low
+ last_shopper = REF(usr)
use_power(5)
if(icon_vend) //Show the vending animation if needed
flick(icon_vend,src)
@@ -1025,10 +1026,10 @@ GLOBAL_LIST_EMPTY(vending_products)
S.forceMove(drop_location())
loaded_items--
use_power(5)
- if(last_shopper != usr || purchase_message_cooldown < world.time)
+ if(last_shopper != REF(usr) || purchase_message_cooldown < world.time)
say("Thank you for buying local and purchasing [S]!")
purchase_message_cooldown = world.time + 5 SECONDS
- last_shopper = usr
+ last_shopper = REF(usr)
vend_ready = TRUE
updateUsrDialog()
return
diff --git a/code/modules/zombie/organs.dm b/code/modules/zombie/organs.dm
index fd5b3b71c5e..01439476699 100644
--- a/code/modules/zombie/organs.dm
+++ b/code/modules/zombie/organs.dm
@@ -30,7 +30,7 @@
/obj/item/organ/zombie_infection/Remove(mob/living/carbon/M, special = 0)
. = ..()
STOP_PROCESSING(SSobj, src)
- if(iszombie(M) && old_species)
+ if(iszombie(M) && old_species && !QDELETED(M))
M.set_species(old_species)
if(timer_id)
deltimer(timer_id)