diff --git a/code/datums/datum.dm b/code/datums/datum.dm index 675c607a32fd..a2d370e2ee68 100644 --- a/code/datums/datum.dm +++ b/code/datums/datum.dm @@ -100,21 +100,26 @@ if(dc) var/all_components = dc[/datum/component] if(length(all_components)) - for(var/I in all_components) - var/datum/component/C = I - qdel(C, FALSE, TRUE) + for(var/datum/component/component as anything in all_components) + qdel(component, FALSE, TRUE) else var/datum/component/C = all_components qdel(C, FALSE, TRUE) dc.Cut() + clear_signal_refs() + + return QDEL_HINT_QUEUE + +///Only override this if you know what you're doing. You do not know what you're doing +///This is a threat +/datum/proc/clear_signal_refs() var/list/lookup = comp_lookup if(lookup) for(var/sig in lookup) var/list/comps = lookup[sig] if(length(comps)) - for(var/i in comps) - var/datum/component/comp = i + for(var/datum/component/comp as anything in comps) comp.UnregisterSignal(src, sig) else var/datum/component/comp = comps @@ -124,8 +129,6 @@ for(var/target in signal_procs) UnregisterSignal(target, signal_procs[target]) - return QDEL_HINT_QUEUE - #ifdef DATUMVAR_DEBUGGING_MODE /datum/proc/save_vars() cached_vars = list() diff --git a/code/datums/hud.dm b/code/datums/hud.dm index ed584a1fd640..fcd6187cec1f 100644 --- a/code/datums/hud.dm +++ b/code/datums/hud.dm @@ -65,14 +65,17 @@ GLOBAL_LIST_INIT(huds, list( GLOB.all_huds -= src return ..() -/datum/atom_hud/proc/remove_hud_from(mob/M) // this is called when something disables HUD +/datum/atom_hud/proc/remove_hud_from(mob/M, absolute = FALSE) if(!M || !hudusers[M]) return - if (!--hudusers[M]) + if (absolute || !--hudusers[M]) + UnregisterSignal(M, COMSIG_PARENT_QDELETING) var/M_is_silicon = FALSE if(do_silicon_check && istype(M, /mob/living/silicon)) M_is_silicon = TRUE hudusers -= M + if(next_time_allowed[M]) + next_time_allowed -= M if(queued_to_see[M]) queued_to_see -= M else @@ -111,6 +114,7 @@ GLOBAL_LIST_INIT(huds, list( return if(!hudusers[M]) hudusers[M] = 1 + RegisterSignal(M, COMSIG_PARENT_QDELETING, .proc/unregister_mob) var/M_is_silicon = FALSE if(do_silicon_check && istype(M, /mob/living/silicon)) M_is_silicon = TRUE @@ -130,6 +134,10 @@ GLOBAL_LIST_INIT(huds, list( else hudusers[M]++ // the hell does this do? +/datum/atom_hud/proc/unregister_mob(datum/source, force) + SIGNAL_HANDLER + remove_hud_from(source, TRUE) + /datum/atom_hud/proc/show_hud_images_after_cooldown(M, M_is_silicon) if(queued_to_see[M]) queued_to_see -= M diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 0b9d19a3b5d6..737800201d60 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -89,15 +89,16 @@ /// The timer for the afk verb var/afk_verb_timer -/datum/mind/New(key) - src.key = key +/datum/mind/New(_key) + key = _key soulOwner = src martial_art = default_martial_art /datum/mind/Destroy() SSticker.minds -= src - if(islist(antag_datums)) - QDEL_LIST(antag_datums) + QDEL_NULL(antag_hud) + QDEL_LIST(antag_datums) + QDEL_NULL(language_holder) current = null soulOwner = null return ..() diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index 2eda8fda45eb..cca3ec421390 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -263,6 +263,7 @@ GLOBAL_LIST_EMPTY(teleportlocs) /area/Destroy() if(GLOB.areas_by_type[type] == src) GLOB.areas_by_type[type] = null + GLOB.sortedAreas -= src GLOB.areas -= src STOP_PROCESSING(SSobj, src) return ..() diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 05998096900e..02f7a821db3c 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -206,16 +206,18 @@ */ /atom/Destroy() if(alternate_appearances) - for(var/K in alternate_appearances) - var/datum/atom_hud/alternate_appearance/AA = alternate_appearances[K] - AA.remove_from_hud(src) + for(var/current_alternate_appearance in alternate_appearances) + var/datum/atom_hud/alternate_appearance/selected_alternate_appearance = alternate_appearances[current_alternate_appearance] + selected_alternate_appearance.remove_from_hud(src) if(reagents) qdel(reagents) orbiters = null // The component is attached to us normaly and will be deleted elsewhere - LAZYCLEARLIST(overlays) + // Checking length(overlays) before cutting has significant speed benefits + if (length(overlays)) + overlays.Cut() LAZYCLEARLIST(priority_overlays) for(var/i in targeted_by) @@ -225,6 +227,8 @@ targeted_by = null QDEL_NULL(light) + if (length(light_sources)) + light_sources.Cut() return ..() diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index e2cb40222a83..74e0f3b3f888 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -72,9 +72,45 @@ if(light_system == MOVABLE_LIGHT) AddComponent(/datum/component/overlay_lighting) -/atom/movable/Destroy() +/atom/movable/Destroy(force) + QDEL_NULL(proximity_monitor) + QDEL_NULL(language_holder) QDEL_NULL(em_block) - return ..() + + unbuckle_all_mobs(force = TRUE) + + if(loc) + //Restore air flow if we were blocking it (movables with ATMOS_PASS_PROC will need to do this manually if necessary) + if(((CanAtmosPass == ATMOS_PASS_DENSITY && density) || CanAtmosPass == ATMOS_PASS_NO) && isturf(loc)) + CanAtmosPass = ATMOS_PASS_YES + air_update_turf(TRUE) + loc.handle_atom_del(src) + + invisibility = INVISIBILITY_ABSTRACT + + if(pulledby) + pulledby.stop_pulling() + if(pulling) + stop_pulling() + + if(orbiting) + orbiting.end_orbit(src) + orbiting = null + + LAZYCLEARLIST(client_mobs_in_contents) + + . = ..() + + for(var/movable_content in contents) + qdel(movable_content) + + moveToNullspace() + + vis_locs = null //clears this atom out of all viscontents + + // Checking length(vis_contents) before cutting has significant speed benefits + if (length(vis_contents)) + vis_contents.Cut() /atom/movable/proc/update_emissive_block() if(blocks_emissive != EMISSIVE_BLOCK_GENERIC) @@ -438,30 +474,6 @@ SSdemo.mark_dirty(src) return TRUE -/atom/movable/Destroy(force) - QDEL_NULL(proximity_monitor) - QDEL_NULL(language_holder) - - unbuckle_all_mobs(force=1) - - . = ..() - if(loc) - //Restore air flow if we were blocking it (movables with ATMOS_PASS_PROC will need to do this manually if necessary) - if(((CanAtmosPass == ATMOS_PASS_DENSITY && density) || CanAtmosPass == ATMOS_PASS_NO) && isturf(loc)) - CanAtmosPass = ATMOS_PASS_YES - air_update_turf(TRUE) - loc.handle_atom_del(src) - for(var/atom/movable/AM in contents) - qdel(AM) - moveToNullspace() - invisibility = INVISIBILITY_ABSTRACT - if(pulledby) - pulledby.stop_pulling() - - if(orbiting) - orbiting.end_orbit(src) - orbiting = null - // Make sure you know what you're doing if you call this, this is intended to only be called by byond directly. // You probably want CanPass() /atom/movable/Cross(atom/movable/AM) diff --git a/code/game/objects/effects/anomalies.dm b/code/game/objects/effects/anomalies.dm index e81b9c49fbea..96b0f0e59d2f 100644 --- a/code/game/objects/effects/anomalies.dm +++ b/code/game/objects/effects/anomalies.dm @@ -52,7 +52,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/chrono_eraser.dm b/code/game/objects/items/chrono_eraser.dm index 04bde957dc2c..f63991f4e6f3 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 3c43eb22354c..8fe070b1f720 100644 --- a/code/game/objects/items/devices/transfer_valve.dm +++ b/code/game/objects/items/devices/transfer_valve.dm @@ -14,6 +14,10 @@ var/valve_open = FALSE var/toggle = TRUE +/obj/item/transfer_valve/Destroy() + attached_device = null + return ..() + /obj/item/transfer_valve/IsAssemblyHolder() return TRUE @@ -246,4 +250,4 @@ attached_device = null . = TRUE - update_icon() \ No newline at end of file + update_icon() diff --git a/code/game/objects/items/melee/energy.dm b/code/game/objects/items/melee/energy.dm index 60e92e1eb62e..078a5ea37e97 100644 --- a/code/game/objects/items/melee/energy.dm +++ b/code/game/objects/items/melee/energy.dm @@ -229,6 +229,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 693c58b52b54..cea0e2f1d07d 100644 --- a/code/game/objects/items/melee/misc.dm +++ b/code/game/objects/items/melee/misc.dm @@ -498,7 +498,7 @@ if(!iscarbon(user)) target.LAssailant = null else - target.LAssailant = user + target.LAssailant = WEAKREF(user) cooldown_check = world.time + cooldown /obj/item/melee/classic_baton/telescopic/contractor_baton/get_wait_description() diff --git a/code/game/objects/structures/beds_chairs/bed.dm b/code/game/objects/structures/beds_chairs/bed.dm index cf9ed1e2d3ed..fc54ef127227 100644 --- a/code/game/objects/structures/beds_chairs/bed.dm +++ b/code/game/objects/structures/beds_chairs/bed.dm @@ -173,7 +173,7 @@ anchored = FALSE buildstacktype = /obj/item/stack/sheet/mineral/wood buildstackamount = 10 - var/mob/living/owner = null + var/owned = FALSE /obj/structure/bed/dogbed/ian desc = "Ian's bed! Looks comfy." @@ -200,10 +200,14 @@ name = "Birdboat's bed" anchored = TRUE +///Used to set the owner of a dogbed, returns FALSE if called on an owned bed or an invalid one, TRUE if the possesion succeeds /obj/structure/bed/dogbed/proc/update_owner(mob/living/M) - owner = M + if(owned || type != /obj/structure/bed/dogbed) //Only marked beds work, this is hacky but I'm a hacky man + return FALSE //Failed + owned = TRUE name = "[M]'s bed" desc = "[M]'s bed! Looks comfy." + return TRUE //Let any callers know that this bed is ours now /obj/structure/bed/dogbed/buckle_mob(mob/living/M, force, check_loc) . = ..() diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index d3b970f48426..7b6461a976ee 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -121,6 +121,13 @@ GLOBAL_LIST_EMPTY(station_turfs) requires_activation = FALSE ..() +/// WARNING WARNING +/// Turfs DO NOT lose their signals when they get replaced, REMEMBER THIS +/// It's possible because turfs are fucked, and if you have one in a list and it's replaced with another one, the list ref points to the new turf +/// We do it because moving signals over was needlessly expensive, and bloated a very commonly used bit of code +/turf/clear_signal_refs() + return + /turf/attack_hand(mob/user) . = ..() if(SEND_SIGNAL(user, COMSIG_MOB_ATTACK_HAND_TURF, src) & COMPONENT_NO_ATTACK_HAND) diff --git a/code/modules/antagonists/abductor/equipment/gland.dm b/code/modules/antagonists/abductor/equipment/gland.dm index 94d40e5f71a7..4bb9d1a76549 100644 --- a/code/modules/antagonists/abductor/equipment/gland.dm +++ b/code/modules/antagonists/abductor/equipment/gland.dm @@ -148,8 +148,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 ad439d962de2..87e87ba24c67 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 point_rate = point_rate * overmind.basemodifier diff --git a/code/modules/antagonists/blob/overmind.dm b/code/modules/antagonists/blob/overmind.dm index 0b2255a11b27..4c4f8013620d 100644 --- a/code/modules/antagonists/blob/overmind.dm +++ b/code/modules/antagonists/blob/overmind.dm @@ -175,6 +175,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/disease/disease_disease.dm b/code/modules/antagonists/disease/disease_disease.dm index b4b8ac095606..802d7209ac9c 100644 --- a/code/modules/antagonists/disease/disease_disease.dm +++ b/code/modules/antagonists/disease/disease_disease.dm @@ -12,6 +12,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 13cf0085f31d..04373100feca 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/assembly/assembly.dm b/code/modules/assembly/assembly.dm index 8cedba9b8188..f3a0fab4bf22 100644 --- a/code/modules/assembly/assembly.dm +++ b/code/modules/assembly/assembly.dm @@ -28,6 +28,10 @@ var/next_activate = 0 //When we're next allowed to activate - for spam control +/obj/item/assembly/Destroy() + holder = null + return ..() + /obj/item/assembly/get_part_rating() return 1 @@ -132,4 +136,4 @@ return src /obj/item/assembly/ui_state(mob/user) - return GLOB.hands_state \ No newline at end of file + return GLOB.hands_state diff --git a/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm b/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm index b342b60c0a53..6651e9376774 100644 --- a/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm +++ b/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm @@ -24,11 +24,9 @@ return 1 /obj/machinery/portable_atmospherics/Destroy() - SSair.atmos_machinery -= src - disconnect() - qdel(air_contents) - air_contents = null + QDEL_NULL(air_contents) + SSair.atmos_machinery -= src return ..() diff --git a/code/modules/awaymissions/mission_code/Cabin.dm b/code/modules/awaymissions/mission_code/Cabin.dm index a13fecd11c45..73b975fad814 100644 --- a/code/modules/awaymissions/mission_code/Cabin.dm +++ b/code/modules/awaymissions/mission_code/Cabin.dm @@ -25,7 +25,7 @@ var/active = 1 /obj/structure/firepit/Initialize() - ..() + . = ..() toggleFirepit() /obj/structure/firepit/interact(mob/living/user) diff --git a/code/modules/clothing/spacesuits/chronosuit.dm b/code/modules/clothing/spacesuits/chronosuit.dm index 1fbb99fff725..cd5500a57579 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) @@ -330,6 +331,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 2e741ece5a85..12b65fcc2749 100644 --- a/code/modules/clothing/spacesuits/hardsuit.dm +++ b/code/modules/clothing/spacesuits/hardsuit.dm @@ -1030,11 +1030,7 @@ allowed = list(/obj/item/gun, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/melee/transforming/energy/sword/saber, /obj/item/restraints/handcuffs, /obj/item/tank/internals) helmettype = /obj/item/clothing/head/helmet/space/hardsuit/shielded/syndi slowdown = 0 - - -/obj/item/clothing/suit/space/hardsuit/shielded/syndi/Initialize() - jetpack = new /obj/item/tank/jetpack/suit(src) - . = ..() + jetpack = /obj/item/tank/jetpack/suit /obj/item/clothing/head/helmet/space/hardsuit/shielded/syndi name = "blood-red hardsuit helmet" diff --git a/code/modules/clothing/suits/toggles.dm b/code/modules/clothing/suits/toggles.dm index 9eca99872dc3..6aaa9e659514 100644 --- a/code/modules/clothing/suits/toggles.dm +++ b/code/modules/clothing/suits/toggles.dm @@ -130,11 +130,11 @@ . = ..() /obj/item/clothing/suit/space/hardsuit/Destroy() - if(helmet) + if(!QDELETED(helmet)) helmet.suit = null - qdel(helmet) + QDEL_NULL(helmet) if(jetpack && istype(jetpack)) - qdel(jetpack) + QDEL_NULL(jetpack) return ..() /obj/item/clothing/head/helmet/space/hardsuit/Destroy() diff --git a/code/modules/fields/timestop.dm b/code/modules/fields/timestop.dm index ff173ea30a02..9315125f984e 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) return ..() /obj/effect/timestop/proc/timestop() diff --git a/code/modules/food_and_drinks/kitchen_machinery/food_cart.dm b/code/modules/food_and_drinks/kitchen_machinery/food_cart.dm index ddd6e1059a0e..962a8de3756b 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/food_cart.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/food_cart.dm @@ -25,6 +25,7 @@ /obj/machinery/food_cart/Destroy() QDEL_NULL(mixer) + stored_food.Cut() return ..() /obj/machinery/food_cart/ui_interact(mob/user) diff --git a/code/modules/mining/laborcamp/laborstacker.dm b/code/modules/mining/laborcamp/laborstacker.dm index d5a9dae906d6..a237ac07db67 100644 --- a/code/modules/mining/laborcamp/laborstacker.dm +++ b/code/modules/mining/laborcamp/laborstacker.dm @@ -31,6 +31,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"] @@ -109,9 +116,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 a6420f1322f0..7d9c342d81ad 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -340,6 +340,12 @@ GLOBAL_LIST_EMPTY(aide_list) 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) var/turf/current_location = get_turf(user)//yogs added a current location check that was totally ripped from the hand tele code honk var/area/current_area = current_location.loc //yogs more location check stuff diff --git a/code/modules/mining/machine_stacking.dm b/code/modules/mining/machine_stacking.dm index cb80b0b9024c..20897fa7dab2 100644 --- a/code/modules/mining/machine_stacking.dm +++ b/code/modules/mining/machine_stacking.dm @@ -14,7 +14,7 @@ . = ..() 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/ui_interact(mob/user) . = ..() @@ -84,7 +84,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. @@ -177,8 +177,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) && !panel_open) - CONSOLE = M.buffer - CONSOLE.machine = src + console = M.buffer + console.machine = src to_chat(user, span_notice("You link [src] to the console in [M]'s buffer.")) return TRUE if(panel_open) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 00b8128aec36..48f262b3dd03 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -164,6 +164,13 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 10) /mob/dead/observer/Destroy() + if(data_huds_on) + remove_data_huds() + + // Update our old body's medhud since we're abandoning it + if(isliving(mind?.current)) + mind.current.med_hud_set_status() + GLOB.ghost_images_default -= ghostimage_default QDEL_NULL(ghostimage_default) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index fd88a3e01862..03d830dcf87f 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -25,21 +25,23 @@ med_hud_set_status() /mob/living/Destroy() - if(LAZYLEN(status_effects)) - for(var/s in status_effects) - var/datum/status_effect/S = s - if(S.on_remove_on_mob_delete) //the status effect calls on_remove when its mob is deleted - qdel(S) - else - S.be_replaced() + for(var/datum/status_effect/effect as anything in status_effects) + // The status effect calls on_remove when its mob is deleted + if(effect.on_remove_on_mob_delete) + qdel(effect) + else + effect.be_replaced() + if(ranged_ability) ranged_ability.remove_ranged_ability(src) + if(buckled) buckled.unbuckle_mob(src,force=1) remove_from_all_data_huds() GLOB.mob_living_list -= src QDEL_LIST(diseases) + QDEL_LIST(surgeries) return ..() /mob/living/onZImpact(turf/T, levels) @@ -283,7 +285,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/simple_animal/friendly/dog.dm b/code/modules/mob/living/simple_animal/friendly/dog.dm index dfafac7bd495..e4cfa4fd0a3f 100644 --- a/code/modules/mob/living/simple_animal/friendly/dog.dm +++ b/code/modules/mob/living/simple_animal/friendly/dog.dm @@ -123,8 +123,7 @@ . = ..() var/dog_area = get_area(src) for(var/obj/structure/bed/dogbed/D in dog_area) - if(!D.owner) - D.update_owner(src) + if(D.update_owner(src)) //No muscling in on my turf you fucking parrot break /mob/living/simple_animal/pet/dog/corgi/Initialize() diff --git a/code/modules/mob/living/simple_animal/slime/life.dm b/code/modules/mob/living/simple_animal/slime/life.dm index 9227bfa32e0c..987dd9580d15 100644 --- a/code/modules/mob/living/simple_animal/slime/life.dm +++ b/code/modules/mob/living/simple_animal/slime/life.dm @@ -51,13 +51,13 @@ break if(Target.health <= -70 || Target.stat == DEAD) - Target = null + set_target(null) AIproc = 0 break if(Target) if(locate(/mob/living/simple_animal/slime) in Target.buckled_mobs) - Target = null + set_target(null) AIproc = 0 break if(!AIproc) @@ -97,7 +97,7 @@ // Bug of the month candidate: slimes were attempting to move to target only if it was directly next to them, which caused them to target things, but not approach them step_to(src, Target) else - Target = null + set_target(null) AIproc = 0 break @@ -188,12 +188,10 @@ if(M.stat == DEAD) // our victim died if(!client) if(!rabid && !attacked) - if(M.LAssailant && M.LAssailant != M) + var/mob/last_to_hurt = M.LAssailant?.resolve() + if(last_to_hurt && last_to_hurt != M) if(prob(50)) - if(!(M.LAssailant in Friends)) - Friends[M.LAssailant] = 1 - else - ++Friends[M.LAssailant] + add_friendship(last_to_hurt, 1) else to_chat(src, "This subject does not have a strong enough life energy anymore...") @@ -309,7 +307,7 @@ --target_patience if (target_patience <= 0 || SStun > world.time || Discipline || attacked || docile) // Tired of chasing or something draws out attention target_patience = 0 - Target = null + set_target(null) if(AIproc && SStun > world.time) return @@ -324,7 +322,7 @@ if(hungry == 2 && !client) // if a slime is starving, it starts losing its friends 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) // Only add to the list if we need to @@ -363,16 +361,16 @@ if(targets.len > 0) if(attacked || rabid || hungry == 2) - Target = targets[1] // I am attacked and am fighting back or so hungry I don't even care + set_target(targets[1]) // I am attacked and am fighting back or so hungry I don't even care else for(var/mob/living/carbon/C in targets) if(!Discipline && prob(5)) if(ishuman(C) || isalienadult(C)) - Target = C + set_target(C) break if(islarva(C) || ismonkey(C)) - Target = C + set_target(C) break if (Target) @@ -446,13 +444,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...") @@ -460,27 +458,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_target(null) else if (Friends[who] > Friends[Leader]) - Leader = null + set_target(null) to_say = "Yes... I stop..." else to_say = "No... keep follow..." @@ -502,7 +500,7 @@ to_say = "No... won't stay..." else if (findtext(phrase, "attack")) if (rabid && prob(20)) - Target = who + set_target(who) AIprocess() //Wake up the slime's Target AI, needed otherwise this doesn't work to_say = "ATTACK!?!?" else if (Friends[who] >= SLIME_FRIENDSHIP_ATTACK) @@ -510,14 +508,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) AIprocess()//Wake up the slime's Target AI, needed otherwise this doesn't work 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/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm index a8925dcf5067..8063901c9f93 100644 --- a/code/modules/mob/living/simple_animal/slime/slime.dm +++ b/code/modules/mob/living/simple_animal/slime/slime.dm @@ -1,3 +1,5 @@ +#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' @@ -107,6 +109,9 @@ for (var/A in actions) var/datum/action/AC = A AC.Remove(src) + set_target(null) + set_leader(null) + clear_friends() return ..() /mob/living/simple_animal/slime/proc/set_colour(new_colour) @@ -362,10 +367,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, span_notice("You feed the slime the plasma. It chirps happily.")) var/obj/item/stack/sheet/mineral/plasma/S = W S.use(1) @@ -433,7 +435,7 @@ adjustBruteLoss(rand(15,20)) if(!client) if(Target) // Like cats - Target = null + set_target(null) ++Discipline return @@ -478,8 +480,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. @@ -509,5 +510,57 @@ /mob/living/simple_animal/slime/can_be_implanted() return TRUE +/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) + /mob/living/simple_animal/slime/random/Initialize(mapload, new_colour, new_is_adult) . = ..(mapload, pick(slime_colours), prob(50)) + +#undef SLIME_CARES_ABOUT diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 64eb236d53fb..ef8b98a61fb6 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -26,20 +26,29 @@ remove_from_mob_list() remove_from_dead_mob_list() remove_from_alive_mob_list() + remove_from_mob_suicide_list() + focus = null + + if(length(progressbars)) + stack_trace("[src] destroyed with elements in its progressbars list") + progressbars = null + for (var/alert in alerts) clear_alert(alert, TRUE) - if(observers && observers.len) - for(var/M in observers) - var/mob/dead/observe = M + + if(observers?.len) + for(var/mob/dead/observe as anything in observers) observe.reset_perspective(null) + qdel(hud_used) - for(var/cc in client_colours) - qdel(cc) - client_colours = null - ghostize() - ..() - return QDEL_HINT_HARDDEL + QDEL_LIST(client_colours) + ghostize() //False, since we're deleting it currently + + 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.current = null + + return ..() /** * Intialize a mob diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index d679cffe647d..56355ba108fc 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -151,8 +151,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 4f71e110dd96..a598d6be8155 100644 --- a/code/modules/mob/mob_lists.dm +++ b/code/modules/mob/mob_lists.dm @@ -20,6 +20,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() @@ -116,4 +123,4 @@ /mob/proc/remove_from_current_living_antags() if(!SSticker?.mode) return - SSticker.mode.current_players[CURRENT_LIVING_ANTAGS] -= src \ No newline at end of file + SSticker.mode.current_players[CURRENT_LIVING_ANTAGS] -= src diff --git a/code/modules/reagents/reagent_containers/borghypo.dm b/code/modules/reagents/reagent_containers/borghypo.dm index 6173adaa4a85..a922925a8c9f 100644 --- a/code/modules/reagents/reagent_containers/borghypo.dm +++ b/code/modules/reagents/reagent_containers/borghypo.dm @@ -45,6 +45,7 @@ Borg Hypospray /obj/item/reagent_containers/borghypo/Destroy() STOP_PROCESSING(SSobj, src) + QDEL_LIST(reagent_list) return ..() diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm index e090782ce478..bab1c389c7b8 100644 --- a/code/modules/recycling/disposal/bin.dm +++ b/code/modules/recycling/disposal/bin.dm @@ -139,7 +139,7 @@ else target.visible_message(span_danger("[user] has placed [target] in [src]."), span_userdanger("[user] has placed [target] 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/xenobiology/crossbreeding/_status_effects.dm b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm index 95060195193b..6fb88510d445 100644 --- a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm +++ b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm @@ -469,7 +469,7 @@ datum/status_effect/rebreathing/tick() for(var/mob/living/simple_animal/slime/S in range(1, get_turf(owner))) if(!(owner in S.Friends)) to_chat(owner, span_notice("[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 292d61e4063e..82cc1c8391c4 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(span_danger("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! ..() @@ -200,10 +200,10 @@ Burning extracts: for(var/mob/living/simple_animal/slime/S in view(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(span_danger("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 05c578a24066..15e66e7416fa 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/yogstation/code/datums/antagonists/vampire.dm b/yogstation/code/datums/antagonists/vampire.dm index 24daa794f63c..f98fafa70f25 100644 --- a/yogstation/code/datums/antagonists/vampire.dm +++ b/yogstation/code/datums/antagonists/vampire.dm @@ -268,7 +268,7 @@ if(!iscarbon(owner)) H.LAssailant = null else - H.LAssailant = O + H.LAssailant = WEAKREF(O) while(do_mob(O, H, 50)) if(!is_vampire(O)) to_chat(O, span_warning("Your fangs have disappeared!"))