diff --git a/code/datums/diseases/kingstons.dm b/code/datums/diseases/kingstons.dm index 1ed17e0df8f..5783b2f664b 100644 --- a/code/datums/diseases/kingstons.dm +++ b/code/datums/diseases/kingstons.dm @@ -43,7 +43,7 @@ affected_mob.visible_message("[affected_mob]'s form contorts into something more feline!", \ "YOU TURN INTO A TAJARAN!") var/mob/living/carbon/human/catface = affected_mob - catface.set_species(/datum/species/tajaran, retain_damage = TRUE) + catface.set_species(/datum/species/tajaran, retain_damage = TRUE, keep_missing_bodyparts = TRUE) /datum/disease/kingstons_advanced //this used to be directly a subtype of kingstons, which sounds nice, but it ment that it would *turn you into a tarjaran always and have normal kingstons stage act* Don't make virusus subtypes unless the base virus does nothing. @@ -90,7 +90,7 @@ if(!istype(twisted.dna.species, chosentype)) twisted.visible_message("[twisted]'s skin splits and form contorts!", \ "Your body mutates into a [initial(chosentype.name)]!") - twisted.set_species(chosentype, retain_damage = TRUE) + twisted.set_species(chosentype, retain_damage = TRUE, keep_missing_bodyparts = TRUE) else twisted.visible_message("[twisted] scratches at their skin!", \ "You scratch your skin to try not to itch!") diff --git a/code/game/dna/dna2.dm b/code/game/dna/dna2.dm index 81105a4c2a9..303f09acac7 100644 --- a/code/game/dna/dna2.dm +++ b/code/game/dna/dna2.dm @@ -445,7 +445,7 @@ GLOBAL_LIST_EMPTY(bad_blocks) return // We manually set the species to ensure all proper species change procs are called. - destination.set_species(species.type, retain_damage = TRUE) + destination.set_species(species.type, retain_damage = TRUE, keep_missing_bodyparts = TRUE) var/datum/dna/new_dna = Clone() new_dna.species = destination.dna.species destination.dna = new_dna diff --git a/code/game/dna/mutations/monkey.dm b/code/game/dna/mutations/monkey.dm index facacbe0d3f..c51522824d3 100644 --- a/code/game/dna/mutations/monkey.dm +++ b/code/game/dna/mutations/monkey.dm @@ -26,7 +26,7 @@ H.invisibility = 101 var/has_primitive_form = H.dna.species.primitive_form // cache this if(has_primitive_form) - H.set_species(has_primitive_form) + H.set_species(has_primitive_form, keep_missing_bodyparts = TRUE) new /obj/effect/temp_visual/monkeyify(H.loc) sleep(22) @@ -60,7 +60,7 @@ H.invisibility = 101 var/has_greater_form = H.dna.species.greater_form //cache this if(has_greater_form) - H.set_species(has_greater_form) + H.set_species(has_greater_form, keep_missing_bodyparts = TRUE) new /obj/effect/temp_visual/monkeyify/humanify(H.loc) sleep(22) diff --git a/code/game/gamemodes/miniantags/abduction/gland.dm b/code/game/gamemodes/miniantags/abduction/gland.dm index 1f6b8eb52ab..397d199dbb8 100644 --- a/code/game/gamemodes/miniantags/abduction/gland.dm +++ b/code/game/gamemodes/miniantags/abduction/gland.dm @@ -179,7 +179,7 @@ /obj/item/organ/internal/heart/gland/pop/activate() to_chat(owner, "You feel unlike yourself.") var/species = pick(/datum/species/unathi, /datum/species/skrell, /datum/species/diona, /datum/species/tajaran, /datum/species/vulpkanin, /datum/species/kidan, /datum/species/grey) - owner.set_species(species) + owner.set_species(species, keep_missing_bodyparts = TRUE) /obj/item/organ/internal/heart/gland/ventcrawling origin_tech = "materials=4;biotech=5;bluespace=4;abductor=3" diff --git a/code/modules/antagonists/changeling/powers/humanform.dm b/code/modules/antagonists/changeling/powers/humanform.dm index 418592d239c..9e3d7be73be 100644 --- a/code/modules/antagonists/changeling/powers/humanform.dm +++ b/code/modules/antagonists/changeling/powers/humanform.dm @@ -14,7 +14,7 @@ user.dna.SetSEState(GLOB.monkeyblock,0,1) singlemutcheck(user,GLOB.monkeyblock, MUTCHK_FORCED) if(istype(user)) - user.set_species(chosen_dna.species.type) + user.set_species(chosen_dna.species.type, keep_missing_bodyparts = TRUE) user.dna = chosen_dna.Clone() user.real_name = chosen_dna.real_name domutcheck(user, MUTCHK_FORCED) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 04fed84f41f..03ed3fbf733 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1243,7 +1243,7 @@ /mob/living/carbon/human/proc/change_dna(datum/dna/new_dna, include_species_change = FALSE, keep_flavor_text = FALSE) if(include_species_change) - set_species(new_dna.species.type, retain_damage = TRUE, transformation = TRUE) + set_species(new_dna.species.type, retain_damage = TRUE, transformation = TRUE, keep_missing_bodyparts = TRUE) dna = new_dna.Clone() if (include_species_change) //We have to call this after new_dna.Clone() so that species actions don't get overwritten dna.species.on_species_gain(src) @@ -1258,7 +1258,19 @@ sec_hud_set_ID() -/mob/living/carbon/human/proc/set_species(datum/species/new_species, use_default_color = FALSE, delay_icon_update = FALSE, skip_same_check = FALSE, retain_damage = FALSE, transformation = FALSE) +/** + * Change a mob's species. + * + * Arguments: + * * new_species - The user's new species. + * * use_default_color - If true, use the species' default color for the new mob. + * * delay_icon_update - If true, UpdateAppearance() won't be called in this proc. + * * skip_same_check - If true, don't bail out early if we would be changing to our current species and run through everything anyway. + * * retain_damage - If true, damage on the mob will be re-applied post-transform. Otherwise, the mob will have its organs healed. + * * transformation - If true, don't apply new species traits to the mob. A false value should be used when creating a new mob instead of transforming into a new species. + * * keep_missing_bodyparts - If true, any bodyparts (legs, head, etc.) that were missing on the mob before species change will be missing post-change as well. + */ +/mob/living/carbon/human/proc/set_species(datum/species/new_species, use_default_color = FALSE, delay_icon_update = FALSE, skip_same_check = FALSE, retain_damage = FALSE, transformation = FALSE, keep_missing_bodyparts = FALSE) if(!skip_same_check) if(dna.species.name == initial(new_species.name)) return @@ -1316,9 +1328,16 @@ if(!transformation) //Distinguish between creating a mob and switching species dna.species.on_species_gain(src) + var/list/missing_bodyparts = list() // should line up here to pop out only what's missing + if(keep_missing_bodyparts) + for(var/organ_name as anything in bodyparts_by_name) + if(isnull(bodyparts_by_name[organ_name])) + missing_bodyparts |= organ_name + if(retain_damage) //Create a list of body parts which are damaged by burn or brute and save them to apply after new organs are generated. First we just handle external organs. var/bodypart_damages = list() + //Loop through all external organs and save the damage states for brute and burn for(var/obj/item/organ/external/E as anything in bodyparts) if(E.brute_dam == 0 && E.burn_dam == 0 && !(E.status & ORGAN_INT_BLEEDING)) //If there's no damage we don't bother remembering it. @@ -1342,7 +1361,7 @@ internal_damages += list(stats) //Create the new organs for the species change - dna.species.create_organs(src) + dna.species.create_organs(src, missing_bodyparts) //Apply relevant damages and variables to the new organs. for(var/obj/item/organ/external/E as anything in bodyparts) @@ -1377,7 +1396,7 @@ qdel(part) else - dna.species.create_organs(src) + dna.species.create_organs(src, missing_bodyparts) for(var/obj/item/thing in kept_items) var/equipped = equip_to_slot_if_possible(thing, kept_items[thing]) diff --git a/code/modules/mob/living/carbon/human/species/_species.dm b/code/modules/mob/living/carbon/human/species/_species.dm index 5808f42bfca..3e931181150 100644 --- a/code/modules/mob/living/carbon/human/species/_species.dm +++ b/code/modules/mob/living/carbon/human/species/_species.dm @@ -190,7 +190,15 @@ var/datum/language/species_language = GLOB.all_languages[language] return species_language.get_random_name(gender) -/datum/species/proc/create_organs(mob/living/carbon/human/H) //Handles creation of mob organs. + +/** + * Handles creation of mob organs. + * + * Arguments: + * * H: The human to create organs inside of + * * bodyparts_to_omit: Any bodyparts in this list (and organs within them) should not be added. + */ +/datum/species/proc/create_organs(mob/living/carbon/human/H, list/bodyparts_to_omit) //Handles creation of mob organs. QDEL_LIST_CONTENTS(H.internal_organs) QDEL_LIST_CONTENTS(H.bodyparts) @@ -198,21 +206,29 @@ LAZYREINITLIST(H.bodyparts_by_name) LAZYREINITLIST(H.internal_organs) - for(var/limb_type in has_limbs) - var/list/organ_data = has_limbs[limb_type] + for(var/limb_name in has_limbs) + if(bodyparts_to_omit && (limb_name in bodyparts_to_omit)) + H.bodyparts_by_name[limb_name] = null // Null it out, but leave the name here so it's still "there" + continue + var/list/organ_data = has_limbs[limb_name] var/limb_path = organ_data["path"] var/obj/item/organ/O = new limb_path(H) organ_data["descriptor"] = O.name for(var/index in has_organ) - var/organ = has_organ[index] - // organ new code calls `insert` on its own - new organ(H) + var/obj/item/organ/internal/organ_path = has_organ[index] + if(initial(organ_path.parent_organ) in bodyparts_to_omit) + continue + + var/obj/item/organ/internal/org = new organ_path() + org.insert(H) create_mutant_organs(H) for(var/name in H.bodyparts_by_name) - H.bodyparts |= H.bodyparts_by_name[name] + var/part_type = H.bodyparts_by_name[name] + if(!isnull(part_type)) + H.bodyparts |= part_type // we do not want nulls here, even though it's alright to have them in bodyparts_by_name for(var/obj/item/organ/external/E as anything in H.bodyparts) E.owner = H @@ -221,10 +237,15 @@ /datum/species/proc/create_mutant_organs(mob/living/carbon/human/H) var/obj/item/organ/internal/ears/ears = H.get_int_organ(/obj/item/organ/internal/ears) if(ears) + if(istype(ears, mutantears)) + // if they're the same, just heal them and don't bother replacing them + ears.rejuvenate() + return qdel(ears) - if(mutantears) - ears = new mutantears(H) + if(mutantears && !isnull(H.bodyparts_by_name[initial(mutantears.parent_organ)])) + var/obj/item/organ/internal/ears/new_ears = new mutantears() + new_ears.insert(H) /datum/species/proc/breathe(mob/living/carbon/human/H) if(HAS_TRAIT(H, TRAIT_NOBREATH)) diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index b8a2b492ed2..d3257eff6b5 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -1,6 +1,6 @@ /mob/living/carbon/human/proc/monkeyize() var/mob/H = src - H.dna.SetSEState(GLOB.monkeyblock,1) + H.dna.SetSEState(GLOB.monkeyblock, 1) singlemutcheck(H, GLOB.monkeyblock, MUTCHK_FORCED) /mob/new_player/AIize()