Reduces species feature boilerplate (#93570)

## About The Pull Request

Rather than having 100 separate list variables on `SSaccessories`, have
1 list for all feature keys that are associated with sprite accessories

This way you can get a feature by doing
`SSaccessories.feature_list[key]`, instead of necessitating
`SSaccessories.ears_list`, `SSaccessories.tail_list`, etc.

This lets us cut back on a lot of boilerplate in prefs, dna, and organs

## Why It's Good For The Game

We can see the benefit in this example: This is all the code for horn
DNA, bodypart overlay, and preference
```dm
/datum/dna_block/feature/accessory/horn
	feature_key = FEATURE_HORNS
```
```dm
/datum/bodypart_overlay/mutant/horns
	layers = EXTERNAL_ADJACENT
	feature_key = FEATURE_HORNS
	dyable = TRUE

/datum/bodypart_overlay/mutant/horns/can_draw_on_bodypart(obj/item/bodypart/bodypart_owner)
	return !(bodypart_owner.owner?.obscured_slots & HIDEHAIR)
```
```dm
/datum/preference/choiced/species_feature/lizard_horns
	savefile_key = "feature_lizard_horns"
	savefile_identifier = PREFERENCE_CHARACTER
	category = PREFERENCE_CATEGORY_FEATURES
	main_feature_name = "Horns"
	should_generate_icons = TRUE
	relevant_organ = /obj/item/organ/horns

/datum/preference/choiced/species_feature/lizard_horns/icon_for(value)
	return generate_lizard_side_shot(get_accessory_for_value(value), "horns")
```

## Changelog

🆑 Melbert
refactor: Refactored species unique organs slightly, particularly how
they are set up at game start. Report any oddities, like invisible tails
or wings
/🆑

---------

Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
This commit is contained in:
MrMelbert
2025-10-30 03:46:32 +01:00
committed by GitHub
co-authored by Ghom
parent 340f9d5fe8
commit 585b02c325
30 changed files with 181 additions and 374 deletions
+7 -22
View File
@@ -23,7 +23,7 @@ Unlike normal organs, we're actually inside a persons limbs at all times
var/restyle_flags = NONE
///If not null, overrides the appearance with this sprite accessory datum
var/sprite_accessory_override
var/datum/sprite_accessory/sprite_accessory_override
/**accessory_type is optional if you haven't set sprite_datums for the object, and is used mostly to generate sprite_datums from a persons DNA
* For _mob_sprite we make a distinction between "Round Snout" and "round". Round Snout is the name of the sprite datum, while "round" would be part of the sprite
@@ -32,7 +32,7 @@ Unlike normal organs, we're actually inside a persons limbs at all times
/obj/item/organ/proc/setup_bodypart_overlay(accessory_type)
bodypart_overlay = new bodypart_overlay(src)
accessory_type = accessory_type ? accessory_type : sprite_accessory_override
accessory_type ||= sprite_accessory_override
var/update_overlays = TRUE
if(accessory_type)
bodypart_overlay.set_appearance(accessory_type)
@@ -107,7 +107,7 @@ Unlike normal organs, we're actually inside a persons limbs at all times
zone = BODY_ZONE_HEAD
slot = ORGAN_SLOT_EXTERNAL_HORNS
dna_block = /datum/dna_block/feature/horn
dna_block = /datum/dna_block/feature/accessory/horn
restyle_flags = EXTERNAL_RESTYLE_ENAMEL
bodypart_overlay = /datum/bodypart_overlay/mutant/horns
@@ -122,9 +122,6 @@ Unlike normal organs, we're actually inside a persons limbs at all times
/datum/bodypart_overlay/mutant/horns/can_draw_on_bodypart(obj/item/bodypart/bodypart_owner)
return !(bodypart_owner.owner?.obscured_slots & HIDEHAIR)
/datum/bodypart_overlay/mutant/horns/get_global_feature_list()
return SSaccessories.horns_list
///The frills of a lizard (like weird fin ears)
/obj/item/organ/frills
name = "frills"
@@ -134,7 +131,7 @@ Unlike normal organs, we're actually inside a persons limbs at all times
zone = BODY_ZONE_HEAD
slot = ORGAN_SLOT_EXTERNAL_FRILLS
dna_block = /datum/dna_block/feature/frill
dna_block = /datum/dna_block/feature/accessory/frill
restyle_flags = EXTERNAL_RESTYLE_FLESH
bodypart_overlay = /datum/bodypart_overlay/mutant/frills
@@ -148,9 +145,6 @@ Unlike normal organs, we're actually inside a persons limbs at all times
/datum/bodypart_overlay/mutant/frills/can_draw_on_bodypart(obj/item/bodypart/bodypart_owner)
return !(bodypart_owner.owner?.obscured_slots & HIDEEARS)
/datum/bodypart_overlay/mutant/frills/get_global_feature_list()
return SSaccessories.frills_list
///Guess what part of the lizard this is?
/obj/item/organ/snout
name = "lizard snout"
@@ -162,7 +156,7 @@ Unlike normal organs, we're actually inside a persons limbs at all times
external_bodyshapes = BODYSHAPE_SNOUTED
dna_block = /datum/dna_block/feature/snout
dna_block = /datum/dna_block/feature/accessory/snout
restyle_flags = EXTERNAL_RESTYLE_FLESH
bodypart_overlay = /datum/bodypart_overlay/mutant/snout
@@ -176,9 +170,6 @@ Unlike normal organs, we're actually inside a persons limbs at all times
/datum/bodypart_overlay/mutant/snout/can_draw_on_bodypart(obj/item/bodypart/bodypart_owner)
return !(bodypart_owner.owner?.obscured_slots & HIDESNOUT)
/datum/bodypart_overlay/mutant/snout/get_global_feature_list()
return SSaccessories.snouts_list
///A moth's antennae
/obj/item/organ/antennae
name = "moth antennae"
@@ -188,7 +179,7 @@ Unlike normal organs, we're actually inside a persons limbs at all times
zone = BODY_ZONE_HEAD
slot = ORGAN_SLOT_EXTERNAL_ANTENNAE
dna_block = /datum/dna_block/feature/moth_antenna
dna_block = /datum/dna_block/feature/accessory/moth_antenna
restyle_flags = EXTERNAL_RESTYLE_FLESH
bodypart_overlay = /datum/bodypart_overlay/mutant/antennae
@@ -254,9 +245,6 @@ Unlike normal organs, we're actually inside a persons limbs at all times
burn_datum = fetch_sprite_datum(burn_datum) //turn the path into the singleton instance
/datum/bodypart_overlay/mutant/antennae/get_global_feature_list()
return SSaccessories.moth_antennae_list
/datum/bodypart_overlay/mutant/antennae/get_base_icon_state()
return burnt ? burn_datum.icon_state : sprite_datum.icon_state
@@ -273,7 +261,7 @@ Unlike normal organs, we're actually inside a persons limbs at all times
use_mob_sprite_as_obj_sprite = TRUE
dna_block = /datum/dna_block/feature/pod_hair
dna_block = /datum/dna_block/feature/accessory/pod_hair
restyle_flags = EXTERNAL_RESTYLE_PLANT
bodypart_overlay = /datum/bodypart_overlay/mutant/pod_hair
@@ -291,9 +279,6 @@ Unlike normal organs, we're actually inside a persons limbs at all times
///The individual rgb colors are subtracted from this to get the color shifted layer
var/color_inverse_base = 255
/datum/bodypart_overlay/mutant/pod_hair/get_global_feature_list()
return SSaccessories.pod_hair_list
/datum/bodypart_overlay/mutant/pod_hair/color_image(image/overlay, draw_layer, obj/item/bodypart/limb)
if(draw_layer != bitflag_to_layer(color_swapped_layer))
return ..()
+1 -4
View File
@@ -7,7 +7,7 @@
zone = BODY_ZONE_CHEST
slot = ORGAN_SLOT_EXTERNAL_SPINES
dna_block = /datum/dna_block/feature/spine
dna_block = /datum/dna_block/feature/accessory/spine
restyle_flags = EXTERNAL_RESTYLE_FLESH
bodypart_overlay = /datum/bodypart_overlay/mutant/spines
@@ -32,9 +32,6 @@
feature_key = FEATURE_SPINES
dyable = TRUE
/datum/bodypart_overlay/mutant/spines/get_global_feature_list()
return SSaccessories.spines_list
/datum/bodypart_overlay/mutant/spines/can_draw_on_bodypart(obj/item/bodypart/bodypart_owner)
return !(bodypart_owner.owner?.obscured_slots & HIDEJUMPSUIT)
+2 -17
View File
@@ -7,7 +7,7 @@
zone = BODY_ZONE_PRECISE_GROIN
slot = ORGAN_SLOT_EXTERNAL_TAIL
dna_block = /datum/dna_block/feature/tail
dna_block = /datum/dna_block/feature/accessory/tail
restyle_flags = EXTERNAL_RESTYLE_FLESH
// defaults to cat, but the parent type shouldn't be created regardless
@@ -166,9 +166,6 @@
feature_key = FEATURE_TAIL_CAT
color_source = ORGAN_COLOR_HAIR
/datum/bodypart_overlay/mutant/tail/cat/get_global_feature_list()
return SSaccessories.tails_list_felinid
/obj/item/organ/tail/monkey
name = "monkey tail"
icon_state = "severedmonkeytail"
@@ -180,9 +177,6 @@
color_source = NONE
feature_key = FEATURE_TAIL_MONKEY
/datum/bodypart_overlay/mutant/tail/monkey/get_global_feature_list()
return SSaccessories.tails_list_monkey
/obj/item/organ/tail/xeno
name = "alien tail"
desc = "A long and flexible tail slightly resembling a spine, used by its original owner as both weapon and balance aid."
@@ -230,9 +224,6 @@
. = ..()
set_appearance_from_name(default_appearance)
/datum/bodypart_overlay/mutant/tail/xeno/get_global_feature_list()
return SSaccessories.tails_list_xeno
/datum/bodypart_overlay/mutant/tail/xeno/randomize_appearance()
set_appearance_from_name(default_appearance)
@@ -246,15 +237,12 @@
bodypart_overlay = /datum/bodypart_overlay/mutant/tail/lizard
wag_flags = WAG_ABLE
dna_block = /datum/dna_block/feature/tail_lizard
dna_block = /datum/dna_block/feature/accessory/tail_lizard
///Lizard tail bodypart overlay datum
/datum/bodypart_overlay/mutant/tail/lizard
feature_key = FEATURE_TAIL_LIZARD
/datum/bodypart_overlay/mutant/tail/lizard/get_global_feature_list()
return SSaccessories.tails_list_lizard
/obj/item/organ/tail/lizard/fake
name = "fabricated lizard tail"
desc = "A fabricated severed lizard tail. This one's made of synthflesh. Probably not usable for lizard wine."
@@ -268,9 +256,6 @@
/// Key for tail spine states, depends on the shape of the tail. Defined in the tail sprite datum.
var/tail_spine_key = NONE
/datum/bodypart_overlay/mutant/tail_spines/get_global_feature_list()
return SSaccessories.tail_spines_list
/datum/bodypart_overlay/mutant/tail_spines/get_base_icon_state()
return (!isnull(tail_spine_key) ? "[tail_spine_key]_" : "") + (wagging ? "wagging_" : "") + sprite_datum.icon_state // Select the wagging state if appropriate
@@ -166,19 +166,16 @@
/datum/bodypart_overlay/mutant/wings/functional
///Are our wings currently open? Change through open_wings or close_wings()
VAR_PRIVATE/wings_open = FALSE
///Feature render key for opened wings
var/open_feature_key = "wingsopen"
/datum/bodypart_overlay/mutant/wings/functional/get_global_feature_list()
if(wings_open)
return SSaccessories.wings_open_list
else
return SSaccessories.wings_list
return SSaccessories.feature_list[FEATURE_WINGS_OPEN]
return ..()
///Update our wingsprite to the open wings variant
/datum/bodypart_overlay/mutant/wings/functional/proc/open_wings()
wings_open = TRUE
feature_key = open_feature_key
feature_key = FEATURE_WINGS_OPEN
set_appearance_from_name(sprite_datum.name) //It'll look for the same name again, but this time from the open wings list
///Update our wingsprite to the closed wings variant
+1 -4
View File
@@ -5,7 +5,7 @@
name = "moth wings"
desc = "Spread your wings and FLOOOOAAAAAT!"
dna_block = /datum/dna_block/feature/moth_wing
dna_block = /datum/dna_block/feature/accessory/moth_wing
bodypart_overlay = /datum/bodypart_overlay/mutant/wings/moth
restyle_flags = EXTERNAL_RESTYLE_FLESH
@@ -107,9 +107,6 @@
burn_datum = fetch_sprite_datum(burn_datum)
/datum/bodypart_overlay/mutant/wings/moth/get_global_feature_list()
return SSaccessories.moth_wings_list
/datum/bodypart_overlay/mutant/wings/moth/can_draw_on_bodypart(obj/item/bodypart/bodypart_owner)
return !(bodypart_owner.owner?.obscured_slots & HIDEMUTWINGS)