From 2444c0818e2c419675837ee18b2d16a083aaf9d1 Mon Sep 17 00:00:00 2001 From: TheOneAndOnlyCreeperJoe Date: Wed, 29 Jul 2026 19:10:44 +0200 Subject: [PATCH 01/10] Removes the for-loop that adds all features. Added support for preserving tails on tail-mobs for the future. --- code/modules/mob/living/carbon/human/dummy.dm | 2 ++ .../organs/mutant_bodypart_overlay.dm | 4 ++++ .../modular_customization/preferences/tail.dm | 17 ++++++++++++----- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/code/modules/mob/living/carbon/human/dummy.dm b/code/modules/mob/living/carbon/human/dummy.dm index ae9bf923f34b9f..43dfa73c5d24ee 100644 --- a/code/modules/mob/living/carbon/human/dummy.dm +++ b/code/modules/mob/living/carbon/human/dummy.dm @@ -113,8 +113,10 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) /proc/create_consistent_human_dna(mob/living/carbon/human/target) target.dna.features[FEATURE_MUTANT_COLOR] = COLOR_VIBRANT_LIME target.dna.features[FEATURE_ETHEREAL_COLOR] = COLOR_WHITE + /* DOPPLER REMOVAL START - Removes applying ALL consistent features just because they exist for(var/feature_key in SSaccessories.feature_list) target.dna.features[feature_key] = get_consistent_feature_entry(SSaccessories.feature_list[feature_key]) + DOPPLER REMOVAL END */ // DOPPLER ADDITION START - Fix tri color features in dummies target.dna.features[FEATURE_EARS_COLORS] = DEFAULT_MATRIXED_FEATURE_COLORS target.dna.features[FEATURE_MARKINGS_COLORS] = DEFAULT_MATRIXED_FEATURE_COLORS diff --git a/modular_doppler/modular_customization/organs/mutant_bodypart_overlay.dm b/modular_doppler/modular_customization/organs/mutant_bodypart_overlay.dm index 99b935dfdb84f5..08ed82df504320 100644 --- a/modular_doppler/modular_customization/organs/mutant_bodypart_overlay.dm +++ b/modular_doppler/modular_customization/organs/mutant_bodypart_overlay.dm @@ -132,5 +132,9 @@ /datum/bodypart_overlay/mutant/proc/get_feature_key_for_overlay() return sprite_datum?.key || feature_key +/// Returns the DNA feature which controls whether this organ's overlay is present, favoring doppler's version and falling back to the og. +/obj/item/organ/proc/get_bodypart_overlay_dna_feature_key() + return bodypart_overlay?.special_feature_key || bodypart_overlay?.feature_key + #undef MAX_MATRIXED_COLORS #undef ALPHA_OPAQUE diff --git a/modular_doppler/modular_customization/preferences/tail.dm b/modular_doppler/modular_customization/preferences/tail.dm index 7a8c02c4505691..cf7c66e05b8b6b 100644 --- a/modular_doppler/modular_customization/preferences/tail.dm +++ b/modular_doppler/modular_customization/preferences/tail.dm @@ -9,23 +9,25 @@ if(!ishuman(target)) return - if(can_regenerate_mutant_feature(FEATURE_TAIL_LIZARD) && target.dna.features[FEATURE_TAIL_LIZARD] != /datum/sprite_accessory/blank::name) + // Because we both have None & Null as possible values we check target.dna.features twice. First for null, then afterwards for "None" + // can_regenerate_mutant_feature() is used to prevent giving mutant parts to species on GLOB.species_blacklist_no_mutant + if(target.dna.features[FEATURE_TAIL_LIZARD] && can_regenerate_mutant_feature(FEATURE_TAIL_LIZARD) && target.dna.features[FEATURE_TAIL_LIZARD] != /datum/sprite_accessory/blank::name) var/obj/item/organ/replacement = SSwardrobe.provide_type(/obj/item/organ/tail/lizard) replacement.Insert(target, special = TRUE, movement_flags = DELETE_IF_REPLACED) return . - else if(can_regenerate_mutant_feature(FEATURE_TAIL_CAT) && target.dna.features[FEATURE_TAIL_CAT] != /datum/sprite_accessory/blank::name) + else if(target.dna.features[FEATURE_TAIL_CAT] && can_regenerate_mutant_feature(FEATURE_TAIL_CAT) && target.dna.features[FEATURE_TAIL_CAT] != /datum/sprite_accessory/blank::name) var/obj/item/organ/replacement = SSwardrobe.provide_type(/obj/item/organ/tail/cat) replacement.Insert(target, special = TRUE, movement_flags = DELETE_IF_REPLACED) return . - else if(can_regenerate_mutant_feature(FEATURE_TAIL_MONKEY) && target.dna.features[FEATURE_TAIL_MONKEY] != /datum/sprite_accessory/blank::name) + else if(target.dna.features[FEATURE_TAIL_MONKEY] && can_regenerate_mutant_feature(FEATURE_TAIL_MONKEY) && target.dna.features[FEATURE_TAIL_MONKEY] != /datum/sprite_accessory/blank::name) var/obj/item/organ/replacement = SSwardrobe.provide_type(/obj/item/organ/tail/monkey) replacement.Insert(target, special = TRUE, movement_flags = DELETE_IF_REPLACED) return . - else if(can_regenerate_mutant_feature(FEATURE_TAIL_FISH) && target.dna.features[FEATURE_TAIL_FISH] != /datum/sprite_accessory/blank::name) + else if(target.dna.features[FEATURE_TAIL_FISH] && can_regenerate_mutant_feature(FEATURE_TAIL_FISH) && target.dna.features[FEATURE_TAIL_FISH] != /datum/sprite_accessory/blank::name) var/obj/item/organ/replacement = SSwardrobe.provide_type(/obj/item/organ/tail/fish) replacement.Insert(target, special = TRUE, movement_flags = DELETE_IF_REPLACED) return . - else if((can_regenerate_mutant_feature(FEATURE_TAIL_OTHER) && target.dna.features[FEATURE_TAIL_OTHER] != /datum/sprite_accessory/blank::name) && (target.dna.tail_type != NO_VARIATION)) + else if((target.dna.features[FEATURE_TAIL_OTHER] && can_regenerate_mutant_feature(FEATURE_TAIL_OTHER) && target.dna.features[FEATURE_TAIL_OTHER] != /datum/sprite_accessory/blank::name) && (target.dna.tail_type != NO_VARIATION)) var/obj/item/organ/organ_path = text2path("/obj/item/organ/tail/[target.dna.tail_type]") var/obj/item/organ/replacement = SSwardrobe.provide_type(organ_path) replacement.Insert(target, special = TRUE, movement_flags = DELETE_IF_REPLACED) @@ -33,6 +35,11 @@ var/obj/item/organ/tail/old_part = target.get_organ_slot(ORGAN_SLOT_EXTERNAL_TAIL) if(istype(old_part)) + // Keep an already-applied species tail (e.g regenerate_organs() for lizards) when no DNA-specific tail is appleid. + var/obj/item/organ/intrinsic_tail_type = get_mutant_organ_type_for_slot(ORGAN_SLOT_EXTERNAL_TAIL) + var/intrinsic_tail_feature_key = old_part.get_bodypart_overlay_dna_feature_key() + if(intrinsic_tail_type == old_part.type && (!intrinsic_tail_feature_key || isnull(target.dna.features[intrinsic_tail_feature_key]))) + return . old_part.Remove(target, special = TRUE, movement_flags = DELETE_IF_REPLACED) old_part.moveToNullspace() From 744fa486b357ab00fab2b9961560ddc71f7a2350 Mon Sep 17 00:00:00 2001 From: TheOneAndOnlyCreeperJoe Date: Wed, 29 Jul 2026 21:12:40 +0200 Subject: [PATCH 02/10] Works functionally for now: see if I can improve it. --- .../organs/mutant_bodypart_overlay.dm | 2 +- .../modular_customization/preferences/tail.dm | 48 ++++++++++++++----- 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/modular_doppler/modular_customization/organs/mutant_bodypart_overlay.dm b/modular_doppler/modular_customization/organs/mutant_bodypart_overlay.dm index 08ed82df504320..506b32f8b91779 100644 --- a/modular_doppler/modular_customization/organs/mutant_bodypart_overlay.dm +++ b/modular_doppler/modular_customization/organs/mutant_bodypart_overlay.dm @@ -132,7 +132,7 @@ /datum/bodypart_overlay/mutant/proc/get_feature_key_for_overlay() return sprite_datum?.key || feature_key -/// Returns the DNA feature which controls whether this organ's overlay is present, favoring doppler's version and falling back to the og. +/// Returns the DNA feature which controls whether this organ's overlay is present. /obj/item/organ/proc/get_bodypart_overlay_dna_feature_key() return bodypart_overlay?.special_feature_key || bodypart_overlay?.feature_key diff --git a/modular_doppler/modular_customization/preferences/tail.dm b/modular_doppler/modular_customization/preferences/tail.dm index cf7c66e05b8b6b..c50512802b8725 100644 --- a/modular_doppler/modular_customization/preferences/tail.dm +++ b/modular_doppler/modular_customization/preferences/tail.dm @@ -1,11 +1,37 @@ /datum/dna /// This variable is read by the regenerate_organs() proc to know what organ subtype to give - var/tail_type = NO_VARIATION + /// Null until a tail choice is applied, NO_VARIATION for an explicit opt-out, or a tail category to generate. + var/tail_type /datum/species/regenerate_organs(mob/living/carbon/target, datum/species/old_species, replace_current = TRUE, list/excluded_zones, visual_only = FALSE, replace_missing = TRUE) - . = ..() if(target == null) - return + return ..() + + // This is a little roundabout: the normal organ code needs the correct DNA entry before it will add a tail, but the tail object itself tells us which DNA entry it uses. I don't know why we do it like this; but here we are. + // Check the mob's current tail when possible, or briefly take a matching one from the wardrobe cache, then fill in the species default before calling the normal organ code below. + // If we do not do this, generic mobs without player preferences will not get a tail when their species should (currently this is only lavaland corpses, but future-proofing doesn't hurt). + var/obj/item/organ/species_tail_type = get_mutant_organ_type_for_slot(ORGAN_SLOT_EXTERNAL_TAIL) + var/use_species_default_tail = FALSE + if(species_tail_type && isnull(target.dna.tail_type)) // isnull() is always false here for mobs with prefs and mobs without a tail, so this is only true for mobs with a species default tail and no player preference. + var/default_tail_appearance = mutant_organs[species_tail_type] + var/obj/item/organ/tail_to_check = target.get_organ_slot(ORGAN_SLOT_EXTERNAL_TAIL) + // We need a real tail object to find which DNA entry controls it. If the mob does not have the right tail yet, take a temporary one from the wardrobe cache for this check. + var/using_temporary_tail = !istype(tail_to_check, species_tail_type) + if(using_temporary_tail) + tail_to_check = SSwardrobe.provide_type(species_tail_type) + var/tail_feature_key = tail_to_check.get_bodypart_overlay_dna_feature_key() + if(tail_feature_key && default_tail_appearance) + target.dna.features[tail_feature_key] = default_tail_appearance + use_species_default_tail = TRUE + // Put the temporary tail back. The parent call below will add the mob's real tail. + if(using_temporary_tail) + SSwardrobe.stash_object(tail_to_check) + + . = ..() + // The parent has now handled the species' usual tail. The customization branches below are only for player-prefs tail choices, including an explicit preference to have no tail. + if(use_species_default_tail) + return . + if(!ishuman(target)) return @@ -27,7 +53,7 @@ var/obj/item/organ/replacement = SSwardrobe.provide_type(/obj/item/organ/tail/fish) replacement.Insert(target, special = TRUE, movement_flags = DELETE_IF_REPLACED) return . - else if((target.dna.features[FEATURE_TAIL_OTHER] && can_regenerate_mutant_feature(FEATURE_TAIL_OTHER) && target.dna.features[FEATURE_TAIL_OTHER] != /datum/sprite_accessory/blank::name) && (target.dna.tail_type != NO_VARIATION)) + else if((target.dna.features[FEATURE_TAIL_OTHER] && can_regenerate_mutant_feature(FEATURE_TAIL_OTHER) && target.dna.features[FEATURE_TAIL_OTHER] != /datum/sprite_accessory/blank::name) && (target.dna.tail_type && target.dna.tail_type != NO_VARIATION)) var/obj/item/organ/organ_path = text2path("/obj/item/organ/tail/[target.dna.tail_type]") var/obj/item/organ/replacement = SSwardrobe.provide_type(organ_path) replacement.Insert(target, special = TRUE, movement_flags = DELETE_IF_REPLACED) @@ -35,11 +61,6 @@ var/obj/item/organ/tail/old_part = target.get_organ_slot(ORGAN_SLOT_EXTERNAL_TAIL) if(istype(old_part)) - // Keep an already-applied species tail (e.g regenerate_organs() for lizards) when no DNA-specific tail is appleid. - var/obj/item/organ/intrinsic_tail_type = get_mutant_organ_type_for_slot(ORGAN_SLOT_EXTERNAL_TAIL) - var/intrinsic_tail_feature_key = old_part.get_bodypart_overlay_dna_feature_key() - if(intrinsic_tail_type == old_part.type && (!intrinsic_tail_feature_key || isnull(target.dna.features[intrinsic_tail_feature_key]))) - return . old_part.Remove(target, special = TRUE, movement_flags = DELETE_IF_REPLACED) old_part.moveToNullspace() @@ -722,8 +743,9 @@ feature_key_sprite = "tail" /datum/bodypart_overlay/mutant/tail/color_images(list/image/overlays, layer, obj/item/bodypart/limb) - if((sprite_datum.color_src == USE_ONE_COLOR) && length(limb.owner?.dna.features[FEATURE_TAIL_COLORS])) - draw_color = limb.owner?.dna.features[FEATURE_TAIL_COLORS][1] - else - draw_color = limb.owner?.dna.features[FEATURE_TAIL_COLORS] + var/list/tail_colors = limb.owner?.dna.features[FEATURE_TAIL_COLORS] + // Preference colors override the tail's inherited limb color. Generic mobs do not have this + // preference data, so retaining draw_color makes their native tail match their mutant color. + if(length(tail_colors)) + draw_color = sprite_datum.color_src == USE_ONE_COLOR ? tail_colors[1] : tail_colors return ..() From 9a75072d63046533735da30a9153cb16177efb73 Mon Sep 17 00:00:00 2001 From: TheOneAndOnlyCreeperJoe Date: Wed, 29 Jul 2026 21:26:00 +0200 Subject: [PATCH 03/10] crops it down and gets rid of the wardrobe workaround --- .../organs/mutant_bodypart_overlay.dm | 11 +++++-- .../modular_customization/preferences/tail.dm | 29 +++++++------------ 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/modular_doppler/modular_customization/organs/mutant_bodypart_overlay.dm b/modular_doppler/modular_customization/organs/mutant_bodypart_overlay.dm index 506b32f8b91779..bbca7d09b4c71f 100644 --- a/modular_doppler/modular_customization/organs/mutant_bodypart_overlay.dm +++ b/modular_doppler/modular_customization/organs/mutant_bodypart_overlay.dm @@ -132,9 +132,14 @@ /datum/bodypart_overlay/mutant/proc/get_feature_key_for_overlay() return sprite_datum?.key || feature_key -/// Returns the DNA feature which controls whether this organ's overlay is present. -/obj/item/organ/proc/get_bodypart_overlay_dna_feature_key() - return bodypart_overlay?.special_feature_key || bodypart_overlay?.feature_key +/// Returns the DNA feature which controls whether an organ type's overlay is present. +/proc/get_bodypart_overlay_dna_feature_key_from_type(obj/item/organ/organ_type) + if(isnull(organ_type)) + return null + var/datum/bodypart_overlay/mutant/overlay_type = initial(organ_type.bodypart_overlay) + if(isnull(overlay_type)) + return null + return initial(overlay_type.special_feature_key) || initial(overlay_type.feature_key) #undef MAX_MATRIXED_COLORS #undef ALPHA_OPAQUE diff --git a/modular_doppler/modular_customization/preferences/tail.dm b/modular_doppler/modular_customization/preferences/tail.dm index c50512802b8725..f82b90242aeaaa 100644 --- a/modular_doppler/modular_customization/preferences/tail.dm +++ b/modular_doppler/modular_customization/preferences/tail.dm @@ -7,25 +7,18 @@ if(target == null) return ..() - // This is a little roundabout: the normal organ code needs the correct DNA entry before it will add a tail, but the tail object itself tells us which DNA entry it uses. I don't know why we do it like this; but here we are. - // Check the mob's current tail when possible, or briefly take a matching one from the wardrobe cache, then fill in the species default before calling the normal organ code below. - // If we do not do this, generic mobs without player preferences will not get a tail when their species should (currently this is only lavaland corpses, but future-proofing doesn't hurt). - var/obj/item/organ/species_tail_type = get_mutant_organ_type_for_slot(ORGAN_SLOT_EXTERNAL_TAIL) + // The normal organ code will not add a tail while its DNA feature is set to "None". + // Read which feature the species' tail overlay uses directly from its type, then set that feature to the species default before calling the normal organ code below. + // Without this, generic mobs without player preferences will not get a tail when their species should. var/use_species_default_tail = FALSE - if(species_tail_type && isnull(target.dna.tail_type)) // isnull() is always false here for mobs with prefs and mobs without a tail, so this is only true for mobs with a species default tail and no player preference. - var/default_tail_appearance = mutant_organs[species_tail_type] - var/obj/item/organ/tail_to_check = target.get_organ_slot(ORGAN_SLOT_EXTERNAL_TAIL) - // We need a real tail object to find which DNA entry controls it. If the mob does not have the right tail yet, take a temporary one from the wardrobe cache for this check. - var/using_temporary_tail = !istype(tail_to_check, species_tail_type) - if(using_temporary_tail) - tail_to_check = SSwardrobe.provide_type(species_tail_type) - var/tail_feature_key = tail_to_check.get_bodypart_overlay_dna_feature_key() - if(tail_feature_key && default_tail_appearance) - target.dna.features[tail_feature_key] = default_tail_appearance - use_species_default_tail = TRUE - // Put the temporary tail back. The parent call below will add the mob's real tail. - if(using_temporary_tail) - SSwardrobe.stash_object(tail_to_check) + if(isnull(target.dna.tail_type)) // always false when the target has prefs + var/obj/item/organ/species_tail_type = get_mutant_organ_type_for_slot(ORGAN_SLOT_EXTERNAL_TAIL) + if(species_tail_type) // always false when a mob doesn't have a tail + var/default_tail_appearance = mutant_organs[species_tail_type] + var/tail_feature_key = get_bodypart_overlay_dna_feature_key_from_type(species_tail_type) + if(tail_feature_key && default_tail_appearance) + target.dna.features[tail_feature_key] = default_tail_appearance + use_species_default_tail = TRUE . = ..() // The parent has now handled the species' usual tail. The customization branches below are only for player-prefs tail choices, including an explicit preference to have no tail. From 5cd47e6ddf0c3ec6941e99a770ac890867192662 Mon Sep 17 00:00:00 2001 From: TheOneAndOnlyCreeperJoe Date: Wed, 29 Jul 2026 21:33:55 +0200 Subject: [PATCH 04/10] clarifying comment --- modular_doppler/modular_customization/preferences/tail.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modular_doppler/modular_customization/preferences/tail.dm b/modular_doppler/modular_customization/preferences/tail.dm index f82b90242aeaaa..f440ae4fc10c4a 100644 --- a/modular_doppler/modular_customization/preferences/tail.dm +++ b/modular_doppler/modular_customization/preferences/tail.dm @@ -13,7 +13,7 @@ var/use_species_default_tail = FALSE if(isnull(target.dna.tail_type)) // always false when the target has prefs var/obj/item/organ/species_tail_type = get_mutant_organ_type_for_slot(ORGAN_SLOT_EXTERNAL_TAIL) - if(species_tail_type) // always false when a mob doesn't have a tail + if(species_tail_type) // always false when a species doesn't normally have a tail var/default_tail_appearance = mutant_organs[species_tail_type] var/tail_feature_key = get_bodypart_overlay_dna_feature_key_from_type(species_tail_type) if(tail_feature_key && default_tail_appearance) From 494a186c47852143f83eec58ffa55c86f5626c0f Mon Sep 17 00:00:00 2001 From: TheOneAndOnlyCreeperJoe Date: Wed, 29 Jul 2026 23:45:40 +0200 Subject: [PATCH 05/10] fixes tail spines breaking everything --- code/modules/surgery/organs/external/tails.dm | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/code/modules/surgery/organs/external/tails.dm b/code/modules/surgery/organs/external/tails.dm index 7a1bb998a2537f..f387d557c94726 100644 --- a/code/modules/surgery/organs/external/tails.dm +++ b/code/modules/surgery/organs/external/tails.dm @@ -71,9 +71,16 @@ if(!tail_spine_key) return + /* DOPPLER ADDITION START - Fixes tail spines throwing runtimes when spawning humanoid mobs/corpses with tails + * The tail spines overlay is dependent on the owner's DNA, which may not be set yet. + * If the owner doesn't have a valid DNA, don't insert the tail spines overlay.*/ + var/obj/item/organ/spines/owner_spines = bodypart.owner.get_organ_slot(ORGAN_SLOT_EXTERNAL_SPINES) + var/feature_name = bodypart.owner.dna.features[FEATURE_SPINES] || bodypart.owner.dna.species.mutant_organs[owner_spines?.type] + if(!feature_name || feature_name == SPRITE_ACCESSORY_NONE) + return + /* DOPPLER ADDITION END */ tail_spines_overlay = new tail_spines_overlay.tail_spine_key = tail_spine_key - var/feature_name = bodypart.owner.dna.features[FEATURE_SPINES] //tail spines don't live in DNA, but share feature names with regular spines tail_spines_overlay.set_appearance_from_name(feature_name) bodypart.add_bodypart_overlay(tail_spines_overlay) From 11e294652d87f20a853065b2368a51083dfc7eae Mon Sep 17 00:00:00 2001 From: TheOneAndOnlyCreeperJoe Date: Thu, 30 Jul 2026 00:25:57 +0200 Subject: [PATCH 06/10] forgot a doppler edit --- code/modules/surgery/organs/external/tails.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/modules/surgery/organs/external/tails.dm b/code/modules/surgery/organs/external/tails.dm index f387d557c94726..603f12bbfc9712 100644 --- a/code/modules/surgery/organs/external/tails.dm +++ b/code/modules/surgery/organs/external/tails.dm @@ -81,6 +81,7 @@ /* DOPPLER ADDITION END */ tail_spines_overlay = new tail_spines_overlay.tail_spine_key = tail_spine_key + //DOPPLER REMOVAL: var/feature_name = bodypart.owner.dna.features[FEATURE_SPINES] //tail spines don't live in DNA, but share feature names with regular spines tail_spines_overlay.set_appearance_from_name(feature_name) bodypart.add_bodypart_overlay(tail_spines_overlay) From 8bc3dda5e5233ae51306db1c6636bf8cefaaa317 Mon Sep 17 00:00:00 2001 From: TheOneAndOnlyCreeperJoe Date: Thu, 30 Jul 2026 17:00:43 +0200 Subject: [PATCH 07/10] Comments out a stack trace that is not compatible with Doppler's mutant parts. --- code/datums/bodypart_overlays/mutant_bodypart_overlay.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/datums/bodypart_overlays/mutant_bodypart_overlay.dm b/code/datums/bodypart_overlays/mutant_bodypart_overlay.dm index a1d06086f74c5a..d26536ca85a86f 100644 --- a/code/datums/bodypart_overlays/mutant_bodypart_overlay.dm +++ b/code/datums/bodypart_overlays/mutant_bodypart_overlay.dm @@ -35,7 +35,7 @@ if(imprint_on_next_insertion) //We only want this set *once* var/feature_name = receiver.dna.features[feature_key] || receiver.dna.species.mutant_organs[parent.type] if (isnull(feature_name)) - stack_trace("[type] has no default feature name for organ [parent.type]!") + // DOPPLER REMOVAL (stack_trace works off of mutant part assumptions that aren't compatible with our own mutant part system) - stack_trace("[type] has no default feature name for organ [parent.type]!") feature_name = get_consistent_feature_entry(get_global_feature_list()) //fallback to something set_appearance_from_name(feature_name) imprint_on_next_insertion = FALSE From 5bd8174e3400b2b9b8383dc56cc9d9903996f1b8 Mon Sep 17 00:00:00 2001 From: TheOneAndOnlyCreeperJoe Date: Thu, 30 Jul 2026 17:07:20 +0200 Subject: [PATCH 08/10] Undoes the tailspines fix because it was solving the same problem. --- code/modules/surgery/organs/external/tails.dm | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/code/modules/surgery/organs/external/tails.dm b/code/modules/surgery/organs/external/tails.dm index 603f12bbfc9712..7a1bb998a2537f 100644 --- a/code/modules/surgery/organs/external/tails.dm +++ b/code/modules/surgery/organs/external/tails.dm @@ -71,17 +71,9 @@ if(!tail_spine_key) return - /* DOPPLER ADDITION START - Fixes tail spines throwing runtimes when spawning humanoid mobs/corpses with tails - * The tail spines overlay is dependent on the owner's DNA, which may not be set yet. - * If the owner doesn't have a valid DNA, don't insert the tail spines overlay.*/ - var/obj/item/organ/spines/owner_spines = bodypart.owner.get_organ_slot(ORGAN_SLOT_EXTERNAL_SPINES) - var/feature_name = bodypart.owner.dna.features[FEATURE_SPINES] || bodypart.owner.dna.species.mutant_organs[owner_spines?.type] - if(!feature_name || feature_name == SPRITE_ACCESSORY_NONE) - return - /* DOPPLER ADDITION END */ tail_spines_overlay = new tail_spines_overlay.tail_spine_key = tail_spine_key - //DOPPLER REMOVAL: var/feature_name = bodypart.owner.dna.features[FEATURE_SPINES] //tail spines don't live in DNA, but share feature names with regular spines + var/feature_name = bodypart.owner.dna.features[FEATURE_SPINES] //tail spines don't live in DNA, but share feature names with regular spines tail_spines_overlay.set_appearance_from_name(feature_name) bodypart.add_bodypart_overlay(tail_spines_overlay) From 68a003a42738fbe6086df0c801856b0fd52812bf Mon Sep 17 00:00:00 2001 From: TheOneAndOnlyCreeperJoe Date: Thu, 30 Jul 2026 17:52:34 +0200 Subject: [PATCH 09/10] redos the tail_spines change because apparently I was wrong --- code/modules/surgery/organs/external/tails.dm | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/code/modules/surgery/organs/external/tails.dm b/code/modules/surgery/organs/external/tails.dm index 7a1bb998a2537f..603f12bbfc9712 100644 --- a/code/modules/surgery/organs/external/tails.dm +++ b/code/modules/surgery/organs/external/tails.dm @@ -71,9 +71,17 @@ if(!tail_spine_key) return + /* DOPPLER ADDITION START - Fixes tail spines throwing runtimes when spawning humanoid mobs/corpses with tails + * The tail spines overlay is dependent on the owner's DNA, which may not be set yet. + * If the owner doesn't have a valid DNA, don't insert the tail spines overlay.*/ + var/obj/item/organ/spines/owner_spines = bodypart.owner.get_organ_slot(ORGAN_SLOT_EXTERNAL_SPINES) + var/feature_name = bodypart.owner.dna.features[FEATURE_SPINES] || bodypart.owner.dna.species.mutant_organs[owner_spines?.type] + if(!feature_name || feature_name == SPRITE_ACCESSORY_NONE) + return + /* DOPPLER ADDITION END */ tail_spines_overlay = new tail_spines_overlay.tail_spine_key = tail_spine_key - var/feature_name = bodypart.owner.dna.features[FEATURE_SPINES] //tail spines don't live in DNA, but share feature names with regular spines + //DOPPLER REMOVAL: var/feature_name = bodypart.owner.dna.features[FEATURE_SPINES] //tail spines don't live in DNA, but share feature names with regular spines tail_spines_overlay.set_appearance_from_name(feature_name) bodypart.add_bodypart_overlay(tail_spines_overlay) From adf2aa41393e3a3c670d7ed86b65aaec095158cd Mon Sep 17 00:00:00 2001 From: TheOneAndOnlyCreeperJoe Date: Thu, 30 Jul 2026 18:40:51 +0200 Subject: [PATCH 10/10] changes on_mob_insert to use special_feature_key instead where possible. --- code/datums/bodypart_overlays/mutant_bodypart_overlay.dm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/code/datums/bodypart_overlays/mutant_bodypart_overlay.dm b/code/datums/bodypart_overlays/mutant_bodypart_overlay.dm index d26536ca85a86f..6bbe3e076ed049 100644 --- a/code/datums/bodypart_overlays/mutant_bodypart_overlay.dm +++ b/code/datums/bodypart_overlays/mutant_bodypart_overlay.dm @@ -33,7 +33,10 @@ stack_trace("adding a [parent.type] to a [receiver.type] when it shouldn't be!") if(imprint_on_next_insertion) //We only want this set *once* - var/feature_name = receiver.dna.features[feature_key] || receiver.dna.species.mutant_organs[parent.type] + /* DOPPLER EDIT START - Uses special_feature_key from modular instead of normal feature_keys */ + var/dna_feature_key = special_feature_key || feature_key + var/feature_name = receiver.dna.features[dna_feature_key] || receiver.dna.species.mutant_organs[parent.type] // originally: var/feature_name = receiver.dna.features[feature_key] || receiver.dna.species.mutant_organs[parent.type] + /* DOPPLER EDIT END */ if (isnull(feature_name)) // DOPPLER REMOVAL (stack_trace works off of mutant part assumptions that aren't compatible with our own mutant part system) - stack_trace("[type] has no default feature name for organ [parent.type]!") feature_name = get_consistent_feature_entry(get_global_feature_list()) //fallback to something