diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm
index 0d9d28d4d858a..517435fc74557 100644
--- a/code/__DEFINES/is_helpers.dm
+++ b/code/__DEFINES/is_helpers.dm
@@ -101,7 +101,7 @@ GLOBAL_LIST_INIT(turfs_pass_meteor, typecacheof(list(
//Human sub-species
#define isabductor(A) (is_species(A, /datum/species/abductor))
#define isgolem(A) (is_species(A, /datum/species/golem))
-#define islizard(A) (is_species(A, /datum/species/lizard))
+#define islizard(A) (is_species(A, /datum/species/lizard) || HAS_TRAIT(A, TRAIT_REPTILE)) // Doppler edit, animal trait - old code: #define islizard(A) (is_species(A, /datum/species/lizard))
#define isashwalker(A) (is_species(A, /datum/species/lizard/ashwalker))
#define isplasmaman(A) (is_species(A, /datum/species/plasmaman))
#define ispodperson(A) (is_species(A, /datum/species/pod))
@@ -111,11 +111,11 @@ GLOBAL_LIST_INIT(turfs_pass_meteor, typecacheof(list(
#define iszombie(A) (is_species(A, /datum/species/zombie))
#define isskeleton(A) (is_species(A, /datum/species/skeleton))
#define ismoth(A) (is_species(A, /datum/species/moth))
-#define isfelinid(A) (is_species(A, /datum/species/human/felinid))
+#define isfelinid(A) (is_species(A, /datum/species/human/felinid) || HAS_TRAIT(A, TRAIT_FELINE)) // Doppler edit, animal trait - old code: #define isfelinid(A) (is_species(A, /datum/species/human/felinid))
#define isethereal(A) (is_species(A, /datum/species/ethereal))
#define isvampire(A) (is_species(A,/datum/species/vampire))
#define isdullahan(A) (is_species(A, /datum/species/dullahan))
-#define ismonkey(A) (is_species(A, /datum/species/monkey))
+#define ismonkey(A) (is_species(A, /datum/species/monkey) || HAS_TRAIT(A, TRAIT_SIMIAN)) // Doppler edit, animal trait - old code: #define ismonkey(A) (is_species(A, /datum/species/monkey))
#define isandroid(A) (is_species(A, /datum/species/android))
#define isnightmare(A) (is_species(A, /datum/species/shadow/nightmare))
diff --git a/code/__DEFINES/~doppler_defines/is_helpers.dm b/code/__DEFINES/~doppler_defines/is_helpers.dm
index ec8c01e36274c..2d0e0a7556b91 100644
--- a/code/__DEFINES/~doppler_defines/is_helpers.dm
+++ b/code/__DEFINES/~doppler_defines/is_helpers.dm
@@ -1,4 +1,4 @@
//Species
-#define isprimitivedemihuman(A) (is_species(A, /datum/species/human/felinid/primitive))
-//Customization bases
-#define isfeline(A) (isfelinid(A) || HAS_TRAIT(A, TRAIT_FELINE))
+#define isprimitivedemihuman(A) (is_species(A, /datum/species/human/kemonomimi/primitive))
+#define isslugcat(A) (is_species(A, /datum/species/slugcat))
+
diff --git a/code/__DEFINES/~doppler_defines/mobs.dm b/code/__DEFINES/~doppler_defines/mobs.dm
new file mode 100644
index 0000000000000..824daddc9dbd2
--- /dev/null
+++ b/code/__DEFINES/~doppler_defines/mobs.dm
@@ -0,0 +1,2 @@
+// Defines for Species IDs. Used to refer to the name of a species, for things like bodypart names or species preferences.
+#define SPECIES_KEMONOMIMI "kemonomimi"
diff --git a/code/__DEFINES/~doppler_defines/traits.dm b/code/__DEFINES/~doppler_defines/traits.dm
index 2c9804211f5a6..876139ea4c00a 100644
--- a/code/__DEFINES/~doppler_defines/traits.dm
+++ b/code/__DEFINES/~doppler_defines/traits.dm
@@ -1,11 +1,6 @@
/// trait that lets you do xenoarch magnification
#define TRAIT_XENOARCH_QUALIFIED "trait_xenoarch_qualified"
-
/// Traits granted by glassblowing
#define TRAIT_GLASSBLOWING "glassblowing"
-
/// Trait that is applied whenever someone or something is glassblowing
#define TRAIT_CURRENTLY_GLASSBLOWING "currently_glassblowing"
-
-// felinid traits
-#define TRAIT_FELINE "feline_aspect"
diff --git a/code/__DEFINES/~doppler_defines/traits/declarations.dm b/code/__DEFINES/~doppler_defines/traits/declarations.dm
new file mode 100644
index 0000000000000..726e36b67de0c
--- /dev/null
+++ b/code/__DEFINES/~doppler_defines/traits/declarations.dm
@@ -0,0 +1,21 @@
+// TRAIT_ANIMALISTIC choices
+#define TRAIT_FELINE "cat" // confirms the isfelinid is_helper
+#define TRAIT_CANINE "dog"
+#define TRAIT_REPTILE "lizard" // confirms the islizard is_helper
+#define TRAIT_LEPORID "bunny"
+#define TRAIT_AVIAN "bird"
+#define TRAIT_MURIDAE "mouse"
+#define TRAIT_PISCINE "fish"
+#define TRAIT_SIMIAN "monkey" // confirms the ismonkey is_helper
+
+/// Every animal trait available for picking roundstart on appropriate species
+GLOBAL_LIST_INIT(animalistic_traits, list(
+ TRAIT_FELINE,
+ TRAIT_CANINE,
+ TRAIT_REPTILE,
+ TRAIT_LEPORID,
+ TRAIT_AVIAN,
+ TRAIT_MURIDAE,
+ TRAIT_PISCINE,
+ TRAIT_SIMIAN,
+))
diff --git a/code/__DEFINES/~doppler_defines/traits/sources.dm b/code/__DEFINES/~doppler_defines/traits/sources.dm
new file mode 100644
index 0000000000000..75f9f91c986f3
--- /dev/null
+++ b/code/__DEFINES/~doppler_defines/traits/sources.dm
@@ -0,0 +1,2 @@
+/// Trait which lets species pick from a list of animal traits, used by kemonomimi and anthromorphs
+#define TRAIT_ANIMALISTIC "animalistic"
diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm
index 0dfcc67c5e1be..bf5212294af53 100644
--- a/code/_globalvars/traits/_traits.dm
+++ b/code/_globalvars/traits/_traits.dm
@@ -661,7 +661,6 @@ GLOBAL_LIST_INIT(traits_by_type, list(
// DOPPLER EDIT ADDITION START - DOPPLER TRAITS
/obj/item/clothing/suit/jacket/doppler = list(
"TRAIT_CURRENTLY_GLASSBLOWING" = TRAIT_CURRENTLY_GLASSBLOWING,
- "TRAIT_FELINE" = TRAIT_FELINE,
"TRAIT_GLASSBLOWING" = TRAIT_GLASSBLOWING,
"TRAIT_XENOARCH_QUALIFIED" = TRAIT_XENOARCH_QUALIFIED,
),
diff --git a/code/_globalvars/traits/admin_tooling.dm b/code/_globalvars/traits/admin_tooling.dm
index 585d121e6ce67..ebc1316c37115 100644
--- a/code/_globalvars/traits/admin_tooling.dm
+++ b/code/_globalvars/traits/admin_tooling.dm
@@ -360,7 +360,6 @@ GLOBAL_LIST_INIT(admin_visible_traits, list(
// DOPPLER EDIT ADDITION START - DOPPLER TRAITS
/obj/item/clothing/suit/jacket/doppler = list(
"TRAIT_CURRENTLY_GLASSBLOWING" = TRAIT_CURRENTLY_GLASSBLOWING,
- "TRAIT_FELINE" = TRAIT_FELINE,
"TRAIT_GLASSBLOWING" = TRAIT_GLASSBLOWING,
"TRAIT_XENOARCH_QUALIFIED" = TRAIT_XENOARCH_QUALIFIED,
),
diff --git a/code/controllers/subsystem/processing/quirks.dm b/code/controllers/subsystem/processing/quirks.dm
index 1f52c6812021f..45354d4bd6164 100644
--- a/code/controllers/subsystem/processing/quirks.dm
+++ b/code/controllers/subsystem/processing/quirks.dm
@@ -26,9 +26,6 @@ GLOBAL_LIST_INIT_TYPED(quirk_blacklist, /list/datum/quirk, list(
list(/datum/quirk/photophobia, /datum/quirk/nyctophobia),
list(/datum/quirk/item_quirk/settler, /datum/quirk/freerunning),
list(/datum/quirk/numb, /datum/quirk/selfaware),
- //DOPPLER EDIT ADDITION BEGIN
- list(/datum/quirk/feline_aspect)
- //DOPPLER EDIT ADDITION END
))
GLOBAL_LIST_INIT(quirk_string_blacklist, generate_quirk_string_blacklist())
diff --git a/code/controllers/subsystem/sprite_accessories.dm b/code/controllers/subsystem/sprite_accessories.dm
index 8930976610877..1c2ec41385d65 100644
--- a/code/controllers/subsystem/sprite_accessories.dm
+++ b/code/controllers/subsystem/sprite_accessories.dm
@@ -87,7 +87,7 @@ SUBSYSTEM_DEF(accessories) // just 'accessories' for brevity
socks_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/socks)[DEFAULT_SPRITE_LIST]
lizard_markings_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/lizard_markings)[DEFAULT_SPRITE_LIST]
- tails_list_human = init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/human, add_blank = TRUE)[DEFAULT_SPRITE_LIST]
+ tails_list_human = init_sprite_accessory_subtypes(/datum/sprite_accessory/tails, add_blank = TRUE)[DEFAULT_SPRITE_LIST] // DOPPLER EDIT, old code: tails_list_human = init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/human, add_blank = TRUE)[DEFAULT_SPRITE_LIST]
tails_list_lizard = init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/lizard)[DEFAULT_SPRITE_LIST]
tails_list_monkey = init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/monkey)[DEFAULT_SPRITE_LIST]
snouts_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/snouts)[DEFAULT_SPRITE_LIST]
diff --git a/code/game/machinery/computer/dna_console.dm b/code/game/machinery/computer/dna_console.dm
index 41c46c0cb205b..4eba98a9096bd 100644
--- a/code/game/machinery/computer/dna_console.dm
+++ b/code/game/machinery/computer/dna_console.dm
@@ -341,7 +341,7 @@
data["subjectStatus"] = scanner_occupant.stat
data["subjectHealth"] = scanner_occupant.health
data["subjectEnzymes"] = scanner_occupant.dna.unique_enzymes
- data["isMonkey"] = ismonkey(scanner_occupant)
+ data["isMonkey"] = (ismonkey(scanner_occupant) && !HAS_TRAIT(scanner_occupant, TRAIT_SIMIAN)) // Doppler station edit, animal trait. Lets the machine work on trait-havers - old code: data["isMonkey"] = ismonkey(scanner_occupant)
data["subjectUNI"] = scanner_occupant.dna.unique_identity
data["subjectUF"] = scanner_occupant.dna.unique_features
data["storage"]["occupant"] = tgui_occupant_mutations
diff --git a/code/modules/client/preferences/species_features/lizard.dm b/code/modules/client/preferences/species_features/lizard.dm
index 7749b31a8b287..d60363be5e4a5 100644
--- a/code/modules/client/preferences/species_features/lizard.dm
+++ b/code/modules/client/preferences/species_features/lizard.dm
@@ -51,27 +51,14 @@
var/icon/final_icon = icon('icons/mob/human/species/lizard/bodyparts.dmi', "lizard_chest_m")
if (sprite_accessory.icon_state != "none")
- /// DOPPLER SHIFT REMOVAL BEGIN
- /*var/icon/body_markings_icon = icon(
+ var/icon/body_markings_icon = icon(
'icons/mob/human/species/lizard/lizard_misc.dmi',
"male_[sprite_accessory.icon_state]_chest",
)
- final_icon.Blend(body_markings_icon, ICON_OVERLAY)*/
- /// DOPPLER SHIFT REMOVAL END
- /// DOPPLER SHIFT ADDITION BEGIN
- var/icon/markings_icon_1 = icon(sprite_accessory.icon, "male_[sprite_accessory.icon_state]_chest")
- markings_icon_1.Blend(COLOR_RED, ICON_MULTIPLY)
- var/icon/markings_icon_2 = icon(sprite_accessory.icon, "male_[sprite_accessory.icon_state]_chest_2")
- markings_icon_2.Blend(COLOR_VIBRANT_LIME, ICON_MULTIPLY)
- var/icon/markings_icon_3 = icon(sprite_accessory.icon, "male_[sprite_accessory.icon_state]_chest_3")
- markings_icon_3.Blend(COLOR_BLUE, ICON_MULTIPLY)
- final_icon.Blend(markings_icon_1, ICON_OVERLAY)
- final_icon.Blend(markings_icon_2, ICON_OVERLAY)
- final_icon.Blend(markings_icon_3, ICON_OVERLAY)
- /// DOPPLER SHIFT ADDITION END
+ final_icon.Blend(body_markings_icon, ICON_OVERLAY)
- //final_icon.Blend(COLOR_VIBRANT_LIME, ICON_MULTIPLY) /// DOPPLER SHIFT REMOVAL
+ final_icon.Blend(COLOR_VIBRANT_LIME, ICON_MULTIPLY)
final_icon.Crop(10, 8, 22, 23)
final_icon.Scale(26, 32)
final_icon.Crop(-2, 1, 29, 32)
@@ -80,7 +67,7 @@
/datum/preference/choiced/lizard_body_markings/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["lizard_markings"] = value
-
+/* DOPPLER EDIT REMOVAL START
/datum/preference/choiced/lizard_frills
savefile_key = "feature_lizard_frills"
savefile_identifier = PREFERENCE_CHARACTER
@@ -112,7 +99,7 @@
/datum/preference/choiced/lizard_horns/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["horns"] = value
-
+DOPPLER EDIT REMOVAL END */
/datum/preference/choiced/lizard_legs
savefile_key = "feature_lizard_legs"
savefile_identifier = PREFERENCE_CHARACTER
@@ -162,7 +149,7 @@
var/datum/species/species_type = preferences.read_preference(/datum/preference/choiced/species)
return initial(species_type.digitigrade_customization) & DIGITIGRADE_OPTIONAL
-
+/* DOPPLER EDIT REMOVAL START
/datum/preference/choiced/lizard_snout
savefile_key = "feature_lizard_snout"
savefile_identifier = PREFERENCE_CHARACTER
@@ -178,7 +165,7 @@
/datum/preference/choiced/lizard_snout/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["snout"] = value
-
+DOPPLER EDIT REMOVAL END */
/datum/preference/choiced/lizard_spines
savefile_key = "feature_lizard_spines"
savefile_identifier = PREFERENCE_CHARACTER
@@ -190,7 +177,7 @@
/datum/preference/choiced/lizard_spines/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["spines"] = value
-
+/* DOPPLER EDIT REMOVAL START
/datum/preference/choiced/lizard_tail
savefile_key = "feature_lizard_tail"
savefile_identifier = PREFERENCE_CHARACTER
@@ -205,3 +192,4 @@
/datum/preference/choiced/lizard_tail/create_default_value()
return /datum/sprite_accessory/tails/lizard/smooth::name
+DOPPLER EDIT REMOVAL END */
diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm
index 661c5fc7abbcd..4b12e8d42287d 100644
--- a/code/modules/mob/living/carbon/human/_species.dm
+++ b/code/modules/mob/living/carbon/human/_species.dm
@@ -573,7 +573,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
sample_overlay = new overlay_path()
organs_to_randomize[overlay_path] = sample_overlay
- new_features["[sample_overlay.feature_key]"] = sample_overlay.get_random_appearance().name
+ new_features["[sample_overlay.feature_key]"] = /datum/sprite_accessory/blank::name // DOPPLER EDIT - no more random features, old code: new_features["[sample_overlay.feature_key]"] = sample_overlay.get_random_appearance().name
return new_features
diff --git a/code/modules/mob/living/carbon/human/dummy.dm b/code/modules/mob/living/carbon/human/dummy.dm
index f13e90719c1dc..0574150504210 100644
--- a/code/modules/mob/living/carbon/human/dummy.dm
+++ b/code/modules/mob/living/carbon/human/dummy.dm
@@ -96,9 +96,12 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy)
/// Takes in an accessory list and returns the first entry from that list, ensuring that we dont return SPRITE_ACCESSORY_NONE in the process.
/proc/get_consistent_feature_entry(list/accessory_feature_list)
- var/consistent_entry = (accessory_feature_list- SPRITE_ACCESSORY_NONE)[1]
- ASSERT(!isnull(consistent_entry))
- return consistent_entry
+// DOPPLER EDIT START
+// var/consistent_entry = (accessory_feature_list- SPRITE_ACCESSORY_NONE)[1]
+// ASSERT(!isnull(consistent_entry))
+// return consistent_entry
+ return SPRITE_ACCESSORY_NONE
+// DOPPLER EDIT END
/proc/create_consistent_human_dna(mob/living/carbon/human/target)
target.dna.features["mcolor"] = COLOR_VIBRANT_LIME
diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm
index 3a9004618470f..ee4bc8cbc6988 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -301,17 +301,17 @@
*/
/mob/living/carbon/human/proc/get_mob_height()
if(HAS_TRAIT(src, TRAIT_DWARF))
- if(ismonkey(src))
+ if(ismonkey(src) && !HAS_TRAIT(src, TRAIT_SIMIAN)) // Doppler edit, animal trait. our helper would like to exlude these - old code: if(ismonkey(src))
return MONKEY_HEIGHT_DWARF
else
return HUMAN_HEIGHT_DWARF
if(HAS_TRAIT(src, TRAIT_TOO_TALL))
- if(ismonkey(src))
+ if(ismonkey(src) && !HAS_TRAIT(src, TRAIT_SIMIAN)) // Doppler edit, animal trait - old code: if(ismonkey(src))
return MONKEY_HEIGHT_TALL
else
return HUMAN_HEIGHT_TALLEST
- else if(ismonkey(src))
+ else if(ismonkey(src) && !HAS_TRAIT(src, TRAIT_SIMIAN)) // Doppler edit, animal trait - old code: else if(ismonkey(src))
return MONKEY_HEIGHT_MEDIUM
return mob_height
diff --git a/code/modules/surgery/organs/external/tails.dm b/code/modules/surgery/organs/external/tails.dm
index ba3e711f15974..cae83153bdc55 100644
--- a/code/modules/surgery/organs/external/tails.dm
+++ b/code/modules/surgery/organs/external/tails.dm
@@ -40,13 +40,6 @@
receiver.add_mood_event("tail_regained", /datum/mood_event/tail_regained_wrong)
/obj/item/organ/external/tail/on_bodypart_insert(obj/item/bodypart/bodypart)
- /// DOPPLER SHIFT ADDITION BEGIN
- // damnit TG your own code fails CI for reasons unclear - TODO, stack trace this to eventually figure out how it's ending up with null owners
- if(bodypart == null)
- return ..()
- if(bodypart.owner == null)
- return ..()
- /// DOPPLER SHIFT ADDITION END
var/obj/item/organ/external/spines/our_spines = bodypart.owner.get_organ_slot(ORGAN_SLOT_EXTERNAL_SPINES)
if(our_spines)
try_insert_tail_spines(bodypart)
diff --git a/code/~doppler_earliest_defines.dm b/code/~doppler_earliest_defines.dm
deleted file mode 100644
index 4e8042c51c12d..0000000000000
--- a/code/~doppler_earliest_defines.dm
+++ /dev/null
@@ -1,26 +0,0 @@
-/// Hi! This file is here to work around some order-of-operations issues consistent humans & a couple other things have.
-/// If our overrides aren't loaded in early enough default TG stuff will end up in the critical [1] slot and break things.
-/datum/sprite_accessory/lizard_markings/none
- icon = 'modular_doppler/customization/icons/fallbacks.dmi'
- name = "No Markings"
- icon_state = "none"
-
-/datum/sprite_accessory/snouts/none
- icon = 'modular_doppler/customization/icons/fallbacks.dmi'
- name = "No Snout"
- icon_state = "none"
-
-/datum/sprite_accessory/frills/none
- icon = 'modular_doppler/customization/icons/fallbacks.dmi'
- name = "No Frills"
- icon_state = "none"
-
-/datum/sprite_accessory/horns/none
- icon = 'modular_doppler/customization/icons/fallbacks.dmi'
- name = "No Horns"
- icon_state = "none"
-
-/datum/sprite_accessory/tails/lizard/none
- icon = 'modular_doppler/customization/icons/fallbacks.dmi'
- name = "No Tail"
- icon_state = "none"
diff --git a/modular_doppler/customization/code/accessory_overrides.dm b/modular_doppler/customization/code/accessory_overrides.dm
deleted file mode 100644
index d29dfe667f433..0000000000000
--- a/modular_doppler/customization/code/accessory_overrides.dm
+++ /dev/null
@@ -1,3 +0,0 @@
-/datum/bodypart_overlay/mutant
- /// Annoying annoying annoyed annoyance - this is to avoid a massive headache trying to work around tails
- var/feature_key_sprite = null
diff --git a/modular_doppler/customization/code/accessory_overrides_lizard.dm b/modular_doppler/customization/code/accessory_overrides_lizard.dm
deleted file mode 100644
index 7ded20b493d71..0000000000000
--- a/modular_doppler/customization/code/accessory_overrides_lizard.dm
+++ /dev/null
@@ -1,418 +0,0 @@
-/datum/species/get_features()
- var/list/features = ..()
-
- features += /datum/preference/choiced/lizard_snout
- features += /datum/preference/choiced/lizard_frills
- features += /datum/preference/choiced/lizard_horns
- features += /datum/preference/choiced/lizard_tail
- features += /datum/preference/choiced/lizard_body_markings
-
- GLOB.features_by_species[type] = features
-
- return features
-
-
-
-
-
-/// Snout fixing
-/obj/item/organ/external/snout
- name = "snout"
-
-/datum/bodypart_overlay/mutant/snout
- layers = EXTERNAL_ADJACENT | EXTERNAL_ADJACENT_2 | EXTERNAL_ADJACENT_3
-
-/datum/bodypart_overlay/mutant/snout/color_image(image/overlay, draw_layer, obj/item/bodypart/limb)
- if(limb == null)
- return ..()
- if(limb.owner == null)
- return ..()
- if(draw_layer == bitflag_to_layer(EXTERNAL_ADJACENT))
- overlay.color = limb.owner.dna.features["snout_color_1"]
- return overlay
- else if(draw_layer == bitflag_to_layer(EXTERNAL_ADJACENT_2))
- overlay.color = limb.owner.dna.features["snout_color_2"]
- return overlay
- else if(draw_layer == bitflag_to_layer(EXTERNAL_ADJACENT_3))
- overlay.color = limb.owner.dna.features["snout_color_3"]
- return overlay
- return ..()
-
-//core toggle
-/datum/preference/toggle/snout
- savefile_key = "has_snout"
- savefile_identifier = PREFERENCE_CHARACTER
- category = PREFERENCE_CATEGORY_SECONDARY_FEATURES
- priority = PREFERENCE_PRIORITY_DEFAULT
-
-/datum/preference/toggle/snout/apply_to_human(mob/living/carbon/human/target, value)
- if(value == FALSE)
- target.dna.features["snout"] = /datum/sprite_accessory/snouts/none::name
-
-/datum/preference/toggle/snout/create_default_value()
- return FALSE
-
-/datum/species/regenerate_organs(mob/living/carbon/target, datum/species/old_species, replace_current = TRUE, list/excluded_zones, visual_only = FALSE)
- . = ..()
- if(target.dna.features["snout"])
- if(target.dna.features["snout"] != /datum/sprite_accessory/snouts/none::name && target.dna.features["snout"] != /datum/sprite_accessory/blank::name)
- var/obj/item/organ/replacement = SSwardrobe.provide_type(/obj/item/organ/external/snout)
- replacement.Insert(target, special = TRUE, movement_flags = DELETE_IF_REPLACED)
- return .
- var/obj/item/organ/old_part = target.get_organ_slot(ORGAN_SLOT_EXTERNAL_SNOUT)
- if(old_part)
- old_part.Remove(target, special = TRUE, movement_flags = DELETE_IF_REPLACED)
- old_part.moveToNullspace()
-
-//sprite selection
-/datum/preference/choiced/lizard_snout
- category = PREFERENCE_CATEGORY_CLOTHING
-
-/datum/preference/choiced/lizard_snout/is_accessible(datum/preferences/preferences)
- . = ..()
- var/has_snout = preferences.read_preference(/datum/preference/toggle/snout)
- if(has_snout == TRUE)
- return TRUE
- return FALSE
-
-/datum/preference/choiced/lizard_snout/create_default_value()
- return /datum/sprite_accessory/snouts/none::name
-
-
-
-
-
-/// Horns fixing
-/obj/item/organ/external/horns
- name = "horns"
-
-/datum/bodypart_overlay/mutant/horns
- layers = EXTERNAL_ADJACENT | EXTERNAL_ADJACENT_2 | EXTERNAL_ADJACENT_3
-
-/datum/bodypart_overlay/mutant/horns/color_image(image/overlay, draw_layer, obj/item/bodypart/limb)
- if(limb == null)
- return ..()
- if(limb.owner == null)
- return ..()
- if(draw_layer == bitflag_to_layer(EXTERNAL_ADJACENT))
- overlay.color = limb.owner.dna.features["horns_color_1"]
- return overlay
- else if(draw_layer == bitflag_to_layer(EXTERNAL_ADJACENT_2))
- overlay.color = limb.owner.dna.features["horns_color_2"]
- return overlay
- else if(draw_layer == bitflag_to_layer(EXTERNAL_ADJACENT_3))
- overlay.color = limb.owner.dna.features["horns_color_3"]
- return overlay
- return ..()
-
-//core toggle
-/datum/preference/toggle/horns
- savefile_key = "has_horns"
- savefile_identifier = PREFERENCE_CHARACTER
- category = PREFERENCE_CATEGORY_SECONDARY_FEATURES
- priority = PREFERENCE_PRIORITY_DEFAULT
-
-/datum/preference/toggle/horns/apply_to_human(mob/living/carbon/human/target, value)
- if(value == FALSE)
- target.dna.features["horns"] = /datum/sprite_accessory/horns/none::name
-
-/datum/preference/toggle/horns/create_default_value()
- return FALSE
-
-/datum/species/regenerate_organs(mob/living/carbon/target, datum/species/old_species, replace_current = TRUE, list/excluded_zones, visual_only = FALSE)
- . = ..()
- if(target.dna.features["horns"])
- if(target.dna.features["horns"] != /datum/sprite_accessory/horns/none::name && target.dna.features["horns"] != /datum/sprite_accessory/blank::name)
- var/obj/item/organ/replacement = SSwardrobe.provide_type(/obj/item/organ/external/horns)
- replacement.Insert(target, special = TRUE, movement_flags = DELETE_IF_REPLACED)
- return .
- var/obj/item/organ/old_part = target.get_organ_slot(ORGAN_SLOT_EXTERNAL_HORNS)
- if(old_part)
- old_part.Remove(target, special = TRUE, movement_flags = DELETE_IF_REPLACED)
- old_part.moveToNullspace()
-
-//sprite selection
-/datum/preference/choiced/lizard_horns
- category = PREFERENCE_CATEGORY_CLOTHING
-
-/datum/preference/choiced/lizard_horns/is_accessible(datum/preferences/preferences)
- . = ..()
- var/has_horns = preferences.read_preference(/datum/preference/toggle/horns)
- if(has_horns == TRUE)
- return TRUE
- return FALSE
-
-/datum/preference/choiced/lizard_horns/create_default_value()
- return /datum/sprite_accessory/horns/none::name
-
-
-
-
-
-/// Frills fixing
-/obj/item/organ/external/frills
- name = "frills"
-
-/datum/bodypart_overlay/mutant/frills
- layers = EXTERNAL_ADJACENT | EXTERNAL_ADJACENT_2 | EXTERNAL_ADJACENT_3
-
-/datum/bodypart_overlay/mutant/frills/color_image(image/overlay, draw_layer, obj/item/bodypart/limb)
- if(limb == null)
- return ..()
- if(limb.owner == null)
- return ..()
- if(draw_layer == bitflag_to_layer(EXTERNAL_ADJACENT))
- overlay.color = limb.owner.dna.features["frills_color_1"]
- return overlay
- else if(draw_layer == bitflag_to_layer(EXTERNAL_ADJACENT_2))
- overlay.color = limb.owner.dna.features["frills_color_2"]
- return overlay
- else if(draw_layer == bitflag_to_layer(EXTERNAL_ADJACENT_3))
- overlay.color = limb.owner.dna.features["frills_color_3"]
- return overlay
- return ..()
-
-//core toggle
-/datum/preference/toggle/frills
- savefile_key = "has_frills"
- savefile_identifier = PREFERENCE_CHARACTER
- category = PREFERENCE_CATEGORY_SECONDARY_FEATURES
- priority = PREFERENCE_PRIORITY_DEFAULT
-
-/datum/preference/toggle/frills/apply_to_human(mob/living/carbon/human/target, value)
- if(value == FALSE)
- target.dna.features["frills"] = /datum/sprite_accessory/frills/none::name
-
-/datum/preference/toggle/frills/create_default_value()
- return FALSE
-
-/datum/species/regenerate_organs(mob/living/carbon/target, datum/species/old_species, replace_current = TRUE, list/excluded_zones, visual_only = FALSE)
- . = ..()
- if(target.dna.features["frills"])
- if(target.dna.features["frills"] != /datum/sprite_accessory/frills/none::name && target.dna.features["frills"] != /datum/sprite_accessory/blank::name)
- var/obj/item/organ/replacement = SSwardrobe.provide_type(/obj/item/organ/external/frills)
- replacement.Insert(target, special = TRUE, movement_flags = DELETE_IF_REPLACED)
- return .
- var/obj/item/organ/old_part = target.get_organ_slot(ORGAN_SLOT_EXTERNAL_FRILLS)
- if(old_part)
- old_part.Remove(target, special = TRUE, movement_flags = DELETE_IF_REPLACED)
- old_part.moveToNullspace()
-
-//sprite selection
-/datum/preference/choiced/lizard_frills
- category = PREFERENCE_CATEGORY_CLOTHING
-
-/datum/preference/choiced/lizard_frills/is_accessible(datum/preferences/preferences)
- . = ..()
- var/has_frills = preferences.read_preference(/datum/preference/toggle/frills)
- if(has_frills == TRUE)
- return TRUE
- return FALSE
-
-/datum/preference/choiced/lizard_frills/create_default_value()
- return /datum/sprite_accessory/frills/none::name
-
-
-
-
-
-/// Tails fixing
-/obj/item/organ/external/tail/lizard
- name = "tail"
-
-/datum/bodypart_overlay/mutant/tail/lizard
- layers = EXTERNAL_FRONT | EXTERNAL_FRONT_2 | EXTERNAL_FRONT_3 | EXTERNAL_BEHIND | EXTERNAL_BEHIND_2 | EXTERNAL_BEHIND_3
- feature_key_sprite = "tail"
-
-/datum/bodypart_overlay/mutant/tail/lizard/color_image(image/overlay, draw_layer, obj/item/bodypart/limb)
- if(limb == null)
- return ..()
- if(limb.owner == null)
- return ..()
- if(draw_layer == bitflag_to_layer(EXTERNAL_FRONT))
- overlay.color = limb.owner.dna.features["tail_color_1"]
- return overlay
- else if(draw_layer == bitflag_to_layer(EXTERNAL_BEHIND))
- overlay.color = limb.owner.dna.features["tail_color_1"]
- return overlay
- else if(draw_layer == bitflag_to_layer(EXTERNAL_FRONT_2))
- overlay.color = limb.owner.dna.features["tail_color_2"]
- return overlay
- else if(draw_layer == bitflag_to_layer(EXTERNAL_BEHIND_2))
- overlay.color = limb.owner.dna.features["tail_color_2"]
- return overlay
- else if(draw_layer == bitflag_to_layer(EXTERNAL_FRONT_3))
- overlay.color = limb.owner.dna.features["tail_color_3"]
- return overlay
- else if(draw_layer == bitflag_to_layer(EXTERNAL_BEHIND_3))
- overlay.color = limb.owner.dna.features["tail_color_3"]
- return overlay
- return ..()
-
-//core toggle
-/datum/preference/toggle/tail
- savefile_key = "has_tail"
- savefile_identifier = PREFERENCE_CHARACTER
- category = PREFERENCE_CATEGORY_SECONDARY_FEATURES
- priority = PREFERENCE_PRIORITY_DEFAULT
-
-/datum/preference/toggle/tail/apply_to_human(mob/living/carbon/human/target, value)
- if(value == FALSE)
- target.dna.features["tail_lizard"] = /datum/sprite_accessory/tails/lizard/none::name
-
-/datum/preference/toggle/tail/create_default_value()
- return FALSE
-
-/datum/species/regenerate_organs(mob/living/carbon/target, datum/species/old_species, replace_current = TRUE, list/excluded_zones, visual_only = FALSE)
- . = ..()
- if(target == null)
- return
- if(target.dna.features["tail_lizard"])
- if(target.dna.features["tail_lizard"] != /datum/sprite_accessory/tails/lizard/none::name && target.dna.features["tail_lizard"] != /datum/sprite_accessory/blank::name)
- var/obj/item/organ/replacement = SSwardrobe.provide_type(/obj/item/organ/external/tail/lizard)
- replacement.Insert(target, special = TRUE, movement_flags = DELETE_IF_REPLACED)
- return .
- var/obj/item/organ/external/tail/lizard/old_part = target.get_organ_slot(ORGAN_SLOT_EXTERNAL_TAIL)
- if(istype(old_part))
- old_part.Remove(target, special = TRUE, movement_flags = DELETE_IF_REPLACED)
- old_part.moveToNullspace()
-
-//sprite selection
-/datum/preference/choiced/lizard_tail
- category = PREFERENCE_CATEGORY_CLOTHING
- relevant_external_organ = null
- should_generate_icons = TRUE
- main_feature_name = "Tail"
-
-/datum/preference/choiced/lizard_tail/is_accessible(datum/preferences/preferences)
- . = ..()
- var/has_tail = preferences.read_preference(/datum/preference/toggle/tail)
- if(has_tail == TRUE)
- return TRUE
- return FALSE
-
-/datum/preference/choiced/lizard_tail/create_default_value()
- return /datum/sprite_accessory/tails/lizard/none::name
-
-/datum/preference/choiced/lizard_tail/icon_for(value)
- var/datum/sprite_accessory/sprite_accessory = SSaccessories.tails_list_lizard[value]
-
- var/icon/final_icon = icon('icons/mob/human/species/lizard/bodyparts.dmi', "lizard_chest_m", NORTH)
-
- if (sprite_accessory.icon_state != "none")
- var/icon/markings_icon_1 = icon(sprite_accessory.icon, "m_tail_[sprite_accessory.icon_state]_BEHIND", NORTH)
- markings_icon_1.Blend(COLOR_RED, ICON_MULTIPLY)
- var/icon/markings_icon_2 = icon(sprite_accessory.icon, "m_tail_[sprite_accessory.icon_state]_BEHIND_2", NORTH)
- markings_icon_2.Blend(COLOR_VIBRANT_LIME, ICON_MULTIPLY)
- var/icon/markings_icon_3 = icon(sprite_accessory.icon, "m_tail_[sprite_accessory.icon_state]_BEHIND_3", NORTH)
- markings_icon_3.Blend(COLOR_BLUE, ICON_MULTIPLY)
- final_icon.Blend(markings_icon_1, ICON_OVERLAY)
- final_icon.Blend(markings_icon_2, ICON_OVERLAY)
- final_icon.Blend(markings_icon_3, ICON_OVERLAY)
- // front breaker
- var/icon/markings_icon_1_f = icon(sprite_accessory.icon, "m_tail_[sprite_accessory.icon_state]_FRONT", NORTH)
- markings_icon_1_f.Blend(COLOR_RED, ICON_MULTIPLY)
- var/icon/markings_icon_2_f = icon(sprite_accessory.icon, "m_tail_[sprite_accessory.icon_state]_FRONT_2", NORTH)
- markings_icon_2_f.Blend(COLOR_VIBRANT_LIME, ICON_MULTIPLY)
- var/icon/markings_icon_3_f = icon(sprite_accessory.icon, "m_tail_[sprite_accessory.icon_state]_FRONT_3", NORTH)
- markings_icon_3_f.Blend(COLOR_BLUE, ICON_MULTIPLY)
- final_icon.Blend(markings_icon_1_f, ICON_OVERLAY)
- final_icon.Blend(markings_icon_2_f, ICON_OVERLAY)
- final_icon.Blend(markings_icon_3_f, ICON_OVERLAY)
-
- //final_icon.Crop(4, 12, 28, 32)
- //final_icon.Scale(32, 26)
- //final_icon.Crop(-2, 1, 29, 32)
-
- return final_icon
-
-
-
-
-
-/// Standard bodymark fixing
-/datum/bodypart_overlay/simple/body_marking/lizard
- layers = EXTERNAL_ADJACENT | EXTERNAL_ADJACENT_2 | EXTERNAL_ADJACENT_3
-
-/datum/bodypart_overlay/simple/body_marking/lizard/get_image(layer, obj/item/bodypart/limb)
- if(limb == null)
- return ..()
- if(limb.owner == null)
- return ..()
- var/gender_string = (use_gender && limb.is_dimorphic) ? (limb.gender == MALE ? MALE : FEMALE + "_") : "" //we only got male and female sprites
- if(layer == bitflag_to_layer(EXTERNAL_ADJACENT_2))
- return image(icon, gender_string + icon_state + "_" + limb.body_zone + "_2", layer = layer)
- if(layer == bitflag_to_layer(EXTERNAL_ADJACENT_3))
- return image(icon, gender_string + icon_state + "_" + limb.body_zone + "_3", layer = layer)
- return image(icon, gender_string + icon_state + "_" + limb.body_zone, layer = layer)
-
-/datum/bodypart_overlay/simple/body_marking/lizard/color_image(image/overlay, draw_layer, obj/item/bodypart/limb)
- if(limb == null)
- return ..()
- if(limb.owner == null)
- return ..()
- if(draw_layer == bitflag_to_layer(EXTERNAL_ADJACENT))
- overlay.color = limb.owner.dna.features["body_markings_color_1"]
- return overlay
- else if(draw_layer == bitflag_to_layer(EXTERNAL_ADJACENT_2))
- overlay.color = limb.owner.dna.features["body_markings_color_2"]
- return overlay
- else if(draw_layer == bitflag_to_layer(EXTERNAL_ADJACENT_3))
- overlay.color = limb.owner.dna.features["body_markings_color_3"]
- return overlay
- return ..()
-
-/datum/preference/choiced/lizard_body_markings/create_default_value()
- return /datum/sprite_accessory/lizard_markings/none::name
-
-//toggle prefs
-/datum/preference/toggle/markings
- savefile_key = "has_markings"
- savefile_identifier = PREFERENCE_CHARACTER
- category = PREFERENCE_CATEGORY_SECONDARY_FEATURES
- priority = PREFERENCE_PRIORITY_DEFAULT
-
-/datum/preference/toggle/markings/apply_to_human(mob/living/carbon/human/target, value)
- if(value == FALSE)
- target.dna.features["lizard_markings"] = /datum/sprite_accessory/lizard_markings/none::name
-
-/datum/preference/toggle/markings/create_default_value()
- return FALSE
-
-//toggle pref integration
-/datum/preference/choiced/lizard_body_markings
- category = PREFERENCE_CATEGORY_CLOTHING
-
-/datum/preference/choiced/lizard_body_markings/is_accessible(datum/preferences/preferences)
- . = ..()
- var/has_markings = preferences.read_preference(/datum/preference/toggle/markings)
- if(has_markings == TRUE)
- return TRUE
- return FALSE
-
-//manually adding them now
-/datum/species/add_body_markings(mob/living/carbon/human/hooman)
- . = ..()
- if(hooman.dna.features["lizard_markings"] && hooman.dna.features["lizard_markings"] != /datum/sprite_accessory/lizard_markings/none::name && hooman.dna.features["snout"] != /datum/sprite_accessory/blank::name) //loop through possible species markings
- var/datum/bodypart_overlay/simple/body_marking/markings = new /datum/bodypart_overlay/simple/body_marking/lizard() // made to die... mostly because we cant use initial on lists but its convenient and organized
- var/accessory_name = hooman.dna.features[markings.dna_feature_key] //get the accessory name from dna
- var/datum/sprite_accessory/moth_markings/accessory = markings.get_accessory(accessory_name) //get the actual datum
-
- if(isnull(accessory))
- CRASH("Value: [accessory_name] did not have a corresponding sprite accessory!")
-
- for(var/obj/item/bodypart/part as anything in markings.applies_to) //check through our limbs
- var/obj/item/bodypart/people_part = hooman.get_bodypart(initial(part.body_zone)) // and see if we have a compatible marking for that limb
-
- if(!people_part)
- continue
-
- var/datum/bodypart_overlay/simple/body_marking/overlay = new /datum/bodypart_overlay/simple/body_marking/lizard()
-
- // Tell the overlay what it should look like
- overlay.icon = accessory.icon
- overlay.icon_state = accessory.icon_state
- overlay.use_gender = accessory.gender_specific
- overlay.draw_color = accessory.color_src ? hooman.dna.features["mcolor"] : null
-
- people_part.add_bodypart_overlay(overlay)
diff --git a/modular_doppler/customization/code/accessory_overrides_moth.dm b/modular_doppler/customization/code/accessory_overrides_moth.dm
deleted file mode 100644
index b71ab3f2e69f4..0000000000000
--- a/modular_doppler/customization/code/accessory_overrides_moth.dm
+++ /dev/null
@@ -1,81 +0,0 @@
-/// Moth bodymark fixing
-/datum/bodypart_overlay/simple/body_marking/moth/color_image(image/overlay, draw_layer, obj/item/bodypart/limb)
- if(limb == null)
- return ..()
- if(limb.owner == null)
- return ..()
- var/color_intended = COLOR_WHITE
-
- var/tcol_1 = limb.owner.dna.features["moth_markings_color_1"]
- var/tcol_2 = limb.owner.dna.features["moth_markings_color_2"]
- var/tcol_3 = limb.owner.dna.features["moth_markings_color_3"]
- if(tcol_1 && tcol_2 && tcol_3)
- //this is beyond ugly but it works
- var/r1 = hex2num(copytext(tcol_1, 2, 4)) / 255.0
- var/g1 = hex2num(copytext(tcol_1, 4, 6)) / 255.0
- var/b1 = hex2num(copytext(tcol_1, 6, 8)) / 255.0
- var/r2 = hex2num(copytext(tcol_2, 2, 4)) / 255.0
- var/g2 = hex2num(copytext(tcol_2, 4, 6)) / 255.0
- var/b2 = hex2num(copytext(tcol_2, 6, 8)) / 255.0
- var/r3 = hex2num(copytext(tcol_3, 2, 4)) / 255.0
- var/g3 = hex2num(copytext(tcol_3, 4, 6)) / 255.0
- var/b3 = hex2num(copytext(tcol_3, 6, 8)) / 255.0
- color_intended = list(r1,g1,b1, r2,g2,b2, r3,g3,b3)
- overlay.color = color_intended
- return overlay
-
-
-
-/// Moth wings recolorening
-/datum/bodypart_overlay/mutant/wings/moth/color_image(image/overlay, draw_layer, obj/item/bodypart/limb)
- if(limb == null)
- return ..()
- if(limb.owner == null)
- return ..()
- var/color_intended = COLOR_WHITE
-
- var/tcol_1 = limb.owner.dna.features["moth_wings_color_1"]
- var/tcol_2 = limb.owner.dna.features["moth_wings_color_2"]
- var/tcol_3 = limb.owner.dna.features["moth_wings_color_3"]
- if(tcol_1 && tcol_2 && tcol_3)
- //this is beyond ugly but it works
- var/r1 = hex2num(copytext(tcol_1, 2, 4)) / 255.0
- var/g1 = hex2num(copytext(tcol_1, 4, 6)) / 255.0
- var/b1 = hex2num(copytext(tcol_1, 6, 8)) / 255.0
- var/r2 = hex2num(copytext(tcol_2, 2, 4)) / 255.0
- var/g2 = hex2num(copytext(tcol_2, 4, 6)) / 255.0
- var/b2 = hex2num(copytext(tcol_2, 6, 8)) / 255.0
- var/r3 = hex2num(copytext(tcol_3, 2, 4)) / 255.0
- var/g3 = hex2num(copytext(tcol_3, 4, 6)) / 255.0
- var/b3 = hex2num(copytext(tcol_3, 6, 8)) / 255.0
- color_intended = list(r1,g1,b1, r2,g2,b2, r3,g3,b3)
- overlay.color = color_intended
- return overlay
-
-
-
-/// Moth antennae recolorening
-/datum/bodypart_overlay/mutant/antennae/color_image(image/overlay, draw_layer, obj/item/bodypart/limb)
- if(limb == null)
- return ..()
- if(limb.owner == null)
- return ..()
- var/color_intended = COLOR_WHITE
-
- var/tcol_1 = limb.owner.dna.features["moth_antennae_color_1"]
- var/tcol_2 = limb.owner.dna.features["moth_antennae_color_2"]
- var/tcol_3 = limb.owner.dna.features["moth_antennae_color_3"]
- if(tcol_1 && tcol_2 && tcol_3)
- //this is beyond ugly but it works
- var/r1 = hex2num(copytext(tcol_1, 2, 4)) / 255.0
- var/g1 = hex2num(copytext(tcol_1, 4, 6)) / 255.0
- var/b1 = hex2num(copytext(tcol_1, 6, 8)) / 255.0
- var/r2 = hex2num(copytext(tcol_2, 2, 4)) / 255.0
- var/g2 = hex2num(copytext(tcol_2, 4, 6)) / 255.0
- var/b2 = hex2num(copytext(tcol_2, 6, 8)) / 255.0
- var/r3 = hex2num(copytext(tcol_3, 2, 4)) / 255.0
- var/g3 = hex2num(copytext(tcol_3, 4, 6)) / 255.0
- var/b3 = hex2num(copytext(tcol_3, 6, 8)) / 255.0
- color_intended = list(r1,g1,b1, r2,g2,b2, r3,g3,b3)
- overlay.color = color_intended
- return overlay
diff --git a/modular_doppler/customization/code/custom_accessories.dm b/modular_doppler/customization/code/custom_accessories.dm
deleted file mode 100644
index 0fc28fc9c3b36..0000000000000
--- a/modular_doppler/customization/code/custom_accessories.dm
+++ /dev/null
@@ -1 +0,0 @@
-// This is where our bespoke fluff, IPC antennae, etc accessories should go.
diff --git a/modular_doppler/customization/code/dropdowns_to_icons.dm b/modular_doppler/customization/code/dropdowns_to_icons.dm
deleted file mode 100644
index a553e496c9df0..0000000000000
--- a/modular_doppler/customization/code/dropdowns_to_icons.dm
+++ /dev/null
@@ -1 +0,0 @@
-//wawa
diff --git a/modular_doppler/customization/icons/fallbacks.dmi b/modular_doppler/customization/icons/fallbacks.dmi
deleted file mode 100644
index 4f5867e07e724..0000000000000
Binary files a/modular_doppler/customization/icons/fallbacks.dmi and /dev/null differ
diff --git a/modular_doppler/customization/species/lizards/code/lizard_accessories.dm b/modular_doppler/customization/species/lizards/code/lizard_accessories.dm
deleted file mode 100644
index 90a0771ffc063..0000000000000
--- a/modular_doppler/customization/species/lizards/code/lizard_accessories.dm
+++ /dev/null
@@ -1,16 +0,0 @@
-//snouts
-/datum/sprite_accessory/lizard_markings
- icon = 'modular_doppler/customization/species/lizards/icons/lizard_markings.dmi'
-
-/datum/sprite_accessory/snouts
- icon = 'modular_doppler/customization/species/lizards/icons/lizard_external.dmi'
-
-/datum/sprite_accessory/frills
- icon = 'modular_doppler/customization/species/lizards/icons/lizard_external.dmi'
-
-/datum/sprite_accessory/horns
- icon = 'modular_doppler/customization/species/lizards/icons/lizard_external.dmi'
-
-/datum/sprite_accessory/tails/lizard
- icon = 'modular_doppler/customization/species/lizards/icons/lizard_tails.dmi'
-
diff --git a/modular_doppler/customization/species/lizards/code/lizard_species.dm b/modular_doppler/customization/species/lizards/code/lizard_species.dm
deleted file mode 100644
index 43c9e98275c6f..0000000000000
--- a/modular_doppler/customization/species/lizards/code/lizard_species.dm
+++ /dev/null
@@ -1 +0,0 @@
-//TODO: we may be able to remove this file
diff --git a/modular_doppler/customization/species/lizards/icons/lizard_external.dmi b/modular_doppler/customization/species/lizards/icons/lizard_external.dmi
deleted file mode 100644
index ca7ad196b2293..0000000000000
Binary files a/modular_doppler/customization/species/lizards/icons/lizard_external.dmi and /dev/null differ
diff --git a/modular_doppler/customization/species/lizards/icons/lizard_markings.dmi b/modular_doppler/customization/species/lizards/icons/lizard_markings.dmi
deleted file mode 100644
index b94ad9d570c79..0000000000000
Binary files a/modular_doppler/customization/species/lizards/icons/lizard_markings.dmi and /dev/null differ
diff --git a/modular_doppler/customization/species/lizards/icons/lizard_tails.dmi b/modular_doppler/customization/species/lizards/icons/lizard_tails.dmi
deleted file mode 100644
index 93788db366118..0000000000000
Binary files a/modular_doppler/customization/species/lizards/icons/lizard_tails.dmi and /dev/null differ
diff --git a/modular_doppler/customization/species/scugs/code/slugcat_accessories.dm b/modular_doppler/customization/species/scugs/code/slugcat_accessories.dm
deleted file mode 100644
index b95c1d478d172..0000000000000
--- a/modular_doppler/customization/species/scugs/code/slugcat_accessories.dm
+++ /dev/null
@@ -1,78 +0,0 @@
-//snouts
-/datum/sprite_accessory/snouts/slugcat
- icon = 'modular_doppler/customization/species/scugs/icons/slugcat_external.dmi'
- name = "Slugcat"
- icon_state = "scug_standard"
-
-/datum/sprite_accessory/snouts/slugcat/sharp
- name = "Slugcat Sharp"
- icon_state = "scug_sharp"
-
-/datum/sprite_accessory/snouts/slugcat/round
- name = "Slugcat Round"
- icon_state = "scug_round"
-
-//frills
-/datum/sprite_accessory/frills/slugcat
- icon = 'modular_doppler/customization/species/scugs/icons/slugcat_external.dmi'
- name = "Slugcat"
- icon_state = "scug_aquatic"
-
-/datum/sprite_accessory/frills/slugcat/sharp
- name = "Slugcat Sharp"
- icon_state = "scug_sharp"
-
-/datum/sprite_accessory/frills/slugcat/fluffy
- name = "Slugcat Fluffy"
- icon_state = "scug_fluffy"
-
-/datum/sprite_accessory/frills/slugcat/draconic
- name = "Slugcat Draconic"
- icon_state = "scug_dragon"
-
-//horns
-/datum/sprite_accessory/horns/slugcat
- icon = 'modular_doppler/customization/species/scugs/icons/slugcat_external.dmi'
- name = "Slugcat"
- icon_state = "scug_standard"
-
-/datum/sprite_accessory/horns/slugcat/tall
- name = "Slugcat Tall"
- icon_state = "scug_tall"
-
-/datum/sprite_accessory/horns/slugcat/sharp
- name = "Slugcat Sharp"
- icon_state = "scug_sharp"
-
-/datum/sprite_accessory/horns/slugcat/forward
- name = "Slugcat Droopy"
- icon_state = "scug_forward"
-
-/datum/sprite_accessory/horns/slugcat/flopped
- name = "Slugcat Long Flop"
- icon_state = "scug_flopped"
-
-/datum/sprite_accessory/horns/slugcat/fluffy
- name = "Slugcat Fluffy"
- icon_state = "scug_fluffy"
-
-/datum/sprite_accessory/horns/slugcat/short
- name = "Slugcat Short"
- icon_state = "scug_short"
-
-//tails
-/datum/sprite_accessory/tails/lizard/slugcat
- icon = 'modular_doppler/customization/species/scugs/icons/slugcat_tails.dmi'
- name = "Slugcat"
- icon_state = "scug_std"
-
-/datum/sprite_accessory/tails/lizard/slugcat/thick
- name = "Slugcat Thick"
- icon_state = "scug_thick"
-
-//body markings
-/datum/sprite_accessory/lizard_markings/slugcat
- icon = 'modular_doppler/customization/species/scugs/icons/slugcat_markings.dmi'
- name = "Slugcat Underbelly"
- icon_state = "scug_lbelly"
- gender_specific = TRUE
diff --git a/modular_doppler/customization/species/scugs/icons/slugcat_external.dmi b/modular_doppler/customization/species/scugs/icons/slugcat_external.dmi
deleted file mode 100644
index 96fe02b359d76..0000000000000
Binary files a/modular_doppler/customization/species/scugs/icons/slugcat_external.dmi and /dev/null differ
diff --git a/modular_doppler/customization/species/scugs/icons/slugcat_markings.dmi b/modular_doppler/customization/species/scugs/icons/slugcat_markings.dmi
deleted file mode 100644
index 9784d69dd4e7b..0000000000000
Binary files a/modular_doppler/customization/species/scugs/icons/slugcat_markings.dmi and /dev/null differ
diff --git a/modular_doppler/customization/species/scugs/icons/slugcat_tails.dmi b/modular_doppler/customization/species/scugs/icons/slugcat_tails.dmi
deleted file mode 100644
index 991bea5a1e771..0000000000000
Binary files a/modular_doppler/customization/species/scugs/icons/slugcat_tails.dmi and /dev/null differ
diff --git a/modular_doppler/enterprise_resource_planning/code/breasts.dm b/modular_doppler/enterprise_resource_planning/code/breasts.dm
index cf2a8ea4772cc..645b05aa07b4d 100644
--- a/modular_doppler/enterprise_resource_planning/code/breasts.dm
+++ b/modular_doppler/enterprise_resource_planning/code/breasts.dm
@@ -1,14 +1,12 @@
/datum/species/get_features()
var/list/features = ..()
- features += /datum/preference/choiced/breasts
+ features += /datum/preference/choiced/breasts::savefile_key
GLOB.features_by_species[type] = features
return features
-
-
/// SSAccessories setup
/datum/controller/subsystem/accessories
var/list/breasts_list
@@ -18,8 +16,6 @@
breasts_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/breasts)["default_sprites"] // FLAKY DEFINE: this should be using DEFAULT_SPRITE_LIST
//damnit SSAccessories
-
-
/// The boobage in question
/obj/item/organ/external/breasts
name = "breasts"
diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/objects.dm b/modular_doppler/hearthkin/primitive_catgirls/code/objects.dm
index f1c7b430b780d..ea06ea9e3f332 100644
--- a/modular_doppler/hearthkin/primitive_catgirls/code/objects.dm
+++ b/modular_doppler/hearthkin/primitive_catgirls/code/objects.dm
@@ -9,7 +9,7 @@
var/being_used = FALSE
/obj/item/anointing_oil/attack(mob/living/target_mob, mob/living/user, params)
- if (!is_species(user, /datum/species/human/felinid/primitive))
+ if (!is_species(user, /datum/species/human/kemonomimi/primitive))
to_chat(user, span_warning("You have no idea what this disgusting concoction is used for."))
return
if(being_used || !ismob(target_mob)) //originally this was going to check if the mob was friendly, but if an icecat wants to name some terror mob while it's tearing chunks out of them, why not?
@@ -48,7 +48,7 @@
/obj/item/anointing_oil/examine(mob/user)
. = ..()
- if(is_species(user, /datum/species/human/felinid/primitive))
+ if(is_species(user, /datum/species/human/kemonomimi/primitive))
. += span_info("Using this on the local wildlife will allow you to give them a name.")
/datum/crafting_recipe/anointing_oil
@@ -74,7 +74,7 @@
w_class = WEIGHT_CLASS_TINY
/obj/item/frozen_breath/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
- if (!is_species(user, /datum/species/human/felinid/primitive))
+ if (!is_species(user, /datum/species/human/kemonomimi/primitive))
to_chat(user, span_warning("You have no idea how to use this freezing concoction."))
return
@@ -94,7 +94,7 @@
/obj/item/frozen_breath/examine(mob/user)
. = ..()
- if(is_species(user, /datum/species/human/felinid/primitive))
+ if(is_species(user, /datum/species/human/kemonomimi/primitive))
. += span_info("Using this on a pair of organic lungs transforms them into hardy lungs. This will remove any other special features from the old lungs, if there were any.")
/datum/crafting_recipe/frozen_breath
diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm b/modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm
index d10dfa45615c9..f9c83086402df 100644
--- a/modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm
+++ b/modular_doppler/hearthkin/primitive_catgirls/code/spawner.dm
@@ -4,7 +4,7 @@
prompt_name = "icemoon dweller"
icon = 'icons/mob/simple/lavaland/nest.dmi'
icon_state = "hole"
- mob_species = /datum/species/human/felinid/primitive
+ mob_species = /datum/species/human/kemonomimi/primitive
outfit = /datum/outfit/primitive_catgirl
density = FALSE
you_are_text = "You are an icemoon dweller."
@@ -20,7 +20,7 @@
/// The team the spawner will assign players to and use to keep track of people that have already used the spawner
var/datum/team/primitive_catgirls/team
- restricted_species = list(/datum/species/human/felinid/primitive)
+ restricted_species = list(/datum/species/human/kemonomimi/primitive)
infinite_use = TRUE
deletes_on_zero_uses_left = FALSE
diff --git a/modular_doppler/modular_customization/accessories/code/feline_accessories.dm b/modular_doppler/modular_customization/accessories/code/feline_accessories.dm
new file mode 100644
index 0000000000000..e8af2f424b85a
--- /dev/null
+++ b/modular_doppler/modular_customization/accessories/code/feline_accessories.dm
@@ -0,0 +1,6 @@
+/datum/sprite_accessory/tails/feline_tails
+ icon = 'modular_doppler/modular_customization/accessories/icons/tails/feline_tails.dmi'
+
+/datum/sprite_accessory/tails/feline_tails/cat
+ name = "Cat"
+ icon_state = "cat"
diff --git a/modular_doppler/modular_customization/accessories/code/reptile_accessories.dm b/modular_doppler/modular_customization/accessories/code/reptile_accessories.dm
new file mode 100644
index 0000000000000..f1c1af584f08f
--- /dev/null
+++ b/modular_doppler/modular_customization/accessories/code/reptile_accessories.dm
@@ -0,0 +1,120 @@
+/// Generic reptile accessories
+// This is lizard content
+/datum/sprite_accessory/snouts/reptile_snouts
+ icon = 'modular_doppler/modular_customization/accessories/icons/snouts/reptile_snouts.dmi'
+ name = SPRITE_ACCESSORY_NONE
+ icon_state = "None"
+
+/datum/sprite_accessory/frills/reptile_frills
+ icon = 'modular_doppler/modular_customization/accessories/icons/frills/reptile_frills.dmi'
+ name = SPRITE_ACCESSORY_NONE
+ icon_state = "None"
+
+/datum/sprite_accessory/horns/reptile_horns
+ icon = 'modular_doppler/modular_customization/accessories/icons/horns/reptile_horns.dmi'
+ name = SPRITE_ACCESSORY_NONE
+ icon_state = "None"
+
+/datum/sprite_accessory/tails/reptile_tails
+ icon = 'modular_doppler/modular_customization/accessories/icons/tails/reptile_tails.dmi'
+ spine_key = SPINE_KEY_LIZARD
+
+/// Slugcat accessories
+// I'm pretty sure these are reptiles
+/datum/sprite_accessory/lizard_markings/none
+ name = SPRITE_ACCESSORY_NONE
+ icon = 'modular_doppler/modular_customization/accessories/icons/bodymarkings/slugcat_bodymarkings.dmi'
+ icon_state = "None"
+
+/datum/sprite_accessory/lizard_markings/slugcat
+ name = "Slugcat Underbelly"
+ icon = 'modular_doppler/modular_customization/accessories/icons/bodymarkings/slugcat_bodymarkings.dmi'
+ icon_state = "scug_lbelly"
+ gender_specific = TRUE
+
+/datum/sprite_accessory/snouts/reptile_snouts/slugcat
+ name = "Slugcat"
+ icon_state = "scug_standard"
+
+/datum/sprite_accessory/snouts/reptile_snouts/slugcat/sharp
+ name = "Slugcat Sharp"
+ icon_state = "scug_sharp"
+
+/datum/sprite_accessory/snouts/reptile_snouts/slugcat/round
+ name = "Slugcat Round"
+ icon_state = "scug_round"
+
+/datum/sprite_accessory/frills/reptile_frills/slugcat
+ name = "Slugcat"
+ icon_state = "scug_aquatic"
+
+/datum/sprite_accessory/frills/reptile_frills/slugcat/sharp
+ name = "Slugcat Sharp"
+ icon_state = "scug_sharp"
+
+/datum/sprite_accessory/frills/reptile_frills/slugcat/fluffy
+ name = "Slugcat Fluffy"
+ icon_state = "scug_fluffy"
+
+/datum/sprite_accessory/frills/reptile_frills/slugcat/draconic
+ name = "Slugcat Draconic"
+ icon_state = "scug_dragon"
+
+/datum/sprite_accessory/horns/reptile_horns/slugcat
+ name = "Slugcat"
+ icon_state = "scug_standard"
+
+/datum/sprite_accessory/horns/reptile_horns/slugcat/tall
+ name = "Slugcat Tall"
+ icon_state = "scug_tall"
+
+/datum/sprite_accessory/horns/reptile_horns/slugcat/sharp
+ name = "Slugcat Sharp"
+ icon_state = "scug_sharp"
+
+/datum/sprite_accessory/horns/reptile_horns/slugcat/forward
+ name = "Slugcat Droopy"
+ icon_state = "scug_forward"
+
+/datum/sprite_accessory/horns/reptile_horns/slugcat/flopped
+ name = "Slugcat Long Flop"
+ icon_state = "scug_flopped"
+
+/datum/sprite_accessory/horns/reptile_horns/slugcat/fluffy
+ name = "Slugcat Fluffy"
+ icon_state = "scug_fluffy"
+
+/datum/sprite_accessory/horns/reptile_horns/slugcat/short
+ name = "Slugcat Short"
+ icon_state = "scug_short"
+
+/datum/sprite_accessory/tails/reptile_tails/slugcat
+ name = "Slugcat"
+ icon_state = "scug_std"
+
+/datum/sprite_accessory/tails/reptile_tails/slugcat/thick
+ name = "Slugcat Thick"
+ icon_state = "scug_thick"
+
+/// Lizard overwrites
+// We do need a duplicate of these, yes
+/datum/sprite_accessory/tails/reptile_tails/smooth
+ name = "Smooth"
+ icon_state = "smooth"
+
+/datum/sprite_accessory/tails/reptile_tails/dtiger
+ name = "Dark Tiger"
+ icon_state = "dtiger"
+
+/datum/sprite_accessory/tails/reptile_tails/ltiger
+ name = "Light Tiger"
+ icon_state = "ltiger"
+
+/datum/sprite_accessory/tails/reptile_tails/spikes
+ name = "Spikes"
+ icon_state = "spikes"
+
+/datum/sprite_accessory/tails/reptile_tails/short
+ name = "Short"
+ icon_state = "short"
+ spine_key = NONE
diff --git a/modular_doppler/modular_customization/accessories/code/simian_accessories.dm b/modular_doppler/modular_customization/accessories/code/simian_accessories.dm
new file mode 100644
index 0000000000000..da15445cf88f5
--- /dev/null
+++ b/modular_doppler/modular_customization/accessories/code/simian_accessories.dm
@@ -0,0 +1,6 @@
+/datum/sprite_accessory/tails/simian_tails
+ icon = 'modular_doppler/modular_customization/accessories/icons/tails/simian_tails.dmi'
+
+/datum/sprite_accessory/tails/simian_tails/monkey
+ name = "Monkey"
+ icon_state = "monkey"
diff --git a/modular_doppler/modular_customization/accessories/icons/bodymarkings/slugcat_bodymarkings.dmi b/modular_doppler/modular_customization/accessories/icons/bodymarkings/slugcat_bodymarkings.dmi
new file mode 100644
index 0000000000000..d8a43bf62aa0e
Binary files /dev/null and b/modular_doppler/modular_customization/accessories/icons/bodymarkings/slugcat_bodymarkings.dmi differ
diff --git a/modular_doppler/customization/species/lizards/icons/bodyparts.dmi b/modular_doppler/modular_customization/accessories/icons/bodyparts.dmi
similarity index 100%
rename from modular_doppler/customization/species/lizards/icons/bodyparts.dmi
rename to modular_doppler/modular_customization/accessories/icons/bodyparts.dmi
diff --git a/modular_doppler/modular_customization/accessories/icons/frills/reptile_frills.dmi b/modular_doppler/modular_customization/accessories/icons/frills/reptile_frills.dmi
new file mode 100644
index 0000000000000..94adf050f1c2f
Binary files /dev/null and b/modular_doppler/modular_customization/accessories/icons/frills/reptile_frills.dmi differ
diff --git a/modular_doppler/modular_customization/accessories/icons/horns/reptile_horns.dmi b/modular_doppler/modular_customization/accessories/icons/horns/reptile_horns.dmi
new file mode 100644
index 0000000000000..37533195e794c
Binary files /dev/null and b/modular_doppler/modular_customization/accessories/icons/horns/reptile_horns.dmi differ
diff --git a/modular_doppler/modular_customization/accessories/icons/snouts/reptile_snouts.dmi b/modular_doppler/modular_customization/accessories/icons/snouts/reptile_snouts.dmi
new file mode 100644
index 0000000000000..69e3a7904bbc1
Binary files /dev/null and b/modular_doppler/modular_customization/accessories/icons/snouts/reptile_snouts.dmi differ
diff --git a/modular_doppler/modular_customization/accessories/icons/tails/feline_tails.dmi b/modular_doppler/modular_customization/accessories/icons/tails/feline_tails.dmi
new file mode 100644
index 0000000000000..1d84734e22d11
Binary files /dev/null and b/modular_doppler/modular_customization/accessories/icons/tails/feline_tails.dmi differ
diff --git a/modular_doppler/modular_customization/accessories/icons/tails/reptile_tails.dmi b/modular_doppler/modular_customization/accessories/icons/tails/reptile_tails.dmi
new file mode 100644
index 0000000000000..70ef46b0c3ecb
Binary files /dev/null and b/modular_doppler/modular_customization/accessories/icons/tails/reptile_tails.dmi differ
diff --git a/modular_doppler/modular_customization/accessories/icons/tails/simian_tails.dmi b/modular_doppler/modular_customization/accessories/icons/tails/simian_tails.dmi
new file mode 100644
index 0000000000000..0dce4867b48f5
Binary files /dev/null and b/modular_doppler/modular_customization/accessories/icons/tails/simian_tails.dmi differ
diff --git a/modular_doppler/modular_customization/accessories/overrides/accessory_overrides.dm b/modular_doppler/modular_customization/accessories/overrides/accessory_overrides.dm
new file mode 100644
index 0000000000000..f8fe86e70a9a7
--- /dev/null
+++ b/modular_doppler/modular_customization/accessories/overrides/accessory_overrides.dm
@@ -0,0 +1,15 @@
+/datum/species/get_features()
+ var/list/features = ..()
+
+ features += /datum/preference/choiced/snout::savefile_key
+ features += /datum/preference/choiced/frills::savefile_key
+ features += /datum/preference/choiced/horns::savefile_key
+ features += /datum/preference/choiced/tail::savefile_key
+
+ GLOB.features_by_species[type] = features
+
+ return features
+
+/datum/bodypart_overlay/mutant
+ /// Annoying annoying annoyed annoyance - this is to avoid a massive headache trying to work around tails
+ var/feature_key_sprite = null
diff --git a/modular_doppler/customization/code/bodypart_overrides.dm b/modular_doppler/modular_customization/bodypart/bodypart_overrides.dm
similarity index 100%
rename from modular_doppler/customization/code/bodypart_overrides.dm
rename to modular_doppler/modular_customization/bodypart/bodypart_overrides.dm
diff --git a/modular_doppler/modular_customization/organs/external/tails.dm b/modular_doppler/modular_customization/organs/external/tails.dm
new file mode 100644
index 0000000000000..1f353293e671a
--- /dev/null
+++ b/modular_doppler/modular_customization/organs/external/tails.dm
@@ -0,0 +1,87 @@
+/// Cat tail
+//
+/obj/item/organ/external/tail/modular/cat
+
+
+/// Dog tail
+// Buffs people if they're closeby while you're wagging it!
+#define DOG_WAG_MOOD "dog_wag"
+
+/obj/item/organ/external/tail/modular/dog
+ var/datum/proximity_monitor/advanced/dog_wag/mood_buff
+ var/timer
+
+/obj/item/organ/external/tail/modular/dog/start_wag(mob/living/carbon/organ_owner, stop_after = INFINITY)
+ . = ..()
+ if(!timer)
+ mood_buff = new(_host = src, range = 4)
+ timer = addtimer(CALLBACK(src, PROC_REF(reset_timer), organ_owner), 1 MINUTES, TIMER_UNIQUE|TIMER_DELETE_ME)
+
+/obj/item/organ/external/tail/modular/dog/proc/reset_timer()
+ deltimer(timer)
+
+/obj/item/organ/external/tail/modular/dog/stop_wag(mob/living/carbon/organ_owner)
+ . = ..()
+ if(mood_buff)
+ QDEL_NULL(mood_buff)
+
+/obj/item/organ/external/tail/modular/dog/on_mob_remove(mob/living/carbon/organ_owner, special = FALSE, movement_flags)
+ . = ..()
+ if(mood_buff)
+ QDEL_NULL(mood_buff)
+
+/datum/proximity_monitor/advanced/dog_wag/field_turf_crossed(atom/movable/crossed, turf/old_location, turf/new_location)
+ if (!isliving(crossed) || !can_see(crossed, host, current_range))
+ return
+ on_enter(crossed)
+
+/datum/proximity_monitor/advanced/dog_wag/field_turf_uncrossed(atom/movable/crossed, turf/old_location, turf/new_location)
+ if (!isliving(crossed) || !can_see(crossed, host, current_range))
+ return
+ on_exit(crossed)
+
+/datum/proximity_monitor/advanced/dog_wag/proc/on_enter(mob/living/viewer)
+ if (!viewer.mind || !viewer.mob_mood || (viewer.stat != CONSCIOUS) || viewer.is_blind())
+ return
+ viewer.add_mood_event(DOG_WAG_MOOD, /datum/mood_event/dog_wag)
+
+/datum/proximity_monitor/advanced/dog_wag/proc/on_exit(mob/living/viewer)
+ if (!viewer.mind || !viewer.mob_mood || (viewer.stat != CONSCIOUS) || viewer.is_blind())
+ return
+ viewer.clear_mood_event(DOG_WAG_MOOD)
+
+/datum/mood_event/dog_wag
+ description = "The excitement is infectious!"
+ mood_change = 0.5
+ category = DOG_WAG_MOOD
+
+#undef DOG_WAG_MOOD
+
+/// Lizard tail
+//
+/obj/item/organ/external/tail/modular/lizard
+
+
+/// Bunny tail
+//
+/obj/item/organ/external/tail/modular/bunny
+
+
+/// Bird tail
+//
+/obj/item/organ/external/tail/modular/bird
+
+
+/// Mouse tail
+//
+/obj/item/organ/external/tail/modular/mouse
+
+
+/// Fish tail
+//
+/obj/item/organ/external/tail/modular/fish
+
+
+/// Monkey tail
+//
+/obj/item/organ/external/tail/modular/monkey
diff --git a/modular_doppler/modular_customization/organs/internal/ears.dm b/modular_doppler/modular_customization/organs/internal/ears.dm
new file mode 100644
index 0000000000000..e38019edc4e54
--- /dev/null
+++ b/modular_doppler/modular_customization/organs/internal/ears.dm
@@ -0,0 +1,14 @@
+/// Cat ears
+//
+/obj/item/organ/internal/ears/cat
+
+/// Dog ears
+//
+/obj/item/organ/internal/ears/dog
+
+/// Bunny ears
+/obj/item/organ/internal/ears/bunny
+
+/// Mouse ears
+//
+/obj/item/organ/internal/ears/mouse
diff --git a/modular_doppler/modular_customization/organs/internal/tongue.dm b/modular_doppler/modular_customization/organs/internal/tongue.dm
new file mode 100644
index 0000000000000..fa6cea216248f
--- /dev/null
+++ b/modular_doppler/modular_customization/organs/internal/tongue.dm
@@ -0,0 +1,60 @@
+/// Cat tongue
+//
+/obj/item/organ/internal/tongue/cat
+ say_mod = "meows"
+
+/// Dog tongue
+//
+/obj/item/organ/internal/tongue/dog
+ name = "canine tongue"
+ desc = "A fleshy muscle mostly used for barking."
+ say_mod = "barks"
+
+/// Lizard tongue
+//
+/obj/item/organ/internal/tongue/lizard
+
+/// Bunny tongue
+/obj/item/organ/internal/tongue/bunny
+ name = "leporid tongue"
+ desc = "A fleshy muscle mostly used for... hopping?"
+ say_mod = "hops"
+
+/// Bird tongue
+//
+/obj/item/organ/internal/tongue/bird
+ name = "avian tongue"
+ desc = "A fleshy muscle mostly used for chirping."
+ say_mod = "chirps"
+
+/obj/item/organ/internal/tongue/bird/Insert(mob/living/carbon/signer, special = FALSE, movement_flags = DELETE_IF_REPLACED)
+ . = ..()
+ signer.verb_ask = "peeps"
+ signer.verb_exclaim = "squawks"
+ signer.verb_whisper = "murmurs"
+ signer.verb_yell = "shrieks"
+
+/obj/item/organ/internal/tongue/bird/Remove(mob/living/carbon/speaker, special = FALSE, movement_flags)
+ . = ..()
+ speaker.verb_ask = initial(verb_ask)
+ speaker.verb_exclaim = initial(verb_exclaim)
+ speaker.verb_whisper = initial(verb_whisper)
+ speaker.verb_yell = initial(verb_yell)
+
+/// Mouse tongue
+//
+/obj/item/organ/internal/tongue/mouse
+ name = "muridae tongue"
+ desc = "A fleshy muscle mostly used for squeaking."
+ say_mod = "squeaks"
+
+/// Fish tongue
+//
+/obj/item/organ/internal/tongue/fish
+ name = "piscine tongue"
+ desc = "A fleshy muscle mostly used for gnashing."
+ say_mod = "gnashes"
+
+/// Monkey tongue
+//
+/obj/item/organ/internal/tongue/monkey
diff --git a/modular_doppler/modular_customization/preferences/body_markings.dm b/modular_doppler/modular_customization/preferences/body_markings.dm
new file mode 100644
index 0000000000000..df9a3af7ef06e
--- /dev/null
+++ b/modular_doppler/modular_customization/preferences/body_markings.dm
@@ -0,0 +1,52 @@
+/// Standard bodymark fixing
+/datum/bodypart_overlay/simple/body_marking/lizard
+ layers = EXTERNAL_ADJACENT | EXTERNAL_ADJACENT_2 | EXTERNAL_ADJACENT_3
+
+/datum/bodypart_overlay/simple/body_marking/lizard/get_image(layer, obj/item/bodypart/limb)
+ if(limb == null)
+ return ..()
+ if(limb.owner == null)
+ return ..()
+ var/gender_string = (use_gender && limb.is_dimorphic) ? (limb.gender == MALE ? MALE : FEMALE + "_") : "" //we only got male and female sprites
+ if(layer == bitflag_to_layer(EXTERNAL_ADJACENT_2))
+ return image(icon, gender_string + icon_state + "_" + limb.body_zone + "_2", layer = layer)
+ if(layer == bitflag_to_layer(EXTERNAL_ADJACENT_3))
+ return image(icon, gender_string + icon_state + "_" + limb.body_zone + "_3", layer = layer)
+ return image(icon, gender_string + icon_state + "_" + limb.body_zone, layer = layer)
+
+/datum/bodypart_overlay/simple/body_marking/lizard/color_image(image/overlay, draw_layer, obj/item/bodypart/limb)
+ if(limb == null)
+ return ..()
+ if(limb.owner == null)
+ return ..()
+ if(draw_layer == bitflag_to_layer(EXTERNAL_ADJACENT))
+ overlay.color = limb.owner.dna.features["body_markings_color_1"]
+ return overlay
+ else if(draw_layer == bitflag_to_layer(EXTERNAL_ADJACENT_2))
+ overlay.color = limb.owner.dna.features["body_markings_color_2"]
+ return overlay
+ else if(draw_layer == bitflag_to_layer(EXTERNAL_ADJACENT_3))
+ overlay.color = limb.owner.dna.features["body_markings_color_3"]
+ return overlay
+
+/datum/preference/choiced/lizard_body_markings/icon_for(value)
+ var/datum/sprite_accessory/sprite_accessory = value ? SSaccessories.lizard_markings_list[value] : /datum/sprite_accessory/blank
+
+ var/icon/final_icon = icon('icons/mob/human/species/lizard/bodyparts.dmi', "lizard_chest_m")
+
+ if (sprite_accessory.icon_state != "none")
+ var/icon/markings_icon_1 = icon(sprite_accessory.icon, "male_[sprite_accessory.icon_state]_chest")
+ markings_icon_1.Blend(COLOR_RED, ICON_MULTIPLY)
+ var/icon/markings_icon_2 = icon(sprite_accessory.icon, "male_[sprite_accessory.icon_state]_chest_2")
+ markings_icon_2.Blend(COLOR_VIBRANT_LIME, ICON_MULTIPLY)
+ var/icon/markings_icon_3 = icon(sprite_accessory.icon, "male_[sprite_accessory.icon_state]_chest_3")
+ markings_icon_3.Blend(COLOR_BLUE, ICON_MULTIPLY)
+ final_icon.Blend(markings_icon_1, ICON_OVERLAY)
+ final_icon.Blend(markings_icon_2, ICON_OVERLAY)
+ final_icon.Blend(markings_icon_3, ICON_OVERLAY)
+
+ final_icon.Crop(10, 8, 22, 23)
+ final_icon.Scale(26, 32)
+ final_icon.Crop(-2, 1, 29, 32)
+
+ return final_icon
diff --git a/modular_doppler/modular_customization/preferences/frills.dm b/modular_doppler/modular_customization/preferences/frills.dm
new file mode 100644
index 0000000000000..34a34c816b027
--- /dev/null
+++ b/modular_doppler/modular_customization/preferences/frills.dm
@@ -0,0 +1,76 @@
+/obj/item/organ/external/frills/modular
+ name = "frills"
+ preference = "feature_frills"
+ bodypart_overlay = /datum/bodypart_overlay/mutant/frills/modular
+
+/datum/bodypart_overlay/mutant/frills/modular
+ layers = EXTERNAL_ADJACENT | EXTERNAL_ADJACENT_2 | EXTERNAL_ADJACENT_3
+
+/datum/bodypart_overlay/mutant/frills/modular/color_image(image/overlay, draw_layer, obj/item/bodypart/limb)
+ if(limb == null)
+ return ..()
+ if(limb.owner == null)
+ return ..()
+ if(draw_layer == bitflag_to_layer(EXTERNAL_ADJACENT))
+ overlay.color = limb.owner.dna.features["frills_color_1"]
+ return overlay
+ else if(draw_layer == bitflag_to_layer(EXTERNAL_ADJACENT_2))
+ overlay.color = limb.owner.dna.features["frills_color_2"]
+ return overlay
+ else if(draw_layer == bitflag_to_layer(EXTERNAL_ADJACENT_3))
+ overlay.color = limb.owner.dna.features["frills_color_3"]
+ return overlay
+ return ..()
+
+//core toggle
+/datum/preference/toggle/frills
+ savefile_key = "has_frills"
+ savefile_identifier = PREFERENCE_CHARACTER
+ category = PREFERENCE_CATEGORY_SECONDARY_FEATURES
+ priority = PREFERENCE_PRIORITY_DEFAULT
+
+/datum/preference/toggle/frills/apply_to_human(mob/living/carbon/human/target, value)
+ if(value == FALSE)
+ target.dna.features["frills"] = /datum/sprite_accessory/blank::name
+
+/datum/preference/toggle/frills/create_default_value()
+ return FALSE
+
+/datum/species/regenerate_organs(mob/living/carbon/target, datum/species/old_species, replace_current = TRUE, list/excluded_zones, visual_only = FALSE)
+ . = ..()
+ if(target.dna.features["frills"])
+ if(target.dna.features["frills"] != /datum/sprite_accessory/blank::name)
+ var/obj/item/organ/replacement = SSwardrobe.provide_type(/obj/item/organ/external/frills/modular)
+ replacement.Insert(target, special = TRUE, movement_flags = DELETE_IF_REPLACED)
+ return .
+ var/obj/item/organ/old_part = target.get_organ_slot(ORGAN_SLOT_EXTERNAL_FRILLS)
+ if(old_part)
+ old_part.Remove(target, special = TRUE, movement_flags = DELETE_IF_REPLACED)
+ old_part.moveToNullspace()
+
+//sprite selection
+/datum/preference/choiced/frills
+ category = PREFERENCE_CATEGORY_CLOTHING
+ savefile_key = "feature_frills"
+ savefile_identifier = PREFERENCE_CHARACTER
+ main_feature_name = "Frills"
+ should_generate_icons = TRUE
+
+/datum/preference/choiced/frills/is_accessible(datum/preferences/preferences)
+ . = ..()
+ var/has_frills = preferences.read_preference(/datum/preference/toggle/frills)
+ if(has_frills == TRUE)
+ return TRUE
+ return FALSE
+
+/datum/preference/choiced/frills/init_possible_values()
+ return assoc_to_keys_features(SSaccessories.frills_list)
+
+/datum/preference/choiced/frills/icon_for(value)
+ return generate_lizard_side_shot(SSaccessories.frills_list[value], "frills")
+
+/datum/preference/choiced/frills/apply_to_human(mob/living/carbon/human/target, value)
+ target.dna.features["frills"] = value
+
+/datum/preference/choiced/frills/create_default_value()
+ return /datum/sprite_accessory/blank::name
diff --git a/modular_doppler/modular_customization/preferences/horns.dm b/modular_doppler/modular_customization/preferences/horns.dm
new file mode 100644
index 0000000000000..c735fe2a3403b
--- /dev/null
+++ b/modular_doppler/modular_customization/preferences/horns.dm
@@ -0,0 +1,76 @@
+/obj/item/organ/external/horns/modular
+ name = "horns"
+ preference = "feature_horns"
+ bodypart_overlay = /datum/bodypart_overlay/mutant/horns/modular
+
+/datum/bodypart_overlay/mutant/horns/modular
+ layers = EXTERNAL_ADJACENT | EXTERNAL_ADJACENT_2 | EXTERNAL_ADJACENT_3
+
+/datum/bodypart_overlay/mutant/horns/modular/color_image(image/overlay, draw_layer, obj/item/bodypart/limb)
+ if(limb == null)
+ return ..()
+ if(limb.owner == null)
+ return ..()
+ if(draw_layer == bitflag_to_layer(EXTERNAL_ADJACENT))
+ overlay.color = limb.owner.dna.features["horns_color_1"]
+ return overlay
+ else if(draw_layer == bitflag_to_layer(EXTERNAL_ADJACENT_2))
+ overlay.color = limb.owner.dna.features["horns_color_2"]
+ return overlay
+ else if(draw_layer == bitflag_to_layer(EXTERNAL_ADJACENT_3))
+ overlay.color = limb.owner.dna.features["horns_color_3"]
+ return overlay
+ return ..()
+
+//core toggle
+/datum/preference/toggle/horns
+ savefile_key = "has_horns"
+ savefile_identifier = PREFERENCE_CHARACTER
+ category = PREFERENCE_CATEGORY_SECONDARY_FEATURES
+ priority = PREFERENCE_PRIORITY_DEFAULT
+
+/datum/preference/toggle/horns/apply_to_human(mob/living/carbon/human/target, value)
+ if(value == FALSE)
+ target.dna.features["horns"] = /datum/sprite_accessory/blank::name
+
+/datum/preference/toggle/horns/create_default_value()
+ return FALSE
+
+/datum/species/regenerate_organs(mob/living/carbon/target, datum/species/old_species, replace_current = TRUE, list/excluded_zones, visual_only = FALSE)
+ . = ..()
+ if(target.dna.features["horns"])
+ if(target.dna.features["horns"] != /datum/sprite_accessory/blank::name)
+ var/obj/item/organ/replacement = SSwardrobe.provide_type(/obj/item/organ/external/horns/modular)
+ replacement.Insert(target, special = TRUE, movement_flags = DELETE_IF_REPLACED)
+ return .
+ var/obj/item/organ/old_part = target.get_organ_slot(ORGAN_SLOT_EXTERNAL_HORNS)
+ if(old_part)
+ old_part.Remove(target, special = TRUE, movement_flags = DELETE_IF_REPLACED)
+ old_part.moveToNullspace()
+
+//sprite selection
+/datum/preference/choiced/horns
+ savefile_key = "feature_horns"
+ savefile_identifier = PREFERENCE_CHARACTER
+ main_feature_name = "Horns"
+ should_generate_icons = TRUE
+ category = PREFERENCE_CATEGORY_CLOTHING
+
+/datum/preference/choiced/horns/is_accessible(datum/preferences/preferences)
+ . = ..()
+ var/has_horns = preferences.read_preference(/datum/preference/toggle/horns)
+ if(has_horns == TRUE)
+ return TRUE
+ return FALSE
+
+/datum/preference/choiced/horns/init_possible_values()
+ return assoc_to_keys_features(SSaccessories.horns_list)
+
+/datum/preference/choiced/horns/icon_for(value)
+ return generate_lizard_side_shot(SSaccessories.horns_list[value], "horns")
+
+/datum/preference/choiced/horns/apply_to_human(mob/living/carbon/human/target, value)
+ target.dna.features["horns"] = value
+
+/datum/preference/choiced/horns/create_default_value()
+ return /datum/sprite_accessory/blank::name
diff --git a/modular_doppler/modular_customization/preferences/snout.dm b/modular_doppler/modular_customization/preferences/snout.dm
new file mode 100644
index 0000000000000..3336f030292a2
--- /dev/null
+++ b/modular_doppler/modular_customization/preferences/snout.dm
@@ -0,0 +1,76 @@
+/obj/item/organ/external/snout/modular
+ name = "snout"
+ preference = "feature_snout"
+ bodypart_overlay = /datum/bodypart_overlay/mutant/snout/modular
+
+/datum/bodypart_overlay/mutant/snout/modular
+ layers = EXTERNAL_ADJACENT | EXTERNAL_ADJACENT_2 | EXTERNAL_ADJACENT_3
+
+/datum/bodypart_overlay/mutant/snout/modular/color_image(image/overlay, draw_layer, obj/item/bodypart/limb)
+ if(limb == null)
+ return ..()
+ if(limb.owner == null)
+ return ..()
+ if(draw_layer == bitflag_to_layer(EXTERNAL_ADJACENT))
+ overlay.color = limb.owner.dna.features["snout_color_1"]
+ return overlay
+ else if(draw_layer == bitflag_to_layer(EXTERNAL_ADJACENT_2))
+ overlay.color = limb.owner.dna.features["snout_color_2"]
+ return overlay
+ else if(draw_layer == bitflag_to_layer(EXTERNAL_ADJACENT_3))
+ overlay.color = limb.owner.dna.features["snout_color_3"]
+ return overlay
+ return ..()
+
+//core toggle
+/datum/preference/toggle/snout
+ savefile_key = "has_snout"
+ savefile_identifier = PREFERENCE_CHARACTER
+ category = PREFERENCE_CATEGORY_SECONDARY_FEATURES
+ priority = PREFERENCE_PRIORITY_DEFAULT
+
+/datum/preference/toggle/snout/apply_to_human(mob/living/carbon/human/target, value)
+ if(value == FALSE)
+ target.dna.features["snout"] = /datum/sprite_accessory/blank::name
+
+/datum/preference/toggle/snout/create_default_value()
+ return FALSE
+
+/datum/species/regenerate_organs(mob/living/carbon/target, datum/species/old_species, replace_current = TRUE, list/excluded_zones, visual_only = FALSE)
+ . = ..()
+ if(target.dna.features["snout"])
+ if(target.dna.features["snout"] != /datum/sprite_accessory/blank::name)
+ var/obj/item/organ/replacement = SSwardrobe.provide_type(/obj/item/organ/external/snout/modular)
+ replacement.Insert(target, special = TRUE, movement_flags = DELETE_IF_REPLACED)
+ return .
+ var/obj/item/organ/old_part = target.get_organ_slot(ORGAN_SLOT_EXTERNAL_SNOUT)
+ if(old_part)
+ old_part.Remove(target, special = TRUE, movement_flags = DELETE_IF_REPLACED)
+ old_part.moveToNullspace()
+
+//sprite selection
+/datum/preference/choiced/snout
+ savefile_key = "feature_snout"
+ savefile_identifier = PREFERENCE_CHARACTER
+ category = PREFERENCE_CATEGORY_CLOTHING
+ main_feature_name = "Snout"
+ should_generate_icons = TRUE
+
+/datum/preference/choiced/snout/is_accessible(datum/preferences/preferences)
+ . = ..()
+ var/has_snout = preferences.read_preference(/datum/preference/toggle/snout)
+ if(has_snout == TRUE)
+ return TRUE
+ return FALSE
+
+/datum/preference/choiced/snout/init_possible_values()
+ return assoc_to_keys_features(SSaccessories.snouts_list)
+
+/datum/preference/choiced/snout/icon_for(value)
+ return generate_lizard_side_shot(SSaccessories.snouts_list[value], "snout", include_snout = FALSE)
+
+/datum/preference/choiced/snout/apply_to_human(mob/living/carbon/human/target, value)
+ target.dna.features["snout"] = value
+
+/datum/preference/choiced/snout/create_default_value()
+ return /datum/sprite_accessory/blank::name
diff --git a/modular_doppler/modular_customization/preferences/tails.dm b/modular_doppler/modular_customization/preferences/tails.dm
new file mode 100644
index 0000000000000..dad3324226b77
--- /dev/null
+++ b/modular_doppler/modular_customization/preferences/tails.dm
@@ -0,0 +1,115 @@
+/obj/item/organ/external/tail/modular
+ name = "tail"
+ preference = "feature_tail"
+ bodypart_overlay = /datum/bodypart_overlay/mutant/tail/modular
+
+/datum/bodypart_overlay/mutant/tail/modular
+ layers = EXTERNAL_FRONT | EXTERNAL_FRONT_2 | EXTERNAL_FRONT_3 | EXTERNAL_BEHIND | EXTERNAL_BEHIND_2 | EXTERNAL_BEHIND_3
+ feature_key_sprite = "tail"
+ feature_key = "tail_cat"
+
+/datum/bodypart_overlay/mutant/tail/modular/color_image(image/overlay, draw_layer, obj/item/bodypart/limb)
+ if(limb == null)
+ return ..()
+ if(limb.owner == null)
+ return ..()
+ if(draw_layer == bitflag_to_layer(EXTERNAL_FRONT))
+ overlay.color = limb.owner.dna.features["tail_color_1"]
+ return overlay
+ else if(draw_layer == bitflag_to_layer(EXTERNAL_BEHIND))
+ overlay.color = limb.owner.dna.features["tail_color_1"]
+ return overlay
+ else if(draw_layer == bitflag_to_layer(EXTERNAL_FRONT_2))
+ overlay.color = limb.owner.dna.features["tail_color_2"]
+ return overlay
+ else if(draw_layer == bitflag_to_layer(EXTERNAL_BEHIND_2))
+ overlay.color = limb.owner.dna.features["tail_color_2"]
+ return overlay
+ else if(draw_layer == bitflag_to_layer(EXTERNAL_FRONT_3))
+ overlay.color = limb.owner.dna.features["tail_color_3"]
+ return overlay
+ else if(draw_layer == bitflag_to_layer(EXTERNAL_BEHIND_3))
+ overlay.color = limb.owner.dna.features["tail_color_3"]
+ return overlay
+ return ..()
+
+//core toggle
+/datum/preference/toggle/tail
+ savefile_key = "has_tail"
+ savefile_identifier = PREFERENCE_CHARACTER
+ category = PREFERENCE_CATEGORY_SECONDARY_FEATURES
+ priority = PREFERENCE_PRIORITY_DEFAULT
+
+/datum/preference/toggle/tail/create_default_value()
+ return FALSE
+
+/datum/preference/toggle/tail/apply_to_human(mob/living/carbon/human/target, value)
+ if(value == FALSE)
+ target.dna.features["tail_cat"] = /datum/sprite_accessory/blank::name
+
+//sprite selection
+/datum/preference/choiced/tail
+ savefile_key = "feature_tail"
+ savefile_identifier = PREFERENCE_CHARACTER
+ category = PREFERENCE_CATEGORY_CLOTHING
+ relevant_external_organ = null
+ should_generate_icons = TRUE
+ main_feature_name = "Tail"
+
+/datum/preference/choiced/tail/is_accessible(datum/preferences/preferences)
+ . = ..()
+ var/has_tail = preferences.read_preference(/datum/preference/toggle/tail)
+ if(has_tail == TRUE)
+ return TRUE
+ return FALSE
+
+/datum/preference/choiced/tail/init_possible_values()
+ return assoc_to_keys_features(SSaccessories.tails_list_human)
+
+/datum/species/regenerate_organs(mob/living/carbon/target, datum/species/old_species, replace_current = TRUE, list/excluded_zones, visual_only = FALSE)
+ . = ..()
+ if(target == null)
+ return
+ if(target.dna.features["tail_cat"])
+ if(target.dna.features["tail_cat"] != /datum/sprite_accessory/blank::name)
+ var/obj/item/organ/replacement = SSwardrobe.provide_type(/obj/item/organ/external/tail/modular) // text2path("/obj/item/organ/external/tail/modular/[find_animal_trait(target)]")
+ replacement.Insert(target, special = TRUE, movement_flags = DELETE_IF_REPLACED)
+ return .
+ var/obj/item/organ/external/tail/old_part = target.get_organ_slot(ORGAN_SLOT_EXTERNAL_TAIL)
+ if(istype(old_part))
+ old_part.Remove(target, special = TRUE, movement_flags = DELETE_IF_REPLACED)
+ old_part.moveToNullspace()
+
+/datum/preference/choiced/tail/apply_to_human(mob/living/carbon/human/target, value)
+ target.dna.features["tail_cat"] = value
+
+/datum/preference/choiced/tail/icon_for(value)
+ var/datum/sprite_accessory/sprite_accessory = value ? SSaccessories.tails_list_human[value] : /datum/sprite_accessory/blank
+
+ var/icon/final_icon = icon('icons/mob/human/bodyparts_greyscale.dmi', "human_chest_m", NORTH)
+
+ if (sprite_accessory.icon_state != "None")
+ var/icon/markings_icon_1 = icon(sprite_accessory.icon, "m_tail_[sprite_accessory.icon_state]_BEHIND", NORTH)
+ markings_icon_1.Blend(COLOR_RED, ICON_MULTIPLY)
+ var/icon/markings_icon_2 = icon(sprite_accessory.icon, "m_tail_[sprite_accessory.icon_state]_BEHIND_2", NORTH)
+ markings_icon_2.Blend(COLOR_VIBRANT_LIME, ICON_MULTIPLY)
+ var/icon/markings_icon_3 = icon(sprite_accessory.icon, "m_tail_[sprite_accessory.icon_state]_BEHIND_3", NORTH)
+ markings_icon_3.Blend(COLOR_BLUE, ICON_MULTIPLY)
+ final_icon.Blend(markings_icon_1, ICON_OVERLAY)
+ final_icon.Blend(markings_icon_2, ICON_OVERLAY)
+ final_icon.Blend(markings_icon_3, ICON_OVERLAY)
+ // front breaker
+ var/icon/markings_icon_1_f = icon(sprite_accessory.icon, "m_tail_[sprite_accessory.icon_state]_FRONT", NORTH)
+ markings_icon_1_f.Blend(COLOR_RED, ICON_MULTIPLY)
+ var/icon/markings_icon_2_f = icon(sprite_accessory.icon, "m_tail_[sprite_accessory.icon_state]_FRONT_2", NORTH)
+ markings_icon_2_f.Blend(COLOR_VIBRANT_LIME, ICON_MULTIPLY)
+ var/icon/markings_icon_3_f = icon(sprite_accessory.icon, "m_tail_[sprite_accessory.icon_state]_FRONT_3", NORTH)
+ markings_icon_3_f.Blend(COLOR_BLUE, ICON_MULTIPLY)
+ final_icon.Blend(markings_icon_1_f, ICON_OVERLAY)
+ final_icon.Blend(markings_icon_2_f, ICON_OVERLAY)
+ final_icon.Blend(markings_icon_3_f, ICON_OVERLAY)
+
+ return final_icon
+
+/datum/preference/choiced/tail/create_default_value()
+ return /datum/sprite_accessory/blank::name
diff --git a/modular_doppler/customization/code/tri_color_prefs.dm b/modular_doppler/modular_customization/tri_color/tri_color_prefs.dm
similarity index 72%
rename from modular_doppler/customization/code/tri_color_prefs.dm
rename to modular_doppler/modular_customization/tri_color/tri_color_prefs.dm
index 8e9e5866a3674..3d96c269aa748 100644
--- a/modular_doppler/customization/code/tri_color_prefs.dm
+++ b/modular_doppler/modular_customization/tri_color/tri_color_prefs.dm
@@ -51,7 +51,7 @@
return TRUE
// Gotta add to the selector too
-/datum/preference/choiced/lizard_snout/compile_constant_data()
+/datum/preference/choiced/snout/compile_constant_data()
var/list/data = ..()
data[SUPPLEMENTAL_FEATURE_KEY] = /datum/preference/tri_color/snout_color::savefile_key
@@ -85,7 +85,7 @@
return TRUE
// Gotta add to the selector too
-/datum/preference/choiced/lizard_horns/compile_constant_data()
+/datum/preference/choiced/horns/compile_constant_data()
var/list/data = ..()
data[SUPPLEMENTAL_FEATURE_KEY] = /datum/preference/tri_color/horns_color::savefile_key
@@ -119,7 +119,7 @@
return TRUE
// Gotta add to the selector too
-/datum/preference/choiced/lizard_frills/compile_constant_data()
+/datum/preference/choiced/frills/compile_constant_data()
var/list/data = ..()
data[SUPPLEMENTAL_FEATURE_KEY] = /datum/preference/tri_color/frills_color::savefile_key
@@ -153,15 +153,13 @@
return TRUE
// Gotta add to the selector too
-/datum/preference/choiced/lizard_tail/compile_constant_data()
+/datum/preference/choiced/tail/compile_constant_data()
var/list/data = ..()
data[SUPPLEMENTAL_FEATURE_KEY] = /datum/preference/tri_color/tail_color::savefile_key
return data
-
-
/// Ears colors!
/datum/preference/tri_color/ears_color
priority = PREFERENCE_PRIORITY_BODY_TYPE
@@ -263,41 +261,6 @@
return data
-
-
-/// Moth marking colors!
-/datum/preference/tri_color/moth_markings_color
- priority = PREFERENCE_PRIORITY_BODY_TYPE
- savefile_key = "moth_markings_color"
- savefile_identifier = PREFERENCE_CHARACTER
- category = PREFERENCE_CATEGORY_SUPPLEMENTAL_FEATURES
-
-/datum/preference/tri_color/moth_markings_color/create_default_value()
- return list(sanitize_hexcolor("[pick("7F", "FF")][pick("7F", "FF")][pick("7F", "FF")]"),
- sanitize_hexcolor("[pick("7F", "FF")][pick("7F", "FF")][pick("7F", "FF")]"),
- sanitize_hexcolor("[pick("7F", "FF")][pick("7F", "FF")][pick("7F", "FF")]"))
-
-/datum/preference/tri_color/moth_markings_color/apply_to_human(mob/living/carbon/human/target, value)
- target.dna.features["moth_markings_color_1"] = value[1]
- target.dna.features["moth_markings_color_2"] = value[2]
- target.dna.features["moth_markings_color_3"] = value[3]
-
-/datum/preference/tri_color/moth_markings_color/is_valid(value)
- if (!..(value))
- return FALSE
-
- return TRUE
-
-// Gotta add to the selector too
-/datum/preference/choiced/moth_markings/compile_constant_data()
- var/list/data = ..()
-
- data[SUPPLEMENTAL_FEATURE_KEY] = /datum/preference/tri_color/moth_markings_color::savefile_key
-
- return data
-
-
-
/// Standard marking colors!
/datum/preference/tri_color/body_markings_color
priority = PREFERENCE_PRIORITY_BODY_TYPE
@@ -328,72 +291,3 @@
data[SUPPLEMENTAL_FEATURE_KEY] = /datum/preference/tri_color/body_markings_color::savefile_key
return data
-
-
-
-/// Wing colors!
-/datum/preference/tri_color/wings_color
- priority = PREFERENCE_PRIORITY_BODY_TYPE
- savefile_key = "wings_color"
- savefile_identifier = PREFERENCE_CHARACTER
- category = PREFERENCE_CATEGORY_SUPPLEMENTAL_FEATURES
- //relevant_external_organ = /obj/item/organ/external/wings
-
-/datum/preference/tri_color/wings_color/create_default_value()
- return list(sanitize_hexcolor("[pick("7F", "FF")][pick("7F", "FF")][pick("7F", "FF")]"),
- sanitize_hexcolor("[pick("7F", "FF")][pick("7F", "FF")][pick("7F", "FF")]"),
- sanitize_hexcolor("[pick("7F", "FF")][pick("7F", "FF")][pick("7F", "FF")]"))
-
-/datum/preference/tri_color/wings_color/apply_to_human(mob/living/carbon/human/target, value)
- target.dna.features["wings_color_1"] = value[1]
- target.dna.features["wings_color_2"] = value[2]
- target.dna.features["wings_color_3"] = value[3]
-
-/datum/preference/tri_color/wings_color/is_valid(value)
- if (!..(value))
- return FALSE
-
- return TRUE
-
-// Gotta add to the selector too
-// TODO: can we migrate off of moth_wings for this?
-/*/datum/preference/choiced/wings/compile_constant_data()
- var/list/data = ..()
-
- data[SUPPLEMENTAL_FEATURE_KEY] = /datum/preference/tri_color/wings_color::savefile_key
-
- return data*/
-
-
-
-/// Moth antennae colors!
-/datum/preference/tri_color/moth_antennae_color
- priority = PREFERENCE_PRIORITY_BODY_TYPE
- savefile_key = "moth_antennae_color"
- savefile_identifier = PREFERENCE_CHARACTER
- category = PREFERENCE_CATEGORY_SUPPLEMENTAL_FEATURES
- //relevant_external_organ = /obj/item/organ/external/wings
-
-/datum/preference/tri_color/moth_antennae_color/create_default_value()
- return list(sanitize_hexcolor("[pick("7F", "FF")][pick("7F", "FF")][pick("7F", "FF")]"),
- sanitize_hexcolor("[pick("7F", "FF")][pick("7F", "FF")][pick("7F", "FF")]"),
- sanitize_hexcolor("[pick("7F", "FF")][pick("7F", "FF")][pick("7F", "FF")]"))
-
-/datum/preference/tri_color/moth_antennae_color/apply_to_human(mob/living/carbon/human/target, value)
- target.dna.features["moth_antennae_color_1"] = value[1]
- target.dna.features["moth_antennae_color_2"] = value[2]
- target.dna.features["moth_antennae_color_3"] = value[3]
-
-/datum/preference/tri_color/moth_antennae_color/is_valid(value)
- if (!..(value))
- return FALSE
-
- return TRUE
-
-// Gotta add to the selector too
-/datum/preference/choiced/moth_antennae/compile_constant_data()
- var/list/data = ..()
-
- data[SUPPLEMENTAL_FEATURE_KEY] = /datum/preference/tri_color/moth_antennae_color::savefile_key
-
- return data
diff --git a/modular_doppler/customization/code/tri_color_prefs_bespoke.dm b/modular_doppler/modular_customization/tri_color/tri_color_prefs_bespoke.dm
similarity index 84%
rename from modular_doppler/customization/code/tri_color_prefs_bespoke.dm
rename to modular_doppler/modular_customization/tri_color/tri_color_prefs_bespoke.dm
index 436a95a81c969..3b87ea02e4cd8 100644
--- a/modular_doppler/customization/code/tri_color_prefs_bespoke.dm
+++ b/modular_doppler/modular_customization/tri_color/tri_color_prefs_bespoke.dm
@@ -32,8 +32,6 @@
return data*/
-
-
/// Synth antenna colors!
/datum/preference/tri_color/ipc_antenna_color
priority = PREFERENCE_PRIORITY_BODY_TYPE
@@ -69,7 +67,6 @@
return data*/
-
/// Taur body colors!
/datum/preference/tri_color/taur_color
priority = PREFERENCE_PRIORITY_BODY_TYPE
@@ -95,17 +92,39 @@
return TRUE
+/// Wing colors!
+/datum/preference/tri_color/wings_color
+ priority = PREFERENCE_PRIORITY_BODY_TYPE
+ savefile_key = "wings_color"
+ savefile_identifier = PREFERENCE_CHARACTER
+ category = PREFERENCE_CATEGORY_SUPPLEMENTAL_FEATURES
+ //relevant_external_organ = /obj/item/organ/external/wings
+
+/datum/preference/tri_color/wings_color/create_default_value()
+ return list(sanitize_hexcolor("[pick("7F", "FF")][pick("7F", "FF")][pick("7F", "FF")]"),
+ sanitize_hexcolor("[pick("7F", "FF")][pick("7F", "FF")][pick("7F", "FF")]"),
+ sanitize_hexcolor("[pick("7F", "FF")][pick("7F", "FF")][pick("7F", "FF")]"))
+
+/datum/preference/tri_color/wings_color/apply_to_human(mob/living/carbon/human/target, value)
+ target.dna.features["wings_color_1"] = value[1]
+ target.dna.features["wings_color_2"] = value[2]
+ target.dna.features["wings_color_3"] = value[3]
+
+/datum/preference/tri_color/wings_color/is_valid(value)
+ if (!..(value))
+ return FALSE
+
+ return TRUE
+
// Gotta add to the selector too
-// TODO: we need fluff organs & selection
-/*/datum/preference/choiced/moth_fluff/compile_constant_data()
+// TODO: can we migrate off of moth_wings for this?
+/*/datum/preference/choiced/wings/compile_constant_data()
var/list/data = ..()
- data[SUPPLEMENTAL_FEATURE_KEY] = /datum/preference/tri_color/taur_color::savefile_key
+ data[SUPPLEMENTAL_FEATURE_KEY] = /datum/preference/tri_color/wings_color::savefile_key
return data*/
-
-
/// Xenomorph dorsal fin colors!
/datum/preference/tri_color/xenodorsal_color
priority = PREFERENCE_PRIORITY_BODY_TYPE
@@ -140,8 +159,6 @@
return data*/
-
-
/// Xenomorph head colors!
/datum/preference/tri_color/xenohead_color
priority = PREFERENCE_PRIORITY_BODY_TYPE
@@ -166,47 +183,3 @@
return FALSE
return TRUE
-
-// Gotta add to the selector too
-// TODO: we need fluff organs & selection
-/*/datum/preference/choiced/moth_fluff/compile_constant_data()
- var/list/data = ..()
-
- data[SUPPLEMENTAL_FEATURE_KEY] = /datum/preference/tri_color/xenohead_color::savefile_key
-
- return data*/
-
-
-
-/// Moth wing colors!
-/datum/preference/tri_color/moth_wings_color
- priority = PREFERENCE_PRIORITY_BODY_TYPE
- savefile_key = "moth_wings_color"
- savefile_identifier = PREFERENCE_CHARACTER
- category = PREFERENCE_CATEGORY_SUPPLEMENTAL_FEATURES
- //relevant_external_organ = /obj/item/organ/external/wings
-
-/datum/preference/tri_color/moth_wings_color/create_default_value()
- return list(sanitize_hexcolor("[pick("7F", "FF")][pick("7F", "FF")][pick("7F", "FF")]"),
- sanitize_hexcolor("[pick("7F", "FF")][pick("7F", "FF")][pick("7F", "FF")]"),
- sanitize_hexcolor("[pick("7F", "FF")][pick("7F", "FF")][pick("7F", "FF")]"))
-
-/datum/preference/tri_color/moth_wings_color/apply_to_human(mob/living/carbon/human/target, value)
- target.dna.features["moth_wings_color_1"] = value[1]
- target.dna.features["moth_wings_color_2"] = value[2]
- target.dna.features["moth_wings_color_3"] = value[3]
-
-/datum/preference/tri_color/moth_wings_color/is_valid(value)
- if (!..(value))
- return FALSE
-
- return TRUE
-
-// Gotta add to the selector too
-// TODO: can we migrate off of moth_wings for this?
-/datum/preference/choiced/moth_wings/compile_constant_data()
- var/list/data = ..()
-
- data[SUPPLEMENTAL_FEATURE_KEY] = /datum/preference/tri_color/moth_wings_color::savefile_key
-
- return data
diff --git a/modular_doppler/modular_species/_species.dm b/modular_doppler/modular_species/_species.dm
new file mode 100644
index 0000000000000..63bd4f98040b4
--- /dev/null
+++ b/modular_doppler/modular_species/_species.dm
@@ -0,0 +1,33 @@
+/// Animal trait logic goes here!
+// Used for the kemonomimi and anthro species
+
+/// Find or build a user's preferred animal trait
+/datum/species/proc/find_animal_trait(mob/living/carbon/human/target)
+ /// Trait which is given to the target, canine by default
+ var/animal_trait = TRAIT_CANINE
+ // Lets find the chosen trait, exciting!
+ for(var/trait as anything in GLOB.animalistic_traits)
+ if(HAS_TRAIT_FROM(target, trait, TRAIT_ANIMALISTIC))
+ animal_trait = trait
+ break
+ return animal_trait
+
+/// Apply the chosen trait, updating the species data according to the desired organ's data
+// The proc runs before the mutant organs are read and loaded onto the target
+/datum/species/proc/apply_animal_trait(mob/living/carbon/human/target, animal_trait)
+ if(!ishuman(target) || !animal_trait)
+ return
+
+ /// Find and set our new informed tongue!
+ var/obj/item/organ/tongue = text2path("/obj/item/organ/internal/tongue/[animal_trait]")
+ if(tongue) // text2path nulls if it can't find a matching subtype, so don't worry adding an organ for every single trait value
+ mutanttongue = tongue.type
+ /// Find and set our new informed ears!
+ var/obj/item/organ/ears = text2path("/obj/item/organ/internal/ears/[animal_trait]")
+ if(ears)
+ mutantears = ears.type
+ /// Find and set our new informed tail!
+ var/obj/item/organ/tail = text2path("/obj/item/organ/external/tail/[animal_trait]")
+ if(tail)
+ LAZYREMOVE(mutant_organs, typecacheof(/obj/item/organ/external/tail)) // Remove the previous tail, you served us well!
+ LAZYADDASSOC(mutant_organs, tail.type, capitalize(animal_trait)) // This is a bit awkward due to the assoc list, luckily most organ data has their own var instead
diff --git a/modular_doppler/modular_species/species_preferences/species_traits.dm b/modular_doppler/modular_species/species_preferences/species_traits.dm
new file mode 100644
index 0000000000000..0f8b7ff138d58
--- /dev/null
+++ b/modular_doppler/modular_species/species_preferences/species_traits.dm
@@ -0,0 +1,39 @@
+//// Pref logic for kemonimimi species traits
+// defines in `code/__DEFINES/~doppler_defines/traits/declarations.dm`
+/datum/preference/choiced/animalistic
+ main_feature_name = "Animalistic trait"
+ savefile_key = "feature_animalistic"
+ savefile_identifier = PREFERENCE_CHARACTER
+ category = PREFERENCE_CATEGORY_FEATURES
+ priority = PREFERENCE_PRIORITY_DEFAULT //important flag
+ relevant_inherent_trait = TRAIT_ANIMALISTIC
+ should_generate_icons = TRUE
+
+/datum/preference/choiced/animalistic/init_possible_values()
+ return GLOB.animalistic_traits
+
+/datum/preference/choiced/animalistic/icon_for(value)
+ switch(value)
+ if(TRAIT_FELINE)
+ return icon('icons/mob/simple/pets.dmi', "cat2", EAST)
+ if(TRAIT_CANINE)
+ return icon('icons/mob/simple/pets.dmi', "corgi", WEST)
+ if(TRAIT_REPTILE)
+ return icon('icons/mob/simple/animal.dmi', "lizard", EAST)
+ if(TRAIT_LEPORID)
+ return icon('icons/mob/simple/rabbit.dmi', "rabbit_white", WEST)
+ if(TRAIT_AVIAN)
+ return icon('icons/mob/simple/animal.dmi', "chicken_brown", EAST)
+ if(TRAIT_MURIDAE)
+ return icon('icons/mob/simple/animal.dmi', "mouse_white", WEST)
+ if(TRAIT_PISCINE)
+ return icon('icons/mob/simple/carp.dmi', "carp", EAST)
+ if(TRAIT_SIMIAN)
+ return icon('icons/mob/human/human.dmi', "monkey", WEST)
+
+
+/datum/preference/choiced/animalistic/apply_to_human(mob/living/carbon/human/target, value)
+ ADD_TRAIT(target, value, TRAIT_ANIMALISTIC)
+
+/datum/preference/choiced/animalistic/create_default_value()
+ return TRAIT_CANINE
diff --git a/modular_doppler/hearthkin/primitive_catgirls/code/species.dm b/modular_doppler/modular_species/species_types/hearthkin/hearthkin.dm
similarity index 91%
rename from modular_doppler/hearthkin/primitive_catgirls/code/species.dm
rename to modular_doppler/modular_species/species_types/hearthkin/hearthkin.dm
index 577d5adb6cc47..4d0a1a0941f0a 100644
--- a/modular_doppler/hearthkin/primitive_catgirls/code/species.dm
+++ b/modular_doppler/modular_species/species_types/hearthkin/hearthkin.dm
@@ -1,5 +1,5 @@
-/mob/living/carbon/human/species/felinid/primitive
- race = /datum/species/human/felinid/primitive
+/mob/living/carbon/human/species/kemonomimi/primitive
+ race = /datum/species/human/kemonomimi/primitive
/datum/language_holder/primitive_felinid
understood_languages = list(
@@ -12,7 +12,7 @@
)
selected_language = /datum/language/primitive_catgirl
-/datum/species/human/felinid/primitive
+/datum/species/human/kemonomimi/primitive
name = "Primitive Demihuman"
id = SPECIES_FELINE_PRIMITIVE
@@ -35,7 +35,7 @@
TRAIT_USES_SKINTONES,
)
-/datum/species/human/felinid/primitive/on_species_gain(mob/living/carbon/new_primitive, datum/species/old_species, pref_load)
+/datum/species/human/kemonomimi/primitive/on_species_gain(mob/living/carbon/new_primitive, datum/species/old_species, pref_load)
. = ..()
var/mob/living/carbon/human/hearthkin = new_primitive
if(!istype(hearthkin))
@@ -48,14 +48,14 @@
mutation.mutadone_proof = TRUE
mutation.instability = 0
-/datum/species/human/felinid/primitive/on_species_loss(mob/living/carbon/former_primitive, datum/species/new_species, pref_load)
+/datum/species/human/kemonomimi/primitive/on_species_loss(mob/living/carbon/former_primitive, datum/species/new_species, pref_load)
. = ..()
var/mob/living/carbon/human/hearthkin = former_primitive
if(!istype(hearthkin))
return
hearthkin.dna.remove_mutation(/datum/mutation/human/olfaction)
-/datum/species/human/felinid/primitive/prepare_human_for_preview(mob/living/carbon/human/human_for_preview)
+/datum/species/human/kemonomimi/primitive/prepare_human_for_preview(mob/living/carbon/human/human_for_preview)
human_for_preview.set_haircolor("#323442", update = FALSE)
human_for_preview.set_hairstyle("Blunt Bangs Alt", update = TRUE)
human_for_preview.skin_tone = "mediterranean"
@@ -71,7 +71,7 @@
human_for_preview.update_body(is_creating = TRUE)
-/datum/species/human/felinid/primitive/get_species_description()
+/datum/species/human/kemonomimi/primitive/get_species_description()
return list(
"Genetically modified humanoids believed to be descendants of a now centuries old colony \
ship from the pre-bluespace travel era. Still having at least some human traits, they \
@@ -79,7 +79,7 @@
the icemoon's many fauna."
)
-/datum/species/human/felinid/primitive/get_species_lore()
+/datum/species/human/kemonomimi/primitive/get_species_lore()
return list(
"The Hearthkin are a culture of disparate Scandinavian groups all sharing a common origin \
as descendents from demihuman genemodders aboard the good ship Stjarndrakkr, or Star Dragon; \
diff --git a/modular_doppler/modular_species/species_types/kemonomimi/kemonomimi.dm b/modular_doppler/modular_species/species_types/kemonomimi/kemonomimi.dm
new file mode 100644
index 0000000000000..4f8524eb63ff8
--- /dev/null
+++ b/modular_doppler/modular_species/species_types/kemonomimi/kemonomimi.dm
@@ -0,0 +1,36 @@
+//// Kemonomimi - Overwrites and continuiations of
+// code/modules/mob/living/carbon/human/species_types/felinid.dm
+/datum/species/human/kemonomimi
+ name = "Kemonomimi"
+ id = SPECIES_KEMONOMIMI
+ examine_limb_id = SPECIES_HUMAN
+ inherent_traits = list(
+ TRAIT_ANIMALISTIC,
+ TRAIT_USES_SKINTONES,
+ )
+ changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT
+
+/datum/species/human/kemonomimi/get_physical_attributes()
+ return "N/a."
+
+/datum/species/human/kemonomimi/get_species_description()
+ return "N/a."
+
+/datum/species/human/kemonomimi/get_species_lore()
+ return list(
+ "N/a.",
+ )
+
+/datum/species/human/kemonomimi/on_species_gain(mob/living/carbon/human/target, datum/species/old_species, pref_load)
+ apply_animal_trait(target, find_animal_trait(target))
+ return ..()
+
+/datum/species/human/kemonomimi/on_species_loss(mob/living/carbon/human/target, datum/species/new_species, pref_load)
+ . = .. ()
+ REMOVE_TRAITS_IN(target, TRAIT_ANIMALISTIC)
+
+/datum/species/human/kemonomimi/prepare_human_for_preview(mob/living/carbon/human/human_for_preview)
+ // remember to make a puppygirl
+ human_for_preview.set_haircolor("#3a2d22", update = FALSE)
+ human_for_preview.set_hairstyle("Short twintails", update = TRUE)
+ human_for_preview.update_body()
diff --git a/modular_doppler/customization/species/scugs/icons/bodyparts.dmi b/modular_doppler/modular_species/species_types/slugcat/icons/bodyparts.dmi
similarity index 100%
rename from modular_doppler/customization/species/scugs/icons/bodyparts.dmi
rename to modular_doppler/modular_species/species_types/slugcat/icons/bodyparts.dmi
diff --git a/modular_doppler/customization/species/scugs/icons/slugcat_eyes.dmi b/modular_doppler/modular_species/species_types/slugcat/icons/slugcat_eyes.dmi
similarity index 100%
rename from modular_doppler/customization/species/scugs/icons/slugcat_eyes.dmi
rename to modular_doppler/modular_species/species_types/slugcat/icons/slugcat_eyes.dmi
diff --git a/modular_doppler/customization/species/scugs/code/slugcat_species.dm b/modular_doppler/modular_species/species_types/slugcat/slugcat.dm
similarity index 93%
rename from modular_doppler/customization/species/scugs/code/slugcat_species.dm
rename to modular_doppler/modular_species/species_types/slugcat/slugcat.dm
index 18680d4f4babb..f7c6e86603737 100644
--- a/modular_doppler/customization/species/scugs/code/slugcat_species.dm
+++ b/modular_doppler/modular_species/species_types/slugcat/slugcat.dm
@@ -19,17 +19,16 @@
TRAIT_TACKLING_TAILED_DEFENDER,
)
inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID
- body_markings = list(/datum/bodypart_overlay/simple/body_marking/lizard = "None")
+ body_markings = list(/datum/bodypart_overlay/simple/body_marking/lizard = "Slugcat Underbelly")
mutant_organs = list(
- /obj/item/organ/external/horns = "Slugcat",
- /obj/item/organ/external/frills = "None",
- /obj/item/organ/external/snout = "Slugcat",
- /obj/item/organ/external/tail/lizard = "Slugcat",
+ /obj/item/organ/external/horns/modular = "Slugcat",
+ /obj/item/organ/external/snout/modular = "Slugcat",
+ /obj/item/organ/external/tail/modular = "Slugcat",
)
payday_modifier = 1.0
changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT
inert_mutation = /datum/mutation/human/mute
- death_sound = 'modular_doppler/customization/species/scugs/sounds/scugdeath.ogg'
+ death_sound = 'modular_doppler/modular_species/species_types/slugcat/sounds/scugdeath.ogg'
species_language_holder = /datum/language_holder/slugcat
digitigrade_customization = DIGITIGRADE_OPTIONAL
@@ -45,7 +44,7 @@
/// SOUNDS BREAKER
/datum/species/slugcat/get_scream_sound(mob/living/carbon/human/scug)
return pick(
- 'modular_doppler/customization/species/scugs/sounds/scugscream_1.ogg',
+ 'modular_doppler/modular_species/species_types/slugcat/sounds/scugscream_1.ogg',
)
/datum/species/slugcat/get_cough_sound(mob/living/carbon/human/scug)
@@ -85,7 +84,7 @@
return 'sound/voice/human/male_sneeze1.ogg'
/datum/species/lizard/get_laugh_sound(mob/living/carbon/human/scug)
- return 'modular_doppler/customization/species/scugs/sounds/scuglaugh_1.ogg'
+ return 'modular_doppler/modular_species/species_types/slugcat/sounds/scuglaugh_1.ogg'
/datum/species/lizard/get_sigh_sound(mob/living/carbon/human/scug)
if(scug.physique == FEMALE)
diff --git a/modular_doppler/customization/species/scugs/code/slugcat_bodyparts.dm b/modular_doppler/modular_species/species_types/slugcat/slugcat_bodyparts.dm
similarity index 58%
rename from modular_doppler/customization/species/scugs/code/slugcat_bodyparts.dm
rename to modular_doppler/modular_species/species_types/slugcat/slugcat_bodyparts.dm
index ebcfcf5c86eaf..881bab519b3ac 100644
--- a/modular_doppler/customization/species/scugs/code/slugcat_bodyparts.dm
+++ b/modular_doppler/modular_species/species_types/slugcat/slugcat_bodyparts.dm
@@ -1,24 +1,24 @@
/obj/item/bodypart/head/slugcat
- icon_greyscale = 'modular_doppler/customization/species/scugs/icons/bodyparts.dmi'
+ icon_greyscale = 'modular_doppler/modular_species/species_types/slugcat/icons/bodyparts.dmi'
limb_id = SPECIES_SLUGCAT
is_dimorphic = FALSE
- eyes_icon = 'modular_doppler/customization/species/scugs/icons/slugcat_eyes.dmi'
+ eyes_icon = 'modular_doppler/modular_species/species_types/slugcat/icons/slugcat_eyes.dmi'
/obj/item/bodypart/chest/slugcat
- icon_greyscale = 'modular_doppler/customization/species/scugs/icons/bodyparts.dmi'
+ icon_greyscale = 'modular_doppler/modular_species/species_types/slugcat/icons/bodyparts.dmi'
limb_id = SPECIES_SLUGCAT
is_dimorphic = TRUE
/obj/item/bodypart/arm/left/lizard/slugcat
- icon_greyscale = 'modular_doppler/customization/species/scugs/icons/bodyparts.dmi'
+ icon_greyscale = 'modular_doppler/modular_species/species_types/slugcat/icons/bodyparts.dmi'
limb_id = SPECIES_SLUGCAT
/obj/item/bodypart/arm/right/lizard/slugcat
- icon_greyscale = 'modular_doppler/customization/species/scugs/icons/bodyparts.dmi'
+ icon_greyscale = 'modular_doppler/modular_species/species_types/slugcat/icons/bodyparts.dmi'
limb_id = SPECIES_SLUGCAT
/obj/item/bodypart/leg/left/digitigrade/slugcat
- icon_greyscale = 'modular_doppler/customization/species/scugs/icons/bodyparts.dmi'
+ icon_greyscale = 'modular_doppler/modular_species/species_types/slugcat/icons/bodyparts.dmi'
limb_id = BODYPART_ID_DIGITIGRADE
bodyshape = BODYSHAPE_HUMANOID | BODYSHAPE_DIGITIGRADE
@@ -28,7 +28,7 @@
limb_id = SPECIES_SLUGCAT
/obj/item/bodypart/leg/right/digitigrade/slugcat
- icon_greyscale = 'modular_doppler/customization/species/scugs/icons/bodyparts.dmi'
+ icon_greyscale = 'modular_doppler/modular_species/species_types/slugcat/icons/bodyparts.dmi'
limb_id = BODYPART_ID_DIGITIGRADE
bodyshape = BODYSHAPE_HUMANOID | BODYSHAPE_DIGITIGRADE
diff --git a/modular_doppler/customization/species/scugs/sounds/scugdeath.ogg b/modular_doppler/modular_species/species_types/slugcat/sounds/scugdeath.ogg
similarity index 100%
rename from modular_doppler/customization/species/scugs/sounds/scugdeath.ogg
rename to modular_doppler/modular_species/species_types/slugcat/sounds/scugdeath.ogg
diff --git a/modular_doppler/customization/species/scugs/sounds/scuglaugh_1.ogg b/modular_doppler/modular_species/species_types/slugcat/sounds/scuglaugh_1.ogg
similarity index 100%
rename from modular_doppler/customization/species/scugs/sounds/scuglaugh_1.ogg
rename to modular_doppler/modular_species/species_types/slugcat/sounds/scuglaugh_1.ogg
diff --git a/modular_doppler/customization/species/scugs/sounds/scugscream_1.ogg b/modular_doppler/modular_species/species_types/slugcat/sounds/scugscream_1.ogg
similarity index 100%
rename from modular_doppler/customization/species/scugs/sounds/scugscream_1.ogg
rename to modular_doppler/modular_species/species_types/slugcat/sounds/scugscream_1.ogg
diff --git a/modular_doppler/modular_traits/code/neutral.dm b/modular_doppler/modular_traits/code/neutral.dm
deleted file mode 100644
index 1bff3c1539b0f..0000000000000
--- a/modular_doppler/modular_traits/code/neutral.dm
+++ /dev/null
@@ -1,22 +0,0 @@
-/datum/quirk/feline_aspect
- name = "Feline Traits"
- desc = "You happen to act like a feline, for whatever reason. This will replace most other tongue-based speech quirks."
- gain_text = span_notice("Nya could go for some catnip right about now...")
- lose_text = span_notice("You feel less attracted to lasers.")
- medical_record_text = "Patient seems to possess behavior much like a feline."
- mob_trait = TRAIT_FELINE
- icon = FA_ICON_CAT
-
-/datum/quirk/feline_aspect/add_unique(client/client_source)
- var/mob/living/carbon/human/human_holder = quirk_holder
- var/obj/item/organ/internal/tongue/cat/new_tongue = new(get_turf(human_holder))
-
- new_tongue.copy_traits_from(human_holder.get_organ_slot(ORGAN_SLOT_TONGUE))
- new_tongue.Insert(human_holder, special = TRUE, movement_flags = DELETE_IF_REPLACED)
-
-/datum/quirk/feline_aspect/remove()
- var/mob/living/carbon/human/human_holder = quirk_holder
- var/obj/item/organ/internal/tongue/new_tongue = new human_holder.dna.species.mutanttongue
-
- new_tongue.copy_traits_from(human_holder.get_organ_slot(ORGAN_SLOT_TONGUE))
- new_tongue.Insert(human_holder, special = TRUE, movement_flags = DELETE_IF_REPLACED)
diff --git a/modular_doppler/reagent_forging/code/forge.dm b/modular_doppler/reagent_forging/code/forge.dm
index 27902e41c9cbe..b552ff1aea010 100644
--- a/modular_doppler/reagent_forging/code/forge.dm
+++ b/modular_doppler/reagent_forging/code/forge.dm
@@ -156,7 +156,7 @@
. += span_notice("
[src] is currently [forge_temperature] degrees hot, going towards [target_temperature] degrees.
")
- if(reagent_forging && (is_species(user, /datum/species/lizard/ashwalker) || is_species(user, /datum/species/human/felinid/primitive)))
+ if(reagent_forging && (is_species(user, /datum/species/lizard/ashwalker) || is_species(user, /datum/species/human/kemonomimi/primitive)))
. += span_warning("[src] has a fine gold trim, it is ready to imbue chemicals into reagent objects.")
return .
@@ -408,7 +408,7 @@
if(SKILL_LEVEL_LEGENDARY)
if(!forced)
- if(is_species(user, /datum/species/lizard/ashwalker) || is_species(user, /datum/species/human/felinid/primitive))
+ if(is_species(user, /datum/species/lizard/ashwalker) || is_species(user, /datum/species/human/kemonomimi/primitive))
to_chat(user, span_notice("With just the right heat treating technique, metal could be made to accept reagents..."))
create_reagent_forge()
if(forge_level == FORGE_LEVEL_MASTER)
@@ -573,7 +573,7 @@
return
var/mob/living/carbon/human/human_user = user
- if(!is_species(human_user, /datum/species/lizard/ashwalker) && !is_species(human_user, /datum/species/human/felinid/primitive))
+ if(!is_species(human_user, /datum/species/lizard/ashwalker) && !is_species(human_user, /datum/species/human/kemonomimi/primitive))
to_chat(user, span_danger("It is impossible for you to imbue!")) //maybe remove (ashwalkers & icecats only) after some time
return
@@ -623,7 +623,7 @@
return
var/mob/living/carbon/human/human_user = user
- if(!is_species(human_user, /datum/species/lizard/ashwalker) && !is_species(human_user, /datum/species/human/felinid/primitive))
+ if(!is_species(human_user, /datum/species/lizard/ashwalker) && !is_species(human_user, /datum/species/human/kemonomimi/primitive))
to_chat(user, span_danger("It is impossible for you to imbue!")) //maybe remove (ashwalkers & icecats only) after some time
return
diff --git a/tgstation.dme b/tgstation.dme
index c46bc90a16e7e..cce4c1929162f 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -19,7 +19,6 @@
#include "code\_compile_options.dm"
#include "code\_experiments.dm"
#include "code\world.dm"
-#include "code\~doppler_earliest_defines.dm"
#include "code\__DEFINES\__globals.dm"
#include "code\__DEFINES\_atoms.dm"
#include "code\__DEFINES\_bitfields.dm"
@@ -401,6 +400,7 @@
#include "code\__DEFINES\~doppler_defines\keybindings.dm"
#include "code\__DEFINES\~doppler_defines\living.dm"
#include "code\__DEFINES\~doppler_defines\loadout.dm"
+#include "code\__DEFINES\~doppler_defines\mobs.dm"
#include "code\__DEFINES\~doppler_defines\obj_flags_doppler.dm"
#include "code\__DEFINES\~doppler_defines\reagent_forging_tools.dm"
#include "code\__DEFINES\~doppler_defines\reskin_defines.dm"
@@ -410,6 +410,8 @@
#include "code\__DEFINES\~doppler_defines\species.dm"
#include "code\__DEFINES\~doppler_defines\techweb_nodes.dm"
#include "code\__DEFINES\~doppler_defines\traits.dm"
+#include "code\__DEFINES\~doppler_defines\traits\declarations.dm"
+#include "code\__DEFINES\~doppler_defines\traits\sources.dm"
#include "code\__HELPERS\_auxtools_api.dm"
#include "code\__HELPERS\_dreamluau.dm"
#include "code\__HELPERS\_lists.dm"
@@ -6385,19 +6387,6 @@
#include "modular_doppler\cryosleep\code\jobs.dm"
#include "modular_doppler\cryosleep\code\mind.dm"
#include "modular_doppler\cryosleep\code\mood.dm"
-#include "modular_doppler\customization\code\accessory_overrides.dm"
-#include "modular_doppler\customization\code\accessory_overrides_lizard.dm"
-#include "modular_doppler\customization\code\accessory_overrides_moth.dm"
-#include "modular_doppler\customization\code\bodypart_overrides.dm"
-#include "modular_doppler\customization\code\custom_accessories.dm"
-#include "modular_doppler\customization\code\dropdowns_to_icons.dm"
-#include "modular_doppler\customization\code\tri_color_prefs.dm"
-#include "modular_doppler\customization\code\tri_color_prefs_bespoke.dm"
-#include "modular_doppler\customization\species\lizards\code\lizard_accessories.dm"
-#include "modular_doppler\customization\species\lizards\code\lizard_species.dm"
-#include "modular_doppler\customization\species\scugs\code\slugcat_accessories.dm"
-#include "modular_doppler\customization\species\scugs\code\slugcat_bodyparts.dm"
-#include "modular_doppler\customization\species\scugs\code\slugcat_species.dm"
#include "modular_doppler\emotes\code\emotes.dm"
#include "modular_doppler\emotes\code\added_emotes\animal_sounds.dm"
#include "modular_doppler\emotes\code\added_emotes\human_things.dm"
@@ -6416,7 +6405,6 @@
#include "modular_doppler\hearthkin\primitive_catgirls\code\smelling_salts.dm"
#include "modular_doppler\hearthkin\primitive_catgirls\code\spawner.dm"
#include "modular_doppler\hearthkin\primitive_catgirls\code\special_metals.dm"
-#include "modular_doppler\hearthkin\primitive_catgirls\code\species.dm"
#include "modular_doppler\hearthkin\primitive_catgirls\code\translator.dm"
#include "modular_doppler\hearthkin\primitive_cooking_additions\code\big_mortar.dm"
#include "modular_doppler\hearthkin\primitive_cooking_additions\code\cauldron.dm"
@@ -6480,6 +6468,21 @@
#include "modular_doppler\modular_cosmetics\GAGS\greyscale_configs_neck.dm"
#include "modular_doppler\modular_crafting\code\crafting_extended.dm"
#include "modular_doppler\modular_crafting\code\sheet_types.dm"
+#include "modular_doppler\modular_customization\accessories\code\feline_accessories.dm"
+#include "modular_doppler\modular_customization\accessories\code\reptile_accessories.dm"
+#include "modular_doppler\modular_customization\accessories\code\simian_accessories.dm"
+#include "modular_doppler\modular_customization\accessories\overrides\accessory_overrides.dm"
+#include "modular_doppler\modular_customization\bodypart\bodypart_overrides.dm"
+#include "modular_doppler\modular_customization\organs\external\tails.dm"
+#include "modular_doppler\modular_customization\organs\internal\ears.dm"
+#include "modular_doppler\modular_customization\organs\internal\tongue.dm"
+#include "modular_doppler\modular_customization\preferences\body_markings.dm"
+#include "modular_doppler\modular_customization\preferences\frills.dm"
+#include "modular_doppler\modular_customization\preferences\horns.dm"
+#include "modular_doppler\modular_customization\preferences\snout.dm"
+#include "modular_doppler\modular_customization\preferences\tails.dm"
+#include "modular_doppler\modular_customization\tri_color\tri_color_prefs.dm"
+#include "modular_doppler\modular_customization\tri_color\tri_color_prefs_bespoke.dm"
#include "modular_doppler\modular_food_drinks_and_chems\chemistry_reagents.dm"
#include "modular_doppler\modular_food_drinks_and_chems\food_and_drinks\alcohol reagents.dm"
#include "modular_doppler\modular_food_drinks_and_chems\food_and_drinks\drink_reagents.dm"
@@ -6488,7 +6491,12 @@
#include "modular_doppler\modular_items\invisible_gear.dm"
#include "modular_doppler\modular_mob_spawn\code\mob_spawn.dm"
#include "modular_doppler\modular_sounds\code\sounds.dm"
-#include "modular_doppler\modular_traits\code\neutral.dm"
+#include "modular_doppler\modular_species\_species.dm"
+#include "modular_doppler\modular_species\species_preferences\species_traits.dm"
+#include "modular_doppler\modular_species\species_types\hearthkin\hearthkin.dm"
+#include "modular_doppler\modular_species\species_types\kemonomimi\kemonomimi.dm"
+#include "modular_doppler\modular_species\species_types\slugcat\slugcat.dm"
+#include "modular_doppler\modular_species\species_types\slugcat\slugcat_bodyparts.dm"
#include "modular_doppler\modular_traits\code\organs.dm"
#include "modular_doppler\obj_flags_doppler\code\objs.dm"
#include "modular_doppler\pixel_shift\living.dm"
diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/dopplershift_preferences/mutant_tricolors.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/dopplershift_preferences/mutant_tricolors.tsx
index 36adc9e2f725c..d2fb9089c730d 100644
--- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/dopplershift_preferences/mutant_tricolors.tsx
+++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/dopplershift_preferences/mutant_tricolors.tsx
@@ -103,15 +103,6 @@ export const caps_color: Feature = {
component: FeatureTriColorInput,
};
-export const has_markings: FeatureToggle = {
- name: 'Add Part: Basic Markings',
- category: 'GAMEPLAY',
- description: `
- When toggled, adds basic bodymarkings to your character.
- `,
- component: CheckboxInput,
-};
-
export const body_markings_color: Feature = {
name: 'Body Markings Color',
component: FeatureTriColorInput,
@@ -126,11 +117,6 @@ export const has_moth_markings: FeatureToggle = {
component: CheckboxInput,
};
-export const moth_markings_color: Feature = {
- name: 'Moth Markings Color',
- component: FeatureTriColorInput,
-};
-
export const has_wings: FeatureToggle = {
name: 'Add Part: Wings',
category: 'GAMEPLAY',
@@ -154,11 +140,6 @@ export const has_moth_wings: FeatureToggle = {
component: CheckboxInput,
};
-export const moth_wings_color: Feature = {
- name: 'Moth Wings Color',
- component: FeatureTriColorInput,
-};
-
export const has_antennae: FeatureToggle = {
name: 'Add Part: Antennae',
category: 'GAMEPLAY',
@@ -181,8 +162,3 @@ export const has_moth_antennae: FeatureToggle = {
`,
component: CheckboxInput,
};
-
-export const moth_antennae_color: Feature = {
- name: 'Moth Antennae Color',
- component: FeatureTriColorInput,
-};
diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/species_features.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/species_features.tsx
index d517cc720c29c..7034086cb13e3 100644
--- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/species_features.tsx
+++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/species_features.tsx
@@ -123,3 +123,10 @@ export const heterochromatic: Feature = {
name: 'Heterochromatic (Right Eye) color',
component: FeatureColorInput,
};
+
+// Dopplerstation addition start
+export const feature_animalistic: Feature = {
+ name: 'Animalistic trait',
+ component: FeatureDropdownInput,
+};
+// Dopplerstation addition end