Files
MrMelbert 585b02c325 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>
2025-10-30 03:46:32 +01:00

72 lines
2.8 KiB
Plaintext

// This DNA block system is by no means perfect, and individual (Especially feature) blocks still contain a lot of copypaste
// It might be worth abstracting these, and compacting all SSaccessories vars that use dna_blocks into a single keyed list
// That's out of scope for me refactoring DNA, but to be considered for a future atomic change
/// A singleton for handling block-unique functions called by the DNA datum.
///
/// You don't need to add a DNA block for every feature.
/// Only add a new one if you want this feature to be changed via genetics.
/datum/dna_block
/// The length of this block when converted to ascii
var/block_length = DNA_BLOCK_SIZE
/// Returns the unique block created from target. To be used for external calls.
///
/// Does extra checks to make sure target is valid before calling the internal
/// `create_unique_block`, don't override this.
/datum/dna_block/proc/unique_block(mob/living/carbon/human/target)
SHOULD_NOT_OVERRIDE(TRUE)
if(!ishuman(target))
CRASH("Non-human mobs shouldn't have DNA")
return create_unique_block(target)
/// Actually creates the unique block from the inputted target.
/// Not used outside of the type, see `unique_block` instead.
///
/// Children should always override this.
/datum/dna_block/proc/create_unique_block(mob/living/carbon/human/target)
PROTECTED_PROC(TRUE)
return null
/// The position of this block's string in its hash type
/datum/dna_block/proc/position_in_hash()
return null
/// Takes in the old hash and a string value to change this block to inside the hash.
///
/// Returns a new hash with block's value updated
/datum/dna_block/proc/modified_hash(old_hash, value)
var/block_pos = position_in_hash()
if(isnull(block_pos))
return old_hash
var/preceding_blocks = copytext(old_hash, 1, block_pos)
var/succeeding_blocks = copytext(old_hash, block_pos + block_length)
return (preceding_blocks + value + succeeding_blocks)
/// Gets the block string from the hash inserted
/datum/dna_block/proc/get_block(from_hash)
if(isnull(from_hash))
CRASH("Null hash provided for getting dna block string")
var/block_pos = position_in_hash()
return copytext(from_hash, block_pos, block_pos + block_length)
/// Applies the DNA effects/appearance that this block's string encodes
/datum/dna_block/proc/apply_to_mob(mob/living/carbon/human/target, dna_hash)
return
/// Blocks for unique identities (skin tones, hair style, and gender)
/datum/dna_block/identity
abstract_type = /datum/dna_block/identity
/datum/dna_block/identity/position_in_hash()
return GLOB.total_ui_len_by_block[type]
/// Blocks for unique features (mutant color, mutant bodyparts)
/datum/dna_block/feature
abstract_type = /datum/dna_block/feature
/// The feature key this block ties in to.
var/feature_key = null
/datum/dna_block/feature/position_in_hash()
return GLOB.total_uf_len_by_block[type]