Datumizes DNA blocks, makes DNA cleaner in general (#92061)

## About The Pull Request

Moves all the dna block handling onto singleton datums initialized
inside global lists, to make the handling dna less of a copy-paste mess
and make adding new blocks significantly easier. There is still some
work to be done in the copypaste department but ultimately that falls
under its own PR scope after the core refactor goes through. (Ill
probably do those but it will also be easier for everyone else as the
code is now significantly less of an eyesore)

Both features and identities have been tested through and through, and
seem to be working fine.

Also removed the reliance on weird hardcoded lookup tables for length,
and other similar things that just didn't make sense when I was passing
through DNA code. There's a lot more that fall out of scope for this
exact PR's goal however

## Why It's Good For The Game

I've been told the maintainers will love me for doing this

## Changelog

🆑
code: feature keys are no longer magical strings floating around the
codebase and use proper defines
refactor: DNA blocks are now handled with singleton datums.
/🆑
This commit is contained in:
Waterpig
2025-07-15 00:51:45 +02:00
committed by GitHub
parent c4ee3d604f
commit b01756b97c
52 changed files with 622 additions and 492 deletions

View File

@@ -44,55 +44,40 @@
//DNA - Because fuck you and your magic numbers being all over the codebase. //DNA - Because fuck you and your magic numbers being all over the codebase.
#define DNA_BLOCK_SIZE 3 #define DNA_BLOCK_SIZE 3
#define DNA_BLOCK_SIZE_COLOR DEFAULT_HEX_COLOR_LEN #define DNA_BLOCK_SIZE_COLOR DEFAULT_HEX_COLOR_LEN
#define DNA_GENDER_BLOCK 1
#define DNA_SKIN_TONE_BLOCK 2
#define DNA_EYE_COLOR_LEFT_BLOCK 3
#define DNA_EYE_COLOR_RIGHT_BLOCK 4
#define DNA_HAIRSTYLE_BLOCK 5
#define DNA_HAIR_COLOR_BLOCK 6
#define DNA_FACIAL_HAIRSTYLE_BLOCK 7
#define DNA_FACIAL_HAIR_COLOR_BLOCK 8
#define DNA_HAIRSTYLE_GRADIENT_BLOCK 9
#define DNA_HAIR_COLOR_GRADIENT_BLOCK 10
#define DNA_FACIAL_HAIRSTYLE_GRADIENT_BLOCK 11
#define DNA_FACIAL_HAIR_COLOR_GRADIENT_BLOCK 12
#define DNA_UNI_IDENTITY_BLOCKS 12
/// This number needs to equal the total number of DNA blocks
#define DNA_MUTANT_COLOR_BLOCK 1
#define DNA_ETHEREAL_COLOR_BLOCK 2
#define DNA_LIZARD_MARKINGS_BLOCK 3
#define DNA_TAIL_BLOCK 4
#define DNA_LIZARD_TAIL_BLOCK 5
#define DNA_SNOUT_BLOCK 6
#define DNA_HORNS_BLOCK 7
#define DNA_FRILLS_BLOCK 8
#define DNA_SPINES_BLOCK 9
#define DNA_EARS_BLOCK 10
#define DNA_MOTH_WINGS_BLOCK 11
#define DNA_MOTH_ANTENNAE_BLOCK 12
#define DNA_MOTH_MARKINGS_BLOCK 13
#define DNA_MUSHROOM_CAPS_BLOCK 14
#define DNA_POD_HAIR_BLOCK 15
#define DNA_FISH_TAIL_BLOCK 16
// Hey! Listen up if you're here because you're adding a species feature!
//
// You don't need to add a DNA block for EVERY species feature!
// You ONLY need DNA blocks if you intend to allow players to change it via GENETICS!
// (Which means having a DNA block for a feature tied to a mob without DNA is entirely pointless.)
/// Total amount of DNA blocks, must be equal to the highest DNA block number
#define DNA_FEATURE_BLOCKS 16
#define DNA_SEQUENCE_LENGTH 4 #define DNA_SEQUENCE_LENGTH 4
#define DNA_MUTATION_BLOCKS 8 #define DNA_MUTATION_BLOCKS 8
#define DNA_UNIQUE_ENZYMES_LEN 32 #define DNA_UNIQUE_ENZYMES_LEN 32
//Features - No more magic strings
//These can't just simply use dna block paths like identities, because there's keys that aren't tied to blocks
// Block tied
#define FEATURE_MUTANT_COLOR "mcolor"
#define FEATURE_ETHEREAL_COLOR "ethcolor"
#define FEATURE_EARS "ears"
#define FEATURE_TAIL "tail_cat"
#define FEATURE_TAIL_LIZARD "tail_lizard"
#define FEATURE_TAIL_FISH "tail_fish"
#define FEATURE_SNOUT "snout"
#define FEATURE_LIZARD_MARKINGS "marking_lizard"
#define FEATURE_HORNS "horns"
#define FEATURE_FRILLS "frills"
#define FEATURE_SPINES "spines"
#define FEATURE_MOTH_WINGS "moth_wings"
#define FEATURE_MOTH_ANTENNAE "moth_antennae"
#define FEATURE_MOTH_MARKINGS "moth_markings"
#define FEATURE_MUSH_CAP "caps"
#define FEATURE_POD_HAIR "pod_hair"
// Other
#define FEATURE_WINGS "wings"
#define FEATURE_TAIL_MONKEY "tail_monkey"
#define FEATURE_TAIL_XENO "tail_xeno"
#define FEATURE_TAILSPINES "tailspines" // Different from regular spines, these appear on tails
#define FEATURE_LEGS "legs"
///flag for the transfer_flag argument from dna/proc/copy_dna(). This one makes it so the SE is copied too. ///flag for the transfer_flag argument from dna/proc/copy_dna(). This one makes it so the SE is copied too.
#define COPY_DNA_SE (1<<0) #define COPY_DNA_SE (1<<0)
///flag for the transfer_flag argument from dna/proc/copy_dna(). This one copies the species. ///flag for the transfer_flag argument from dna/proc/copy_dna(). This one copies the species.

View File

@@ -12,7 +12,5 @@
#define GET_MUTATION_POWER(A) ((A.power_coeff < 0) ? 1 : A.power_coeff) #define GET_MUTATION_POWER(A) ((A.power_coeff < 0) ? 1 : A.power_coeff)
#define GET_MUTATION_ENERGY(A) ((A.energy_coeff < 0) ? 1 : A.energy_coeff) #define GET_MUTATION_ENERGY(A) ((A.energy_coeff < 0) ? 1 : A.energy_coeff)
///Getter macro used to get the length of a identity block
#define GET_UI_BLOCK_LEN(blocknum) (GLOB.identity_block_lengths["[blocknum]"] || DNA_BLOCK_SIZE)
///Ditto, but for a feature. ///Ditto, but for a feature.
#define GET_UF_BLOCK_LEN(blocknum) (GLOB.features_block_lengths["[blocknum]"] || DNA_BLOCK_SIZE) #define GET_UF_BLOCK_LEN(blocknum) (GLOB.features_block_lengths["[blocknum]"] || DNA_BLOCK_SIZE)

View File

@@ -197,3 +197,21 @@ GLOBAL_LIST_INIT(construct_radial_images, list(
if(mind) if(mind)
minds += mind minds += mind
return minds return minds
/// A keyed list of identity block singletons, in a key:value group of typepath:block
GLOBAL_LIST_INIT(dna_identity_blocks, init_identity_block_types())
/proc/init_identity_block_types()
. = list()
for(var/datum/dna_block/identity/block_path as anything in subtypesof(/datum/dna_block/identity))
var/datum/dna_block/identity/new_block = new block_path()
.[block_path] = new_block
/// A keyed list of feature block singletons, in a key:value group of typepath:block
GLOBAL_LIST_INIT(dna_feature_blocks, init_feature_block_types())
/proc/init_feature_block_types()
. = list()
for(var/datum/dna_block/feature/block_path as anything in subtypesof(/datum/dna_block/feature))
var/datum/dna_block/feature/new_block = new block_path()
.[block_path] = new_block

View File

@@ -11,6 +11,7 @@ SUBSYSTEM_DEF(accessories) // just 'accessories' for brevity
name = "Sprite Accessories" name = "Sprite Accessories"
flags = SS_NO_FIRE | SS_NO_INIT flags = SS_NO_FIRE | SS_NO_INIT
// HOLY SHIT COMPACT THIS INTO ASSOCIATED LISTS SO WE STOP ADDING VARIABLES
//Hairstyles //Hairstyles
var/list/hairstyles_list //! stores /datum/sprite_accessory/hair indexed by name var/list/hairstyles_list //! stores /datum/sprite_accessory/hair indexed by name
var/list/hairstyles_male_list //! stores only hair names var/list/hairstyles_male_list //! stores only hair names

View File

@@ -43,13 +43,13 @@
return mutable_appearance(icon, gender_string + icon_state + "_" + limb.body_zone, layer = layer) return mutable_appearance(icon, gender_string + icon_state + "_" + limb.body_zone, layer = layer)
/datum/bodypart_overlay/simple/body_marking/moth /datum/bodypart_overlay/simple/body_marking/moth
dna_feature_key = "moth_markings" dna_feature_key = FEATURE_MOTH_MARKINGS
/datum/bodypart_overlay/simple/body_marking/moth/get_accessory(name) /datum/bodypart_overlay/simple/body_marking/moth/get_accessory(name)
return SSaccessories.moth_markings_list[name] return SSaccessories.moth_markings_list[name]
/datum/bodypart_overlay/simple/body_marking/lizard /datum/bodypart_overlay/simple/body_marking/lizard
dna_feature_key = "lizard_markings" dna_feature_key = FEATURE_LIZARD_MARKINGS
applies_to = list(/obj/item/bodypart/chest) applies_to = list(/obj/item/bodypart/chest)
/datum/bodypart_overlay/simple/body_marking/lizard/get_accessory(name) /datum/bodypart_overlay/simple/body_marking/lizard/get_accessory(name)

View File

@@ -0,0 +1,151 @@
/datum/dna_block/feature/mutant_color
block_length = DNA_BLOCK_SIZE_COLOR
feature_key = FEATURE_MUTANT_COLOR
/datum/dna_block/feature/mutant_color/create_unique_block(mob/living/carbon/human/target)
return sanitize_hexcolor(target.dna.features[feature_key], include_crunch = FALSE)
/datum/dna_block/feature/mutant_color/apply_to_mob(mob/living/carbon/human/target, dna_hash)
target.dna.features[feature_key] = sanitize_hexcolor(get_block(dna_hash))
/datum/dna_block/feature/ethereal_color
block_length = DNA_BLOCK_SIZE_COLOR
feature_key = FEATURE_ETHEREAL_COLOR
/datum/dna_block/feature/ethereal_color/create_unique_block(mob/living/carbon/human/target)
return sanitize_hexcolor(target.dna.features[FEATURE_ETHEREAL_COLOR], include_crunch = FALSE)
/datum/dna_block/feature/ethereal_color/apply_to_mob(mob/living/carbon/human/target, dna_hash)
target.dna.features[feature_key] = sanitize_hexcolor(get_block(dna_hash))
/datum/dna_block/feature/ears
feature_key = FEATURE_EARS
/datum/dna_block/feature/ears/create_unique_block(mob/living/carbon/human/target)
return construct_block(SSaccessories.ears_list.Find(target.dna.features[feature_key]), length(SSaccessories.ears_list))
/datum/dna_block/feature/ears/apply_to_mob(mob/living/carbon/human/target, dna_hash)
target.dna.features[feature_key] = SSaccessories.ears_list[deconstruct_block(get_block(dna_hash), length(SSaccessories.ears_list))]
// One day, someone should consider merging all tails into one, this is stupid
// No I don't care that it will "Create situations where a felinid grows a lizard tail" that makes it more fun
/datum/dna_block/feature/tail
feature_key = FEATURE_TAIL
/datum/dna_block/feature/tail/create_unique_block(mob/living/carbon/human/target)
return construct_block(SSaccessories.tails_list_felinid.Find(target.dna.features[feature_key]), length(SSaccessories.tails_list_felinid))
/datum/dna_block/feature/tail/apply_to_mob(mob/living/carbon/human/target, dna_hash)
target.dna.features[feature_key] = SSaccessories.tails_list_felinid[deconstruct_block(get_block(dna_hash), length(SSaccessories.tails_list_felinid))]
/datum/dna_block/feature/tail_lizard
feature_key = FEATURE_TAIL_LIZARD
/datum/dna_block/feature/tail_lizard/create_unique_block(mob/living/carbon/human/target)
return construct_block(SSaccessories.tails_list_lizard.Find(target.dna.features[feature_key]), length(SSaccessories.tails_list_lizard))
/datum/dna_block/feature/tail_lizard/apply_to_mob(mob/living/carbon/human/target, dna_hash)
target.dna.features[feature_key] = SSaccessories.tails_list_lizard[deconstruct_block(get_block(dna_hash), length(SSaccessories.tails_list_lizard))]
/datum/dna_block/feature/tail_fish
feature_key = FEATURE_TAIL_FISH
/datum/dna_block/feature/tail_fish/create_unique_block(mob/living/carbon/human/target)
return construct_block(SSaccessories.tails_list_fish.Find(target.dna.features[feature_key]), length(SSaccessories.tails_list_fish))
/datum/dna_block/feature/tail_fish/apply_to_mob(mob/living/carbon/human/target, dna_hash)
target.dna.features[feature_key] = SSaccessories.tails_list_fish[deconstruct_block(get_block(dna_hash), length(SSaccessories.tails_list_fish))]
/datum/dna_block/feature/snout
feature_key = FEATURE_SNOUT
/datum/dna_block/feature/snout/create_unique_block(mob/living/carbon/human/target)
return construct_block(SSaccessories.snouts_list.Find(target.dna.features[feature_key]), length(SSaccessories.snouts_list))
/datum/dna_block/feature/snout/apply_to_mob(mob/living/carbon/human/target, dna_hash)
target.dna.features[feature_key] = SSaccessories.snouts_list[deconstruct_block(get_block(dna_hash), length(SSaccessories.snouts_list))]
/datum/dna_block/feature/lizard_marking
feature_key = FEATURE_LIZARD_MARKINGS
/datum/dna_block/feature/lizard_marking/create_unique_block(mob/living/carbon/human/target)
return construct_block(SSaccessories.lizard_markings_list.Find(target.dna.features[feature_key]), length(SSaccessories.lizard_markings_list))
/datum/dna_block/feature/lizard_marking/apply_to_mob(mob/living/carbon/human/target, dna_hash)
target.dna.features[feature_key] = SSaccessories.lizard_markings_list[deconstruct_block(get_block(dna_hash), length(SSaccessories.lizard_markings_list))]
/datum/dna_block/feature/horn
feature_key = FEATURE_HORNS
/datum/dna_block/feature/horn/create_unique_block(mob/living/carbon/human/target)
return construct_block(SSaccessories.horns_list.Find(target.dna.features[feature_key]), length(SSaccessories.horns_list))
/datum/dna_block/feature/horn/apply_to_mob(mob/living/carbon/human/target, dna_hash)
target.dna.features[feature_key] = SSaccessories.horns_list[deconstruct_block(get_block(dna_hash), length(SSaccessories.horns_list))]
/datum/dna_block/feature/frill
feature_key = FEATURE_FRILLS
/datum/dna_block/feature/frill/create_unique_block(mob/living/carbon/human/target)
return construct_block(SSaccessories.frills_list.Find(target.dna.features[feature_key]), length(SSaccessories.frills_list))
/datum/dna_block/feature/frill/apply_to_mob(mob/living/carbon/human/target, dna_hash)
target.dna.features[feature_key] = SSaccessories.frills_list[deconstruct_block(get_block(dna_hash), length(SSaccessories.frills_list))]
/datum/dna_block/feature/spine
feature_key = FEATURE_SPINES
/datum/dna_block/feature/spine/create_unique_block(mob/living/carbon/human/target)
return construct_block(SSaccessories.spines_list.Find(target.dna.features[feature_key]), length(SSaccessories.spines_list))
/datum/dna_block/feature/spine/apply_to_mob(mob/living/carbon/human/target, dna_hash)
target.dna.features[feature_key] = SSaccessories.spines_list[deconstruct_block(get_block(dna_hash), length(SSaccessories.spines_list))]
/datum/dna_block/feature/moth_wing
feature_key = FEATURE_MOTH_WINGS
/datum/dna_block/feature/moth_wing/create_unique_block(mob/living/carbon/human/target)
if(target.dna.features[feature_key] == "Burnt Off") // Why is this snowflake check a thing. Please find a way to fix this later
return random_string(block_length, GLOB.hex_characters)
return construct_block(SSaccessories.moth_wings_list.Find(target.dna.features[feature_key]), length(SSaccessories.moth_wings_list))
/datum/dna_block/feature/moth_wing/apply_to_mob(mob/living/carbon/human/target, dna_hash)
target.dna.features[feature_key] = SSaccessories.moth_wings_list[deconstruct_block(get_block(dna_hash), length(SSaccessories.moth_wings_list))]
/datum/dna_block/feature/moth_antenna
feature_key = FEATURE_MOTH_ANTENNAE
/datum/dna_block/feature/moth_antenna/create_unique_block(mob/living/carbon/human/target)
if(target.dna.features[feature_key] == "Burnt Off")
return random_string(block_length, GLOB.hex_characters)
return construct_block(SSaccessories.moth_antennae_list.Find(target.dna.features[feature_key]), length(SSaccessories.moth_antennae_list))
/datum/dna_block/feature/moth_antenna/apply_to_mob(mob/living/carbon/human/target, dna_hash)
target.dna.features[feature_key] = SSaccessories.moth_antennae_list[deconstruct_block(get_block(dna_hash), length(SSaccessories.moth_antennae_list))]
/datum/dna_block/feature/moth_marking
feature_key = FEATURE_MOTH_MARKINGS
/datum/dna_block/feature/moth_marking/create_unique_block(mob/living/carbon/human/target)
return construct_block(SSaccessories.moth_markings_list.Find(target.dna.features[feature_key]), length(SSaccessories.moth_markings_list))
/datum/dna_block/feature/moth_marking/apply_to_mob(mob/living/carbon/human/target, dna_hash)
target.dna.features[feature_key] = SSaccessories.moth_markings_list[deconstruct_block(get_block(dna_hash), length(SSaccessories.moth_markings_list))]
/datum/dna_block/feature/mush_cap
feature_key = FEATURE_MUSH_CAP
/datum/dna_block/feature/mush_cap/create_unique_block(mob/living/carbon/human/target)
return construct_block(SSaccessories.caps_list.Find(target.dna.features[feature_key]), length(SSaccessories.caps_list))
/datum/dna_block/feature/mush_cap/apply_to_mob(mob/living/carbon/human/target, dna_hash)
target.dna.features[feature_key] = SSaccessories.caps_list[deconstruct_block(get_block(dna_hash), length(SSaccessories.caps_list))]
/datum/dna_block/feature/pod_hair
feature_key = FEATURE_POD_HAIR
/datum/dna_block/feature/pod_hair/create_unique_block(mob/living/carbon/human/target)
return construct_block(SSaccessories.pod_hair_list.Find(target.dna.features[feature_key]), length(SSaccessories.pod_hair_list))
/datum/dna_block/feature/pod_hair/apply_to_mob(mob/living/carbon/human/target, dna_hash)
target.dna.features[feature_key] = SSaccessories.pod_hair_list[deconstruct_block(get_block(dna_hash), length(SSaccessories.pod_hair_list))]

View File

@@ -0,0 +1,129 @@
/datum/dna_block/identity/gender
/datum/dna_block/identity/gender/create_unique_block(mob/living/carbon/human/target)
//ignores TRAIT_AGENDER so that a "real" gender can be stored in the DNA if later use is needed
switch(target.gender)
if(MALE)
. = construct_block(G_MALE, GENDERS)
if(FEMALE)
. = construct_block(G_FEMALE, GENDERS)
if(NEUTER)
. = construct_block(G_NEUTER, GENDERS)
else
. = construct_block(G_PLURAL, GENDERS)
return .
/datum/dna_block/identity/gender/apply_to_mob(mob/living/carbon/human/target, dna_hash)
//Always plural gender if agender
if(HAS_TRAIT(target, TRAIT_AGENDER))
target.gender = PLURAL
return
switch(deconstruct_block(get_block(dna_hash), GENDERS))
if(G_MALE)
target.gender = MALE
if(G_FEMALE)
target.gender = FEMALE
if(G_NEUTER)
target.gender = NEUTER
else
target.gender = PLURAL
/datum/dna_block/identity/skin_tone
/datum/dna_block/identity/skin_tone/create_unique_block(mob/living/carbon/human/target)
return construct_block(GLOB.skin_tones.Find(target.skin_tone), GLOB.skin_tones.len)
/datum/dna_block/identity/skin_tone/apply_to_mob(mob/living/carbon/human/target, dna_hash)
target.skin_tone = GLOB.skin_tones[deconstruct_block(get_block(dna_hash), GLOB.skin_tones.len)]
/// Holds both the left and right eye color at once
/datum/dna_block/identity/eye_colors
block_length = DNA_BLOCK_SIZE_COLOR * 2 // Left eye color, then right eye color
/datum/dna_block/identity/eye_colors/create_unique_block(mob/living/carbon/human/target)
var/left = sanitize_hexcolor(target.eye_color_left, include_crunch = FALSE)
var/right = sanitize_hexcolor(target.eye_color_right, include_crunch = FALSE)
return left + right
/datum/dna_block/identity/eye_colors/apply_to_mob(mob/living/carbon/human/target, dna_hash)
var/colors = get_block(dna_hash)
var/right_color_begin = DNA_BLOCK_SIZE_COLOR + 1
target.set_eye_color(sanitize_hexcolor(copytext(colors, 1, right_color_begin)), sanitize_hexcolor(copytext(colors, right_color_begin, length(colors) + 1)))
/datum/dna_block/identity/hair_style
/datum/dna_block/identity/hair_style/create_unique_block(mob/living/carbon/human/target)
return construct_block(SSaccessories.hairstyles_list.Find(target.hairstyle), length(SSaccessories.hairstyles_list))
/datum/dna_block/identity/hair_style/apply_to_mob(mob/living/carbon/human/target, dna_hash)
if(HAS_TRAIT(target, TRAIT_BALD))
target.set_hairstyle("Bald", update = FALSE)
return
var/style = SSaccessories.hairstyles_list[deconstruct_block(get_block(dna_hash), length(SSaccessories.hairstyles_list))]
target.set_hairstyle(style, update = FALSE)
/datum/dna_block/identity/hair_color
block_length = DNA_BLOCK_SIZE_COLOR
/datum/dna_block/identity/hair_color/create_unique_block(mob/living/carbon/human/target)
return sanitize_hexcolor(target.hair_color, include_crunch = FALSE)
/datum/dna_block/identity/hair_color/apply_to_mob(mob/living/carbon/human/target, dna_hash)
target.set_haircolor(sanitize_hexcolor(get_block(dna_hash)), update = FALSE)
/datum/dna_block/identity/facial_style
/datum/dna_block/identity/facial_style/create_unique_block(mob/living/carbon/human/target)
return construct_block(SSaccessories.facial_hairstyles_list.Find(target.facial_hairstyle), length(SSaccessories.facial_hairstyles_list))
/datum/dna_block/identity/facial_style/apply_to_mob(mob/living/carbon/human/target, dna_hash)
if(HAS_TRAIT(src, TRAIT_SHAVED))
target.set_facial_hairstyle("Shaved", update = FALSE)
return
var/style = SSaccessories.facial_hairstyles_list[deconstruct_block(get_block(dna_hash), length(SSaccessories.facial_hairstyles_list))]
target.set_facial_hairstyle(style, update = FALSE)
/datum/dna_block/identity/facial_color
block_length = DNA_BLOCK_SIZE_COLOR
/datum/dna_block/identity/facial_color/create_unique_block(mob/living/carbon/human/target)
return sanitize_hexcolor(target.facial_hair_color, include_crunch = FALSE)
/datum/dna_block/identity/facial_color/apply_to_mob(mob/living/carbon/human/target, dna_hash)
target.set_facial_haircolor(sanitize_hexcolor(get_block(dna_hash)), update = FALSE)
/datum/dna_block/identity/hair_gradient
/datum/dna_block/identity/hair_gradient/create_unique_block(mob/living/carbon/human/target)
return construct_block(SSaccessories.hair_gradients_list.Find(target.grad_style[GRADIENT_HAIR_KEY]), length(SSaccessories.hair_gradients_list))
/datum/dna_block/identity/hair_gradient/apply_to_mob(mob/living/carbon/human/target, dna_hash)
var/gradient_style = SSaccessories.hair_gradients_list[deconstruct_block(get_block(dna_hash), length(SSaccessories.hair_gradients_list))]
target.set_hair_gradient_style(gradient_style, update = FALSE)
/datum/dna_block/identity/hair_gradient_color
block_length = DNA_BLOCK_SIZE_COLOR
/datum/dna_block/identity/hair_gradient_color/create_unique_block(mob/living/carbon/human/target)
return sanitize_hexcolor(target.grad_color[GRADIENT_HAIR_KEY], include_crunch = FALSE)
/datum/dna_block/identity/hair_gradient_color/apply_to_mob(mob/living/carbon/human/target, dna_hash)
target.set_hair_gradient_color(sanitize_hexcolor(get_block(dna_hash)), update = FALSE)
/datum/dna_block/identity/facial_gradient
/datum/dna_block/identity/facial_gradient/create_unique_block(mob/living/carbon/human/target)
return construct_block(SSaccessories.facial_hair_gradients_list.Find(target.grad_style[GRADIENT_FACIAL_HAIR_KEY]), length(SSaccessories.facial_hair_gradients_list))
/datum/dna_block/identity/facial_gradient/apply_to_mob(mob/living/carbon/human/target, dna_hash)
var/gradient_style = SSaccessories.hair_gradients_list[deconstruct_block(get_block(dna_hash), length(SSaccessories.hair_gradients_list))]
target.set_facial_hair_gradient_style(gradient_style, update = FALSE)
/datum/dna_block/identity/facial_gradient_color
block_length = DNA_BLOCK_SIZE_COLOR
/datum/dna_block/identity/facial_gradient_color/create_unique_block(mob/living/carbon/human/target)
return sanitize_hexcolor(target.grad_color[GRADIENT_FACIAL_HAIR_KEY], include_crunch = FALSE)
/datum/dna_block/identity/facial_gradient_color/apply_to_mob(mob/living/carbon/human/target, dna_hash)
target.set_facial_hair_gradient_color(sanitize_hexcolor(get_block(dna_hash)), update = FALSE)

View File

@@ -1,31 +1,3 @@
/**
* Some identity blocks (basically pieces of the unique_identity string variable of the dna datum, commonly abbreviated with ui)
* may have a length that differ from standard length of 3 ASCII characters. This list is necessary
* for these non-standard blocks to work, as well as the entire unique identity string.
* Should you add a new ui block which size differ from the standard (again, 3 ASCII characters), like for example, a color,
* please do not forget to also include it in this list in the following format:
* "[dna block number]" = dna block size,
* Failure to do that may result in bugs. Thanks.
*/
GLOBAL_LIST_INIT(identity_block_lengths, list(
"[DNA_HAIR_COLOR_BLOCK]" = DNA_BLOCK_SIZE_COLOR,
"[DNA_FACIAL_HAIR_COLOR_BLOCK]" = DNA_BLOCK_SIZE_COLOR,
"[DNA_EYE_COLOR_LEFT_BLOCK]" = DNA_BLOCK_SIZE_COLOR,
"[DNA_EYE_COLOR_RIGHT_BLOCK]" = DNA_BLOCK_SIZE_COLOR,
"[DNA_HAIR_COLOR_GRADIENT_BLOCK]" = DNA_BLOCK_SIZE_COLOR,
"[DNA_FACIAL_HAIR_COLOR_GRADIENT_BLOCK]" = DNA_BLOCK_SIZE_COLOR,
))
/**
* The same rules of the above also apply here, with the exception that this is for the unique_features string variable
* (commonly abbreviated with uf) and its blocks. Both ui and uf have a standard block length of 3 ASCII characters.
*/
GLOBAL_LIST_INIT(features_block_lengths, list(
"[DNA_MUTANT_COLOR_BLOCK]" = DNA_BLOCK_SIZE_COLOR,
"[DNA_ETHEREAL_COLOR_BLOCK]" = DNA_BLOCK_SIZE_COLOR,
))
/** /**
* A list of numbers that keeps track of where ui blocks start in the unique_identity string variable of the dna datum. * A list of numbers that keeps track of where ui blocks start in the unique_identity string variable of the dna datum.
* Commonly used by the datum/dna/set_uni_identity_block and datum/dna/get_uni_identity_block procs. * Commonly used by the datum/dna/set_uni_identity_block and datum/dna/get_uni_identity_block procs.
@@ -37,9 +9,10 @@ GLOBAL_LIST_INIT(standard_mutation_sources, list(MUTATION_SOURCE_ACTIVATED, MUTA
/proc/populate_total_ui_len_by_block() /proc/populate_total_ui_len_by_block()
. = list() . = list()
var/total_block_len = 1 var/total_block_len = 1
for(var/blocknumber in 1 to DNA_UNI_IDENTITY_BLOCKS) for(var/block_path in GLOB.dna_identity_blocks)
. += total_block_len var/datum/dna_block/identity/block = GLOB.dna_identity_blocks[block_path]
total_block_len += GET_UI_BLOCK_LEN(blocknumber) .[block_path] += total_block_len
total_block_len += block.block_length
///Ditto but for unique features. Used by the datum/dna/set_uni_feature_block and datum/dna/get_uni_feature_block procs. ///Ditto but for unique features. Used by the datum/dna/set_uni_feature_block and datum/dna/get_uni_feature_block procs.
GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
@@ -47,9 +20,10 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
/proc/populate_total_uf_len_by_block() /proc/populate_total_uf_len_by_block()
. = list() . = list()
var/total_block_len = 1 var/total_block_len = 1
for(var/blocknumber in 1 to DNA_FEATURE_BLOCKS) for(var/block_path in GLOB.dna_feature_blocks)
. += total_block_len var/datum/dna_block/feature/block = GLOB.dna_feature_blocks[block_path]
total_block_len += GET_UF_BLOCK_LEN(blocknumber) .[block_path] += total_block_len
total_block_len += block.block_length
/////////////////////////// DNA DATUM /////////////////////////// DNA DATUM
/datum/dna /datum/dna
@@ -63,7 +37,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
var/datum/species/species = new /datum/species/human var/datum/species/species = new /datum/species/human
/// Assoc list of feature keys to their value /// Assoc list of feature keys to their value
/// Note if you set these manually, and do not update [unique_features] afterwards, it will likely be reset. /// Note if you set these manually, and do not update [unique_features] afterwards, it will likely be reset.
var/list/features = list("mcolor" = COLOR_WHITE) var/list/features = list(FEATURE_MUTANT_COLOR = COLOR_WHITE)
///Stores the hashed values of the person's non-human features ///Stores the hashed values of the person's non-human features
var/unique_features var/unique_features
///Stores the real name of the person who originally got this dna datum. Used primarily for changelings ///Stores the real name of the person who originally got this dna datum. Used primarily for changelings
@@ -211,77 +185,18 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
/datum/dna/proc/generate_unique_identity() /datum/dna/proc/generate_unique_identity()
. = "" . = ""
var/list/L = new /list(DNA_UNI_IDENTITY_BLOCKS) for(var/block_type in GLOB.dna_identity_blocks)
var/datum/dna_block/identity/block = GLOB.dna_identity_blocks[block_type]
//ignores TRAIT_AGENDER so that a "real" gender can be stored in the DNA if later use is needed . += block.unique_block(holder)
switch(holder.gender)
if(MALE)
L[DNA_GENDER_BLOCK] = construct_block(G_MALE, GENDERS)
if(FEMALE)
L[DNA_GENDER_BLOCK] = construct_block(G_FEMALE, GENDERS)
if(NEUTER)
L[DNA_GENDER_BLOCK] = construct_block(G_NEUTER, GENDERS)
else
L[DNA_GENDER_BLOCK] = construct_block(G_PLURAL, GENDERS)
if(ishuman(holder))
var/mob/living/carbon/human/H = holder
if(length(SSaccessories.hairstyles_list) == 0 || length(SSaccessories.facial_hairstyles_list) == 0)
CRASH("SSaccessories lists are empty, this is bad!")
L[DNA_HAIRSTYLE_BLOCK] = construct_block(SSaccessories.hairstyles_list.Find(H.hairstyle), length(SSaccessories.hairstyles_list))
L[DNA_HAIR_COLOR_BLOCK] = sanitize_hexcolor(H.hair_color, include_crunch = FALSE)
L[DNA_FACIAL_HAIRSTYLE_BLOCK] = construct_block(SSaccessories.facial_hairstyles_list.Find(H.facial_hairstyle), length(SSaccessories.facial_hairstyles_list))
L[DNA_FACIAL_HAIR_COLOR_BLOCK] = sanitize_hexcolor(H.facial_hair_color, include_crunch = FALSE)
L[DNA_SKIN_TONE_BLOCK] = construct_block(GLOB.skin_tones.Find(H.skin_tone), GLOB.skin_tones.len)
L[DNA_EYE_COLOR_LEFT_BLOCK] = sanitize_hexcolor(H.eye_color_left, include_crunch = FALSE)
L[DNA_EYE_COLOR_RIGHT_BLOCK] = sanitize_hexcolor(H.eye_color_right, include_crunch = FALSE)
L[DNA_HAIRSTYLE_GRADIENT_BLOCK] = construct_block(SSaccessories.hair_gradients_list.Find(H.grad_style[GRADIENT_HAIR_KEY]), length(SSaccessories.hair_gradients_list))
L[DNA_HAIR_COLOR_GRADIENT_BLOCK] = sanitize_hexcolor(H.grad_color[GRADIENT_HAIR_KEY], include_crunch = FALSE)
L[DNA_FACIAL_HAIRSTYLE_GRADIENT_BLOCK] = construct_block(SSaccessories.facial_hair_gradients_list.Find(H.grad_style[GRADIENT_FACIAL_HAIR_KEY]), length(SSaccessories.facial_hair_gradients_list))
L[DNA_FACIAL_HAIR_COLOR_GRADIENT_BLOCK] = sanitize_hexcolor(H.grad_color[GRADIENT_FACIAL_HAIR_KEY], include_crunch = FALSE)
for(var/blocknum in 1 to DNA_UNI_IDENTITY_BLOCKS)
. += L[blocknum] || random_string(GET_UI_BLOCK_LEN(blocknum), GLOB.hex_characters)
/datum/dna/proc/generate_unique_features() /datum/dna/proc/generate_unique_features()
. = "" . = ""
var/list/L = new /list(DNA_FEATURE_BLOCKS) for(var/block_type in GLOB.dna_feature_blocks)
var/datum/dna_block/feature/block = GLOB.dna_feature_blocks[block_type]
if(features["mcolor"]) if(isnull(features[block.feature_key]))
L[DNA_MUTANT_COLOR_BLOCK] = sanitize_hexcolor(features["mcolor"], include_crunch = FALSE) . += random_string(block.block_length, GLOB.hex_characters)
if(features["ethcolor"]) continue
L[DNA_ETHEREAL_COLOR_BLOCK] = sanitize_hexcolor(features["ethcolor"], include_crunch = FALSE) . += block.unique_block(holder)
if(features["lizard_markings"])
L[DNA_LIZARD_MARKINGS_BLOCK] = construct_block(SSaccessories.lizard_markings_list.Find(features["lizard_markings"]), length(SSaccessories.lizard_markings_list))
if(features["tail_cat"])
L[DNA_TAIL_BLOCK] = construct_block(SSaccessories.tails_list_felinid.Find(features["tail_cat"]), length(SSaccessories.tails_list_felinid))
if(features["tail_lizard"])
L[DNA_LIZARD_TAIL_BLOCK] = construct_block(SSaccessories.tails_list_lizard.Find(features["tail_lizard"]), length(SSaccessories.tails_list_lizard))
if(features["snout"])
L[DNA_SNOUT_BLOCK] = construct_block(SSaccessories.snouts_list.Find(features["snout"]), length(SSaccessories.snouts_list))
if(features["horns"])
L[DNA_HORNS_BLOCK] = construct_block(SSaccessories.horns_list.Find(features["horns"]), length(SSaccessories.horns_list))
if(features["frills"])
L[DNA_FRILLS_BLOCK] = construct_block(SSaccessories.frills_list.Find(features["frills"]), length(SSaccessories.frills_list))
if(features["spines"])
L[DNA_SPINES_BLOCK] = construct_block(SSaccessories.spines_list.Find(features["spines"]), length(SSaccessories.spines_list))
if(features["ears"])
L[DNA_EARS_BLOCK] = construct_block(SSaccessories.ears_list.Find(features["ears"]), length(SSaccessories.ears_list))
if(features["moth_wings"] != "Burnt Off")
L[DNA_MOTH_WINGS_BLOCK] = construct_block(SSaccessories.moth_wings_list.Find(features["moth_wings"]), length(SSaccessories.moth_wings_list))
if(features["moth_antennae"] != "Burnt Off")
L[DNA_MOTH_ANTENNAE_BLOCK] = construct_block(SSaccessories.moth_antennae_list.Find(features["moth_antennae"]), length(SSaccessories.moth_antennae_list))
if(features["moth_markings"])
L[DNA_MOTH_MARKINGS_BLOCK] = construct_block(SSaccessories.moth_markings_list.Find(features["moth_markings"]), length(SSaccessories.moth_markings_list))
if(features["caps"])
L[DNA_MUSHROOM_CAPS_BLOCK] = construct_block(SSaccessories.caps_list.Find(features["caps"]), length(SSaccessories.caps_list))
if(features["pod_hair"])
L[DNA_POD_HAIR_BLOCK] = construct_block(SSaccessories.pod_hair_list.Find(features["pod_hair"]), length(SSaccessories.pod_hair_list))
if(features["fish_tail"])
L[DNA_FISH_TAIL_BLOCK] = construct_block(SSaccessories.tails_list_fish.Find(features["fish_tail"]), length(SSaccessories.tails_list_fish))
for(var/blocknum in 1 to DNA_FEATURE_BLOCKS)
. += L[blocknum] || random_string(GET_UI_BLOCK_LEN(blocknum), GLOB.hex_characters)
/** /**
* Picks what mutations this DNA has innate and generates DNA blocks for them * Picks what mutations this DNA has innate and generates DNA blocks for them
@@ -341,96 +256,27 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
. += random_string(DNA_UNIQUE_ENZYMES_LEN, GLOB.hex_characters) . += random_string(DNA_UNIQUE_ENZYMES_LEN, GLOB.hex_characters)
return . return .
///Setter macro used to modify unique identity blocks.
/datum/dna/proc/set_uni_identity_block(blocknum, input)
var/precesing_blocks = copytext(unique_identity, 1, GLOB.total_ui_len_by_block[blocknum])
var/succeeding_blocks = blocknum < GLOB.total_ui_len_by_block.len ? copytext(unique_identity, GLOB.total_ui_len_by_block[blocknum+1]) : ""
unique_identity = precesing_blocks + input + succeeding_blocks
///Setter macro used to modify unique features blocks. ///Setter macro used to modify unique features blocks.
/datum/dna/proc/set_uni_feature_block(blocknum, input) /datum/dna/proc/set_uni_feature_block(blocknum, input)
var/precesing_blocks = copytext(unique_features, 1, GLOB.total_uf_len_by_block[blocknum]) var/precesing_blocks = copytext(unique_features, 1, GLOB.total_uf_len_by_block[blocknum])
var/succeeding_blocks = blocknum < GLOB.total_uf_len_by_block.len ? copytext(unique_features, GLOB.total_uf_len_by_block[blocknum+1]) : "" var/succeeding_blocks = blocknum < GLOB.total_uf_len_by_block.len ? copytext(unique_features, GLOB.total_uf_len_by_block[blocknum+1]) : ""
unique_features = precesing_blocks + input + succeeding_blocks unique_features = precesing_blocks + input + succeeding_blocks
/datum/dna/proc/update_ui_block(blocknumber) /datum/dna/proc/update_ui_block(blocktype)
if(!blocknumber) if(isnull(blocktype))
CRASH("UI block index is null") CRASH("UI block type is null")
if(!ishuman(holder)) if(!ishuman(holder))
CRASH("Non-human mobs shouldn't have DNA") CRASH("Non-human mobs shouldn't have DNA")
var/mob/living/carbon/human/H = holder var/datum/dna_block/identity/block = GLOB.dna_identity_blocks[blocktype]
switch(blocknumber) unique_identity = block.modified_hash(unique_identity, block.unique_block(holder))
if(DNA_HAIR_COLOR_BLOCK)
set_uni_identity_block(blocknumber, sanitize_hexcolor(H.hair_color, include_crunch = FALSE))
if(DNA_FACIAL_HAIR_COLOR_BLOCK)
set_uni_identity_block(blocknumber, sanitize_hexcolor(H.facial_hair_color, include_crunch = FALSE))
if(DNA_SKIN_TONE_BLOCK)
set_uni_identity_block(blocknumber, construct_block(GLOB.skin_tones.Find(H.skin_tone), GLOB.skin_tones.len))
if(DNA_EYE_COLOR_LEFT_BLOCK)
set_uni_identity_block(blocknumber, sanitize_hexcolor(H.eye_color_left, include_crunch = FALSE))
if(DNA_EYE_COLOR_RIGHT_BLOCK)
set_uni_identity_block(blocknumber, sanitize_hexcolor(H.eye_color_right, include_crunch = FALSE))
if(DNA_GENDER_BLOCK)
switch(H.gender)
if(MALE)
set_uni_identity_block(blocknumber, construct_block(G_MALE, GENDERS))
if(FEMALE)
set_uni_identity_block(blocknumber, construct_block(G_FEMALE, GENDERS))
if(NEUTER)
set_uni_identity_block(blocknumber, construct_block(G_NEUTER, GENDERS))
else
set_uni_identity_block(blocknumber, construct_block(G_PLURAL, GENDERS))
if(DNA_FACIAL_HAIRSTYLE_BLOCK)
set_uni_identity_block(blocknumber, construct_block(SSaccessories.facial_hairstyles_list.Find(H.facial_hairstyle), length(SSaccessories.facial_hairstyles_list)))
if(DNA_HAIRSTYLE_BLOCK)
set_uni_identity_block(blocknumber, construct_block(SSaccessories.hairstyles_list.Find(H.hairstyle), length(SSaccessories.hairstyles_list)))
if(DNA_HAIRSTYLE_GRADIENT_BLOCK)
set_uni_identity_block(blocknumber, construct_block(SSaccessories.hair_gradients_list.Find(H.grad_style[GRADIENT_HAIR_KEY]), length(SSaccessories.hair_gradients_list)))
if(DNA_FACIAL_HAIRSTYLE_GRADIENT_BLOCK)
set_uni_identity_block(blocknumber, construct_block(SSaccessories.facial_hair_gradients_list.Find(H.grad_style[GRADIENT_FACIAL_HAIR_KEY]), length(SSaccessories.facial_hair_gradients_list)))
if(DNA_HAIR_COLOR_GRADIENT_BLOCK)
set_uni_identity_block(blocknumber, sanitize_hexcolor(H.grad_color[GRADIENT_HAIR_KEY], include_crunch = FALSE))
if(DNA_FACIAL_HAIR_COLOR_GRADIENT_BLOCK)
set_uni_identity_block(blocknumber, sanitize_hexcolor(H.grad_color[GRADIENT_FACIAL_HAIR_KEY], include_crunch = FALSE))
/datum/dna/proc/update_uf_block(blocknumber) /datum/dna/proc/update_uf_block(blocktype)
if(!blocknumber) if(!blocktype)
CRASH("UF block index is null") CRASH("UF block type is null")
if(!ishuman(holder)) if(!ishuman(holder))
CRASH("Non-human mobs shouldn't have DNA") CRASH("Non-human mobs shouldn't have DNA")
switch(blocknumber) var/datum/dna_block/feature/block = GLOB.dna_identity_blocks[blocktype]
if(DNA_MUTANT_COLOR_BLOCK) unique_features = block.modified_hash(unique_features, block.unique_block(holder))
set_uni_feature_block(blocknumber, sanitize_hexcolor(features["mcolor"], include_crunch = FALSE))
if(DNA_ETHEREAL_COLOR_BLOCK)
set_uni_feature_block(blocknumber, sanitize_hexcolor(features["ethcolor"], include_crunch = FALSE))
if(DNA_LIZARD_MARKINGS_BLOCK)
set_uni_feature_block(blocknumber, construct_block(SSaccessories.lizard_markings_list.Find(features["lizard_markings"]), length(SSaccessories.lizard_markings_list)))
if(DNA_TAIL_BLOCK)
set_uni_feature_block(blocknumber, construct_block(SSaccessories.tails_list_felinid.Find(features["tail_cat"]), length(SSaccessories.tails_list_felinid)))
if(DNA_LIZARD_TAIL_BLOCK)
set_uni_feature_block(blocknumber, construct_block(SSaccessories.tails_list_lizard.Find(features["tail_lizard"]), length(SSaccessories.tails_list_lizard)))
if(DNA_SNOUT_BLOCK)
set_uni_feature_block(blocknumber, construct_block(SSaccessories.snouts_list.Find(features["snout"]), length(SSaccessories.snouts_list)))
if(DNA_HORNS_BLOCK)
set_uni_feature_block(blocknumber, construct_block(SSaccessories.horns_list.Find(features["horns"]), length(SSaccessories.horns_list)))
if(DNA_FRILLS_BLOCK)
set_uni_feature_block(blocknumber, construct_block(SSaccessories.frills_list.Find(features["frills"]), length(SSaccessories.frills_list)))
if(DNA_SPINES_BLOCK)
set_uni_feature_block(blocknumber, construct_block(SSaccessories.spines_list.Find(features["spines"]), length(SSaccessories.spines_list)))
if(DNA_EARS_BLOCK)
set_uni_feature_block(blocknumber, construct_block(SSaccessories.ears_list.Find(features["ears"]), length(SSaccessories.ears_list)))
if(DNA_MOTH_WINGS_BLOCK)
set_uni_feature_block(blocknumber, construct_block(SSaccessories.moth_wings_list.Find(features["moth_wings"]), length(SSaccessories.moth_wings_list)))
if(DNA_MOTH_ANTENNAE_BLOCK)
set_uni_feature_block(blocknumber, construct_block(SSaccessories.moth_antennae_list.Find(features["moth_antennae"]), length(SSaccessories.moth_antennae_list)))
if(DNA_MOTH_MARKINGS_BLOCK)
set_uni_feature_block(blocknumber, construct_block(SSaccessories.moth_markings_list.Find(features["moth_markings"]), length(SSaccessories.moth_markings_list)))
if(DNA_MUSHROOM_CAPS_BLOCK)
set_uni_feature_block(blocknumber, construct_block(SSaccessories.caps_list.Find(features["caps"]), length(SSaccessories.caps_list)))
if(DNA_POD_HAIR_BLOCK)
set_uni_feature_block(blocknumber, construct_block(SSaccessories.pod_hair_list.Find(features["pod_hair"]), length(SSaccessories.pod_hair_list)))
if(DNA_FISH_TAIL_BLOCK)
set_uni_feature_block(blocknumber, construct_block(SSaccessories.tails_list_fish.Find(features["fish_tail"]), length(SSaccessories.tails_list_fish)))
/** /**
* Checks if two DNAs are practically the same by comparing their most defining features * Checks if two DNAs are practically the same by comparing their most defining features
@@ -480,6 +326,8 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
/// Updates the UI, UE, and UF of the DNA according to the features, appearance, name, etc. of the DNA / holder. /// Updates the UI, UE, and UF of the DNA according to the features, appearance, name, etc. of the DNA / holder.
/datum/dna/proc/update_dna_identity() /datum/dna/proc/update_dna_identity()
if(!holder.has_dna())
return
unique_identity = generate_unique_identity() unique_identity = generate_unique_identity()
unique_enzymes = generate_unique_enzymes() unique_enzymes = generate_unique_enzymes()
unique_features = generate_unique_features() unique_features = generate_unique_features()
@@ -502,7 +350,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
for(var/feature in new_features) for(var/feature in new_features)
features[feature] = new_features[feature] features[feature] = new_features[feature]
features["mcolor"] = "#[random_color()]" features[FEATURE_MUTANT_COLOR] = "#[random_color()]"
update_dna_identity() update_dna_identity()
@@ -636,88 +484,25 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
dna.species = new rando_race() dna.species = new rando_race()
//proc used to update the mob's appearance after its dna UI has been changed //proc used to update the mob's appearance after its dna UI has been changed
/mob/living/carbon/proc/updateappearance(icon_update=1, mutcolor_update=0, mutations_overlay_update=0) //2025: Im unsure if dna is meant to be living, carbon, or human level.. there's contradicting stuff and bugfixes going back 8 years
//If youre reading this, and you know for sure, update this, or maybe remove the carbon part entirely
/mob/living/carbon/proc/updateappearance(icon_update = TRUE, mutcolor_update = FALSE, mutations_overlay_update = FALSE)
if(!has_dna()) if(!has_dna())
return return
//Always plural gender if agender
if(HAS_TRAIT(src, TRAIT_AGENDER))
gender = PLURAL
return
switch(deconstruct_block(get_uni_identity_block(dna.unique_identity, DNA_GENDER_BLOCK), GENDERS))
if(G_MALE)
gender = MALE
if(G_FEMALE)
gender = FEMALE
if(G_NEUTER)
gender = NEUTER
else
gender = PLURAL
/mob/living/carbon/human/updateappearance(icon_update = TRUE, mutcolor_update = FALSE, mutations_overlay_update = FALSE) /mob/living/carbon/human/updateappearance(icon_update = TRUE, mutcolor_update = FALSE, mutations_overlay_update = FALSE)
..() . = ..()
var/structure = dna.unique_identity for(var/block_type in GLOB.dna_identity_blocks)
skin_tone = GLOB.skin_tones[deconstruct_block(get_uni_identity_block(structure, DNA_SKIN_TONE_BLOCK), GLOB.skin_tones.len)] var/datum/dna_block/identity/block_to_apply = GLOB.dna_identity_blocks[block_type]
set_eye_color(sanitize_hexcolor(get_uni_identity_block(structure, DNA_EYE_COLOR_LEFT_BLOCK)), sanitize_hexcolor(get_uni_identity_block(structure, DNA_EYE_COLOR_RIGHT_BLOCK))) block_to_apply.apply_to_mob(src, dna.unique_identity)
set_haircolor(sanitize_hexcolor(get_uni_identity_block(structure, DNA_HAIR_COLOR_BLOCK)), update = FALSE)
set_facial_haircolor(sanitize_hexcolor(get_uni_identity_block(structure, DNA_FACIAL_HAIR_COLOR_BLOCK)), update = FALSE) for(var/block_type in GLOB.dna_feature_blocks)
set_hair_gradient_color(sanitize_hexcolor(get_uni_identity_block(structure, DNA_HAIR_COLOR_GRADIENT_BLOCK)), update = FALSE) var/datum/dna_block/feature/block_to_apply = GLOB.dna_feature_blocks[block_type]
set_facial_hair_gradient_color(sanitize_hexcolor(get_uni_identity_block(structure, DNA_FACIAL_HAIR_COLOR_GRADIENT_BLOCK)), update = FALSE) if(dna.features[block_to_apply.feature_key])
if(HAS_TRAIT(src, TRAIT_SHAVED)) block_to_apply.apply_to_mob(src, dna.unique_features)
set_facial_hairstyle("Shaved", update = FALSE)
else
var/style = SSaccessories.facial_hairstyles_list[deconstruct_block(get_uni_identity_block(structure, DNA_FACIAL_HAIRSTYLE_BLOCK), length(SSaccessories.facial_hairstyles_list))]
var/gradient_style = SSaccessories.facial_hair_gradients_list[deconstruct_block(get_uni_identity_block(structure, DNA_FACIAL_HAIRSTYLE_GRADIENT_BLOCK), length(SSaccessories.facial_hair_gradients_list))]
set_facial_hairstyle(style, update = FALSE)
set_facial_hair_gradient_style(gradient_style, update = FALSE)
if(HAS_TRAIT(src, TRAIT_BALD))
set_hairstyle("Bald", update = FALSE)
else
var/style = SSaccessories.hairstyles_list[deconstruct_block(get_uni_identity_block(structure, DNA_HAIRSTYLE_BLOCK), length(SSaccessories.hairstyles_list))]
var/gradient_style = SSaccessories.hair_gradients_list[deconstruct_block(get_uni_identity_block(structure, DNA_HAIRSTYLE_GRADIENT_BLOCK), length(SSaccessories.hair_gradients_list))]
set_hairstyle(style, update = FALSE)
set_hair_gradient_style(gradient_style, update = FALSE)
var/features = dna.unique_features
if(dna.features["mcolor"])
dna.features["mcolor"] = sanitize_hexcolor(get_uni_feature_block(features, DNA_MUTANT_COLOR_BLOCK))
if(dna.features["ethcolor"])
dna.features["ethcolor"] = sanitize_hexcolor(get_uni_feature_block(features, DNA_ETHEREAL_COLOR_BLOCK))
if(dna.features["lizard_markings"])
dna.features["lizard_markings"] = SSaccessories.lizard_markings_list[deconstruct_block(get_uni_feature_block(features, DNA_LIZARD_MARKINGS_BLOCK), length(SSaccessories.lizard_markings_list))]
if(dna.features["snout"])
dna.features["snout"] = SSaccessories.snouts_list[deconstruct_block(get_uni_feature_block(features, DNA_SNOUT_BLOCK), length(SSaccessories.snouts_list))]
if(dna.features["horns"])
dna.features["horns"] = SSaccessories.horns_list[deconstruct_block(get_uni_feature_block(features, DNA_HORNS_BLOCK), length(SSaccessories.horns_list))]
if(dna.features["frills"])
dna.features["frills"] = SSaccessories.frills_list[deconstruct_block(get_uni_feature_block(features, DNA_FRILLS_BLOCK), length(SSaccessories.frills_list))]
if(dna.features["spines"])
dna.features["spines"] = SSaccessories.spines_list[deconstruct_block(get_uni_feature_block(features, DNA_SPINES_BLOCK), length(SSaccessories.spines_list))]
if(dna.features["tail_cat"])
dna.features["tail_cat"] = SSaccessories.tails_list_felinid[deconstruct_block(get_uni_feature_block(features, DNA_TAIL_BLOCK), length(SSaccessories.tails_list_felinid))]
if(dna.features["tail_lizard"])
dna.features["tail_lizard"] = SSaccessories.tails_list_lizard[deconstruct_block(get_uni_feature_block(features, DNA_LIZARD_TAIL_BLOCK), length(SSaccessories.tails_list_lizard))]
if(dna.features["ears"])
dna.features["ears"] = SSaccessories.ears_list[deconstruct_block(get_uni_feature_block(features, DNA_EARS_BLOCK), length(SSaccessories.ears_list))]
if(dna.features["moth_wings"])
var/genetic_value = SSaccessories.moth_wings_list[deconstruct_block(get_uni_feature_block(features, DNA_MOTH_WINGS_BLOCK), length(SSaccessories.moth_wings_list))]
dna.features["original_moth_wings"] = genetic_value
dna.features["moth_wings"] = genetic_value
if(dna.features["moth_antennae"])
var/genetic_value = SSaccessories.moth_antennae_list[deconstruct_block(get_uni_feature_block(features, DNA_MOTH_ANTENNAE_BLOCK), length(SSaccessories.moth_antennae_list))]
dna.features["original_moth_antennae"] = genetic_value
dna.features["moth_antennae"] = genetic_value
if(dna.features["moth_markings"])
dna.features["moth_markings"] = SSaccessories.moth_markings_list[deconstruct_block(get_uni_feature_block(features, DNA_MOTH_MARKINGS_BLOCK), length(SSaccessories.moth_markings_list))]
if(dna.features["caps"])
dna.features["caps"] = SSaccessories.caps_list[deconstruct_block(get_uni_feature_block(features, DNA_MUSHROOM_CAPS_BLOCK), length(SSaccessories.caps_list))]
if(dna.features["pod_hair"])
dna.features["pod_hair"] = SSaccessories.pod_hair_list[deconstruct_block(get_uni_feature_block(features, DNA_POD_HAIR_BLOCK), length(SSaccessories.pod_hair_list))]
if(dna.features["fish_tail"])
dna.features["fish_tail"] = SSaccessories.tails_list_fish[deconstruct_block(get_uni_feature_block(features, DNA_FISH_TAIL_BLOCK), length(SSaccessories.tails_list_fish))]
for(var/obj/item/organ/organ in organs) for(var/obj/item/organ/organ in organs)
organ.mutate_feature(features, src) organ.mutate_feature(dna.unique_features, src)
if(icon_update) if(icon_update)
update_body(is_creating = mutcolor_update) update_body(is_creating = mutcolor_update)
@@ -839,15 +624,17 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
/mob/living/carbon/proc/random_mutate_unique_identity() /mob/living/carbon/proc/random_mutate_unique_identity()
if(!has_dna()) if(!has_dna())
CRASH("[src] does not have DNA") CRASH("[src] does not have DNA")
var/num = rand(1, DNA_UNI_IDENTITY_BLOCKS) var/mutblock_path = pick(GLOB.dna_identity_blocks)
dna.set_uni_feature_block(num, random_string(GET_UI_BLOCK_LEN(num), GLOB.hex_characters)) var/datum/dna_block/identity/mutblock = GLOB.dna_identity_blocks[mutblock_path]
updateappearance(mutations_overlay_update=1) dna.unique_identity = mutblock.modified_hash(dna.unique_identity, random_string(mutblock.block_length, GLOB.hex_characters))
updateappearance(mutations_overlay_update = TRUE)
/mob/living/carbon/proc/random_mutate_unique_features() /mob/living/carbon/proc/random_mutate_unique_features()
if(!has_dna()) if(!has_dna())
CRASH("[src] does not have DNA") CRASH("[src] does not have DNA")
var/num = rand(1, DNA_FEATURE_BLOCKS) var/mutblock_path = pick(GLOB.dna_feature_blocks)
dna.set_uni_feature_block(num, random_string(GET_UF_BLOCK_LEN(num), GLOB.hex_characters)) var/datum/dna_block/feature/mutblock = GLOB.dna_feature_blocks[mutblock_path]
dna.unique_features = mutblock.modified_hash(dna.unique_features, random_string(mutblock.block_length, GLOB.hex_characters))
updateappearance(mutcolor_update = TRUE, mutations_overlay_update = TRUE) updateappearance(mutcolor_update = TRUE, mutations_overlay_update = TRUE)
/mob/living/carbon/proc/clean_dna() /mob/living/carbon/proc/clean_dna()
@@ -859,7 +646,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
clean_dna() clean_dna()
random_mutate(candidates, difficulty) random_mutate(candidates, difficulty)
/proc/scramble_dna(mob/living/carbon/M, ui=FALSE, se=FALSE, uf=FALSE, probability) /proc/scramble_dna(mob/living/carbon/M, ui = FALSE, se = FALSE, uf = FALSE, probability = 100)
if(!M.has_dna()) if(!M.has_dna())
CRASH("[M] does not have DNA") CRASH("[M] does not have DNA")
if(HAS_TRAIT(M, TRAIT_NO_DNA_SCRAMBLE)) if(HAS_TRAIT(M, TRAIT_NO_DNA_SCRAMBLE))
@@ -870,13 +657,15 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
M.dna.generate_dna_blocks() M.dna.generate_dna_blocks()
M.domutcheck() M.domutcheck()
if(ui) if(ui)
for(var/blocknum in 1 to DNA_UNI_IDENTITY_BLOCKS) for(var/block_id in GLOB.dna_identity_blocks)
var/datum/dna_block/identity/block = GLOB.dna_identity_blocks[block_id]
if(prob(probability)) if(prob(probability))
M.dna.set_uni_feature_block(blocknum, random_string(GET_UI_BLOCK_LEN(blocknum), GLOB.hex_characters)) M.dna.unique_identity = block.modified_hash(M.dna.unique_identity, random_string(block.block_length, GLOB.hex_characters))
if(uf) if(uf)
for(var/blocknum in 1 to DNA_FEATURE_BLOCKS) for(var/block_id in GLOB.dna_feature_blocks)
var/datum/dna_block/feature/block = GLOB.dna_feature_blocks[block_id]
if(prob(probability)) if(prob(probability))
M.dna.set_uni_feature_block(blocknum, random_string(GET_UF_BLOCK_LEN(blocknum), GLOB.hex_characters)) M.dna.unique_identity = block.modified_hash(M.dna.unique_identity, random_string(block.block_length, GLOB.hex_characters))
if(ui || uf) if(ui || uf)
M.updateappearance(mutcolor_update=uf, mutations_overlay_update=1) M.updateappearance(mutcolor_update=uf, mutations_overlay_update=1)
@@ -897,12 +686,6 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
value = values value = values
return value return value
/proc/get_uni_identity_block(identity, blocknum)
return copytext(identity, GLOB.total_ui_len_by_block[blocknum], LAZYACCESS(GLOB.total_ui_len_by_block, blocknum+1))
/proc/get_uni_feature_block(features, blocknum)
return copytext(features, GLOB.total_uf_len_by_block[blocknum], LAZYACCESS(GLOB.total_uf_len_by_block, blocknum+1))
/////////////////////////// DNA HELPER-PROCS /////////////////////////// DNA HELPER-PROCS
/mob/living/carbon/human/proc/something_horrible(ignore_stability) /mob/living/carbon/human/proc/something_horrible(ignore_stability)

View File

@@ -0,0 +1,69 @@
// 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
/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
/// 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]

View File

@@ -20,7 +20,7 @@
var/was_not_hetero = !human_holder.eye_color_heterochromatic var/was_not_hetero = !human_holder.eye_color_heterochromatic
human_holder.eye_color_heterochromatic = TRUE human_holder.eye_color_heterochromatic = TRUE
human_holder.eye_color_right = color human_holder.eye_color_right = color
human_holder.dna.update_ui_block(DNA_EYE_COLOR_RIGHT_BLOCK) human_holder.dna.update_ui_block(/datum/dna_block/identity/eye_colors)
var/obj/item/organ/eyes/eyes_of_the_holder = quirk_holder.get_organ_by_type(/obj/item/organ/eyes) var/obj/item/organ/eyes/eyes_of_the_holder = quirk_holder.get_organ_by_type(/obj/item/organ/eyes)
if(!eyes_of_the_holder) if(!eyes_of_the_holder)

View File

@@ -220,7 +220,7 @@
greyscale_colors = FISH_ORGAN_COLOR greyscale_colors = FISH_ORGAN_COLOR
bodypart_overlay = /datum/bodypart_overlay/mutant/tail/fish bodypart_overlay = /datum/bodypart_overlay/mutant/tail/fish
dna_block = DNA_FISH_TAIL_BLOCK dna_block = /datum/dna_block/feature/tail_fish
wag_flags = NONE wag_flags = NONE
organ_traits = list(TRAIT_FLOPPING, TRAIT_SWIMMER) organ_traits = list(TRAIT_FLOPPING, TRAIT_SWIMMER)
restyle_flags = EXTERNAL_RESTYLE_FLESH restyle_flags = EXTERNAL_RESTYLE_FLESH
@@ -282,15 +282,15 @@
source.add_traits(list(TRAIT_OFF_BALANCE_TACKLER, TRAIT_NO_STAGGER, TRAIT_NO_THROW_HITPUSH), type) source.add_traits(list(TRAIT_OFF_BALANCE_TACKLER, TRAIT_NO_STAGGER, TRAIT_NO_THROW_HITPUSH), type)
/datum/bodypart_overlay/mutant/tail/fish /datum/bodypart_overlay/mutant/tail/fish
feature_key = "fish_tail" feature_key = FEATURE_TAIL_FISH
color_source = ORGAN_COLOR_OVERRIDE color_source = ORGAN_COLOR_OVERRIDE
/datum/bodypart_overlay/mutant/tail/fish/on_mob_insert(obj/item/organ/parent, mob/living/carbon/receiver) /datum/bodypart_overlay/mutant/tail/fish/on_mob_insert(obj/item/organ/parent, mob/living/carbon/receiver)
//Initialize the related dna feature block if we don't have any so it doesn't error out. //Initialize the related dna feature block if we don't have any so it doesn't error out.
//This isn't tied to any species, but I kinda want it to be mutable instead of having a fixed sprite accessory. //This isn't tied to any species, but I kinda want it to be mutable instead of having a fixed sprite accessory.
if(imprint_on_next_insertion && !receiver.dna.features["fish_tail"]) if(imprint_on_next_insertion && !receiver.dna.features[FEATURE_TAIL_FISH])
receiver.dna.features["fish_tail"] = pick(SSaccessories.tails_list_fish) receiver.dna.features[FEATURE_TAIL_FISH] = pick(SSaccessories.tails_list_fish)
receiver.dna.update_uf_block(DNA_FISH_TAIL_BLOCK) receiver.dna.update_uf_block(FEATURE_TAIL_FISH)
return ..() return ..()

View File

@@ -6,6 +6,6 @@
visual = TRUE visual = TRUE
damage_multiplier = 2 damage_multiplier = 2
dna_block = DNA_EARS_BLOCK dna_block = /datum/dna_block/feature/ears
bodypart_overlay = /datum/bodypart_overlay/mutant/cat_ears bodypart_overlay = /datum/bodypart_overlay/mutant/cat_ears
sprite_accessory_override = /datum/sprite_accessory/ears/fox sprite_accessory_override = /datum/sprite_accessory/ears/fox

View File

@@ -199,15 +199,15 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28)
var/new_s_tone = tgui_input_list(race_changer, "Choose your skin tone", "Race change", GLOB.skin_tones) var/new_s_tone = tgui_input_list(race_changer, "Choose your skin tone", "Race change", GLOB.skin_tones)
if(new_s_tone) if(new_s_tone)
race_changer.skin_tone = new_s_tone race_changer.skin_tone = new_s_tone
race_changer.dna.update_ui_block(DNA_SKIN_TONE_BLOCK) race_changer.dna.update_ui_block(/datum/dna_block/identity/skin_tone)
else if(HAS_TRAIT(race_changer, TRAIT_MUTANT_COLORS) && !HAS_TRAIT(race_changer, TRAIT_FIXED_MUTANT_COLORS)) else if(HAS_TRAIT(race_changer, TRAIT_MUTANT_COLORS) && !HAS_TRAIT(race_changer, TRAIT_FIXED_MUTANT_COLORS))
var/new_mutantcolor = input(race_changer, "Choose your skin color:", "Race change", race_changer.dna.features["mcolor"]) as color|null var/new_mutantcolor = input(race_changer, "Choose your skin color:", "Race change", race_changer.dna.features[FEATURE_MUTANT_COLOR]) as color|null
if(new_mutantcolor) if(new_mutantcolor)
var/list/mutant_hsv = rgb2hsv(new_mutantcolor) var/list/mutant_hsv = rgb2hsv(new_mutantcolor)
if(mutant_hsv[3] >= 50) // mutantcolors must be bright if(mutant_hsv[3] >= 50) // mutantcolors must be bright
race_changer.dna.features["mcolor"] = sanitize_hexcolor(new_mutantcolor) race_changer.dna.features[FEATURE_MUTANT_COLOR] = sanitize_hexcolor(new_mutantcolor)
race_changer.dna.update_uf_block(DNA_MUTANT_COLOR_BLOCK) race_changer.dna.update_uf_block(FEATURE_MUTANT_COLOR)
else else
to_chat(race_changer, span_notice("Invalid color. Your color is not bright enough.")) to_chat(race_changer, span_notice("Invalid color. Your color is not bright enough."))
return TRUE return TRUE
@@ -241,7 +241,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28)
if(chosen_physique && chosen_physique != "Wizards Don't Need Gender") if(chosen_physique && chosen_physique != "Wizards Don't Need Gender")
sexy.physique = (chosen_physique == "Warlock Physique") ? MALE : FEMALE sexy.physique = (chosen_physique == "Warlock Physique") ? MALE : FEMALE
sexy.dna.update_ui_block(DNA_GENDER_BLOCK) sexy.dna.update_ui_block(/datum/dna_block/identity/gender)
sexy.update_body(is_creating = TRUE) // or else physique won't change properly sexy.update_body(is_creating = TRUE) // or else physique won't change properly
sexy.update_mutations_overlay() //(hulk male/female) sexy.update_mutations_overlay() //(hulk male/female)
sexy.update_clothing(ITEM_SLOT_ICLOTHING) // update gender shaped clothing sexy.update_clothing(ITEM_SLOT_ICLOTHING) // update gender shaped clothing
@@ -251,8 +251,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28)
if(isnull(new_eye_color)) if(isnull(new_eye_color))
return TRUE return TRUE
user.set_eye_color(sanitize_hexcolor(new_eye_color)) user.set_eye_color(sanitize_hexcolor(new_eye_color))
user.dna.update_ui_block(DNA_EYE_COLOR_LEFT_BLOCK) user.dna.update_ui_block(/datum/dna_block/identity/eye_colors)
user.dna.update_ui_block(DNA_EYE_COLOR_RIGHT_BLOCK)
user.update_body() user.update_body()
to_chat(user, span_notice("You gaze at your new eyes with your new eyes. Perfect!")) to_chat(user, span_notice("You gaze at your new eyes with your new eyes. Perfect!"))
@@ -383,12 +382,12 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28)
if(new_hair_color) if(new_hair_color)
user.set_haircolor(sanitize_hexcolor(new_hair_color)) user.set_haircolor(sanitize_hexcolor(new_hair_color))
user.dna.update_ui_block(DNA_HAIR_COLOR_BLOCK) user.dna.update_ui_block(/datum/dna_block/identity/hair_color)
if(user.physique == MALE) if(user.physique == MALE)
var/new_face_color = input(user, "Choose your facial hair color", "Hair Color", user.facial_hair_color) as color|null var/new_face_color = input(user, "Choose your facial hair color", "Hair Color", user.facial_hair_color) as color|null
if(new_face_color) if(new_face_color)
user.set_facial_haircolor(sanitize_hexcolor(new_face_color)) user.set_facial_haircolor(sanitize_hexcolor(new_face_color))
user.dna.update_ui_block(DNA_FACIAL_HAIR_COLOR_BLOCK) user.dna.update_ui_block(/datum/dna_block/identity/facial_color)
/obj/structure/mirror/magic/attack_hand(mob/living/carbon/human/user) /obj/structure/mirror/magic/attack_hand(mob/living/carbon/human/user)
. = ..() . = ..()

View File

@@ -578,7 +578,7 @@ ADMIN_VERB(secrets, R_NONE, "Secrets", "Abuse harder than you ever have before w
SEND_SOUND(H, sound(SSstation.announcer.event_sounds[ANNOUNCER_ANIMES])) SEND_SOUND(H, sound(SSstation.announcer.event_sounds[ANNOUNCER_ANIMES]))
if(H.dna.species.id == SPECIES_HUMAN) if(H.dna.species.id == SPECIES_HUMAN)
if(H.dna.features["tail_human"] == "None" || H.dna.features["ears"] == "None") if(H.dna.features[FEATURE_TAIL] == "None" || H.dna.features[FEATURE_EARS] == "None")
var/obj/item/organ/ears/cat/ears = new var/obj/item/organ/ears/cat/ears = new
var/obj/item/organ/tail/cat/tail = new var/obj/item/organ/tail/cat/tail = new
ears.Insert(H, movement_flags = DELETE_IF_REPLACED) ears.Insert(H, movement_flags = DELETE_IF_REPLACED)

View File

@@ -133,12 +133,12 @@
var/mob/living/carbon/human/dummy/consistent/brother1 = new var/mob/living/carbon/human/dummy/consistent/brother1 = new
var/mob/living/carbon/human/dummy/consistent/brother2 = new var/mob/living/carbon/human/dummy/consistent/brother2 = new
brother1.dna.features["ethcolor"] = GLOB.color_list_ethereal["Faint Red"] brother1.dna.features[FEATURE_ETHEREAL_COLOR] = GLOB.color_list_ethereal["Faint Red"]
brother1.set_species(/datum/species/ethereal) brother1.set_species(/datum/species/ethereal)
brother2.dna.features["moth_antennae"] = "Plain" brother2.dna.features[FEATURE_MOTH_ANTENNAE] = "Plain"
brother2.dna.features["moth_markings"] = "None" brother2.dna.features[FEATURE_MOTH_MARKINGS] = "None"
brother2.dna.features["moth_wings"] = "Plain" brother2.dna.features[FEATURE_MOTH_WINGS] = "Plain"
brother2.set_species(/datum/species/moth) brother2.set_species(/datum/species/moth)
var/icon/brother1_icon = render_preview_outfit(/datum/outfit/job/quartermaster, brother1) var/icon/brother1_icon = render_preview_outfit(/datum/outfit/job/quartermaster, brother1)

View File

@@ -33,4 +33,4 @@
return icon return icon
/datum/preference/choiced/ethereal_color/apply_to_human(mob/living/carbon/human/target, value) /datum/preference/choiced/ethereal_color/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["ethcolor"] = GLOB.color_list_ethereal[value] target.dna.features[FEATURE_ETHEREAL_COLOR] = GLOB.color_list_ethereal[value]

View File

@@ -9,7 +9,7 @@
return assoc_to_keys_features(SSaccessories.tails_list_felinid) return assoc_to_keys_features(SSaccessories.tails_list_felinid)
/datum/preference/choiced/tail_felinid/apply_to_human(mob/living/carbon/human/target, value) /datum/preference/choiced/tail_felinid/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["tail_cat"] = value target.dna.features[FEATURE_TAIL] = value
/datum/preference/choiced/tail_felinid/create_default_value() /datum/preference/choiced/tail_felinid/create_default_value()
var/datum/sprite_accessory/tails/felinid/cat/tail = /datum/sprite_accessory/tails/felinid/cat var/datum/sprite_accessory/tails/felinid/cat/tail = /datum/sprite_accessory/tails/felinid/cat
@@ -26,7 +26,7 @@
return assoc_to_keys_features(SSaccessories.ears_list) return assoc_to_keys_features(SSaccessories.ears_list)
/datum/preference/choiced/felinid_ears/apply_to_human(mob/living/carbon/human/target, value) /datum/preference/choiced/felinid_ears/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["ears"] = value target.dna.features[FEATURE_EARS] = value
/datum/preference/choiced/felinid_ears/create_default_value() /datum/preference/choiced/felinid_ears/create_default_value()
return /datum/sprite_accessory/ears/cat::name return /datum/sprite_accessory/ears/cat::name

View File

@@ -55,7 +55,7 @@
return final_icon return final_icon
/datum/preference/choiced/lizard_body_markings/apply_to_human(mob/living/carbon/human/target, value) /datum/preference/choiced/lizard_body_markings/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["lizard_markings"] = value target.dna.features[FEATURE_LIZARD_MARKINGS] = value
/datum/preference/choiced/lizard_frills /datum/preference/choiced/lizard_frills
savefile_key = "feature_lizard_frills" savefile_key = "feature_lizard_frills"
@@ -72,7 +72,7 @@
return generate_lizard_side_shot(SSaccessories.frills_list[value], "frills") return generate_lizard_side_shot(SSaccessories.frills_list[value], "frills")
/datum/preference/choiced/lizard_frills/apply_to_human(mob/living/carbon/human/target, value) /datum/preference/choiced/lizard_frills/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["frills"] = value target.dna.features[FEATURE_FRILLS] = value
/datum/preference/choiced/lizard_horns /datum/preference/choiced/lizard_horns
savefile_key = "feature_lizard_horns" savefile_key = "feature_lizard_horns"
@@ -89,7 +89,7 @@
return generate_lizard_side_shot(SSaccessories.horns_list[value], "horns") return generate_lizard_side_shot(SSaccessories.horns_list[value], "horns")
/datum/preference/choiced/lizard_horns/apply_to_human(mob/living/carbon/human/target, value) /datum/preference/choiced/lizard_horns/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["horns"] = value target.dna.features[FEATURE_HORNS] = value
/datum/preference/choiced/lizard_legs /datum/preference/choiced/lizard_legs
savefile_key = "feature_lizard_legs" savefile_key = "feature_lizard_legs"
@@ -100,7 +100,7 @@
return list(NORMAL_LEGS, DIGITIGRADE_LEGS) return list(NORMAL_LEGS, DIGITIGRADE_LEGS)
/datum/preference/choiced/lizard_legs/apply_to_human(mob/living/carbon/human/target, value) /datum/preference/choiced/lizard_legs/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["legs"] = value target.dna.features[FEATURE_LEGS] = value
// Hack to update the dummy in the preference menu // Hack to update the dummy in the preference menu
// (Because digi legs are ONLY handled on species change) // (Because digi legs are ONLY handled on species change)
if(!isdummy(target) || target.dna.species.digitigrade_customization == DIGITIGRADE_NEVER) if(!isdummy(target) || target.dna.species.digitigrade_customization == DIGITIGRADE_NEVER)
@@ -145,7 +145,7 @@
return generate_lizard_side_shot(SSaccessories.snouts_list[value], "snout", include_snout = FALSE) return generate_lizard_side_shot(SSaccessories.snouts_list[value], "snout", include_snout = FALSE)
/datum/preference/choiced/lizard_snout/apply_to_human(mob/living/carbon/human/target, value) /datum/preference/choiced/lizard_snout/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["snout"] = value target.dna.features[FEATURE_SNOUT] = value
/datum/preference/choiced/lizard_spines /datum/preference/choiced/lizard_spines
savefile_key = "feature_lizard_spines" savefile_key = "feature_lizard_spines"
@@ -157,7 +157,7 @@
return assoc_to_keys_features(SSaccessories.spines_list) return assoc_to_keys_features(SSaccessories.spines_list)
/datum/preference/choiced/lizard_spines/apply_to_human(mob/living/carbon/human/target, value) /datum/preference/choiced/lizard_spines/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["spines"] = value target.dna.features[FEATURE_SPINES] = value
/datum/preference/choiced/lizard_tail /datum/preference/choiced/lizard_tail
savefile_key = "feature_lizard_tail" savefile_key = "feature_lizard_tail"
@@ -169,7 +169,7 @@
return assoc_to_keys_features(SSaccessories.tails_list_lizard) return assoc_to_keys_features(SSaccessories.tails_list_lizard)
/datum/preference/choiced/lizard_tail/apply_to_human(mob/living/carbon/human/target, value) /datum/preference/choiced/lizard_tail/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["tail_lizard"] = value target.dna.features[FEATURE_TAIL_LIZARD] = value
/datum/preference/choiced/lizard_tail/create_default_value() /datum/preference/choiced/lizard_tail/create_default_value()
return /datum/sprite_accessory/tails/lizard/smooth::name return /datum/sprite_accessory/tails/lizard/smooth::name

View File

@@ -9,7 +9,7 @@
return assoc_to_keys_features(SSaccessories.tails_list_monkey) return assoc_to_keys_features(SSaccessories.tails_list_monkey)
/datum/preference/choiced/monkey_tail/apply_to_human(mob/living/carbon/human/target, value) /datum/preference/choiced/monkey_tail/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["tail_monkey"] = value target.dna.features[FEATURE_TAIL_MONKEY] = value
/datum/preference/choiced/monkey_tail/create_default_value() /datum/preference/choiced/monkey_tail/create_default_value()
return /datum/sprite_accessory/tails/monkey/default::name return /datum/sprite_accessory/tails/monkey/default::name

View File

@@ -27,7 +27,7 @@
return icon_with_antennae return icon_with_antennae
/datum/preference/choiced/moth_antennae/apply_to_human(mob/living/carbon/human/target, value) /datum/preference/choiced/moth_antennae/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["moth_antennae"] = value target.dna.features[FEATURE_MOTH_ANTENNAE] = value
/datum/preference/choiced/moth_markings /datum/preference/choiced/moth_markings
savefile_key = "feature_moth_markings" savefile_key = "feature_moth_markings"
@@ -77,7 +77,7 @@
return icon_with_markings return icon_with_markings
/datum/preference/choiced/moth_markings/apply_to_human(mob/living/carbon/human/target, value) /datum/preference/choiced/moth_markings/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["moth_markings"] = value target.dna.features[FEATURE_MOTH_MARKINGS] = value
/datum/preference/choiced/moth_wings /datum/preference/choiced/moth_wings
savefile_key = "feature_moth_wings" savefile_key = "feature_moth_wings"
@@ -95,4 +95,4 @@
return uni_icon(moth_wings.icon, "m_moth_wings_[moth_wings.icon_state]_BEHIND") return uni_icon(moth_wings.icon, "m_moth_wings_[moth_wings.icon_state]_BEHIND")
/datum/preference/choiced/moth_wings/apply_to_human(mob/living/carbon/human/target, value) /datum/preference/choiced/moth_wings/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["moth_wings"] = value target.dna.features[FEATURE_MOTH_WINGS] = value

View File

@@ -8,4 +8,4 @@
return assoc_to_keys_features(SSaccessories.caps_list) return assoc_to_keys_features(SSaccessories.caps_list)
/datum/preference/choiced/mushroom_cap/apply_to_human(mob/living/carbon/human/target, value) /datum/preference/choiced/mushroom_cap/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["caps"] = value target.dna.features[FEATURE_MUSH_CAP] = value

View File

@@ -16,7 +16,7 @@
return sanitize_hexcolor("[pick("7F", "FF")][pick("7F", "FF")][pick("7F", "FF")]") return sanitize_hexcolor("[pick("7F", "FF")][pick("7F", "FF")][pick("7F", "FF")]")
/datum/preference/color/mutant_color/apply_to_human(mob/living/carbon/human/target, value) /datum/preference/color/mutant_color/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["mcolor"] = value target.dna.features[FEATURE_MUTANT_COLOR] = value
/datum/preference/color/mutant_color/is_valid(value) /datum/preference/color/mutant_color/is_valid(value)
if (!..(value)) if (!..(value))

View File

@@ -28,4 +28,4 @@
return pick(assoc_to_keys_features(SSaccessories.pod_hair_list)) return pick(assoc_to_keys_features(SSaccessories.pod_hair_list))
/datum/preference/choiced/pod_hair/apply_to_human(mob/living/carbon/human/target, value) /datum/preference/choiced/pod_hair/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["pod_hair"] = value target.dna.features[FEATURE_POD_HAIR] = value

View File

@@ -199,10 +199,10 @@
podman.gender = blood_gender podman.gender = blood_gender
podman.faction |= factions podman.faction |= factions
if(!features["mcolor"]) if(!features[FEATURE_MUTANT_COLOR])
features["mcolor"] = "#59CE00" features[FEATURE_MUTANT_COLOR] = "#59CE00"
if(!features["pod_hair"]) if(!features[FEATURE_POD_HAIR])
features["pod_hair"] = pick(SSaccessories.pod_hair_list) features[FEATURE_POD_HAIR] = pick(SSaccessories.pod_hair_list)
for(var/V in quirks) for(var/V in quirks)
new V(podman) new V(podman)

View File

@@ -171,17 +171,17 @@
if(1) if(1)
to_chat(user, span_danger("Your appearance morphs to that of a very small humanoid ash dragon! You get to look like a freak without the cool abilities.")) to_chat(user, span_danger("Your appearance morphs to that of a very small humanoid ash dragon! You get to look like a freak without the cool abilities."))
consumer.dna.features = list( consumer.dna.features = list(
"mcolor" = "#A02720", FEATURE_MUTANT_COLOR = "#A02720",
"tail_lizard" = "Dark Tiger", FEATURE_TAIL_LIZARD = "Dark Tiger",
"tail_human" = "None", FEATURE_TAIL = "None",
"snout" = "Sharp", FEATURE_SNOUT = "Sharp",
"horns" = "Curled", FEATURE_HORNS = "Curled",
"ears" = "None", FEATURE_EARS = "None",
"wings" = "None", FEATURE_WINGS = "None",
"frills" = "None", FEATURE_FRILLS = "None",
"spines" = "Long", FEATURE_SPINES = "Long",
"lizard_markings" = "Dark Tiger Body", FEATURE_LIZARD_MARKINGS = "Dark Tiger Body",
"legs" = DIGITIGRADE_LEGS, FEATURE_LEGS = DIGITIGRADE_LEGS,
) )
consumer.set_eye_color("#FEE5A3") consumer.set_eye_color("#FEE5A3")
consumer.set_species(/datum/species/lizard) consumer.set_species(/datum/species/lizard)

View File

@@ -350,9 +350,9 @@
// Ensures that lighter slimefolk look half-decent when wounded and bleeding // Ensures that lighter slimefolk look half-decent when wounded and bleeding
/datum/blood_type/slime/get_wound_color(mob/living/carbon/victim) /datum/blood_type/slime/get_wound_color(mob/living/carbon/victim)
return victim.dna?.features?["mcolor"] || get_color() return victim.dna?.features?[FEATURE_MUTANT_COLOR] || get_color()
/datum/blood_type/slime/get_damage_color(mob/living/carbon/victim) /datum/blood_type/slime/get_damage_color(mob/living/carbon/victim)
return victim.dna?.features?["mcolor"] || get_color() return victim.dna?.features?[FEATURE_MUTANT_COLOR] || get_color()
/// Podpeople blood /// Podpeople blood
/datum/blood_type/water /datum/blood_type/water

View File

@@ -1996,7 +1996,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
//Note for future: Potentionally add a new C.dna.species() to build a template species for more accurate limb replacement //Note for future: Potentionally add a new C.dna.species() to build a template species for more accurate limb replacement
var/list/final_bodypart_overrides = new_species.bodypart_overrides.Copy() var/list/final_bodypart_overrides = new_species.bodypart_overrides.Copy()
if((new_species.digitigrade_customization == DIGITIGRADE_OPTIONAL && target.dna.features["legs"] == DIGITIGRADE_LEGS) || new_species.digitigrade_customization == DIGITIGRADE_FORCED) if((new_species.digitigrade_customization == DIGITIGRADE_OPTIONAL && target.dna.features[FEATURE_LEGS] == DIGITIGRADE_LEGS) || new_species.digitigrade_customization == DIGITIGRADE_FORCED)
final_bodypart_overrides[BODY_ZONE_R_LEG] = /obj/item/bodypart/leg/right/digitigrade final_bodypart_overrides[BODY_ZONE_R_LEG] = /obj/item/bodypart/leg/right/digitigrade
final_bodypart_overrides[BODY_ZONE_L_LEG] = /obj/item/bodypart/leg/left/digitigrade final_bodypart_overrides[BODY_ZONE_L_LEG] = /obj/item/bodypart/leg/left/digitigrade
@@ -2048,7 +2048,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
ASSERT(!isnull(for_mob)) ASSERT(!isnull(for_mob))
switch(hair_color_mode) switch(hair_color_mode)
if(USE_MUTANT_COLOR) if(USE_MUTANT_COLOR)
return for_mob.dna.features["mcolor"] return for_mob.dna.features[FEATURE_MUTANT_COLOR]
if(USE_FIXED_MUTANT_COLOR) if(USE_FIXED_MUTANT_COLOR)
return fixed_mut_color return fixed_mut_color
@@ -2065,7 +2065,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
continue continue
var/datum/bodypart_overlay/simple/body_marking/overlay = new markings_type() var/datum/bodypart_overlay/simple/body_marking/overlay = new markings_type()
overlay.set_appearance(accessory_name, hooman.dna.features["mcolor"]) overlay.set_appearance(accessory_name, hooman.dna.features[FEATURE_MUTANT_COLOR])
people_part.add_bodypart_overlay(overlay) people_part.add_bodypart_overlay(overlay)
qdel(markings) qdel(markings)

View File

@@ -105,23 +105,23 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy)
return consistent_entry return consistent_entry
/proc/create_consistent_human_dna(mob/living/carbon/human/target) /proc/create_consistent_human_dna(mob/living/carbon/human/target)
target.dna.features["mcolor"] = COLOR_VIBRANT_LIME target.dna.features[FEATURE_MUTANT_COLOR] = COLOR_VIBRANT_LIME
target.dna.features["ethcolor"] = COLOR_WHITE target.dna.features[FEATURE_ETHEREAL_COLOR] = COLOR_WHITE
target.dna.features["lizard_markings"] = get_consistent_feature_entry(SSaccessories.lizard_markings_list) target.dna.features[FEATURE_LIZARD_MARKINGS] = get_consistent_feature_entry(SSaccessories.lizard_markings_list)
target.dna.features["ears"] = get_consistent_feature_entry(SSaccessories.ears_list) target.dna.features[FEATURE_EARS] = get_consistent_feature_entry(SSaccessories.ears_list)
target.dna.features["frills"] = get_consistent_feature_entry(SSaccessories.frills_list) target.dna.features[FEATURE_FRILLS] = get_consistent_feature_entry(SSaccessories.frills_list)
target.dna.features["horns"] = get_consistent_feature_entry(SSaccessories.horns_list) target.dna.features[FEATURE_HORNS] = get_consistent_feature_entry(SSaccessories.horns_list)
target.dna.features["moth_antennae"] = get_consistent_feature_entry(SSaccessories.moth_antennae_list) target.dna.features[FEATURE_MOTH_ANTENNAE] = get_consistent_feature_entry(SSaccessories.moth_antennae_list)
target.dna.features["moth_markings"] = get_consistent_feature_entry(SSaccessories.moth_markings_list) target.dna.features[FEATURE_MOTH_MARKINGS] = get_consistent_feature_entry(SSaccessories.moth_markings_list)
target.dna.features["moth_wings"] = get_consistent_feature_entry(SSaccessories.moth_wings_list) target.dna.features[FEATURE_MOTH_WINGS] = get_consistent_feature_entry(SSaccessories.moth_wings_list)
target.dna.features["snout"] = get_consistent_feature_entry(SSaccessories.snouts_list) target.dna.features[FEATURE_SNOUT] = get_consistent_feature_entry(SSaccessories.snouts_list)
target.dna.features["spines"] = get_consistent_feature_entry(SSaccessories.spines_list) target.dna.features[FEATURE_SPINES] = get_consistent_feature_entry(SSaccessories.spines_list)
target.dna.features["tail_cat"] = get_consistent_feature_entry(SSaccessories.tails_list_felinid) // it's a lie target.dna.features[FEATURE_TAIL] = get_consistent_feature_entry(SSaccessories.tails_list_felinid) // it's a lie
target.dna.features["tail_lizard"] = get_consistent_feature_entry(SSaccessories.tails_list_lizard) target.dna.features[FEATURE_TAIL_LIZARD] = get_consistent_feature_entry(SSaccessories.tails_list_lizard)
target.dna.features["tail_monkey"] = get_consistent_feature_entry(SSaccessories.tails_list_monkey) target.dna.features[FEATURE_TAIL_MONKEY] = get_consistent_feature_entry(SSaccessories.tails_list_monkey)
target.dna.features["fish_tail"] = get_consistent_feature_entry(SSaccessories.tails_list_fish) target.dna.features[FEATURE_TAIL_FISH] = get_consistent_feature_entry(SSaccessories.tails_list_fish)
target.dna.features["pod_hair"] = get_consistent_feature_entry(SSaccessories.pod_hair_list) target.dna.features[FEATURE_POD_HAIR] = get_consistent_feature_entry(SSaccessories.pod_hair_list)
target.dna.features["caps"] = get_consistent_feature_entry(SSaccessories.caps_list) target.dna.features[FEATURE_MUSH_CAP] = get_consistent_feature_entry(SSaccessories.caps_list)
target.dna.initialize_dna(newblood_type = get_blood_type(BLOOD_TYPE_O_MINUS), create_mutation_blocks = FALSE, randomize_features = FALSE) target.dna.initialize_dna(newblood_type = get_blood_type(BLOOD_TYPE_O_MINUS), create_mutation_blocks = FALSE, randomize_features = FALSE)
// UF and UI are nondeterministic, even though the features are the same some blocks will randomize slightly // UF and UI are nondeterministic, even though the features are the same some blocks will randomize slightly
// In practice this doesn't matter, but this is for the sake of 100%(ish) consistency // In practice this doesn't matter, but this is for the sake of 100%(ish) consistency

View File

@@ -55,7 +55,7 @@
. = ..() . = ..()
if(!ishuman(new_ethereal)) if(!ishuman(new_ethereal))
return return
default_color = new_ethereal.dna.features["ethcolor"] default_color = new_ethereal.dna.features[FEATURE_ETHEREAL_COLOR]
RegisterSignal(new_ethereal, COMSIG_ATOM_EMAG_ACT, PROC_REF(on_emag_act)) RegisterSignal(new_ethereal, COMSIG_ATOM_EMAG_ACT, PROC_REF(on_emag_act))
RegisterSignal(new_ethereal, COMSIG_ATOM_EMP_ACT, PROC_REF(on_emp_act)) RegisterSignal(new_ethereal, COMSIG_ATOM_EMP_ACT, PROC_REF(on_emp_act))
RegisterSignal(new_ethereal, COMSIG_ATOM_SABOTEUR_ACT, PROC_REF(hit_by_saboteur)) RegisterSignal(new_ethereal, COMSIG_ATOM_SABOTEUR_ACT, PROC_REF(hit_by_saboteur))
@@ -84,7 +84,7 @@
/datum/species/ethereal/randomize_features() /datum/species/ethereal/randomize_features()
var/list/features = ..() var/list/features = ..()
features["ethcolor"] = GLOB.color_list_ethereal[pick(GLOB.color_list_ethereal)] features[FEATURE_ETHEREAL_COLOR] = GLOB.color_list_ethereal[pick(GLOB.color_list_ethereal)]
return features return features
/datum/species/ethereal/proc/refresh_light_color(mob/living/carbon/human/ethereal) /datum/species/ethereal/proc/refresh_light_color(mob/living/carbon/human/ethereal)
@@ -95,7 +95,7 @@
var/healthpercent = max(ethereal.health, 0) / 100 var/healthpercent = max(ethereal.health, 0) / 100
if(!emageffect) if(!emageffect)
var/static/list/skin_color = rgb2num("#eda495") var/static/list/skin_color = rgb2num("#eda495")
var/list/colors = rgb2num(ethereal.dna.features["ethcolor"]) var/list/colors = rgb2num(ethereal.dna.features[FEATURE_ETHEREAL_COLOR])
var/list/built_color = list() var/list/built_color = list()
for(var/i in 1 to 3) for(var/i in 1 to 3)
built_color += skin_color[i] + ((colors[i] - skin_color[i]) * healthpercent) built_color += skin_color[i] + ((colors[i] - skin_color[i]) * healthpercent)
@@ -334,5 +334,5 @@
/datum/species/ethereal/lustrous/on_species_gain(mob/living/carbon/new_lustrous, datum/species/old_species, pref_load, regenerate_icons) /datum/species/ethereal/lustrous/on_species_gain(mob/living/carbon/new_lustrous, datum/species/old_species, pref_load, regenerate_icons)
..() ..()
default_color = new_lustrous.dna.features["ethcolor"] default_color = new_lustrous.dna.features[FEATURE_ETHEREAL_COLOR]
new_lustrous.dna.features["ethcolor"] = GLOB.color_list_lustrous[pick(GLOB.color_list_lustrous)] //Picks one of 5 lustrous-specific colors. new_lustrous.dna.features[FEATURE_ETHEREAL_COLOR] = GLOB.color_list_lustrous[pick(GLOB.color_list_lustrous)] //Picks one of 5 lustrous-specific colors.

View File

@@ -28,19 +28,19 @@
if(ishuman(carbon_being)) if(ishuman(carbon_being))
var/mob/living/carbon/human/target_human = carbon_being var/mob/living/carbon/human/target_human = carbon_being
if(!pref_load) //Hah! They got forcefully purrbation'd. Force default felinid parts on them if they have no mutant parts in those areas! if(!pref_load) //Hah! They got forcefully purrbation'd. Force default felinid parts on them if they have no mutant parts in those areas!
target_human.dna.features["tail_cat"] = "Cat" target_human.dna.features[FEATURE_TAIL] = "Cat"
if(target_human.dna.features["ears"] == "None") if(target_human.dna.features[FEATURE_EARS] == "None")
target_human.dna.features["ears"] = "Cat" target_human.dna.features[FEATURE_EARS] = "Cat"
if(target_human.dna.features["ears"] == "None") if(target_human.dna.features[FEATURE_EARS] == "None")
mutantears = /obj/item/organ/ears mutantears = /obj/item/organ/ears
else else
var/obj/item/organ/ears/cat/ears = new(FALSE, target_human.dna.features["ears"]) var/obj/item/organ/ears/cat/ears = new(FALSE, target_human.dna.features[FEATURE_EARS])
ears.Insert(target_human, movement_flags = DELETE_IF_REPLACED) ears.Insert(target_human, movement_flags = DELETE_IF_REPLACED)
return ..() return ..()
/datum/species/human/felinid/randomize_features(mob/living/carbon/human/human_mob) /datum/species/human/felinid/randomize_features(mob/living/carbon/human/human_mob)
var/list/features = ..() var/list/features = ..()
features["ears"] = pick("None", "Cat") features[FEATURE_EARS] = pick("None", "Cat")
return features return features
/datum/species/human/felinid/get_laugh_sound(mob/living/carbon/human/felinid) /datum/species/human/felinid/get_laugh_sound(mob/living/carbon/human/felinid)

View File

@@ -107,7 +107,7 @@
) )
/datum/species/jelly/prepare_human_for_preview(mob/living/carbon/human/human) /datum/species/jelly/prepare_human_for_preview(mob/living/carbon/human/human)
human.dna.features["mcolor"] = COLOR_PINK human.dna.features[FEATURE_MUTANT_COLOR] = COLOR_PINK
human.hairstyle = "Bob Hair 2" human.hairstyle = "Bob Hair 2"
human.hair_color = COLOR_PINK human.hair_color = COLOR_PINK
human.update_body(is_creating = TRUE) human.update_body(is_creating = TRUE)
@@ -304,8 +304,8 @@
spare.underwear = "Nude" spare.underwear = "Nude"
H.dna.copy_dna(spare.dna, COPY_DNA_SE|COPY_DNA_SPECIES|COPY_DNA_MUTATIONS) H.dna.copy_dna(spare.dna, COPY_DNA_SE|COPY_DNA_SPECIES|COPY_DNA_MUTATIONS)
spare.dna.features["mcolor"] = "#[pick("7F", "FF")][pick("7F", "FF")][pick("7F", "FF")]" spare.dna.features[FEATURE_MUTANT_COLOR] = "#[pick("7F", "FF")][pick("7F", "FF")][pick("7F", "FF")]"
spare.dna.update_uf_block(DNA_MUTANT_COLOR_BLOCK) spare.dna.update_uf_block(FEATURE_MUTANT_COLOR)
spare.real_name = spare.dna.real_name spare.real_name = spare.dna.real_name
spare.name = spare.dna.real_name spare.name = spare.dna.real_name
spare.updateappearance(mutcolor_update=1) spare.updateappearance(mutcolor_update=1)
@@ -371,7 +371,7 @@
continue continue
var/list/L = list() var/list/L = list()
L["htmlcolor"] = body.dna.features["mcolor"] L["htmlcolor"] = body.dna.features[FEATURE_MUTANT_COLOR]
L["area"] = get_area_name(body, TRUE) L["area"] = get_area_name(body, TRUE)
var/stat = "error" var/stat = "error"
switch(body.stat) switch(body.stat)
@@ -541,7 +541,7 @@
/datum/species/jelly/luminescent/proc/update_glow(mob/living/carbon/human/glowie, intensity) /datum/species/jelly/luminescent/proc/update_glow(mob/living/carbon/human/glowie, intensity)
if(intensity) if(intensity)
glow_intensity = intensity glow_intensity = intensity
glow.set_light_range_power_color(glow_intensity, glow_intensity, glowie.dna.features["mcolor"]) glow.set_light_range_power_color(glow_intensity, glow_intensity, glowie.dna.features[FEATURE_MUTANT_COLOR])
/datum/action/innate/integrate_extract /datum/action/innate/integrate_extract
name = "Integrate Extract" name = "Integrate Extract"

View File

@@ -51,7 +51,7 @@
/datum/species/lizard/randomize_features() /datum/species/lizard/randomize_features()
var/list/features = ..() var/list/features = ..()
features["lizard_markings"] = pick(SSaccessories.lizard_markings_list) features[FEATURE_LIZARD_MARKINGS] = pick(SSaccessories.lizard_markings_list)
return features return features
/datum/species/lizard/get_scream_sound(mob/living/carbon/human/lizard) /datum/species/lizard/get_scream_sound(mob/living/carbon/human/lizard)
@@ -225,14 +225,14 @@ Lizard subspecies: SILVER SCALED
and their tongue allows them to turn into a statue, for some reason." and their tongue allows them to turn into a statue, for some reason."
/datum/species/lizard/silverscale/on_species_gain(mob/living/carbon/human/new_silverscale, datum/species/old_species, pref_load, regenerate_icons) /datum/species/lizard/silverscale/on_species_gain(mob/living/carbon/human/new_silverscale, datum/species/old_species, pref_load, regenerate_icons)
old_mutcolor = new_silverscale.dna.features["mcolor"] old_mutcolor = new_silverscale.dna.features[FEATURE_MUTANT_COLOR]
new_silverscale.dna.features["mcolor"] = "#eeeeee" new_silverscale.dna.features[FEATURE_MUTANT_COLOR] = "#eeeeee"
new_silverscale.add_eye_color("#0000a0", EYE_COLOR_SPECIES_PRIORITY) new_silverscale.add_eye_color("#0000a0", EYE_COLOR_SPECIES_PRIORITY)
. = ..() . = ..()
new_silverscale.add_filter("silver_glint", 2, list("type" = "outline", "color" = "#ffffff63", "size" = 2)) new_silverscale.add_filter("silver_glint", 2, list("type" = "outline", "color" = "#ffffff63", "size" = 2))
/datum/species/lizard/silverscale/on_species_loss(mob/living/carbon/human/was_silverscale, datum/species/new_species, pref_load) /datum/species/lizard/silverscale/on_species_loss(mob/living/carbon/human/was_silverscale, datum/species/new_species, pref_load)
was_silverscale.dna.features["mcolor"] = old_mutcolor was_silverscale.dna.features[FEATURE_MUTANT_COLOR] = old_mutcolor
was_silverscale.remove_eye_color(EYE_COLOR_SPECIES_PRIORITY) was_silverscale.remove_eye_color(EYE_COLOR_SPECIES_PRIORITY)
was_silverscale.remove_filter("silver_glint") was_silverscale.remove_filter("silver_glint")
return ..() return ..()

View File

@@ -45,7 +45,7 @@
/datum/species/moth/randomize_features() /datum/species/moth/randomize_features()
var/list/features = ..() var/list/features = ..()
features["moth_markings"] = pick(SSaccessories.moth_markings_list) features[FEATURE_MOTH_MARKINGS] = pick(SSaccessories.moth_markings_list)
return features return features
/datum/species/moth/get_scream_sound(mob/living/carbon/human/moth) /datum/species/moth/get_scream_sound(mob/living/carbon/human/moth)

View File

@@ -61,7 +61,7 @@
preference = "feature_mushperson_cap" preference = "feature_mushperson_cap"
dna_block = DNA_MUSHROOM_CAPS_BLOCK dna_block = /datum/dna_block/feature/mush_cap
restyle_flags = EXTERNAL_RESTYLE_PLANT restyle_flags = EXTERNAL_RESTYLE_PLANT
bodypart_overlay = /datum/bodypart_overlay/mutant/mushroom_cap bodypart_overlay = /datum/bodypart_overlay/mutant/mushroom_cap
@@ -71,7 +71,7 @@
/// Bodypart overlay for the mushroom cap organ /// Bodypart overlay for the mushroom cap organ
/datum/bodypart_overlay/mutant/mushroom_cap /datum/bodypart_overlay/mutant/mushroom_cap
layers = EXTERNAL_ADJACENT layers = EXTERNAL_ADJACENT
feature_key = "caps" feature_key = FEATURE_MUSH_CAP
dyable = TRUE dyable = TRUE
/datum/bodypart_overlay/mutant/mushroom_cap/get_global_feature_list() /datum/bodypart_overlay/mutant/mushroom_cap/get_global_feature_list()

View File

@@ -40,8 +40,8 @@
) )
/datum/species/pod/prepare_human_for_preview(mob/living/carbon/human/human) /datum/species/pod/prepare_human_for_preview(mob/living/carbon/human/human)
human.dna.features["mcolor"] = "#886600" human.dna.features[FEATURE_MUTANT_COLOR] = "#886600"
human.dna.features["pod_hair"] = "Rose" human.dna.features[FEATURE_POD_HAIR] = "Rose"
human.update_body(is_creating = TRUE) human.update_body(is_creating = TRUE)
/datum/species/pod/get_physical_attributes() /datum/species/pod/get_physical_attributes()

View File

@@ -28,7 +28,7 @@
) )
/datum/species/snail/prepare_human_for_preview(mob/living/carbon/human/human) /datum/species/snail/prepare_human_for_preview(mob/living/carbon/human/human)
human.dna.features["mcolor"] = COLOR_BEIGE human.dna.features[FEATURE_MUTANT_COLOR] = COLOR_BEIGE
human.update_body(is_creating = TRUE) human.update_body(is_creating = TRUE)
/datum/species/snail/get_physical_attributes() /datum/species/snail/get_physical_attributes()

View File

@@ -31,14 +31,8 @@
/mob/living/carbon/proc/on_agender_trait_loss(datum/source) /mob/living/carbon/proc/on_agender_trait_loss(datum/source)
SIGNAL_HANDLER SIGNAL_HANDLER
//updates our gender to be whatever our DNA wants it to be var/datum/dna_block/identity/gender/to_update = GLOB.dna_identity_blocks[/datum/dna_block/identity/gender]
switch(deconstruct_block(get_uni_identity_block(dna.unique_identity, DNA_GENDER_BLOCK), 3) || pick(G_MALE, G_FEMALE)) to_update.apply_to_mob(src, src.dna.unique_identity)
if(G_MALE)
gender = MALE
if(G_FEMALE)
gender = FEMALE
else
gender = PLURAL
/** /**
* On gain of TRAIT_NOBREATH * On gain of TRAIT_NOBREATH

View File

@@ -168,7 +168,7 @@
if(HAS_TRAIT(affected_human, TRAIT_USES_SKINTONES)) if(HAS_TRAIT(affected_human, TRAIT_USES_SKINTONES))
affected_human.skin_tone = "green" affected_human.skin_tone = "green"
else if(HAS_TRAIT(affected_human, TRAIT_MUTANT_COLORS) && !HAS_TRAIT(affected_human, TRAIT_FIXED_MUTANT_COLORS)) //Code stolen from spraytan overdose else if(HAS_TRAIT(affected_human, TRAIT_MUTANT_COLORS) && !HAS_TRAIT(affected_human, TRAIT_FIXED_MUTANT_COLORS)) //Code stolen from spraytan overdose
affected_human.dna.features["mcolor"] = "#a8e61d" affected_human.dna.features[FEATURE_MUTANT_COLOR] = "#a8e61d"
affected_human.update_body(is_creating = TRUE) affected_human.update_body(is_creating = TRUE)
/datum/reagent/consumable/ethanol/kahlua /datum/reagent/consumable/ethanol/kahlua

View File

@@ -589,7 +589,7 @@
exposed_human.skin_tone = "mixed3" exposed_human.skin_tone = "mixed3"
//take current alien color and darken it slightly //take current alien color and darken it slightly
else if(HAS_TRAIT(exposed_human, TRAIT_MUTANT_COLORS) && !HAS_TRAIT(exposed_human, TRAIT_FIXED_MUTANT_COLORS)) else if(HAS_TRAIT(exposed_human, TRAIT_MUTANT_COLORS) && !HAS_TRAIT(exposed_human, TRAIT_FIXED_MUTANT_COLORS))
var/list/existing_color = rgb2num(exposed_human.dna.features["mcolor"]) var/list/existing_color = rgb2num(exposed_human.dna.features[FEATURE_MUTANT_COLOR])
var/list/darkened_color = list() var/list/darkened_color = list()
// Reduces each part of the color by 16 // Reduces each part of the color by 16
for(var/channel in existing_color) for(var/channel in existing_color)
@@ -599,7 +599,7 @@
var/list/new_hsv = rgb2hsv(new_color) var/list/new_hsv = rgb2hsv(new_color)
// Can't get too dark now // Can't get too dark now
if(new_hsv[3] >= 50) if(new_hsv[3] >= 50)
exposed_human.dna.features["mcolor"] = new_color exposed_human.dna.features[FEATURE_MUTANT_COLOR] = new_color
exposed_human.update_body(is_creating = TRUE) exposed_human.update_body(is_creating = TRUE)
if((methods & INGEST) && show_message) if((methods & INGEST) && show_message)
@@ -623,7 +623,7 @@
if(HAS_TRAIT(affected_human, TRAIT_USES_SKINTONES)) if(HAS_TRAIT(affected_human, TRAIT_USES_SKINTONES))
affected_human.skin_tone = "orange" affected_human.skin_tone = "orange"
else if(HAS_TRAIT(affected_human, TRAIT_MUTANT_COLORS) && !HAS_TRAIT(affected_human, TRAIT_FIXED_MUTANT_COLORS)) //Aliens with custom colors simply get turned orange else if(HAS_TRAIT(affected_human, TRAIT_MUTANT_COLORS) && !HAS_TRAIT(affected_human, TRAIT_FIXED_MUTANT_COLORS)) //Aliens with custom colors simply get turned orange
affected_human.dna.features["mcolor"] = "#ff8800" affected_human.dna.features[FEATURE_MUTANT_COLOR] = "#ff8800"
affected_human.update_body(is_creating = TRUE) affected_human.update_body(is_creating = TRUE)
if(SPT_PROB(3.5, seconds_per_tick)) if(SPT_PROB(3.5, seconds_per_tick))
if(affected_human.w_uniform) if(affected_human.w_uniform)

View File

@@ -606,8 +606,8 @@
/obj/item/slime_extract/rainbow/activate(mob/living/carbon/human/user, datum/species/jelly/luminescent/species, activation_type) /obj/item/slime_extract/rainbow/activate(mob/living/carbon/human/user, datum/species/jelly/luminescent/species, activation_type)
switch(activation_type) switch(activation_type)
if(SLIME_ACTIVATE_MINOR) if(SLIME_ACTIVATE_MINOR)
user.dna.features["mcolor"] = "#[pick("7F", "FF")][pick("7F", "FF")][pick("7F", "FF")]" user.dna.features[FEATURE_MUTANT_COLOR] = "#[pick("7F", "FF")][pick("7F", "FF")][pick("7F", "FF")]"
user.dna.update_uf_block(DNA_MUTANT_COLOR_BLOCK) user.dna.update_uf_block(FEATURE_MUTANT_COLOR)
user.updateappearance(mutcolor_update=1) user.updateappearance(mutcolor_update=1)
species.update_glow(user) species.update_glow(user)
to_chat(user, span_notice("You feel different...")) to_chat(user, span_notice("You feel different..."))

View File

@@ -982,7 +982,7 @@
if(owner_species.fixed_mut_color) if(owner_species.fixed_mut_color)
species_color = owner_species.fixed_mut_color species_color = owner_species.fixed_mut_color
else else
species_color = human_owner.dna.features["mcolor"] species_color = human_owner.dna.features[FEATURE_MUTANT_COLOR]
else else
skin_tone = "" skin_tone = ""
species_color = "" species_color = ""

View File

@@ -10,7 +10,7 @@ Unlike normal organs, we're actually inside a persons limbs at all times
/// The savefile_key of the preference this relates to. Used for the preferences UI. /// The savefile_key of the preference this relates to. Used for the preferences UI.
var/preference var/preference
///With what DNA block do we mutate in mutate_feature() ? For genetics ///With what DNA block do we mutate in mutate_feature() ? For genetics
var/dna_block var/datum/dna_block/dna_block
///Set to EXTERNAL_BEHIND, EXTERNAL_FRONT or EXTERNAL_ADJACENT if you want to draw one of those layers as the object sprite. FALSE to use your own ///Set to EXTERNAL_BEHIND, EXTERNAL_FRONT or EXTERNAL_ADJACENT if you want to draw one of those layers as the object sprite. FALSE to use your own
///This will not work if it doesn't have a limb to generate its icon with ///This will not work if it doesn't have a limb to generate its icon with
@@ -75,7 +75,8 @@ Unlike normal organs, we're actually inside a persons limbs at all times
var/list/feature_list = bodypart_overlay.get_global_feature_list() var/list/feature_list = bodypart_overlay.get_global_feature_list()
bodypart_overlay.set_appearance_from_name(feature_list[deconstruct_block(get_uni_feature_block(features, dna_block), feature_list.len)]) var/datum/dna_block/feature/feature_block = GLOB.dna_feature_blocks[dna_block]
bodypart_overlay.set_appearance_from_name(feature_list[deconstruct_block(feature_block.get_block(features), feature_list.len)])
///If you need to change an external_organ for simple one-offs, use this. Pass the accessory type : /datum/accessory/something ///If you need to change an external_organ for simple one-offs, use this. Pass the accessory type : /datum/accessory/something
/obj/item/organ/proc/simple_change_sprite(accessory_type) /obj/item/organ/proc/simple_change_sprite(accessory_type)
@@ -109,7 +110,7 @@ Unlike normal organs, we're actually inside a persons limbs at all times
slot = ORGAN_SLOT_EXTERNAL_HORNS slot = ORGAN_SLOT_EXTERNAL_HORNS
preference = "feature_lizard_horns" preference = "feature_lizard_horns"
dna_block = DNA_HORNS_BLOCK dna_block = /datum/dna_block/feature/horn
restyle_flags = EXTERNAL_RESTYLE_ENAMEL restyle_flags = EXTERNAL_RESTYLE_ENAMEL
bodypart_overlay = /datum/bodypart_overlay/mutant/horns bodypart_overlay = /datum/bodypart_overlay/mutant/horns
@@ -118,7 +119,7 @@ Unlike normal organs, we're actually inside a persons limbs at all times
/datum/bodypart_overlay/mutant/horns /datum/bodypart_overlay/mutant/horns
layers = EXTERNAL_ADJACENT layers = EXTERNAL_ADJACENT
feature_key = "horns" feature_key = FEATURE_HORNS
dyable = TRUE dyable = TRUE
/datum/bodypart_overlay/mutant/horns/can_draw_on_bodypart(obj/item/bodypart/bodypart_owner) /datum/bodypart_overlay/mutant/horns/can_draw_on_bodypart(obj/item/bodypart/bodypart_owner)
@@ -142,7 +143,7 @@ Unlike normal organs, we're actually inside a persons limbs at all times
slot = ORGAN_SLOT_EXTERNAL_FRILLS slot = ORGAN_SLOT_EXTERNAL_FRILLS
preference = "feature_lizard_frills" preference = "feature_lizard_frills"
dna_block = DNA_FRILLS_BLOCK dna_block = /datum/dna_block/feature/frill
restyle_flags = EXTERNAL_RESTYLE_FLESH restyle_flags = EXTERNAL_RESTYLE_FLESH
bodypart_overlay = /datum/bodypart_overlay/mutant/frills bodypart_overlay = /datum/bodypart_overlay/mutant/frills
@@ -151,7 +152,7 @@ Unlike normal organs, we're actually inside a persons limbs at all times
/datum/bodypart_overlay/mutant/frills /datum/bodypart_overlay/mutant/frills
layers = EXTERNAL_ADJACENT layers = EXTERNAL_ADJACENT
feature_key = "frills" feature_key = FEATURE_FRILLS
/datum/bodypart_overlay/mutant/frills/can_draw_on_bodypart(obj/item/bodypart/bodypart_owner) /datum/bodypart_overlay/mutant/frills/can_draw_on_bodypart(obj/item/bodypart/bodypart_owner)
var/mob/living/carbon/human/human = bodypart_owner.owner var/mob/living/carbon/human/human = bodypart_owner.owner
@@ -176,7 +177,7 @@ Unlike normal organs, we're actually inside a persons limbs at all times
preference = "feature_lizard_snout" preference = "feature_lizard_snout"
external_bodyshapes = BODYSHAPE_SNOUTED external_bodyshapes = BODYSHAPE_SNOUTED
dna_block = DNA_SNOUT_BLOCK dna_block = /datum/dna_block/feature/snout
restyle_flags = EXTERNAL_RESTYLE_FLESH restyle_flags = EXTERNAL_RESTYLE_FLESH
bodypart_overlay = /datum/bodypart_overlay/mutant/snout bodypart_overlay = /datum/bodypart_overlay/mutant/snout
@@ -185,7 +186,7 @@ Unlike normal organs, we're actually inside a persons limbs at all times
/datum/bodypart_overlay/mutant/snout /datum/bodypart_overlay/mutant/snout
layers = EXTERNAL_ADJACENT layers = EXTERNAL_ADJACENT
feature_key = "snout" feature_key = FEATURE_SNOUT
/datum/bodypart_overlay/mutant/snout/can_draw_on_bodypart(obj/item/bodypart/bodypart_owner) /datum/bodypart_overlay/mutant/snout/can_draw_on_bodypart(obj/item/bodypart/bodypart_owner)
var/mob/living/carbon/human/human = bodypart_owner.owner var/mob/living/carbon/human/human = bodypart_owner.owner
@@ -208,7 +209,7 @@ Unlike normal organs, we're actually inside a persons limbs at all times
slot = ORGAN_SLOT_EXTERNAL_ANTENNAE slot = ORGAN_SLOT_EXTERNAL_ANTENNAE
preference = "feature_moth_antennae" preference = "feature_moth_antennae"
dna_block = DNA_MOTH_ANTENNAE_BLOCK dna_block = /datum/dna_block/feature/moth_antenna
restyle_flags = EXTERNAL_RESTYLE_FLESH restyle_flags = EXTERNAL_RESTYLE_FLESH
bodypart_overlay = /datum/bodypart_overlay/mutant/antennae bodypart_overlay = /datum/bodypart_overlay/mutant/antennae
@@ -262,7 +263,7 @@ Unlike normal organs, we're actually inside a persons limbs at all times
///Moth antennae datum, with full burning functionality ///Moth antennae datum, with full burning functionality
/datum/bodypart_overlay/mutant/antennae /datum/bodypart_overlay/mutant/antennae
layers = EXTERNAL_FRONT | EXTERNAL_BEHIND layers = EXTERNAL_FRONT | EXTERNAL_BEHIND
feature_key = "moth_antennae" feature_key = FEATURE_MOTH_ANTENNAE
dyable = TRUE dyable = TRUE
///Accessory datum of the burn sprite ///Accessory datum of the burn sprite
var/datum/sprite_accessory/burn_datum = /datum/sprite_accessory/moth_antennae/burnt_off var/datum/sprite_accessory/burn_datum = /datum/sprite_accessory/moth_antennae/burnt_off
@@ -299,7 +300,7 @@ Unlike normal organs, we're actually inside a persons limbs at all times
preference = "feature_pod_hair" preference = "feature_pod_hair"
use_mob_sprite_as_obj_sprite = TRUE use_mob_sprite_as_obj_sprite = TRUE
dna_block = DNA_POD_HAIR_BLOCK dna_block = /datum/dna_block/feature/pod_hair
restyle_flags = EXTERNAL_RESTYLE_PLANT restyle_flags = EXTERNAL_RESTYLE_PLANT
bodypart_overlay = /datum/bodypart_overlay/mutant/pod_hair bodypart_overlay = /datum/bodypart_overlay/mutant/pod_hair
@@ -309,7 +310,7 @@ Unlike normal organs, we're actually inside a persons limbs at all times
///Podperson bodypart overlay, with special coloring functionality to render the flowers in the inverse color ///Podperson bodypart overlay, with special coloring functionality to render the flowers in the inverse color
/datum/bodypart_overlay/mutant/pod_hair /datum/bodypart_overlay/mutant/pod_hair
layers = EXTERNAL_FRONT|EXTERNAL_ADJACENT layers = EXTERNAL_FRONT|EXTERNAL_ADJACENT
feature_key = "pod_hair" feature_key = FEATURE_POD_HAIR
dyable = TRUE dyable = TRUE
///This layer will be colored differently than the rest of the organ. So we can get differently colored flowers or something ///This layer will be colored differently than the rest of the organ. So we can get differently colored flowers or something

View File

@@ -9,7 +9,7 @@
preference = "feature_lizard_spines" preference = "feature_lizard_spines"
dna_block = DNA_SPINES_BLOCK dna_block = /datum/dna_block/feature/spine
restyle_flags = EXTERNAL_RESTYLE_FLESH restyle_flags = EXTERNAL_RESTYLE_FLESH
bodypart_overlay = /datum/bodypart_overlay/mutant/spines bodypart_overlay = /datum/bodypart_overlay/mutant/spines
@@ -31,7 +31,7 @@
///Bodypart overlay for spines ///Bodypart overlay for spines
/datum/bodypart_overlay/mutant/spines /datum/bodypart_overlay/mutant/spines
layers = EXTERNAL_ADJACENT|EXTERNAL_BEHIND layers = EXTERNAL_ADJACENT|EXTERNAL_BEHIND
feature_key = "spines" feature_key = FEATURE_SPINES
dyable = TRUE dyable = TRUE
/datum/bodypart_overlay/mutant/spines/get_global_feature_list() /datum/bodypart_overlay/mutant/spines/get_global_feature_list()

View File

@@ -7,7 +7,7 @@
zone = BODY_ZONE_PRECISE_GROIN zone = BODY_ZONE_PRECISE_GROIN
slot = ORGAN_SLOT_EXTERNAL_TAIL slot = ORGAN_SLOT_EXTERNAL_TAIL
dna_block = DNA_TAIL_BLOCK dna_block = /datum/dna_block/feature/tail
restyle_flags = EXTERNAL_RESTYLE_FLESH restyle_flags = EXTERNAL_RESTYLE_FLESH
// defaults to cat, but the parent type shouldn't be created regardless // defaults to cat, but the parent type shouldn't be created regardless
@@ -65,7 +65,7 @@
tail_spines_overlay = new tail_spines_overlay = new
tail_spines_overlay.tail_spine_key = tail_spine_key tail_spines_overlay.tail_spine_key = tail_spine_key
var/feature_name = bodypart.owner.dna.features["spines"] //tail spines don't live in DNA, but share feature names with regular spines var/feature_name = bodypart.owner.dna.features[FEATURE_SPINES] //tail spines don't live in DNA, but share feature names with regular spines
tail_spines_overlay.set_appearance_from_name(feature_name) tail_spines_overlay.set_appearance_from_name(feature_name)
bodypart.add_bodypart_overlay(tail_spines_overlay) bodypart.add_bodypart_overlay(tail_spines_overlay)
@@ -169,7 +169,7 @@
///Cat tail bodypart overlay ///Cat tail bodypart overlay
/datum/bodypart_overlay/mutant/tail/cat /datum/bodypart_overlay/mutant/tail/cat
feature_key = "tail_cat" feature_key = FEATURE_TAIL
color_source = ORGAN_COLOR_HAIR color_source = ORGAN_COLOR_HAIR
/datum/bodypart_overlay/mutant/tail/cat/get_global_feature_list() /datum/bodypart_overlay/mutant/tail/cat/get_global_feature_list()
@@ -185,7 +185,7 @@
///Monkey tail bodypart overlay ///Monkey tail bodypart overlay
/datum/bodypart_overlay/mutant/tail/monkey /datum/bodypart_overlay/mutant/tail/monkey
color_source = NONE color_source = NONE
feature_key = "tail_monkey" feature_key = FEATURE_TAIL_MONKEY
/datum/bodypart_overlay/mutant/tail/monkey/get_global_feature_list() /datum/bodypart_overlay/mutant/tail/monkey/get_global_feature_list()
return SSaccessories.tails_list_monkey return SSaccessories.tails_list_monkey
@@ -228,7 +228,7 @@
///Alien tail bodypart overlay ///Alien tail bodypart overlay
/datum/bodypart_overlay/mutant/tail/xeno /datum/bodypart_overlay/mutant/tail/xeno
color_source = NONE color_source = NONE
feature_key = "tail_xeno" feature_key = FEATURE_TAIL_XENO
imprint_on_next_insertion = FALSE imprint_on_next_insertion = FALSE
/// We don't want to bother writing this in DNA, just use this appearance /// We don't want to bother writing this in DNA, just use this appearance
var/default_appearance = "Xeno" var/default_appearance = "Xeno"
@@ -254,11 +254,11 @@
bodypart_overlay = /datum/bodypart_overlay/mutant/tail/lizard bodypart_overlay = /datum/bodypart_overlay/mutant/tail/lizard
wag_flags = WAG_ABLE wag_flags = WAG_ABLE
dna_block = DNA_LIZARD_TAIL_BLOCK dna_block = /datum/dna_block/feature/tail_lizard
///Lizard tail bodypart overlay datum ///Lizard tail bodypart overlay datum
/datum/bodypart_overlay/mutant/tail/lizard /datum/bodypart_overlay/mutant/tail/lizard
feature_key = "tail_lizard" feature_key = FEATURE_TAIL_LIZARD
/datum/bodypart_overlay/mutant/tail/lizard/get_global_feature_list() /datum/bodypart_overlay/mutant/tail/lizard/get_global_feature_list()
return SSaccessories.tails_list_lizard return SSaccessories.tails_list_lizard
@@ -270,7 +270,7 @@
///Bodypart overlay for tail spines. Handled by the tail - has no actual organ associated. ///Bodypart overlay for tail spines. Handled by the tail - has no actual organ associated.
/datum/bodypart_overlay/mutant/tail_spines /datum/bodypart_overlay/mutant/tail_spines
layers = EXTERNAL_ADJACENT|EXTERNAL_BEHIND layers = EXTERNAL_ADJACENT|EXTERNAL_BEHIND
feature_key = "tailspines" feature_key = FEATURE_TAILSPINES
///Spines wag when the tail does ///Spines wag when the tail does
var/wagging = FALSE var/wagging = FALSE
/// Key for tail spine states, depends on the shape of the tail. Defined in the tail sprite datum. /// Key for tail spine states, depends on the shape of the tail. Defined in the tail sprite datum.

View File

@@ -7,7 +7,7 @@
preference = "feature_moth_wings" preference = "feature_moth_wings"
dna_block = DNA_MOTH_WINGS_BLOCK dna_block = /datum/dna_block/feature/moth_wing
bodypart_overlay = /datum/bodypart_overlay/mutant/wings/moth bodypart_overlay = /datum/bodypart_overlay/mutant/wings/moth
restyle_flags = EXTERNAL_RESTYLE_FLESH restyle_flags = EXTERNAL_RESTYLE_FLESH
@@ -101,7 +101,7 @@
///Moth wing bodypart overlay, including burn functionality! ///Moth wing bodypart overlay, including burn functionality!
/datum/bodypart_overlay/mutant/wings/moth /datum/bodypart_overlay/mutant/wings/moth
feature_key = "moth_wings" feature_key = FEATURE_MOTH_WINGS
layers = EXTERNAL_BEHIND | EXTERNAL_FRONT layers = EXTERNAL_BEHIND | EXTERNAL_FRONT
///Accessory datum of the burn sprite ///Accessory datum of the burn sprite
var/datum/sprite_accessory/burn_datum = /datum/sprite_accessory/moth_wings/burnt_off var/datum/sprite_accessory/burn_datum = /datum/sprite_accessory/moth_wings/burnt_off

View File

@@ -22,7 +22,7 @@
///Bodypart overlay of default wings. Does not have any wing functionality ///Bodypart overlay of default wings. Does not have any wing functionality
/datum/bodypart_overlay/mutant/wings /datum/bodypart_overlay/mutant/wings
layers = ALL_EXTERNAL_OVERLAYS layers = ALL_EXTERNAL_OVERLAYS
feature_key = "wings" feature_key = FEATURE_WINGS
/datum/bodypart_overlay/mutant/wings/can_draw_on_bodypart(obj/item/bodypart/bodypart_owner) /datum/bodypart_overlay/mutant/wings/can_draw_on_bodypart(obj/item/bodypart/bodypart_owner)
var/mob/living/carbon/human/human = bodypart_owner.owner var/mob/living/carbon/human/human = bodypart_owner.owner

View File

@@ -160,7 +160,7 @@
preference = "feature_human_ears" preference = "feature_human_ears"
restyle_flags = EXTERNAL_RESTYLE_FLESH restyle_flags = EXTERNAL_RESTYLE_FLESH
dna_block = DNA_EARS_BLOCK dna_block = /datum/dna_block/feature/ears
bodypart_overlay = /datum/bodypart_overlay/mutant/cat_ears bodypart_overlay = /datum/bodypart_overlay/mutant/cat_ears
@@ -168,7 +168,7 @@
/datum/bodypart_overlay/mutant/cat_ears /datum/bodypart_overlay/mutant/cat_ears
layers = EXTERNAL_FRONT | EXTERNAL_BEHIND layers = EXTERNAL_FRONT | EXTERNAL_BEHIND
color_source = ORGAN_COLOR_HAIR color_source = ORGAN_COLOR_HAIR
feature_key = "ears" feature_key = FEATURE_EARS
dyable = TRUE dyable = TRUE
/// Layer upon which we add the inner ears overlay /// Layer upon which we add the inner ears overlay

View File

@@ -103,7 +103,7 @@
var/mob/living/carbon/human/human = carbon var/mob/living/carbon/human/human = carbon
if(human.dna?.species) if(human.dna?.species)
//fixed_mut_color is also ethereal color (for some reason) //fixed_mut_color is also ethereal color (for some reason)
carbon.flash_lighting_fx(5, 7, human.dna.species.fixed_mut_color ? human.dna.species.fixed_mut_color : human.dna.features["mcolor"]) carbon.flash_lighting_fx(5, 7, human.dna.species.fixed_mut_color ? human.dna.species.fixed_mut_color : human.dna.features[FEATURE_MUTANT_COLOR])
playsound(carbon, 'sound/effects/magic/lightningshock.ogg', 100, TRUE, extrarange = 5) playsound(carbon, 'sound/effects/magic/lightningshock.ogg', 100, TRUE, extrarange = 5)
carbon.cut_overlay(overcharge) carbon.cut_overlay(overcharge)

View File

@@ -26,7 +26,7 @@
TEST_ASSERT_EQUAL(victim.real_name, ling_name, "Victim real name did not change on being transformation stung.") TEST_ASSERT_EQUAL(victim.real_name, ling_name, "Victim real name did not change on being transformation stung.")
TEST_ASSERT_EQUAL(victim.name, ling_name, "Victim name did not change on being transformation stung.") TEST_ASSERT_EQUAL(victim.name, ling_name, "Victim name did not change on being transformation stung.")
TEST_ASSERT_EQUAL(victim.dna.species.type, ling.dna.species.type, "Victim species did not change on being transformation stung.") TEST_ASSERT_EQUAL(victim.dna.species.type, ling.dna.species.type, "Victim species did not change on being transformation stung.")
TEST_ASSERT_EQUAL(victim.dna.features["mcolor"], ling.dna.features["mcolor"], "Victim mcolor did not change on being transformation stung.") TEST_ASSERT_EQUAL(victim.dna.features[FEATURE_MUTANT_COLOR], ling.dna.features[FEATURE_MUTANT_COLOR], "Victim mcolor did not change on being transformation stung.")
// Check they actually look the same // Check they actually look the same
add_to_screenshot(ling, victim) add_to_screenshot(ling, victim)
@@ -37,7 +37,7 @@
TEST_ASSERT_EQUAL(victim.name, base_victim_name, "Victim name did not change back after transformation sting expired.") TEST_ASSERT_EQUAL(victim.name, base_victim_name, "Victim name did not change back after transformation sting expired.")
TEST_ASSERT_EQUAL(victim.real_name, base_victim_name, "Victim real name did not change back after transformation sting expired.") TEST_ASSERT_EQUAL(victim.real_name, base_victim_name, "Victim real name did not change back after transformation sting expired.")
TEST_ASSERT_NOTEQUAL(victim.dna.species.type, ling.dna.species.type, "Victim species did not change back after transformation sting expired.") TEST_ASSERT_NOTEQUAL(victim.dna.species.type, ling.dna.species.type, "Victim species did not change back after transformation sting expired.")
TEST_ASSERT_NOTEQUAL(victim.dna.features["mcolor"], ling.dna.features["mcolor"], "Victim mcolor did not reset after transformation sting expired.") TEST_ASSERT_NOTEQUAL(victim.dna.features[FEATURE_MUTANT_COLOR], ling.dna.features[FEATURE_MUTANT_COLOR], "Victim mcolor did not reset after transformation sting expired.")
// Check they actually look different again // Check they actually look different again
add_to_screenshot(ling, victim, both_species = TRUE) add_to_screenshot(ling, victim, both_species = TRUE)
@@ -74,17 +74,16 @@
// Because we use two consistent humans, we need to change some of the features to know they're actually updating to new values. // Because we use two consistent humans, we need to change some of the features to know they're actually updating to new values.
// The more DNA features and random things we change, the more likely we are to catch something not updating correctly. // The more DNA features and random things we change, the more likely we are to catch something not updating correctly.
// Yeah guess who/what this is, I dare you. // Yeah guess who/what this is, I dare you.
ling.dna.features["mcolor"] = "#886600" ling.dna.features[FEATURE_MUTANT_COLOR] = "#886600"
ling.dna.features["tail_lizard"] = "Smooth" ling.dna.features[FEATURE_TAIL_LIZARD] = "Smooth"
ling.dna.features["snout"] = "Sharp + Light" ling.dna.features[FEATURE_SNOUT] = "Sharp + Light"
ling.dna.features["horns"] = "Curled" ling.dna.features[FEATURE_HORNS] = "Curled"
ling.dna.features["frills"] = "Short" ling.dna.features[FEATURE_FRILLS] = "Short"
ling.dna.features["spines"] = "Long + Membrane" ling.dna.features[FEATURE_SPINES] = "Long + Membrane"
ling.dna.features["lizard_markings"] = "Light Belly" ling.dna.features[FEATURE_LIZARD_MARKINGS] = "Light Belly"
ling.dna.features["legs"] = DIGITIGRADE_LEGS ling.dna.features[FEATURE_LEGS] = DIGITIGRADE_LEGS
ling.set_eye_color(COLOR_WHITE) ling.set_eye_color(COLOR_WHITE)
ling.dna.update_ui_block(DNA_EYE_COLOR_LEFT_BLOCK) ling.dna.update_ui_block(/datum/dna_block/identity/eye_colors)
ling.dna.update_ui_block(DNA_EYE_COLOR_RIGHT_BLOCK)
ling.set_species(/datum/species/lizard) ling.set_species(/datum/species/lizard)
ling.real_name = ling_name ling.real_name = ling_name

View File

@@ -6,12 +6,12 @@
// Test lizards as their own thing so we can get more coverage on their features // Test lizards as their own thing so we can get more coverage on their features
var/mob/living/carbon/human/lizard = allocate(/mob/living/carbon/human/dummy/consistent) var/mob/living/carbon/human/lizard = allocate(/mob/living/carbon/human/dummy/consistent)
lizard.dna.features["mcolor"] = "#099" lizard.dna.features[FEATURE_MUTANT_COLOR] = "#099"
lizard.dna.features["tail_lizard"] = "Light Tiger" lizard.dna.features[FEATURE_TAIL_LIZARD] = "Light Tiger"
lizard.dna.features["snout"] = "Sharp + Light" lizard.dna.features[FEATURE_SNOUT] = "Sharp + Light"
lizard.dna.features["horns"] = "Simple" lizard.dna.features[FEATURE_HORNS] = "Simple"
lizard.dna.features["frills"] = "Aquatic" lizard.dna.features[FEATURE_FRILLS] = "Aquatic"
lizard.dna.features["legs"] = "Normal Legs" lizard.dna.features[FEATURE_LEGS] = "Normal Legs"
lizard.set_species(/datum/species/lizard) lizard.set_species(/datum/species/lizard)
lizard.equipOutfit(/datum/outfit/job/engineer) lizard.equipOutfit(/datum/outfit/job/engineer)
test_screenshot("[/datum/species/lizard]", get_flat_icon_for_all_directions(lizard)) test_screenshot("[/datum/species/lizard]", get_flat_icon_for_all_directions(lizard))
@@ -24,9 +24,9 @@
// let me have this // let me have this
var/mob/living/carbon/human/moth = allocate(/mob/living/carbon/human/dummy/consistent) var/mob/living/carbon/human/moth = allocate(/mob/living/carbon/human/dummy/consistent)
moth.dna.features["moth_antennae"] = "Firewatch" moth.dna.features[FEATURE_MOTH_ANTENNAE] = "Firewatch"
moth.dna.features["moth_markings"] = "None" moth.dna.features[FEATURE_MOTH_MARKINGS] = "None"
moth.dna.features["moth_wings"] = "Firewatch" moth.dna.features[FEATURE_MOTH_WINGS] = "Firewatch"
moth.set_species(/datum/species/moth) moth.set_species(/datum/species/moth)
moth.equipOutfit(/datum/outfit/job/cmo, visuals_only = TRUE) moth.equipOutfit(/datum/outfit/job/cmo, visuals_only = TRUE)
test_screenshot("[/datum/species/moth]", get_flat_icon_for_all_directions(moth)) test_screenshot("[/datum/species/moth]", get_flat_icon_for_all_directions(moth))
@@ -35,7 +35,7 @@
// More in depth test for slimes since they have a lot going on // More in depth test for slimes since they have a lot going on
for (var/datum/species/slime_type as anything in typesof(/datum/species/jelly)) for (var/datum/species/slime_type as anything in typesof(/datum/species/jelly))
var/mob/living/carbon/human/slime = allocate(/mob/living/carbon/human/dummy/consistent) var/mob/living/carbon/human/slime = allocate(/mob/living/carbon/human/dummy/consistent)
slime.dna.features["mcolor"] = COLOR_PINK slime.dna.features[FEATURE_MUTANT_COLOR] = COLOR_PINK
slime.hairstyle = "Bob Hair 2" slime.hairstyle = "Bob Hair 2"
slime.hair_color = COLOR_RED // Should be forced to pink slime.hair_color = COLOR_RED // Should be forced to pink
slime.set_species(slime_type) slime.set_species(slime_type)

View File

@@ -7,7 +7,7 @@
var/mob/living/carbon/human/morphing_human = allocate(/mob/living/carbon/human/dummy/consistent) var/mob/living/carbon/human/morphing_human = allocate(/mob/living/carbon/human/dummy/consistent)
morphing_human.equipOutfit(/datum/outfit/job/assistant/consistent) morphing_human.equipOutfit(/datum/outfit/job/assistant/consistent)
morphing_human.dna.features["legs"] = DIGITIGRADE_LEGS //you WILL have digitigrade legs morphing_human.dna.features[FEATURE_LEGS] = DIGITIGRADE_LEGS //you WILL have digitigrade legs
var/obj/item/human_shoes = morphing_human.get_item_by_slot(ITEM_SLOT_FEET) var/obj/item/human_shoes = morphing_human.get_item_by_slot(ITEM_SLOT_FEET)
human_shoes.supports_variations_flags = NONE //do not fit lizards at all costs. human_shoes.supports_variations_flags = NONE //do not fit lizards at all costs.

View File

@@ -812,7 +812,6 @@
#include "code\datums\dash_weapon.dm" #include "code\datums\dash_weapon.dm"
#include "code\datums\datum.dm" #include "code\datums\datum.dm"
#include "code\datums\datumvars.dm" #include "code\datums\datumvars.dm"
#include "code\datums\dna.dm"
#include "code\datums\dog_fashion.dm" #include "code\datums\dog_fashion.dm"
#include "code\datums\drift_handler.dm" #include "code\datums\drift_handler.dm"
#include "code\datums\ductnet.dm" #include "code\datums\ductnet.dm"
@@ -1452,6 +1451,10 @@
#include "code\datums\diseases\floor_diseases\carpellosis.dm" #include "code\datums\diseases\floor_diseases\carpellosis.dm"
#include "code\datums\diseases\floor_diseases\gastritium.dm" #include "code\datums\diseases\floor_diseases\gastritium.dm"
#include "code\datums\diseases\floor_diseases\nebula_nausea.dm" #include "code\datums\diseases\floor_diseases\nebula_nausea.dm"
#include "code\datums\dna\dna.dm"
#include "code\datums\dna\dna_block.dm"
#include "code\datums\dna\blocks\dna_features_block.dm"
#include "code\datums\dna\blocks\dna_identity_block.dm"
#include "code\datums\elements\_element.dm" #include "code\datums\elements\_element.dm"
#include "code\datums\elements\ai_control_examine.dm" #include "code\datums\elements\ai_control_examine.dm"
#include "code\datums\elements\ai_flee_while_injured.dm" #include "code\datums\elements\ai_flee_while_injured.dm"