diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_carbon.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_carbon.dm index 76cdcd04b38a0..ad2b38da0ddd2 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_carbon.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_carbon.dm @@ -25,6 +25,7 @@ ///from base of /obj/item/bodypart/proc/try_attach_limb(): (new_limb, special) #define COMSIG_CARBON_ATTACH_LIMB "carbon_attach_limb" + #define COMPONENT_NO_ATTACH (1<<0) /// Called from bodypart being attached /obj/item/bodypart/proc/try_attach_limb(mob/living/carbon/new_owner, special) #define COMSIG_BODYPART_ATTACHED "bodypart_attached" ///from base of /obj/item/bodypart/proc/try_attach_limb(): (new_limb, special) diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_living.dm index 66dd862db99d7..0f6068756a8e6 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_living.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_living.dm @@ -13,6 +13,8 @@ #define COMSIG_LIVING_ELECTROCUTE_ACT "living_electrocute_act" ///from base of mob/living/revive() (full_heal, admin_revive) #define COMSIG_LIVING_REVIVE "living_revive" +///from base of /mob/living/regenerate_limbs(): (noheal, excluded_limbs) +#define COMSIG_LIVING_REGENERATE_LIMBS "living_regen_limbs" ///from base of mob/living/set_buckled(): (new_buckled) #define COMSIG_LIVING_SET_BUCKLED "living_set_buckled" #define COMSIG_LIVING_MINOR_SHOCK "living_minor_shock" //! sent by stuff like stunbatons and tasers: () diff --git a/code/datums/diseases/advance/symptoms/clockwork.dm b/code/datums/diseases/advance/symptoms/clockwork.dm index 9c84bd2161db6..31be490fe2e1a 100644 --- a/code/datums/diseases/advance/symptoms/clockwork.dm +++ b/code/datums/diseases/advance/symptoms/clockwork.dm @@ -348,7 +348,7 @@ H.update_body() return if(istype(H)) - if(!("tail_human" in H.dna.species.mutant_bodyparts)) + if(!(H.dna.species.mutant_bodyparts["tail_human"])) H.dna.features["tail_human"] = tail_type H.dna.species.mutant_bodyparts |= "tail_human" H.update_body() diff --git a/code/datums/diseases/advance/symptoms/organs.dm b/code/datums/diseases/advance/symptoms/organs.dm index 85f64b361ab4c..266b01f75ece0 100644 --- a/code/datums/diseases/advance/symptoms/organs.dm +++ b/code/datums/diseases/advance/symptoms/organs.dm @@ -202,15 +202,6 @@ O.Insert(M, drop_if_replaced = FALSE) M.adjustOrganLoss(ORGAN_SLOT_LIVER, 200) return - if(!M.getorgan(/obj/item/organ/tail)) - if(S.mutanttail) - var/obj/item/organ/tail/O = new S.mutanttail() - O.Insert(M, drop_if_replaced = FALSE) - M.adjustOrganLoss(ORGAN_SLOT_TAIL, 200) - M.visible_message("[M] sprouts a new tail!", "You sprout a new tail!.") - playsound(M, 'sound/magic/demon_consume.ogg', 50, 1) - M.add_splatter_floor(get_turf(M)) - return if(!M.getorgan(/obj/item/organ/wings)) if(S.mutantwings) var/obj/item/organ/wings/O = new S.mutantwings() diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 912ae6c2c49a7..fe483c15e7822 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -410,29 +410,18 @@ GENE SCANNER if(ishuman(M)) var/mob/living/carbon/human/H = M var/datum/species/S = H.dna.species - var/mutant = FALSE - if(H.dna.check_mutation(HULK)) - mutant = TRUE - else if(S.mutantlungs != initial(S.mutantlungs)) - mutant = TRUE - else if(S.mutant_brain != initial(S.mutant_brain)) - mutant = TRUE - else if(S.mutant_heart != initial(S.mutant_heart)) - mutant = TRUE - else if(S.mutanteyes != initial(S.mutanteyes)) - mutant = TRUE - else if(S.mutantears != initial(S.mutantears)) - mutant = TRUE - else if(S.mutanthands != initial(S.mutanthands)) - mutant = TRUE - else if(S.mutanttongue != initial(S.mutanttongue)) - mutant = TRUE - else if(S.mutanttail != initial(S.mutanttail)) - mutant = TRUE - else if(S.mutantliver != initial(S.mutantliver)) - mutant = TRUE - else if(S.mutantstomach != initial(S.mutantstomach)) - mutant = TRUE + var/mutant = H.dna.check_mutation(HULK) \ + || S.mutantlungs != initial(S.mutantlungs) \ + || S.mutantbrain != initial(S.mutantbrain) \ + || S.mutantheart != initial(S.mutantheart) \ + || S.mutanteyes != initial(S.mutanteyes) \ + || S.mutantears != initial(S.mutantears) \ + || S.mutanthands != initial(S.mutanthands) \ + || S.mutanttongue != initial(S.mutanttongue) \ + || S.mutantliver != initial(S.mutantliver) \ + || S.mutantstomach != initial(S.mutantstomach) \ + || S.mutantappendix != initial(S.mutantappendix) \ + || S.mutantwings != initial(S.mutantwings) message += "Species: [S.name][mutant ? "-derived mutant" : ""]" message += "Core temperature: [round(H.coretemperature-T0C,0.1)] °C ([round(H.coretemperature*1.8-459.67,0.1)] °F)" diff --git a/code/modules/antagonists/changeling/powers/regenerate.dm b/code/modules/antagonists/changeling/powers/regenerate.dm index 7987a3761650d..130ced301e540 100644 --- a/code/modules/antagonists/changeling/powers/regenerate.dm +++ b/code/modules/antagonists/changeling/powers/regenerate.dm @@ -26,8 +26,8 @@ C.regenerate_limbs(1) if(!user.getorganslot(ORGAN_SLOT_BRAIN)) var/obj/item/organ/brain/B - if(C.has_dna() && C.dna.species.mutant_brain) - B = new C.dna.species.mutant_brain() + if(C.has_dna() && C.dna.species.mutantbrain) + B = new C.dna.species.mutantbrain() else B = new() B.organ_flags &= ~ORGAN_VITAL diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index 1fe9ae2567ded..9ee26290729d5 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -188,7 +188,7 @@ /datum/emote/living/carbon/human/wing/select_message_type(mob/user, intentional) . = ..() var/mob/living/carbon/human/H = user - if(("wings" in H.dna.species.mutant_bodyparts) || ("moth_wings" in H.dna.species.mutant_bodyparts)) + if((H.dna.species.mutant_bodyparts["wings"]) || (H.dna.species.mutant_bodyparts["moth_wings"])) . = "opens " + message else . = "closes " + message diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index a5cc1ea7cea13..6fb41d94c8178 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -33,10 +33,20 @@ GLOBAL_LIST_EMPTY(features_by_species) var/list/no_equip = list() // slots the race can't equip stuff to var/nojumpsuit = 0 // this is sorta... weird. it basically lets you equip stuff that usually needs jumpsuits without one, like belts and pockets and ids var/species_language_holder = /datum/language_holder - var/list/default_features = list("body_size" = "Normal") // Default mutant bodyparts for this species. Don't forget to set one for every mutant bodypart you allow this species to have. - var/list/forced_features = list() // A list of features forced on characters - var/list/mutant_bodyparts = list() // Visible CURRENT bodyparts that are unique to a species. DO NOT USE THIS AS A LIST OF ALL POSSIBLE BODYPARTS AS IT WILL FUCK SHIT UP! Changes to this list for non-species specific bodyparts (ie cat ears and tails) should be assigned at organ level if possible. Layer hiding is handled by handle_mutant_bodyparts() below. + /** + * Visible CURRENT bodyparts that are unique to a species. + * DO NOT USE THIS AS A LIST OF ALL POSSIBLE BODYPARTS AS IT WILL FUCK + * SHIT UP! Changes to this list for non-species specific bodyparts (ie + * cat ears and tails) should be assigned at organ level if possible. + * Assoc values are defaults for given bodyparts, also modified by aforementioned organs. + * They also allow for faster '[]' list access versus 'in'. Other than that, they are useless right now. + * Layer hiding is handled by [/datum/species/proc/handle_mutant_bodyparts] below. + */ + var/list/mutant_bodyparts = list() var/list/mutant_organs = list() //Internal organs that are unique to this race. + + var/list/forced_features = list() // A list of features forced on characters + var/speedmod = 0 // this affects the race's speed. positive numbers make it move slower, negative numbers make it move faster var/armor = 0 // overall defense for the race... or less defense, if it's negative. var/brutemod = 1 // multiplier for brute damage @@ -85,22 +95,36 @@ GLOBAL_LIST_EMPTY(features_by_species) var/sound/attack_sound = 'sound/weapons/punch1.ogg' var/sound/miss_sound = 'sound/weapons/punchmiss.ogg' - //Breathing! - var/obj/item/organ/lungs/mutantlungs = null + //Breathing! Most changes are in mutantlungs, though var/breathid = "o2" var/list/required_organs = list() - var/obj/item/organ/brain/mutant_brain = /obj/item/organ/brain - var/obj/item/organ/heart/mutant_heart = /obj/item/organ/heart + + //Do NOT remove by setting to null. use OR make a RESPECTIVE TRAIT (removing stomach? add the NOSTOMACH trait to your species) + //why does it work this way? because traits also disable the downsides of not having an organ, removing organs but not having the trait will make your species die + + ///Replaces default brain with a different organ + var/obj/item/organ/brain/mutantbrain = /obj/item/organ/brain + ///Replaces default heart with a different organ + var/obj/item/organ/heart/mutantheart = /obj/item/organ/heart + ///Replaces default lungs with a different organ + var/obj/item/organ/lungs/mutantlungs = /obj/item/organ/lungs + ///Replaces default eyes with a different organ var/obj/item/organ/eyes/mutanteyes = /obj/item/organ/eyes + ///Replaces default ears with a different organ var/obj/item/organ/ears/mutantears = /obj/item/organ/ears - var/obj/item/mutanthands + ///Replaces default tongue with a different organ var/obj/item/organ/tongue/mutanttongue = /obj/item/organ/tongue - var/obj/item/organ/tail/mutanttail = null + ///Replaces default liver with a different organ + var/obj/item/organ/liver/mutantliver = /obj/item/organ/liver + ///Replaces default stomach with a different organ + var/obj/item/organ/stomach/mutantstomach = /obj/item/organ/stomach + ///Replaces default appendix with a different organ. + var/obj/item/organ/appendix/mutantappendix = /obj/item/organ/appendix + ///Replaces default wings with a different organ. (There should be no default wings, only those on moths & apids, thus null) var/obj/item/organ/wings/mutantwings = null - - var/obj/item/organ/liver/mutantliver - var/obj/item/organ/stomach/mutantstomach + //only an honorary mutantthing because not an organ and not loaded in the same way, you've been warned to do your research + var/obj/item/mutanthands //Bitflag that controls what in game ways can select this species as a spawnable source //Think magic mirror and pride mirror, slime extract, ERT etc, see defines @@ -230,164 +254,102 @@ GLOBAL_LIST_EMPTY(features_by_species) return 0 return 1 -//Will regenerate missing organs -/datum/species/proc/regenerate_organs(mob/living/carbon/C,datum/species/old_species,replace_current=TRUE) - var/obj/item/organ/brain/brain = C.getorganslot(ORGAN_SLOT_BRAIN) - var/obj/item/organ/heart/heart = C.getorganslot(ORGAN_SLOT_HEART) - var/obj/item/organ/lungs/lungs = C.getorganslot(ORGAN_SLOT_LUNGS) - var/obj/item/organ/appendix/appendix = C.getorganslot(ORGAN_SLOT_APPENDIX) - var/obj/item/organ/eyes/eyes = C.getorganslot(ORGAN_SLOT_EYES) - var/obj/item/organ/ears/ears = C.getorganslot(ORGAN_SLOT_EARS) - var/obj/item/organ/tongue/tongue = C.getorganslot(ORGAN_SLOT_TONGUE) - var/obj/item/organ/liver/liver = C.getorganslot(ORGAN_SLOT_LIVER) - var/obj/item/organ/stomach/stomach = C.getorganslot(ORGAN_SLOT_STOMACH) - var/obj/item/organ/tail/tail = C.getorganslot(ORGAN_SLOT_TAIL) - var/obj/item/organ/wings/wings = C.getorganslot(ORGAN_SLOT_WINGS) - - var/should_have_brain = TRUE - var/should_have_heart = !(NOBLOOD in species_traits) - var/should_have_lungs = !(TRAIT_NOBREATH in inherent_traits) - var/should_have_appendix = !((TRAIT_NOHUNGER in inherent_traits) || (TRAIT_POWERHUNGRY in inherent_traits)) - var/should_have_eyes = TRUE - var/should_have_ears = TRUE - var/should_have_tongue = TRUE - var/should_have_liver = !(TRAIT_NOMETABOLISM in inherent_traits) - var/should_have_stomach = !(NOSTOMACH in species_traits) - var/should_have_tail = mutanttail - var/should_have_wings = mutantwings - - if(heart && (!should_have_heart || replace_current)) - heart.Remove(C,1) - required_organs -= /obj/item/organ/heart - QDEL_NULL(heart) - if(should_have_heart && !heart) - heart = new mutant_heart() - heart.Insert(C) - required_organs |= /obj/item/organ/heart - - if(lungs && (!should_have_lungs || replace_current)) - lungs.Remove(C,1) - required_organs -= /obj/item/organ/lungs - QDEL_NULL(lungs) - if(should_have_lungs && !lungs) - if(mutantlungs) - lungs = new mutantlungs() - else - lungs = new() - lungs.Insert(C) - required_organs |= /obj/item/organ/lungs - - if(liver && (!should_have_liver || replace_current)) - liver.Remove(C,1) - required_organs -= /obj/item/organ/liver - QDEL_NULL(liver) - if(should_have_liver && !liver) - if(mutantliver) - liver = new mutantliver() - else - liver = new() - liver.Insert(C) - required_organs |= /obj/item/organ/liver - - if(stomach && (!should_have_stomach || replace_current)) - stomach.Remove(C,1) - required_organs -= /obj/item/organ/stomach - QDEL_NULL(stomach) - if(should_have_stomach && !stomach) - if(mutantstomach) - stomach = new mutantstomach() - else - stomach = new() - stomach.Insert(C) - required_organs |= /obj/item/organ/stomach - - if(appendix && (!should_have_appendix || replace_current)) - appendix.Remove(C,1) - required_organs -= /obj/item/organ/appendix - QDEL_NULL(appendix) - if(should_have_appendix && !appendix) - appendix = new() - appendix.Insert(C) - required_organs |= /obj/item/organ/appendix - - if(tail && (!should_have_tail || replace_current)) - tail.Remove(C,1) - required_organs -= /obj/item/organ/tail - QDEL_NULL(tail) - if(should_have_tail && !tail) - tail = new mutanttail() - if(islizard(C)) - var/obj/item/organ/tail/lizard/lizard_tail = tail - lizard_tail.tail_type = C.dna.features["tail_lizard"] - lizard_tail.spines = C.dna.features["spines"] - tail = lizard_tail - tail.Insert(C) - required_organs |= /obj/item/organ/tail - - if(wings && (!should_have_wings || replace_current)) - wings.Remove(C,1) - required_organs -= /obj/item/organ/wings - QDEL_NULL(wings) - if(should_have_wings && !wings) - wings = new mutantwings() - if(ismoth(C)) - wings.wing_type = C.dna.features["moth_wings"] - wings.flight_level = WINGS_FLIGHTLESS - if(locate(/datum/mutation/strongwings) in C.dna.mutations) - wings.flight_level = WINGS_FLYING - wings.Insert(C) - required_organs |= /obj/item/organ/wings - - if(C.get_bodypart(BODY_ZONE_HEAD)) - if(brain && (replace_current || !should_have_brain)) - if(!brain.decoy_override)//Just keep it if it's fake - brain.Remove(C,TRUE,TRUE) - required_organs -= /obj/item/organ/brain - QDEL_NULL(brain) - if(should_have_brain && !brain) - brain = new mutant_brain() - brain.Insert(C, TRUE, TRUE) - required_organs |= /obj/item/organ/brain - - if(eyes && (replace_current || !should_have_eyes)) - eyes.Remove(C,1) - required_organs -= /obj/item/organ/eyes - QDEL_NULL(eyes) - if(should_have_eyes && !eyes) - eyes = new mutanteyes - eyes.Insert(C) - required_organs |= /obj/item/organ/eyes - - if(ears && (replace_current || !should_have_ears)) - ears.Remove(C,1) - required_organs -= /obj/item/organ/ears - QDEL_NULL(ears) - if(should_have_ears && !ears) - ears = new mutantears - ears.Insert(C) - required_organs |= /obj/item/organ/ears - - if(tongue && (replace_current || !should_have_tongue)) - tongue.Remove(C,1) - required_organs -= /obj/item/organ/tongue - QDEL_NULL(tongue) - if(should_have_tongue && !tongue) - tongue = new mutanttongue - tongue.Insert(C) - required_organs |= /obj/item/organ/tongue + +/** regenerate_organs + * Corrects organs in a carbon, removing ones it doesn't need and adding ones it does + * + * takes all organ slots, removes organs a species should not have, adds organs a species should have. + * can use replace_current to refresh all organs, creating an entirely new set. + * Arguments: + * C - carbon, the owner of the species datum AKA whoever we're regenerating organs in + * old_species - datum, used when regenerate organs is called in a switching species to remove old mutant organs. + * replace_current - boolean, forces all old organs to get deleted whether or not they pass the species' ability to keep that organ + * excluded_zones - list, add zone defines to block organs inside of the zones from getting handled. see headless mutation for an example + */ +/datum/species/proc/regenerate_organs(mob/living/carbon/C,datum/species/old_species,replace_current=TRUE,list/excluded_zones) + //what should be put in if there is no mutantorgan (brains handled seperately) + var/list/slot_mutantorgans = list( + ORGAN_SLOT_BRAIN = mutantbrain, + ORGAN_SLOT_HEART = mutantheart, + ORGAN_SLOT_LUNGS = mutantlungs, + ORGAN_SLOT_APPENDIX = mutantappendix, + ORGAN_SLOT_EYES = mutanteyes, + ORGAN_SLOT_EARS = mutantears, + ORGAN_SLOT_TONGUE = mutanttongue, + ORGAN_SLOT_LIVER = mutantliver, + ORGAN_SLOT_STOMACH = mutantstomach, + ORGAN_SLOT_WINGS = mutantwings + ) + + var/list/slot_organs = list( + ORGAN_SLOT_BRAIN, + ORGAN_SLOT_HEART, + ORGAN_SLOT_LUNGS, + ORGAN_SLOT_APPENDIX, + ORGAN_SLOT_EYES, + ORGAN_SLOT_EARS, + ORGAN_SLOT_TONGUE, + ORGAN_SLOT_LIVER, + ORGAN_SLOT_STOMACH, + ORGAN_SLOT_WINGS + ) + + //if theres no added wing type, we want to avoid adding a null + if(isnull(mutantwings)) + slot_organs -= ORGAN_SLOT_WINGS + + for(var/slot in slot_organs) + + var/obj/item/organ/oldorgan = C.getorganslot(slot) //used in removing + var/obj/item/organ/neworgan = slot_mutantorgans[slot] //used in adding + var/used_neworgan = FALSE + neworgan = new neworgan() + var/should_have = neworgan.get_availability(src) //organ proc that points back to a species trait (so if the species is supposed to have this organ) + + if(oldorgan && (!should_have || replace_current) && !(oldorgan.zone in excluded_zones)) + if(slot == ORGAN_SLOT_BRAIN) + var/obj/item/organ/brain/brain = oldorgan + if(!brain.decoy_override)//"Just keep it if it's fake" - confucius, probably + brain.Remove(C,TRUE, TRUE) //brain argument used so it doesn't cause any... sudden death. + QDEL_NULL(brain) + oldorgan.Remove(C,TRUE) + required_organs -= oldorgan + QDEL_NULL(oldorgan) + + if(oldorgan) + oldorgan.setOrganDamage(0) + else if(should_have && !(initial(neworgan.zone) in excluded_zones)) + used_neworgan = TRUE + neworgan.Insert(C, TRUE, FALSE) + required_organs |= neworgan + + if(!used_neworgan) + qdel(neworgan) if(old_species) for(var/mutantorgan in old_species.mutant_organs) + // Snowflake check. If our species share this mutant organ, let's not remove it + // just yet as we'll be properly replacing it later. + if(mutantorgan in mutant_organs) + continue var/obj/item/organ/I = C.getorgan(mutantorgan) if(I) I.Remove(C) required_organs -= I.type QDEL_NULL(I) - for(var/path in mutant_organs) - var/obj/item/organ/I = new path() - I.Insert(C) - required_organs |= I.type + for(var/organ_path in mutant_organs) + var/obj/item/organ/current_organ = C.getorgan(organ_path) + if(!current_organ || replace_current) + var/obj/item/organ/replacement = new organ_path() + // If there's an existing mutant organ, we're technically replacing it. + // Let's abuse the snowflake proc. Basically retains + // feature parity with every other organ too. + 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(C, TRUE, FALSE) + required_organs |= replacement.type /datum/species/proc/replace_body(mob/living/carbon/C, var/datum/species/new_species) new_species ||= C.dna.species //If no new species is provided, assume its src. @@ -857,83 +819,83 @@ GLOBAL_LIST_EMPTY(features_by_species) var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD) - if("tail_lizard" in mutant_bodyparts) + if(mutant_bodyparts["tail_lizard"]) if(H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT)) bodyparts_to_add -= "tail_lizard" - if("waggingtail_lizard" in mutant_bodyparts) + if(mutant_bodyparts["waggingtail_lizard"]) if(H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT)) bodyparts_to_add -= "waggingtail_lizard" - else if ("tail_lizard" in mutant_bodyparts) + else if (mutant_bodyparts["tail_lizard"]) bodyparts_to_add -= "waggingtail_lizard" - if("tail_human" in mutant_bodyparts) + if(mutant_bodyparts["tail_human"]) if(H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT)) bodyparts_to_add -= "tail_human" - if("waggingtail_human" in mutant_bodyparts) + if(mutant_bodyparts["waggingtail_human"]) if(H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT)) bodyparts_to_add -= "waggingtail_human" - else if ("tail_human" in mutant_bodyparts) + else if (mutant_bodyparts["tail_human"]) bodyparts_to_add -= "waggingtail_human" - if("spines" in mutant_bodyparts) + if(mutant_bodyparts["spines"]) if(!H.dna.features["spines"] || H.dna.features["spines"] == "None" || H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT)) bodyparts_to_add -= "spines" - if("waggingspines" in mutant_bodyparts) + if(mutant_bodyparts["waggingspines"]) if(!H.dna.features["spines"] || H.dna.features["spines"] == "None" || H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT)) bodyparts_to_add -= "waggingspines" - else if ("tail" in mutant_bodyparts) + else if (mutant_bodyparts["tail"]) bodyparts_to_add -= "waggingspines" - if("snout" in mutant_bodyparts) //Take a closer look at that snout! + if(mutant_bodyparts["snout"]) //Take a closer look at that snout! if((H.wear_mask?.flags_inv & HIDESNOUT) || (H.head?.flags_inv & HIDESNOUT) || !HD) bodyparts_to_add -= "snout" - if("frills" in mutant_bodyparts) + if(mutant_bodyparts["frills"]) if(!H.dna.features["frills"] || H.dna.features["frills"] == "None" || (H.head?.flags_inv & HIDEEARS) || !HD) bodyparts_to_add -= "frills" - if("horns" in mutant_bodyparts) + if(mutant_bodyparts["horns"]) if(!H.dna.features["horns"] || H.dna.features["horns"] == "None" || H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD) bodyparts_to_add -= "horns" - if("ears" in mutant_bodyparts) + if(mutant_bodyparts["ears"]) if(!H.dna.features["ears"] || H.dna.features["ears"] == "None" || H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD) bodyparts_to_add -= "ears" - if("wings" in mutant_bodyparts) + if(mutant_bodyparts["wings"]) if(!H.dna.features["wings"] || H.dna.features["wings"] == "None" || (H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT) && (!H.wear_suit.species_exception || !is_type_in_list(src, H.wear_suit.species_exception)))) bodyparts_to_add -= "wings" - if("wings_open" in mutant_bodyparts) + if(mutant_bodyparts["wings_open"]) if(H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT) && (!H.wear_suit.species_exception || !is_type_in_list(src, H.wear_suit.species_exception))) bodyparts_to_add -= "wings_open" - else if ("wings" in mutant_bodyparts) + else if (mutant_bodyparts["wings"]) bodyparts_to_add -= "wings_open" - if("moth_antennae" in mutant_bodyparts) + if(mutant_bodyparts["moth_antennae"]) if(!H.dna.features["moth_antennae"] || H.dna.features["moth_antennae"] == "None" || !HD) bodyparts_to_add -= "moth_antennae" - if("ipc_screen" in mutant_bodyparts) + if(mutant_bodyparts["ipc_screen"]) if(!H.dna.features["ipc_screen"] || H.dna.features["ipc_screen"] == "None" || (H.wear_mask && (H.wear_mask.flags_inv & HIDEEYES)) || !HD) bodyparts_to_add -= "ipc_screen" - if("ipc_antenna" in mutant_bodyparts) + if(mutant_bodyparts["ipc_antenna"]) if(!H.dna.features["ipc_antenna"] || H.dna.features["ipc_antenna"] == "None" || (H.head?.flags_inv & HIDEEARS) || !HD) bodyparts_to_add -= "ipc_antenna" - if("apid_antenna" in mutant_bodyparts) + if(mutant_bodyparts["apid_antenna"]) if(!H.dna.features["apid_antenna"] || H.dna.features["apid_antenna"] == "None" || H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD) bodyparts_to_add -= "apid_antenna" - if("apid_headstripe" in mutant_bodyparts) + if(mutant_bodyparts["apid_headstripe"]) if(!H.dna.features["apid_headstripe"] || H.dna.features["apid_headstripe"] == "None" || (H.wear_mask && (H.wear_mask.flags_inv & HIDEEYES)) || !HD) bodyparts_to_add -= "apid_headstripe" - if("psyphoza_cap" in mutant_bodyparts) + if(mutant_bodyparts["psyphoza_cap"]) if(!H.dna.features["psyphoza_cap"] || H.dna.features["psyphoza_cap"] == "None" || !HD) bodyparts_to_add -= "psyphoza_cap" @@ -2350,14 +2312,14 @@ GLOBAL_LIST_EMPTY(features_by_species) speedmod -= 0.35 ADD_TRAIT(H, TRAIT_MOVE_FLYING, SPECIES_FLIGHT_TRAIT) H.pass_flags |= PASSTABLE - if(("wings" in H.dna.species.mutant_bodyparts) || ("moth_wings" in H.dna.species.mutant_bodyparts)) + if((H.dna.species.mutant_bodyparts["wings"]) || (H.dna.species.mutant_bodyparts["moth_wings"])) H.Togglewings() else stunmod *= 0.5 speedmod += 0.35 REMOVE_TRAIT(H, TRAIT_MOVE_FLYING, SPECIES_FLIGHT_TRAIT) H.pass_flags &= ~PASSTABLE - if(("wingsopen" in H.dna.species.mutant_bodyparts) || ("moth_wingsopen" in H.dna.species.mutant_bodyparts)) + if((H.dna.species.mutant_bodyparts["wingsopen"]) || (H.dna.species.mutant_bodyparts["moth_wingsopen"])) H.Togglewings() if(isturf(H.loc)) var/turf/T = H.loc diff --git a/code/modules/mob/living/carbon/human/species_types/IPC.dm b/code/modules/mob/living/carbon/human/species_types/IPC.dm index 2473efcfe839a..238747e1cc0d6 100644 --- a/code/modules/mob/living/carbon/human/species_types/IPC.dm +++ b/code/modules/mob/living/carbon/human/species_types/IPC.dm @@ -7,21 +7,19 @@ species_traits = list(NOTRANSSTING,NOEYESPRITES,NO_DNA_COPY,NOZOMBIE,MUTCOLORS,REVIVESBYHEALING,NOHUSK,NOMOUTH, MUTCOLORS) inherent_traits = list(TRAIT_BLOOD_COOLANT,TRAIT_RESISTCOLD,TRAIT_NOBREATH,TRAIT_RADIMMUNE,TRAIT_LIMBATTACHMENT,TRAIT_EASYDISMEMBER,TRAIT_POWERHUNGRY,TRAIT_XENO_IMMUNE, TRAIT_TOXIMMUNE) inherent_biotypes = list(MOB_ROBOTIC, MOB_HUMANOID) - mutant_brain = /obj/item/organ/brain/positron + mutantbrain = /obj/item/organ/brain/positron mutanteyes = /obj/item/organ/eyes/robotic mutanttongue = /obj/item/organ/tongue/robot mutantliver = /obj/item/organ/liver/cybernetic/upgraded/ipc mutantstomach = /obj/item/organ/stomach/battery/ipc mutantears = /obj/item/organ/ears/robot - mutant_heart = /obj/item/organ/heart/cybernetic/ipc + mutantheart = /obj/item/organ/heart/cybernetic/ipc mutant_organs = list(/obj/item/organ/cyberimp/arm/power_cord) - mutant_bodyparts = list("ipc_screen", "ipc_antenna", "ipc_chassis") - default_features = list("mcolor" = "#7D7D7D", "ipc_screen" = "Static", "ipc_antenna" = "None", "ipc_chassis" = "Morpheus Cyberkinetics (Custom)") + mutant_bodyparts = list("mcolor" = "#7D7D7D", "ipc_screen" = "Static", "ipc_antenna" = "None", "ipc_chassis" = "Morpheus Cyberkinetics (Custom)") meat = /obj/item/stack/sheet/plasteel{amount = 5} skinned_type = /obj/item/stack/sheet/iron{amount = 10} damage_overlay_type = "synth" - mutant_bodyparts = list("ipc_screen", "ipc_antenna", "ipc_chassis") - default_features = list("ipc_screen" = "BSOD", "ipc_antenna" = "None") + burnmod = 2 heatmod = 1.5 brutemod = 1 diff --git a/code/modules/mob/living/carbon/human/species_types/apid.dm b/code/modules/mob/living/carbon/human/species_types/apid.dm index dd28658b01875..da89b4dd55f8e 100644 --- a/code/modules/mob/living/carbon/human/species_types/apid.dm +++ b/code/modules/mob/living/carbon/human/species_types/apid.dm @@ -7,8 +7,7 @@ species_traits = list(LIPS,NOEYESPRITES,MUTCOLORS) inherent_traits = list(TRAIT_BEEFRIEND) inherent_biotypes = list(MOB_ORGANIC,MOB_HUMANOID,MOB_BUG) - mutant_bodyparts = list("apid_stripes","apid_antenna","apid_headstripes") - default_features = list("apid_stripes" = "thick","apid_headstripes" = "thick", "apid_antenna" = "curled") + mutant_bodyparts = list("apid_stripes" = "thick","apid_headstripes" = "thick", "apid_antenna" = "curled") hair_color = "fixedmutcolor" attack_verb = "slash" attack_sound = 'sound/weapons/slash.ogg' diff --git a/code/modules/mob/living/carbon/human/species_types/dullahan.dm b/code/modules/mob/living/carbon/human/species_types/dullahan.dm index 2179e274a6775..c5370e1f69784 100644 --- a/code/modules/mob/living/carbon/human/species_types/dullahan.dm +++ b/code/modules/mob/living/carbon/human/species_types/dullahan.dm @@ -5,9 +5,9 @@ default_color = "FFFFFF" species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS) inherent_traits = list(TRAIT_NOHUNGER,TRAIT_NOBREATH, TRAIT_NONECRODISEASE) - default_features = list("mcolor" = "FFF", "tail_human" = "None", "ears" = "None", "wings" = "None", "body_size" = "Normal") + mutant_bodyparts = list("mcolor" = "FFF", "tail_human" = "None", "ears" = "None", "wings" = "None", "body_size" = "Normal") use_skintones = TRUE - mutant_brain = /obj/item/organ/brain/dullahan + mutantbrain = /obj/item/organ/brain/dullahan mutanteyes = /obj/item/organ/eyes/dullahan mutanttongue = /obj/item/organ/tongue/dullahan mutantears = /obj/item/organ/ears/dullahan diff --git a/code/modules/mob/living/carbon/human/species_types/felinid.dm b/code/modules/mob/living/carbon/human/species_types/felinid.dm index acda8d150343a..80c3b46b48663 100644 --- a/code/modules/mob/living/carbon/human/species_types/felinid.dm +++ b/code/modules/mob/living/carbon/human/species_types/felinid.dm @@ -5,12 +5,11 @@ bodyflag = FLAG_FELINID examine_limb_id = SPECIES_HUMAN - mutant_bodyparts = list("ears", "tail_human") - default_features = list("mcolor" = "FFF", "wings" = "None", "body_size" = "Normal") + mutant_bodyparts = list("tail_human" = "Cat", "ears" = "Cat", "wings" = "None", "body_size" = "Normal") forced_features = list("tail_human" = "Cat", "ears" = "Cat") mutantears = /obj/item/organ/ears/cat - mutanttail = /obj/item/organ/tail/cat + mutant_organs = list(/obj/item/organ/tail/cat) mutanttongue = /obj/item/organ/tongue/cat changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT @@ -49,37 +48,9 @@ var/obj/item/organ/tail/cat/tail = new tail.Insert(H, drop_if_replaced = FALSE, pref_load = pref_load) else - mutanttail = null + mutant_organs = list() return ..() -/datum/species/human/felinid/on_species_loss(mob/living/carbon/H, datum/species/new_species, pref_load) - var/obj/item/organ/ears/cat/ears = H.getorgan(/obj/item/organ/ears/cat) - var/obj/item/organ/tail/cat/tail = H.getorgan(/obj/item/organ/tail/cat) - - if(ears) - var/obj/item/organ/ears/new_ears - if(new_species?.mutantears) - // Roundstart cat ears override new_species.mutantears, reset it here. - new_species.mutantears = initial(new_species.mutantears) - if(new_species.mutantears) - new_ears = new new_species.mutantears - if(!new_ears) - // Go with default ears - new_ears = new /obj/item/organ/ears - new_ears.Insert(H, drop_if_replaced = FALSE, pref_load = pref_load) - - if(tail) - var/obj/item/organ/tail/new_tail - if(new_species && new_species.mutanttail) - // Roundstart cat tail overrides new_species.mutanttail, reset it here. - new_species.mutanttail = initial(new_species.mutanttail) - if(new_species.mutanttail) - new_tail = new new_species.mutanttail - if(new_tail) - new_tail.Insert(H, drop_if_replaced = FALSE, pref_load = pref_load) - else - tail.Remove(H, pref_load = pref_load) - /datum/species/human/felinid/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/M) if(istype(chem, /datum/reagent/consumable/cocoa)) if(prob(40)) diff --git a/code/modules/mob/living/carbon/human/species_types/flypeople.dm b/code/modules/mob/living/carbon/human/species_types/flypeople.dm index f19269e3471fd..e1b43c4560030 100644 --- a/code/modules/mob/living/carbon/human/species_types/flypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/flypeople.dm @@ -9,8 +9,7 @@ mutantliver = /obj/item/organ/liver/fly mutantstomach = /obj/item/organ/stomach/fly meat = /obj/item/food/meat/slab/human/mutant/fly - mutant_bodyparts = list("insect_type") - default_features = list("insect_type" = "fly", "body_size" = "Normal") + mutant_bodyparts = list("insect_type" = "fly", "body_size" = "Normal") burnmod = 1.4 brutemod = 1.4 speedmod = 0.7 diff --git a/code/modules/mob/living/carbon/human/species_types/humans.dm b/code/modules/mob/living/carbon/human/species_types/humans.dm index 8b46658c88f6e..6c0ad26df0a4e 100644 --- a/code/modules/mob/living/carbon/human/species_types/humans.dm +++ b/code/modules/mob/living/carbon/human/species_types/humans.dm @@ -3,7 +3,7 @@ id = SPECIES_HUMAN default_color = "FFFFFF" species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS) - default_features = list("mcolor" = "FFF", "wings" = "None", "body_size" = "Normal") + mutant_bodyparts = list("body_size" = "Normal") use_skintones = 1 skinned_type = /obj/item/stack/sheet/animalhide/human changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm index ac0bbbf2bcc57..6be939510e757 100644 --- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm @@ -7,12 +7,12 @@ default_color = "00FF00" species_traits = list(MUTCOLORS,EYECOLOR,LIPS) inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID, MOB_REPTILE) - mutant_bodyparts = list("tail_lizard", "snout", "spines", "horns", "frills", "body_markings", "legs") + mutant_bodyparts = list("tail_lizard" = "Smooth", "snout" = "Round", "horns" = "None", + "frills" = "None", "spines" = "None", "body_markings" = "None", "legs" = "Normal Legs", "body_size" = "Normal") mutanttongue = /obj/item/organ/tongue/lizard - mutanttail = /obj/item/organ/tail/lizard + mutant_organs = list(/obj/item/organ/tail/lizard) coldmod = 1.5 heatmod = 0.67 - default_features = list("mcolor" = "0F0", "tail_lizard" = "Smooth", "snout" = "Round", "horns" = "None", "frills" = "None", "spines" = "None", "body_markings" = "None", "legs" = "Normal Legs", "body_size" = "Normal") changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT attack_verb = "slash" attack_sound = 'sound/weapons/slash.ogg' diff --git a/code/modules/mob/living/carbon/human/species_types/mothmen.dm b/code/modules/mob/living/carbon/human/species_types/mothmen.dm index 30779164add58..ab4b47c0a4f62 100644 --- a/code/modules/mob/living/carbon/human/species_types/mothmen.dm +++ b/code/modules/mob/living/carbon/human/species_types/mothmen.dm @@ -13,8 +13,7 @@ default_color = "00FF00" species_traits = list(LIPS, NOEYESPRITES, HAS_MARKINGS) inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID, MOB_BUG) - mutant_bodyparts = list("moth_wings", "moth_antennae", "moth_markings") - default_features = list("moth_wings" = "Plain", "moth_antennae" = "Plain", "moth_markings" = "None", "body_size" = "Normal") + mutant_bodyparts = list("moth_wings" = "Plain", "moth_antennae" = "Plain", "moth_markings" = "None", "body_size" = "Normal") attack_verb = "slash" attack_sound = 'sound/weapons/slash.ogg' miss_sound = 'sound/weapons/slashmiss.ogg' diff --git a/code/modules/mob/living/carbon/human/species_types/psyphoza.dm b/code/modules/mob/living/carbon/human/species_types/psyphoza.dm index 00588d8e363d1..b0032317c64fc 100644 --- a/code/modules/mob/living/carbon/human/species_types/psyphoza.dm +++ b/code/modules/mob/living/carbon/human/species_types/psyphoza.dm @@ -14,12 +14,11 @@ offset_features = list(OFFSET_UNIFORM = list(0,0), OFFSET_ID = list(0,0), OFFSET_GLOVES = list(0,0), OFFSET_GLASSES = list(0,-2), OFFSET_EARS = list(0,-3), OFFSET_SHOES = list(0,0), OFFSET_S_STORE = list(0,0), OFFSET_FACEMASK = list(0,-2), OFFSET_HEAD = list(0,-2), OFFSET_FACE = list(0,-2), OFFSET_BELT = list(0,0), OFFSET_BACK = list(0,0), OFFSET_SUIT = list(0,0), OFFSET_NECK = list(0,0)) - mutant_brain = /obj/item/organ/brain/psyphoza + mutantbrain = /obj/item/organ/brain/psyphoza mutanteyes = /obj/item/organ/eyes/psyphoza mutanttongue = /obj/item/organ/tongue/psyphoza - mutant_bodyparts = list("psyphoza_cap") - default_features = list("psyphoza_cap" = "Portobello", "body_size" = "Normal", "mcolor" = "fff") + mutant_bodyparts = list("psyphoza_cap" = "Portobello", "body_size" = "Normal", "mcolor" = "fff") hair_color = "fixedmutcolor" species_chest = /obj/item/bodypart/chest/psyphoza diff --git a/code/modules/mob/living/carbon/human/species_types/pumpkin_man.dm b/code/modules/mob/living/carbon/human/species_types/pumpkin_man.dm index 466113a2ae762..431564f384c1b 100644 --- a/code/modules/mob/living/carbon/human/species_types/pumpkin_man.dm +++ b/code/modules/mob/living/carbon/human/species_types/pumpkin_man.dm @@ -10,7 +10,7 @@ miss_sound = 'sound/weapons/punchmiss.ogg' changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | ERT_SPAWN - mutant_brain = /obj/item/organ/brain/pumpkin_brain + mutantbrain = /obj/item/organ/brain/pumpkin_brain mutanttongue = /obj/item/organ/tongue/podperson/pumpkin species_chest = /obj/item/bodypart/chest/pumpkin_man diff --git a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm index ae06c0f247468..b092d7ba1f149 100644 --- a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm @@ -95,8 +95,8 @@ species_traits = list(NOBLOOD,NO_UNDERWEAR,NO_DNA_COPY,NOTRANSSTING,NOEYESPRITES,NOFLASH) inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_NOBREATH,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_VIRUSIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER) mutanteyes = /obj/item/organ/eyes/night_vision/nightmare - mutant_organs = list(/obj/item/organ/heart/nightmare) - mutant_brain = /obj/item/organ/brain/nightmare + mutantheart = /obj/item/organ/heart/nightmare + mutantbrain = /obj/item/organ/brain/nightmare nojumpsuit = 1 var/info_text = "You are a Nightmare. The ability shadow walk allows unlimited, unrestricted movement in the dark while activated. \ diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm index 50a4022c48485..f761d4f7c60bd 100644 --- a/code/modules/mob/living/carbon/human/species_types/vampire.dm +++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm @@ -5,11 +5,11 @@ species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS) inherent_traits = list(TRAIT_NOHUNGER,TRAIT_NOBREATH,TRAIT_DRINKSBLOOD) inherent_biotypes = list(MOB_UNDEAD, MOB_HUMANOID) - default_features = list("mcolor" = "FFF", "tail_human" = "None", "ears" = "None", "wings" = "None", "body_size" = "Normal") + mutant_bodyparts = list("tail_human" = "None", "ears" = "None", "wings" = "None", "body_size" = "Normal") changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | ERT_SPAWN exotic_bloodtype = "U" use_skintones = TRUE - mutant_heart = /obj/item/organ/heart/vampire + mutantheart = /obj/item/organ/heart/vampire mutanttongue = /obj/item/organ/tongue/vampire examine_limb_id = SPECIES_HUMAN skinned_type = /obj/item/stack/sheet/animalhide/human diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm index 3d67252925f1c..ce45170756a7e 100644 --- a/code/modules/mob/living/carbon/monkey/monkey.dm +++ b/code/modules/mob/living/carbon/monkey/monkey.dm @@ -243,11 +243,10 @@ CREATION_TEST_IGNORE_SUBTYPES(/mob/living/carbon/monkey) id = "teratoma" species_traits = list(NOTRANSSTING, NO_DNA_COPY, EYECOLOR, HAIR, FACEHAIR, LIPS) inherent_traits = list(TRAIT_NOHUNGER, TRAIT_RADIMMUNE, TRAIT_BADDNA, TRAIT_NOGUNS, TRAIT_NONECRODISEASE) //Made of mutated cells - default_features = list("mcolor" = "FFF", "wings" = "None") use_skintones = FALSE skinned_type = /obj/item/stack/sheet/animalhide/monkey changesource_flags = MIRROR_BADMIN - mutant_brain = /obj/item/organ/brain/tumor + mutantbrain = /obj/item/organ/brain/tumor mutanttongue = /obj/item/organ/tongue/teratoma species_chest = /obj/item/bodypart/chest/monkey/teratoma diff --git a/code/modules/surgery/bodyparts/bodyparts.dm b/code/modules/surgery/bodyparts/bodyparts.dm index ad9e65c33931d..d4ec2353a5462 100644 --- a/code/modules/surgery/bodyparts/bodyparts.dm +++ b/code/modules/surgery/bodyparts/bodyparts.dm @@ -130,14 +130,16 @@ var/mob/living/carbon/human/H = C if(HAS_TRAIT(C, TRAIT_LIMBATTACHMENT)) if(!H.get_bodypart(body_zone) && !animal_origin) + user.temporarilyRemoveItemFromInventory(src, TRUE) + if(!attach_limb(C)) + to_chat(user, "[H]'s body rejects [src]!") + forceMove(H.loc) if(H == user) H.visible_message("[H] jams [src] into [H.p_their()] empty socket!",\ "You force [src] into your empty socket, and it locks into place!") else H.visible_message("[user] jams [src] into [H]'s empty socket!",\ "[user] forces [src] into your empty socket, and it locks into place!") - user.temporarilyRemoveItemFromInventory(src, TRUE) - attach_limb(C) return ..() diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm index c8079b137523c..3f8bdf4d2e7ac 100644 --- a/code/modules/surgery/bodyparts/dismemberment.dm +++ b/code/modules/surgery/bodyparts/dismemberment.dm @@ -252,24 +252,25 @@ /obj/item/bodypart/proc/replace_limb(mob/living/carbon/C, special, is_creating = FALSE) if(!istype(C)) return - var/obj/item/bodypart/O = C.get_bodypart(body_zone) + var/obj/item/bodypart/O = C.get_bodypart(body_zone) //needs to happen before attach because multiple limbs in same zone breaks helpers + if(!attach_limb(C, special, is_creating))//we can attach this limb and drop the old after because of our robust bodyparts system. you know, just for a sec. + return if(O) O.drop_limb(1) - attach_limb(C, special, is_creating) /obj/item/bodypart/head/replace_limb(mob/living/carbon/C, special, is_creating = FALSE) if(!istype(C)) return var/obj/item/bodypart/head/O = C.get_bodypart(body_zone) + if(!attach_limb(C, special, is_creating)) + return if(O) - if(!special) - return - else - O.drop_limb(1) - attach_limb(C, special, is_creating) + O.drop_limb(1) /obj/item/bodypart/proc/attach_limb(mob/living/carbon/C, special, is_creating = FALSE) - SEND_SIGNAL(C, COMSIG_CARBON_ATTACH_LIMB, src, special) + //if(SEND_SIGNAL(C, COMSIG_CARBON_ATTACH_LIMB, src, special) & COMPONENT_NO_ATTACH) + // return FALSE + //. = TRUE SEND_SIGNAL(src, COMSIG_BODYPART_ATTACHED, C, special) moveToNullspace() set_owner(C) @@ -287,8 +288,7 @@ C.update_inv_gloves() if(special) //non conventional limb attachment - for(var/X in C.surgeries) //if we had an ongoing surgery to attach a new limb, we stop it. - var/datum/surgery/S = X + for(var/datum/surgery/S as anything in C.surgeries) //if we had an ongoing surgery to attach a new limb, we stop it. var/surgery_zone = check_zone(S.location) if(surgery_zone == body_zone) C.surgeries -= S @@ -309,7 +309,10 @@ SEND_SIGNAL(C, COMSIG_CARBON_POST_ATTACH_LIMB, src, special) -/obj/item/bodypart/head/attach_limb(mob/living/carbon/C, special, is_creating = FALSE) +/obj/item/bodypart/head/attach_limb(mob/living/carbon/C, special = FALSE, abort = FALSE, is_creating = FALSE) + . = ..() + if(!.) + return . //Transfer some head appearance vars over if(brain) if(brainmob) @@ -347,7 +350,10 @@ AP.Grant(C) break - ..() + C.updatehealth() + C.update_body() + C.update_hair() + C.update_damage_overlays() /obj/item/bodypart/proc/synchronize_bodytypes(mob/living/carbon/C) if(!C.dna.species) @@ -360,15 +366,15 @@ C.dna.species.bodytype = all_limb_flags //Regenerates all limbs. Returns amount of limbs regenerated -/mob/living/proc/regenerate_limbs(noheal, excluded_limbs) - return 0 +/mob/living/proc/regenerate_limbs(noheal = FALSE, list/excluded_zones = list()) + SEND_SIGNAL(src, COMSIG_LIVING_REGENERATE_LIMBS, noheal, excluded_zones) -/mob/living/carbon/regenerate_limbs(noheal, list/excluded_limbs) - var/list/limb_list = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG) - if(excluded_limbs) - limb_list -= excluded_limbs - for(var/Z in limb_list) - . += regenerate_limb(Z, noheal) +/mob/living/carbon/regenerate_limbs(noheal = FALSE, list/excluded_zones = list()) + var/list/zone_list = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG) + if(length(excluded_zones)) + zone_list -= excluded_zones + for(var/limb_zone in zone_list) + . += regenerate_limb(limb_zone, noheal) /mob/living/proc/regenerate_limb(limb_zone, noheal) return @@ -376,7 +382,7 @@ /mob/living/carbon/regenerate_limb(limb_zone, noheal) var/obj/item/bodypart/L if(get_bodypart(limb_zone)) - return 0 + return FALSE L = newBodyPart(limb_zone, 0, 0) L.replace_limb(src, TRUE, TRUE) return 1 diff --git a/code/modules/surgery/organs/appendix.dm b/code/modules/surgery/organs/appendix.dm index 0645e4bc6c101..d1f1b92de12c8 100644 --- a/code/modules/surgery/organs/appendix.dm +++ b/code/modules/surgery/organs/appendix.dm @@ -28,6 +28,9 @@ if(M) M.adjustToxLoss(4, TRUE, TRUE) //forced to ensure people don't use it to gain tox as slime person +/obj/item/organ/appendix/get_availability(datum/species/S) + return !((TRAIT_NOHUNGER in S.species_traits) || (TRAIT_POWERHUNGRY in S.inherent_traits)) + /obj/item/organ/appendix/Remove(mob/living/carbon/M, special = 0, pref_load = FALSE) for(var/datum/disease/appendicitis/A in M.diseases) A.cure() diff --git a/code/modules/surgery/organs/ears.dm b/code/modules/surgery/organs/ears.dm index 8cef3e044916c..147108d0f464f 100644 --- a/code/modules/surgery/organs/ears.dm +++ b/code/modules/surgery/organs/ears.dm @@ -105,8 +105,7 @@ return if(istype(H)) color = H.hair_color - H.dna.species.mutant_bodyparts |= "ears" - H.dna.features["ears"] = "Cat" + H.dna.features["ears"] = H.dna.species.mutant_bodyparts["ears"] = "Cat" H.update_body() /obj/item/organ/ears/cat/Remove(mob/living/carbon/human/H, special = 0, pref_load = FALSE) diff --git a/code/modules/surgery/organs/heart.dm b/code/modules/surgery/organs/heart.dm index 531fa34ed7dbf..0439c5c092615 100644 --- a/code/modules/surgery/organs/heart.dm +++ b/code/modules/surgery/organs/heart.dm @@ -98,6 +98,9 @@ owner.set_heartattack(TRUE) failed = TRUE +/obj/item/organ/heart/get_availability(datum/species/S) + return !(NOBLOOD in S.species_traits) + /obj/item/organ/heart/cursed name = "cursed heart" desc = "A heart that, when inserted, will force you to pump it manually." diff --git a/code/modules/surgery/organs/liver.dm b/code/modules/surgery/organs/liver.dm index 6d84980cc3ea7..71dae581957a3 100755 --- a/code/modules/surgery/organs/liver.dm +++ b/code/modules/surgery/organs/liver.dm @@ -67,6 +67,9 @@ #undef HAS_NO_TOXIN #undef HAS_PAINFUL_TOXIN +/obj/item/organ/liver/get_availability(datum/species/S) + return !(TRAIT_NOMETABOLISM in S.species_traits) + /obj/item/organ/liver/fly name = "insectoid liver" icon_state = "liver-x" //xenomorph liver? It's just a black liver so it fits. diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm index dc32c17641833..d816c0bb7a5df 100644 --- a/code/modules/surgery/organs/lungs.dm +++ b/code/modules/surgery/organs/lungs.dm @@ -366,6 +366,8 @@ failed = FALSE return +/obj/item/organ/lungs/get_availability(datum/species/S) + return !(TRAIT_NOBREATH in S.species_traits) /obj/item/organ/lungs/plasmaman name = "plasma filter" diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm index 97b650a9ac0b0..af54623dc1a0c 100644 --- a/code/modules/surgery/organs/organ_internal.dm +++ b/code/modules/surgery/organs/organ_internal.dm @@ -217,22 +217,47 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) return else - if(!getorganslot(ORGAN_SLOT_LUNGS)) - var/obj/item/organ/lungs/L = new() + var/obj/item/organ/lungs/L = getorganslot(ORGAN_SLOT_LUNGS) + if(!L) + L = new() L.Insert(src) + L.setOrganDamage(0) - if(!getorganslot(ORGAN_SLOT_HEART)) - var/obj/item/organ/heart/H = new() + var/obj/item/organ/heart/H = getorganslot(ORGAN_SLOT_HEART) + if(!H) + H = new() H.Insert(src) + H.setOrganDamage(0) - if(!getorganslot(ORGAN_SLOT_TONGUE)) - var/obj/item/organ/tongue/T = new() + var/obj/item/organ/tongue/T = getorganslot(ORGAN_SLOT_TONGUE) + if(!T) + T = new() T.Insert(src) + T.setOrganDamage(0) - if(!getorganslot(ORGAN_SLOT_EYES)) - var/obj/item/organ/eyes/E = new() - E.Insert(src) + var/obj/item/organ/eyes/eyes = getorganslot(ORGAN_SLOT_EYES) + if(!eyes) + eyes = new() + eyes.Insert(src) + eyes.setOrganDamage(0) - if(!getorganslot(ORGAN_SLOT_EARS)) - var/obj/item/organ/ears/ears = new() + var/obj/item/organ/ears/ears = getorganslot(ORGAN_SLOT_EARS) + if(!ears) + ears = new() ears.Insert(src) + ears.setOrganDamage(0) + +/** get_availability + * returns whether the species should innately have this organ. + * + * regenerate organs works with generic organs, so we need to get whether it can accept certain organs just by what this returns. + * This is set to return true or false, depending on if a species has a specific organless trait. stomach for example checks if the species has NOSTOMACH and return based on that. + * Arguments: + * S - species, needed to return whether the species has an organ specific trait + */ +/obj/item/organ/proc/get_availability(datum/species/S) + return TRUE + +/// Called before organs are replaced in regenerate_organs with new ones +/obj/item/organ/proc/before_organ_replacement(obj/item/organ/replacement) + return diff --git a/code/modules/surgery/organs/stomach.dm b/code/modules/surgery/organs/stomach.dm index 33630b88d1229..e6e63abf3bac0 100755 --- a/code/modules/surgery/organs/stomach.dm +++ b/code/modules/surgery/organs/stomach.dm @@ -43,6 +43,9 @@ H.vomit(damage) to_chat(H, "Your stomach reels in pain as you're incapable of holding down all that food!") +/obj/item/organ/stomach/get_availability(datum/species/S) + return !(NOSTOMACH in S.species_traits) + /obj/item/organ/stomach/proc/handle_disgust(mob/living/carbon/human/H) if(H.disgust) var/pukeprob = 5 + 0.05 * H.disgust diff --git a/code/modules/surgery/organs/tails.dm b/code/modules/surgery/organs/tails.dm index f17295579da96..c5922b4a83189 100644 --- a/code/modules/surgery/organs/tails.dm +++ b/code/modules/surgery/organs/tails.dm @@ -28,9 +28,9 @@ H.update_body() return if(istype(H)) - if(!("tail_human" in H.dna.species.mutant_bodyparts)) - H.dna.species.mutant_bodyparts |= "tail_human" - H.dna.features["tail_human"] = tail_type + var/default_part = H.dna.species.mutant_bodyparts["tail_human"] + if(!default_part || default_part == "None") + H.dna.features["tail_human"] = H.dna.species.mutant_bodyparts["tail_human"] = tail_type H.update_body() /obj/item/organ/tail/cat/Remove(mob/living/carbon/human/H, special = 0, pref_load = FALSE) @@ -48,7 +48,7 @@ /obj/item/organ/tail/cat/is_wagging(mob/living/carbon/human/H) if(!H?.dna?.species) return FALSE - return ("waggingtail_human" in H.dna.species.mutant_bodyparts) + return (H.dna.species.mutant_bodyparts["waggingtail_human"]) /obj/item/organ/tail/cat/set_wagging(mob/living/carbon/human/H, wagging = FALSE) . = FALSE @@ -75,15 +75,40 @@ ..() if(istype(H)) // Checks here are necessary so it wouldn't overwrite the tail of a lizard it spawned in - if(!("tail_lizard" in H.dna.species.mutant_bodyparts)) - H.dna.features["tail_lizard"] = tail_type - H.dna.species.mutant_bodyparts |= "tail_lizard" + var/default_part = H.dna.species.mutant_bodyparts["tail_lizard"] + if(!default_part || default_part == "None") + H.dna.features["tail_lizard"] = H.dna.species.mutant_bodyparts["tail_lizard"] = tail_type - if(!("spines" in H.dna.species.mutant_bodyparts)) - H.dna.features["spines"] = spines - H.dna.species.mutant_bodyparts |= "spines" + default_part = H.dna.species.mutant_bodyparts["spines"] + if(!default_part || default_part == "None") + H.dna.features["spines"] = H.dna.species.mutant_bodyparts["spines"] = spines H.update_body() +/datum/species/lizard/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load) + var/real_tail_type = C.dna.features["tail_lizard"] + var/real_spines = C.dna.features["spines"] + + . = ..() + + // Special handler for loading preferences. If we're doing it from a preference load, we'll want + // to make sure we give the appropriate lizard tail AFTER we call the parent proc, as the parent + // proc will overwrite the lizard tail. Species code at its finest. + if(pref_load) + C.dna.features["tail_lizard"] = real_tail_type + C.dna.features["spines"] = real_spines + + var/obj/item/organ/tail/lizard/new_tail = new /obj/item/organ/tail/lizard() + + new_tail.tail_type = C.dna.features["tail_lizard"] + C.dna.species.mutant_bodyparts |= "tail_lizard" + + new_tail.spines = C.dna.features["spines"] + C.dna.species.mutant_bodyparts |= "spines" + + // organ.Insert will qdel any existing organs in the same slot, so + // we don't need to manage that. + new_tail.Insert(C, TRUE, FALSE) + /obj/item/organ/tail/lizard/Remove(mob/living/carbon/human/H, special = 0, pref_load = FALSE) ..() if(istype(H)) @@ -94,10 +119,20 @@ spines = H.dna.features["spines"] H.update_body() +/obj/item/organ/tail/lizard/before_organ_replacement(obj/item/organ/replacement) + . = ..() + var/obj/item/organ/tail/lizard/new_tail = replacement + + if(!istype(new_tail)) + return + + new_tail.tail_type = tail_type + new_tail.spines = spines + /obj/item/organ/tail/lizard/is_wagging(mob/living/carbon/human/H) if(!H?.dna?.species) return FALSE - return ("waggingtail_lizard" in H.dna.species.mutant_bodyparts) + return (H.dna.species.mutant_bodyparts["waggingtail_lizard"]) /obj/item/organ/tail/lizard/set_wagging(mob/living/carbon/human/H, wagging = FALSE) . = FALSE diff --git a/code/modules/surgery/organs/wings.dm b/code/modules/surgery/organs/wings.dm index 6ce219b437b40..95c03fbb691d9 100644 --- a/code/modules/surgery/organs/wings.dm +++ b/code/modules/surgery/organs/wings.dm @@ -24,7 +24,7 @@ /obj/item/organ/wings/proc/Refresh(mob/living/carbon/human/H) H.dna.species.mutant_bodyparts -= "[basewings]open" - if(!(basewings in H.dna.species.mutant_bodyparts)) + if(!(H.dna.species.mutant_bodyparts[basewings])) H.dna.species.mutant_bodyparts |= basewings H.dna.features[basewings] = wing_type H.update_body() @@ -56,16 +56,16 @@ if(wingsound) playsound(H, wingsound, 100, 7) if(basewings == "wings" || basewings == "moth_wings") - if("wings" in H.dna.species.mutant_bodyparts) + if(H.dna.species.mutant_bodyparts["wings"]) H.dna.species.mutant_bodyparts -= "wings" H.dna.species.mutant_bodyparts |= "wingsopen" - else if("wingsopen" in H.dna.species.mutant_bodyparts) + else if(H.dna.species.mutant_bodyparts["wingsopen"]) H.dna.species.mutant_bodyparts -= "wingsopen" H.dna.species.mutant_bodyparts |= "wings" - else if("moth_wings" in H.dna.species.mutant_bodyparts) + else if(H.dna.species.mutant_bodyparts["moth_wings"]) H.dna.species.mutant_bodyparts |= "moth_wingsopen" H.dna.species.mutant_bodyparts -= "moth_wings" - else if("moth_wingsopen" in H.dna.species.mutant_bodyparts) + else if(H.dna.species.mutant_bodyparts["moth_wingsopen"]) H.dna.species.mutant_bodyparts -= "moth_wingsopen" H.dna.species.mutant_bodyparts |= "moth_wings" else //it appears we don't actually have wing icons. apply them!!