From c1163dff1935dfe7aa18ef668ffa57eb37ded530 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Tue, 20 Jul 2021 12:59:41 +0200 Subject: [PATCH] [MIRROR] EVEN MORE HARDDEL FIXES (#7017) * EVEN MORE HARDDEL FIXES (#60228) Fixes a ton of harddels, sourced from #59996 I think this brings us down to like, ~100 per round from ~200, with only like 20 of those being proper hell failures. I've seen harddel profiles below 1 second of total cost. Feeling good. See you on the other side Makes the cryopod control computer into a weakref, never trust bee code Converts brig door timer internal lists to weakrefs Fixes a harddel caused by qdeling a motion sensitive camera after it had left its source area, jesus christ why didn't we do this already holy shit Converts the radio implant ref held by the antenna mutation to weakrefs because it isn't reliably cleaned up, makes the radio implant actually qdel its fucking radio Removes the target var from the throwing datum, it does literally nothing and just exists to cause harddels, mostly for the singularity Fixes a cable harddel sourced from things that try to enter blueprints after smoothing, but before roundstart. IE, shuttles. Removes shuttles from the blueprints Fixes emmisive blockers being added post qdel Removes some manual ghosting from cryopods, I initially did this for harddel reasons, but I figured out a better fix for that. I'm now doing it because it's got this really strange logic for like "re-entering the game" that doesn't actually link to what the ghostize proc does. We should remove this at some point Fixes robot hud objects harddeling due to hanging refs Fixes buildmode related hanging refs, I'm coming for you admin team Fixes a few instances of trying to add the forensics component post qdel, hhhhhhhhhhh Fixes some split personality harddels/weirdness Replaces a use of disconnect_duct with an init qdel hint, I suspect there's more issues with duct harddels, I've seen some odd logs about ahhh the area_contents list, but we can worry about that later Makes teleporter targets into weakrefs, properly types them as /atom Makes frequency devices into weakrefs Makes cameras remove themselves from camera nets on Destroy Makes tgui ui datums implement destroy, this means if I ever see one hang a ref to user or whatever, I know there's an error with calling close() properly. I've seen this harddel once, but not after this change so I assume there was some error with close(). IDK maybe this is a papering over? Would have to ask @ stylemistake I've seen logs of beartraps being in world post del, putting a return there just in case. The same is true of nerf darts, but I haven't really looked into that yet Makes a shoe's ref to untying alerts a weakref, yes this is needed. Moves clearing client_in_contents to the Login of the new mob. This prevents doing things like ghosting someone before a mob qdel causing harddels Fixes a harddel set sourced from adding a status effect to a qdeleted thing. Is this an error? I'm honestly not sure. Converts bsa code to weakrefs Converts the partner var of heat exchangers to weakrefs Converts camera assemblies to weakrefs Fixes some dumb behavior with ammo casings and assuming you'll be on a turf post Destroy parent call Fixes? merger related harddels, you were never cleared from your own members list, so origin objects would end up making a new list, creating harddels. Potential input from @ ninjanomnom about the logic Chasms store a static list of "falling atoms", which only exists for chasms that go somewhere else. This list wasn't being cleared of qdeleted objects, which is what happens when you fall in most chasms. Fixes this, and converts the list to weakrefs. Fixes some runtimes in both sheet code, and the weather listener element. This is here because runtime spam made testing more of a pain, didn't think it needed its own pr Fixes colorful reagent harddels sourced from reagents that were qdel'd before roundstart. I'm only like 50% sure this actually got it, but the issue may have been solved by #60174, so eh Turns the nuke op antag datum's ref to the war button into a weakref Fixes some holopad code that was not nulling refs all the time Converts camera bugs to weakrefs, this was the result of the bug being "reworked" like 6 years back without taking the existing ref clearing into account. Whole item needs a redo, but this'll do for now. Ensures that the both pulling and pullee refs are cleared on Destroy The crew monitor held all users in a non clearing list, makes that list a weakref because I hate everything Oh and I removed all sources of gas_mixture qdeletion, I'm kinda unsure on this since it's not technically supported, but any harddels from it might? indicate something going wrong with like, gas passing logic. I'd like @ MrStonedOne's thoughts, since I trust him to call me an idiot if I'm wrong. ## Why it's not good for the game I crashed sybil like 10 times to get this data, I'm gonna put it to good use. Don't think you're safe sybilites, I'm coming for you. * EVEN MORE HARDDEL FIXES Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> --- code/_onclick/hud/robot.dm | 10 +++ code/_onclick/observer.dm | 12 +++- code/controllers/subsystem/icon_smooth.dm | 5 +- code/controllers/subsystem/throwing.dm | 5 +- code/datums/brain_damage/split_personality.dm | 7 ++ code/datums/components/chasm.dm | 19 ++--- code/datums/elements/weather_listener.dm | 4 +- code/datums/holocall.dm | 1 + code/datums/mergers/_merger.dm | 13 ++-- code/datums/mutations/antenna.dm | 9 ++- code/datums/status_effects/status_effect.dm | 6 +- code/game/atoms.dm | 1 - code/game/atoms_movable.dm | 6 +- code/game/communications.dm | 15 ++-- code/game/machinery/camera/camera.dm | 19 +++-- code/game/machinery/camera/motion.dm | 5 +- code/game/machinery/camera/presets.dm | 8 ++- code/game/machinery/computer/atmos_control.dm | 11 ++- code/game/machinery/computer/crew.dm | 4 +- code/game/machinery/computer/teleporter.dm | 21 ++++-- code/game/machinery/cryopod.dm | 28 ++++---- code/game/machinery/doors/brigdoors.dm | 72 +++++++++++++------ code/game/machinery/hologram.dm | 1 + code/game/machinery/teleporter.dm | 12 ++-- code/game/objects/items/devices/camera_bug.dm | 70 ++++++++++-------- code/game/objects/items/handcuffs.dm | 1 + .../objects/items/implants/implant_misc.dm | 4 ++ .../game/objects/items/stacks/sheets/glass.dm | 5 +- code/game/objects/items/tanks/tanks.dm | 4 +- code/game/objects/items/teleportation.dm | 25 ++++--- code/game/objects/objs.dm | 1 + code/game/objects/structures/girders.dm | 5 ++ code/game/turfs/change_turf.dm | 2 - code/game/turfs/turf.dm | 2 +- code/modules/admin/verbs/diagnostics.dm | 12 ++-- code/modules/antagonists/nukeop/nukeop.dm | 7 +- .../traitor/equipment/Malf_Modules.dm | 4 +- .../machinery/components/components_base.dm | 2 +- .../unary_devices/heat_exchanger.dm | 14 ++-- .../atmospherics/machinery/pipes/pipes.dm | 1 - .../portable/portable_atmospherics.dm | 2 +- code/modules/buildmode/buildmode.dm | 2 + code/modules/clothing/shoes/_shoes.dm | 17 +++-- code/modules/detectivework/detective_work.dm | 5 +- code/modules/mob/login.dm | 3 + code/modules/mob/mob.dm | 1 - code/modules/plumbing/ducts.dm | 5 +- .../projectiles/ammunition/_ammunition.dm | 3 +- .../projectile/energy/net_snare.dm | 7 +- .../chemistry/reagents/other_reagents.dm | 10 ++- code/modules/recycling/disposal/holder.dm | 1 - code/modules/station_goals/bsa.dm | 31 +++++--- code/modules/tgui/tgui.dm | 5 ++ 53 files changed, 358 insertions(+), 187 deletions(-) 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 *