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!!