diff --git a/code/controllers/subsystem/persistence/_persistence.dm b/code/controllers/subsystem/persistence/_persistence.dm index d494561d0f..c9898f2976 100644 --- a/code/controllers/subsystem/persistence/_persistence.dm +++ b/code/controllers/subsystem/persistence/_persistence.dm @@ -335,7 +335,7 @@ SUBSYSTEM_DEF(persistence) if(!istype(ending_human) || !ending_human.mind || !ending_human.client || !ending_human.client.prefs || !ending_human.client.prefs.persistent_scars) continue - var/mob/living/carbon/human/original_human = ending_human.mind.original_character + var/mob/living/carbon/human/original_human = ending_human.mind.original_character.resolve() if(!original_human || original_human.stat == DEAD || !original_human.all_scars || !(original_human == ending_human)) if(ending_human.client) // i was told if i don't check this every step of the way byond might decide a client ceases to exist mid proc so here we go ending_human.client.prefs.scars_list["[ending_human.client.prefs.scars_index]"] = "" @@ -356,7 +356,7 @@ SUBSYSTEM_DEF(persistence) if(!istype(ending_human) || !ending_human.mind || !ending_human.client || !ending_human.client.prefs || !ending_human.client.prefs.tcg_cards) continue - var/mob/living/carbon/human/original_human = ending_human.mind.original_character + var/mob/living/carbon/human/original_human = ending_human.mind.original_character.resolve() if(!original_human || original_human.stat == DEAD || !(original_human == ending_human)) continue diff --git a/code/datums/dash_weapon.dm b/code/datums/dash_weapon.dm index f143fea419..adf7b72c11 100644 --- a/code/datums/dash_weapon.dm +++ b/code/datums/dash_weapon.dm @@ -6,7 +6,6 @@ var/current_charges = 1 var/max_charges = 1 var/charge_rate = 250 - var/mob/living/carbon/human/holder var/obj/item/dashing_item var/dash_sound = 'sound/magic/blink.ogg' var/recharge_sound = 'sound/magic/charge.ogg' @@ -17,7 +16,6 @@ /datum/action/innate/dash/Grant(mob/user, obj/dasher) . = ..() dashing_item = dasher - holder = user /datum/action/innate/dash/IsAvailable(silent = FALSE) if(current_charges > 0) @@ -26,7 +24,7 @@ return FALSE /datum/action/innate/dash/Activate() - dashing_item.attack_self(holder) //Used to toggle dash behavior in the dashing item + dashing_item.attack_self(owner) //Used to toggle dash behavior in the dashing item /datum/action/innate/dash/proc/Teleport(mob/user, atom/target) if(!IsAvailable()) @@ -38,12 +36,12 @@ var/obj/spot2 = new phasein(get_turf(user), user.dir) spot1.Beam(spot2,beam_effect,time=20) current_charges-- - holder.update_action_buttons_icon() + owner.update_action_buttons_icon() addtimer(CALLBACK(src, PROC_REF(charge)), charge_rate) /datum/action/innate/dash/proc/charge() current_charges = clamp(current_charges + 1, 0, max_charges) - holder.update_action_buttons_icon() + owner.update_action_buttons_icon() if(recharge_sound) playsound(dashing_item, recharge_sound, 50, 1) - to_chat(holder, "[src] now has [current_charges]/[max_charges] charges.") + to_chat(owner, "[src] now has [current_charges]/[max_charges] charges.") diff --git a/code/datums/dna.dm b/code/datums/dna.dm index 83e2de80b9..ebec1017f7 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -27,12 +27,16 @@ /datum/dna/Destroy() if(iscarbon(holder)) var/mob/living/carbon/cholder = holder + // We do this because a lot of stuff keeps references on species, for some reason. + species.on_species_loss(holder) if(cholder.dna == src) cholder.dna = null holder = null if(delete_species) QDEL_NULL(species) + else + species = null mutations.Cut() //This only references mutations, just dereference. temporary_mutations.Cut() //^ diff --git a/code/datums/elements/photosynthesis.dm b/code/datums/elements/photosynthesis.dm index 8e1c8c53ff..b54525fb6b 100644 --- a/code/datums/elements/photosynthesis.dm +++ b/code/datums/elements/photosynthesis.dm @@ -39,12 +39,13 @@ attached_atoms[target]++ /datum/element/photosynthesis/Detach(datum/target) - attached_atoms[target]-- - if(!attached_atoms[target]) - attached_atoms -= target - if(!length(attached_atoms)) - STOP_PROCESSING(SSobj, src) - attached_atoms = null + if(LAZYLEN(attached_atoms)) + attached_atoms[target]-- + if(!attached_atoms[target]) + attached_atoms -= target + if(!length(attached_atoms)) + STOP_PROCESSING(SSobj, src) + attached_atoms = null return ..() /datum/element/photosynthesis/process() diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 5308ef3189..c05d04ede8 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -81,13 +81,13 @@ var/list/ambitions //ambition end - ///What character we spawned in as- either at roundstart or latejoin, so we know for persistent scars if we ended as the same person or not - var/mob/original_character + ///Weakref to the character we spawned in as- either at roundstart or latejoin, so we know for persistent scars if we ended as the same person or not + var/datum/weakref/original_character /// A lazy list of statuses to add next to this mind in the traitor panel var/list/special_statuses -/datum/mind/New(var/key) +/datum/mind/New(key) skill_holder = new(src) src.key = key soulOwner = src @@ -95,15 +95,29 @@ /datum/mind/Destroy() SSticker.minds -= src - if(islist(antag_datums)) - for(var/i in antag_datums) - var/datum/antagonist/antag_datum = i - if(antag_datum.delete_on_mind_deletion) - qdel(i) - antag_datums = null + QDEL_LIST(antag_datums) + QDEL_NULL(language_holder) QDEL_NULL(skill_holder) + set_current(null) + soulOwner = null return ..() +/datum/mind/proc/set_current(mob/new_current) + if(new_current && QDELETED(new_current)) + CRASH("Tried to set a mind's current var to a qdeleted mob, what the fuck") + if(current) + UnregisterSignal(src, COMSIG_PARENT_QDELETING) + current = new_current + if(current) + RegisterSignal(src, COMSIG_PARENT_QDELETING, PROC_REF(clear_current)) + +/datum/mind/proc/clear_current(datum/source) + SIGNAL_HANDLER + set_current(null) + +/datum/mind/proc/set_original_character(new_original_character) + original_character = WEAKREF(new_original_character) + /datum/mind/proc/get_language_holder() if(!language_holder) language_holder = new (src) @@ -126,13 +140,13 @@ key = new_character.key if(new_character.mind) //disassociate any mind currently in our new body's mind variable - new_character.mind.current = null + new_character.mind.set_current(null) var/datum/atom_hud/antag/hud_to_transfer = antag_hud//we need this because leave_hud() will clear this list var/mob/living/old_current = current if(current) current.transfer_observers_to(new_character) //transfer anyone observing the old character to the new one - current = new_character //associate ourself with our new body + set_current(new_character) //associate ourself with our new body new_character.mind = src //and associate our new body with ourself for(var/a in antag_datums) //Makes sure all antag datums effects are applied in the new body var/datum/antagonist/A = a @@ -1715,7 +1729,7 @@ GLOBAL_LIST(objective_choices) SEND_SIGNAL(src, COMSIG_MOB_ON_NEW_MIND) if(!mind.name) mind.name = real_name - mind.current = src + mind.set_current(src) mind.hide_ckey = client?.prefs?.hide_ckey /mob/living/carbon/mind_initialize() diff --git a/code/datums/mutations/actions.dm b/code/datums/mutations/actions.dm index 0787c10874..37da0c80bf 100644 --- a/code/datums/mutations/actions.dm +++ b/code/datums/mutations/actions.dm @@ -422,13 +422,13 @@ embedding = list("embedded_pain_multiplier" = 4, "embed_chance" = 100, "embedded_fall_chance" = 0) w_class = WEIGHT_CLASS_SMALL sharpness = SHARP_POINTY - var/mob/living/carbon/human/fired_by + var/datum/weakref/fired_by /// if we missed our target var/missed = TRUE /obj/item/hardened_spike/Initialize(mapload, firedby) . = ..() - fired_by = firedby + fired_by = WEAKREF(firedby) addtimer(CALLBACK(src, PROC_REF(checkembedded)), 5 SECONDS) /obj/item/hardened_spike/proc/checkembedded() @@ -478,13 +478,16 @@ return been_places = TRUE chems = new - chems.transfered = embedded_mob - chems.spikey = src - to_chat(fired_by, "Link established! Use the \"Transfer Chemicals\" ability to send your chemicals to the linked target!") - chems.Grant(fired_by) + chems.transfered = WEAKREF(embedded_mob) + var/mob/fired_by_mob = fired_by.resolve() + if(fired_by_mob) + to_chat(fired_by_mob, span_notice("Link established! Use the \"Transfer Chemicals\" ability to send your chemicals to the linked target!")) + chems.Grant(fired_by_mob) /obj/item/hardened_spike/chem/unembedded() - to_chat(fired_by, "Link lost!") + var/mob/fired_by_mob = fired_by.resolve() + if(fired_by_mob) + to_chat(fired_by_mob, span_warning("Link lost!")) QDEL_NULL(chems) ..() @@ -496,19 +499,17 @@ name = "Transfer Chemicals" desc = "Send all of your reagents into whomever the chem spike is embedded in. One use." var/obj/item/hardened_spike/chem/spikey - var/mob/living/carbon/human/transfered + var/datum/weakref/transfered /datum/action/innate/send_chems/Activate() - if(!ishuman(transfered) || !ishuman(owner)) + var/mob/living/carbon/human/transfered_mob = transfered?.resolve() + if(!ishuman(transfered_mob) || !ishuman(owner)) return - var/mob/living/carbon/human/transferer = owner - - to_chat(transfered, "You feel a tiny prick!") - transferer.reagents.trans_to(transfered, transferer.reagents.total_volume, 1, 1, 0) + to_chat(transfered_mob, span_warning("You feel a tiny prick!")) + owner.reagents.trans_to(transfered_mob, owner.reagents.total_volume, 1, 1, 0) var/obj/item/bodypart/L = spikey.checkembedded() //this is where it would deal damage, if it transfers chems it removes itself so no damage spikey.forceMove(get_turf(L)) - transfered.visible_message("[spikey] falls out of [transfered]!") - + transfered_mob.visible_message(span_notice("[spikey] falls out of [transfered_mob]!")) diff --git a/code/datums/mutations/antenna.dm b/code/datums/mutations/antenna.dm index ad08b8ebdc..866180ab4b 100644 --- a/code/datums/mutations/antenna.dm +++ b/code/datums/mutations/antenna.dm @@ -28,8 +28,7 @@ /datum/mutation/human/antenna/on_losing(mob/living/carbon/human/owner) if(..()) return - if(linked_radio) - linked_radio.Destroy() + QDEL_NULL(linked_radio) /datum/mutation/human/antenna/New(class_ = MUT_OTHER, timer, datum/mutation/human/copymut) ..() diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm index e3778811ea..05da7a7919 100644 --- a/code/game/machinery/cryopod.dm +++ b/code/game/machinery/cryopod.dm @@ -346,8 +346,10 @@ GLOBAL_LIST_EMPTY(cryopod_computers) else if(ishuman(mob_occupant)) var/mob/living/carbon/human/H = mob_occupant - if(H.mind && H.client && H.client.prefs && H == H.mind.original_character) - H.SaveTCGCards() + if(H.mind && H.client && H.client.prefs) + var/mob/living/carbon/human/H_original_character = H.mind.original_character?.resolve() + if(H_original_character && H == H_original_character) + H.SaveTCGCards() var/list/gear = list() if(iscarbon(mob_occupant)) // sorry simp-le-mobs deserve no mercy diff --git a/code/modules/antagonists/blob/blob/blobstrains/_blobstrain.dm b/code/modules/antagonists/blob/blob/blobstrains/_blobstrain.dm index 2c55cc6915..69011f0d86 100644 --- a/code/modules/antagonists/blob/blob/blobstrains/_blobstrain.dm +++ b/code/modules/antagonists/blob/blob/blobstrains/_blobstrain.dm @@ -22,6 +22,10 @@ GLOBAL_LIST_INIT(valid_blobstrains, subtypesof(/datum/blobstrain) - list(/datum/ stack_trace("blobstrain created without overmind") overmind = new_overmind +/datum/blobstrain/Destroy(force, ...) + overmind = null + return ..() + /datum/blobstrain/proc/on_gain() overmind.color = complementary_color for(var/BL in GLOB.blobs) diff --git a/code/modules/antagonists/blob/blob/overmind.dm b/code/modules/antagonists/blob/blob/overmind.dm index f15234cd48..80b7d097d0 100644 --- a/code/modules/antagonists/blob/blob/overmind.dm +++ b/code/modules/antagonists/blob/blob/overmind.dm @@ -177,6 +177,9 @@ GLOBAL_LIST_EMPTY(blob_nodes) blob_mobs = null resource_blobs = null blobs_legit = null + blob_core = null + if(blobstrain) + QDEL_NULL(blobstrain) SSshuttle.clearHostileEnvironment(src) STOP_PROCESSING(SSobj, src) diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm index 38cabce8e5..878fe4a443 100644 --- a/code/modules/antagonists/cult/cult_items.dm +++ b/code/modules/antagonists/cult/cult_items.dm @@ -231,7 +231,7 @@ phaseout = /obj/effect/temp_visual/dir_setting/cult/phase/out /datum/action/innate/dash/cult/IsAvailable(silent = FALSE) - if(iscultist(holder) && current_charges) + if(iscultist(owner) && current_charges) return TRUE else return FALSE diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm index a45916aff9..46e80b3255 100644 --- a/code/modules/awaymissions/corpse.dm +++ b/code/modules/awaymissions/corpse.dm @@ -272,16 +272,26 @@ //Non-human spawners -/obj/effect/mob_spawn/AICorpse/create(ckey, name) //Creates a corrupted AI - var/A = locate(/mob/living/silicon/ai) in loc - if(A) +/obj/effect/mob_spawn/AICorpse //Creates a corrupted AI + mob_type = /mob/living/silicon/ai/spawned + +/obj/effect/mob_spawn/AICorpse/create(ckey, name) + var/ai_already_present = locate(/mob/living/silicon/ai) in loc + if(ai_already_present) + qdel(src) return - var/mob/living/silicon/ai/spawned/M = new(loc) //spawn new AI at landmark as var M - M.name = src.name - M.real_name = src.name - M.aiPDA.toff = TRUE //turns the AI's PDA messenger off, stopping it showing up on player PDAs - M.death() //call the AI's death proc - qdel(src) + . = ..() + +// TODO: Port the upstream tgstation rewrite of this. +/obj/effect/mob_spawn/AICorpse/equip(mob/living/silicon/ai/ai) + . = ..() + if(!isAI(ai)) // This should never happen. + stack_trace("[type] spawned a mob of type [ai?.type || "NULL"] that was not an AI!") + return + ai.name = name + ai.real_name = name + ai.aiPDA.toff = TRUE //turns the AI's PDA messenger off, stopping it showing up on player PDAs + ai.death() //call the AI's death proc /obj/effect/mob_spawn/slime mob_type = /mob/living/simple_animal/slime diff --git a/code/modules/integrated_electronics/passive/power.dm b/code/modules/integrated_electronics/passive/power.dm index adc99f0ff5..bd24135ea5 100644 --- a/code/modules/integrated_electronics/passive/power.dm +++ b/code/modules/integrated_electronics/passive/power.dm @@ -122,8 +122,9 @@ var/datum/reagent/blood/B = locate() in reagents.reagent_list if(lfwb) if(B && B.data["cloneable"]) - var/mob/M = B.data["donor"] - if(M && (M.stat != DEAD) && (M.client)) + var/datum/weakref/donor_ref = B.data["donor"] + var/mob/donor = donor_ref.resolve() + if(donor && (donor.stat != DEAD) && (donor.client)) bp = 500000 if((assembly.battery.maxcharge-assembly.battery.charge) / GLOB.CELLRATE > bp) if(reagents.remove_reagent(/datum/reagent/blood, 1)) diff --git a/code/modules/mob/dead/new_player/login.dm b/code/modules/mob/dead/new_player/login.dm index dbcc2cb2b4..e40b467a79 100644 --- a/code/modules/mob/dead/new_player/login.dm +++ b/code/modules/mob/dead/new_player/login.dm @@ -5,7 +5,7 @@ if(!mind) mind = new /datum/mind(key) mind.active = 1 - mind.current = src + mind.set_current(src) ..() diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index 514dab55f3..e76a8f5a38 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -695,7 +695,7 @@ mind.late_joiner = TRUE mind.active = 0 //we wish to transfer the key manually mind.transfer_to(H) //won't transfer key since the mind is not active - mind.original_character = H + mind.set_original_character(H) H.name = real_name client.init_verbs() diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm index 8d5bd40acc..70307520bc 100644 --- a/code/modules/mob/living/blood.dm +++ b/code/modules/mob/living/blood.dm @@ -185,7 +185,7 @@ /mob/living/carbon/get_blood_data() var/blood_data = list() //set the blood data - blood_data["donor"] = src + blood_data["donor"] = WEAKREF(src) blood_data["viruses"] = list() for(var/thing in diseases) diff --git a/code/modules/mob/living/brain/brain.dm b/code/modules/mob/living/brain/brain.dm index a6a74fe4de..b00ab69bf7 100644 --- a/code/modules/mob/living/brain/brain.dm +++ b/code/modules/mob/living/brain/brain.dm @@ -34,10 +34,11 @@ if(stat!=DEAD) //If not dead. death(1) //Brains can die again. AND THEY SHOULD AHA HA HA HA HA HA if(mind) //You aren't allowed to return to brains that don't exist - mind.current = null + mind.set_current(null) mind.active = FALSE //No one's using it anymore. ghostize() //Ghostize checks for key so nothing else is necessary. container = null + QDEL_NULL(stored_dna) return ..() /mob/living/brain/update_mobility() diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm index 7e10ae1c39..9d16907467 100644 --- a/code/modules/mob/living/brain/brain_item.dm +++ b/code/modules/mob/living/brain/brain_item.dm @@ -282,6 +282,8 @@ if(brainmob) QDEL_NULL(brainmob) QDEL_LIST(traumas) + if(owner?.mind) + owner.mind.set_current(null) return ..() //other types of brains diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 42e8fbd77d..efa178de33 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -17,7 +17,6 @@ QDEL_LIST(internal_organs) QDEL_LIST(stomach_contents) QDEL_LIST(bodyparts) - QDEL_LIST(implants) hand_bodyparts = null //Just references out bodyparts, don't need to delete twice. remove_from_all_data_huds() QDEL_NULL(dna) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 3ad1101c96..e1af109877 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -553,7 +553,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) /datum/species/proc/on_species_loss(mob/living/carbon/human/C, datum/species/new_species, pref_load) if(C.dna.species.exotic_bloodtype) - if(!new_species.exotic_bloodtype) + if(!new_species?.exotic_bloodtype) C.dna.blood_type = random_blood_type() else C.dna.blood_type = new_species.exotic_bloodtype @@ -573,7 +573,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) C.type_of_meat = initial(meat) //If their inert mutation is not the same, swap it out - if((inert_mutation != new_species.inert_mutation) && LAZYLEN(C.dna.mutation_index) && (inert_mutation in C.dna.mutation_index)) + if(new_species && (inert_mutation != new_species.inert_mutation) && LAZYLEN(C.dna.mutation_index) && (inert_mutation in C.dna.mutation_index)) C.dna.remove_mutation(inert_mutation) //keep it at the right spot, so we can't have people taking shortcuts var/location = C.dna.mutation_index.Find(inert_mutation) @@ -582,7 +582,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) C.dna.mutation_index[new_species.inert_mutation] = create_sequence(new_species.inert_mutation) C.dna.default_mutation_genes[new_species.inert_mutation] = C.dna.mutation_index[new_species.inert_mutation] - if(!new_species.has_field_of_vision && has_field_of_vision && ishuman(C) && CONFIG_GET(flag/use_field_of_vision)) + if(new_species && !new_species.has_field_of_vision && has_field_of_vision && ishuman(C) && CONFIG_GET(flag/use_field_of_vision)) var/datum/component/field_of_vision/F = C.GetComponent(/datum/component/field_of_vision) if(F) qdel(F) diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm index 98dc00a2f4..550789a066 100644 --- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm @@ -320,17 +320,17 @@ L["name"] = body.name L["ref"] = "[REF(body)]" L["occupied"] = occupied - var/button + var/button_state if(occupied == "owner") - button = "selected" + button_state = "selected" else if(occupied == "stranger") - button = "danger" + button_state = "danger" else if(can_swap(body)) - button = null + button_state = null else - button = "disabled" + button_state = "disabled" - L["swap_button_state"] = button + L["swap_button_state"] = button_state L["swappable"] = (occupied == "available") && can_swap(body) data["bodies"] += list(L) @@ -745,9 +745,9 @@ background_icon_state = "bg_alien" var/datum/species/jelly/stargazer/species -/datum/action/innate/link_minds/New(_species) +/datum/action/innate/link_minds/New(species) ..() - species = _species + src.species = species /datum/action/innate/link_minds/Activate() var/mob/living/carbon/human/H = owner @@ -771,3 +771,7 @@ else to_chat(H, "You can't seem to link [target]'s mind...") to_chat(target, "The foreign presence leaves your mind.") + +/datum/action/innate/link_minds/Destroy() + species = null + return ..() diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index f426eac569..1615b80193 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -35,8 +35,10 @@ if(buckled) buckled.unbuckle_mob(src,force=1) QDEL_LIST_ASSOC_VAL(ability_actions) - + QDEL_LIST(abilities) + QDEL_LIST(implants) remove_from_all_data_huds() + cleanse_trait_datums() GLOB.mob_living_list -= src QDEL_LIST(diseases) return ..() @@ -909,7 +911,7 @@ else throw_alert("gravity", /atom/movable/screen/alert/weightless) if(!override && !is_flying()) - INVOKE_ASYNC(src, TYPE_PROC_REF(/atom/movable, float), !has_gravity) + float(!has_gravity) /mob/living/float(on) if(throwing) diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 64b17b2622..6f0306350a 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -100,7 +100,9 @@ var/display_icon_override var/emote_display = "Neutral" //text string of the current emote we set for the status displays, to prevent logins resetting it. + // TODO: Currently unused, needs port from TG. var/datum/robot_control/robot_control + // TODO: Currently unused, needs port from TG. /// Station alert datum for showing alerts UI var/datum/station_alert/alert_control ///remember AI's last location @@ -119,7 +121,7 @@ new/obj/structure/ai_core/deactivated(loc) //New empty terminal. return INITIALIZE_HINT_QDEL //Delete AI. - ADD_TRAIT(src, TRAIT_NO_TELEPORT, src) + ADD_TRAIT(src, TRAIT_NO_TELEPORT, INNATE_TRAIT) if(L && istype(L, /datum/ai_laws)) laws = L laws.associate(src) @@ -189,20 +191,34 @@ GLOB.ai_list -= src GLOB.shuttle_caller_list -= src SSshuttle.autoEvac() + stop_controlling_display() QDEL_NULL(eyeobj) // No AI, no Eye QDEL_NULL(spark_system) + QDEL_NULL(deploy_action) + QDEL_NULL(redeploy_action) + QDEL_NULL(custom_holoform) + QDEL_NULL(master_multicam) + deployed_shell = null + parent = null + QDEL_NULL(spark_system) QDEL_NULL(malf_picker) QDEL_NULL(doomsday_device) - // TODO: Why these no work? + // TODO: Port implementation of these from TG or remove the unused code. // QDEL_NULL(robot_control) - QDEL_NULL(aiMulti) // QDEL_NULL(alert_control) + QDEL_NULL(aiMulti) + QDEL_NULL(aiPDA) malfhack = null current = null Bot = null controlled_equipment = null linked_core = null apc_override = null + for(var/mob/living/silicon/robot/linked_robot as anything in connected_robots) + if(QDELETED(linked_robot)) + continue + linked_robot.set_connected_ai(null) + connected_robots.Cut() return ..() /mob/living/silicon/ai/IgniteMob() @@ -357,12 +373,12 @@ is_anchored = !is_anchored move_resist = MOVE_FORCE_NORMAL status_flags |= CANPUSH - REMOVE_TRAIT(src, TRAIT_NO_TELEPORT, src) + REMOVE_TRAIT(src, TRAIT_NO_TELEPORT, INNATE_TRAIT) else is_anchored = !is_anchored move_resist = MOVE_FORCE_OVERPOWERING status_flags &= ~CANPUSH - ADD_TRAIT(src, TRAIT_NO_TELEPORT, src) + ADD_TRAIT(src, TRAIT_NO_TELEPORT, INNATE_TRAIT) /mob/living/silicon/ai/proc/ai_mob_to_structure() disconnect_shell() @@ -1097,6 +1113,10 @@ else Remove(owner) //If the last shell is blown, destroy it. +/datum/action/innate/deploy_last_shell/Destroy() + last_used_shell = null + return ..() + /mob/living/silicon/ai/proc/disconnect_shell() if(deployed_shell) //Forcibly call back AI in event of things such as damage, EMP or power loss. to_chat(src, "Your remote connection has been reset!") @@ -1107,9 +1127,7 @@ return /mob/living/silicon/ai/spawned/Initialize(mapload, datum/ai_laws/L, mob/target_ai) - . = ..() - if(!target_ai) - target_ai = src //cheat! just give... ourselves as the spawned AI, because that's technically correct + . = ..(mapload, L, src) //cheat! just give... ourselves as the spawned AI, because that's technically correct /mob/living/silicon/ai/proc/camera_visibility(mob/camera/aiEye/moved_eye) GLOB.cameranet.visibility(moved_eye, client, all_eyes, USE_STATIC_OPAQUE) diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index cf995f07f0..26431ece5f 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -57,7 +57,6 @@ var/encryptmod = FALSE var/holoform = FALSE var/canholo = TRUE - var/obj/item/card/id/access_card = null var/chassis = "repairbot" var/dynamic_chassis var/dynamic_chassis_sit = FALSE //whether we're sitting instead of resting spritewise @@ -85,13 +84,21 @@ var/icon/custom_holoform_icon /mob/living/silicon/pai/Destroy() + QDEL_NULL(signaler) + QDEL_NULL(pda) QDEL_NULL(internal_instrument) + if(cable) + QDEL_NULL(cable) + hackdoor = null if (loc != card) card.forceMove(drop_location()) card.pai = null card.cut_overlays() card.add_overlay("pai-off") + card = null + current = null GLOB.pai_list -= src + STOP_PROCESSING(SSfastprocess, src) return ..() /mob/living/silicon/pai/Initialize(mapload) diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm index 4539c594a1..0a84d5afc8 100644 --- a/code/modules/mob/living/simple_animal/constructs.dm +++ b/code/modules/mob/living/simple_animal/constructs.dm @@ -401,22 +401,16 @@ buttontooltipstyle = "cult" button_icon_state = "cult_mark" var/tracking = FALSE - var/mob/living/simple_animal/hostile/construct/the_construct - - -/datum/action/innate/seek_master/Grant(var/mob/living/C) - the_construct = C - ..() /datum/action/innate/seek_master/Activate() var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult) if(!C) return if(!C.cult_team) - to_chat(the_construct, "You are alone, and have no team.") + to_chat(owner, "You are alone, and have no team.") return var/datum/objective/eldergod/summon_objective = locate() in C.cult_team.objectives - + var/mob/living/simple_animal/hostile/construct/the_construct = owner if(summon_objective.check_completion()) the_construct.master = C.cult_team.blood_target @@ -442,15 +436,11 @@ background_icon_state = "bg_demon" buttontooltipstyle = "cult" button_icon_state = "cult_mark" - var/mob/living/simple_animal/hostile/construct/harvester/the_construct - -/datum/action/innate/seek_prey/Grant(var/mob/living/C) - the_construct = C - ..() /datum/action/innate/seek_prey/Activate() if(GLOB.cult_narsie == null) return + var/mob/living/simple_animal/hostile/construct/the_construct = owner if(the_construct.seeking) desc = "None can hide from Nar'Sie, activate to track a survivor attempting to flee the red harvest!" button_icon_state = "cult_mark" diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm index 987a1f3e9c..bd97907337 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm @@ -35,6 +35,10 @@ var/datum/action/innate/elite_attack/attack_action = new action_type() attack_action.Grant(src) +/mob/living/simple_animal/hostile/asteroid/elite/Destroy(force, ...) + owner = null + return ..() + //Prevents elites from attacking members of their faction (can't hurt themselves either) and lets them mine rock with an attack despite not being able to smash walls. /mob/living/simple_animal/hostile/asteroid/elite/AttackingTarget() if(istype(target, /mob/living/simple_animal/hostile)) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 784400a818..72d2f327eb 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -20,27 +20,38 @@ hook_vr("mob_new",list(src)) /mob/Destroy()//This makes sure that mobs with clients/keys are not just deleted from the game. + // if(client) + // stack_trace("Mob with client has been deleted.") + // else if(ckey) + // stack_trace("Mob without client but with associated ckey, [ckey], has been deleted.") + unset_machine() remove_from_mob_list() remove_from_dead_mob_list() remove_from_alive_mob_list() + QDEL_LIST(mob_spell_list) + QDEL_LIST(actions) GLOB.all_clockwork_mobs -= src + // remove_from_mob_suicide_list() focus = null LAssailant = null movespeed_modification = null + if(length(progressbars)) + stack_trace("[src] destroyed with elements in its progressbars list.") + progressbars = null for (var/alert in alerts) clear_alert(alert, TRUE) - if(observers && observers.len) - for(var/M in observers) - var/mob/dead/observe = M + if(observers?.len) + for(var/mob/dead/observe as anything in observers) observe.reset_perspective(null) dispose_rendering() qdel(hud_used) - for(var/cc in client_colours) - qdel(cc) - client_colours = null - ghostize() - ..() - return QDEL_HINT_HARDDEL + QDEL_LIST(client_colours) + ghostize(can_reenter_corpse = FALSE) //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) + // if(mock_client) + // mock_client.mob = null + return ..() /mob/GenerateTag() tag = "mob_[next_mob_id++]" diff --git a/code/modules/shuttle/arrivals.dm b/code/modules/shuttle/arrivals.dm index 8d9c5a5f77..bd8fe83338 100644 --- a/code/modules/shuttle/arrivals.dm +++ b/code/modules/shuttle/arrivals.dm @@ -33,6 +33,14 @@ WARNING("More than one arrivals docking_port placed on map! Ignoring duplicates.") SSshuttle.arrivals = src +/obj/docking_port/mobile/arrivals/proc/on_console_deleted(datum/source) + SIGNAL_HANDLER + console = null + for(var/obj/machinery/requests_console/new_console as anything in GLOB.allConsoles) + var/area/console_area = get_area(new_console) + if(istype(console_area, /area/shuttle/arrival) && !QDELETED(new_console) && new_console != source) + console = new_console + /obj/docking_port/mobile/arrivals/LateInitialize() areas = list() @@ -40,10 +48,18 @@ for(var/area/shuttle/arrival/A in GLOB.sortedAreas) for(var/obj/structure/chair/C in A) new_latejoin += C - if(!console) - console = locate(/obj/machinery/requests_console) in A areas += A + if(!console) + for(var/obj/machinery/requests_console/new_console as anything in GLOB.allConsoles) + var/area/console_area = get_area(new_console) + if(!istype(console_area, /area/shuttle/arrival) || QDELETED(new_console)) + continue + console = new_console + RegisterSignal(console, COMSIG_PARENT_QDELETING, PROC_REF(on_console_deleted)) + else if(istype(console)) + RegisterSignal(console, COMSIG_PARENT_QDELETING, PROC_REF(on_console_deleted)) + if(SSjob.latejoin_trackers.len) WARNING("Map contains predefined latejoin spawn points and an arrivals shuttle. Using the arrivals shuttle.") diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index 5cb4a083cb..73dcd4c6e9 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -941,13 +941,19 @@ /obj/docking_port/mobile/proc/count_engines() . = 0 + engine_list = list() for(var/thing in shuttle_areas) var/area/shuttle/areaInstance = thing for(var/obj/structure/shuttle/engine/E in areaInstance.contents) if(!QDELETED(E)) engine_list += E + RegisterSignal(E, COMSIG_PARENT_QDELETING, PROC_REF(on_engine_deleted)) . += E.engine_power +/obj/docking_port/mobile/proc/on_engine_deleted(datum/source) + SIGNAL_HANDLER + engine_list -= source + // Double initial engines to get to 0.5 minimum // Lose all initial engines to get to 2 //For 0 engine shuttles like BYOS 5 engines to get to doublespeed diff --git a/code/modules/shuttle/shuttle_creation/shuttle_creator.dm b/code/modules/shuttle/shuttle_creation/shuttle_creator.dm index ac604fbe49..222cbd2ed7 100644 --- a/code/modules/shuttle/shuttle_creation/shuttle_creator.dm +++ b/code/modules/shuttle/shuttle_creation/shuttle_creator.dm @@ -198,8 +198,8 @@ GLOBAL_LIST_EMPTY(custom_shuttle_machines) //Machines that require updating (He var/invertedDir = invertDir(portDirection) if(!portDirection || !invertedDir) to_chat(usr, "Shuttle creation aborted, docking airlock must be on an external wall. Please select a new airlock.") - port.Destroy() - stationary_port.Destroy() + QDEL_NULL(port) + QDEL_NULL(stationary_port) linkedShuttleId = null return FALSE port.dir = invertedDir @@ -207,8 +207,8 @@ GLOBAL_LIST_EMPTY(custom_shuttle_machines) //Machines that require updating (He if(!calculate_bounds(port)) to_chat(usr, "Bluespace calculations failed, please select a new airlock.") - port.Destroy() - stationary_port.Destroy() + QDEL_NULL(port) + QDEL_NULL(stationary_port) linkedShuttleId = null return FALSE diff --git a/code/modules/spells/spell_types/ethereal_jaunt.dm b/code/modules/spells/spell_types/ethereal_jaunt.dm index 4b02f9fbcd..8f0d0fd6c0 100644 --- a/code/modules/spells/spell_types/ethereal_jaunt.dm +++ b/code/modules/spells/spell_types/ethereal_jaunt.dm @@ -39,7 +39,7 @@ return mobloc = get_turf(target.loc) jaunt_steam(mobloc) - ADD_TRAIT(target, TRAIT_MOBILITY_NOMOVE, src) + ADD_TRAIT(target, TRAIT_MOBILITY_NOMOVE, MAGIC_TRAIT) target.update_mobility() holder.reappearing = 1 play_sound("exit",target) @@ -55,7 +55,7 @@ if(T) if(target.Move(T)) break - REMOVE_TRAIT(target, TRAIT_MOBILITY_NOMOVE, src) + REMOVE_TRAIT(target, TRAIT_MOBILITY_NOMOVE, MAGIC_TRAIT) target.update_mobility() /obj/effect/proc_holder/spell/targeted/ethereal_jaunt/proc/jaunt_steam(mobloc) diff --git a/code/modules/unit_tests/vore_tests.dm b/code/modules/unit_tests/vore_tests.dm index 3a8df28479..65a8ad94db 100644 --- a/code/modules/unit_tests/vore_tests.dm +++ b/code/modules/unit_tests/vore_tests.dm @@ -97,8 +97,8 @@ endOxyloss = prey.getOxyLoss() if(startOxyloss < endOxyloss) Fail("Prey takes oxygen damage in a pred's belly! (Before: [startOxyloss]; after: [endOxyloss])") - qdel(prey) - qdel(pred) + QDEL_NULL(prey) + QDEL_NULL(pred) return TRUE //////////////////////////////////////////////////////////////// /datum/unit_test/belly_spacesafe @@ -160,8 +160,8 @@ endBruteloss = prey.getBruteLoss() if(startBruteloss < endBruteloss) Fail("Prey takes brute damage in space! (Before: [startBruteloss]; after: [endBruteloss])") - qdel(prey) - qdel(pred) + QDEL_NULL(prey) + QDEL_NULL(pred) return TRUE //////////////////////////////////////////////////////////////// /datum/unit_test/belly_damage @@ -213,6 +213,6 @@ endBruteBurn = prey.getBruteLoss() + prey.getFireLoss() if(startBruteBurn >= endBruteBurn) Fail("Prey doesn't take damage in digesting belly! (Before: [startBruteBurn]; after: [endBruteBurn])") - qdel(prey) - qdel(pred) + QDEL_NULL(prey) + QDEL_NULL(pred) return TRUE diff --git a/code/modules/vehicles/mecha/combat/neovgre.dm b/code/modules/vehicles/mecha/combat/neovgre.dm index 918fc33f7c..bda8d586d9 100644 --- a/code/modules/vehicles/mecha/combat/neovgre.dm +++ b/code/modules/vehicles/mecha/combat/neovgre.dm @@ -53,7 +53,8 @@ /obj/vehicle/sealed/mecha/combat/neovgre/proc/go_critical() explosion(get_turf(loc), 3, 5, 10, 20, 30) - Destroy(src) + if(!QDELETED(src)) + qdel(src) /obj/vehicle/sealed/mecha/combat/neovgre/container_resist(mob/living/user) to_chat(user, "Neovgre requires a lifetime commitment friend, no backing out now!") diff --git a/code/modules/zombie/organs.dm b/code/modules/zombie/organs.dm index 3011f9acd2..312735115d 100644 --- a/code/modules/zombie/organs.dm +++ b/code/modules/zombie/organs.dm @@ -28,11 +28,10 @@ START_PROCESSING(SSobj, src) /obj/item/organ/zombie_infection/Remove(special = FALSE) - if(owner) - if(iszombie(owner) && old_species) - owner.set_species(old_species) - if(timer_id) - deltimer(timer_id) + if(!QDELETED(owner) && iszombie(owner) && old_species) + owner.set_species(old_species) + if(timer_id) + deltimer(timer_id) . = ..() STOP_PROCESSING(SSobj, src) //Required to be done after the parent call to avoid conflicts with organ decay.