Organ movement refactor *Un-nullspaces your organs* (#79687)

<!-- Write **BELOW** The Headers and **ABOVE** The comments else it may
not be viewable. -->
<!-- You can view Contributing.MD for a detailed description of the pull
request process. -->

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

<!-- Argue for the merits of your changes and how they benefit the game,
especially if they are controversial and/or far reaching. If you can't
actually explain WHY what you are doing will improve the game, then it
probably isn't good for the game in the first place. -->

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

<!-- If your PR modifies aspects of the game that can be concretely
observed by players or admins you should add a changelog. If your change
does NOT meet this description, remove this section. Be sure to properly
mark your PRs to prevent unnecessary GBP loss. You can read up on GBP
and it's effects on PRs in the tgstation guides for contributors. Please
note that maintainers freely reserve the right to remove and add tags
should they deem it appropriate. You can attempt to finagle the system
all you want, but it's best to shoot for clear communication right off
the bat. -->

🆑
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
/🆑

<!-- Both 🆑's are required for the changelog to work! You can put
your name to the right of the first 🆑 if you want to overwrite your
GitHub username as author ingame. -->
<!-- You can use multiple of the same prefix (they're only used for the
icon ingame) and delete the unneeded ones. Despite some of the tags,
changelogs should generally represent how a player might be affected by
the changes rather than a summary of the PR's contents. -->
This commit is contained in:
Time-Green
2023-12-09 17:50:46 +00:00
committed by GitHub
parent 6b30843774
commit 54ab1e3936
96 changed files with 893 additions and 798 deletions
+4
View File
@@ -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)
+2
View File
@@ -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"
-5
View File
@@ -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
@@ -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)
@@ -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
@@ -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)
+1 -1
View File
@@ -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")
-1
View File
@@ -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
+3 -1
View File
@@ -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))
+1 -1
View File
@@ -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)
. = ..()
@@ -49,7 +49,7 @@
medical_record_text = "During physical examination, patient was found to have a low-budget prosthetic [slot_string]. \
<b>Removal of these organs is known to be dangerous to the patient as well as the practitioner.</b>"
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)
@@ -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. \
@@ -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"
+1 -1
View File
@@ -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)
@@ -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)
@@ -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
@@ -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))
@@ -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))
@@ -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)
@@ -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!
+4
View File
@@ -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
+2 -2
View File
@@ -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()
+1 -1
View File
@@ -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!"), \
+4
View File
@@ -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()
+2 -2
View File
@@ -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]
@@ -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
@@ -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)
@@ -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)
@@ -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"
@@ -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
@@ -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)
@@ -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)
@@ -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)
@@ -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."
@@ -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()
@@ -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)
@@ -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
@@ -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
@@ -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)
+1 -1
View File
@@ -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
+21 -27
View File
@@ -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)
@@ -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 ..()
+19 -4
View File
@@ -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 ..()
+3 -3
View File
@@ -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)
@@ -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)
@@ -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"
@@ -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."))
@@ -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)
@@ -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)
+1 -1
View File
@@ -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
@@ -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()
+4 -4
View File
@@ -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
@@ -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
+118 -97
View File
@@ -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
+41 -69
View File
@@ -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
+11 -44
View File
@@ -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 ..()
+2 -1
View File
@@ -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
+106 -89
View File
@@ -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
@@ -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'
+13 -138
View File
@@ -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)
+23 -63
View File
@@ -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)
+1 -1
View File
@@ -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)
+2 -2
View File
@@ -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
+7 -10
View File
@@ -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
@@ -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)
+2 -2
View File
@@ -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))
@@ -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.
@@ -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)
@@ -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 ..()
@@ -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)
. = ..()
@@ -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)
..()
@@ -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]
@@ -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))
@@ -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)
@@ -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)
@@ -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
@@ -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)
@@ -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))
@@ -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
@@ -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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
+1
View File
@@ -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"
+8 -1
View File
@@ -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.
@@ -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.
+2 -2
View File
@@ -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()
@@ -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
+1 -1
View File
@@ -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.
+3 -7
View File
@@ -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])
@@ -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)
+2 -2
View File
@@ -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!")
@@ -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.
+5 -5
View File
@@ -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)
+2
View File
@@ -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"