diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm index d3d35ac4ddf..d775224a6a2 100644 --- a/code/_onclick/hud/robot.dm +++ b/code/_onclick/hud/robot.dm @@ -300,6 +300,11 @@ icon_state = "[base_icon_state]_[robot?.lamp_enabled ? "on" : "off"]" return ..() +/atom/movable/screen/robot/lamp/Destroy() + robot.lampButton = null + robot = null + return ..() + /atom/movable/screen/robot/modPC name = "Modular Interface" icon_state = "template" @@ -311,6 +316,11 @@ return robot.modularInterface?.interact(robot) +/atom/movable/screen/robot/modPC/Destroy() + robot.interfaceButton = null + robot = null + return ..() + /atom/movable/screen/robot/alerts name = "Alert Panel" icon = 'icons/hud/screen_ai.dmi' diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm index 499278ca176..1ca37d04882 100644 --- a/code/_onclick/observer.dm +++ b/code/_onclick/observer.dm @@ -76,6 +76,12 @@ return ..() /obj/machinery/teleport/hub/attack_ghost(mob/user) - if(power_station?.engaged && power_station.teleporter_console && power_station.teleporter_console.target) - user.abstract_move(get_turf(power_station.teleporter_console.target)) - return ..() + if(!power_station?.engaged || !power_station.teleporter_console || !power_station.teleporter_console.target_ref) + return ..() + + var/atom/target = power_station.teleporter_console.target_ref.resolve() + if(!target) + power_station.teleporter_console.target_ref = null + return ..() + + user.abstract_move(get_turf(target)) diff --git a/code/controllers/subsystem/icon_smooth.dm b/code/controllers/subsystem/icon_smooth.dm index 2979a2645e5..ec941f9b18c 100644 --- a/code/controllers/subsystem/icon_smooth.dm +++ b/code/controllers/subsystem/icon_smooth.dm @@ -47,7 +47,7 @@ SUBSYSTEM_DEF(icon_smooth) CHECK_TICK queue = blueprint_queue - blueprint_queue = list() + blueprint_queue = null for(var/item in queue) var/atom/movable/movable_item = item @@ -70,5 +70,6 @@ SUBSYSTEM_DEF(icon_smooth) /datum/controller/subsystem/icon_smooth/proc/remove_from_queues(atom/thing) thing.smoothing_flags &= ~SMOOTH_QUEUED smooth_queue -= thing - blueprint_queue -= thing + if(blueprint_queue) + blueprint_queue -= thing deferred -= thing diff --git a/code/controllers/subsystem/throwing.dm b/code/controllers/subsystem/throwing.dm index 16374fbd201..6b3ab2ccf9b 100644 --- a/code/controllers/subsystem/throwing.dm +++ b/code/controllers/subsystem/throwing.dm @@ -42,7 +42,6 @@ SUBSYSTEM_DEF(throwing) /datum/thrownthing var/atom/movable/thrownthing - var/atom/target var/turf/target_turf var/target_zone var/init_dir @@ -66,11 +65,10 @@ SUBSYSTEM_DEF(throwing) var/last_move = 0 -/datum/thrownthing/New(thrownthing, target, target_turf, init_dir, maxrange, speed, thrower, diagonals_first, force, gentle, callback, target_zone) +/datum/thrownthing/New(thrownthing, target_turf, init_dir, maxrange, speed, thrower, diagonals_first, force, gentle, callback, target_zone) . = ..() src.thrownthing = thrownthing RegisterSignal(thrownthing, COMSIG_PARENT_QDELETING, .proc/on_thrownthing_qdel) - src.target = target src.target_turf = target_turf src.init_dir = init_dir src.maxrange = maxrange @@ -88,7 +86,6 @@ SUBSYSTEM_DEF(throwing) SSthrowing.currentrun -= thrownthing thrownthing.throwing = null thrownthing = null - target = null thrower = null if(callback) QDEL_NULL(callback) //It stores a reference to the thrownthing, its source. Let's clean that. diff --git a/code/datums/brain_damage/split_personality.dm b/code/datums/brain_damage/split_personality.dm index 756903fa5ce..5efe286e0f8 100644 --- a/code/datums/brain_damage/split_personality.dm +++ b/code/datums/brain_damage/split_personality.dm @@ -58,6 +58,13 @@ QDEL_NULL(owner_backseat) ..() +/datum/brain_trauma/severe/split_personality/Destroy() + if(stranger_backseat) + QDEL_NULL(stranger_backseat) + if(owner_backseat) + QDEL_NULL(owner_backseat) + return ..() + /datum/brain_trauma/severe/split_personality/proc/switch_personalities(reset_to_owner = FALSE) if(QDELETED(owner) || QDELETED(stranger_backseat) || QDELETED(owner_backseat)) return diff --git a/code/datums/components/chasm.dm b/code/datums/components/chasm.dm index 68c8daea7aa..74f916d9785 100644 --- a/code/datums/components/chasm.dm +++ b/code/datums/components/chasm.dm @@ -4,7 +4,8 @@ var/fall_message = "GAH! Ah... where are you?" var/oblivion_message = "You stumble and stare into the abyss before you. It stares back, and you fall into the enveloping dark." - var/static/list/falling_atoms = list() // Atoms currently falling into chasms + /// List of refs to falling objects -> how many levels deep we've fallen + var/static/list/falling_atoms = list() var/static/list/forbidden_types = typecacheof(list( /obj/singularity, /obj/energy_ball, @@ -54,7 +55,6 @@ return LAZYLEN(found_safeties) /datum/component/chasm/proc/drop_stuff(AM) - . = 0 if (is_safe()) return FALSE @@ -62,12 +62,13 @@ var/to_check = AM ? list(AM) : parent.contents for (var/thing in to_check) if (droppable(thing)) - . = 1 + . = TRUE INVOKE_ASYNC(src, .proc/drop, thing) /datum/component/chasm/proc/droppable(atom/movable/AM) + var/datum/weakref/falling_ref = WEAKREF(AM) // avoid an infinite loop, but allow falling a large distance - if(falling_atoms[AM] && falling_atoms[AM] > 30) + if(falling_atoms[falling_ref] && falling_atoms[falling_ref] > 30) return FALSE if(!isliving(AM) && !isobj(AM)) return FALSE @@ -91,10 +92,12 @@ return TRUE /datum/component/chasm/proc/drop(atom/movable/AM) + var/datum/weakref/falling_ref = WEAKREF(AM) //Make sure the item is still there after our sleep - if(!AM || QDELETED(AM)) + if(!AM || !falling_ref?.resolve()) + falling_atoms -= falling_ref return - falling_atoms[AM] = (falling_atoms[AM] || 0) + 1 + falling_atoms[falling_ref] = (falling_atoms[falling_ref] || 0) + 1 var/turf/T = target_turf if(T) @@ -106,7 +109,7 @@ var/mob/living/L = AM L.Paralyze(100) L.adjustBruteLoss(30) - falling_atoms -= AM + falling_atoms -= falling_ref else // send to oblivion @@ -135,7 +138,7 @@ var/mob/living/silicon/robot/S = AM qdel(S.mmi) - falling_atoms -= AM + falling_atoms -= falling_ref qdel(AM) if(AM && !QDELETED(AM)) //It's indestructible var/atom/parent = src.parent diff --git a/code/datums/elements/weather_listener.dm b/code/datums/elements/weather_listener.dm index 956a355d97b..c5a568a480c 100644 --- a/code/datums/elements/weather_listener.dm +++ b/code/datums/elements/weather_listener.dm @@ -24,8 +24,8 @@ weather_trait = trait playlist = weather_playlist - RegisterSignal(target, COMSIG_MOVABLE_Z_CHANGED, .proc/handle_z_level_change) - RegisterSignal(target, COMSIG_MOB_LOGOUT, .proc/handle_logout) + RegisterSignal(target, COMSIG_MOVABLE_Z_CHANGED, .proc/handle_z_level_change, override = TRUE) + RegisterSignal(target, COMSIG_MOB_LOGOUT, .proc/handle_logout, override = TRUE) /datum/element/weather_listener/Detach(datum/source) . = ..() diff --git a/code/datums/holocall.dm b/code/datums/holocall.dm index 1702bafcaa6..c165ae480df 100644 --- a/code/datums/holocall.dm +++ b/code/datums/holocall.dm @@ -81,6 +81,7 @@ if(!QDELETED(hologram)) hologram.HC = null QDEL_NULL(hologram) + hologram = null for(var/I in dialed_holopads) var/obj/machinery/holopad/H = I diff --git a/code/datums/mergers/_merger.dm b/code/datums/mergers/_merger.dm index 76ba6202727..d59470b9313 100644 --- a/code/datums/mergers/_merger.dm +++ b/code/datums/mergers/_merger.dm @@ -19,10 +19,7 @@ #endif /// Signals in members to trigger a refresh - var/static/list/refresh_signals = list( - COMSIG_PARENT_QDELETING, - COMSIG_MOVABLE_MOVED, - ) + var/static/list/refresh_signals = list(COMSIG_MOVABLE_MOVED) /datum/merger/New(id, list/merged_typecache, atom/origin, attempt_merge_proc) #if MERGERS_DEBUG @@ -42,18 +39,21 @@ /datum/merger/proc/RemoveMember(atom/thing, clean=TRUE) SEND_SIGNAL(thing, COMSIG_MERGER_REMOVING, src) UnregisterSignal(thing, refresh_signals) + UnregisterSignal(thing, COMSIG_PARENT_QDELETING) if(!thing.mergers) return thing.mergers -= id if(clean && !length(thing.mergers)) thing.mergers = null members -= thing + origin = null if(origin == thing && length(members)) origin = pick(members) /datum/merger/proc/AddMember(atom/thing, connected_dir) // note that this fires for the origin of the merger as well SEND_SIGNAL(thing, COMSIG_MERGER_ADDING, src) RegisterSignal(thing, refresh_signals, .proc/QueueRefresh) + RegisterSignal(thing, COMSIG_PARENT_QDELETING, .proc/HandleMemberDel) if(!thing.mergers) thing.mergers = list() else if(thing.mergers[id]) @@ -73,6 +73,11 @@ sleep(1 SECONDS) #endif +/datum/merger/proc/HandleMemberDel(atom/source) + SIGNAL_HANDLER + RemoveMember(source) + QueueRefresh() + /datum/merger/proc/QueueRefresh() SIGNAL_HANDLER addtimer(CALLBACK(src, .proc/Refresh), 1, TIMER_UNIQUE) diff --git a/code/datums/mutations/antenna.dm b/code/datums/mutations/antenna.dm index 15721f888f7..77bb76e0345 100644 --- a/code/datums/mutations/antenna.dm +++ b/code/datums/mutations/antenna.dm @@ -6,7 +6,7 @@ text_lose_indication = "Your antenna shrinks back down." instability = 5 difficulty = 8 - var/obj/item/implant/radio/antenna/linked_radio + var/datum/weakref/radio_weakref /obj/item/implant/radio/antenna name = "internal antenna organ" @@ -21,13 +21,16 @@ /datum/mutation/human/antenna/on_acquiring(mob/living/carbon/human/owner) if(..()) return - linked_radio = new(owner) + var/obj/item/implant/radio/antenna/linked_radio = new(owner) linked_radio.implant(owner, null, TRUE, TRUE) + radio_weakref = WEAKREF(linked_radio) /datum/mutation/human/antenna/on_losing(mob/living/carbon/human/owner) if(..()) return - QDEL_NULL(linked_radio) + var/obj/item/implant/radio/antenna/linked_radio = radio_weakref.resolve() + if(linked_radio) + QDEL_NULL(linked_radio) /datum/mutation/human/antenna/New(class_ = MUT_OTHER, timer, datum/mutation/human/copymut) ..() diff --git a/code/datums/status_effects/status_effect.dm b/code/datums/status_effects/status_effect.dm index 5fd836948ae..85e18550ff9 100644 --- a/code/datums/status_effects/status_effect.dm +++ b/code/datums/status_effects/status_effect.dm @@ -21,11 +21,11 @@ /datum/status_effect/proc/on_creation(mob/living/new_owner, ...) if(new_owner) owner = new_owner - if(owner) - LAZYADD(owner.status_effects, src) - if(!owner || !on_apply()) + if(QDELETED(owner) || !on_apply()) qdel(src) return + if(owner) + LAZYADD(owner.status_effects, src) if(duration != -1) duration = world.time + duration tick_interval = world.time + tick_interval diff --git a/code/game/atoms.dm b/code/game/atoms.dm index c4852738ec8..344dd1598b4 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -455,7 +455,6 @@ ///Take air from the passed in gas mixture datum /atom/proc/assume_air(datum/gas_mixture/giver) - qdel(giver) return null ///Remove air from this atom diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 663d5041978..62a5801ab7a 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -129,6 +129,8 @@ if(pulledby) pulledby.stop_pulling() + if(pulling) + stop_pulling() if(orbiting) orbiting.end_orbit(src) @@ -159,7 +161,7 @@ gen_emissive_blocker.appearance_flags |= appearance_flags return gen_emissive_blocker else if(blocks_emissive == EMISSIVE_BLOCK_UNIQUE) - if(!em_block) + if(!em_block && !QDELETED(src)) render_target = ref(src) em_block = new(src, render_target) return em_block @@ -872,7 +874,7 @@ else target_zone = thrower.zone_selected - var/datum/thrownthing/TT = new(src, target, get_turf(target), get_dir(src, target), range, speed, thrower, diagonals_first, force, gentle, callback, target_zone) + var/datum/thrownthing/TT = new(src, get_turf(target), get_dir(src, target), range, speed, thrower, diagonals_first, force, gentle, callback, target_zone) var/dist_x = abs(target.x - src.x) var/dist_y = abs(target.y - src.y) diff --git a/code/game/communications.dm b/code/game/communications.dm index ae36cda5343..3c52c5b2eaa 100644 --- a/code/game/communications.dm +++ b/code/game/communications.dm @@ -134,8 +134,9 @@ GLOBAL_LIST_INIT(reverseradiochannels, list( )) /datum/radio_frequency - var/frequency as num - var/list/list/obj/devices = list() + var/frequency + /// List of filters -> list of devices + var/list/list/datum/weakref/devices = list() /datum/radio_frequency/New(freq) frequency = freq @@ -165,7 +166,11 @@ GLOBAL_LIST_INIT(reverseradiochannels, list( //Send the data for(var/current_filter in filter_list) - for(var/obj/device in devices[current_filter]) + for(var/datum/weakref/device_ref as anything in devices[current_filter]) + var/obj/device = device_ref.resolve() + if(!device) + devices[current_filter] -= device_ref + continue if(device == source) continue if(range) @@ -183,7 +188,7 @@ GLOBAL_LIST_INIT(reverseradiochannels, list( var/list/devices_line = devices[filter] if(!devices_line) devices[filter] = devices_line = list() - devices_line += device + devices_line += WEAKREF(device) /datum/radio_frequency/proc/remove_listener(obj/device) @@ -191,7 +196,7 @@ GLOBAL_LIST_INIT(reverseradiochannels, list( var/list/devices_line = devices[devices_filter] if(!devices_line) devices -= devices_filter - devices_line -= device + devices_line -= WEAKREF(device) if(!devices_line.len) devices -= devices_filter diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index e4ef225894e..5a06e4a2cf1 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -23,7 +23,7 @@ var/start_active = FALSE //If it ignores the random chance to start broken on round start var/invuln = null var/obj/item/camera_bug/bug = null - var/obj/structure/camera_assembly/assembly = null + var/datum/weakref/assembly_ref = null var/area/myarea = null //OTHER @@ -56,6 +56,7 @@ for(var/i in network) network -= i network += lowertext(i) + var/obj/structure/camera_assembly/assembly if(CA) assembly = CA if(assembly.xray_module) @@ -73,6 +74,7 @@ else assembly = new(src) assembly.state = 4 //STATE_FINISHED + assembly_ref = WEAKREF(assembly) GLOB.cameranet.cameras += src GLOB.cameranet.addCamera(src) if (isturf(loc)) @@ -100,11 +102,12 @@ /obj/machinery/camera/Destroy() if(can_use()) toggle_cam(null, 0) //kick anyone viewing out and remove from the camera chunks + GLOB.cameranet.removeCamera(src) GLOB.cameranet.cameras -= src cancelCameraAlarm() if(isarea(myarea)) myarea.clear_camera(src) - QDEL_NULL(assembly) + QDEL_NULL(assembly_ref) if(bug) bug.bugged_cameras -= c_tag if(bug.current == src) @@ -204,6 +207,10 @@ . = ..() if(!panel_open) return + var/obj/structure/camera_assembly/assembly = assembly_ref?.resolve() + if(!assembly) + assembly_ref = null + return var/list/droppable_parts = list() if(assembly.xray_module) droppable_parts += assembly.xray_module @@ -267,6 +274,9 @@ /obj/machinery/camera/attackby(obj/item/I, mob/living/user, params) // UPGRADES if(panel_open) + var/obj/structure/camera_assembly/assembly = assembly_ref?.resolve() + if(!assembly) + assembly_ref = null if(I.tool_behaviour == TOOL_ANALYZER) if(!isXRay(TRUE)) //don't reveal it was already upgraded if was done via MALF AI Upgrade Camera Network ability if(!user.temporarilyRemoveItemFromInventory(I)) @@ -342,7 +352,7 @@ else to_chat(user, span_notice("Camera bugged.")) bug = I - bug.bugged_cameras[src.c_tag] = src + bug.bugged_cameras[src.c_tag] = WEAKREF(src) return return ..() @@ -364,12 +374,13 @@ /obj/machinery/camera/deconstruct(disassembled = TRUE) if(!(flags_1 & NODECONSTRUCT_1)) if(disassembled) + var/obj/structure/camera_assembly/assembly = assembly_ref?.resolve() if(!assembly) assembly = new() assembly.forceMove(drop_location()) assembly.state = 1 assembly.setDir(dir) - assembly = null + assembly_ref = null else var/obj/item/I = new /obj/item/wallframe/camera (loc) I.update_integrity(I.max_integrity * 0.5) diff --git a/code/game/machinery/camera/motion.dm b/code/game/machinery/camera/motion.dm index 4dd308a6fe7..5914e2f1930 100644 --- a/code/game/machinery/camera/motion.dm +++ b/code/game/machinery/camera/motion.dm @@ -38,10 +38,9 @@ return TRUE /obj/machinery/camera/Destroy() - var/area/ai_monitored/A = get_area(src) localMotionTargets = null - if(istype(A)) - A.motioncameras -= src + if(area_motion) + area_motion.motioncameras -= src cancelAlarm() return ..() diff --git a/code/game/machinery/camera/presets.dm b/code/game/machinery/camera/presets.dm index 47615a045f5..fa61ebceda4 100644 --- a/code/game/machinery/camera/presets.dm +++ b/code/game/machinery/camera/presets.dm @@ -72,12 +72,14 @@ // UPGRADE PROCS /obj/machinery/camera/proc/isEmpProof(ignore_malf_upgrades) - return (upgrades & CAMERA_UPGRADE_EMP_PROOF) && (!(ignore_malf_upgrades && assembly.malf_emp_firmware_active)) + var/obj/structure/camera_assembly/assembly = assembly_ref?.resolve() + return (upgrades & CAMERA_UPGRADE_EMP_PROOF) && (!(ignore_malf_upgrades && assembly?.malf_emp_firmware_active)) /obj/machinery/camera/proc/upgradeEmpProof(malf_upgrade, ignore_malf_upgrades) if(isEmpProof(ignore_malf_upgrades)) //pass a malf upgrade to ignore_malf_upgrades so we can replace the malf module with the normal one return //that way if someone tries to upgrade an already malf-upgraded camera, it'll just upgrade it to a normal version. AddElement(/datum/element/empprotection, EMP_PROTECT_SELF | EMP_PROTECT_WIRES | EMP_PROTECT_CONTENTS) + var/obj/structure/camera_assembly/assembly = assembly_ref?.resolve() if(malf_upgrade) assembly.malf_emp_firmware_active = TRUE //don't add parts to drop, update icon, ect. reconstructing it will also retain the upgrade. assembly.malf_emp_firmware_present = TRUE //so the upgrade is retained after incompatible parts are removed. @@ -98,11 +100,13 @@ /obj/machinery/camera/proc/isXRay(ignore_malf_upgrades) + var/obj/structure/camera_assembly/assembly = assembly_ref?.resolve() return (upgrades & CAMERA_UPGRADE_XRAY) && (!(ignore_malf_upgrades && assembly.malf_xray_firmware_active)) /obj/machinery/camera/proc/upgradeXRay(malf_upgrade, ignore_malf_upgrades) if(isXRay(ignore_malf_upgrades)) //pass a malf upgrade to ignore_malf_upgrades so we can replace the malf upgrade with the normal one return //that way if someone tries to upgrade an already malf-upgraded camera, it'll just upgrade it to a normal version. + var/obj/structure/camera_assembly/assembly = assembly_ref?.resolve() if(malf_upgrade) assembly.malf_xray_firmware_active = TRUE //don't add parts to drop, update icon, ect. reconstructing it will also retain the upgrade. assembly.malf_xray_firmware_present = TRUE //so the upgrade is retained after incompatible parts are removed. @@ -128,6 +132,8 @@ /obj/machinery/camera/proc/upgradeMotion() if(isMotion()) return + var/obj/structure/camera_assembly/assembly = assembly_ref?.resolve() + if(name == initial(name)) name = "motion-sensitive security camera" if(!assembly.proxy_module) diff --git a/code/game/machinery/computer/atmos_control.dm b/code/game/machinery/computer/atmos_control.dm index 492c9807464..e970c28a236 100644 --- a/code/game/machinery/computer/atmos_control.dm +++ b/code/game/machinery/computer/atmos_control.dm @@ -417,7 +417,16 @@ GLOBAL_LIST_EMPTY(atmos_air_controllers) /obj/machinery/computer/atmos_control/tank/proc/reconnect(mob/user) var/list/IO = list() var/datum/radio_frequency/freq = SSradio.return_frequency(frequency) - var/list/devices = freq.devices["_default"] + + var/list/devices = list() + var/list/device_refs = freq.devices["_default"] + for(var/datum/weakref/device_ref as anything in device_refs) + var/atom/device = device_ref.resolve() + if(!device) + device_refs -= device_ref + continue + devices += device + for(var/obj/machinery/atmospherics/components/unary/vent_pump/U in devices) var/list/text = splittext(U.id_tag, "_") IO |= text[1] diff --git a/code/game/machinery/computer/crew.dm b/code/game/machinery/computer/crew.dm index 7d7c23db397..b654cc1a710 100644 --- a/code/game/machinery/computer/crew.dm +++ b/code/game/machinery/computer/crew.dm @@ -172,11 +172,11 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new) ui.open() /datum/crewmonitor/proc/show(mob/M, source) - ui_sources[M] = source + ui_sources[WEAKREF(M)] = source ui_interact(M) /datum/crewmonitor/ui_host(mob/user) - return ui_sources[user] + return ui_sources[WEAKREF(user)] /datum/crewmonitor/ui_data(mob/user) var/z = user.z diff --git a/code/game/machinery/computer/teleporter.dm b/code/game/machinery/computer/teleporter.dm index e679ef3fde6..4579f1dcbd3 100644 --- a/code/game/machinery/computer/teleporter.dm +++ b/code/game/machinery/computer/teleporter.dm @@ -10,7 +10,8 @@ var/id var/obj/machinery/teleport/station/power_station var/calibrating - var/turf/target + ///Weakref to the target atom we're pointed at currently + var/datum/weakref/target_ref /obj/machinery/computer/teleporter/Initialize() . = ..() @@ -45,6 +46,11 @@ ui.open() /obj/machinery/computer/teleporter/ui_data(mob/user) + var/atom/target + if(target_ref) + target = target_ref.resolve() + if(!target) + target_ref = null var/list/data = list() data["power_station"] = power_station ? TRUE : FALSE data["teleporter_hub"] = power_station?.teleporter_hub ? TRUE : FALSE @@ -85,7 +91,7 @@ set_target(usr) . = TRUE if("calibrate") - if(!target) + if(!target_ref) say("Error: No target set to calibrate to.") return if(power_station.teleporter_hub.calibrated || power_station.teleporter_hub.accuracy >= 3) @@ -96,13 +102,14 @@ calibrating = TRUE power_station.update_appearance() addtimer(CALLBACK(src, .proc/finish_calibration), 50 * (3 - power_station.teleporter_hub.accuracy)) //Better parts mean faster calibration - . = TRUE + return TRUE /obj/machinery/computer/teleporter/proc/set_teleport_target(new_target) - if (target == new_target) + var/datum/weakref/new_target_ref = WEAKREF(new_target) + if (target_ref == new_target_ref) return SEND_SIGNAL(src, COMSIG_TELEPORTER_NEW_TARGET, new_target) - target = new_target + target_ref = new_target_ref /obj/machinery/computer/teleporter/proc/finish_calibration() calibrating = FALSE @@ -152,8 +159,8 @@ var/desc = input("Please select a location to lock in.", "Locking Computer") as null|anything in sortList(L) set_teleport_target(L[desc]) - var/turf/T = get_turf(target) - log_game("[key_name(user)] has set the teleporter target to [target] at [AREACOORD(T)]") + var/turf/T = get_turf(L[desc]) + log_game("[key_name(user)] has set the teleporter target to [L[desc]] at [AREACOORD(T)]") else var/list/S = power_station.linked_stations diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm index 44507d4d70a..2e17fbd3dec 100644 --- a/code/game/machinery/cryopod.dm +++ b/code/game/machinery/cryopod.dm @@ -137,7 +137,8 @@ GLOBAL_LIST_EMPTY(cryopod_computers) /// Cooldown for when it's now safe to try an despawn the player. COOLDOWN_DECLARE(despawn_world_time) - var/obj/machinery/computer/cryopod/control_computer + ///Weakref to our controller + var/datum/weakref/control_computer_weakref COOLDOWN_DECLARE(last_no_computer_message) /obj/machinery/cryopod/Initialize() @@ -150,27 +151,27 @@ GLOBAL_LIST_EMPTY(cryopod_computers) // This is not a good situation /obj/machinery/cryopod/Destroy() - control_computer = null + control_computer_weakref = null return ..() /obj/machinery/cryopod/proc/find_control_computer(urgent = FALSE) for(var/cryo_console as anything in GLOB.cryopod_computers) var/obj/machinery/computer/cryopod/console = cryo_console if(get_area(console) == get_area(src)) - control_computer = console + control_computer_weakref = WEAKREF(console) break // Don't send messages unless we *need* the computer, and less than five minutes have passed since last time we messaged - if(!control_computer && urgent && COOLDOWN_FINISHED(src, last_no_computer_message)) + if(!control_computer_weakref && urgent && COOLDOWN_FINISHED(src, last_no_computer_message)) COOLDOWN_START(src, last_no_computer_message, 5 MINUTES) log_admin("Cryopod in [get_area(src)] could not find control computer!") message_admins("Cryopod in [get_area(src)] could not find control computer!") last_no_computer_message = world.time - return control_computer != null + return control_computer_weakref != null /obj/machinery/cryopod/close_machine(atom/movable/target) - if(!control_computer) + if(!control_computer_weakref) find_control_computer(TRUE) if((isnull(target) || isliving(target)) && state_open && !panel_open) ..(target) @@ -204,7 +205,7 @@ GLOBAL_LIST_EMPTY(cryopod_computers) open_machine() if(!mob_occupant.client && COOLDOWN_FINISHED(src, despawn_world_time)) - if(!control_computer) + if(!control_computer_weakref) find_control_computer(urgent = TRUE) despawn_occupant() @@ -298,7 +299,11 @@ GLOBAL_LIST_EMPTY(cryopod_computers) announce_rank = general_record.fields["rank"] qdel(general_record) - control_computer?.frozen_crew += list(crew_member) + var/obj/machinery/computer/cryopod/control_computer = control_computer_weakref?.resolve() + if(!control_computer) + control_computer_weakref = null + else + control_computer.frozen_crew += list(crew_member) // Make an announcement and log the person entering storage. if(GLOB.announcement_systems.len) @@ -323,13 +328,6 @@ GLOBAL_LIST_EMPTY(cryopod_computers) else mob_occupant.transferItemToLoc(item_content, drop_location(), force = TRUE, silent = TRUE) // Skyrat Edit End - // Ghost and delete the mob. - if(!mob_occupant.get_ghost(TRUE)) - if(world.time < 15 MINUTES) // before the 15 minute mark - mob_occupant.ghostize(FALSE) // Players despawned too early may not re-enter the game - else - mob_occupant.ghostize(TRUE) - handle_objectives() QDEL_NULL(occupant) open_machine() diff --git a/code/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/brigdoors.dm index fb1df3b0acc..0e07c5d3052 100644 --- a/code/game/machinery/doors/brigdoors.dm +++ b/code/game/machinery/doors/brigdoors.dm @@ -32,7 +32,13 @@ var/timer_duration = 0 var/timing = FALSE // boolean, true/1 timer is on, false/0 means it's not timing - var/list/obj/machinery/targets = list() + ///List of weakrefs to nearby doors + var/list/doors = list() + ///List of weakrefs to nearby flashers + var/list/flashers = list() + ///List of weakrefs to nearby closets + var/list/closets = list() + var/obj/item/radio/Radio //needed to send messages to sec radio maptext_height = 26 @@ -50,17 +56,17 @@ if(id != null) for(var/obj/machinery/door/window/brigdoor/M in urange(20, src)) if (M.id == id) - targets += M + doors += WEAKREF(M) for(var/obj/machinery/flasher/F in urange(20, src)) if(F.id == id) - targets += F + flashers += WEAKREF(F) for(var/obj/structure/closet/secure_closet/brig/C in urange(20, src)) if(C.id == id) - targets += C + closets += WEAKREF(C) - if(!targets.len) + if(!length(doors) && !length(flashers) && length(closets)) obj_break() update_appearance() @@ -88,18 +94,26 @@ activation_time = world.realtime //SKYRAT EDIT CHANGE timing = TRUE - for(var/obj/machinery/door/window/brigdoor/door in targets) + for(var/datum/weakref/door_ref as anything in doors) + var/obj/machinery/door/window/brigdoor/door = door_ref.resolve() + if(!door) + doors -= door_ref + continue if(door.density) continue INVOKE_ASYNC(door, /obj/machinery/door/window/brigdoor.proc/close) - for(var/obj/structure/closet/secure_closet/brig/C in targets) - if(C.broken) + for(var/datum/weakref/closet_ref as anything in closets) + var/obj/structure/closet/secure_closet/brig/closet = closet_ref.resolve() + if(!closet) + closets -= closet_ref continue - if(C.opened && !C.close()) + if(closet.broken) continue - C.locked = TRUE - C.update_appearance() + if(closet.opened && !closet.close()) + continue + closet.locked = TRUE + closet.update_appearance() return 1 @@ -117,18 +131,26 @@ set_timer(0) update_appearance() - for(var/obj/machinery/door/window/brigdoor/door in targets) + for(var/datum/weakref/door_ref as anything in doors) + var/obj/machinery/door/window/brigdoor/door = door_ref.resolve() + if(!door) + doors -= door_ref + continue if(!door.density) continue INVOKE_ASYNC(door, /obj/machinery/door/window/brigdoor.proc/open) - for(var/obj/structure/closet/secure_closet/brig/C in targets) - if(C.broken) + for(var/datum/weakref/closet_ref as anything in closets) + var/obj/structure/closet/secure_closet/brig/closet = closet_ref.resolve() + if(!closet) + closets -= closet_ref continue - if(C.opened) + if(closet.broken) continue - C.locked = FALSE - C.update_appearance() + if(closet.opened) + continue + closet.locked = FALSE + closet.update_appearance() return 1 @@ -200,8 +222,12 @@ data["minutes"] = round((time_left - data["seconds"]) / 60) data["timing"] = timing data["flash_charging"] = FALSE - for(var/obj/machinery/flasher/F in targets) - if(F.last_flash && (F.last_flash + 15 SECONDS) > world.time) + for(var/datum/weakref/flash_ref as anything in flashers) + var/obj/machinery/flasher/flasher = flash_ref.resolve() + if(!flasher) + flashers -= flash_ref + continue + if(flasher.last_flash && (flasher.last_flash + 15 SECONDS) > world.time) data["flash_charging"] = TRUE break return data @@ -238,8 +264,12 @@ if("flash") investigate_log("[key_name(usr)] has flashed cell [id]", INVESTIGATE_RECORDS) user.log_message("[key_name(usr)] has flashed cell [id]", LOG_ATTACK) - for(var/obj/machinery/flasher/F in targets) - F.flash() + for(var/datum/weakref/flash_ref as anything in flashers) + var/obj/machinery/flasher/flasher = flash_ref.resolve() + if(!flasher) + flashers -= flash_ref + continue + flasher.flash() if("preset") var/preset = params["preset"] var/preset_time = time_left() diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index c0e34d39738..966459a9d96 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -726,6 +726,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ Impersonation = null if(!QDELETED(HC)) HC.Disconnect(HC.calling_holopad) + HC = null return ..() /obj/effect/overlay/holo_pad_hologram/Process_Spacemove(movement_dir = 0) diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm index a40d0beb844..672ed0e2501 100644 --- a/code/game/machinery/teleporter.dm +++ b/code/game/machinery/teleporter.dm @@ -68,12 +68,15 @@ var/obj/machinery/computer/teleporter/com = power_station.teleporter_console if (QDELETED(com)) return - if (QDELETED(com.target)) - com.target = null + var/atom/target + if(com.target_ref) + target = com.target_ref.resolve() + if (!target) + com.target_ref = null visible_message(span_alert("Cannot authenticate locked on coordinates. Please reinstate coordinate matrix.")) return if (ismovable(M)) - if(do_teleport(M, com.target, channel = TELEPORT_CHANNEL_BLUESPACE)) + if(do_teleport(M, target, channel = TELEPORT_CHANNEL_BLUESPACE)) use_power(5000) if(!calibrated && prob(30 - ((accuracy) * 10))) //oh dear a problem if(ishuman(M))//don't remove people from the round randomly you jerks @@ -214,7 +217,7 @@ /obj/machinery/teleport/station/proc/toggle(mob/user) if(machine_stat & (BROKEN|NOPOWER) || !teleporter_hub || !teleporter_console ) return - if (teleporter_console.target) + if (teleporter_console.target_ref?.resolve()) if(teleporter_hub.panel_open || teleporter_hub.machine_stat & (BROKEN|NOPOWER)) to_chat(user, span_alert("The teleporter hub isn't responding.")) else @@ -222,6 +225,7 @@ use_power(5000) to_chat(user, span_notice("Teleporter [engaged ? "" : "dis"]engaged!")) else + teleporter_console.target_ref = null to_chat(user, span_alert("No target detected.")) engaged = FALSE teleporter_hub.update_appearance() diff --git a/code/game/objects/items/devices/camera_bug.dm b/code/game/objects/items/devices/camera_bug.dm index 5db602dffb1..2e66a70c102 100644 --- a/code/game/objects/items/devices/camera_bug.dm +++ b/code/game/objects/items/devices/camera_bug.dm @@ -39,7 +39,8 @@ STOP_PROCESSING(SSobj, src) get_cameras() for(var/cam_tag in bugged_cameras) - var/obj/machinery/camera/camera = bugged_cameras[cam_tag] + var/datum/weakref/camera_ref = bugged_cameras[cam_tag] + var/obj/machinery/camera/camera = camera_ref.resolve() if(camera && camera.bug == src) camera.bug = null bugged_cameras = list() @@ -81,8 +82,11 @@ for(var/obj/machinery/camera/camera in GLOB.cameranet.cameras) if(camera.machine_stat || !camera.can_use()) continue - if(length(list("ss13","mine", "rd", "labor", "toxins", "minisat")&camera.network)) - bugged_cameras[camera.c_tag] = camera + if(length(list("ss13","mine", "rd", "labor", "toxins", "minisat") & camera.network)) + var/datum/weakref/camera_ref = WEAKREF(camera) + if(!camera_ref || !camera.c_tag) + continue + bugged_cameras[camera.c_tag] = camera_ref return sortList(bugged_cameras) @@ -95,15 +99,17 @@ if(BUGMODE_LIST) html = "

Select a camera:

\[Cancel camera view\]
" for(var/entry in cameras) - var/obj/machinery/camera/C = cameras[entry] - if(QDELETED(C)) + var/datum/weakref/camera_ref = cameras[entry] + var/obj/machinery/camera/camera = camera_ref.resolve() + if(!camera) + cameras -= camera_ref continue var/functions = "" - if(C.bug == src) - functions = " - \[Monitor\]\[Disable\]" + if(camera.bug == src) + functions = " - \[Monitor\]\[Disable\]" else - functions = " - \[Monitor\]" - html += "" + functions = " - \[Monitor\]" + html += "" if(BUGMODE_MONITOR) if(current) @@ -117,10 +123,11 @@ html = "Tracking '[tracked_name]' \[Cancel Tracking\]\[Cancel camera view\]
" if(last_found) var/time_diff = round((world.time - last_seen) / 150) - var/obj/machinery/camera/C = bugged_cameras[last_found] + var/datum/weakref/camera_ref = bugged_cameras[last_found] + var/obj/machinery/camera/camera = camera_ref.resolve() var/outstring - if(C) - outstring = "[last_found]" + if(camera) + outstring = "[last_found]" else outstring = last_found if(!time_diff) @@ -132,8 +139,8 @@ if(!s) s = "00" html += "Last seen near [outstring] ([m]:[s] minute\s ago)
" - if( C && (C.bug == src)) //Checks to see if the camera has a bug - html += "\[Disable\]" + if(camera && (camera.bug == src)) //Checks to see if the camera has a bug + html += "\[Disable\]" else html += "Not yet seen." @@ -204,12 +211,13 @@ if("monitor" in href_list) //You can't locate on a list with keys var/list/cameras = flatten_list(bugged_cameras) - var/obj/machinery/camera/C = locate(href_list["monitor"]) in cameras - if(C && istype(C)) - if(!same_z_level(C)) + var/datum/weakref/camera_ref = locate(href_list["monitor"]) in cameras + var/obj/machinery/camera/camera = camera_ref.resolve() + if(camera && istype(camera)) + if(!same_z_level(camera)) return track_mode = BUGMODE_MONITOR - current = C + current = camera usr.reset_perspective(null) interact() if("track" in href_list) @@ -225,13 +233,14 @@ if("emp" in href_list) //You can't locate on a list with keys var/list/cameras = flatten_list(bugged_cameras) - var/obj/machinery/camera/C = locate(href_list["emp"]) in cameras - if(C && istype(C) && C.bug == src) - if(!same_z_level(C)) + var/datum/weakref/camera_ref = locate(href_list["emp"]) in cameras + var/obj/machinery/camera/camera = camera_ref.resolve() + if(camera && istype(camera) && camera.bug == src) + if(!same_z_level(camera)) return - C.emp_act(EMP_HEAVY) - C.bug = null - bugged_cameras -= C.c_tag + camera.emp_act(EMP_HEAVY) + camera.bug = null + bugged_cameras -= camera.c_tag interact() return if("close" in href_list) @@ -241,17 +250,18 @@ if("view" in href_list) //You can't locate on a list with keys var/list/cameras = flatten_list(bugged_cameras) - var/obj/machinery/camera/C = locate(href_list["view"]) in cameras - if(C && istype(C)) - if(!same_z_level(C)) + var/datum/weakref/camera_ref = locate(href_list["view"]) in cameras + var/obj/machinery/camera/camera = camera_ref.resolve() + if(camera && istype(camera)) + if(!same_z_level(camera)) return - if(!C.can_use()) + if(!camera.can_use()) to_chat(usr, span_warning("Something's wrong with that camera! You can't get a feed.")) return - current = C + current = camera spawn(6) if(src.check_eye(usr)) - usr.reset_perspective(C) + usr.reset_perspective(camera) interact() else usr.unset_machine() diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm index 3d02783fd7a..2d34ad53c2d 100644 --- a/code/game/objects/items/handcuffs.dm +++ b/code/game/objects/items/handcuffs.dm @@ -479,6 +479,7 @@ var/obj/item/restraints/legcuffs/beartrap/B = new /obj/item/restraints/legcuffs/beartrap/energy/cyborg(get_turf(hit_atom)) B.spring_trap(null, hit_atom) qdel(src) + return . = ..() /** diff --git a/code/game/objects/items/implants/implant_misc.dm b/code/game/objects/items/implants/implant_misc.dm index 72107310fe2..53ec15646bd 100644 --- a/code/game/objects/items/implants/implant_misc.dm +++ b/code/game/objects/items/implants/implant_misc.dm @@ -77,6 +77,10 @@ radio.keyslot = new radio_key radio.recalculateChannels() +/obj/item/implant/radio/Destroy() + QDEL_NULL(radio) + return ..() + /obj/item/implant/radio/mining radio_key = /obj/item/encryptionkey/headset_cargo diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm index 31857d3ad03..6bd03eab16e 100644 --- a/code/game/objects/items/stacks/sheets/glass.dm +++ b/code/game/objects/items/stacks/sheets/glass.dm @@ -61,11 +61,12 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \ var/obj/item/stack/rods/V = W if (V.get_amount() >= 1 && get_amount() >= 1) var/obj/item/stack/sheet/rglass/RG = new (get_turf(user)) - RG.add_fingerprint(user) + if(!QDELETED(RG)) + RG.add_fingerprint(user) var/replace = user.get_inactive_held_item()==src V.use(1) use(1) - if(QDELETED(src) && replace) + if(QDELETED(src) && replace && !QDELETED(RG)) user.put_in_hands(RG) else to_chat(user, span_warning("You need one rod and one sheet of glass to make reinforced glass!")) diff --git a/code/game/objects/items/tanks/tanks.dm b/code/game/objects/items/tanks/tanks.dm index e449579597c..ab8363744ed 100644 --- a/code/game/objects/items/tanks/tanks.dm +++ b/code/game/objects/items/tanks/tanks.dm @@ -86,9 +86,7 @@ return /obj/item/tank/Destroy() - if(air_contents) - QDEL_NULL(air_contents) - + air_contents = null STOP_PROCESSING(SSobj, src) return ..() diff --git a/code/game/objects/items/teleportation.dm b/code/game/objects/items/teleportation.dm index 7ded0215df4..296e5f37583 100644 --- a/code/game/objects/items/teleportation.dm +++ b/code/game/objects/items/teleportation.dm @@ -172,15 +172,17 @@ //SKYRAT EDIT END var/list/locations = list() for(var/obj/machinery/computer/teleporter/computer in GLOB.machines) - if(!computer.target) + var/atom/target = computer.target_ref?.resolve() + if(!target) + computer.target_ref = null continue - var/area/computer_area = get_area(computer.target) + var/area/computer_area = get_area(target) if(!computer_area || (computer_area.area_flags & NOTELEPORT)) continue if(computer.power_station?.teleporter_hub && computer.power_station.engaged) - locations["[get_area(computer.target)] (Active)"] = computer + locations["[get_area(target)] (Active)"] = computer else - locations["[get_area(computer.target)] (Inactive)"] = computer + locations["[get_area(target)] (Inactive)"] = computer locations["None (Dangerous)"] = PORTAL_LOCATION_DANGEROUS @@ -212,7 +214,7 @@ user.show_message(span_notice("[src] is recharging!")) return - var/teleport_turf + var/atom/teleport_target if (teleport_location == PORTAL_LOCATION_DANGEROUS) var/list/dangerous_turfs = list() @@ -226,16 +228,19 @@ continue dangerous_turfs += dangerous_turf - teleport_turf = pick(dangerous_turfs) + teleport_target = pick(dangerous_turfs) else var/obj/machinery/computer/teleporter/computer = teleport_location - teleport_turf = computer.target + var/atom/target = computer.target_ref?.resolve() + if(!target) + computer.target_ref = null + teleport_target = target - if (teleport_turf == null) + if (teleport_target == null) to_chat(user, span_notice("[src] vibrates, then stops. Maybe you should try something else.")) return - var/area/teleport_area = get_area(teleport_turf) + var/area/teleport_area = get_area(teleport_target) if (teleport_area.area_flags & NOTELEPORT) to_chat(user, span_notice("[src] is malfunctioning.")) return @@ -243,7 +248,7 @@ if (!can_teleport_notifies(user)) return - var/list/obj/effect/portal/created = create_portal_pair(get_turf(user), get_teleport_turf(get_turf(teleport_turf)), 300, 1, null, atmos_link_override) + var/list/obj/effect/portal/created = create_portal_pair(get_turf(user), get_teleport_turf(get_turf(teleport_target)), 300, 1, null, atmos_link_override) if(LAZYLEN(created) != 2) return diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 0fba31192a3..c013909f1ae 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -72,6 +72,7 @@ obj_flags &= ~string_to_objflag[flag] else obj_flags |= string_to_objflag[flag] + if((obj_flags & ON_BLUEPRINTS) && isturf(loc)) var/turf/T = loc T.add_blueprints_preround(src) diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index 53e93b17dc3..f7e2d64ed47 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -43,6 +43,7 @@ var/obj/item/stack/sheet/iron/M = new (loc, 2) M.add_fingerprint(user) qdel(src) + return else if(istype(W, /obj/item/stack)) if(iswallturf(loc)) @@ -70,6 +71,7 @@ var/obj/structure/falsewall/iron/FW = new (loc) transfer_fingerprints_to(FW) qdel(src) + return else if(S.get_amount() < 5) to_chat(user, span_warning("You need at least five rods to add plating!")) @@ -104,6 +106,7 @@ var/obj/structure/falsewall/F = new (loc) transfer_fingerprints_to(F) qdel(src) + return else if(state == GIRDER_REINF) to_chat(user, span_warning("You can't finish a reinforced girder with regular iron. You need a plasteel sheet for that.")) return @@ -137,6 +140,7 @@ var/obj/structure/falsewall/reinforced/FW = new (loc) transfer_fingerprints_to(FW) qdel(src) + return else if(state == GIRDER_REINF) if(S.get_amount() < 1) return @@ -183,6 +187,7 @@ var/obj/structure/falsewall/FW = new falsewall_type (loc) transfer_fingerprints_to(FW) qdel(src) + return else if(S.get_amount() < 2) to_chat(user, span_warning("You need at least two sheets to add plating!")) diff --git a/code/game/turfs/change_turf.dm b/code/game/turfs/change_turf.dm index 3a7fa55bba6..57b3baccc5f 100644 --- a/code/game/turfs/change_turf.dm +++ b/code/game/turfs/change_turf.dm @@ -190,11 +190,9 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( var/datum/excited_group/stashed_group = excited_group . = ..() //If path == type this will return us, don't bank on making a new type if (!.) // changeturf failed or didn't do anything - QDEL_NULL(stashed_air) return var/turf/open/newTurf = . newTurf.air.copy_from(stashed_air) - QDEL_NULL(stashed_air) newTurf.excited = stashed_state newTurf.excited_group = stashed_group #ifdef VISUALIZE_ACTIVE_TURFS diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 62cb9a54d82..a400099d921 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -524,7 +524,7 @@ GLOBAL_LIST_EMPTY(station_turfs) LAZYADD(blueprint_data, I) /turf/proc/add_blueprints_preround(atom/movable/AM) - if(!SSticker.HasRoundStarted()) + if(!SSicon_smooth.initialized) if(AM.layer == WIRE_LAYER) //wires connect to adjacent positions after its parent init, meaning we need to wait (in this case, until smoothing) to take its image SSicon_smooth.blueprint_queue += AM else diff --git a/code/modules/admin/verbs/diagnostics.dm b/code/modules/admin/verbs/diagnostics.dm index 0d87167f4d3..bfaa713e50d 100644 --- a/code/modules/admin/verbs/diagnostics.dm +++ b/code/modules/admin/verbs/diagnostics.dm @@ -50,12 +50,16 @@ output += "  ERROR
" continue for (var/filter in fqs.devices) - var/list/f = fqs.devices[filter] - if (!f) + var/list/filtered = fqs.devices[filter] + if (!filtered) output += "  [filter]: ERROR
" continue - output += "  [filter]: [f.len]
" - for (var/device in f) + output += "  [filter]: [filtered.len]
" + for(var/datum/weakref/device_ref as anything in filtered) + var/atom/device = device_ref.resolve() + if(!device) + filtered -= device_ref + continue if (istype(device, /atom)) var/atom/A = device output += "    [device] ([AREACOORD(A)])
" diff --git a/code/modules/antagonists/nukeop/nukeop.dm b/code/modules/antagonists/nukeop/nukeop.dm index 008e1f172e9..d76d07b90bf 100644 --- a/code/modules/antagonists/nukeop/nukeop.dm +++ b/code/modules/antagonists/nukeop/nukeop.dm @@ -187,7 +187,7 @@ dukinuki.forceMove(H.drop_location()) else H.put_in_hands(dukinuki, TRUE) - nuke_team.war_button = dukinuki + nuke_team.war_button_ref = WEAKREF(dukinuki) owner.announce_objectives() addtimer(CALLBACK(src, .proc/nuketeam_name_assign), 1) @@ -251,7 +251,7 @@ var/core_objective = /datum/objective/nuclear var/memorized_code var/list/team_discounts - var/obj/item/nuclear_challenge/war_button + var/datum/weakref/war_button_ref /datum/team/nuclear/New() ..() @@ -394,7 +394,8 @@ disk_report += "
[entry][functions]
[entry][functions]
" var/common_part = ..() var/challenge_report - if(!QDELETED(war_button)) + var/obj/item/nuclear_challenge/war_button = war_button_ref?.resolve() + if(war_button) challenge_report += "War not declared. \[Force war\]" return common_part + disk_report + challenge_report diff --git a/code/modules/antagonists/traitor/equipment/Malf_Modules.dm b/code/modules/antagonists/traitor/equipment/Malf_Modules.dm index 3df7d399fd6..147230d9c44 100644 --- a/code/modules/antagonists/traitor/equipment/Malf_Modules.dm +++ b/code/modules/antagonists/traitor/equipment/Malf_Modules.dm @@ -788,7 +788,8 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) var/upgraded_cameras = 0 for(var/V in GLOB.cameranet.cameras) var/obj/machinery/camera/C = V - if(C.assembly) + var/obj/structure/camera_assembly/assembly = C.assembly_ref?.resolve() + if(assembly) var/upgraded = FALSE if(!C.isXRay()) @@ -803,7 +804,6 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module)) if(upgraded) upgraded_cameras++ - unlock_text = replacetext(unlock_text, "CAMSUPGRADED", "[upgraded_cameras]") //This works, since unlock text is called after upgrade() /// AI Turret Upgrade: Increases the health and damage of all turrets. diff --git a/code/modules/atmospherics/machinery/components/components_base.dm b/code/modules/atmospherics/machinery/components/components_base.dm index cf070e366d6..8519a6a3551 100644 --- a/code/modules/atmospherics/machinery/components/components_base.dm +++ b/code/modules/atmospherics/machinery/components/components_base.dm @@ -91,7 +91,7 @@ /obj/machinery/atmospherics/components/nullifyNode(i) if(parents[i]) nullifyPipenet(parents[i]) - QDEL_NULL(airs[i]) + airs[i] = null return ..() /obj/machinery/atmospherics/components/on_construction() diff --git a/code/modules/atmospherics/machinery/components/unary_devices/heat_exchanger.dm b/code/modules/atmospherics/machinery/components/unary_devices/heat_exchanger.dm index 66d632b29b3..803215f231d 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/heat_exchanger.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/heat_exchanger.dm @@ -10,7 +10,7 @@ layer = LOW_OBJ_LAYER - var/obj/machinery/atmospherics/components/unary/heat_exchanger/partner = null + var/datum/weakref/partner_ref = null var/update_cycle pipe_state = "heunary" @@ -35,20 +35,26 @@ PIPING_LAYER_SHIFT(src, piping_layer) /obj/machinery/atmospherics/components/unary/heat_exchanger/atmosinit() + var/obj/machinery/atmospherics/components/unary/heat_exchanger/partner = partner_ref?.resolve() if(!partner) + partner_ref = null var/partner_connect = turn(dir,180) for(var/obj/machinery/atmospherics/components/unary/heat_exchanger/target in get_step(src,partner_connect)) if(target.dir & get_dir(src,target)) - partner = target - partner.partner = src + partner_ref = WEAKREF(target) + target.partner_ref = WEAKREF(src) break ..() /obj/machinery/atmospherics/components/unary/heat_exchanger/process_atmos() ..() - if(!partner || SSair.times_fired <= update_cycle) + var/obj/machinery/atmospherics/components/unary/heat_exchanger/partner = partner_ref?.resolve() + if(!partner) + partner_ref = null + return + if(SSair.times_fired <= update_cycle) return update_cycle = SSair.times_fired diff --git a/code/modules/atmospherics/machinery/pipes/pipes.dm b/code/modules/atmospherics/machinery/pipes/pipes.dm index 62ff2734d1b..5bfc9474040 100644 --- a/code/modules/atmospherics/machinery/pipes/pipes.dm +++ b/code/modules/atmospherics/machinery/pipes/pipes.dm @@ -82,7 +82,6 @@ QDEL_NULL(parent) releaseAirToTurf() - QDEL_NULL(air_temporary) var/turf/T = loc for(var/obj/machinery/meter/meter in T) diff --git a/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm b/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm index e19a68d79bd..abd1f2005a1 100644 --- a/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm +++ b/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm @@ -26,7 +26,7 @@ /obj/machinery/portable_atmospherics/Destroy() disconnect() - QDEL_NULL(air_contents) + air_contents = null SSair.stop_processing_machine(src) return ..() diff --git a/code/modules/buildmode/buildmode.dm b/code/modules/buildmode/buildmode.dm index 9fa4eb495e0..f256fae89b6 100644 --- a/code/modules/buildmode/buildmode.dm +++ b/code/modules/buildmode/buildmode.dm @@ -45,8 +45,10 @@ /datum/buildmode/Destroy() close_switchstates() holder.player_details.post_login_callbacks -= li_cb + li_cb = null holder = null QDEL_NULL(mode) + QDEL_LIST(buttons) QDEL_LIST(modeswitch_buttons) QDEL_LIST(dirswitch_buttons) return ..() diff --git a/code/modules/clothing/shoes/_shoes.dm b/code/modules/clothing/shoes/_shoes.dm index cf53ab48043..e9ca910b7e5 100644 --- a/code/modules/clothing/shoes/_shoes.dm +++ b/code/modules/clothing/shoes/_shoes.dm @@ -19,8 +19,8 @@ var/tied = SHOES_TIED ///How long it takes to lace/unlace these shoes var/lace_time = 5 SECONDS - ///any alerts we have active - var/atom/movable/screen/alert/our_alert + ///An active alert + var/datum/weakref/our_alert_ref /obj/item/clothing/shoes/suicide_act(mob/living/carbon/user) if(rand(2)>1) @@ -76,7 +76,7 @@ /obj/item/clothing/shoes/equipped(mob/user, slot) . = ..() if(can_be_tied && tied == SHOES_UNTIED) - our_alert = user.throw_alert("shoealert", /atom/movable/screen/alert/shoes/untied) + our_alert_ref = WEAKREF(user.throw_alert("shoealert", /atom/movable/screen/alert/shoes/untied)) RegisterSignal(src, COMSIG_SHOES_STEP_ACTION, .proc/check_trip, override=TRUE) /obj/item/clothing/shoes/proc/restore_offsets(mob/user) @@ -85,7 +85,10 @@ worn_y_dimension = world.icon_size /obj/item/clothing/shoes/dropped(mob/user) - if(our_alert && our_alert.owner == user) + var/atom/movable/screen/alert/our_alert = our_alert_ref?.resolve() + if(!our_alert) + our_alert_ref = null + if(our_alert?.owner == user) user.clear_alert("shoealert") if(offset && equipped_before_drop) restore_offsets(user) @@ -125,7 +128,7 @@ UnregisterSignal(src, COMSIG_SHOES_STEP_ACTION) else if(tied == SHOES_UNTIED && our_guy && user == our_guy) - our_alert = our_guy.throw_alert("shoealert", /atom/movable/screen/alert/shoes/untied) // if we're the ones unknotting our own laces, of course we know they're untied + our_alert_ref = WEAKREF(our_guy.throw_alert("shoealert", /atom/movable/screen/alert/shoes/untied)) // if we're the ones unknotting our own laces, of course we know they're untied RegisterSignal(src, COMSIG_SHOES_STEP_ACTION, .proc/check_trip, override=TRUE) /** @@ -216,7 +219,7 @@ our_guy.Knockdown(10) our_guy.visible_message(span_danger("[our_guy] trips on [our_guy.p_their()] knotted shoelaces and falls! What a klutz!"), span_userdanger("You trip on your knotted shoelaces and fall over!")) SEND_SIGNAL(our_guy, COMSIG_ADD_MOOD_EVENT, "trip", /datum/mood_event/tripped) // well we realized they're knotted now! - our_alert = our_guy.throw_alert("shoealert", /atom/movable/screen/alert/shoes/knotted) + our_alert_ref = WEAKREF(our_guy.throw_alert("shoealert", /atom/movable/screen/alert/shoes/knotted)) else if(tied == SHOES_UNTIED) var/wiser = TRUE // did we stumble and realize our laces are undone? @@ -248,7 +251,7 @@ wiser = FALSE if(wiser) SEND_SIGNAL(our_guy, COMSIG_ADD_MOOD_EVENT, "untied", /datum/mood_event/untied) // well we realized they're untied now! - our_alert = our_guy.throw_alert("shoealert", /atom/movable/screen/alert/shoes/untied) + our_alert_ref = WEAKREF(our_guy.throw_alert("shoealert", /atom/movable/screen/alert/shoes/untied)) /obj/item/clothing/shoes/attack_hand(mob/living/carbon/human/user, list/modifiers) diff --git a/code/modules/detectivework/detective_work.dm b/code/modules/detectivework/detective_work.dm index 63722206c11..b048bdad414 100644 --- a/code/modules/detectivework/detective_work.dm +++ b/code/modules/detectivework/detective_work.dm @@ -77,8 +77,9 @@ var/obj/effect/decal/cleanable/blood/splatter/B = locate() in src if(QDELETED(B)) // SKYRAT EDIT - SANITY CHECK; DONT ADD DNA TO A FUCKING DELETED BLOOD SPATTER - original: if(!B) B = new /obj/effect/decal/cleanable/blood/splatter(src, diseases) - B.add_blood_DNA(blood_dna) //give blood info to the blood decal. - return TRUE //we bloodied the floor + if(!QDELETED(B)) + B.add_blood_DNA(blood_dna) //give blood info to the blood decal. + return TRUE //we bloodied the floor /mob/living/carbon/human/add_blood_DNA(list/blood_dna, list/datum/disease/diseases) if(wear_suit) diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm index ba1b4ed28d3..474a7642945 100644 --- a/code/modules/mob/login.dm +++ b/code/modules/mob/login.dm @@ -48,6 +48,9 @@ if(!client) return FALSE + //We do this here to prevent hanging refs from ghostize or whatever, since if we were in another mob before this'll take care of it + clear_client_in_contents() + SEND_SIGNAL(src, COMSIG_MOB_LOGIN) if (key != client.key) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 0cca15ca286..9f92252b13a 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -43,7 +43,6 @@ observe.reset_perspective(null) qdel(hud_used) QDEL_LIST(client_colours) - 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() //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.set_current(null) diff --git a/code/modules/plumbing/ducts.dm b/code/modules/plumbing/ducts.dm index b3c7b49cbba..83721752c7e 100644 --- a/code/modules/plumbing/ducts.dm +++ b/code/modules/plumbing/ducts.dm @@ -61,7 +61,7 @@ All the important duct code: if(D == src) continue if(D.duct_layer & duct_layer) - disconnect_duct() + return INITIALIZE_HINT_QDEL //If we have company, end it all attempt_connect() AddElement(/datum/element/undertile, TRAIT_T_RAY_VISIBLE) @@ -166,8 +166,9 @@ All the important duct code: lose_neighbours() reset_connects(0) update_appearance() - if(ispath(drop_on_wrench) && !QDELING(src)) + if(ispath(drop_on_wrench)) new drop_on_wrench(drop_location()) + if(!QDELETED(src)) qdel(src) ///Special proc to draw a new connect frame based on neighbours. not the norm so we can support multiple duct kinds diff --git a/code/modules/projectiles/ammunition/_ammunition.dm b/code/modules/projectiles/ammunition/_ammunition.dm index e73b6520492..4b82e8fdd78 100644 --- a/code/modules/projectiles/ammunition/_ammunition.dm +++ b/code/modules/projectiles/ammunition/_ammunition.dm @@ -51,12 +51,11 @@ update_appearance() /obj/item/ammo_casing/Destroy() - . = ..() - var/turf/T = get_turf(src) if(T && !loaded_projectile && is_station_level(T.z)) SSblackbox.record_feedback("tally", "station_mess_destroyed", 1, name) QDEL_NULL(loaded_projectile) + return ..() /obj/item/ammo_casing/add_weapon_description() AddElement(/datum/element/weapon_description, attached_proc = .proc/add_notes_ammo) diff --git a/code/modules/projectiles/projectile/energy/net_snare.dm b/code/modules/projectiles/projectile/energy/net_snare.dm index d7d3e979096..d4b0d284964 100644 --- a/code/modules/projectiles/projectile/energy/net_snare.dm +++ b/code/modules/projectiles/projectile/energy/net_snare.dm @@ -33,9 +33,12 @@ . = ..() var/obj/item/beacon/teletarget = null for(var/obj/machinery/computer/teleporter/com in GLOB.machines) - if(com.target) + var/atom/target = com.target_ref.resolve() + if(target) if(com.power_station && com.power_station.teleporter_hub && com.power_station.engaged) - teletarget = com.target + teletarget = target + else + com.target_ref = null addtimer(CALLBACK(src, .proc/pop, teletarget), 30) diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index 702d587fe03..dd0fd84c688 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -2066,12 +2066,20 @@ taste_description = "rainbows" var/can_colour_mobs = TRUE chemical_flags = REAGENT_CAN_BE_SYNTHESIZED + var/datum/callback/color_callback /datum/reagent/colorful_reagent/New() - SSticker.OnRoundstart(CALLBACK(src,.proc/UpdateColor)) + color_callback = CALLBACK(src, .proc/UpdateColor) + SSticker.OnRoundstart(color_callback) + return ..() + +/datum/reagent/colorful_reagent/Destroy() + LAZYREMOVE(SSticker.round_end_events, color_callback) //Prevents harddels during roundstart + color_callback = null //Fly free little callback return ..() /datum/reagent/colorful_reagent/proc/UpdateColor() + color_callback = null color = pick(random_color_list) /datum/reagent/colorful_reagent/on_mob_life(mob/living/carbon/M, delta_time, times_fired) diff --git a/code/modules/recycling/disposal/holder.dm b/code/modules/recycling/disposal/holder.dm index 0295ef4feb8..04987a92284 100644 --- a/code/modules/recycling/disposal/holder.dm +++ b/code/modules/recycling/disposal/holder.dm @@ -16,7 +16,6 @@ var/hasmob = FALSE // contains a mob /obj/structure/disposalholder/Destroy() - QDEL_NULL(gas) active = FALSE return ..() diff --git a/code/modules/station_goals/bsa.dm b/code/modules/station_goals/bsa.dm index a9d879fb30d..86b79e175b4 100644 --- a/code/modules/station_goals/bsa.dm +++ b/code/modules/station_goals/bsa.dm @@ -65,8 +65,8 @@ name = "Bluespace Artillery Fusor" desc = "Contents classified by Nanotrasen Naval Command. Needs to be linked with the other BSA parts using a multitool." icon_state = "fuel_chamber" - var/obj/machinery/bsa/back/back - var/obj/machinery/bsa/front/front + var/datum/weakref/back_ref + var/datum/weakref/front_ref /obj/machinery/bsa/middle/multitool_act(mob/living/user, obj/item/I) if(!multitool_check_buffer(user, I)) @@ -74,18 +74,20 @@ var/obj/item/multitool/M = I if(M.buffer) if(istype(M.buffer, /obj/machinery/bsa/back)) - back = M.buffer + back_ref = WEAKREF(M.buffer) + to_chat(user, span_notice("You link [src] with [M.buffer].")) M.buffer = null - to_chat(user, span_notice("You link [src] with [back].")) else if(istype(M.buffer, /obj/machinery/bsa/front)) - front = M.buffer + front_ref = WEAKREF(M.buffer) + to_chat(user, span_notice("You link [src] with [M.buffer].")) M.buffer = null - to_chat(user, span_notice("You link [src] with [front].")) else to_chat(user, span_warning("[I]'s data buffer is empty!")) return TRUE /obj/machinery/bsa/middle/proc/check_completion() + var/obj/machinery/bsa/front/front = front_ref?.resolve() + var/obj/machinery/bsa/back/back = back_ref?.resolve() if(!front || !back) return "No linked parts detected!" if(!front.anchored || !back.anchored || !anchored) @@ -113,6 +115,10 @@ return TRUE /obj/machinery/bsa/middle/proc/get_cannon_direction() + var/obj/machinery/bsa/front/front = front_ref?.resolve() + var/obj/machinery/bsa/back/back = back_ref?.resolve() + if(!front || !back) + return if(front.x > x && back.x < x) return EAST else if(front.x < x && back.x > x) @@ -237,7 +243,7 @@ icon_state = "control_boxp" icon_keyboard = "" - var/obj/machinery/bsa/full/cannon + var/datum/weakref/cannon_ref var/notice var/target var/area_aim = FALSE //should also show areas for targeting @@ -252,6 +258,7 @@ ui.open() /obj/machinery/computer/bsa_control/ui_data() + var/obj/machinery/bsa/full/cannon = cannon_ref?.resolve() var/list/data = list() data["ready"] = cannon ? cannon.ready : FALSE data["connected"] = cannon @@ -268,7 +275,7 @@ switch(action) if("build") - cannon = deploy() + cannon_ref = WEAKREF(deploy()) . = TRUE if("fire") fire(usr) @@ -308,6 +315,10 @@ return get_turf(G.parent) /obj/machinery/computer/bsa_control/proc/fire(mob/user) + var/obj/machinery/bsa/full/cannon = cannon_ref?.resolve() + if(!cannon) + notice = "No Cannon Exists!" + return if(cannon.machine_stat) notice = "Cannon unpowered!" return @@ -331,8 +342,8 @@ s.set_up(4,get_turf(centerpiece)) s.start() var/obj/machinery/bsa/full/cannon = new(get_turf(centerpiece),centerpiece.get_cannon_direction()) - qdel(centerpiece.front) - qdel(centerpiece.back) + QDEL_NULL(centerpiece.front_ref) + QDEL_NULL(centerpiece.back_ref) qdel(centerpiece) return cannon */ diff --git a/code/modules/tgui/tgui.dm b/code/modules/tgui/tgui.dm index b99783f67ad..fe98745c018 100644 --- a/code/modules/tgui/tgui.dm +++ b/code/modules/tgui/tgui.dm @@ -63,6 +63,11 @@ if(ui_x && ui_y) src.window_size = list(ui_x, ui_y) +/datum/tgui/Destroy() + user = null + src_object = null + return ..() + /** * public *