From 54ab1e3936b3d5a301b995f2c1ca14fcdaf3e80d Mon Sep 17 00:00:00 2001 From: Time-Green <7501474+Time-Green@users.noreply.github.com> Date: Sat, 9 Dec 2023 18:50:46 +0100 Subject: [PATCH] Organ movement refactor *Un-nullspaces your organs* (#79687) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit closes #53931, #70916, #53931 ## About The Pull Request Organs were previously stored in nullspace. Now they are stored in their prospective bodyparts. Bodyparts are now stored in the mob. I've also had to refactor a lot of code concerning organ movement. Previously, organs were only moved into bodyparts once the bodyparts were removed. To accomodate this change, two major distinctions have been made: **Bodypart removal/insertion** Called only when an organ is taken out of a bodypart. Bodypart overlays, damage modifiers or other changes that should affect a bodypart itself goes here. **Mob insertion/removal** Called when an organ is removed from a mob. This can either be directly, by taking the organ out of a mob, or by removing the bodypart that contains the organ. This lets you add and remove organ effects safely without having to worry about the bodypart. Now that we controle the movement of bodyparts and organs, we can fuck around with them more. Summoning someones head or chest or heart will actually kill them now (and quite violently I must say (chest summoning gibs lol)). https://github.com/tgstation/tgstation/assets/7501474/5efc9dd3-cfd5-4ce4-b70f-d0d74894626e I´ve also added a unit test that violently tears apart and reconstructs a person in different ways to see if they get put toghether the right way This will definitely need a testmerge. I've done a lot of testing to make sure interactions work, but more niche stuff or my own incompetence can always slip through. ## Why It's Good For The Game A lot of organ work is quite restricted. You can't C4 someones heart, you cant summon their organs and a lot of exceptions have to be made to keep organs in nullspace. This lets organs (and bodyparts) play more nicely with the rest of the game. This also makes it a lot easier to move away from extorgans since a lot of their unique movement code has been removed and or generalized. I don't like making PRs of this size (I'm so sorry reviewers), but I was in a unique position to replace the entire system in a way I couldn't have done conveniently in multiple PRs ## Changelog :cl: refactor: Your organs are now inside your body. Please report any issues with bodypart and organ movement, including exotic organ, on github and scream at me fix: Cases of unexpected organ movement, such as teleporting bodyparts and organs with spells, now invokes a proper reaction (usually violent death) runtime: Fixes HARS runtiming on activation/deactivation fix: Fixes lag when species swapping /:cl: --- code/__DEFINES/organ_movement.dm | 4 + code/__DEFINES/traits/sources.dm | 2 + code/__HELPERS/mobs.dm | 5 - code/datums/ai/generic/generic_behaviors.dm | 4 + .../mutant_bodypart_overlay.dm | 14 +- code/datums/components/crafting/crafting.dm | 4 + code/datums/diseases/gastrolisis.dm | 2 +- code/datums/dna.dm | 1 - code/datums/mutations/body.dm | 4 +- code/datums/quirks/negative_quirks/junkie.dm | 2 +- .../negative_quirks/prosthetic_organ.dm | 2 +- code/datums/quirks/negative_quirks/tin_man.dm | 2 +- code/datums/station_traits/positive_traits.dm | 2 +- code/datums/status_effects/neutral.dm | 2 +- .../dna_infuser/organ_sets/carp_organs.dm | 23 +- .../dna_infuser/organ_sets/fox_organs.dm | 4 +- .../dna_infuser/organ_sets/goliath_organs.dm | 4 +- .../dna_infuser/organ_sets/gondola_organs.dm | 12 +- .../dna_infuser/organ_sets/rat_organs.dm | 8 +- .../dna_infuser/organ_sets/roach_organs.dm | 23 +- code/game/machinery/recycler.dm | 4 + code/game/objects/items/body_egg.dm | 4 +- code/game/turfs/open/lava.dm | 2 +- code/modules/admin/verbs/admin.dm | 4 + code/modules/admin/verbs/secrets.dm | 4 +- .../antagonists/abductor/equipment/gland.dm | 4 +- .../abductor/equipment/glands/electric.dm | 4 +- .../abductor/equipment/glands/slime.dm | 4 +- .../antagonists/fugitive/fugitive_outfits.dm | 2 +- .../heretic/knowledge/lock_lore.dm | 3 +- .../antagonists/heretic/transmutation_rune.dm | 4 + .../antagonists/nightmare/nightmare_organs.dm | 12 +- .../chaplain/chaplain_vorpal_scythe.dm | 2 +- .../library/skill_learning/skillchip.dm | 2 +- .../equipment/monster_organs/monster_organ.dm | 4 +- .../equipment/monster_organs/rush_gland.dm | 4 +- .../living/basic/lavaland/legion/legion.dm | 2 +- .../basic/lavaland/legion/legion_tumour.dm | 2 +- .../basic/space_fauna/demon/demon_items.dm | 4 +- code/modules/mob/living/blood.dm | 2 +- code/modules/mob/living/brain/brain_item.dm | 48 ++-- .../modules/mob/living/carbon/alien/organs.dm | 18 +- code/modules/mob/living/carbon/carbon.dm | 23 +- code/modules/mob/living/carbon/death.dm | 6 +- .../mob/living/carbon/human/_species.dm | 16 +- .../mob/living/carbon/human/human_defines.dm | 1 + .../carbon/human/species_types/felinid.dm | 12 +- .../carbon/human/species_types/monkeys.dm | 4 +- .../carbon/human/species_types/vampire.dm | 4 +- code/modules/mob/living/living.dm | 2 +- .../mob_spawn/corpses/mining_corpses.dm | 2 +- code/modules/religion/burdened/psyker.dm | 8 +- .../spells/spell_types/self/summonitem.dm | 12 +- code/modules/surgery/bodyparts/_bodyparts.dm | 215 ++++++++-------- .../surgery/bodyparts/dismemberment.dm | 110 ++++----- code/modules/surgery/bodyparts/head.dm | 55 +---- code/modules/surgery/bodyparts/helpers.dm | 3 +- code/modules/surgery/bodyparts/parts.dm | 195 ++++++++------- .../bodyparts/species_parts/misc_bodyparts.dm | 30 ++- code/modules/surgery/organs/_organ.dm | 151 +----------- .../organs/external/_external_organ.dm | 86 ++----- .../surgery/organs/external/restyling.dm | 2 +- .../modules/surgery/organs/external/spines.dm | 4 +- code/modules/surgery/organs/external/tails.dm | 17 +- .../organs/external/wings/functional_wings.dm | 4 +- .../organs/external/wings/moth_wings.dm | 4 +- .../organs/internal/_internal_organ.dm | 25 +- .../organs/internal/appendix/_appendix.dm | 4 +- .../internal/appendix/appendix_golem.dm | 4 +- .../organs/internal/cyberimp/augments_arms.dm | 14 +- .../internal/cyberimp/augments_chest.dm | 2 +- .../organs/internal/cyberimp/augments_eyes.dm | 4 +- .../internal/cyberimp/augments_internal.dm | 6 +- .../surgery/organs/internal/ears/_ears.dm | 16 +- .../surgery/organs/internal/eyes/_eyes.dm | 25 +- .../surgery/organs/internal/heart/_heart.dm | 8 +- .../organs/internal/heart/heart_ethereal.dm | 4 +- .../surgery/organs/internal/liver/_liver.dm | 8 +- .../surgery/organs/internal/lungs/_lungs.dm | 4 +- .../organs/internal/stomach/_stomach.dm | 6 +- .../internal/stomach/stomach_ethereal.dm | 4 +- .../organs/internal/stomach/stomach_golem.dm | 4 +- .../surgery/organs/internal/tongue/_tongue.dm | 4 +- code/modules/surgery/organs/organ_movement.dm | 230 ++++++++++++++++++ code/modules/unit_tests/_unit_tests.dm | 1 + code/modules/unit_tests/heretic_rituals.dm | 9 +- .../unit_tests/human_through_recycler.dm | 7 +- code/modules/unit_tests/ling_decap.dm | 4 +- .../unit_tests/organ_bodypart_shuffle.dm | 34 +++ code/modules/unit_tests/organ_set_bonus.dm | 2 +- code/modules/unit_tests/organs.dm | 10 +- .../unit_tests/species_change_organs.dm | 2 +- code/modules/unit_tests/tail_wag.dm | 4 +- .../wiremod/shell/brain_computer_interface.dm | 5 - code/modules/zombie/organs.dm | 10 +- tgstation.dme | 2 + 96 files changed, 893 insertions(+), 798 deletions(-) create mode 100644 code/__DEFINES/organ_movement.dm create mode 100644 code/modules/surgery/organs/organ_movement.dm create mode 100644 code/modules/unit_tests/organ_bodypart_shuffle.dm diff --git a/code/__DEFINES/organ_movement.dm b/code/__DEFINES/organ_movement.dm new file mode 100644 index 00000000000..16f003ede81 --- /dev/null +++ b/code/__DEFINES/organ_movement.dm @@ -0,0 +1,4 @@ +/// Delete the organ if replaced +#define DELETE_IF_REPLACED (1<<0) +/// When deleting a brain, we don't delete the identity and the player can keep playing +#define NO_ID_TRANSFER (1<<1) diff --git a/code/__DEFINES/traits/sources.dm b/code/__DEFINES/traits/sources.dm index f0b67a95b92..f9cdbe4326d 100644 --- a/code/__DEFINES/traits/sources.dm +++ b/code/__DEFINES/traits/sources.dm @@ -275,5 +275,7 @@ #define ANALYZER_TRAIT "analyzer_trait" +/// Trait from an organ being inside a bodypart +#define ORGAN_INSIDE_BODY_TRAIT "organ_inside_body" /// Trait when something was labelled by a pen. #define PEN_LABEL_TRAIT "pen_label" diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index 1c4958a0b03..a8cbdf950be 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -654,11 +654,6 @@ GLOBAL_LIST_EMPTY(species_list) if(isliving(occupant)) mob_occupant = occupant - else if(isbodypart(occupant)) - var/obj/item/bodypart/head/head = occupant - - mob_occupant = head.brainmob - else if(isorgan(occupant)) var/obj/item/organ/internal/brain/brain = occupant mob_occupant = brain.brainmob diff --git a/code/datums/ai/generic/generic_behaviors.dm b/code/datums/ai/generic/generic_behaviors.dm index 962c8d141cd..a5838e1811e 100644 --- a/code/datums/ai/generic/generic_behaviors.dm +++ b/code/datums/ai/generic/generic_behaviors.dm @@ -359,6 +359,10 @@ continue if(thing.IsObscured()) continue + if(isitem(thing)) + var/obj/item/item = thing + if(item.item_flags & ABSTRACT) + continue possible_targets += thing if(!possible_targets.len) finish_action(controller, FALSE) diff --git a/code/datums/bodypart_overlays/mutant_bodypart_overlay.dm b/code/datums/bodypart_overlays/mutant_bodypart_overlay.dm index 10f76317897..57c11814c02 100644 --- a/code/datums/bodypart_overlays/mutant_bodypart_overlay.dm +++ b/code/datums/bodypart_overlays/mutant_bodypart_overlay.dm @@ -93,8 +93,8 @@ CRASH("External organ has no feature list, it will render invisible") ///Give the organ its color. Force will override the existing one. -/datum/bodypart_overlay/mutant/proc/inherit_color(obj/item/bodypart/ownerlimb, force) - if(isnull(ownerlimb)) +/datum/bodypart_overlay/mutant/proc/inherit_color(obj/item/bodypart/bodypart_owner, force) + if(isnull(bodypart_owner)) draw_color = null return TRUE @@ -103,14 +103,14 @@ switch(color_source) if(ORGAN_COLOR_OVERRIDE) - draw_color = override_color(ownerlimb.draw_color) + draw_color = override_color(bodypart_owner.draw_color) if(ORGAN_COLOR_INHERIT) - draw_color = ownerlimb.draw_color + draw_color = bodypart_owner.draw_color if(ORGAN_COLOR_HAIR) - if(!ishuman(ownerlimb.owner)) + if(!ishuman(bodypart_owner.owner)) return - var/mob/living/carbon/human/human_owner = ownerlimb.owner - var/obj/item/bodypart/head/my_head = human_owner.get_bodypart(BODY_ZONE_HEAD) //not always the same as ownerlimb + var/mob/living/carbon/human/human_owner = bodypart_owner.owner + var/obj/item/bodypart/head/my_head = human_owner.get_bodypart(BODY_ZONE_HEAD) //not always the same as bodypart_owner //head hair color takes priority, owner hair color is a backup if we lack a head or something if(my_head) draw_color = my_head.hair_color diff --git a/code/datums/components/crafting/crafting.dm b/code/datums/components/crafting/crafting.dm index 39c53be57d9..7f2753d6771 100644 --- a/code/datums/components/crafting/crafting.dm +++ b/code/datums/components/crafting/crafting.dm @@ -106,6 +106,10 @@ for(var/atom/movable/AM in range(radius_range, a)) if((AM.flags_1 & HOLOGRAM_1) || (blacklist && (AM.type in blacklist))) continue + if(isitem(AM)) + var/obj/item/item = AM + if(item.item_flags & ABSTRACT) //let's not tempt fate, shall we? + continue . += AM /datum/component/personal_crafting/proc/get_surroundings(atom/a, list/blacklist=null) diff --git a/code/datums/diseases/gastrolisis.dm b/code/datums/diseases/gastrolisis.dm index c3a24903b81..aab0fcded1d 100644 --- a/code/datums/diseases/gastrolisis.dm +++ b/code/datums/diseases/gastrolisis.dm @@ -40,7 +40,7 @@ var/obj/item/organ/internal/eyes/eyes = locate(/obj/item/organ/internal/eyes/snail) in affected_mob.organs if(!eyes && SPT_PROB(2.5, seconds_per_tick)) var/obj/item/organ/internal/eyes/snail/new_eyes = new() - new_eyes.Insert(affected_mob, drop_if_replaced = TRUE) + new_eyes.Insert(affected_mob) affected_mob.visible_message(span_warning("[affected_mob]'s eyes fall out, with snail eyes taking its place!"), \ span_userdanger("You scream in pain as your eyes are pushed out by your new snail eyes!")) affected_mob.emote("scream") diff --git a/code/datums/dna.dm b/code/datums/dna.dm index f3a6558ec00..6960a5e28dc 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -526,7 +526,6 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) update_body(is_creating = TRUE) update_mutations_overlay()// no lizard with human hulk overlay please. - /mob/proc/has_dna() return diff --git a/code/datums/mutations/body.dm b/code/datums/mutations/body.dm index 6c5243ac0ed..a02bf26d747 100644 --- a/code/datums/mutations/body.dm +++ b/code/datums/mutations/body.dm @@ -500,14 +500,16 @@ var/obj/item/organ/internal/brain/brain = owner.get_organ_slot(ORGAN_SLOT_BRAIN) if(brain) + brain.Remove(owner, special = TRUE) brain.zone = BODY_ZONE_CHEST + brain.Insert(owner, special = TRUE) var/obj/item/bodypart/head/head = owner.get_bodypart(BODY_ZONE_HEAD) if(head) owner.visible_message(span_warning("[owner]'s head splatters with a sickening crunch!"), ignored_mobs = list(owner)) new /obj/effect/gibspawner/generic(get_turf(owner), owner) - head.dismember(dam_type = BRUTE, silent = TRUE) head.drop_organs() + head.dismember(dam_type = BRUTE, silent = TRUE) qdel(head) RegisterSignal(owner, COMSIG_ATTEMPT_CARBON_ATTACH_LIMB, PROC_REF(abort_attachment)) diff --git a/code/datums/quirks/negative_quirks/junkie.dm b/code/datums/quirks/negative_quirks/junkie.dm index 269f6d2d96e..2ce29f743c3 100644 --- a/code/datums/quirks/negative_quirks/junkie.dm +++ b/code/datums/quirks/negative_quirks/junkie.dm @@ -134,7 +134,7 @@ smoker_lungs = /obj/item/organ/internal/lungs/smoker_lungs if(!isnull(smoker_lungs)) smoker_lungs = new smoker_lungs - smoker_lungs.Insert(carbon_holder, special = TRUE, drop_if_replaced = FALSE) + smoker_lungs.Insert(carbon_holder, special = TRUE, movement_flags = DELETE_IF_REPLACED) /datum/quirk/item_quirk/junkie/smoker/process(seconds_per_tick) . = ..() diff --git a/code/datums/quirks/negative_quirks/prosthetic_organ.dm b/code/datums/quirks/negative_quirks/prosthetic_organ.dm index 6330035b5a7..0fd5061a787 100644 --- a/code/datums/quirks/negative_quirks/prosthetic_organ.dm +++ b/code/datums/quirks/negative_quirks/prosthetic_organ.dm @@ -49,7 +49,7 @@ medical_record_text = "During physical examination, patient was found to have a low-budget prosthetic [slot_string]. \ Removal of these organs is known to be dangerous to the patient as well as the practitioner." old_organ = human_holder.get_organ_slot(organ_slot) - if(prosthetic.Insert(human_holder, special = TRUE, drop_if_replaced = TRUE)) + if(prosthetic.Insert(human_holder, special = TRUE)) old_organ.moveToNullspace() STOP_PROCESSING(SSobj, old_organ) diff --git a/code/datums/quirks/negative_quirks/tin_man.dm b/code/datums/quirks/negative_quirks/tin_man.dm index 5a4ab4b1357..3fea6893a75 100644 --- a/code/datums/quirks/negative_quirks/tin_man.dm +++ b/code/datums/quirks/negative_quirks/tin_man.dm @@ -30,7 +30,7 @@ for(var/organ_slot in possible_organ_slots) var/organ_path = possible_organ_slots[organ_slot] var/obj/item/organ/new_organ = new organ_path() - new_organ.Insert(human_holder, special = TRUE, drop_if_replaced = FALSE) + new_organ.Insert(human_holder, special = TRUE, movement_flags = DELETE_IF_REPLACED) /datum/quirk/tin_man/post_add() to_chat(quirk_holder, span_boldannounce("Most of your internal organs have been replaced with surplus prosthetics. They are fragile and will easily come apart under duress. \ diff --git a/code/datums/station_traits/positive_traits.dm b/code/datums/station_traits/positive_traits.dm index 2ed8a2e4bee..9b05a146555 100644 --- a/code/datums/station_traits/positive_traits.dm +++ b/code/datums/station_traits/positive_traits.dm @@ -334,7 +334,7 @@ ai.eyeobj.relay_speech = TRUE //surveillance upgrade. the ai gets cybernetics too. return var/obj/item/organ/internal/cybernetic = new cybernetic_type() - cybernetic.Insert(spawned, special = TRUE, drop_if_replaced = FALSE) + cybernetic.Insert(spawned, special = TRUE, movement_flags = DELETE_IF_REPLACED) /datum/station_trait/luxury_escape_pods name = "Luxury Escape Pods" diff --git a/code/datums/status_effects/neutral.dm b/code/datums/status_effects/neutral.dm index 50c93e7db8f..84f30ab7855 100644 --- a/code/datums/status_effects/neutral.dm +++ b/code/datums/status_effects/neutral.dm @@ -522,7 +522,7 @@ return if(prob(1))//low chance of the alternative reality returning to monkey var/obj/item/organ/external/tail/monkey/monkey_tail = new () - monkey_tail.Insert(human_mob, drop_if_replaced = FALSE) + monkey_tail.Insert(human_mob, movement_flags = DELETE_IF_REPLACED) var/datum/species/human_species = human_mob.dna?.species if(human_species) human_species.randomize_active_features(human_mob) diff --git a/code/game/machinery/dna_infuser/organ_sets/carp_organs.dm b/code/game/machinery/dna_infuser/organ_sets/carp_organs.dm index cbe6e1c31c7..afbb8404060 100644 --- a/code/game/machinery/dna_infuser/organ_sets/carp_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/carp_organs.dm @@ -48,7 +48,7 @@ AddElement(/datum/element/noticable_organ, "teeth are big and sharp.", BODY_ZONE_PRECISE_MOUTH) AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/carp) -/obj/item/organ/internal/tongue/carp/on_insert(mob/living/carbon/tongue_owner) +/obj/item/organ/internal/tongue/carp/on_mob_insert(mob/living/carbon/tongue_owner, special, movement_flags) . = ..() if(!ishuman(tongue_owner)) return @@ -57,12 +57,14 @@ return var/datum/species/rec_species = human_receiver.dna.species rec_species.update_no_equip_flags(tongue_owner, rec_species.no_equip_flags | ITEM_SLOT_MASK) - var/obj/item/bodypart/head/head = human_receiver.get_bodypart(BODY_ZONE_HEAD) - head.unarmed_damage_low = 10 - head.unarmed_damage_high = 15 - head.unarmed_effectiveness = 15 -/obj/item/organ/internal/tongue/carp/on_remove(mob/living/carbon/tongue_owner) +/obj/item/organ/internal/tongue/carp/on_bodypart_insert(obj/item/bodypart/limb) + . = ..() + limb.unarmed_damage_low = 10 + limb.unarmed_damage_high = 15 + limb.unarmed_effectiveness = 15 + +/obj/item/organ/internal/tongue/carp/on_mob_remove(mob/living/carbon/tongue_owner) . = ..() if(!ishuman(tongue_owner)) return @@ -71,7 +73,10 @@ return var/datum/species/rec_species = human_receiver.dna.species rec_species.update_no_equip_flags(tongue_owner, initial(rec_species.no_equip_flags)) - var/obj/item/bodypart/head/head = human_receiver.get_bodypart(BODY_ZONE_HEAD) + +/obj/item/organ/internal/tongue/carp/on_bodypart_remove(obj/item/bodypart/head) + . = ..() + head.unarmed_damage_low = initial(head.unarmed_damage_low) head.unarmed_damage_high = initial(head.unarmed_damage_high) head.unarmed_effectiveness = initial(head.unarmed_effectiveness) @@ -110,13 +115,13 @@ AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/carp) AddElement(/datum/element/noticable_organ, "seem%PRONOUN_S unable to stay still.") -/obj/item/organ/internal/brain/carp/on_insert(mob/living/carbon/brain_owner) +/obj/item/organ/internal/brain/carp/on_mob_insert(mob/living/carbon/brain_owner) . = ..() cooldown_timer = addtimer(CALLBACK(src, PROC_REF(unsatisfied_nomad)), cooldown_time, TIMER_STOPPABLE|TIMER_OVERRIDE|TIMER_UNIQUE) RegisterSignal(brain_owner, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(satisfied_nomad)) //technically you could get around the mood issue by extracting and reimplanting the brain but it will be far easier to just go one z there and back -/obj/item/organ/internal/brain/carp/on_remove(mob/living/carbon/brain_owner) +/obj/item/organ/internal/brain/carp/on_mob_remove(mob/living/carbon/brain_owner) . = ..() UnregisterSignal(brain_owner, COMSIG_MOVABLE_Z_CHANGED) deltimer(cooldown_timer) diff --git a/code/game/machinery/dna_infuser/organ_sets/fox_organs.dm b/code/game/machinery/dna_infuser/organ_sets/fox_organs.dm index 1b2f69f4ccc..ab33c1ad57e 100644 --- a/code/game/machinery/dna_infuser/organ_sets/fox_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/fox_organs.dm @@ -6,7 +6,7 @@ visual = TRUE damage_multiplier = 2 -/obj/item/organ/internal/ears/fox/on_insert(mob/living/carbon/human/ear_owner) +/obj/item/organ/internal/ears/fox/on_mob_insert(mob/living/carbon/human/ear_owner) . = ..() if(istype(ear_owner) && ear_owner.dna) color = ear_owner.hair_color @@ -14,7 +14,7 @@ ear_owner.dna.update_uf_block(DNA_EARS_BLOCK) ear_owner.update_body() -/obj/item/organ/internal/ears/fox/on_remove(mob/living/carbon/human/ear_owner) +/obj/item/organ/internal/ears/fox/on_mob_remove(mob/living/carbon/human/ear_owner) . = ..() if(istype(ear_owner) && ear_owner.dna) color = ear_owner.hair_color diff --git a/code/game/machinery/dna_infuser/organ_sets/goliath_organs.dm b/code/game/machinery/dna_infuser/organ_sets/goliath_organs.dm index 6cd753eb760..477b461bdf3 100644 --- a/code/game/machinery/dna_infuser/organ_sets/goliath_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/goliath_organs.dm @@ -66,7 +66,7 @@ AddElement(/datum/element/noticable_organ, "arm is just a mass of plate and tendrils.", BODY_ZONE_CHEST) AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/goliath) -/obj/item/organ/internal/brain/goliath/on_insert(mob/living/carbon/brain_owner) +/obj/item/organ/internal/brain/goliath/on_mob_insert(mob/living/carbon/brain_owner) . = ..() if(!ishuman(brain_owner)) return @@ -78,7 +78,7 @@ hammer = new/obj/item/goliath_infuser_hammer brain_owner.put_in_hands(hammer) -/obj/item/organ/internal/brain/goliath/on_remove(mob/living/carbon/brain_owner) +/obj/item/organ/internal/brain/goliath/on_mob_remove(mob/living/carbon/brain_owner) . = ..() UnregisterSignal(brain_owner) if(!ishuman(brain_owner)) diff --git a/code/game/machinery/dna_infuser/organ_sets/gondola_organs.dm b/code/game/machinery/dna_infuser/organ_sets/gondola_organs.dm index 515c56622c4..2a5c776709c 100644 --- a/code/game/machinery/dna_infuser/organ_sets/gondola_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/gondola_organs.dm @@ -33,7 +33,7 @@ Fluoride Stare: After someone says 5 words, blah blah blah... AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/gondola) AddElement(/datum/element/noticable_organ, "radiate%PRONOUN_S an aura of serenity.") -/obj/item/organ/internal/heart/gondola/Insert(mob/living/carbon/receiver, special, drop_if_replaced) +/obj/item/organ/internal/heart/gondola/Insert(mob/living/carbon/receiver, special, movement_flags) . = ..() if(!(FACTION_HOSTILE in receiver.faction)) factions_to_remove += FACTION_HOSTILE @@ -41,7 +41,7 @@ Fluoride Stare: After someone says 5 words, blah blah blah... factions_to_remove += FACTION_MINING receiver.faction |= list(FACTION_HOSTILE, FACTION_MINING) -/obj/item/organ/internal/heart/gondola/Remove(mob/living/carbon/heartless, special) +/obj/item/organ/internal/heart/gondola/Remove(mob/living/carbon/heartless, special, movement_flags) . = ..() for(var/faction in factions_to_remove) heartless.faction -= faction @@ -63,11 +63,11 @@ Fluoride Stare: After someone says 5 words, blah blah blah... AddElement(/datum/element/noticable_organ, "mouth is permanently affixed into a relaxed smile.", BODY_ZONE_PRECISE_MOUTH) AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/gondola) -/obj/item/organ/internal/tongue/gondola/Insert(mob/living/carbon/tongue_owner, special, drop_if_replaced) +/obj/item/organ/internal/tongue/gondola/Insert(mob/living/carbon/tongue_owner, special, movement_flags) . = ..() tongue_owner.add_mood_event("gondola_zen", /datum/mood_event/gondola_serenity) -/obj/item/organ/internal/tongue/gondola/Remove(mob/living/carbon/tongue_owner, special) +/obj/item/organ/internal/tongue/gondola/Remove(mob/living/carbon/tongue_owner, special, movement_flags) tongue_owner.clear_mood_event("gondola_zen") return ..() @@ -89,7 +89,7 @@ Fluoride Stare: After someone says 5 words, blah blah blah... AddElement(/datum/element/noticable_organ, "right arm has small needles breaching the skin all over it.", BODY_ZONE_R_ARM) pax_hugs = new -/obj/item/organ/internal/liver/gondola/Insert(mob/living/carbon/liver_owner, special, drop_if_replaced) +/obj/item/organ/internal/liver/gondola/Insert(mob/living/carbon/liver_owner, special, movement_flags) . = ..() var/has_left = liver_owner.has_left_hand(check_disabled = FALSE) var/has_right = liver_owner.has_right_hand(check_disabled = FALSE) @@ -104,7 +104,7 @@ Fluoride Stare: After someone says 5 words, blah blah blah... RegisterSignal(liver_owner, COMSIG_HUMAN_EQUIPPING_ITEM, PROC_REF(on_owner_equipping_item)) RegisterSignal(liver_owner, COMSIG_LIVING_TRY_PULL, PROC_REF(on_owner_try_pull)) -/obj/item/organ/internal/liver/gondola/Remove(mob/living/carbon/liver_owner, special) +/obj/item/organ/internal/liver/gondola/Remove(mob/living/carbon/liver_owner, special, movement_flags) . = ..() pax_hugs.remove(liver_owner) UnregisterSignal(liver_owner, list(COMSIG_HUMAN_EQUIPPING_ITEM, COMSIG_LIVING_TRY_PULL)) diff --git a/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm b/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm index 96c33871a40..092a4c7889a 100644 --- a/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm @@ -63,7 +63,7 @@ AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/rat) AddElement(/datum/element/noticable_organ, "hunch%PRONOUN_ES over unnaturally!") -/obj/item/organ/internal/heart/rat/on_insert(mob/living/carbon/receiver) +/obj/item/organ/internal/heart/rat/on_mob_insert(mob/living/carbon/receiver) . = ..() if(!. || !ishuman(receiver)) return @@ -75,7 +75,7 @@ if(human_receiver.physiology) human_receiver.physiology.damage_resistance -= 50 -/obj/item/organ/internal/heart/rat/on_remove(mob/living/carbon/heartless, special) +/obj/item/organ/internal/heart/rat/on_mob_remove(mob/living/carbon/heartless, special) . = ..() if(!ishuman(heartless)) return @@ -113,11 +113,11 @@ if(message == "hi?") speech_args[SPEECH_MESSAGE] = "Um... cheesed to meet you?" -/obj/item/organ/internal/tongue/rat/on_insert(mob/living/carbon/tongue_owner, special, drop_if_replaced) +/obj/item/organ/internal/tongue/rat/on_mob_insert(mob/living/carbon/tongue_owner, special, movement_flags) . = ..() RegisterSignal(tongue_owner, COMSIG_CARBON_ITEM_GIVEN, PROC_REF(its_on_the_mouse)) -/obj/item/organ/internal/tongue/rat/on_remove(mob/living/carbon/tongue_owner) +/obj/item/organ/internal/tongue/rat/on_mob_remove(mob/living/carbon/tongue_owner) . = ..() UnregisterSignal(tongue_owner, COMSIG_CARBON_ITEM_GIVEN) diff --git a/code/game/machinery/dna_infuser/organ_sets/roach_organs.dm b/code/game/machinery/dna_infuser/organ_sets/roach_organs.dm index f10c9b039f2..0644bca0354 100644 --- a/code/game/machinery/dna_infuser/organ_sets/roach_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/roach_organs.dm @@ -71,7 +71,7 @@ QDEL_NULL(roach_shell) return ..() -/obj/item/organ/internal/heart/roach/on_insert(mob/living/carbon/organ_owner, special) +/obj/item/organ/internal/heart/roach/on_mob_insert(mob/living/carbon/organ_owner, special) . = ..() if(!ishuman(organ_owner)) return @@ -82,11 +82,11 @@ RegisterSignal(human_owner, COMSIG_MOB_AFTER_APPLY_DAMAGE, PROC_REF(do_block_effect)) human_owner.physiology.knockdown_mod *= 3 - var/obj/item/bodypart/chest/chest = human_owner.get_bodypart(BODY_ZONE_CHEST) - chest.add_bodypart_overlay(roach_shell) - human_owner.update_body_parts() +/obj/item/organ/internal/heart/roach/on_bodypart_insert(obj/item/bodypart/limb) + . = ..() + limb.add_bodypart_overlay(roach_shell) -/obj/item/organ/internal/heart/roach/on_remove(mob/living/carbon/organ_owner, special) +/obj/item/organ/internal/heart/roach/on_mob_remove(mob/living/carbon/organ_owner, special) . = ..() if(!ishuman(organ_owner) || QDELETED(organ_owner)) return @@ -96,9 +96,10 @@ UnregisterSignal(human_owner, list(COMSIG_MOB_APPLY_DAMAGE_MODIFIERS, COMSIG_MOB_AFTER_APPLY_DAMAGE)) human_owner.physiology.knockdown_mod /= 3 - var/obj/item/bodypart/chest/chest = human_owner.get_bodypart(BODY_ZONE_CHEST) - chest.remove_bodypart_overlay(roach_shell) - human_owner.update_body_parts() +/obj/item/organ/internal/heart/roach/on_bodypart_remove(obj/item/bodypart/limb) + . = ..() + + limb.remove_bodypart_overlay(roach_shell) /** * Signal proc for [COMSIG_MOB_APPLY_DAMAGE_MODIFIERS] @@ -193,7 +194,7 @@ . = ..() AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/roach) -/obj/item/organ/internal/liver/roach/on_insert(mob/living/carbon/organ_owner, special) +/obj/item/organ/internal/liver/roach/on_mob_insert(mob/living/carbon/organ_owner, special) . = ..() if(!ishuman(organ_owner)) return @@ -201,13 +202,13 @@ var/mob/living/carbon/human/human_owner = owner human_owner.physiology.tox_mod *= 2 -/obj/item/organ/internal/liver/roach/on_remove(mob/living/carbon/organ_owner, special) +/obj/item/organ/internal/liver/roach/on_mob_remove(mob/living/carbon/organ_owner, special) . = ..() if(!ishuman(organ_owner) || QDELETED(organ_owner)) return var/mob/living/carbon/human/human_owner = organ_owner - human_owner.physiology.tox_mod /= 2 + human_owner.physiology.tox_mod *= 0.5 /// Roach appendix: /// No appendicitus! weee! diff --git a/code/game/machinery/recycler.dm b/code/game/machinery/recycler.dm index a17d9b845b0..50751d95b5f 100644 --- a/code/game/machinery/recycler.dm +++ b/code/game/machinery/recycler.dm @@ -151,6 +151,10 @@ var/obj/item/mmi/as_mmi = thing if(istype(thing, /obj/item/organ/internal/brain) || (istype(as_head) && as_head.brain) || (istype(as_mmi) && as_mmi.brain) || istype(thing, /obj/item/dullahan_relay)) living_detected = TRUE + if(isitem(as_object)) + var/obj/item/as_item = as_object + if(as_item.item_flags & ABSTRACT) //also catches organs and bodyparts *stares* + continue nom += thing else if(isliving(thing)) living_detected = TRUE diff --git a/code/game/objects/items/body_egg.dm b/code/game/objects/items/body_egg.dm index f95b9f2e164..d244d8c55cc 100644 --- a/code/game/objects/items/body_egg.dm +++ b/code/game/objects/items/body_egg.dm @@ -15,7 +15,7 @@ if(iscarbon(loc)) Insert(loc) -/obj/item/organ/internal/body_egg/Insert(mob/living/carbon/egg_owner, special = FALSE, drop_if_replaced = TRUE) +/obj/item/organ/internal/body_egg/Insert(mob/living/carbon/egg_owner, special = FALSE, movement_flags = DELETE_IF_REPLACED) . = ..() if(!.) return @@ -23,7 +23,7 @@ egg_owner.med_hud_set_status() INVOKE_ASYNC(src, PROC_REF(AddInfectionImages), egg_owner) -/obj/item/organ/internal/body_egg/Remove(mob/living/carbon/egg_owner, special = FALSE) +/obj/item/organ/internal/body_egg/Remove(mob/living/carbon/egg_owner, special, movement_flags) . = ..() egg_owner.remove_traits(list(TRAIT_XENO_HOST, TRAIT_XENO_IMMUNE), ORGAN_TRAIT) egg_owner.med_hud_set_status() diff --git a/code/game/turfs/open/lava.dm b/code/game/turfs/open/lava.dm index cce5a49e993..8b3fcb9f00a 100644 --- a/code/game/turfs/open/lava.dm +++ b/code/game/turfs/open/lava.dm @@ -418,7 +418,7 @@ if(BODY_ZONE_HEAD) plasmalimb = new /obj/item/bodypart/head/plasmaman - burn_human.del_and_replace_bodypart(plasmalimb) + burn_human.del_and_replace_bodypart(plasmalimb, special = TRUE) burn_human.update_body_parts() burn_human.emote("scream") burn_human.visible_message(span_warning("[burn_human]'s [burn_limb.plaintext_zone] melts down to the bone!"), \ diff --git a/code/modules/admin/verbs/admin.dm b/code/modules/admin/verbs/admin.dm index e62936ea413..1c0bd7806db 100644 --- a/code/modules/admin/verbs/admin.dm +++ b/code/modules/admin/verbs/admin.dm @@ -176,6 +176,10 @@ for(var/obj/item/W in M) if(!M.dropItemToGround(W)) + // I hate that this is necessary, but the code is literally just dropping or deleting everything otherwise + // people should be allowed to keep their fucking organs + if(istype(W, /obj/item/organ) || istype(W, /obj/item/bodypart)) + continue qdel(W) M.regenerate_icons() diff --git a/code/modules/admin/verbs/secrets.dm b/code/modules/admin/verbs/secrets.dm index 6e26fb9754a..2a355e21714 100644 --- a/code/modules/admin/verbs/secrets.dm +++ b/code/modules/admin/verbs/secrets.dm @@ -506,8 +506,8 @@ GLOBAL_DATUM(everyone_a_traitor, /datum/everyone_is_a_traitor_controller) if(H.dna.features["tail_human"] == "None" || H.dna.features["ears"] == "None") var/obj/item/organ/internal/ears/cat/ears = new var/obj/item/organ/external/tail/cat/tail = new - ears.Insert(H, drop_if_replaced=FALSE) - tail.Insert(H, drop_if_replaced=FALSE) + ears.Insert(H, movement_flags = DELETE_IF_REPLACED) + tail.Insert(H, movement_flags = DELETE_IF_REPLACED) var/list/honorifics = list("[MALE]" = list("kun"), "[FEMALE]" = list("chan","tan"), "[NEUTER]" = list("san"), "[PLURAL]" = list("san")) //John Robust -> Robust-kun var/list/names = splittext(H.real_name," ") var/forename = names.len > 1 ? names[2] : names[1] diff --git a/code/modules/antagonists/abductor/equipment/gland.dm b/code/modules/antagonists/abductor/equipment/gland.dm index e29388c9fd6..960851280e3 100644 --- a/code/modules/antagonists/abductor/equipment/gland.dm +++ b/code/modules/antagonists/abductor/equipment/gland.dm @@ -84,7 +84,7 @@ active_mind_control = FALSE return TRUE -/obj/item/organ/internal/heart/gland/Remove(mob/living/carbon/gland_owner, special = FALSE) +/obj/item/organ/internal/heart/gland/Remove(mob/living/carbon/gland_owner, special, movement_flags) . = ..() active = FALSE if(initial(uses) == 1) @@ -93,7 +93,7 @@ hud.remove_atom_from_hud(gland_owner) clear_mind_control() -/obj/item/organ/internal/heart/gland/Insert(mob/living/carbon/gland_owner, special = FALSE, drop_if_replaced = TRUE) +/obj/item/organ/internal/heart/gland/Insert(mob/living/carbon/gland_owner, special = FALSE, movement_flags = DELETE_IF_REPLACED) . = ..() if(!.) return diff --git a/code/modules/antagonists/abductor/equipment/glands/electric.dm b/code/modules/antagonists/abductor/equipment/glands/electric.dm index a3107af0217..a5ec2cfde21 100644 --- a/code/modules/antagonists/abductor/equipment/glands/electric.dm +++ b/code/modules/antagonists/abductor/equipment/glands/electric.dm @@ -7,11 +7,11 @@ mind_control_uses = 2 mind_control_duration = 900 -/obj/item/organ/internal/heart/gland/electric/on_insert(mob/living/carbon/gland_owner) +/obj/item/organ/internal/heart/gland/electric/on_mob_insert(mob/living/carbon/gland_owner) . = ..() ADD_TRAIT(gland_owner, TRAIT_SHOCKIMMUNE, ABDUCTOR_GLAND_TRAIT) -/obj/item/organ/internal/heart/gland/electric/on_remove(mob/living/carbon/gland_owner) +/obj/item/organ/internal/heart/gland/electric/on_mob_remove(mob/living/carbon/gland_owner) . = ..() REMOVE_TRAIT(gland_owner, TRAIT_SHOCKIMMUNE, ABDUCTOR_GLAND_TRAIT) diff --git a/code/modules/antagonists/abductor/equipment/glands/slime.dm b/code/modules/antagonists/abductor/equipment/glands/slime.dm index 60e680bc2a9..853f0bb6473 100644 --- a/code/modules/antagonists/abductor/equipment/glands/slime.dm +++ b/code/modules/antagonists/abductor/equipment/glands/slime.dm @@ -7,12 +7,12 @@ mind_control_uses = 1 mind_control_duration = 2400 -/obj/item/organ/internal/heart/gland/slime/on_insert(mob/living/carbon/gland_owner) +/obj/item/organ/internal/heart/gland/slime/on_mob_insert(mob/living/carbon/gland_owner) . = ..() gland_owner.faction |= FACTION_SLIME gland_owner.grant_language(/datum/language/slime, source = LANGUAGE_GLAND) -/obj/item/organ/internal/heart/gland/slime/on_remove(mob/living/carbon/gland_owner) +/obj/item/organ/internal/heart/gland/slime/on_mob_remove(mob/living/carbon/gland_owner) . = ..() gland_owner.faction -= FACTION_SLIME gland_owner.remove_language(/datum/language/slime, source = LANGUAGE_GLAND) diff --git a/code/modules/antagonists/fugitive/fugitive_outfits.dm b/code/modules/antagonists/fugitive/fugitive_outfits.dm index ba1fe87bfbb..3efab657101 100644 --- a/code/modules/antagonists/fugitive/fugitive_outfits.dm +++ b/code/modules/antagonists/fugitive/fugitive_outfits.dm @@ -67,7 +67,7 @@ if(visualsOnly) return var/obj/item/organ/internal/eyes/robotic/glow/eyes = new() - eyes.Insert(H, drop_if_replaced = FALSE) + eyes.Insert(H, movement_flags = DELETE_IF_REPLACED) /datum/outfit/invisible_man name = "Invisible Man" diff --git a/code/modules/antagonists/heretic/knowledge/lock_lore.dm b/code/modules/antagonists/heretic/knowledge/lock_lore.dm index 6c6df4c6567..3550e287b6a 100644 --- a/code/modules/antagonists/heretic/knowledge/lock_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/lock_lore.dm @@ -199,8 +199,7 @@ for(var/mob/living/carbon/human/body in atoms) if(body.stat != DEAD) continue - var/obj/item/bodypart/chest = body.get_bodypart(BODY_ZONE_CHEST) - if(LAZYLEN(chest.get_organs())) + if(LAZYLEN(body.get_organs_for_zone(BODY_ZONE_CHEST))) to_chat(user, span_hierophant_warning("[body] has organs in their chest.")) continue diff --git a/code/modules/antagonists/heretic/transmutation_rune.dm b/code/modules/antagonists/heretic/transmutation_rune.dm index 55ca897342f..efd53418a78 100644 --- a/code/modules/antagonists/heretic/transmutation_rune.dm +++ b/code/modules/antagonists/heretic/transmutation_rune.dm @@ -80,6 +80,10 @@ for(var/atom/close_atom as anything in range(1, src)) if(!ismovable(close_atom)) continue + if(isitem(close_atom)) + var/obj/item/close_item = close_atom + if(close_item.item_flags & ABSTRACT) //woops sacrificed your own head + continue if(close_atom.invisibility) continue if(close_atom == user) diff --git a/code/modules/antagonists/nightmare/nightmare_organs.dm b/code/modules/antagonists/nightmare/nightmare_organs.dm index ce5ff427a21..fc3a4c52667 100644 --- a/code/modules/antagonists/nightmare/nightmare_organs.dm +++ b/code/modules/antagonists/nightmare/nightmare_organs.dm @@ -14,8 +14,10 @@ ///Our associated terrorize spell, for antagonist nightmares var/datum/action/cooldown/spell/pointed/terrorize/terrorize_spell -/obj/item/organ/internal/brain/shadow/nightmare/on_insert(mob/living/carbon/brain_owner) +/obj/item/organ/internal/brain/shadow/nightmare/on_mob_insert(mob/living/carbon/brain_owner) . = ..() + RegisterSignal(brain_owner, COMSIG_ATOM_PRE_BULLET_ACT, PROC_REF(dodge_bullets)) + if(brain_owner.dna.species.id != SPECIES_NIGHTMARE) brain_owner.set_species(/datum/species/shadow/nightmare) visible_message(span_warning("[brain_owner] thrashes as [src] takes root in [brain_owner.p_their()] body!")) @@ -27,9 +29,7 @@ terrorize_spell = new(src) terrorize_spell.Grant(brain_owner) - RegisterSignal(brain_owner, COMSIG_ATOM_PRE_BULLET_ACT, PROC_REF(dodge_bullets)) - -/obj/item/organ/internal/brain/shadow/nightmare/on_remove(mob/living/carbon/brain_owner) +/obj/item/organ/internal/brain/shadow/nightmare/on_mob_remove(mob/living/carbon/brain_owner) . = ..() QDEL_NULL(our_jaunt) QDEL_NULL(terrorize_spell) @@ -76,13 +76,13 @@ user.temporarilyRemoveItemFromInventory(src, TRUE) Insert(user) -/obj/item/organ/internal/heart/nightmare/on_insert(mob/living/carbon/heart_owner, special) +/obj/item/organ/internal/heart/nightmare/on_mob_insert(mob/living/carbon/heart_owner, special) . = ..() if(special != HEART_SPECIAL_SHADOWIFY) blade = new/obj/item/light_eater heart_owner.put_in_hands(blade) -/obj/item/organ/internal/heart/nightmare/on_remove(mob/living/carbon/heart_owner, special) +/obj/item/organ/internal/heart/nightmare/on_mob_remove(mob/living/carbon/heart_owner, special) . = ..() respawn_progress = 0 if(blade && special != HEART_SPECIAL_SHADOWIFY) diff --git a/code/modules/jobs/job_types/chaplain/chaplain_vorpal_scythe.dm b/code/modules/jobs/job_types/chaplain/chaplain_vorpal_scythe.dm index 3e752910a29..0dffeda5781 100644 --- a/code/modules/jobs/job_types/chaplain/chaplain_vorpal_scythe.dm +++ b/code/modules/jobs/job_types/chaplain/chaplain_vorpal_scythe.dm @@ -10,7 +10,7 @@ If the scythe isn't empowered when you sheath it, you take a heap of damage and desc = "This shard seems to be directly linked to some sinister entity. It might be your god! It also gives you a really horrible rash when you hold onto it for too long." items_to_create = list(/obj/item/vorpalscythe) -/obj/item/organ/internal/cyberimp/arm/shard/scythe/Insert(mob/living/carbon/receiver, special, drop_if_replaced) +/obj/item/organ/internal/cyberimp/arm/shard/scythe/Insert(mob/living/carbon/receiver, special, movement_flags) . = ..() if(receiver.mind) ADD_TRAIT(receiver.mind, TRAIT_MORBID, ORGAN_TRAIT) diff --git a/code/modules/library/skill_learning/skillchip.dm b/code/modules/library/skill_learning/skillchip.dm index a58fbec7c75..2ef7a20e680 100644 --- a/code/modules/library/skill_learning/skillchip.dm +++ b/code/modules/library/skill_learning/skillchip.dm @@ -106,7 +106,7 @@ return "Skillchip is not active." // Should not happen. Holding brain is destroyed and the chip hasn't had its state set appropriately. - if(QDELETED(holding_brain)) + if(!holding_brain) stack_trace("Skillchip's owner is null or qdeleted brain.") return "Skillchip cannot detect viable brain." diff --git a/code/modules/mining/equipment/monster_organs/monster_organ.dm b/code/modules/mining/equipment/monster_organs/monster_organ.dm index 699564c9ed7..8c1b031171f 100644 --- a/code/modules/mining/equipment/monster_organs/monster_organ.dm +++ b/code/modules/mining/equipment/monster_organs/monster_organ.dm @@ -69,7 +69,7 @@ deltimer(decay_timer) return ..() -/obj/item/organ/internal/monster_core/Insert(mob/living/carbon/target_carbon, special = FALSE, drop_if_replaced = TRUE) +/obj/item/organ/internal/monster_core/Insert(mob/living/carbon/target_carbon, special = FALSE, movement_flags) . = ..() if(!.) return @@ -83,7 +83,7 @@ target_carbon.visible_message(span_notice("[src] stabilizes as it's inserted.")) return TRUE -/obj/item/organ/internal/monster_core/Remove(mob/living/carbon/target_carbon, special = 0) +/obj/item/organ/internal/monster_core/Remove(mob/living/carbon/target_carbon, special, movement_flags) if (!inert && !special) owner.visible_message(span_notice("[src] rapidly decays as it's removed.")) go_inert() diff --git a/code/modules/mining/equipment/monster_organs/rush_gland.dm b/code/modules/mining/equipment/monster_organs/rush_gland.dm index 3554d67b2a6..b3932afdaab 100644 --- a/code/modules/mining/equipment/monster_organs/rush_gland.dm +++ b/code/modules/mining/equipment/monster_organs/rush_gland.dm @@ -21,11 +21,11 @@ if (owner.health <= HEALTH_DANGER_ZONE) trigger_organ_action() -/obj/item/organ/internal/monster_core/rush_gland/on_insert(mob/living/carbon/organ_owner) +/obj/item/organ/internal/monster_core/rush_gland/on_mob_insert(mob/living/carbon/organ_owner) . = ..() RegisterSignal(organ_owner, COMSIG_GOLIATH_TENTACLED_GRABBED, PROC_REF(trigger_organ_action)) -/obj/item/organ/internal/monster_core/rush_gland/on_remove(mob/living/carbon/organ_owner, special) +/obj/item/organ/internal/monster_core/rush_gland/on_mob_remove(mob/living/carbon/organ_owner, special) . = ..() UnregisterSignal(organ_owner, COMSIG_GOLIATH_TENTACLED_GRABBED) diff --git a/code/modules/mob/living/basic/lavaland/legion/legion.dm b/code/modules/mob/living/basic/lavaland/legion/legion.dm index 080f397226e..3a18a0703e6 100644 --- a/code/modules/mob/living/basic/lavaland/legion/legion.dm +++ b/code/modules/mob/living/basic/lavaland/legion/legion.dm @@ -83,7 +83,7 @@ return // Congratulations you have won a special prize: cancer var/obj/item/organ/internal/legion_tumour/cancer = new() - cancer.Insert(consumed, special = TRUE, drop_if_replaced = FALSE) + cancer.Insert(consumed, special = TRUE, movement_flags = DELETE_IF_REPLACED) /// A Legion which only drops skeletons instead of corpses which might have fun loot, so it cannot be farmed diff --git a/code/modules/mob/living/basic/lavaland/legion/legion_tumour.dm b/code/modules/mob/living/basic/lavaland/legion/legion_tumour.dm index 078af57de2a..55c1e6426b3 100644 --- a/code/modules/mob/living/basic/lavaland/legion/legion_tumour.dm +++ b/code/modules/mob/living/basic/lavaland/legion/legion_tumour.dm @@ -50,7 +50,7 @@ animate(transform = matrix(), time = 0.5 SECONDS / speed_divider, easing = SINE_EASING | EASE_IN) animate(transform = matrix(), time = 2 SECONDS / speed_divider) -/obj/item/organ/internal/legion_tumour/Remove(mob/living/carbon/egg_owner, special) +/obj/item/organ/internal/legion_tumour/Remove(mob/living/carbon/egg_owner, special, movement_flags) . = ..() stage = 0 elapsed_time = 0 diff --git a/code/modules/mob/living/basic/space_fauna/demon/demon_items.dm b/code/modules/mob/living/basic/space_fauna/demon/demon_items.dm index 8cdd7a6cf53..1cc7549f0ea 100644 --- a/code/modules/mob/living/basic/space_fauna/demon/demon_items.dm +++ b/code/modules/mob/living/basic/space_fauna/demon/demon_items.dm @@ -33,13 +33,13 @@ user.temporarilyRemoveItemFromInventory(src, TRUE) src.Insert(user) //Consuming the heart literally replaces your heart with a demon heart. H A R D C O R E -/obj/item/organ/internal/heart/demon/on_insert(mob/living/carbon/heart_owner) +/obj/item/organ/internal/heart/demon/on_mob_insert(mob/living/carbon/heart_owner) . = ..() // Gives a non-eat-people crawl to the new owner var/datum/action/cooldown/spell/jaunt/bloodcrawl/crawl = new(heart_owner) crawl.Grant(heart_owner) -/obj/item/organ/internal/heart/demon/on_remove(mob/living/carbon/heart_owner, special = FALSE) +/obj/item/organ/internal/heart/demon/on_mob_remove(mob/living/carbon/heart_owner, special = FALSE) . = ..() var/datum/action/cooldown/spell/jaunt/bloodcrawl/crawl = locate() in heart_owner.actions qdel(crawl) diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm index bc0d2e3d8e8..0818532cc4d 100644 --- a/code/modules/mob/living/blood.dm +++ b/code/modules/mob/living/blood.dm @@ -286,7 +286,7 @@ return /datum/reagent/blood /mob/living/carbon/human/get_blood_id() - if(HAS_TRAIT(src, TRAIT_HUSK)) + if(HAS_TRAIT(src, TRAIT_HUSK) || !dna) return if(check_holidays(APRIL_FOOLS) && is_clown_job(mind?.assigned_role)) return /datum/reagent/colorful_reagent diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm index 8f29a7d2be7..b09513c42de 100644 --- a/code/modules/mob/living/brain/brain_item.dm +++ b/code/modules/mob/living/brain/brain_item.dm @@ -47,7 +47,14 @@ // Brain size logic transform = transform.Scale(brain_size) -/obj/item/organ/internal/brain/Insert(mob/living/carbon/brain_owner, special = FALSE, drop_if_replaced = TRUE, no_id_transfer = FALSE) +/obj/item/organ/internal/brain/examine() + . = ..() + if(brain_size < 1) + . += span_notice("It is a bit on the smaller side...") + if(brain_size > 1) + . += span_notice("It is bigger than average...") + +/obj/item/organ/internal/brain/mob_insert(mob/living/carbon/brain_owner, special = FALSE, movement_flags) . = ..() if(!.) return @@ -55,7 +62,7 @@ name = initial(name) // Special check for if you're trapped in a body you can't control because it's owned by a ling. - if(brain_owner?.mind?.has_antag_datum(/datum/antagonist/changeling) && !no_id_transfer) + if(brain_owner?.mind?.has_antag_datum(/datum/antagonist/changeling) && !(movement_flags & NO_ID_TRANSFER)) if(brainmob && !(brain_owner.stat == DEAD || (HAS_TRAIT(brain_owner, TRAIT_DEATHCOMA)))) to_chat(brainmob, span_danger("You can't feel your body! You're still just a brain!")) forceMove(brain_owner) @@ -102,25 +109,11 @@ //Update the body's icon so it doesnt appear debrained anymore brain_owner.update_body_parts() -/obj/item/organ/internal/brain/on_insert(mob/living/carbon/organ_owner, special) - // Are we inserting into a new mob from a head? - // If yes, we want to quickly steal the brainmob from the head before we do anything else. - // This is usually stuff like reattaching dismembered/amputated heads. - if(istype(loc, /obj/item/bodypart/head)) - var/obj/item/bodypart/head/brain_holder = loc - if(brain_holder.brainmob) - brainmob = brain_holder.brainmob - brain_holder.brainmob = null - brainmob.container = null - brainmob.forceMove(src) - - return ..() - -/obj/item/organ/internal/brain/Remove(mob/living/carbon/brain_owner, special = 0, no_id_transfer = FALSE) +/obj/item/organ/internal/brain/mob_remove(mob/living/carbon/organ_owner, special, movement_flags) // Delete skillchips first as parent proc sets owner to null, and skillchips need to know the brain's owner. - if(!QDELETED(brain_owner) && length(skillchips)) + if(!QDELETED(organ_owner) && length(skillchips)) if(!special) - to_chat(brain_owner, span_notice("You feel your skillchips enable emergency power saving mode, deactivating as your brain leaves your body...")) + to_chat(organ_owner, span_notice("You feel your skillchips enable emergency power saving mode, deactivating as your brain leaves your body...")) for(var/chip in skillchips) var/obj/item/skillchip/skillchip = chip // Run the try_ proc with force = TRUE. @@ -133,10 +126,11 @@ BT.on_lose(TRUE) BT.owner = null - if((!gc_destroyed || (owner && !owner.gc_destroyed)) && !no_id_transfer) - transfer_identity(brain_owner) - brain_owner.update_body_parts() - brain_owner.clear_mood_event("brain_damage") + if((!gc_destroyed || (owner && !owner.gc_destroyed)) && !(movement_flags & NO_ID_TRANSFER)) + transfer_identity(organ_owner) + if(!special) + organ_owner.update_body_parts() + organ_owner.clear_mood_event("brain_damage") /obj/item/organ/internal/brain/proc/transfer_identity(mob/living/L) name = "[L.name]'s [initial(name)]" @@ -417,11 +411,11 @@ icon_state = "random_fly_4" organ_traits = list(TRAIT_ADVANCEDTOOLUSER, TRAIT_LITERATE, TRAIT_CAN_STRIP) -/obj/item/organ/internal/brain/lustrous/before_organ_replacement(mob/living/carbon/organ_owner, special) +/obj/item/organ/internal/brain/lustrous/on_mob_remove(mob/living/carbon/organ_owner, special) . = ..() organ_owner.cure_trauma_type(/datum/brain_trauma/special/bluespace_prophet, TRAUMA_RESILIENCE_ABSOLUTE) -/obj/item/organ/internal/brain/lustrous/on_insert(mob/living/carbon/organ_owner, special) +/obj/item/organ/internal/brain/lustrous/on_mob_insert(mob/living/carbon/organ_owner, special) . = ..() organ_owner.gain_trauma(/datum/brain_trauma/special/bluespace_prophet, TRAUMA_RESILIENCE_ABSOLUTE) @@ -580,6 +574,6 @@ /// Brains REALLY like ghosting people. we need special tricks to avoid that, namely removing the old brain with no_id_transfer /obj/item/organ/internal/brain/replace_into(mob/living/carbon/new_owner) var/obj/item/organ/internal/brain/old_brain = new_owner.get_organ_slot(ORGAN_SLOT_BRAIN) - old_brain.Remove(new_owner, special = TRUE, no_id_transfer = TRUE) + old_brain.Remove(new_owner, special = TRUE, movement_flags = NO_ID_TRANSFER) qdel(old_brain) - return Insert(new_owner, special = TRUE, drop_if_replaced = FALSE, no_id_transfer = TRUE) + return Insert(new_owner, special = TRUE, movement_flags = NO_ID_TRANSFER | DELETE_IF_REPLACED) diff --git a/code/modules/mob/living/carbon/alien/organs.dm b/code/modules/mob/living/carbon/alien/organs.dm index a29b126dd8d..66f555b639a 100644 --- a/code/modules/mob/living/carbon/alien/organs.dm +++ b/code/modules/mob/living/carbon/alien/organs.dm @@ -69,14 +69,14 @@ else owner.adjustPlasma(0.1 * plasma_rate * delta_time) -/obj/item/organ/internal/alien/plasmavessel/on_insert(mob/living/carbon/organ_owner) +/obj/item/organ/internal/alien/plasmavessel/on_mob_insert(mob/living/carbon/organ_owner) . = ..() if(isalien(organ_owner)) var/mob/living/carbon/alien/target_alien = organ_owner target_alien.updatePlasmaDisplay() RegisterSignal(organ_owner, COMSIG_MOB_GET_STATUS_TAB_ITEMS, PROC_REF(get_status_tab_item)) -/obj/item/organ/internal/alien/plasmavessel/on_remove(mob/living/carbon/organ_owner) +/obj/item/organ/internal/alien/plasmavessel/on_mob_remove(mob/living/carbon/organ_owner) . = ..() if(isalien(organ_owner)) var/mob/living/carbon/alien/organ_owner_alien = organ_owner @@ -95,18 +95,18 @@ zone = BODY_ZONE_HEAD slot = ORGAN_SLOT_XENO_HIVENODE w_class = WEIGHT_CLASS_TINY + organ_traits = list(TRAIT_XENO_IMMUNE) actions_types = list(/datum/action/cooldown/alien/whisper) /// Indicates if the queen died recently, aliens are heavily weakened while this is active. var/recent_queen_death = FALSE -/obj/item/organ/internal/alien/hivenode/on_insert(mob/living/carbon/organ_owner) +/obj/item/organ/internal/alien/hivenode/on_mob_insert(mob/living/carbon/organ_owner) . = ..() organ_owner.faction |= ROLE_ALIEN - ADD_TRAIT(organ_owner, TRAIT_XENO_IMMUNE, ORGAN_TRAIT) -/obj/item/organ/internal/alien/hivenode/Remove(mob/living/carbon/organ_owner, special = FALSE) - organ_owner.faction -= ROLE_ALIEN - REMOVE_TRAIT(organ_owner, TRAIT_XENO_IMMUNE, ORGAN_TRAIT) +/obj/item/organ/internal/alien/hivenode/on_mob_remove(mob/living/carbon/organ_owner, special = FALSE) + if(organ_owner) + organ_owner.faction -= ROLE_ALIEN return ..() //When the alien queen dies, all aliens suffer a penalty as punishment for failing to protect her. @@ -232,11 +232,11 @@ stomach_contents -= source UnregisterSignal(source, list(COMSIG_MOVABLE_MOVED, COMSIG_LIVING_DEATH, COMSIG_QDELETING)) -/obj/item/organ/internal/stomach/alien/Insert(mob/living/carbon/stomach_owner, special = FALSE, drop_if_replaced = TRUE) +/obj/item/organ/internal/stomach/alien/Insert(mob/living/carbon/stomach_owner, special, movement_flags) RegisterSignal(stomach_owner, COMSIG_ATOM_RELAYMOVE, PROC_REF(something_moved)) return ..() -/obj/item/organ/internal/stomach/alien/Remove(mob/living/carbon/stomach_owner, special = FALSE) +/obj/item/organ/internal/stomach/alien/Remove(mob/living/carbon/stomach_owner, special, movement_flags) UnregisterSignal(stomach_owner, COMSIG_ATOM_RELAYMOVE) return ..() diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 01ef424b00f..a6761f85cbc 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -979,7 +979,6 @@ for(var/obj/item/bodypart/bodypart_path as anything in bodyparts_paths) var/real_body_part_path = overrides?[initial(bodypart_path.body_zone)] || bodypart_path var/obj/item/bodypart/bodypart_instance = new real_body_part_path() - bodypart_instance.set_owner(src) add_bodypart(bodypart_instance) /// Called when a new hand is added @@ -996,8 +995,12 @@ /mob/living/carbon/proc/add_bodypart(obj/item/bodypart/new_bodypart) SHOULD_NOT_OVERRIDE(TRUE) + new_bodypart.on_adding(src) bodyparts += new_bodypart - new_bodypart.set_owner(src) + new_bodypart.update_owner(src) + + for(var/obj/item/organ/organ in new_bodypart) + organ.mob_insert(src) switch(new_bodypart.body_part) if(LEG_LEFT, LEG_RIGHT) @@ -1012,10 +1015,17 @@ synchronize_bodytypes() ///Proc to hook behavior on bodypart removals. Do not directly call. You're looking for [/obj/item/bodypart/proc/drop_limb()]. -/mob/living/carbon/proc/remove_bodypart(obj/item/bodypart/old_bodypart) +/mob/living/carbon/proc/remove_bodypart(obj/item/bodypart/old_bodypart, special) SHOULD_NOT_OVERRIDE(TRUE) - old_bodypart.on_removal() + if(special) + for(var/obj/item/organ/organ in old_bodypart) + organ.bodypart_remove(limb_owner = src, movement_flags = NO_ID_TRANSFER) + else + for(var/obj/item/organ/organ in old_bodypart) + organ.mob_remove(src, special) + + old_bodypart.on_removal(src) bodyparts -= old_bodypart switch(old_bodypart.body_part) @@ -1413,3 +1423,8 @@ our_splatter.blood_dna_info = get_blood_dna_list() var/turf/targ = get_ranged_target_turf(src, splatter_direction, splatter_strength) our_splatter.fly_towards(targ, splatter_strength) + +/mob/living/carbon/dropItemToGround(obj/item/item, force = FALSE, silent = FALSE, invdrop = TRUE) + if(item && ((item in organs) || (item in bodyparts))) //let's not do this, aight? + return FALSE + return ..() diff --git a/code/modules/mob/living/carbon/death.dm b/code/modules/mob/living/carbon/death.dm index 78b8554361b..85a6b06a2d3 100644 --- a/code/modules/mob/living/carbon/death.dm +++ b/code/modules/mob/living/carbon/death.dm @@ -28,9 +28,9 @@ add_memory_in_range(src, 7, /datum/memory/witness_gib, protagonist = src) if(drop_bitflags & DROP_ITEMS) for(var/obj/item/W in src) - dropItemToGround(W) - if(prob(50)) - step(W, pick(GLOB.alldirs)) + if(dropItemToGround(W)) + if(prob(50)) + step(W, pick(GLOB.alldirs)) var/atom/Tsec = drop_location() for(var/mob/M in src) M.forceMove(Tsec) diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index e67651f0ce6..f0d4e644c4d 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -370,19 +370,17 @@ GLOBAL_LIST_EMPTY(features_by_species) health_pct = (existing_organ.maxHealth - existing_organ.damage) / existing_organ.maxHealth if(slot == ORGAN_SLOT_BRAIN) var/obj/item/organ/internal/brain/existing_brain = existing_organ - if(!existing_brain.decoy_override) - existing_brain.before_organ_replacement(new_organ) - existing_brain.Remove(organ_holder, special = TRUE, no_id_transfer = TRUE) - QDEL_NULL(existing_organ) + existing_brain.before_organ_replacement(new_organ) + existing_brain.Remove(organ_holder, special = TRUE, movement_flags = NO_ID_TRANSFER) else existing_organ.before_organ_replacement(new_organ) existing_organ.Remove(organ_holder, special = TRUE) - QDEL_NULL(existing_organ) - if(isnull(existing_organ) && should_have && !(new_organ.zone in excluded_zones)) + QDEL_NULL(existing_organ) + if(isnull(existing_organ) && should_have && !(new_organ.zone in excluded_zones) && organ_holder.get_bodypart(deprecise_zone(new_organ.zone))) used_neworgan = TRUE new_organ.set_organ_damage(new_organ.maxHealth * (1 - health_pct)) - new_organ.Insert(organ_holder, special = TRUE, drop_if_replaced = FALSE) + new_organ.Insert(organ_holder, special = TRUE, movement_flags = DELETE_IF_REPLACED) if(!used_neworgan) QDEL_NULL(new_organ) @@ -425,7 +423,7 @@ GLOBAL_LIST_EMPTY(features_by_species) if(current_organ) current_organ.before_organ_replacement(replacement) // organ.Insert will qdel any current organs in that slot, so we don't need to. - replacement.Insert(organ_holder, special=TRUE, drop_if_replaced=FALSE) + replacement.Insert(organ_holder, special=TRUE, movement_flags = DELETE_IF_REPLACED) /datum/species/proc/worn_items_fit_body_check(mob/living/carbon/wearer) for(var/obj/item/equipped_item in wearer.get_all_worn_items()) @@ -492,7 +490,7 @@ GLOBAL_LIST_EMPTY(features_by_species) //Load a persons preferences from DNA var/obj/item/organ/external/new_organ = SSwardrobe.provide_type(organ_path) - new_organ.Insert(human, special=TRUE, drop_if_replaced=FALSE) + new_organ.Insert(human, special=TRUE, movement_flags = DELETE_IF_REPLACED) diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 48980076f4e..00b59ffe25f 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -13,6 +13,7 @@ mob_biotypes = MOB_ORGANIC|MOB_HUMANOID can_be_shoved_into = TRUE initial_language_holder = /datum/language_holder/empty // We get stuff from our species + flags_1 = PREVENT_CONTENTS_EXPLOSION_1 //Hair colour and style var/hair_color = "#000000" diff --git a/code/modules/mob/living/carbon/human/species_types/felinid.dm b/code/modules/mob/living/carbon/human/species_types/felinid.dm index 161b42fff5b..277bc7d72af 100644 --- a/code/modules/mob/living/carbon/human/species_types/felinid.dm +++ b/code/modules/mob/living/carbon/human/species_types/felinid.dm @@ -41,7 +41,7 @@ target_human.dna.features["ears"] = "Cat" if(target_human.dna.features["ears"] == "Cat") var/obj/item/organ/internal/ears/cat/ears = new - ears.Insert(target_human, drop_if_replaced = FALSE) + ears.Insert(target_human, movement_flags = DELETE_IF_REPLACED) else mutantears = /obj/item/organ/internal/ears return ..() @@ -92,8 +92,8 @@ // Humans get converted directly to felinids, and the key is handled in on_species_gain. // Now when we get mob.dna.features[feature_key], it returns None, which is why the tail is invisible. // stored_feature_id is only set once (the first time an organ is inserted), so this should be safe. - kitty_ears.Insert(soon_to_be_felinid, special = TRUE, drop_if_replaced = FALSE) - kitty_tail.Insert(soon_to_be_felinid, special = TRUE, drop_if_replaced = FALSE) + kitty_ears.Insert(soon_to_be_felinid, special = TRUE, movement_flags = DELETE_IF_REPLACED) + kitty_tail.Insert(soon_to_be_felinid, special = TRUE, movement_flags = DELETE_IF_REPLACED) if(!silent) to_chat(soon_to_be_felinid, span_boldnotice("Something is nya~t right.")) playsound(get_turf(soon_to_be_felinid), 'sound/effects/meow1.ogg', 50, TRUE, -1) @@ -116,16 +116,16 @@ for(var/external_organ in target_species.external_organs) if(ispath(external_organ, /obj/item/organ/external/tail)) var/obj/item/organ/external/tail/new_tail = new external_organ() - new_tail.Insert(purrbated_human, special = TRUE, drop_if_replaced = FALSE) + new_tail.Insert(purrbated_human, special = TRUE, movement_flags = DELETE_IF_REPLACED) // Don't forget the spines we removed earlier else if(ispath(external_organ, /obj/item/organ/external/spines)) var/obj/item/organ/external/spines/new_spines = new external_organ() - new_spines.Insert(purrbated_human, special = TRUE, drop_if_replaced = FALSE) + new_spines.Insert(purrbated_human, special = TRUE, movement_flags = DELETE_IF_REPLACED) var/obj/item/organ/internal/ears/old_ears = purrbated_human.get_organ_slot(ORGAN_SLOT_EARS) if(istype(old_ears, /obj/item/organ/internal/ears/cat)) var/obj/item/organ/new_ears = new target_species.mutantears() - new_ears.Insert(purrbated_human, special = TRUE, drop_if_replaced = FALSE) + new_ears.Insert(purrbated_human, special = TRUE, movement_flags = DELETE_IF_REPLACED) if(!silent) to_chat(purrbated_human, span_boldnotice("You are no longer a cat.")) diff --git a/code/modules/mob/living/carbon/human/species_types/monkeys.dm b/code/modules/mob/living/carbon/human/species_types/monkeys.dm index 8fb36e7c4e2..8d0cbac2e7e 100644 --- a/code/modules/mob/living/carbon/human/species_types/monkeys.dm +++ b/code/modules/mob/living/carbon/human/species_types/monkeys.dm @@ -166,11 +166,11 @@ build_all_button_icons() -/obj/item/organ/internal/brain/primate/on_insert(mob/living/carbon/primate) +/obj/item/organ/internal/brain/primate/on_mob_insert(mob/living/carbon/primate) . = ..() RegisterSignal(primate, COMSIG_MOVABLE_CROSS, PROC_REF(on_crossed), TRUE) -/obj/item/organ/internal/brain/primate/on_remove(mob/living/carbon/primate) +/obj/item/organ/internal/brain/primate/on_mob_remove(mob/living/carbon/primate) . = ..() UnregisterSignal(primate, COMSIG_MOVABLE_CROSS) diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm index 6e56b13055b..427f1f5f71b 100644 --- a/code/modules/mob/living/carbon/human/species_types/vampire.dm +++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm @@ -203,11 +203,11 @@ name = "vampire heart" color = "#1C1C1C" -/obj/item/organ/internal/heart/vampire/on_insert(mob/living/carbon/receiver) +/obj/item/organ/internal/heart/vampire/on_mob_insert(mob/living/carbon/receiver) . = ..() RegisterSignal(receiver, COMSIG_MOB_GET_STATUS_TAB_ITEMS, PROC_REF(get_status_tab_item)) -/obj/item/organ/internal/heart/vampire/on_remove(mob/living/carbon/heartless) +/obj/item/organ/internal/heart/vampire/on_mob_remove(mob/living/carbon/heartless) . = ..() UnregisterSignal(heartless, COMSIG_MOB_GET_STATUS_TAB_ITEMS) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index b6ca0349aed..d11e5d5620b 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1391,7 +1391,7 @@ Robot.notify_ai(AI_NOTIFICATION_NEW_BORG) else for(var/obj/item/item in src) - if(!dropItemToGround(item)) + if(!dropItemToGround(item) && !(item.item_flags & ABSTRACT)) qdel(item) continue item_contents += item diff --git a/code/modules/mob_spawn/corpses/mining_corpses.dm b/code/modules/mob_spawn/corpses/mining_corpses.dm index 8b7ad474b16..972bb5c3fa5 100644 --- a/code/modules/mob_spawn/corpses/mining_corpses.dm +++ b/code/modules/mob_spawn/corpses/mining_corpses.dm @@ -27,7 +27,7 @@ /obj/effect/mob_spawn/corpse/human/legioninfested/special(mob/living/carbon/human/spawned_human) . = ..() var/obj/item/organ/internal/legion_tumour/cancer = new() - cancer.Insert(spawned_human, special = TRUE, drop_if_replaced = FALSE) + cancer.Insert(spawned_human, special = TRUE, movement_flags = DELETE_IF_REPLACED) /// Returns the outfit worn by our corpse /obj/effect/mob_spawn/corpse/human/legioninfested/proc/select_outfit() diff --git a/code/modules/religion/burdened/psyker.dm b/code/modules/religion/burdened/psyker.dm index 2b2df26a446..1fe730c1f5e 100644 --- a/code/modules/religion/burdened/psyker.dm +++ b/code/modules/religion/burdened/psyker.dm @@ -10,12 +10,12 @@ organ_traits = list(TRAIT_ADVANCEDTOOLUSER, TRAIT_LITERATE, TRAIT_CAN_STRIP, TRAIT_ANTIMAGIC_NO_SELFBLOCK) w_class = WEIGHT_CLASS_NORMAL -/obj/item/organ/internal/brain/psyker/on_insert(mob/living/carbon/inserted_into) +/obj/item/organ/internal/brain/psyker/on_mob_insert(mob/living/carbon/inserted_into) . = ..() inserted_into.AddComponent(/datum/component/echolocation, blocking_trait = TRAIT_DUMB, echo_group = "psyker", echo_icon = "psyker", color_path = /datum/client_colour/psyker) inserted_into.AddComponent(/datum/component/anti_magic, antimagic_flags = MAGIC_RESISTANCE_MIND) -/obj/item/organ/internal/brain/psyker/on_remove(mob/living/carbon/removed_from) +/obj/item/organ/internal/brain/psyker/on_mob_remove(mob/living/carbon/removed_from) . = ..() qdel(removed_from.GetComponent(/datum/component/echolocation)) qdel(removed_from.GetComponent(/datum/component/anti_magic)) @@ -82,9 +82,9 @@ qdel(old_head) var/obj/item/organ/internal/brain/psyker/psyker_brain = new() old_brain.before_organ_replacement(psyker_brain) - old_brain.Remove(src, special = TRUE, no_id_transfer = TRUE) + old_brain.Remove(src, special = TRUE, movement_flags = NO_ID_TRANSFER) qdel(old_brain) - psyker_brain.Insert(src, special = TRUE, drop_if_replaced = FALSE) + psyker_brain.Insert(src, special = TRUE, movement_flags = DELETE_IF_REPLACED) if(old_eyes) qdel(old_eyes) return TRUE diff --git a/code/modules/spells/spell_types/self/summonitem.dm b/code/modules/spells/spell_types/self/summonitem.dm index 62d6b078161..ab99f35271d 100644 --- a/code/modules/spells/spell_types/self/summonitem.dm +++ b/code/modules/spells/spell_types/self/summonitem.dm @@ -138,7 +138,6 @@ item_to_retrieve = null break - SEND_SIGNAL(holding_mark, COMSIG_MAGIC_RECALL, caster, item_to_retrieve) holding_mark.dropItemToGround(item_to_retrieve) else if(isobj(item_to_retrieve.loc)) @@ -157,15 +156,6 @@ infinite_recursion += 1 - else - // Organs are usually stored in nullspace - if(isorgan(item_to_retrieve)) - var/obj/item/organ/organ = item_to_retrieve - if(organ.owner) - // If this code ever runs I will be happy - log_combat(caster, organ.owner, "magically removed [organ.name] from", addition = "COMBAT MODE: [uppertext(caster.combat_mode)]") - organ.Remove(organ.owner) - if(!item_to_retrieve) return @@ -176,6 +166,8 @@ else item_to_retrieve.forceMove(caster.drop_location()) item_to_retrieve.loc.visible_message(span_warning("[item_to_retrieve] suddenly appears!")) + + SEND_SIGNAL(item_to_retrieve, COMSIG_MAGIC_RECALL, caster, item_to_retrieve) playsound(get_turf(item_to_retrieve), 'sound/magic/summonitems_generic.ogg', 50, TRUE) /datum/action/cooldown/spell/summonitem/abductor diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 1ff1082b4a4..020e0d36c01 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -6,6 +6,7 @@ w_class = WEIGHT_CLASS_SMALL icon = 'icons/mob/human/bodyparts.dmi' icon_state = "" //Leave this blank! Bodyparts are built using overlays + flags_1 = PREVENT_CONTENTS_EXPLOSION_1 //actually mindblowing /// The icon for Organic limbs using greyscale VAR_PROTECTED/icon_greyscale = DEFAULT_BODYPART_ICON_ORGANIC ///The icon for non-greyscale limbs @@ -19,7 +20,7 @@ layer = BELOW_MOB_LAYER //so it isn't hidden behind objects when on the floor grind_results = list(/datum/reagent/bone_dust = 10, /datum/reagent/consumable/liquidgibs = 5) // robotic bodyparts and chests/heads cannot be ground /// The mob that "owns" this limb - /// DO NOT MODIFY DIRECTLY. Use set_owner() + /// DO NOT MODIFY DIRECTLY. Use update_owner() var/mob/living/carbon/owner /// If this limb can be scarred. @@ -155,9 +156,6 @@ /// If something is currently grasping this bodypart and trying to staunch bleeding (see [/obj/item/hand_item/self_grasp]) var/obj/item/hand_item/self_grasp/grasped_by - ///A list of all the external organs we've got stored to draw horns, wings and stuff with (special because we are actually in the limbs unlike normal organs :/ ) - ///If someone ever comes around to making all organs exist in the bodyparts, you can just remove this and use a typed loop - var/list/obj/item/organ/external/external_organs = list() ///A list of all bodypart overlays to draw var/list/bodypart_overlays = list() @@ -232,31 +230,40 @@ refresh_bleed_rate() /obj/item/bodypart/Destroy() - if(owner) - owner.remove_bodypart(src) - set_owner(null) + if(owner && !QDELETED(owner)) + forced_removal(special = FALSE, dismembered = TRUE, move_to_floor = FALSE) + update_owner(null) for(var/wound in wounds) qdel(wound) // wounds is a lazylist, and each wound removes itself from it on deletion. if(length(wounds)) stack_trace("[type] qdeleted with [length(wounds)] uncleared wounds") wounds.Cut() - if(length(external_organs)) - for(var/obj/item/organ/external/external_organ as anything in external_organs) - external_organs -= external_organ - qdel(external_organ) // It handles removing its references to this limb on its own. + owner = null + + for(var/atom/movable/movable in contents) + qdel(movable) - external_organs = list() QDEL_LIST_ASSOC_VAL(feature_offsets) return ..() -/obj/item/bodypart/forceMove(atom/destination) //Please. Never forcemove a limb if its's actually in use. This is only for borgs. - SHOULD_CALL_PARENT(TRUE) +/obj/item/bodypart/ex_act(severity, target) + if(owner) //trust me bro you dont want this + return FALSE + return ..() - . = ..() - if(isturf(destination)) - update_icon_dropped() + +/obj/item/bodypart/proc/on_forced_removal(atom/old_loc, dir, forced, list/old_locs) + SIGNAL_HANDLER + + forced_removal(special = FALSE, dismembered = TRUE, move_to_floor = FALSE) + +/// In-case someone, somehow only teleports someones limb +/obj/item/bodypart/proc/forced_removal(special, dismembered, move_to_floor) + drop_limb(special, dismembered, move_to_floor) + + update_icon_dropped() /obj/item/bodypart/examine(mob/user) SHOULD_CALL_PARENT(TRUE) @@ -403,32 +410,25 @@ var/atom/drop_loc = drop_location() if(IS_ORGANIC_LIMB(src)) playsound(drop_loc, 'sound/misc/splort.ogg', 50, TRUE, -1) + QDEL_NULL(current_gauze) - for(var/obj/item/organ/bodypart_organ as anything in get_organs()) - bodypart_organ.transfer_to_limb(src, owner) - for(var/obj/item/organ/external/external as anything in external_organs) - external.remove_from_limb() - external.forceMove(drop_loc) - for(var/obj/item/item_in_bodypart in src) - item_in_bodypart.forceMove(drop_loc) + + for(var/obj/item/organ/bodypart_organ in contents) + if(bodypart_organ.organ_flags & ORGAN_UNREMOVABLE) + continue + if(owner) + bodypart_organ.Remove(bodypart_organ.owner) + else + if(bodypart_organ.bodypart_remove(src)) + if(drop_loc) //can be null if being deleted + bodypart_organ.forceMove(get_turf(drop_loc)) + + if(drop_loc) //can be null during deletion + for(var/atom/movable/movable as anything in src) + movable.forceMove(drop_loc) update_icon_dropped() -///since organs aren't actually stored in the bodypart themselves while attached to a person, we have to query the owner for what we should have -/obj/item/bodypart/proc/get_organs() - SHOULD_CALL_PARENT(TRUE) - RETURN_TYPE(/list) - - if(!owner) - return FALSE - - var/list/bodypart_organs - for(var/obj/item/organ/organ_check as anything in owner.organs) //internal organs inside the dismembered limb are dropped. - if(check_zone(organ_check.zone) == body_zone) - LAZYADD(bodypart_organs, organ_check) // this way if we don't have any, it'll just return null - - return bodypart_organs - //Return TRUE to get whatever mob this is in to update health. /obj/item/bodypart/proc/on_life(seconds_per_tick, times_fired) SHOULD_CALL_PARENT(TRUE) @@ -737,70 +737,91 @@ owner.update_health_hud() //update the healthdoll owner.update_body() -///Proc to change the value of the `owner` variable and react to the event of its change. -/obj/item/bodypart/proc/set_owner(new_owner) - SHOULD_CALL_PARENT(TRUE) +/// Proc to change the value of the `owner` variable and react to the event of its change. +/obj/item/bodypart/proc/update_owner(new_owner) + SHOULD_NOT_OVERRIDE(TRUE) + if(owner == new_owner) return FALSE //`null` is a valid option, so we need to use a num var to make it clear no change was made. - var/mob/living/carbon/old_owner = owner - owner = new_owner - SEND_SIGNAL(src, COMSIG_BODYPART_CHANGED_OWNER, new_owner, old_owner) - var/needs_update_disabled = FALSE //Only really relevant if there's an owner - if(old_owner) - if(held_index) - old_owner.on_lost_hand(src) - if(old_owner.hud_used) - var/atom/movable/screen/inventory/hand/hand = old_owner.hud_used.hand_slots["[held_index]"] - if(hand) - hand.update_appearance() - old_owner.update_worn_gloves() - if(speed_modifier) - old_owner.update_bodypart_speed_modifier() - if(length(bodypart_traits)) - old_owner.remove_traits(bodypart_traits, bodypart_trait_source) - if(initial(can_be_disabled)) - if(HAS_TRAIT(old_owner, TRAIT_NOLIMBDISABLE)) - if(!owner || !HAS_TRAIT(owner, TRAIT_NOLIMBDISABLE)) - set_can_be_disabled(initial(can_be_disabled)) - needs_update_disabled = TRUE - UnregisterSignal(old_owner, list( - SIGNAL_REMOVETRAIT(TRAIT_NOLIMBDISABLE), - SIGNAL_ADDTRAIT(TRAIT_NOLIMBDISABLE), - SIGNAL_REMOVETRAIT(TRAIT_NOBLOOD), - SIGNAL_ADDTRAIT(TRAIT_NOBLOOD), - )) - UnregisterSignal(old_owner, COMSIG_ATOM_RESTYLE) + + SEND_SIGNAL(src, COMSIG_BODYPART_CHANGED_OWNER, new_owner, owner) + if(owner) - if(held_index) - owner.on_added_hand(src, held_index) - if(owner.hud_used) - var/atom/movable/screen/inventory/hand/hand = owner.hud_used.hand_slots["[held_index]"] - if(hand) - hand.update_appearance() - owner.update_worn_gloves() - if(speed_modifier) - owner.update_bodypart_speed_modifier() - if(length(bodypart_traits)) - owner.add_traits(bodypart_traits, bodypart_trait_source) - if(initial(can_be_disabled)) - if(HAS_TRAIT(owner, TRAIT_NOLIMBDISABLE)) - set_can_be_disabled(FALSE) - needs_update_disabled = FALSE - RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_NOLIMBDISABLE), PROC_REF(on_owner_nolimbdisable_trait_loss)) - RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_NOLIMBDISABLE), PROC_REF(on_owner_nolimbdisable_trait_gain)) - // Bleeding stuff - RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_NOBLOOD), PROC_REF(on_owner_nobleed_loss)) - RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_NOBLOOD), PROC_REF(on_owner_nobleed_gain)) - - if(needs_update_disabled) - update_disabled() - - RegisterSignal(owner, COMSIG_ATOM_RESTYLE, PROC_REF(on_attempt_feature_restyle_mob)) + . = owner //return value is old owner + clear_ownership(owner) + if(new_owner) + apply_ownership(new_owner) refresh_bleed_rate() - return old_owner + return . + +/// Run all necessary procs to remove a limbs ownership and remove the appropriate signals and traits +/obj/item/bodypart/proc/clear_ownership(mob/living/carbon/old_owner) + SHOULD_CALL_PARENT(TRUE) + + owner = null + + if(speed_modifier) + old_owner.update_bodypart_speed_modifier() + if(length(bodypart_traits)) + old_owner.remove_traits(bodypart_traits, bodypart_trait_source) + + UnregisterSignal(old_owner, list( + SIGNAL_REMOVETRAIT(TRAIT_NOLIMBDISABLE), + SIGNAL_ADDTRAIT(TRAIT_NOLIMBDISABLE), + SIGNAL_REMOVETRAIT(TRAIT_NOBLOOD), + SIGNAL_ADDTRAIT(TRAIT_NOBLOOD), + )) + + UnregisterSignal(old_owner, COMSIG_ATOM_RESTYLE) + +/// Apply ownership of a limb to someone, giving the appropriate traits, updates and signals +/obj/item/bodypart/proc/apply_ownership(mob/living/carbon/new_owner) + SHOULD_CALL_PARENT(TRUE) + + owner = new_owner + + if(speed_modifier) + owner.update_bodypart_speed_modifier() + if(length(bodypart_traits)) + owner.add_traits(bodypart_traits, bodypart_trait_source) + + if(initial(can_be_disabled)) + if(HAS_TRAIT(owner, TRAIT_NOLIMBDISABLE)) + set_can_be_disabled(FALSE) + + // Listen to disable traits being added + RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_NOLIMBDISABLE), PROC_REF(on_owner_nolimbdisable_trait_loss)) + RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_NOLIMBDISABLE), PROC_REF(on_owner_nolimbdisable_trait_gain)) + + // Listen to no blood traits being added + RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_NOBLOOD), PROC_REF(on_owner_nobleed_loss)) + RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_NOBLOOD), PROC_REF(on_owner_nobleed_gain)) + + if(can_be_disabled) + update_disabled() + + RegisterSignal(owner, COMSIG_ATOM_RESTYLE, PROC_REF(on_attempt_feature_restyle_mob)) + + forceMove(owner) + RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(on_forced_removal)) //this must be set after we moved, or we insta gib + +/// Called on addition of a bodypart +/obj/item/bodypart/proc/on_adding(mob/living/carbon/new_owner) + SHOULD_CALL_PARENT(TRUE) + + item_flags |= ABSTRACT + ADD_TRAIT(src, TRAIT_NODROP, ORGAN_INSIDE_BODY_TRAIT) + +/// Called on removal of a bodypart. +/obj/item/bodypart/proc/on_removal(mob/living/carbon/old_owner) + SHOULD_CALL_PARENT(TRUE) + + UnregisterSignal(src, COMSIG_MOVABLE_MOVED) + + item_flags &= ~ABSTRACT + REMOVE_TRAIT(src, TRAIT_NODROP, ORGAN_INSIDE_BODY_TRAIT) -/obj/item/bodypart/proc/on_removal() if(!length(bodypart_traits)) return diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm index db92a901916..2856b9c23cc 100644 --- a/code/modules/surgery/bodyparts/dismemberment.dm +++ b/code/modules/surgery/bodyparts/dismemberment.dm @@ -67,7 +67,7 @@ if(wounding_type != WOUND_BURN && isturf(chest_owner.loc) && can_bleed()) chest_owner.add_splatter_floor(chest_owner.loc) playsound(get_turf(chest_owner), 'sound/misc/splort.ogg', 80, TRUE) - for(var/obj/item/organ/organ as anything in chest_owner.organs) + for(var/obj/item/organ/organ in contents) var/org_zone = check_zone(organ.zone) if(org_zone != BODY_ZONE_CHEST) continue @@ -75,21 +75,13 @@ organ.forceMove(chest_owner.loc) . += organ - for(var/obj/item/organ/external/ext_organ as anything in src.external_organs) - if(!(ext_organ.organ_flags & ORGAN_UNREMOVABLE)) - ext_organ.Remove(chest_owner) - ext_organ.forceMove(chest_owner.loc) - . += ext_organ - if(cavity_item) cavity_item.forceMove(chest_owner.loc) . += cavity_item cavity_item = null - return . - ///limb removal. The "special" argument is used for swapping a limb with a new one without the effects of losing a limb kicking in. -/obj/item/bodypart/proc/drop_limb(special, dismembered) +/obj/item/bodypart/proc/drop_limb(special, dismembered, move_to_floor = TRUE) if(!owner) return var/atom/drop_loc = owner.drop_location() @@ -98,16 +90,13 @@ SEND_SIGNAL(src, COMSIG_BODYPART_REMOVED, owner, special, dismembered) update_limb(dropping_limb = TRUE) bodypart_flags &= ~BODYPART_IMPLANTED //limb is out and about, it can't really be considered an implant - owner.remove_bodypart(src) + owner.remove_bodypart(src, special) for(var/datum/scar/scar as anything in scars) scar.victim = null LAZYREMOVE(owner.all_scars, scar) - for(var/obj/item/organ/external/ext_organ as anything in external_organs) - ext_organ.transfer_to_limb(src, null) //Null is the second arg because the bodypart is being removed from it's owner. - - var/mob/living/carbon/phantom_owner = set_owner(null) // so we can still refer to the guy who lost their limb after said limb forgets 'em + var/mob/living/carbon/phantom_owner = update_owner(null) // so we can still refer to the guy who lost their limb after said limb forgets 'em for(var/datum/wound/wound as anything in wounds) wound.remove_wound(TRUE) @@ -131,27 +120,22 @@ to_chat(phantom_owner, span_warning("You feel your [mutation] deactivating from the loss of your [body_zone]!")) phantom_owner.dna.force_lose(mutation) - for(var/obj/item/organ/organ as anything in phantom_owner.organs) //internal organs inside the dismembered limb are dropped. - var/org_zone = check_zone(organ.zone) - if(org_zone != body_zone) - continue - organ.transfer_to_limb(src, phantom_owner) - update_icon_dropped() phantom_owner.update_health_hud() //update the healthdoll phantom_owner.update_body() phantom_owner.update_body_parts() - if(!drop_loc) // drop_loc = null happens when a "dummy human" used for rendering icons on prefs screen gets its limbs replaced. - qdel(src) - return - if(bodypart_flags & BODYPART_PSEUDOPART) drop_organs(phantom_owner) //Psuedoparts shouldn't have organs, but just in case qdel(src) return - forceMove(drop_loc) + if(move_to_floor) + if(!drop_loc) // drop_loc = null happens when a "dummy human" used for rendering icons on prefs screen gets its limbs replaced. + qdel(src) + return + forceMove(drop_loc) + SEND_SIGNAL(phantom_owner, COMSIG_CARBON_POST_REMOVE_LIMB, src, special, dismembered) /** @@ -201,48 +185,45 @@ var/datum/wound/loss/dismembering = new return dismembering.apply_dismember(src, wounding_type) -///Transfers the organ to the limb, and to the limb's owner, if it has one. This is done on drop_limb(). -/obj/item/organ/proc/transfer_to_limb(obj/item/bodypart/bodypart, mob/living/carbon/bodypart_owner) - Remove(bodypart_owner) - add_to_limb(bodypart) - -///Adds the organ to a bodypart, used in transfer_to_limb() -/obj/item/organ/proc/add_to_limb(obj/item/bodypart/bodypart) - forceMove(bodypart) - -///Removes the organ from the limb, placing it into nullspace. -/obj/item/organ/proc/remove_from_limb() - moveToNullspace() - -/obj/item/organ/internal/brain/transfer_to_limb(obj/item/bodypart/head/head, mob/living/carbon/human/head_owner) - Remove(head_owner) //Changeling brain concerns are now handled in Remove - forceMove(head) - head.brain = src - if(brainmob) - head.brainmob = brainmob - brainmob = null - head.brainmob.forceMove(head) - head.brainmob.set_stat(DEAD) - -/obj/item/organ/internal/eyes/transfer_to_limb(obj/item/bodypart/head/head, mob/living/carbon/human/head_owner) +/obj/item/organ/internal/eyes/on_bodypart_insert(obj/item/bodypart/head/head) head.eyes = src ..() -/obj/item/organ/internal/ears/transfer_to_limb(obj/item/bodypart/head/head, mob/living/carbon/human/head_owner) +/obj/item/organ/internal/ears/on_bodypart_insert(obj/item/bodypart/head/head) head.ears = src ..() -/obj/item/organ/internal/tongue/transfer_to_limb(obj/item/bodypart/head/head, mob/living/carbon/human/head_owner) +/obj/item/organ/internal/tongue/on_bodypart_insert(obj/item/bodypart/head/head) head.tongue = src ..() -/obj/item/bodypart/chest/drop_limb(special) +/obj/item/organ/internal/brain/on_bodypart_insert(obj/item/bodypart/head/head) + head.brain = src + ..() + +/obj/item/organ/internal/eyes/on_bodypart_remove(obj/item/bodypart/head/head) + head.eyes = null + ..() + +/obj/item/organ/internal/ears/on_bodypart_remove(obj/item/bodypart/head/head) + head.ears = null + ..() + +/obj/item/organ/internal/tongue/on_bodypart_remove(obj/item/bodypart/head/head) + head.tongue = null + ..() + +/obj/item/organ/internal/brain/on_bodypart_remove(obj/item/bodypart/head/head) + head.brain = null + ..() + +/obj/item/bodypart/chest/drop_limb(special, dismembered, move_to_floor = TRUE) if(special) return ..() //if this is not a special drop, this is a mistake return FALSE -/obj/item/bodypart/arm/drop_limb(special) +/obj/item/bodypart/arm/drop_limb(special, dismembered, move_to_floor = TRUE) var/mob/living/carbon/arm_owner = owner if(special || !arm_owner) @@ -265,7 +246,7 @@ arm_owner.update_worn_gloves() //to remove the bloody hands overlay return ..() -/obj/item/bodypart/leg/drop_limb(special) +/obj/item/bodypart/leg/drop_limb(special, dismembered, move_to_floor = TRUE) if(owner && !special) if(owner.legcuffed) owner.legcuffed.forceMove(owner.drop_location()) //At this point bodypart is still in nullspace @@ -276,7 +257,7 @@ owner.dropItemToGround(owner.shoes, TRUE) return ..() -/obj/item/bodypart/head/drop_limb(special) +/obj/item/bodypart/head/drop_limb(special, dismembered, move_to_floor = TRUE) if(!special) //Drop all worn head items for(var/obj/item/head_item as anything in list(owner.glasses, owner.ears, owner.wear_mask, owner.head)) @@ -332,8 +313,6 @@ SEND_SIGNAL(new_limb_owner, COMSIG_CARBON_ATTACH_LIMB, src, special) SEND_SIGNAL(src, COMSIG_BODYPART_ATTACHED, new_limb_owner, special) - moveToNullspace() - set_owner(new_limb_owner) new_limb_owner.add_bodypart(src) LAZYREMOVE(new_limb_owner.body_zone_dismembered_by, body_zone) @@ -346,8 +325,10 @@ qdel(attach_surgery) break - for(var/obj/item/organ/limb_organ in contents) - limb_organ.Insert(new_limb_owner, TRUE) + for(var/obj/item/organ/organ as anything in new_limb_owner.organs) + if(deprecise_zone(organ.zone) != body_zone) + continue + organ.bodypart_insert(src) for(var/datum/wound/wound as anything in wounds) // we have to remove the wound from the limb wound list first, so that we can reapply it fresh with the new person @@ -387,15 +368,6 @@ if(!.) return - if(brain) - brain = null - if(tongue) - tongue = null - if(ears) - ears = null - if(eyes) - eyes = null - if(old_real_name) new_head_owner.real_name = old_real_name real_name = new_head_owner.real_name diff --git a/code/modules/surgery/bodyparts/head.dm b/code/modules/surgery/bodyparts/head.dm index 04c74b91473..e43d6ca05c0 100644 --- a/code/modules/surgery/bodyparts/head.dm +++ b/code/modules/surgery/bodyparts/head.dm @@ -26,7 +26,6 @@ unarmed_effectiveness = 0 bodypart_trait_source = HEAD_TRAIT - var/mob/living/brain/brainmob //The current occupant. var/obj/item/organ/internal/brain/brain //The brain organ var/obj/item/organ/internal/eyes/eyes var/obj/item/organ/internal/ears/ears @@ -93,12 +92,6 @@ var/datum/worn_feature_offset/worn_face_offset /obj/item/bodypart/head/Destroy() - QDEL_NULL(brainmob) //order is sensitive, see warning in Exited() below - QDEL_NULL(brain) - QDEL_NULL(eyes) - QDEL_NULL(ears) - QDEL_NULL(tongue) - QDEL_NULL(worn_ears_offset) QDEL_NULL(worn_glasses_offset) QDEL_NULL(worn_mask_offset) @@ -110,11 +103,6 @@ if(gone == brain) brain = null update_icon_dropped() - if(!QDELETED(brainmob)) //this shouldn't happen without badminnery. - message_admins("Brainmob: ([ADMIN_LOOKUPFLW(brainmob)]) was left stranded in [src] at [ADMIN_VERBOSEJMP(src)] without a brain!") - brainmob.log_message(", brainmob, was left stranded in [src] without a brain", LOG_GAME) - if(gone == brainmob) - brainmob = null if(gone == eyes) eyes = null update_icon_dropped() @@ -129,12 +117,12 @@ if(show_organs_on_examine && IS_ORGANIC_LIMB(src)) if(!brain) . += span_info("The brain has been removed from [src].") - else if(brain.suicided || (brainmob && HAS_TRAIT(brainmob, TRAIT_SUICIDED))) + else if(brain.suicided || (brain.brainmob && HAS_TRAIT(brain.brainmob, TRAIT_SUICIDED))) . += span_info("There's a miserable expression on [real_name]'s face; they must have really hated life. There's no hope of recovery.") - else if(brainmob?.health <= HEALTH_THRESHOLD_DEAD) - . += span_info("It's leaking some kind of... clear fluid? The brain inside must be in pretty bad shape.") - else if(brainmob) - if(brainmob.key || brainmob.get_ghost(FALSE, TRUE)) + else if(brain.brainmob) + if(brain.brainmob?.health <= HEALTH_THRESHOLD_DEAD) + . += span_info("It's leaking some kind of... clear fluid? The brain inside must be in pretty bad shape.") + if(brain.brainmob.key || brain.brainmob.get_ghost(FALSE, TRUE)) . += span_info("Its muscles are twitching slightly... It seems to have some life still in it.") else . += span_info("It's completely lifeless. Perhaps there'll be a chance for them later.") @@ -158,33 +146,12 @@ return ..() /obj/item/bodypart/head/drop_organs(mob/user, violent_removal) - var/atom/drop_loc = drop_location() - for(var/obj/item/head_item in src) - if(head_item == brain) - if(user) - user.visible_message(span_warning("[user] saws [src] open and pulls out a brain!"), span_notice("You saw [src] open and pull out a brain.")) - if(brainmob) - brainmob.container = null - brain.brainmob = brainmob - brainmob = null - if(violent_removal && prob(rand(80, 100))) //ghetto surgery can damage the brain. - to_chat(user, span_warning("[brain] was damaged in the process!")) - brain.set_organ_damage(brain.maxHealth) - brain.forceMove(drop_loc) - brain = null - update_icon_dropped() - else - if(istype(head_item, /obj/item/reagent_containers/pill)) - for(var/datum/action/item_action/hands_free/activate_pill/pill_action in head_item.actions) - qdel(pill_action) - else if(isorgan(head_item)) - var/obj/item/organ/organ = head_item - if(organ.organ_flags & ORGAN_UNREMOVABLE) - continue - head_item.forceMove(drop_loc) - eyes = null - ears = null - tongue = null + if(user) + user.visible_message(span_warning("[user] saws [src] open and pulls out a brain!"), span_notice("You saw [src] open and pull out a brain.")) + if(brain && violent_removal && prob(90)) //ghetto surgery can damage the brain. + to_chat(user, span_warning("[brain] was damaged in the process!")) + brain.set_organ_damage(brain.maxHealth) + update_limb() return ..() diff --git a/code/modules/surgery/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm index c93fdf10b47..52671b5fbc1 100644 --- a/code/modules/surgery/bodyparts/helpers.dm +++ b/code/modules/surgery/bodyparts/helpers.dm @@ -15,6 +15,7 @@ /mob/living/carbon/proc/del_and_replace_bodypart(obj/item/bodypart/new_limb, special) var/obj/item/bodypart/old_limb = get_bodypart(new_limb.body_zone) if(old_limb) + old_limb.drop_limb(special = TRUE) qdel(old_limb) new_limb.try_attach_limb(src, special = special) @@ -172,7 +173,7 @@ /mob/living/carbon/proc/synchronize_bodytypes() var/all_limb_flags = NONE for(var/obj/item/bodypart/limb as anything in bodyparts) - for(var/obj/item/organ/external/ext_organ as anything in limb.external_organs) + for(var/obj/item/organ/external/ext_organ in limb) all_limb_flags |= ext_organ.external_bodytypes all_limb_flags |= limb.bodytype diff --git a/code/modules/surgery/bodyparts/parts.dm b/code/modules/surgery/bodyparts/parts.dm index 25f1ab985b6..5f40b14c02d 100644 --- a/code/modules/surgery/bodyparts/parts.dm +++ b/code/modules/surgery/bodyparts/parts.dm @@ -35,8 +35,18 @@ /// Which functional (i.e. flightpotion) wing types (if any) does this bodypart support? If count is >1 a radial menu is used to choose between all icons in list var/list/wing_types = list(/obj/item/organ/external/wings/functional/angel) +/obj/item/bodypart/chest/forced_removal(dismembered, special, move_to_floor) + var/mob/living/carbon/old_owner = owner + ..(special = TRUE) //special because we're self destructing + + //If someones chest is teleported away, they die pretty hard + if(!old_owner) + return + message_admins("[ADMIN_LOOKUPFLW(old_owner)] was gibbed after their chest teleport to [ADMIN_VERBOSEJMP(loc)].") + old_owner.gib(DROP_ALL_REMAINS) + /obj/item/bodypart/chest/can_dismember(obj/item/item) - if(owner.stat < HARD_CRIT || !get_organs()) + if(owner.stat < HARD_CRIT || !contents.len) return FALSE return ..() @@ -127,6 +137,40 @@ QDEL_NULL(held_hand_offset) return ..() +/// We need to clear out hand hud items and appearance, so do that here +/obj/item/bodypart/arm/clear_ownership(mob/living/carbon/old_owner) + ..() + + old_owner.update_worn_gloves() + + if(!held_index) + return + + old_owner.on_lost_hand(src) + + if(!old_owner.hud_used) + return + + var/atom/movable/screen/inventory/hand/hand = old_owner.hud_used.hand_slots["[held_index]"] + hand?.update_appearance() + +/// We need to add hand hud items and appearance, so do that here +/obj/item/bodypart/arm/apply_ownership(mob/living/carbon/new_owner) + ..() + + new_owner.update_worn_gloves() + + if(!held_index) + return + + new_owner.on_added_hand(src, held_index) + + if(!new_owner.hud_used) + return + + var/atom/movable/screen/inventory/hand/hand = new_owner.hud_used.hand_slots["[held_index]"] + hand.update_appearance() + /obj/item/bodypart/arm/left name = "left arm" desc = "Did you know that the word 'sinister' stems originally from the \ @@ -143,27 +187,22 @@ px_y = 0 bodypart_trait_source = LEFT_ARM_TRAIT +/obj/item/bodypart/arm/left/apply_ownership(mob/living/carbon/new_owner) + if(HAS_TRAIT(new_owner, TRAIT_PARALYSIS_L_ARM)) + ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_ARM) + RegisterSignal(new_owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_ARM), PROC_REF(on_owner_paralysis_loss)) + else + REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_ARM) + RegisterSignal(new_owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_ARM), PROC_REF(on_owner_paralysis_gain)) + ..() -/obj/item/bodypart/arm/left/set_owner(new_owner) - . = ..() - if(. == FALSE) - return - if(owner) - if(HAS_TRAIT(owner, TRAIT_PARALYSIS_L_ARM)) - ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_ARM) - RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_ARM), PROC_REF(on_owner_paralysis_loss)) - else - REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_ARM) - RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_ARM), PROC_REF(on_owner_paralysis_gain)) - if(.) - var/mob/living/carbon/old_owner = . - if(HAS_TRAIT(old_owner, TRAIT_PARALYSIS_L_ARM)) - UnregisterSignal(old_owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_ARM)) - if(!owner || !HAS_TRAIT(owner, TRAIT_PARALYSIS_L_ARM)) - REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_ARM) - else - UnregisterSignal(old_owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_ARM)) - +/obj/item/bodypart/arm/left/clear_ownership(mob/living/carbon/old_owner) + if(HAS_TRAIT(old_owner, TRAIT_PARALYSIS_L_ARM)) + UnregisterSignal(old_owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_ARM)) + REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_ARM) + else + UnregisterSignal(old_owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_ARM)) + ..() ///Proc to react to the owner gaining the TRAIT_PARALYSIS_L_ARM trait. /obj/item/bodypart/arm/left/proc/on_owner_paralysis_gain(mob/living/carbon/source) @@ -172,7 +211,6 @@ UnregisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_ARM)) RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_ARM), PROC_REF(on_owner_paralysis_loss)) - ///Proc to react to the owner losing the TRAIT_PARALYSIS_L_ARM trait. /obj/item/bodypart/arm/left/proc/on_owner_paralysis_loss(mob/living/carbon/source) SIGNAL_HANDLER @@ -180,7 +218,6 @@ UnregisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_ARM)) RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_ARM), PROC_REF(on_owner_paralysis_gain)) - /obj/item/bodypart/arm/left/set_disabled(new_disabled) . = ..() if(isnull(.) || !owner) @@ -200,7 +237,6 @@ var/atom/movable/screen/inventory/hand/hand_screen_object = owner.hud_used.hand_slots["[held_index]"] hand_screen_object?.update_appearance() - /obj/item/bodypart/arm/left/monkey icon = 'icons/mob/human/species/monkey/bodyparts.dmi' icon_static = 'icons/mob/human/species/monkey/bodyparts.dmi' @@ -233,7 +269,6 @@ should_draw_greyscale = FALSE appendage_noun = "scythe-like hand" - /obj/item/bodypart/arm/right name = "right arm" desc = "Over 87% of humans are right handed. That figure is much lower \ @@ -249,26 +284,22 @@ px_y = 0 bodypart_trait_source = RIGHT_ARM_TRAIT -/obj/item/bodypart/arm/right/set_owner(new_owner) - . = ..() - if(. == FALSE) - return - if(owner) - if(HAS_TRAIT(owner, TRAIT_PARALYSIS_R_ARM)) - ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_ARM) - RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_ARM), PROC_REF(on_owner_paralysis_loss)) - else - REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_ARM) - RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_ARM), PROC_REF(on_owner_paralysis_gain)) - if(.) - var/mob/living/carbon/old_owner = . - if(HAS_TRAIT(old_owner, TRAIT_PARALYSIS_R_ARM)) - UnregisterSignal(old_owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_ARM)) - if(!owner || !HAS_TRAIT(owner, TRAIT_PARALYSIS_R_ARM)) - REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_ARM) - else - UnregisterSignal(old_owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_ARM)) +/obj/item/bodypart/arm/right/apply_ownership(mob/living/carbon/new_owner) + if(HAS_TRAIT(new_owner, TRAIT_PARALYSIS_R_ARM)) + ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_ARM) + RegisterSignal(new_owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_ARM), PROC_REF(on_owner_paralysis_loss)) + else + REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_ARM) + RegisterSignal(new_owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_ARM), PROC_REF(on_owner_paralysis_gain)) + ..() +/obj/item/bodypart/arm/right/clear_ownership(mob/living/carbon/old_owner) + if(HAS_TRAIT(old_owner, TRAIT_PARALYSIS_R_ARM)) + UnregisterSignal(old_owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_ARM)) + REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_ARM) + else + UnregisterSignal(old_owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_ARM)) + ..() ///Proc to react to the owner gaining the TRAIT_PARALYSIS_R_ARM trait. /obj/item/bodypart/arm/right/proc/on_owner_paralysis_gain(mob/living/carbon/source) @@ -277,7 +308,6 @@ UnregisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_ARM)) RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_ARM), PROC_REF(on_owner_paralysis_loss)) - ///Proc to react to the owner losing the TRAIT_PARALYSIS_R_ARM trait. /obj/item/bodypart/arm/right/proc/on_owner_paralysis_loss(mob/living/carbon/source) SIGNAL_HANDLER @@ -285,7 +315,6 @@ UnregisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_ARM)) RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_ARM), PROC_REF(on_owner_paralysis_gain)) - /obj/item/bodypart/arm/right/set_disabled(new_disabled) . = ..() if(isnull(.) || !owner) @@ -305,7 +334,6 @@ var/atom/movable/screen/inventory/hand/hand_screen_object = owner.hud_used.hand_slots["[held_index]"] hand_screen_object?.update_appearance() - /obj/item/bodypart/arm/right/monkey icon = 'icons/mob/human/species/monkey/bodyparts.dmi' icon_static = 'icons/mob/human/species/monkey/bodyparts.dmi' @@ -375,35 +403,30 @@ can_be_disabled = TRUE bodypart_trait_source = LEFT_LEG_TRAIT -/obj/item/bodypart/leg/left/set_owner(new_owner) - . = ..() - if(. == FALSE) - return - if(owner) - if(HAS_TRAIT(owner, TRAIT_PARALYSIS_L_LEG)) - ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_LEG) - RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_LEG), PROC_REF(on_owner_paralysis_loss)) - else - REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_LEG) - RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_LEG), PROC_REF(on_owner_paralysis_gain)) - if(.) - var/mob/living/carbon/old_owner = . - if(HAS_TRAIT(old_owner, TRAIT_PARALYSIS_L_LEG)) - UnregisterSignal(old_owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_LEG)) - if(!owner || !HAS_TRAIT(owner, TRAIT_PARALYSIS_L_LEG)) - REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_LEG) - else - UnregisterSignal(old_owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_LEG)) +/obj/item/bodypart/leg/left/apply_ownership(mob/living/carbon/new_owner) + if(HAS_TRAIT(new_owner, TRAIT_PARALYSIS_L_LEG)) + ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_LEG) + RegisterSignal(new_owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_LEG), PROC_REF(on_owner_paralysis_loss)) + else + REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_LEG) + RegisterSignal(new_owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_LEG), PROC_REF(on_owner_paralysis_gain)) + ..() +/obj/item/bodypart/leg/left/clear_ownership(mob/living/carbon/old_owner) + if(HAS_TRAIT(old_owner, TRAIT_PARALYSIS_L_LEG)) + UnregisterSignal(old_owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_LEG)) + REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_LEG) + else + UnregisterSignal(old_owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_LEG)) + ..() -///Proc to react to the owner gaining the TRAIT_PARALYSIS_L_LEG trait. +///Proc to react to the owner gaining the TRAIT_PARALYSIS_L_ARM trait. /obj/item/bodypart/leg/left/proc/on_owner_paralysis_gain(mob/living/carbon/source) SIGNAL_HANDLER ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_LEG) UnregisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_LEG)) RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_LEG), PROC_REF(on_owner_paralysis_loss)) - ///Proc to react to the owner losing the TRAIT_PARALYSIS_L_LEG trait. /obj/item/bodypart/leg/left/proc/on_owner_paralysis_loss(mob/living/carbon/source) SIGNAL_HANDLER @@ -411,7 +434,6 @@ UnregisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_LEG)) RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_LEG), PROC_REF(on_owner_paralysis_gain)) - /obj/item/bodypart/leg/left/set_disabled(new_disabled) . = ..() if(isnull(.) || !owner) @@ -469,26 +491,22 @@ px_y = 12 bodypart_trait_source = RIGHT_LEG_TRAIT -/obj/item/bodypart/leg/right/set_owner(new_owner) - . = ..() - if(. == FALSE) - return - if(owner) - if(HAS_TRAIT(owner, TRAIT_PARALYSIS_R_LEG)) - ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_LEG) - RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_LEG), PROC_REF(on_owner_paralysis_loss)) - else - REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_LEG) - RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_LEG), PROC_REF(on_owner_paralysis_gain)) - if(.) - var/mob/living/carbon/old_owner = . - if(HAS_TRAIT(old_owner, TRAIT_PARALYSIS_R_LEG)) - UnregisterSignal(old_owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_LEG)) - if(!owner || !HAS_TRAIT(owner, TRAIT_PARALYSIS_R_LEG)) - REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_LEG) - else - UnregisterSignal(old_owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_LEG)) +/obj/item/bodypart/leg/right/apply_ownership(mob/living/carbon/new_owner) + if(HAS_TRAIT(new_owner, TRAIT_PARALYSIS_R_LEG)) + ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_LEG) + RegisterSignal(new_owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_LEG), PROC_REF(on_owner_paralysis_loss)) + else + REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_LEG) + RegisterSignal(new_owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_LEG), PROC_REF(on_owner_paralysis_gain)) + ..() +/obj/item/bodypart/leg/right/clear_ownership(mob/living/carbon/old_owner) + if(HAS_TRAIT(old_owner, TRAIT_PARALYSIS_R_LEG)) + UnregisterSignal(old_owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_LEG)) + REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_LEG) + else + UnregisterSignal(old_owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_LEG)) + ..() ///Proc to react to the owner gaining the TRAIT_PARALYSIS_R_LEG trait. /obj/item/bodypart/leg/right/proc/on_owner_paralysis_gain(mob/living/carbon/source) @@ -497,7 +515,6 @@ UnregisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_LEG)) RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_LEG), PROC_REF(on_owner_paralysis_loss)) - ///Proc to react to the owner losing the TRAIT_PARALYSIS_R_LEG trait. /obj/item/bodypart/leg/right/proc/on_owner_paralysis_loss(mob/living/carbon/source) SIGNAL_HANDLER diff --git a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm index 7cf82552d8f..81a7636c100 100644 --- a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm @@ -518,17 +518,16 @@ ) return ..() -/obj/item/bodypart/arm/left/golem/set_owner(new_owner) +/obj/item/bodypart/arm/left/golem/clear_ownership(mob/living/carbon/old_owner) . = ..() - if (. == FALSE) - return - if (owner) - owner.AddComponentFrom(REF(src), /datum/component/shovel_hands) - if (isnull(.)) - return - var/mob/living/carbon/old_owner = . + old_owner.RemoveComponentSource(REF(src), /datum/component/shovel_hands) +/obj/item/bodypart/arm/left/golem/apply_ownership(mob/living/carbon/new_owner) + . = ..() + + new_owner.AddComponentFrom(REF(src), /datum/component/shovel_hands) + /obj/item/bodypart/arm/right/golem icon = 'icons/mob/human/species/golems.dmi' icon_static = 'icons/mob/human/species/golems.dmi' @@ -552,17 +551,16 @@ ) return ..() -/obj/item/bodypart/arm/right/golem/set_owner(new_owner) +/obj/item/bodypart/arm/right/golem/clear_ownership(mob/living/carbon/old_owner) . = ..() - if (. == FALSE) - return - if (owner) - owner.AddComponentFrom(REF(src), /datum/component/shovel_hands) - if (isnull(.)) - return - var/mob/living/carbon/old_owner = . + old_owner.RemoveComponentSource(REF(src), /datum/component/shovel_hands) +/obj/item/bodypart/arm/right/golem/apply_ownership(mob/living/carbon/new_owner) + . = ..() + + new_owner.AddComponentFrom(REF(src), /datum/component/shovel_hands) + /obj/item/bodypart/leg/left/golem icon = 'icons/mob/human/species/golems.dmi' icon_static = 'icons/mob/human/species/golems.dmi' diff --git a/code/modules/surgery/organs/_organ.dm b/code/modules/surgery/organs/_organ.dm index a3feba76fec..d7f08a7be35 100644 --- a/code/modules/surgery/organs/_organ.dm +++ b/code/modules/surgery/organs/_organ.dm @@ -6,6 +6,8 @@ throwforce = 0 /// The mob that owns this organ. var/mob/living/carbon/owner = null + /// Reference to the limb we're inside of + var/obj/item/bodypart/bodypart_owner /// The cached info about the blood this organ belongs to var/list/blood_dna_info = list("Synthetic DNA" = "O+") // not every organ spawns inside a person /// The body zone this organ is supposed to inhabit. @@ -77,134 +79,16 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) volume = reagent_vol,\ after_eat = CALLBACK(src, PROC_REF(OnEatFrom))) - if(!IS_ROBOTIC_ORGAN(src)) - add_blood_DNA(blood_dna_info) - -/* - * Insert the organ into the select mob. - * - * receiver - the mob who will get our organ - * special - "quick swapping" an organ out - when TRUE, the mob will be unaffected by not having that organ for the moment - * drop_if_replaced - if there's an organ in the slot already, whether we drop it afterwards - */ -/obj/item/organ/proc/Insert(mob/living/carbon/receiver, special = FALSE, drop_if_replaced = TRUE) - SHOULD_CALL_PARENT(TRUE) - - if(!iscarbon(receiver) || owner == receiver) - return FALSE - - var/obj/item/organ/replaced = receiver.get_organ_slot(slot) - if(replaced) - replaced.Remove(receiver, special = TRUE) - if(drop_if_replaced) - replaced.forceMove(get_turf(receiver)) - else - qdel(replaced) - - receiver.organs |= src - receiver.organs_slot[slot] = src - owner = receiver - - if(!IS_ROBOTIC_ORGAN(src) && (organ_flags & ORGAN_VIRGIN)) - blood_dna_info = receiver.get_blood_dna_list() - // need to remove the synethic blood DNA that is initialized - // wash also adds the blood dna again - wash(CLEAN_TYPE_BLOOD) - organ_flags &= ~ORGAN_VIRGIN - - - // Apply unique side-effects. Return value does not matter. - on_insert(receiver, special) - - return TRUE - -/// Called after the organ is inserted into a mob. -/// Adds Traits, Actions, and Status Effects on the mob in which the organ is impanted. -/// Override this proc to create unique side-effects for inserting your organ. Must be called by overrides. -/obj/item/organ/proc/on_insert(mob/living/carbon/organ_owner, special) - SHOULD_CALL_PARENT(TRUE) - - moveToNullspace() - - for(var/trait in organ_traits) - ADD_TRAIT(organ_owner, trait, REF(src)) - - for(var/datum/action/action as anything in actions) - action.Grant(organ_owner) - - for(var/datum/status_effect/effect as anything in organ_effects) - organ_owner.apply_status_effect(effect, type) - - RegisterSignal(owner, COMSIG_ATOM_EXAMINE, PROC_REF(on_owner_examine)) - SEND_SIGNAL(src, COMSIG_ORGAN_IMPLANTED, organ_owner) - SEND_SIGNAL(organ_owner, COMSIG_CARBON_GAIN_ORGAN, src, special) - -/* - * Remove the organ from the select mob. - * - * * organ_owner - the mob who owns our organ, that we're removing the organ from. - * * special - "quick swapping" an organ out - when TRUE, the mob will be unaffected by not having that organ for the moment - */ -/obj/item/organ/proc/Remove(mob/living/carbon/organ_owner, special = FALSE) - SHOULD_CALL_PARENT(TRUE) - - organ_owner.organs -= src - if(organ_owner.organs_slot[slot] == src) - organ_owner.organs_slot.Remove(slot) - - owner = null - - // Apply or reset unique side-effects. Return value does not matter. - on_remove(organ_owner, special) - - return TRUE - -/// Called after the organ is removed from a mob. -/// Removes Traits, Actions, and Status Effects on the mob in which the organ was impanted. -/// Override this proc to create unique side-effects for removing your organ. Must be called by overrides. -/obj/item/organ/proc/on_remove(mob/living/carbon/organ_owner, special) - SHOULD_CALL_PARENT(TRUE) - - if(!iscarbon(organ_owner)) - stack_trace("Organ removal should not be happening on non carbon mobs: [organ_owner]") - - for(var/trait in organ_traits) - REMOVE_TRAIT(organ_owner, trait, REF(src)) - - for(var/datum/action/action as anything in actions) - action.Remove(organ_owner) - - for(var/datum/status_effect/effect as anything in organ_effects) - organ_owner.remove_status_effect(effect, type) - - UnregisterSignal(organ_owner, COMSIG_ATOM_EXAMINE) - SEND_SIGNAL(src, COMSIG_ORGAN_REMOVED, organ_owner) - SEND_SIGNAL(organ_owner, COMSIG_CARBON_LOSE_ORGAN, src, special) - - // We don't need to readd things to the organ if it's getting deleted - if(QDELING(src)) - return - - if(!IS_ROBOTIC_ORGAN(src) && !(item_flags & NO_BLOOD_ON_ITEM)) - AddElement(/datum/element/decal/blood) - - var/list/diseases = organ_owner.get_static_viruses() - if(!LAZYLEN(diseases)) - return - - var/list/datum/disease/diseases_to_add = list() - for(var/datum/disease/disease as anything in diseases) - // robotic organs are immune to disease unless 'inorganic biology' symptom is present - if(IS_ROBOTIC_ORGAN(src) && !(disease.infectable_biotypes & MOB_ROBOTIC)) - continue - - // admin or special viruses that should not be reproduced - if(disease.spread_flags & (DISEASE_SPREAD_SPECIAL | DISEASE_SPREAD_NON_CONTAGIOUS)) - continue - - diseases_to_add += disease - if(LAZYLEN(diseases_to_add)) - AddComponent(/datum/component/infective, diseases_to_add) +/obj/item/organ/Destroy() + if(bodypart_owner && !owner && !QDELETED(bodypart_owner)) + bodypart_remove(bodypart_owner) + else if(owner) + // The special flag is important, because otherwise mobs can die + // while undergoing transformation into different mobs. + Remove(owner, special=TRUE) + else + STOP_PROCESSING(SSobj, src) + return ..() /// Add a Trait to an organ that it will give its owner. /obj/item/organ/proc/add_organ_trait(trait) @@ -241,15 +125,6 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) /obj/item/organ/proc/on_find(mob/living/finder) return -/** - * Proc that gets called when the organ is surgically removed by someone, can be used for special effects - * Currently only used so surplus organs can explode when surgically removed. - */ -/obj/item/organ/proc/on_surgical_removal(mob/living/user, mob/living/carbon/old_owner, target_zone, obj/item/tool) - SHOULD_CALL_PARENT(TRUE) - SEND_SIGNAL(src, COMSIG_ORGAN_SURGICALLY_REMOVED, user, old_owner, target_zone, tool) - RemoveElement(/datum/element/decal/blood) - /obj/item/organ/wash(clean_types) . = ..() @@ -452,4 +327,4 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) /// Tries to replace the existing organ on the passed mob with this one, with special handling for replacing a brain without ghosting target /obj/item/organ/proc/replace_into(mob/living/carbon/new_owner) - return Insert(new_owner, special = TRUE, drop_if_replaced = FALSE) + return Insert(new_owner, special = TRUE, movement_flags = DELETE_IF_REPLACED) diff --git a/code/modules/surgery/organs/external/_external_organ.dm b/code/modules/surgery/organs/external/_external_organ.dm index db0d2535640..c75712d06d5 100644 --- a/code/modules/surgery/organs/external/_external_organ.dm +++ b/code/modules/surgery/organs/external/_external_organ.dm @@ -12,8 +12,6 @@ ///The overlay datum that actually draws stuff on the limb var/datum/bodypart_overlay/mutant/bodypart_overlay - ///Reference to the limb we're inside of - var/obj/item/bodypart/ownerlimb ///If not null, overrides the appearance with this sprite accessory datum var/sprite_accessory_override @@ -25,7 +23,7 @@ ///Set to EXTERNAL_BEHIND, EXTERNAL_FRONT or EXTERNAL_ADJACENT if you want to draw one of those layers as the object sprite. FALSE to use your own ///This will not work if it doesn't have a limb to generate it's icon with var/use_mob_sprite_as_obj_sprite = FALSE - ///Does this organ have any bodytypes to pass to it's ownerlimb? + ///Does this organ have any bodytypes to pass to it's bodypart_owner? var/external_bodytypes = NONE ///Which flags does a 'modification tool' need to have to restyle us, if it all possible (located in code/_DEFINES/mobs) var/restyle_flags = NONE @@ -55,23 +53,10 @@ if(restyle_flags) RegisterSignal(src, COMSIG_ATOM_RESTYLE, PROC_REF(on_attempt_feature_restyle)) -/obj/item/organ/external/Destroy() - if(owner) - Remove(owner, special=TRUE) - else if(ownerlimb) - remove_from_limb() - - return ..() - -/obj/item/organ/external/Insert(mob/living/carbon/receiver, special, drop_if_replaced) +/obj/item/organ/external/mob_insert(mob/living/carbon/receiver, special, movement_flags) if(!should_external_organ_apply_to(type, receiver)) stack_trace("adding a [type] to a [receiver.type] when it shouldn't be!") - var/obj/item/bodypart/limb = receiver.get_bodypart(deprecise_zone(zone)) - - if(!limb) - return FALSE - . = ..() if(!.) @@ -84,54 +69,28 @@ bodypart_overlay.set_appearance_from_name(feature_name) bodypart_overlay.imprint_on_next_insertion = FALSE - ownerlimb = limb - add_to_limb(ownerlimb) - if(external_bodytypes) receiver.synchronize_bodytypes() receiver.update_body_parts() -/obj/item/organ/external/Remove(mob/living/carbon/organ_owner, special, moving) - . = ..() - - if(ownerlimb) - remove_from_limb() - if(!moving && use_mob_sprite_as_obj_sprite) //so we're being taken out and dropped - update_appearance(UPDATE_OVERLAYS) - - if(organ_owner) +/obj/item/organ/external/mob_remove(mob/living/carbon/organ_owner, special, moving) + if(!special) + organ_owner.synchronize_bodytypes() organ_owner.update_body_parts() - - -/obj/item/organ/external/on_remove(mob/living/carbon/organ_owner, special) - . = ..() - color = bodypart_overlay.draw_color // so a pink felinid doesn't drop a gray tail - -///Transfers the organ to the limb, and to the limb's owner, if it has one. -/obj/item/organ/external/transfer_to_limb(obj/item/bodypart/bodypart, mob/living/carbon/bodypart_owner) - if(owner) - Remove(owner, moving = TRUE) - else if(ownerlimb) - remove_from_limb() - - if(bodypart_owner) - Insert(bodypart_owner, TRUE) - else - add_to_limb(bodypart) - -/obj/item/organ/external/add_to_limb(obj/item/bodypart/bodypart) - bodypart.external_organs += src - ownerlimb = bodypart - ownerlimb.add_bodypart_overlay(bodypart_overlay) return ..() -/obj/item/organ/external/remove_from_limb() - ownerlimb.external_organs -= src - ownerlimb.remove_bodypart_overlay(bodypart_overlay) - if(ownerlimb.owner && external_bodytypes) - ownerlimb.owner.synchronize_bodytypes() - ownerlimb = null +/obj/item/organ/external/on_bodypart_insert(obj/item/bodypart/bodypart) + bodypart.add_bodypart_overlay(bodypart_overlay) + return ..() + +/obj/item/organ/external/on_bodypart_remove(obj/item/bodypart/bodypart) + bodypart.remove_bodypart_overlay(bodypart_overlay) + + if(use_mob_sprite_as_obj_sprite) + update_appearance(UPDATE_OVERLAYS) + + color = bodypart_overlay.draw_color // so a pink felinid doesn't drop a gray tail return ..() /proc/should_external_organ_apply_to(obj/item/organ/external/organpath, mob/living/carbon/target) @@ -165,8 +124,8 @@ if(owner) //are we in a person? owner.update_body_parts() - else if(ownerlimb) //are we in a limb? - ownerlimb.update_icon_dropped() + else if(bodypart_owner) //are we in a limb? + bodypart_owner.update_icon_dropped() //else if(use_mob_sprite_as_obj_sprite) //are we out in the world, unprotected by flesh? /obj/item/organ/external/on_life(seconds_per_tick, times_fired) @@ -181,7 +140,7 @@ //Build the mob sprite and use it as our overlay for(var/external_layer in bodypart_overlay.all_layers) if(bodypart_overlay.layers & external_layer) - . += bodypart_overlay.get_overlay(external_layer, ownerlimb) + . += bodypart_overlay.get_overlay(external_layer, bodypart_owner) ///The horns of a lizard! /obj/item/organ/external/horns @@ -287,16 +246,17 @@ ///Store our old datum here for if our antennae are healed var/original_sprite_datum -/obj/item/organ/external/antennae/Insert(mob/living/carbon/receiver, special, drop_if_replaced) +/obj/item/organ/external/antennae/Insert(mob/living/carbon/receiver, special, movement_flags) . = ..() if(!.) return RegisterSignal(receiver, COMSIG_HUMAN_BURNING, PROC_REF(try_burn_antennae)) RegisterSignal(receiver, COMSIG_LIVING_POST_FULLY_HEAL, PROC_REF(heal_antennae)) -/obj/item/organ/external/antennae/Remove(mob/living/carbon/organ_owner, special, moving) +/obj/item/organ/external/antennae/Remove(mob/living/carbon/organ_owner, special, movement_flags) . = ..() - UnregisterSignal(organ_owner, list(COMSIG_HUMAN_BURNING, COMSIG_LIVING_POST_FULLY_HEAL)) + if(organ_owner) + UnregisterSignal(organ_owner, list(COMSIG_HUMAN_BURNING, COMSIG_LIVING_POST_FULLY_HEAL)) ///check if our antennae can burn off ;_; /obj/item/organ/external/antennae/proc/try_burn_antennae(mob/living/carbon/human/human) diff --git a/code/modules/surgery/organs/external/restyling.dm b/code/modules/surgery/organs/external/restyling.dm index 454e4395ae6..7d6be1b6d58 100644 --- a/code/modules/surgery/organs/external/restyling.dm +++ b/code/modules/surgery/organs/external/restyling.dm @@ -31,7 +31,7 @@ ///Asks the external organs inside the limb if they can restyle /obj/item/bodypart/proc/attempt_feature_restyle(atom/source, mob/living/trimmer, atom/movable/original_target, body_zone, restyle_type, style_speed) var/list/valid_features = list() - for(var/obj/item/organ/external/feature in external_organs) + for(var/obj/item/organ/external/feature in contents) if(feature.restyle_flags & restyle_type) valid_features.Add(feature) diff --git a/code/modules/surgery/organs/external/spines.dm b/code/modules/surgery/organs/external/spines.dm index d7b9dd785d0..7588e26735e 100644 --- a/code/modules/surgery/organs/external/spines.dm +++ b/code/modules/surgery/organs/external/spines.dm @@ -17,13 +17,13 @@ ///A two-way reference between the tail and the spines because of wagging sprites. Bruh. var/obj/item/organ/external/tail/lizard/paired_tail -/obj/item/organ/external/spines/Insert(mob/living/carbon/receiver, special, drop_if_replaced) +/obj/item/organ/external/spines/Insert(mob/living/carbon/receiver, special, movement_flags) . = ..() if(.) paired_tail = locate(/obj/item/organ/external/tail/lizard) in receiver.organs //We want specifically a lizard tail, so we don't use the slot. paired_tail?.paired_spines = src -/obj/item/organ/external/spines/Remove(mob/living/carbon/organ_owner, special, moving) +/obj/item/organ/external/spines/Remove(mob/living/carbon/organ_owner, special, movement_flags) . = ..() if(paired_tail) paired_tail.paired_spines = null diff --git a/code/modules/surgery/organs/external/tails.dm b/code/modules/surgery/organs/external/tails.dm index 65db70f70b5..9937ee18d10 100644 --- a/code/modules/surgery/organs/external/tails.dm +++ b/code/modules/surgery/organs/external/tails.dm @@ -18,7 +18,7 @@ ///The original owner of this tail var/original_owner //Yay, snowflake code! -/obj/item/organ/external/tail/Insert(mob/living/carbon/receiver, special, drop_if_replaced) +/obj/item/organ/external/tail/Insert(mob/living/carbon/receiver, special, movement_flags) . = ..() if(.) RegisterSignal(receiver, COMSIG_ORGAN_WAG_TAIL, PROC_REF(wag)) @@ -32,15 +32,12 @@ else if(type in receiver.dna.species.external_organs) receiver.add_mood_event("wrong_tail_regained", /datum/mood_event/tail_regained_wrong) -/obj/item/organ/external/tail/Remove(mob/living/carbon/organ_owner, special, moving) +/obj/item/organ/external/tail/on_mob_remove(mob/living/carbon/organ_owner, special) + . = ..() + if(wag_flags & WAG_WAGGING) wag(organ_owner, start = FALSE) - return ..() - -/obj/item/organ/external/tail/on_remove(mob/living/carbon/organ_owner, special) - . = ..() - UnregisterSignal(organ_owner, COMSIG_ORGAN_WAG_TAIL) if(type in organ_owner.dna.species.external_organs) @@ -136,13 +133,13 @@ ///A reference to the paired_spines, since for some fucking reason tail spines are tied to the spines themselves. var/obj/item/organ/external/spines/paired_spines -/obj/item/organ/external/tail/lizard/Insert(mob/living/carbon/receiver, special, drop_if_replaced) +/obj/item/organ/external/tail/lizard/Insert(mob/living/carbon/receiver, special, movement_flags) . = ..() if(.) - paired_spines = ownerlimb.owner.get_organ_slot(ORGAN_SLOT_EXTERNAL_SPINES) + paired_spines = bodypart_owner.owner.get_organ_slot(ORGAN_SLOT_EXTERNAL_SPINES) paired_spines?.paired_tail = src -/obj/item/organ/external/tail/lizard/Remove(mob/living/carbon/organ_owner, special, moving) +/obj/item/organ/external/tail/lizard/Remove(mob/living/carbon/organ_owner, special, movement_flags) . = ..() if(paired_spines) paired_spines.paired_tail = null diff --git a/code/modules/surgery/organs/external/wings/functional_wings.dm b/code/modules/surgery/organs/external/wings/functional_wings.dm index 72f55ea0e34..aacf6f08f6a 100644 --- a/code/modules/surgery/organs/external/wings/functional_wings.dm +++ b/code/modules/surgery/organs/external/wings/functional_wings.dm @@ -29,13 +29,13 @@ // grind_results = list(/datum/reagent/flightpotion = 5) food_reagents = list(/datum/reagent/flightpotion = 5) -/obj/item/organ/external/wings/functional/Insert(mob/living/carbon/receiver, special, drop_if_replaced) +/obj/item/organ/external/wings/functional/Insert(mob/living/carbon/receiver, special, movement_flags) . = ..() if(. && isnull(fly)) fly = new fly.Grant(receiver) -/obj/item/organ/external/wings/functional/Remove(mob/living/carbon/organ_owner, special, moving) +/obj/item/organ/external/wings/functional/Remove(mob/living/carbon/organ_owner, special, movement_flags) . = ..() fly.Remove(organ_owner) diff --git a/code/modules/surgery/organs/external/wings/moth_wings.dm b/code/modules/surgery/organs/external/wings/moth_wings.dm index f13b346ab07..f4e0f156e70 100644 --- a/code/modules/surgery/organs/external/wings/moth_wings.dm +++ b/code/modules/surgery/organs/external/wings/moth_wings.dm @@ -14,13 +14,13 @@ ///Store our old datum here for if our burned wings are healed var/original_sprite_datum -/obj/item/organ/external/wings/moth/on_insert(mob/living/carbon/receiver) +/obj/item/organ/external/wings/moth/on_mob_insert(mob/living/carbon/receiver) . = ..() RegisterSignal(receiver, COMSIG_HUMAN_BURNING, PROC_REF(try_burn_wings)) RegisterSignal(receiver, COMSIG_LIVING_POST_FULLY_HEAL, PROC_REF(heal_wings)) RegisterSignal(receiver, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(update_float_move)) -/obj/item/organ/external/wings/moth/on_remove(mob/living/carbon/organ_owner) +/obj/item/organ/external/wings/moth/on_mob_remove(mob/living/carbon/organ_owner) . = ..() UnregisterSignal(organ_owner, list(COMSIG_HUMAN_BURNING, COMSIG_LIVING_POST_FULLY_HEAL, COMSIG_MOVABLE_PRE_MOVE)) REMOVE_TRAIT(organ_owner, TRAIT_FREE_FLOAT_MOVEMENT, REF(src)) diff --git a/code/modules/surgery/organs/internal/_internal_organ.dm b/code/modules/surgery/organs/internal/_internal_organ.dm index eb8629347e6..ecd6eb2b7d7 100644 --- a/code/modules/surgery/organs/internal/_internal_organ.dm +++ b/code/modules/surgery/organs/internal/_internal_organ.dm @@ -5,19 +5,8 @@ . = ..() START_PROCESSING(SSobj, src) -/obj/item/organ/internal/Destroy() - if(owner) - // The special flag is important, because otherwise mobs can die - // while undergoing transformation into different mobs. - Remove(owner, special=TRUE) - else - STOP_PROCESSING(SSobj, src) - return ..() - -/obj/item/organ/internal/Insert(mob/living/carbon/receiver, special = FALSE, drop_if_replaced = TRUE) +/obj/item/organ/internal/on_mob_insert(mob/living/carbon/organ_owner, special, movement_flags) . = ..() - if(!. || !owner) - return // organs_slot must ALWAYS be ordered in the same way as organ_process_order // Otherwise life processing breaks down @@ -25,18 +14,16 @@ STOP_PROCESSING(SSobj, src) -/obj/item/organ/internal/Remove(mob/living/carbon/organ_owner, special = FALSE) +/obj/item/organ/internal/on_mob_remove(mob/living/carbon/organ_owner, special = FALSE) . = ..() - if(organ_owner) - if((organ_flags & ORGAN_VITAL) && !special && !(organ_owner.status_flags & GODMODE)) - if(organ_owner.stat != DEAD) - organ_owner.investigate_log("has been killed by losing a vital organ ([src]).", INVESTIGATE_DEATHS) - organ_owner.death() + if((organ_flags & ORGAN_VITAL) && !special && !(organ_owner.status_flags & GODMODE)) + if(organ_owner.stat != DEAD) + organ_owner.investigate_log("has been killed by losing a vital organ ([src]).", INVESTIGATE_DEATHS) + organ_owner.death() START_PROCESSING(SSobj, src) - /obj/item/organ/internal/process(seconds_per_tick, times_fired) on_death(seconds_per_tick, times_fired) //Kinda hate doing it like this, but I really don't want to call process directly. diff --git a/code/modules/surgery/organs/internal/appendix/_appendix.dm b/code/modules/surgery/organs/internal/appendix/_appendix.dm index ee87d674dc4..e5190f1282e 100644 --- a/code/modules/surgery/organs/internal/appendix/_appendix.dm +++ b/code/modules/surgery/organs/internal/appendix/_appendix.dm @@ -76,12 +76,12 @@ /obj/item/organ/internal/appendix/get_availability(datum/species/owner_species, mob/living/owner_mob) return owner_species.mutantappendix -/obj/item/organ/internal/appendix/on_remove(mob/living/carbon/organ_owner) +/obj/item/organ/internal/appendix/on_mob_remove(mob/living/carbon/organ_owner) . = ..() REMOVE_TRAIT(organ_owner, TRAIT_DISEASELIKE_SEVERITY_MEDIUM, type) organ_owner.med_hud_set_status() -/obj/item/organ/internal/appendix/on_insert(mob/living/carbon/organ_owner) +/obj/item/organ/internal/appendix/on_mob_insert(mob/living/carbon/organ_owner) . = ..() if(inflamation_stage) ADD_TRAIT(organ_owner, TRAIT_DISEASELIKE_SEVERITY_MEDIUM, type) diff --git a/code/modules/surgery/organs/internal/appendix/appendix_golem.dm b/code/modules/surgery/organs/internal/appendix/appendix_golem.dm index ede8dfa1e6b..5510b4bf967 100644 --- a/code/modules/surgery/organs/internal/appendix/appendix_golem.dm +++ b/code/modules/surgery/organs/internal/appendix/appendix_golem.dm @@ -12,7 +12,7 @@ . = ..() smelter = new(src) -/obj/item/organ/internal/appendix/golem/on_insert(mob/living/carbon/organ_owner) +/obj/item/organ/internal/appendix/golem/on_mob_insert(mob/living/carbon/organ_owner) . = ..() RegisterSignal(owner, COMSIG_MOVABLE_MOVED, PROC_REF(check_for_lava)) @@ -25,7 +25,7 @@ if (smelter.owner != owner) smelter.Grant(owner) -/obj/item/organ/internal/appendix/golem/on_remove(mob/living/carbon/organ_owner) +/obj/item/organ/internal/appendix/golem/on_mob_remove(mob/living/carbon/organ_owner) UnregisterSignal(organ_owner, COMSIG_MOVABLE_MOVED) smelter?.Remove(organ_owner) // Might have been deleted by Destroy already return ..() diff --git a/code/modules/surgery/organs/internal/cyberimp/augments_arms.dm b/code/modules/surgery/organs/internal/cyberimp/augments_arms.dm index 2c14c91dbd5..6f87ad0e8ee 100644 --- a/code/modules/surgery/organs/internal/cyberimp/augments_arms.dm +++ b/code/modules/surgery/organs/internal/cyberimp/augments_arms.dm @@ -76,7 +76,7 @@ to_chat(user, span_notice("You modify [src] to be installed on the [zone == BODY_ZONE_R_ARM ? "right" : "left"] arm.")) update_appearance() -/obj/item/organ/internal/cyberimp/arm/on_insert(mob/living/carbon/arm_owner) +/obj/item/organ/internal/cyberimp/arm/on_mob_insert(mob/living/carbon/arm_owner) . = ..() var/side = zone == BODY_ZONE_R_ARM? RIGHT_HANDS : LEFT_HANDS hand = arm_owner.hand_bodyparts[side] @@ -84,7 +84,7 @@ RegisterSignal(hand, COMSIG_ITEM_ATTACK_SELF, PROC_REF(on_item_attack_self)) //If the limb gets an attack-self, open the menu. Only happens when hand is empty RegisterSignal(arm_owner, COMSIG_KB_MOB_DROPITEM_DOWN, PROC_REF(dropkey)) //We're nodrop, but we'll watch for the drop hotkey anyway and then stow if possible. -/obj/item/organ/internal/cyberimp/arm/on_remove(mob/living/carbon/arm_owner) +/obj/item/organ/internal/cyberimp/arm/on_mob_remove(mob/living/carbon/arm_owner) . = ..() Retract() if(hand) @@ -378,14 +378,14 @@ ///How long will the implant malfunction if it is EMP'd var/emp_base_duration = 9 SECONDS -/obj/item/organ/internal/cyberimp/arm/muscle/Insert(mob/living/carbon/receiver, special = FALSE, drop_if_replaced = TRUE) +/obj/item/organ/internal/cyberimp/arm/muscle/on_mob_insert(mob/living/carbon/arm_owner) . = ..() - if(ishuman(receiver)) //Sorry, only humans - RegisterSignal(receiver, COMSIG_LIVING_EARLY_UNARMED_ATTACK, PROC_REF(on_attack_hand)) + if(ishuman(arm_owner)) //Sorry, only humans + RegisterSignal(arm_owner, COMSIG_LIVING_EARLY_UNARMED_ATTACK, PROC_REF(on_attack_hand)) -/obj/item/organ/internal/cyberimp/arm/muscle/Remove(mob/living/carbon/implant_owner, special = 0) +/obj/item/organ/internal/cyberimp/arm/muscle/on_mob_remove(mob/living/carbon/arm_owner) . = ..() - UnregisterSignal(implant_owner, COMSIG_LIVING_EARLY_UNARMED_ATTACK) + UnregisterSignal(arm_owner, COMSIG_LIVING_EARLY_UNARMED_ATTACK) /obj/item/organ/internal/cyberimp/arm/muscle/emp_act(severity) . = ..() diff --git a/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm b/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm index 3fe5e150288..41860d60b48 100644 --- a/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm +++ b/code/modules/surgery/organs/internal/cyberimp/augments_chest.dm @@ -182,7 +182,7 @@ /datum/effect_system/trail_follow/ion \ ) -/obj/item/organ/internal/cyberimp/chest/thrusters/Remove(mob/living/carbon/thruster_owner, special = 0) +/obj/item/organ/internal/cyberimp/chest/thrusters/Remove(mob/living/carbon/thruster_owner, special, movement_flags) if(on) deactivate(silent = TRUE) ..() diff --git a/code/modules/surgery/organs/internal/cyberimp/augments_eyes.dm b/code/modules/surgery/organs/internal/cyberimp/augments_eyes.dm index 869d4cc1c9e..cec0241ece3 100644 --- a/code/modules/surgery/organs/internal/cyberimp/augments_eyes.dm +++ b/code/modules/surgery/organs/internal/cyberimp/augments_eyes.dm @@ -31,7 +31,7 @@ hud.show_to(eye_owner) toggled_on = TRUE -/obj/item/organ/internal/cyberimp/eyes/hud/Insert(mob/living/carbon/eye_owner, special = FALSE, drop_if_replaced = TRUE) +/obj/item/organ/internal/cyberimp/eyes/hud/Insert(mob/living/carbon/eye_owner, special = FALSE, movement_flags) . = ..() if(!.) return @@ -42,7 +42,7 @@ ADD_TRAIT(eye_owner, HUD_trait, ORGAN_TRAIT) toggled_on = TRUE -/obj/item/organ/internal/cyberimp/eyes/hud/Remove(mob/living/carbon/eye_owner, special = FALSE) +/obj/item/organ/internal/cyberimp/eyes/hud/Remove(mob/living/carbon/eye_owner, special, movement_flags) . = ..() if(HUD_type) var/datum/atom_hud/hud = GLOB.huds[HUD_type] diff --git a/code/modules/surgery/organs/internal/cyberimp/augments_internal.dm b/code/modules/surgery/organs/internal/cyberimp/augments_internal.dm index f0578832969..67a02e71d7e 100644 --- a/code/modules/surgery/organs/internal/cyberimp/augments_internal.dm +++ b/code/modules/surgery/organs/internal/cyberimp/augments_internal.dm @@ -87,7 +87,7 @@ stored_items = list() -/obj/item/organ/internal/cyberimp/brain/anti_drop/Remove(mob/living/carbon/implant_owner, special = 0) +/obj/item/organ/internal/cyberimp/brain/anti_drop/Remove(mob/living/carbon/implant_owner, special, movement_flags) if(active) ui_action_click() ..() @@ -113,11 +113,11 @@ var/stun_cap_amount = 40 -/obj/item/organ/internal/cyberimp/brain/anti_stun/on_remove(mob/living/carbon/implant_owner) +/obj/item/organ/internal/cyberimp/brain/anti_stun/on_mob_remove(mob/living/carbon/implant_owner) . = ..() UnregisterSignal(implant_owner, signalCache) -/obj/item/organ/internal/cyberimp/brain/anti_stun/on_insert(mob/living/carbon/receiver) +/obj/item/organ/internal/cyberimp/brain/anti_stun/on_mob_insert(mob/living/carbon/receiver) . = ..() RegisterSignals(receiver, signalCache, PROC_REF(on_signal)) diff --git a/code/modules/surgery/organs/internal/ears/_ears.dm b/code/modules/surgery/organs/internal/ears/_ears.dm index 7d2b0f3c549..ad48645e893 100644 --- a/code/modules/surgery/organs/internal/ears/_ears.dm +++ b/code/modules/surgery/organs/internal/ears/_ears.dm @@ -68,7 +68,7 @@ visual = TRUE damage_multiplier = 2 -/obj/item/organ/internal/ears/cat/on_insert(mob/living/carbon/human/ear_owner) +/obj/item/organ/internal/ears/cat/on_mob_insert(mob/living/carbon/human/ear_owner) . = ..() if(istype(ear_owner) && ear_owner.dna) color = ear_owner.hair_color @@ -76,7 +76,7 @@ ear_owner.dna.update_uf_block(DNA_EARS_BLOCK) ear_owner.update_body() -/obj/item/organ/internal/ears/cat/on_remove(mob/living/carbon/human/ear_owner) +/obj/item/organ/internal/ears/cat/on_mob_remove(mob/living/carbon/human/ear_owner) . = ..() if(istype(ear_owner) && ear_owner.dna) color = ear_owner.hair_color @@ -87,13 +87,13 @@ name = "penguin ears" desc = "The source of a penguin's happy feet." -/obj/item/organ/internal/ears/penguin/on_insert(mob/living/carbon/human/ear_owner) +/obj/item/organ/internal/ears/penguin/on_mob_insert(mob/living/carbon/human/ear_owner) . = ..() if(istype(ear_owner)) to_chat(ear_owner, span_notice("You suddenly feel like you've lost your balance.")) ear_owner.AddElement(/datum/element/waddling) -/obj/item/organ/internal/ears/penguin/on_remove(mob/living/carbon/human/ear_owner) +/obj/item/organ/internal/ears/penguin/on_mob_remove(mob/living/carbon/human/ear_owner) . = ..() if(istype(ear_owner)) to_chat(ear_owner, span_notice("Your sense of balance comes back to you.")) @@ -122,11 +122,11 @@ // The original idea was to use signals to do this not traits. Unfortunately, the star effect used for whispers applies before any relevant signals // This seems like the least invasive solution -/obj/item/organ/internal/ears/cybernetic/whisper/on_insert(mob/living/carbon/ear_owner) +/obj/item/organ/internal/ears/cybernetic/whisper/on_mob_insert(mob/living/carbon/ear_owner) . = ..() ADD_TRAIT(ear_owner, TRAIT_GOOD_HEARING, ORGAN_TRAIT) -/obj/item/organ/internal/ears/cybernetic/whisper/on_remove(mob/living/carbon/ear_owner) +/obj/item/organ/internal/ears/cybernetic/whisper/on_mob_remove(mob/living/carbon/ear_owner) . = ..() REMOVE_TRAIT(ear_owner, TRAIT_GOOD_HEARING, ORGAN_TRAIT) @@ -138,11 +138,11 @@ // Same sensitivity as felinid ears damage_multiplier = 2 -/obj/item/organ/internal/ears/cybernetic/xray/on_insert(mob/living/carbon/ear_owner) +/obj/item/organ/internal/ears/cybernetic/xray/on_mob_insert(mob/living/carbon/ear_owner) . = ..() ADD_TRAIT(ear_owner, TRAIT_XRAY_HEARING, ORGAN_TRAIT) -/obj/item/organ/internal/ears/cybernetic/xray/on_remove(mob/living/carbon/ear_owner) +/obj/item/organ/internal/ears/cybernetic/xray/on_mob_remove(mob/living/carbon/ear_owner) . = ..() REMOVE_TRAIT(ear_owner, TRAIT_XRAY_HEARING, ORGAN_TRAIT) diff --git a/code/modules/surgery/organs/internal/eyes/_eyes.dm b/code/modules/surgery/organs/internal/eyes/_eyes.dm index 2b6329702f3..d9c0ea86fcf 100644 --- a/code/modules/surgery/organs/internal/eyes/_eyes.dm +++ b/code/modules/surgery/organs/internal/eyes/_eyes.dm @@ -52,7 +52,7 @@ /// Native FOV that will be applied if a config is enabled var/native_fov = FOV_90_DEGREES -/obj/item/organ/internal/eyes/Insert(mob/living/carbon/eye_recipient, special = FALSE, drop_if_replaced = FALSE) +/obj/item/organ/internal/eyes/Insert(mob/living/carbon/eye_recipient, special = FALSE, movement_flags = DELETE_IF_REPLACED) // If we don't do this before everything else, heterochromia will be reset leading to eye_color_right no longer being accurate if(ishuman(eye_recipient)) var/mob/living/carbon/human/human_recipient = eye_recipient @@ -94,7 +94,7 @@ if(call_update) affected_human.update_body() -/obj/item/organ/internal/eyes/Remove(mob/living/carbon/eye_owner, special = FALSE) +/obj/item/organ/internal/eyes/Remove(mob/living/carbon/eye_owner, special, movement_flags) . = ..() if(ishuman(eye_owner)) var/mob/living/carbon/human/human_owner = eye_owner @@ -104,7 +104,8 @@ human_owner.eye_color_right = old_eye_color_right if(native_fov) eye_owner.remove_fov_trait(type) - human_owner.update_body() + if(!special) + human_owner.update_body() // Cure blindness from eye damage eye_owner.cure_blind(EYE_DAMAGE) @@ -327,11 +328,11 @@ eye_color_right = "000" sight_flags = SEE_MOBS | SEE_OBJS | SEE_TURFS -/obj/item/organ/internal/eyes/robotic/xray/on_insert(mob/living/carbon/eye_owner) +/obj/item/organ/internal/eyes/robotic/xray/on_mob_insert(mob/living/carbon/eye_owner) . = ..() ADD_TRAIT(eye_owner, TRAIT_XRAY_VISION, ORGAN_TRAIT) -/obj/item/organ/internal/eyes/robotic/xray/on_remove(mob/living/carbon/eye_owner) +/obj/item/organ/internal/eyes/robotic/xray/on_mob_remove(mob/living/carbon/eye_owner) . = ..() REMOVE_TRAIT(eye_owner, TRAIT_XRAY_VISION, ORGAN_TRAIT) @@ -359,7 +360,7 @@ /obj/item/organ/internal/eyes/robotic/flashlight/emp_act(severity) return -/obj/item/organ/internal/eyes/robotic/flashlight/on_insert(mob/living/carbon/victim) +/obj/item/organ/internal/eyes/robotic/flashlight/on_mob_insert(mob/living/carbon/victim) . = ..() if(!eye) eye = new /obj/item/flashlight/eyelight() @@ -368,7 +369,7 @@ eye.update_brightness(victim) victim.become_blind(FLASHLIGHT_EYES) -/obj/item/organ/internal/eyes/robotic/flashlight/on_remove(mob/living/carbon/victim) +/obj/item/organ/internal/eyes/robotic/flashlight/on_mob_remove(mob/living/carbon/victim) . = ..() eye.set_light_on(FALSE) eye.update_brightness(victim) @@ -425,18 +426,18 @@ deactivate(close_ui = TRUE) /// Set the initial color of the eyes on insert to be the mob's previous eye color. -/obj/item/organ/internal/eyes/robotic/glow/Insert(mob/living/carbon/eye_recipient, special = FALSE, drop_if_replaced = FALSE) +/obj/item/organ/internal/eyes/robotic/glow/Insert(mob/living/carbon/eye_recipient, special = FALSE, movement_flags = DELETE_IF_REPLACED) . = ..() left_eye_color_string = old_eye_color_left right_eye_color_string = old_eye_color_right update_mob_eye_color(eye_recipient) -/obj/item/organ/internal/eyes/robotic/glow/on_insert(mob/living/carbon/eye_recipient) +/obj/item/organ/internal/eyes/robotic/glow/on_mob_insert(mob/living/carbon/eye_recipient) . = ..() deactivate(close_ui = TRUE) eye.forceMove(eye_recipient) -/obj/item/organ/internal/eyes/robotic/glow/on_remove(mob/living/carbon/eye_owner) +/obj/item/organ/internal/eyes/robotic/glow/on_mob_remove(mob/living/carbon/eye_owner) deactivate(eye_owner, close_ui = TRUE) if(!QDELETED(eye)) eye.forceMove(src) @@ -723,7 +724,7 @@ high_light_cutoff = list(30, 35, 50) var/obj/item/flashlight/eyelight/adapted/adapt_light -/obj/item/organ/internal/eyes/night_vision/maintenance_adapted/on_insert(mob/living/carbon/eye_owner) +/obj/item/organ/internal/eyes/night_vision/maintenance_adapted/on_mob_insert(mob/living/carbon/eye_owner) . = ..() //add lighting if(!adapt_light) @@ -742,7 +743,7 @@ apply_organ_damage(-10) //heal quickly . = ..() -/obj/item/organ/internal/eyes/night_vision/maintenance_adapted/Remove(mob/living/carbon/unadapted, special = FALSE) +/obj/item/organ/internal/eyes/night_vision/maintenance_adapted/on_mob_remove(mob/living/carbon/unadapted, special = FALSE) //remove lighting adapt_light.set_light_on(FALSE) adapt_light.update_brightness(unadapted) diff --git a/code/modules/surgery/organs/internal/heart/_heart.dm b/code/modules/surgery/organs/internal/heart/_heart.dm index 8a5646d1814..e2ca8725b9d 100644 --- a/code/modules/surgery/organs/internal/heart/_heart.dm +++ b/code/modules/surgery/organs/internal/heart/_heart.dm @@ -33,7 +33,7 @@ . = ..() icon_state = "[base_icon_state]-[beating ? "on" : "off"]" -/obj/item/organ/internal/heart/Remove(mob/living/carbon/heartless, special = 0) +/obj/item/organ/internal/heart/Remove(mob/living/carbon/heartless, special, movement_flags) . = ..() if(!special) addtimer(CALLBACK(src, PROC_REF(stop_if_unowned)), 12 SECONDS) @@ -146,12 +146,14 @@ else return ..() -/obj/item/organ/internal/heart/cursed/on_insert(mob/living/carbon/accursed) +/obj/item/organ/internal/heart/cursed/on_mob_insert(mob/living/carbon/accursed) . = ..() + accursed.AddComponent(/datum/component/manual_heart, pump_delay = pump_delay, blood_loss = blood_loss, heal_brute = heal_brute, heal_burn = heal_burn, heal_oxy = heal_oxy) -/obj/item/organ/internal/heart/cursed/Remove(mob/living/carbon/accursed, special = FALSE) +/obj/item/organ/internal/heart/cursed/on_mob_remove(mob/living/carbon/accursed, special = FALSE) . = ..() + qdel(accursed.GetComponent(/datum/component/manual_heart)) /obj/item/organ/internal/heart/cybernetic diff --git a/code/modules/surgery/organs/internal/heart/heart_ethereal.dm b/code/modules/surgery/organs/internal/heart/heart_ethereal.dm index 78ee55b0b28..50659115872 100644 --- a/code/modules/surgery/organs/internal/heart/heart_ethereal.dm +++ b/code/modules/surgery/organs/internal/heart/heart_ethereal.dm @@ -21,7 +21,7 @@ add_atom_colour(ethereal_color, FIXED_COLOUR_PRIORITY) update_appearance() -/obj/item/organ/internal/heart/ethereal/Insert(mob/living/carbon/heart_owner, special = FALSE, drop_if_replaced = TRUE) +/obj/item/organ/internal/heart/ethereal/Insert(mob/living/carbon/heart_owner, special = FALSE, movement_flags) . = ..() if(!.) return @@ -29,7 +29,7 @@ RegisterSignal(heart_owner, COMSIG_LIVING_POST_FULLY_HEAL, PROC_REF(on_owner_fully_heal)) RegisterSignal(heart_owner, COMSIG_QDELETING, PROC_REF(owner_deleted)) -/obj/item/organ/internal/heart/ethereal/Remove(mob/living/carbon/heart_owner, special = FALSE) +/obj/item/organ/internal/heart/ethereal/Remove(mob/living/carbon/heart_owner, special, movement_flags) UnregisterSignal(heart_owner, list(COMSIG_MOB_STATCHANGE, COMSIG_LIVING_POST_FULLY_HEAL, COMSIG_QDELETING)) REMOVE_TRAIT(heart_owner, TRAIT_CORPSELOCKED, SPECIES_TRAIT) stop_crystalization_process(heart_owner) diff --git a/code/modules/surgery/organs/internal/liver/_liver.dm b/code/modules/surgery/organs/internal/liver/_liver.dm index c78b071eec0..92e2cb0039f 100755 --- a/code/modules/surgery/organs/internal/liver/_liver.dm +++ b/code/modules/surgery/organs/internal/liver/_liver.dm @@ -61,12 +61,12 @@ qdel(GetComponent(/datum/component/squeak)) /// Registers COMSIG_SPECIES_HANDLE_CHEMICAL from owner -/obj/item/organ/internal/liver/on_insert(mob/living/carbon/organ_owner, special) +/obj/item/organ/internal/liver/on_mob_insert(mob/living/carbon/organ_owner, special) . = ..() RegisterSignal(organ_owner, COMSIG_SPECIES_HANDLE_CHEMICAL, PROC_REF(handle_chemical)) /// Unregisters COMSIG_SPECIES_HANDLE_CHEMICAL from owner -/obj/item/organ/internal/liver/on_remove(mob/living/carbon/organ_owner, special) +/obj/item/organ/internal/liver/on_mob_remove(mob/living/carbon/organ_owner, special) . = ..() UnregisterSignal(organ_owner, COMSIG_SPECIES_HANDLE_CHEMICAL) @@ -134,7 +134,7 @@ return var/obj/belly = owner.get_organ_slot(ORGAN_SLOT_STOMACH) - var/list/cached_reagents = owner.reagents.reagent_list + var/list/cached_reagents = owner.reagents?.reagent_list var/liver_damage = 0 var/provide_pain_message = HAS_NO_TOXIN @@ -152,7 +152,7 @@ if(provide_pain_message != HAS_PAINFUL_TOXIN) provide_pain_message = toxin.silent_toxin ? HAS_SILENT_TOXIN : HAS_PAINFUL_TOXIN - owner.reagents.metabolize(owner, seconds_per_tick, times_fired, can_overdose = TRUE) + owner.reagents?.metabolize(owner, seconds_per_tick, times_fired, can_overdose = TRUE) if(liver_damage) apply_organ_damage(min(liver_damage * seconds_per_tick , MAX_TOXIN_LIVER_DAMAGE * seconds_per_tick)) diff --git a/code/modules/surgery/organs/internal/lungs/_lungs.dm b/code/modules/surgery/organs/internal/lungs/_lungs.dm index 2e99f70d989..874ec320648 100644 --- a/code/modules/surgery/organs/internal/lungs/_lungs.dm +++ b/code/modules/surgery/organs/internal/lungs/_lungs.dm @@ -153,7 +153,7 @@ add_gas_reaction(/datum/gas/zauker, while_present = PROC_REF(too_much_zauker)) ///Simply exists so that you don't keep any alerts from your previous lack of lungs. -/obj/item/organ/internal/lungs/Insert(mob/living/carbon/receiver, special = FALSE, drop_if_replaced = TRUE) +/obj/item/organ/internal/lungs/Insert(mob/living/carbon/receiver, special = FALSE, movement_flags) . = ..() if(!.) return . @@ -163,7 +163,7 @@ receiver.clear_alert(ALERT_NOT_ENOUGH_PLASMA) receiver.clear_alert(ALERT_NOT_ENOUGH_N2O) -/obj/item/organ/internal/lungs/Remove(mob/living/carbon/organ_owner, special) +/obj/item/organ/internal/lungs/Remove(mob/living/carbon/organ_owner, special, movement_flags) . = ..() // This is very "manual" I realize, but it's useful to ensure cleanup for gases we're removing happens // Avoids stuck alerts and such diff --git a/code/modules/surgery/organs/internal/stomach/_stomach.dm b/code/modules/surgery/organs/internal/stomach/_stomach.dm index d97b883817d..6e985e26329 100644 --- a/code/modules/surgery/organs/internal/stomach/_stomach.dm +++ b/code/modules/surgery/organs/internal/stomach/_stomach.dm @@ -55,7 +55,7 @@ var/mob/living/carbon/body = owner // digest food, sent all reagents that can metabolize to the body - for(var/datum/reagent/bit as anything in reagents.reagent_list) + for(var/datum/reagent/bit as anything in reagents?.reagent_list) // If the reagent does not metabolize then it will sit in the stomach // This has an effect on items like plastic causing them to take up space in the stomach @@ -93,7 +93,7 @@ return //We are checking if we have nutriment in a damaged stomach. - var/datum/reagent/nutri = locate(/datum/reagent/consumable/nutriment) in reagents.reagent_list + var/datum/reagent/nutri = locate(/datum/reagent/consumable/nutriment) in reagents?.reagent_list //No nutriment found lets exit out if(!nutri) return @@ -262,7 +262,7 @@ disgusted.throw_alert(ALERT_DISGUST, /atom/movable/screen/alert/disgusted) disgusted.add_mood_event("disgust", /datum/mood_event/disgusted) -/obj/item/organ/internal/stomach/Remove(mob/living/carbon/stomach_owner, special = 0) +/obj/item/organ/internal/stomach/Remove(mob/living/carbon/stomach_owner, special, movement_flags) if(ishuman(stomach_owner)) var/mob/living/carbon/human/human_owner = owner human_owner.clear_alert(ALERT_DISGUST) diff --git a/code/modules/surgery/organs/internal/stomach/stomach_ethereal.dm b/code/modules/surgery/organs/internal/stomach/stomach_ethereal.dm index c1632f33329..68f9d9428a0 100644 --- a/code/modules/surgery/organs/internal/stomach/stomach_ethereal.dm +++ b/code/modules/surgery/organs/internal/stomach/stomach_ethereal.dm @@ -13,12 +13,12 @@ adjust_charge(-ETHEREAL_CHARGE_FACTOR * seconds_per_tick) handle_charge(owner, seconds_per_tick, times_fired) -/obj/item/organ/internal/stomach/ethereal/on_insert(mob/living/carbon/stomach_owner) +/obj/item/organ/internal/stomach/ethereal/on_mob_insert(mob/living/carbon/stomach_owner) . = ..() RegisterSignal(stomach_owner, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, PROC_REF(charge)) RegisterSignal(stomach_owner, COMSIG_LIVING_ELECTROCUTE_ACT, PROC_REF(on_electrocute)) -/obj/item/organ/internal/stomach/ethereal/on_remove(mob/living/carbon/stomach_owner) +/obj/item/organ/internal/stomach/ethereal/on_mob_remove(mob/living/carbon/stomach_owner) . = ..() UnregisterSignal(stomach_owner, COMSIG_PROCESS_BORGCHARGER_OCCUPANT) UnregisterSignal(stomach_owner, COMSIG_LIVING_ELECTROCUTE_ACT) diff --git a/code/modules/surgery/organs/internal/stomach/stomach_golem.dm b/code/modules/surgery/organs/internal/stomach/stomach_golem.dm index 5f721fa52b1..a1f5ce6c70e 100644 --- a/code/modules/surgery/organs/internal/stomach/stomach_golem.dm +++ b/code/modules/surgery/organs/internal/stomach/stomach_golem.dm @@ -11,11 +11,11 @@ /// How slow are you if you have absolutely nothing in the tank? var/max_hunger_slowdown = 4 -/obj/item/organ/internal/stomach/golem/on_insert(mob/living/carbon/organ_owner, special) +/obj/item/organ/internal/stomach/golem/on_mob_insert(mob/living/carbon/organ_owner, special) . = ..() RegisterSignal(owner, COMSIG_CARBON_ATTEMPT_EAT, PROC_REF(try_eating)) -/obj/item/organ/internal/stomach/golem/on_remove(mob/living/carbon/organ_owner, special) +/obj/item/organ/internal/stomach/golem/on_mob_remove(mob/living/carbon/organ_owner, special) . = ..() UnregisterSignal(organ_owner, COMSIG_CARBON_ATTEMPT_EAT) organ_owner.remove_movespeed_modifier(/datum/movespeed_modifier/golem_hunger) diff --git a/code/modules/surgery/organs/internal/tongue/_tongue.dm b/code/modules/surgery/organs/internal/tongue/_tongue.dm index ca5e3873a2b..cbed058a44c 100644 --- a/code/modules/surgery/organs/internal/tongue/_tongue.dm +++ b/code/modules/surgery/organs/internal/tongue/_tongue.dm @@ -120,7 +120,7 @@ food_taste_reaction = FOOD_LIKED return food_taste_reaction -/obj/item/organ/internal/tongue/Insert(mob/living/carbon/tongue_owner, special = FALSE, drop_if_replaced = TRUE) +/obj/item/organ/internal/tongue/Insert(mob/living/carbon/tongue_owner, special = FALSE, movement_flags) . = ..() if(!.) return @@ -135,7 +135,7 @@ REMOVE_TRAIT(tongue_owner, TRAIT_AGEUSIA, NO_TONGUE_TRAIT) apply_tongue_effects() -/obj/item/organ/internal/tongue/Remove(mob/living/carbon/tongue_owner, special = FALSE) +/obj/item/organ/internal/tongue/Remove(mob/living/carbon/tongue_owner, special, movement_flags) . = ..() temp_say_mod = "" UnregisterSignal(tongue_owner, COMSIG_MOB_SAY) diff --git a/code/modules/surgery/organs/organ_movement.dm b/code/modules/surgery/organs/organ_movement.dm new file mode 100644 index 00000000000..98eeb969fac --- /dev/null +++ b/code/modules/surgery/organs/organ_movement.dm @@ -0,0 +1,230 @@ +// There are two kinds of organ movement: mob movement and limb movement +// If you pull someones brain out, you remove it from the mob and the limb +// If you take someones head off, you remove it from the mob but not the limb +// If you remove the brain from an already decapitated head, you remove it from the limb but not the mob + +// Keep the seperation of limb removal and mob removal absolute + +/* + * Insert the organ into the select mob. + * + * receiver - the mob who will get our organ + * special - "quick swapping" an organ out - when TRUE, the mob will be unaffected by not having that organ for the moment + * movement_flags - Flags for how we behave in movement. See DEFINES/organ_movement for flags + */ +/obj/item/organ/proc/Insert(mob/living/carbon/receiver, special = FALSE, movement_flags) + SHOULD_CALL_PARENT(TRUE) + + mob_insert(receiver, special, movement_flags) + bodypart_insert(limb_owner = receiver, movement_flags = movement_flags) + + return TRUE + +/* + * Remove the organ from the select mob. + * + * * organ_owner - the mob who owns our organ, that we're removing the organ from. Can be null + * * special - "quick swapping" an organ out - when TRUE, the mob will be unaffected by not having that organ for the moment + */ +/obj/item/organ/proc/Remove(mob/living/carbon/organ_owner, special = FALSE, movement_flags) + SHOULD_CALL_PARENT(TRUE) + + mob_remove(organ_owner, special, movement_flags) + bodypart_remove(null, organ_owner, movement_flags) + +/* + * Insert the organ into the select mob. + * + * receiver - the mob who will get our organ + * special - "quick swapping" an organ out - when TRUE, the mob will be unaffected by not having that organ for the moment + * movement_flags - Flags for how we behave in movement. See DEFINES/organ_movement for flags + */ +/obj/item/organ/proc/mob_insert(mob/living/carbon/receiver, special, movement_flags) + SHOULD_CALL_PARENT(TRUE) + + if(!iscarbon(receiver)) + stack_trace("Tried to insert organ into non-carbon: [receiver.type]") + return + + if(owner == receiver) + stack_trace("Organ receiver is already organ owner") + return + + var/obj/item/organ/replaced = receiver.get_organ_slot(slot) + if(replaced) + replaced.Remove(receiver, special = TRUE) + if(movement_flags & DELETE_IF_REPLACED) + qdel(replaced) + else + replaced.forceMove(get_turf(receiver)) + + if(!IS_ROBOTIC_ORGAN(src) && (organ_flags & ORGAN_VIRGIN)) + blood_dna_info = receiver.get_blood_dna_list() + // need to remove the synethic blood DNA that is initialized + // wash also adds the blood dna again + wash(CLEAN_TYPE_BLOOD) + organ_flags &= ~ORGAN_VIRGIN + + receiver.organs |= src + receiver.organs_slot[slot] = src + owner = receiver + + on_mob_insert(receiver, special) + + return TRUE + +/// Called after the organ is inserted into a mob. +/// Adds Traits, Actions, and Status Effects on the mob in which the organ is impanted. +/// Override this proc to create unique side-effects for inserting your organ. Must be called by overrides. +/obj/item/organ/proc/on_mob_insert(mob/living/carbon/organ_owner, special = FALSE, movement_flags) + SHOULD_CALL_PARENT(TRUE) + + for(var/trait in organ_traits) + ADD_TRAIT(organ_owner, trait, REF(src)) + + for(var/datum/action/action as anything in actions) + action.Grant(organ_owner) + + for(var/datum/status_effect/effect as anything in organ_effects) + organ_owner.apply_status_effect(effect, type) + + RegisterSignal(owner, COMSIG_ATOM_EXAMINE, PROC_REF(on_owner_examine)) + SEND_SIGNAL(src, COMSIG_ORGAN_IMPLANTED, organ_owner) + SEND_SIGNAL(organ_owner, COMSIG_CARBON_GAIN_ORGAN, src, special) + +/// Insert an organ into a limb, assume the limb as always detached and include no owner operations here (except the get_bodypart helper here I guess) +/// Give EITHER a limb OR a limb owner +/obj/item/organ/proc/bodypart_insert(obj/item/bodypart/bodypart, mob/living/carbon/limb_owner, movement_flags) + SHOULD_CALL_PARENT(TRUE) + + if(limb_owner) + bodypart = limb_owner.get_bodypart(deprecise_zone(zone)) + + // The true movement + forceMove(bodypart) + bodypart.contents |= src + bodypart_owner = bodypart + + RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(forced_removal)) + + // Apply unique side-effects. Return value does not matter. + on_bodypart_insert(bodypart) + + return TRUE + +/// Add any limb specific effects you might want here +/obj/item/organ/proc/on_bodypart_insert(obj/item/bodypart/limb, movement_flags) + SHOULD_CALL_PARENT(TRUE) + + item_flags |= ABSTRACT + ADD_TRAIT(src, TRAIT_NODROP, ORGAN_INSIDE_BODY_TRAIT) + +/* + * Remove the organ from the select mob. + * + * * organ_owner - the mob who owns our organ, that we're removing the organ from. Can be null + * * special - "quick swapping" an organ out - when TRUE, the mob will be unaffected by not having that organ for the moment + */ +/obj/item/organ/proc/mob_remove(mob/living/carbon/organ_owner, special = FALSE, movement_flags) + SHOULD_CALL_PARENT(TRUE) + + if(organ_owner) + if(organ_owner.organs_slot[slot] == src) + organ_owner.organs_slot.Remove(slot) + organ_owner.organs -= src + + owner = null + + on_mob_remove(organ_owner, special) + + return TRUE + +/// Called after the organ is removed from a mob. +/// Removes Traits, Actions, and Status Effects on the mob in which the organ was impanted. +/// Override this proc to create unique side-effects for removing your organ. Must be called by overrides. +/obj/item/organ/proc/on_mob_remove(mob/living/carbon/organ_owner, special = FALSE, movement_flags) + SHOULD_CALL_PARENT(TRUE) + + if(!iscarbon(organ_owner)) + stack_trace("Organ removal should not be happening on non carbon mobs: [organ_owner]") + + for(var/trait in organ_traits) + REMOVE_TRAIT(organ_owner, trait, REF(src)) + + for(var/datum/action/action as anything in actions) + action.Remove(organ_owner) + + for(var/datum/status_effect/effect as anything in organ_effects) + organ_owner.remove_status_effect(effect, type) + + UnregisterSignal(organ_owner, COMSIG_ATOM_EXAMINE) + SEND_SIGNAL(src, COMSIG_ORGAN_REMOVED, organ_owner) + SEND_SIGNAL(organ_owner, COMSIG_CARBON_LOSE_ORGAN, src, special) + + var/list/diseases = organ_owner.get_static_viruses() + if(!LAZYLEN(diseases)) + return + + var/list/datum/disease/diseases_to_add = list() + for(var/datum/disease/disease as anything in diseases) + // robotic organs are immune to disease unless 'inorganic biology' symptom is present + if(IS_ROBOTIC_ORGAN(src) && !(disease.infectable_biotypes & MOB_ROBOTIC)) + continue + + // admin or special viruses that should not be reproduced + if(disease.spread_flags & (DISEASE_SPREAD_SPECIAL | DISEASE_SPREAD_NON_CONTAGIOUS)) + continue + + diseases_to_add += disease + + if(LAZYLEN(diseases_to_add)) + AddComponent(/datum/component/infective, diseases_to_add) + +/// Called to remove an organ from a limb. Do not put any mob operations here (except the bodypart_getter at the start) +/// Give EITHER a limb OR a limb_owner +/obj/item/organ/proc/bodypart_remove(obj/item/bodypart/limb, mob/living/carbon/limb_owner, movement_flags) + SHOULD_CALL_PARENT(TRUE) + + if(limb_owner) + limb = limb_owner.get_bodypart(deprecise_zone(zone)) + + UnregisterSignal(src, COMSIG_MOVABLE_MOVED) //DONT MOVE THIS!!!! we moves the organ right after, so we unregister before we move them physically + + // The true movement is here + moveToNullspace() + bodypart_owner.contents -= src + bodypart_owner = null + + on_bodypart_remove(limb) + + return TRUE + +/// Called on limb removal to remove limb specific limb effects or statusses +/obj/item/organ/proc/on_bodypart_remove(obj/item/bodypart/limb, movement_flags) + SHOULD_CALL_PARENT(TRUE) + + if(!IS_ROBOTIC_ORGAN(src) && !(item_flags & NO_BLOOD_ON_ITEM) && !QDELING(src)) + AddElement(/datum/element/decal/blood) + + item_flags &= ~ABSTRACT + REMOVE_TRAIT(src, TRAIT_NODROP, ORGAN_INSIDE_BODY_TRAIT) + +/// In space station videogame, nothing is sacred. If somehow an organ is removed unexpectedly, handle it properly +/obj/item/organ/proc/forced_removal() + SIGNAL_HANDLER + + if(owner) + Remove(owner) + else if(bodypart_owner) + bodypart_remove(limb_owner = owner) + else + stack_trace("Force removed an already removed organ!") + +/** + * Proc that gets called when the organ is surgically removed by someone, can be used for special effects + * Currently only used so surplus organs can explode when surgically removed. + */ +/obj/item/organ/proc/on_surgical_removal(mob/living/user, mob/living/carbon/old_owner, target_zone, obj/item/tool) + SHOULD_CALL_PARENT(TRUE) + SEND_SIGNAL(src, COMSIG_ORGAN_SURGICALLY_REMOVED, user, old_owner, target_zone, tool) + RemoveElement(/datum/element/decal/blood) diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index 2bce0963b70..61bc9ec6d4e 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -195,6 +195,7 @@ #include "objectives.dm" #include "operating_table.dm" #include "orderable_items.dm" +#include "organ_bodypart_shuffle.dm" #include "organ_set_bonus.dm" #include "organs.dm" #include "outfit_sanity.dm" diff --git a/code/modules/unit_tests/heretic_rituals.dm b/code/modules/unit_tests/heretic_rituals.dm index 4ac5bce8d3d..b55136cface 100644 --- a/code/modules/unit_tests/heretic_rituals.dm +++ b/code/modules/unit_tests/heretic_rituals.dm @@ -66,7 +66,10 @@ if(islist(ritual_item_path)) ritual_item_path = pick(ritual_item_path) for(var/i in 1 to amount_to_create) - created_atoms += new ritual_item_path(get_turf(our_heretic)) + var/obj/item/item = new ritual_item_path(get_turf(our_heretic)) + if(isitem(item)) + item.item_flags &= ~ABSTRACT + created_atoms += item // Now, we can ACTUALLY run the ritual. Let's do it. // Attempt to run the knowledge via the sacrifice rune. @@ -106,6 +109,10 @@ for(var/atom/thing as anything in nearby_atoms) if(!ismovable(thing)) continue + if(isitem(thing)) + var/obj/item/item = thing + if(item.item_flags & ABSTRACT) //bodyparts and stuff will get registered otherwise + continue // There are atoms around the rune still, and there shouldn't be. // All component atoms were consumed, and all resulting atoms were cleaned up. diff --git a/code/modules/unit_tests/human_through_recycler.dm b/code/modules/unit_tests/human_through_recycler.dm index 7d554d72690..c51b9a0e30b 100644 --- a/code/modules/unit_tests/human_through_recycler.dm +++ b/code/modules/unit_tests/human_through_recycler.dm @@ -17,8 +17,13 @@ TEST_ASSERT_EQUAL(damage_incurred, chewer.crush_damage, "Assistant did not take the expected amount of brute damage ([chewer.crush_damage]) from the emagged recycler! Took ([damage_incurred]) instead.") TEST_ASSERT(chewer.bloody, "The emagged recycler did not become bloody after crushing the assistant!") + var/list/bad_contents = assistant.contents + for(var/obj/item/item in assistant.contents) + if(item.item_flags & ABSTRACT) + bad_contents -= item + // Now, let's test to see if all of their clothing got properly deleted. - TEST_ASSERT_EQUAL(length(assistant.contents), 0, "Assistant still has items in its contents after being put through an emagged recycler!") + TEST_ASSERT_EQUAL(length(bad_contents), 0, "Assistant still has items in its contents after being put through an emagged recycler!") // Consistent Assistants will always have the following: ID, PDA, backpack, a uniform, a headset, and a pair of shoes. If any of these are still present, then the recycler did not properly delete the assistant's clothing. // However, let's check for EVERYTHING just in case, because we don't want to miss anything. // This is just what we expect to be deleted. diff --git a/code/modules/unit_tests/ling_decap.dm b/code/modules/unit_tests/ling_decap.dm index 0c964f9a043..5d6f01caf9a 100644 --- a/code/modules/unit_tests/ling_decap.dm +++ b/code/modules/unit_tests/ling_decap.dm @@ -9,7 +9,7 @@ var/obj/item/bodypart/head/noggin = ling.get_bodypart(BODY_ZONE_HEAD) noggin.dismember() TEST_ASSERT_NULL(ling.get_bodypart(BODY_ZONE_HEAD), "Changeling failed to be decapitated.") - TEST_ASSERT_NULL(noggin.brainmob.mind, "Changeling's mind was moved to their head after decapitation, but it should have remained in their body.") + TEST_ASSERT_NULL(noggin.brain.brainmob.mind, "Changeling's mind was moved to their brain after decapitation, but it should have remained in their body.") var/obj/item/organ/internal/brain/oldbrain = noggin.brain noggin.drop_organs() @@ -33,7 +33,7 @@ var/obj/item/bodypart/head/noggin = normal_guy.get_bodypart(BODY_ZONE_HEAD) noggin.dismember() - TEST_ASSERT_EQUAL(noggin.brainmob.mind, my_guys_mind, "Dummy's mind was not moved to their head after decapitation.") + TEST_ASSERT_EQUAL(noggin.brain.brainmob.mind, my_guys_mind, "Dummy's mind was not moved to their brain after decapitation.") var/obj/item/organ/internal/brain/oldbrain = noggin.brain noggin.drop_organs() diff --git a/code/modules/unit_tests/organ_bodypart_shuffle.dm b/code/modules/unit_tests/organ_bodypart_shuffle.dm new file mode 100644 index 00000000000..842dd1c6c13 --- /dev/null +++ b/code/modules/unit_tests/organ_bodypart_shuffle.dm @@ -0,0 +1,34 @@ +/// Moves organs in and out of bodyparts, and moves the bodyparts around to see if someone didn't fuck up their movement +/datum/unit_test/organ_bodypart_shuffle + +/datum/unit_test/organ_bodypart_shuffle/Run() + var/mob/living/carbon/human/hollow_boy = allocate(/mob/living/carbon/human/consistent) + + // Test if organs are all properly updating when forcefully removed + var/list/removed_organs = list() + + for(var/obj/item/organ/organ as anything in hollow_boy.organs) + organ.moveToNullspace() + removed_organs += organ + + for(var/obj/item/organ/organ as anything in removed_organs) + TEST_ASSERT(!(organ in hollow_boy.organs), "Organ '[organ.name] remained inside human after forceMove into nullspace.") + TEST_ASSERT(organ.loc == null, "Organ '[organ.name] did not move to nullspace after being forced to.") + TEST_ASSERT(!(organ.owner), "Organ '[organ.name] kept reference to human after forceMove into nullspace.") + TEST_ASSERT(!(organ.bodypart_owner), "Organ '[organ.name] kept reference to bodypart after forceMove into nullspace.") + + for(var/obj/item/bodypart/bodypart as anything in hollow_boy.bodyparts) + bodypart = new bodypart.type() //fresh, duplice bodypart with no insides + for(var/obj/item/organ/organ as anything in removed_organs) + if(bodypart.body_zone != deprecise_zone(organ.zone)) + continue + organ.bodypart_insert(bodypart) // Put all the old organs back in + bodypart.replace_limb(hollow_boy) //so stick new bodyparts on them with their old organs + // Check if, after we put the old organs in a new limb, and after we put that new limb on the mob, if the organs came with + for(var/obj/item/organ/organ as anything in removed_organs) //technically readded organ now + if(bodypart.body_zone != deprecise_zone(organ.zone)) + continue + TEST_ASSERT(organ in hollow_boy.organs, "Organ '[organ.name] was put in an empty bodypart that replaced a humans, but the organ did not come with.") + + // Test if bodyparts are all properly updating when forcefully removed + hollow_boy = allocate(/mob/living/carbon/human/consistent) //freshly filled with wet insides diff --git a/code/modules/unit_tests/organ_set_bonus.dm b/code/modules/unit_tests/organ_set_bonus.dm index 250433028c1..a9e9a8805f9 100644 --- a/code/modules/unit_tests/organ_set_bonus.dm +++ b/code/modules/unit_tests/organ_set_bonus.dm @@ -30,7 +30,7 @@ // Attempt to insert entire list of mutant organs for the given infusion_entry. for(var/obj/item/organ/organ as anything in output_organs) organ = new organ() - TEST_ASSERT(organ.Insert(lab_rat, special = TRUE, drop_if_replaced = FALSE), "The organ `[organ.type]` for `[infuser_entry.type]` was not inserted in the mob when expected, Insert() returned falsy when TRUE was expected.") + TEST_ASSERT(organ.Insert(lab_rat, special = TRUE, movement_flags = DELETE_IF_REPLACED), "The organ `[organ.type]` for `[infuser_entry.type]` was not inserted in the mob when expected, Insert() returned falsy when TRUE was expected.") inserted_organs += organ // Search for added Status Effect. diff --git a/code/modules/unit_tests/organs.dm b/code/modules/unit_tests/organs.dm index 4ba51e0870c..1da3808ba39 100644 --- a/code/modules/unit_tests/organs.dm +++ b/code/modules/unit_tests/organs.dm @@ -25,14 +25,10 @@ )) /datum/unit_test/organ_sanity/Run() - for(var/obj/item/organ/organ_type as anything in subtypesof(/obj/item/organ)) + for(var/obj/item/organ/organ_type as anything in subtypesof(/obj/item/organ) - test_organ_blacklist) organ_test_insert(organ_type) /datum/unit_test/organ_sanity/proc/organ_test_insert(obj/item/organ/organ_type) - // Skip prototypes. - if(test_organ_blacklist[organ_type]) - return - // Appropriate mob (Human) which will receive organ. var/mob/living/carbon/human/lab_rat = allocate(/mob/living/carbon/human/consistent) var/obj/item/organ/test_organ = new organ_type() @@ -41,8 +37,8 @@ var/mob/living/basic/pet/dog/lab_dog = allocate(/mob/living/basic/pet/dog/corgi) var/obj/item/organ/reject_organ = new organ_type() - TEST_ASSERT(test_organ.Insert(lab_rat, special = TRUE, drop_if_replaced = FALSE), TEST_ORGAN_INSERT_MESSAGE(test_organ, "should return TRUE to indicate success.")) - TEST_ASSERT(!reject_organ.Insert(lab_dog, special = TRUE, drop_if_replaced = FALSE), TEST_ORGAN_INSERT_MESSAGE(test_organ, "shouldn't return TRUE when inserting into a basic mob (Corgi).")) + TEST_ASSERT(test_organ.Insert(lab_rat, special = TRUE, movement_flags = DELETE_IF_REPLACED), TEST_ORGAN_INSERT_MESSAGE(test_organ, "should return TRUE to indicate success.")) + TEST_ASSERT(!reject_organ.Insert(lab_dog, special = TRUE, movement_flags = DELETE_IF_REPLACED), TEST_ORGAN_INSERT_MESSAGE(test_organ, "shouldn't return TRUE when inserting into a basic mob (Corgi).")) // Species change swaps out all the organs, making test_organ un-usable by this point. if(species_changing_organs[test_organ.type]) diff --git a/code/modules/unit_tests/species_change_organs.dm b/code/modules/unit_tests/species_change_organs.dm index e0555aa89bc..41d55047f03 100644 --- a/code/modules/unit_tests/species_change_organs.dm +++ b/code/modules/unit_tests/species_change_organs.dm @@ -12,7 +12,7 @@ dummy.gain_trauma(/datum/brain_trauma/severe/blindness) // Give a cyber heart var/obj/item/organ/internal/heart/cybernetic/cyber_heart = allocate(/obj/item/organ/internal/heart/cybernetic) - cyber_heart.Insert(dummy, special = TRUE, drop_if_replaced = FALSE) + cyber_heart.Insert(dummy, special = TRUE, movement_flags = DELETE_IF_REPLACED) // Give one of their organs a bit of damage var/obj/item/organ/internal/appendix/existing_appendix = dummy.get_organ_slot(ORGAN_SLOT_APPENDIX) existing_appendix.set_organ_damage(25) diff --git a/code/modules/unit_tests/tail_wag.dm b/code/modules/unit_tests/tail_wag.dm index 0d828557953..ceb82e98c0d 100644 --- a/code/modules/unit_tests/tail_wag.dm +++ b/code/modules/unit_tests/tail_wag.dm @@ -6,7 +6,7 @@ /datum/unit_test/tail_wag/Run() var/mob/living/carbon/human/dummy = allocate(/mob/living/carbon/human/consistent) var/obj/item/organ/external/tail/cat/dummy_tail = allocate(/obj/item/organ/external/tail/cat) - dummy_tail.Insert(dummy, special = TRUE, drop_if_replaced = FALSE) + dummy_tail.Insert(dummy, special = TRUE, movement_flags = DELETE_IF_REPLACED) // SANITY TEST @@ -74,7 +74,7 @@ // TESTING MOB DEATH // put it back and start wagging again - dummy_tail.Insert(dummy, special = TRUE, drop_if_replaced = FALSE) + dummy_tail.Insert(dummy, special = TRUE, movement_flags = DELETE_IF_REPLACED) SEND_SIGNAL(dummy, COMSIG_ORGAN_WAG_TAIL, TRUE) if(!(dummy_tail.wag_flags & WAG_WAGGING)) TEST_FAIL("Tail did not start wagging when it should have!") diff --git a/code/modules/wiremod/shell/brain_computer_interface.dm b/code/modules/wiremod/shell/brain_computer_interface.dm index c3ac3154d2d..1d71bfa0c25 100644 --- a/code/modules/wiremod/shell/brain_computer_interface.dm +++ b/code/modules/wiremod/shell/brain_computer_interface.dm @@ -17,11 +17,6 @@ new /obj/item/circuit_component/bci_core, ), SHELL_CAPACITY_SMALL, starting_circuit = circuit) -/obj/item/organ/internal/cyberimp/bci/on_insert(mob/living/carbon/receiver) - . = ..() - // Organs are put in nullspace, but this breaks circuit interactions - forceMove(receiver) - /obj/item/organ/internal/cyberimp/bci/say(message, bubble_type, list/spans, sanitize, datum/language/language, ignore_spam, forced = null, filterproof = null, message_range = 7, datum/saymode/saymode = null) if (owner) // Otherwise say_dead will be called. diff --git a/code/modules/zombie/organs.dm b/code/modules/zombie/organs.dm index 94ace7e6c7f..73149fc8d76 100644 --- a/code/modules/zombie/organs.dm +++ b/code/modules/zombie/organs.dm @@ -23,25 +23,25 @@ GLOB.zombie_infection_list -= src . = ..() -/obj/item/organ/internal/zombie_infection/Insert(mob/living/carbon/M, special = FALSE, drop_if_replaced = TRUE) +/obj/item/organ/internal/zombie_infection/on_mob_insert(mob/living/carbon/M, special = FALSE, movement_flags) . = ..() if(!.) return . START_PROCESSING(SSobj, src) -/obj/item/organ/internal/zombie_infection/Remove(mob/living/carbon/M, special = FALSE) +/obj/item/organ/internal/zombie_infection/on_mob_remove(mob/living/carbon/M, special = FALSE) . = ..() STOP_PROCESSING(SSobj, src) - if(iszombie(M) && old_species && !special && !QDELETED(src)) + if(iszombie(M) && old_species && !special) M.set_species(old_species) if(timer_id) deltimer(timer_id) -/obj/item/organ/internal/zombie_infection/on_insert(mob/living/carbon/organ_owner, special) +/obj/item/organ/internal/zombie_infection/on_mob_insert(mob/living/carbon/organ_owner, special) . = ..() RegisterSignal(organ_owner, COMSIG_LIVING_DEATH, PROC_REF(organ_owner_died)) -/obj/item/organ/internal/zombie_infection/on_remove(mob/living/carbon/organ_owner, special) +/obj/item/organ/internal/zombie_infection/on_mob_remove(mob/living/carbon/organ_owner, special) . = ..() UnregisterSignal(organ_owner, COMSIG_LIVING_DEATH) diff --git a/tgstation.dme b/tgstation.dme index a40e405951a..c4a89286782 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -159,6 +159,7 @@ #include "code\__DEFINES\nuclear_bomb.dm" #include "code\__DEFINES\obj_flags.dm" #include "code\__DEFINES\observers.dm" +#include "code\__DEFINES\organ_movement.dm" #include "code\__DEFINES\overlays.dm" #include "code\__DEFINES\pai.dm" #include "code\__DEFINES\paintings.dm" @@ -5670,6 +5671,7 @@ #include "code\modules\surgery\organs\_organ.dm" #include "code\modules\surgery\organs\autosurgeon.dm" #include "code\modules\surgery\organs\helpers.dm" +#include "code\modules\surgery\organs\organ_movement.dm" #include "code\modules\surgery\organs\external\_external_organ.dm" #include "code\modules\surgery\organs\external\restyling.dm" #include "code\modules\surgery\organs\external\spines.dm"