From 6927aab9f916734f998d807fb7f199922fcb868c Mon Sep 17 00:00:00 2001 From: Chubbygummibear <46236974+Chubbygummibear@users.noreply.github.com> Date: Wed, 13 Jul 2022 23:49:08 -0700 Subject: [PATCH 01/25] please let this work (#1) * ho * pod nerfed by a pod main * sugone * yea * yer * lotsa stuff * tgui is pain * i don't know * maybe? * god kill me * tailed * wait no i fixed it wrong, this should be better * SCOPE CREEP BABEEEEEEEEEE * sins * mother of all omlettes jack * is it over? * ethereal colors because idk * i think that's it until we find out what else i broke cl ass clean up debug messages last one probably * Revert "i think that's it until we find out what else i broke" This reverts commit 574b0e8b75c0a1f5b6361d225e33344eee6e9016. * last time with gusto * hhh * ho * pod nerfed by a pod main * yer * fix * Revert "fix" This reverts commit 979eddbaa8889a249cc9ff830109757af888e753. * Delete plantpeople.dm * Revert "Merge branch 'dna-blocks-but-like-good' of https://github.com/Chubbygummibear/Yogstation-TG into dna-blocks-but-like-good" This reverts commit 1756ff2be65686ea062193fc14ce1ed34ef1988f, reversing changes made to 05f88bee81b29e3e26140d0e9235d9f2784bbff1. * this shouldn't be in here * missed that * so many little things * please for the love of god work --- code/__DEFINES/DNA.dm | 27 ++ code/__HELPERS/dna.dm | 7 +- code/__HELPERS/mobs.dm | 22 +- code/__HELPERS/sanitize_values.dm | 54 ++- code/_globalvars/lists/flavor_misc.dm | 21 +- code/datums/components/forensics.dm | 2 +- code/datums/datacore.dm | 4 +- code/datums/diseases/retrovirus.dm | 22 +- code/datums/dna.dm | 349 ++++++++++++++---- code/datums/mutations/actions.dm | 2 +- code/datums/mutations/body.dm | 13 +- .../weather/weather_types/radiation_storm.dm | 7 +- code/game/machinery/cloning.dm | 4 +- code/game/machinery/computer/cloning.dm | 4 +- code/game/machinery/computer/dna_console.dm | 110 +++++- code/game/machinery/exp_cloner.dm | 6 +- code/game/objects/items/cosmetics.dm | 2 +- code/game/objects/items/dna_injector.dm | 19 +- code/game/objects/structures/mirror.dm | 23 +- code/modules/admin/create_mob.dm | 4 +- code/modules/admin/secrets.dm | 2 +- .../antagonists/abductor/equipment/gland.dm | 1 + .../antagonists/bloodsuckers/powers/veil.dm | 2 +- .../eldritch_cult/eldritch_transmutations.dm | 4 +- .../antagonists/wizard/equipment/artefact.dm | 2 +- code/modules/client/preferences.dm | 50 +-- code/modules/client/preferences_savefile.dm | 23 +- code/modules/detectivework/scanner.dm | 2 +- code/modules/events/disease_outbreak.dm | 2 +- code/modules/events/spacevine.dm | 4 +- code/modules/goals/station_goals/dna_vault.dm | 4 +- code/modules/mob/dead/observer/observer.dm | 4 +- code/modules/mob/living/carbon/human/human.dm | 2 +- .../mob/living/carbon/human/species.dm | 56 +-- .../carbon/human/species_types/eggpeople.dm | 2 +- .../carbon/human/species_types/ethereal.dm | 4 +- .../carbon/human/species_types/felinid.dm | 8 +- .../carbon/human/species_types/golems.dm | 44 +-- .../carbon/human/species_types/jellypeople.dm | 1 + .../human/species_types/lizardpeople.dm | 2 +- .../carbon/human/species_types/mushpeople.dm | 4 +- .../carbon/human/species_types/podpeople.dm | 7 +- .../carbon/human/species_types/polysmorphs.dm | 2 +- .../mob/living/carbon/human/update_icons.dm | 2 +- code/modules/mob/living/carbon/life.dm | 9 +- code/modules/mob/living/carbon/monkey/life.dm | 2 +- code/modules/projectiles/projectile/magic.dm | 5 +- .../chemistry/reagents/other_reagents.dm | 3 +- .../chemistry/reagents/toxin_reagents.dm | 7 +- .../crossbreeding/_status_effects.dm | 1 + .../research/xenobiology/xenobiology.dm | 1 + .../ruins/icemoonruin_code/hotsprings.dm | 1 + code/modules/surgery/bodyparts/_bodyparts.dm | 6 +- code/modules/surgery/bodyparts/head.dm | 10 +- code/modules/surgery/bodyparts/helpers.dm | 26 +- code/modules/surgery/organs/tails.dm | 47 ++- tgui/packages/tgui/interfaces/DnaConsole.js | 67 +++- .../guardian/abilities/major/predator.dm | 2 +- .../carbon/human/species_types/plantpeople.dm | 8 +- 59 files changed, 789 insertions(+), 342 deletions(-) diff --git a/code/__DEFINES/DNA.dm b/code/__DEFINES/DNA.dm index a3ed9e72d5e1..a67f371fa271 100644 --- a/code/__DEFINES/DNA.dm +++ b/code/__DEFINES/DNA.dm @@ -59,6 +59,7 @@ #define UI_CHANGED "ui changed" #define UE_CHANGED "ue changed" +#define UF_CHANGED "uf changed" #define CHAMELEON_MUTATION_DEFAULT_TRANSPARENCY 204 @@ -78,6 +79,11 @@ //DNA - Because fuck you and your magic numbers being all over the codebase. #define DNA_BLOCK_SIZE 3 +//this should be in a colors.dm define but we don't use that like tg does +#define DEFAULT_HEX_COLOR_LEN 6 + +#define DNA_BLOCK_SIZE_COLOR DEFAULT_HEX_COLOR_LEN + #define DNA_UNI_IDENTITY_BLOCKS 7 #define DNA_HAIR_COLOR_BLOCK 1 #define DNA_FACIAL_HAIR_COLOR_BLOCK 2 @@ -87,6 +93,27 @@ #define DNA_FACIAL_HAIR_STYLE_BLOCK 6 #define DNA_HAIR_STYLE_BLOCK 7 +#define DNA_FEATURE_BLOCKS 19 +#define DNA_MUTANT_COLOR_BLOCK 1 +#define DNA_ETHEREAL_COLOR_BLOCK 2 +#define DNA_LIZARD_MARKINGS_BLOCK 3 +#define DNA_LIZARD_TAIL_BLOCK 4 +#define DNA_SNOUT_BLOCK 5 +#define DNA_HORNS_BLOCK 6 +#define DNA_FRILLS_BLOCK 7 +#define DNA_SPINES_BLOCK 8 +#define DNA_HUMAN_TAIL_BLOCK 9 +#define DNA_EARS_BLOCK 10 +#define DNA_MOTH_WINGS_BLOCK 11 +#define DNA_MUSHROOM_CAPS_BLOCK 12 +#define DNA_POLY_TAIL_BLOCK 13 +#define DNA_POLY_TEETH_BLOCK 14 +#define DNA_POLY_DOME_BLOCK 15 +#define DNA_POLY_DORSAL_BLOCK 16 +#define DNA_ETHEREAL_MARK_BLOCK 17 +#define DNA_PLANT_HAIR_BLOCK 18 +#define DNA_PLANT_FLOWER_BLOCK 19 + #define DNA_SEQUENCE_LENGTH 4 #define DNA_MUTATION_BLOCKS 8 #define DNA_UNIQUE_ENZYMES_LEN 32 diff --git a/code/__HELPERS/dna.dm b/code/__HELPERS/dna.dm index 5ec66923ea54..0ec3e7ee8d49 100644 --- a/code/__HELPERS/dna.dm +++ b/code/__HELPERS/dna.dm @@ -10,4 +10,9 @@ #define GET_MUTATION_STABILIZER(A) ((A.stabilizer_coeff < 0) ? 1 : A.stabilizer_coeff) #define GET_MUTATION_SYNCHRONIZER(A) ((A.synchronizer_coeff < 0) ? 1 : A.synchronizer_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) \ No newline at end of file +#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. +#define GET_UF_BLOCK_LEN(blocknum) (GLOB.features_block_lengths["[blocknum]"] || DNA_BLOCK_SIZE) diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index a1adb0d3f60b..2c2781af4b13 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -4,21 +4,21 @@ /proc/random_eye_color() switch(pick(20;"brown",20;"hazel",20;"grey",15;"blue",15;"green",1;"amber",1;"albino")) if("brown") - return "630" + return "#663300" if("hazel") - return "542" + return "#554422" if("grey") - return pick("666","777","888","999","aaa","bbb","ccc") + return pick("#666666","#777777","#888888","#999999","#aaaaaa","#bbbbbb","#cccccc") if("blue") - return "36c" + return "#3366cc" if("green") - return "060" + return "#006600" if("amber") - return "fc0" + return "#ffcc00" if("albino") - return pick("c","d","e","f") + pick("0","1","2","3","4","5","6","7","8","9") + pick("0","1","2","3","4","5","6","7","8","9") + return "#" + pick("cc","dd","ee","ff") + pick("00","11","22","33","44","55","66","77","88","99") + pick("00","11","22","33","44","55","66","77","88","99") else - return "000" + return "#000000" /proc/random_underwear(gender) if(!GLOB.underwear_list.len) @@ -87,9 +87,9 @@ //For now we will always return none for tail_human and ears. this shit was unreadable if you do somethign like this make it at least readable return(list( - "mcolor" = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F"), + "mcolor" = "#[pick("7F","FF")][pick("7F","FF")][pick("7F","FF")]", "gradientstyle" = random_hair_gradient_style(10), - "gradientcolor" = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F"), + "gradientcolor" = "#[pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F")]", "ethcolor" = GLOB.color_list_ethereal[pick(GLOB.color_list_ethereal)], "tail_lizard" = pick(GLOB.tails_list_lizard), "tail_human" = "None", @@ -103,7 +103,7 @@ "legs" = "Normal Legs", "caps" = pick(GLOB.caps_list), "moth_wings" = pick(GLOB.moth_wings_list), - "tail_polysmorph" = "Polys", + "tail_polysmorph" = pick(GLOB.tails_list_polysmorph), "teeth" = pick(GLOB.teeth_list), "dome" = pick(GLOB.dome_list), "dorsal_tubes" = pick(GLOB.dorsal_tubes_list), diff --git a/code/__HELPERS/sanitize_values.dm b/code/__HELPERS/sanitize_values.dm index 783b0463caa3..97ce3664f7f8 100644 --- a/code/__HELPERS/sanitize_values.dm +++ b/code/__HELPERS/sanitize_values.dm @@ -6,17 +6,30 @@ return number return default +/proc/sanitize_float(number, min=0, max=1, accuracy=1, default=0) + if(isnum(number)) + number = round(number, accuracy) + if(min <= number && number <= max) + return number + return default + /proc/sanitize_text(text, default="") if(istext(text)) return text return default +/proc/sanitize_islist(value, default) + if(islist(value) && length(value)) + return value + if(default) + return default + /proc/sanitize_inlist(value, list/List, default) if(value in List) return value if(default) return default - if(List && List.len) + if(List?.len) return pick(List) @@ -38,7 +51,7 @@ return default return default -/proc/sanitize_hexcolor(color, desired_format=3, include_crunch=0, default) +/proc/sanitize_hexcolor(color, desired_format = DEFAULT_HEX_COLOR_LEN, include_crunch = TRUE, default) var/crunch = include_crunch ? "#" : "" if(!istext(color)) color = "" @@ -46,32 +59,39 @@ var/start = 1 + (text2ascii(color, 1) == 35) var/len = length(color) var/char = "" - // RRGGBB -> RGB but awful - var/convert_to_shorthand = desired_format == 3 && length_char(color) > 3 + // Used for conversion between RGBA hex formats. + var/format_input_ratio = "[desired_format]:[length_char(color)-(start-1)]" . = "" var/i = start while(i <= len) char = color[i] + i += length(char) switch(text2ascii(char)) - if(48 to 57) //numbers 0 to 9 + if(48 to 57) //numbers 0 to 9 + . += char + if(97 to 102) //letters a to f . += char - if(97 to 102) //letters a to f + if(65 to 70) //letters A to F + char = lowertext(char) . += char - if(65 to 70) //letters A to F - . += lowertext(char) else break - i += length(char) - if(convert_to_shorthand && i <= len) //skip next one - i += length(color[i]) - - if(length_char(.) != desired_format) - if(default) - return default - return crunch + repeat_string(desired_format, "0") + switch(format_input_ratio) + if("3:8", "4:8", "3:6", "4:6") //skip next one. RRGGBB(AA) -> RGB(A) + i += length(color[i]) + if("6:4", "6:3", "8:4", "8:3") //add current char again. RGB(A) -> RRGGBB(AA) + . += char - return crunch + . + if(length_char(.) == desired_format) + return crunch + . + switch(format_input_ratio) //add or remove alpha channel depending on desired format. + if("3:8", "3:4", "6:4") + return crunch + copytext(., 1, desired_format+1) + if("4:6", "4:3", "8:3") + return crunch + . + ((desired_format == 4) ? "f" : "ff") + else //not a supported hex color format. + return default ? default : crunch + repeat_string(desired_format, "0") /proc/sanitize_ooccolor(color) if(length(color) != length_char(color)) diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm index 21b43fc86081..c3c89640f770 100644 --- a/code/_globalvars/lists/flavor_misc.dm +++ b/code/_globalvars/lists/flavor_misc.dm @@ -44,7 +44,26 @@ GLOBAL_LIST_EMPTY(moth_wingsopen_list) GLOBAL_LIST_EMPTY(caps_list) GLOBAL_LIST_EMPTY(ethereal_mark_list) //ethereal face marks -GLOBAL_LIST_INIT(color_list_ethereal, list("F Class(Green)" = "97ee63", "F2 Class (Light Green)" = "00fa9a", "F3 Class (Dark Green)" = "37835b", "M Class (Red)" = "9c3030", "M1 Class (Purple)" = "ee82ee", "G Class (Yellow)" = "fbdf56", "O Class (Blue)" = "3399ff", "A Class (Cyan)" = "00ffff")) +GLOBAL_LIST_INIT(color_list_ethereal, list( + "F Class (Green)" = "#97ee63", + "F2 Class (Light Green)" = "#00fa9a", + "F3 Class (Dark Green)" = "#37835b", + "F4 Class (Faint Green)" = "#ddff99", + "M Class (Red)" = "#9c3030", + "M1 Class (Purple)" = "#ee82ee", + "M2 Class (Faint Red)" = "#ff4d4d", + "M3 Class (Light Pink)" = "#ffb3b3", + "M4 Class (Pink)" = "#ff99cc", + "G Class (Yellow)" = "#fbdf56", + "G1 Class (Bright Yellow)" = "#ffff99", + "O Class (Blue)" = "#3399ff", + "O1 Class (Dark Blue)" = "#6666ff", + "O2 Class (Faint Blue)" = "#b3d9ff", + "O3 Class (Dark Fuschia)" = "#cc0066", + "A Class (Cyan)" = "#00ffff", + "K Class (Orange)" = "#ffa64d", + "K1 Class (Burnt Orange)" = "#cc4400", + "White Dwarf" = "#f2f2f2",)) GLOBAL_LIST_EMPTY(pod_hair_list) //ethereal face marks GLOBAL_LIST_EMPTY(pod_flower_list) //ethereal face marks diff --git a/code/datums/components/forensics.dm b/code/datums/components/forensics.dm index 9cdca54d9c9b..1695f44237a2 100644 --- a/code/datums/components/forensics.dm +++ b/code/datums/components/forensics.dm @@ -90,7 +90,7 @@ if(!ignoregloves) H.gloves.add_fingerprint(H, TRUE) //ignoregloves = 1 to avoid infinite loop. return - var/full_print = md5(H.dna.uni_identity) + var/full_print = md5(H.dna.unique_identity) LAZYSET(fingerprints, full_print, full_print) return TRUE diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm index e67af876d9eb..3b22088beb81 100644 --- a/code/datums/datacore.dm +++ b/code/datums/datacore.dm @@ -326,7 +326,7 @@ G.fields["rank"] = assignment G.fields["age"] = H.age G.fields["species"] = H.dna.species.name - G.fields["fingerprint"] = md5(H.dna.uni_identity) + G.fields["fingerprint"] = md5(H.dna.unique_identity) G.fields["p_stat"] = "Active" G.fields["m_stat"] = "Stable" G.fields["gender"] = H.gender @@ -383,7 +383,7 @@ G.fields["gender"] = "Other" L.fields["blood_type"] = H.dna.blood_type L.fields["b_dna"] = H.dna.unique_enzymes - L.fields["identity"] = H.dna.uni_identity + L.fields["identity"] = H.dna.unique_identity L.fields["species"] = H.dna.species.type L.fields["features"] = H.dna.features L.fields["image"] = image diff --git a/code/datums/diseases/retrovirus.dm b/code/datums/diseases/retrovirus.dm index 81cb105cda5e..c54724705a37 100644 --- a/code/datums/diseases/retrovirus.dm +++ b/code/datums/diseases/retrovirus.dm @@ -66,10 +66,13 @@ to_chat(affected_mob, span_danger("Your entire body vibrates.")) if (prob(35)) - if(prob(50)) - scramble_dna(affected_mob, 1, 0, rand(15,45)) - else - scramble_dna(affected_mob, 0, 1, rand(15,45)) + switch(rand(1,3)) + if(1) + scramble_dna(affected_mob, 1, 0, 0, rand(15,45)) + if(2) + scramble_dna(affected_mob, 0, 1, 0, rand(15,45)) + if(3) + scramble_dna(affected_mob, 0, 0, 1, rand(15,45)) if(4) if(restcure) @@ -78,7 +81,10 @@ cure() return if (prob(60)) - if(prob(50)) - scramble_dna(affected_mob, 1, 0, rand(50,75)) - else - scramble_dna(affected_mob, 0, 1, rand(50,75)) \ No newline at end of file + switch(rand(1,3)) + if(1) + scramble_dna(affected_mob, 1, 0, 0, rand(50,75)) + if(2) + scramble_dna(affected_mob, 0, 1, 0, rand(50,75)) + if(3) + scramble_dna(affected_mob, 0, 0, 1, rand(50,75)) diff --git a/code/datums/dna.dm b/code/datums/dna.dm index f551fd96b61d..dbd3e4d94017 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -1,11 +1,62 @@ +/** + * 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_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. + * Commonly used by the datum/dna/set_uni_identity_block and datum/dna/get_uni_identity_block procs. + */ +GLOBAL_LIST_INIT(total_ui_len_by_block, populate_total_ui_len_by_block()) + +/proc/populate_total_ui_len_by_block() + . = list() + var/total_block_len = 1 + for(var/blocknumber in 1 to DNA_UNI_IDENTITY_BLOCKS) + . += total_block_len + total_block_len += GET_UI_BLOCK_LEN(blocknumber) + +///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()) + +/proc/populate_total_uf_len_by_block() + . = list() + var/total_block_len = 1 + for(var/blocknumber in 1 to DNA_FEATURE_BLOCKS) + . += total_block_len + total_block_len += GET_UF_BLOCK_LEN(blocknumber) + /////////////////////////// DNA DATUM /datum/dna + ///An md5 hash of the dna holder's real name var/unique_enzymes - var/uni_identity + ///Stores the hashed values of traits such as skin tones, hair style, and gender + var/unique_identity var/blood_type var/datum/species/species = new /datum/species/human //The type of mutant race the player is if applicable (i.e. potato-man) var/list/features = list("FFF") //first value is mutant color + ///Stores the hashed values of the person's non-human features + var/unique_features var/real_name //Stores the real name of the person who originally got this dna datum. Used primarely for changelings, var/list/mutations = list() //All mutations are from now on here var/list/temporary_mutations = list() //Temporary changes to the UE @@ -41,9 +92,10 @@ if(!istype(destination)) return destination.dna.unique_enzymes = unique_enzymes - destination.dna.uni_identity = uni_identity + destination.dna.unique_identity = unique_identity destination.dna.blood_type = blood_type destination.set_species(species.type, icon_update=0) + destination.dna.unique_features = unique_features destination.dna.features = features.Copy() destination.dna.real_name = real_name destination.dna.temporary_mutations = temporary_mutations.Copy() @@ -56,7 +108,8 @@ new_dna.unique_enzymes = unique_enzymes new_dna.mutation_index = mutation_index new_dna.default_mutation_genes = default_mutation_genes - new_dna.uni_identity = uni_identity + new_dna.unique_identity = unique_identity + new_dna.unique_features = unique_features new_dna.blood_type = blood_type new_dna.features = features.Copy() new_dna.species = new species.type @@ -90,7 +143,7 @@ if((HM.class in classes) && !(HM.mutadone_proof && mutadone)) force_lose(HM) -/datum/dna/proc/generate_uni_identity() +/datum/dna/proc/generate_unique_identity() . = "" var/list/L = new /list(DNA_UNI_IDENTITY_BLOCKS) @@ -106,20 +159,63 @@ if(!GLOB.hair_styles_list.len) init_sprite_accessory_subtypes(/datum/sprite_accessory/hair,GLOB.hair_styles_list, GLOB.hair_styles_male_list, GLOB.hair_styles_female_list) L[DNA_HAIR_STYLE_BLOCK] = construct_block(GLOB.hair_styles_list.Find(H.hair_style), GLOB.hair_styles_list.len) - L[DNA_HAIR_COLOR_BLOCK] = sanitize_hexcolor(H.hair_color) + L[DNA_HAIR_COLOR_BLOCK] = sanitize_hexcolor(H.hair_color, include_crunch = FALSE) if(!GLOB.facial_hair_styles_list.len) init_sprite_accessory_subtypes(/datum/sprite_accessory/facial_hair, GLOB.facial_hair_styles_list, GLOB.facial_hair_styles_male_list, GLOB.facial_hair_styles_female_list) L[DNA_FACIAL_HAIR_STYLE_BLOCK] = construct_block(GLOB.facial_hair_styles_list.Find(H.facial_hair_style), GLOB.facial_hair_styles_list.len) - L[DNA_FACIAL_HAIR_COLOR_BLOCK] = sanitize_hexcolor(H.facial_hair_color) + 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_BLOCK] = sanitize_hexcolor(H.eye_color) + L[DNA_EYE_COLOR_BLOCK] = sanitize_hexcolor(H.eye_color, include_crunch = FALSE) - for(var/i=1, i<=DNA_UNI_IDENTITY_BLOCKS, i++) - if(L[i]) - . += L[i] - else - . += random_string(DNA_BLOCK_SIZE,GLOB.hex_characters) - return . + 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() + . = "" + + var/list/L = new /list(DNA_FEATURE_BLOCKS) + + if(features["mcolor"]) + L[DNA_MUTANT_COLOR_BLOCK] = sanitize_hexcolor(features["mcolor"], include_crunch = FALSE) + if(features["ethcolor"]) + L[DNA_ETHEREAL_COLOR_BLOCK] = sanitize_hexcolor(features["ethcolor"], include_crunch = FALSE) + if(features["body_markings"]) + L[DNA_LIZARD_MARKINGS_BLOCK] = construct_block(GLOB.body_markings_list.Find(features["body_markings"]), GLOB.body_markings_list.len) + if(features["tail_lizard"]) + L[DNA_LIZARD_TAIL_BLOCK] = construct_block(GLOB.tails_list_lizard.Find(features["tail_lizard"]), GLOB.tails_list_lizard.len) + if(features["snout"]) + L[DNA_SNOUT_BLOCK] = construct_block(GLOB.snouts_list.Find(features["snout"]), GLOB.snouts_list.len) + if(features["horns"]) + L[DNA_HORNS_BLOCK] = construct_block(GLOB.horns_list.Find(features["horns"]), GLOB.horns_list.len) + if(features["frills"]) + L[DNA_FRILLS_BLOCK] = construct_block(GLOB.frills_list.Find(features["frills"]), GLOB.frills_list.len) + if(features["spines"]) + L[DNA_SPINES_BLOCK] = construct_block(GLOB.spines_list.Find(features["spines"]), GLOB.spines_list.len) + if(features["tail_human"]) + L[DNA_HUMAN_TAIL_BLOCK] = construct_block(GLOB.tails_list_human.Find(features["tail_human"]), GLOB.tails_list_human.len) + if(features["ears"]) + L[DNA_EARS_BLOCK] = construct_block(GLOB.ears_list.Find(features["ears"]), GLOB.ears_list.len) + if(features["moth_wings"] != "Burnt Off") + L[DNA_MOTH_WINGS_BLOCK] = construct_block(GLOB.moth_wings_list.Find(features["moth_wings"]), GLOB.moth_wings_list.len) + if(features["caps"]) + L[DNA_MUSHROOM_CAPS_BLOCK] = construct_block(GLOB.caps_list.Find(features["caps"]), GLOB.caps_list.len) + if(features["tail_polysmorph"]) + L[DNA_POLY_TAIL_BLOCK] = construct_block(GLOB.tails_list_polysmorph.Find(features["tail_polysmorph"]), GLOB.tails_list_polysmorph.len) + if(features["teeth"]) + L[DNA_POLY_TEETH_BLOCK] = construct_block(GLOB.teeth_list.Find(features["teeth"]), GLOB.teeth_list.len) + if(features["dome"]) + L[DNA_POLY_DOME_BLOCK] = construct_block(GLOB.dome_list.Find(features["dome"]), GLOB.dome_list.len) + if(features["dorsal_tubes"]) + L[DNA_POLY_DORSAL_BLOCK] = construct_block(GLOB.dorsal_tubes_list.Find(features["dorsal_tubes"]), GLOB.dorsal_tubes_list.len) + if(features["ethereal_mark"]) + L[DNA_ETHEREAL_MARK_BLOCK] = construct_block(GLOB.ethereal_mark_list.Find(features["ethereal_mark"]), GLOB.ethereal_mark_list.len) + if(features["pod_hair"]) + L[DNA_PLANT_HAIR_BLOCK] = construct_block(GLOB.pod_hair_list.Find(features["pod_hair"]), GLOB.pod_hair_list.len) + if(features["pod_flower"]) + L[DNA_PLANT_FLOWER_BLOCK] = construct_block(GLOB.pod_flower_list.Find(features["pod_flower"]), GLOB.pod_flower_list.len) + + for(var/blocknum in 1 to DNA_FEATURE_BLOCKS) + . += L[blocknum] || random_string(GET_UI_BLOCK_LEN(blocknum), GLOB.hex_characters) /datum/dna/proc/generate_dna_blocks() var/bonus @@ -163,8 +259,8 @@ if(active) return sequence while(difficulty) - var/randnum = rand(1, length_char(sequence)) - sequence = copytext_char(sequence, 1, randnum) + "X" + copytext_char(sequence, randnum + 1) + var/randnum = rand(1, length(sequence)) + sequence = copytext(sequence, 1, randnum) + "X" + copytext(sequence, randnum + 1) difficulty-- return sequence @@ -177,35 +273,90 @@ . += random_string(DNA_UNIQUE_ENZYMES_LEN, GLOB.hex_characters) 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. +/datum/dna/proc/set_uni_feature_block(blocknum, input) + 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]) : "" + unique_features = precesing_blocks + input + succeeding_blocks + /datum/dna/proc/update_ui_block(blocknumber) - if(!blocknumber || !ishuman(holder)) - return + if(!blocknumber) + CRASH("UI block index is null") + if(!ishuman(holder)) + CRASH("Non-human mobs shouldn't have DNA") var/mob/living/carbon/human/H = holder switch(blocknumber) if(DNA_HAIR_COLOR_BLOCK) - uni_identity = setblock(uni_identity, blocknumber, sanitize_hexcolor(H.hair_color)) + set_uni_identity_block(blocknumber, sanitize_hexcolor(H.hair_color, include_crunch = FALSE)) if(DNA_FACIAL_HAIR_COLOR_BLOCK) - uni_identity = setblock(uni_identity, blocknumber, sanitize_hexcolor(H.facial_hair_color)) + set_uni_identity_block(blocknumber, sanitize_hexcolor(H.facial_hair_color, include_crunch = FALSE)) if(DNA_SKIN_TONE_BLOCK) - uni_identity = setblock(uni_identity, blocknumber, construct_block(GLOB.skin_tones.Find(H.skin_tone), GLOB.skin_tones.len)) + set_uni_identity_block(blocknumber, construct_block(GLOB.skin_tones.Find(H.skin_tone), GLOB.skin_tones.len)) if(DNA_EYE_COLOR_BLOCK) - uni_identity = setblock(uni_identity, blocknumber, sanitize_hexcolor(H.eye_color)) - var/obj/item/organ/eyes/eyes = H.getorgan(/obj/item/organ/eyes) - if(eyes) - eyes.old_eye_color = sanitize_hexcolor(H.eye_color) - eyes.eye_color = sanitize_hexcolor(H.eye_color) + set_uni_identity_block(blocknumber, sanitize_hexcolor(H.eye_color, include_crunch = FALSE)) if(DNA_GENDER_BLOCK) switch(H.gender) if(MALE) - uni_identity = setblock(uni_identity, blocknumber, construct_block(G_MALE, 3)) + set_uni_identity_block(blocknumber, construct_block(G_MALE, 3)) if(FEMALE) - uni_identity = setblock(uni_identity, blocknumber, construct_block(G_FEMALE, 3)) + set_uni_identity_block(blocknumber, construct_block(G_FEMALE, 3)) else - uni_identity = setblock(uni_identity, blocknumber, construct_block(G_PLURAL, 3)) + set_uni_identity_block(blocknumber, construct_block(G_PLURAL, 3)) if(DNA_FACIAL_HAIR_STYLE_BLOCK) - uni_identity = setblock(uni_identity, blocknumber, construct_block(GLOB.facial_hair_styles_list.Find(H.facial_hair_style), GLOB.facial_hair_styles_list.len)) + set_uni_identity_block(blocknumber, construct_block(GLOB.facial_hair_styles_list.Find(H.facial_hair_style), GLOB.facial_hair_styles_list.len)) if(DNA_HAIR_STYLE_BLOCK) - uni_identity = setblock(uni_identity, blocknumber, construct_block(GLOB.hair_styles_list.Find(H.hair_style), GLOB.hair_styles_list.len)) + set_uni_identity_block(blocknumber, construct_block(GLOB.hair_styles_list.Find(H.hair_style), GLOB.hair_styles_list.len)) + +/datum/dna/proc/update_uf_block(blocknumber) + if(!blocknumber) + CRASH("UF block index is null") + if(!ishuman(holder)) + CRASH("Non-human mobs shouldn't have DNA") + switch(blocknumber) + if(DNA_MUTANT_COLOR_BLOCK) + 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(GLOB.body_markings_list.Find(features["body_markings"]), GLOB.body_markings_list.len)) + if(DNA_LIZARD_TAIL_BLOCK) + set_uni_feature_block(blocknumber, construct_block(GLOB.tails_list_lizard.Find(features["tail_lizard"]), GLOB.tails_list_lizard.len)) + if(DNA_SNOUT_BLOCK) + set_uni_feature_block(blocknumber, construct_block(GLOB.snouts_list.Find(features["snout"]), GLOB.snouts_list.len)) + if(DNA_HORNS_BLOCK) + set_uni_feature_block(blocknumber, construct_block(GLOB.horns_list.Find(features["horns"]), GLOB.horns_list.len)) + if(DNA_FRILLS_BLOCK) + set_uni_feature_block(blocknumber, construct_block(GLOB.frills_list.Find(features["frills"]), GLOB.frills_list.len)) + if(DNA_SPINES_BLOCK) + set_uni_feature_block(blocknumber, construct_block(GLOB.spines_list.Find(features["spines"]), GLOB.spines_list.len)) + if(DNA_HUMAN_TAIL_BLOCK) + set_uni_feature_block(blocknumber, construct_block(GLOB.tails_list_human.Find(features["tail_human"]), GLOB.tails_list_human.len)) + if(DNA_EARS_BLOCK) + set_uni_feature_block(blocknumber, construct_block(GLOB.ears_list.Find(features["ears"]), GLOB.ears_list.len)) + if(DNA_MOTH_WINGS_BLOCK) + set_uni_feature_block(blocknumber, construct_block(GLOB.moth_wings_list.Find(features["moth_wings"]), GLOB.moth_wings_list.len)) + if(DNA_MUSHROOM_CAPS_BLOCK) + set_uni_feature_block(blocknumber, construct_block(GLOB.caps_list.Find(features["caps"]), GLOB.caps_list.len)) + if(DNA_POLY_TAIL_BLOCK) + set_uni_feature_block(blocknumber, construct_block(GLOB.tails_list_polysmorph.Find(features["tail_polysmorph"]), GLOB.tails_list_polysmorph.len)) + if(DNA_POLY_TEETH_BLOCK) + set_uni_feature_block(blocknumber, construct_block(GLOB.teeth_list.Find(features["teeth"]), GLOB.teeth_list.len)) + if(DNA_POLY_DOME_BLOCK) + set_uni_feature_block(blocknumber, construct_block(GLOB.dome_list.Find(features["dome"]), GLOB.dome_list.len)) + if(DNA_POLY_DORSAL_BLOCK) + set_uni_feature_block(blocknumber, construct_block(GLOB.dorsal_tubes_list.Find(features["dorsal_tubes"]), GLOB.dorsal_tubes_list.len)) + if(DNA_ETHEREAL_MARK_BLOCK) + set_uni_feature_block(blocknumber, construct_block(GLOB.ethereal_mark_list.Find(features["ethereal_mark"]), GLOB.ethereal_mark_list.len)) + if(DNA_PLANT_HAIR_BLOCK) + set_uni_feature_block(blocknumber, construct_block(GLOB.pod_hair_list.Find(features["pod_hair"]), GLOB.pod_hair_list.len)) + if(DNA_PLANT_FLOWER_BLOCK) + set_uni_feature_block(blocknumber, construct_block(GLOB.pod_flower_list.Find(features["pod_flower"]), GLOB.pod_flower_list.len)) //Please use add_mutation or activate_mutation instead /datum/dna/proc/force_give(datum/mutation/human/HM) @@ -226,7 +377,7 @@ return /datum/dna/proc/is_same_as(datum/dna/D) - if(uni_identity == D.uni_identity && mutation_index == D.mutation_index && real_name == D.real_name) + if(unique_identity == D.unique_identity && mutation_index == D.mutation_index && real_name == D.real_name) if(species.type == D.species.type && features == D.features && blood_type == D.blood_type) return 1 return 0 @@ -259,17 +410,19 @@ //used to update dna UI, UE, and dna.real_name. /datum/dna/proc/update_dna_identity() - uni_identity = generate_uni_identity() + unique_identity = generate_unique_identity() unique_enzymes = generate_unique_enzymes() + unique_features = generate_unique_features() /datum/dna/proc/initialize_dna(newblood_type, skip_index = FALSE) if(newblood_type) blood_type = newblood_type unique_enzymes = generate_unique_enzymes() - uni_identity = generate_uni_identity() + unique_identity = generate_unique_identity() if(!skip_index) //I hate this generate_dna_blocks() features = random_features() + unique_features = generate_unique_features() /datum/dna/stored //subtype used by brain mob's stored_dna @@ -342,6 +495,7 @@ //Do not use force_transfer_mutations for stuff like cloners without some precautions, otherwise some conditional mutations could break (timers, drill hat etc) if(newfeatures) dna.features = newfeatures + dna.generate_unique_features() if(mrace) var/datum/species/newrace = new mrace.type @@ -356,7 +510,7 @@ dna.blood_type = newblood_type if(ui) - dna.uni_identity = ui + dna.unique_identity = ui updateappearance(icon_update=0) if(LAZYLEN(mutation_index)) @@ -390,7 +544,7 @@ if(!has_dna()) return - switch(deconstruct_block(getblock(dna.uni_identity, DNA_GENDER_BLOCK), 3)) + switch(deconstruct_block(get_uni_identity_block(dna.unique_identity, DNA_GENDER_BLOCK), 3)) if(G_MALE) gender = MALE if(G_FEMALE) @@ -400,15 +554,58 @@ /mob/living/carbon/human/updateappearance(icon_update=1, mutcolor_update=0, mutations_overlay_update=0) ..() - var/structure = dna.uni_identity - hair_color = sanitize_hexcolor(getblock(structure, DNA_HAIR_COLOR_BLOCK)) - facial_hair_color = sanitize_hexcolor(getblock(structure, DNA_FACIAL_HAIR_COLOR_BLOCK)) - skin_tone = GLOB.skin_tones[deconstruct_block(getblock(structure, DNA_SKIN_TONE_BLOCK), GLOB.skin_tones.len)] - eye_color = sanitize_hexcolor(getblock(structure, DNA_EYE_COLOR_BLOCK)) - facial_hair_style = GLOB.facial_hair_styles_list[deconstruct_block(getblock(structure, DNA_FACIAL_HAIR_STYLE_BLOCK), GLOB.facial_hair_styles_list.len)] - hair_style = GLOB.hair_styles_list[deconstruct_block(getblock(structure, DNA_HAIR_STYLE_BLOCK), GLOB.hair_styles_list.len)] + var/structure = dna.unique_identity + hair_color = sanitize_hexcolor(get_uni_identity_block(structure, DNA_HAIR_COLOR_BLOCK)) + facial_hair_color = sanitize_hexcolor(get_uni_identity_block(structure, DNA_FACIAL_HAIR_COLOR_BLOCK)) + skin_tone = GLOB.skin_tones[deconstruct_block(get_uni_identity_block(structure, DNA_SKIN_TONE_BLOCK), GLOB.skin_tones.len)] + eye_color = sanitize_hexcolor(get_uni_identity_block(structure, DNA_EYE_COLOR_BLOCK)) + facial_hair_style = GLOB.facial_hair_styles_list[deconstruct_block(get_uni_identity_block(structure, DNA_FACIAL_HAIR_STYLE_BLOCK), GLOB.facial_hair_styles_list.len)] + hair_style = GLOB.hair_styles_list[deconstruct_block(get_uni_identity_block(structure, DNA_HAIR_STYLE_BLOCK), GLOB.hair_styles_list.len)] + 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["body_markings"]) + dna.features["body_markings"] = GLOB.body_markings_list[deconstruct_block(get_uni_feature_block(features, DNA_LIZARD_MARKINGS_BLOCK), GLOB.body_markings_list.len)] + if(dna.features["tail_lizard"]) + dna.features["tail_lizard"] = GLOB.tails_list_lizard[deconstruct_block(get_uni_feature_block(features, DNA_LIZARD_TAIL_BLOCK), GLOB.tails_list_lizard.len)] + if(dna.features["snout"]) + dna.features["snout"] = GLOB.snouts_list[deconstruct_block(get_uni_feature_block(features, DNA_SNOUT_BLOCK), GLOB.snouts_list.len)] + if(dna.features["horns"]) + dna.features["horns"] = GLOB.horns_list[deconstruct_block(get_uni_feature_block(features, DNA_HORNS_BLOCK), GLOB.horns_list.len)] + if(dna.features["frills"]) + dna.features["frills"] = GLOB.frills_list[deconstruct_block(get_uni_feature_block(features, DNA_FRILLS_BLOCK), GLOB.frills_list.len)] + if(dna.features["spines"]) + dna.features["spines"] = GLOB.spines_list[deconstruct_block(get_uni_feature_block(features, DNA_SPINES_BLOCK), GLOB.spines_list.len)] + if(dna.features["tail_human"]) + dna.features["tail_human"] = GLOB.tails_list_human[deconstruct_block(get_uni_feature_block(features, DNA_HUMAN_TAIL_BLOCK), GLOB.tails_list_human.len)] + if(dna.features["ears"]) + dna.features["ears"] = GLOB.ears_list[deconstruct_block(get_uni_feature_block(features, DNA_EARS_BLOCK), GLOB.ears_list.len)] + if(dna.features["moth_wings"]) + var/genetic_value = GLOB.moth_wings_list[deconstruct_block(get_uni_feature_block(features, DNA_MOTH_WINGS_BLOCK), GLOB.moth_wings_list.len)] + dna.features["original_moth_wings"] = genetic_value + if(dna.features["moth_wings"] != "Burnt Off") + dna.features["moth_wings"] = genetic_value + if(dna.features["caps"]) + dna.features["caps"] = GLOB.caps_list[deconstruct_block(get_uni_feature_block(features, DNA_MUSHROOM_CAPS_BLOCK), GLOB.caps_list.len)] + // if(features["tail_polysmorph"]) + // dna.features["tail_polysmorph"] = GLOB.tails_list_polysmorph[deconstruct_block(get_uni_feature_block(features, DNA_POLY_TAIL_BLOCK), GLOB.tails_list_polysmorph.len)] + if(dna.features["teeth"]) + dna.features["teeth"] = GLOB.teeth_list[deconstruct_block(get_uni_feature_block(features, DNA_POLY_TEETH_BLOCK), GLOB.teeth_list.len)] + if(dna.features["dome"]) + dna.features["dome"] = GLOB.dome_list[deconstruct_block(get_uni_feature_block(features, DNA_POLY_DOME_BLOCK), GLOB.dome_list.len)] + if(dna.features["dorsal_tubes"]) + dna.features["dorsal_tubes"] = GLOB.dorsal_tubes_list[deconstruct_block(get_uni_feature_block(features, DNA_POLY_DORSAL_BLOCK), GLOB.dorsal_tubes_list.len)] + if(dna.features["ethereal_mark"]) + dna.features["ethereal_mark"] = GLOB.ethereal_mark_list[deconstruct_block(get_uni_feature_block(features, DNA_ETHEREAL_MARK_BLOCK), GLOB.ethereal_mark_list.len)] + if(dna.features["pod_hair"]) + dna.features["pod_hair"] = GLOB.pod_hair_list[deconstruct_block(get_uni_feature_block(features, DNA_PLANT_HAIR_BLOCK), GLOB.pod_hair_list.len)] + if(dna.features["pod_flower"]) + dna.features["pod_flower"] = GLOB.pod_flower_list[deconstruct_block(get_uni_feature_block(features, DNA_PLANT_FLOWER_BLOCK), GLOB.pod_flower_list.len)] + if(icon_update) - update_body() + dna.species.handle_body(src) // We want 'update_body_parts()' to be called only if mutcolor_update is TRUE, so no 'update_body()' here. update_hair() if(mutcolor_update) update_body_parts() @@ -476,22 +673,6 @@ /////////////////////////// DNA HELPER-PROCS ////////////////////////////// -/proc/getleftblocks(input,blocknumber,blocksize) - if(blocknumber > 1) - return copytext_char(input,1,((blocksize*blocknumber)-(blocksize-1))) - -/proc/getrightblocks(input,blocknumber,blocksize) - if(blocknumber < (length(input)/blocksize)) - return copytext_char(input,blocksize*blocknumber+1,length(input)+1) - -/proc/getblock(input, blocknumber, blocksize=DNA_BLOCK_SIZE) - return copytext_char(input, blocksize*(blocknumber-1)+1, (blocksize*blocknumber)+1) - -/proc/setblock(istring, blocknumber, replacement, blocksize=DNA_BLOCK_SIZE) - if(!istring || !blocknumber || !replacement || !blocksize) - return 0 - return getleftblocks(istring, blocknumber, blocksize) + replacement + getrightblocks(istring, blocknumber, blocksize) - /datum/dna/proc/mutation_in_sequence(mutation) if(!mutation) return @@ -503,15 +684,15 @@ return TRUE -/mob/living/carbon/proc/randmut(list/candidates, difficulty = 2) +/mob/living/carbon/proc/random_mutate(list/candidates, difficulty = 2) if(!has_dna()) - return + CRASH("[src] does not have DNA") var/mutation = pick(candidates) . = dna.add_mutation(mutation) -/mob/living/carbon/proc/easy_randmut(quality = POSITIVE + NEGATIVE + MINOR_NEGATIVE, scrambled = TRUE, sequence = TRUE, exclude_monkey = TRUE) +/mob/living/carbon/proc/easy_random_mutate(quality = POSITIVE + NEGATIVE + MINOR_NEGATIVE, scrambled = TRUE, sequence = TRUE, exclude_monkey = TRUE) if(!has_dna()) - return + CRASH("[src] does not have DNA") var/list/mutations = list() if(quality & POSITIVE) mutations += GLOB.good_mutations @@ -534,37 +715,47 @@ HM.scrambled = TRUE return TRUE -/mob/living/carbon/proc/randmuti() +/mob/living/carbon/proc/random_mutate_unique_identity() if(!has_dna()) - return + CRASH("[src] does not have DNA") var/num = rand(1, DNA_UNI_IDENTITY_BLOCKS) - var/newdna = setblock(dna.uni_identity, num, random_string(DNA_BLOCK_SIZE, GLOB.hex_characters)) - dna.uni_identity = newdna + dna.set_uni_feature_block(num, random_string(GET_UI_BLOCK_LEN(num), GLOB.hex_characters)) updateappearance(mutations_overlay_update=1) +/mob/living/carbon/proc/random_mutate_unique_features() + if(!has_dna()) + CRASH("[src] does not have DNA") + var/num = rand(1, DNA_FEATURE_BLOCKS) + dna.set_uni_feature_block(num, random_string(GET_UF_BLOCK_LEN(num), GLOB.hex_characters)) + updateappearance(mutcolor_update = TRUE, mutations_overlay_update = TRUE) + /mob/living/carbon/proc/clean_dna() if(!has_dna()) - return + CRASH("[src] does not have DNA") dna.remove_all_mutations() -/mob/living/carbon/proc/clean_randmut(list/candidates, difficulty = 2) +/mob/living/carbon/proc/clean_random_mutate(list/candidates, difficulty = 2) clean_dna() - randmut(candidates, difficulty) + random_mutate(candidates, difficulty) -/proc/scramble_dna(mob/living/carbon/M, ui=FALSE, se=FALSE, probability) +/proc/scramble_dna(mob/living/carbon/M, ui=FALSE, se=FALSE, uf=FALSE, probability) if(!M.has_dna()) - return 0 + CRASH("[M] does not have DNA") if(se) for(var/i=1, i<=DNA_MUTATION_BLOCKS, i++) if(prob(probability)) M.dna.generate_dna_blocks() M.domutcheck() if(ui) - for(var/i=1, i<=DNA_UNI_IDENTITY_BLOCKS, i++) + for(var/blocknum in 1 to DNA_UNI_IDENTITY_BLOCKS) if(prob(probability)) - M.dna.uni_identity = setblock(M.dna.uni_identity, i, random_string(DNA_BLOCK_SIZE, GLOB.hex_characters)) - M.updateappearance(mutations_overlay_update=1) - return 1 + M.dna.set_uni_feature_block(blocknum, random_string(GET_UI_BLOCK_LEN(blocknum), GLOB.hex_characters)) + if(uf) + for(var/blocknum in 1 to DNA_FEATURE_BLOCKS) + if(prob(probability)) + M.dna.set_uni_feature_block(blocknum, random_string(GET_UF_BLOCK_LEN(blocknum), GLOB.hex_characters)) + if(ui || uf) + M.updateappearance(mutcolor_update=uf, mutations_overlay_update=1) //value in range 1 to values. values must be greater than 0 //all arguments assumed to be positive integers @@ -583,6 +774,12 @@ value = values 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 /mob/living/carbon/human/proc/something_horrible(ignore_stability) diff --git a/code/datums/mutations/actions.dm b/code/datums/mutations/actions.dm index 4c0a1636a83a..df537367b3e7 100644 --- a/code/datums/mutations/actions.dm +++ b/code/datums/mutations/actions.dm @@ -54,7 +54,7 @@ possible = list() var/list/prints = sniffed.return_fingerprints() for(var/mob/living/carbon/C in GLOB.carbon_list) - if(prints[md5(C.dna.uni_identity)]) + if(prints[md5(C.dna.unique_identity)]) possible |= C if(!length(possible)) to_chat(user,span_warning("Despite your best efforts, there are no scents to be found on [sniffed]...")) diff --git a/code/datums/mutations/body.dm b/code/datums/mutations/body.dm index f8a4895721b8..915b93668527 100644 --- a/code/datums/mutations/body.dm +++ b/code/datums/mutations/body.dm @@ -36,12 +36,15 @@ to_chat(owner, text_gain_indication) var/mob/new_mob if(prob(95)) - if(prob(50)) - new_mob = owner.easy_randmut(NEGATIVE + MINOR_NEGATIVE) - else - new_mob = owner.randmuti() + switch(rand(1,3)) + if(1) + new_mob = owner.easy_random_mutate(NEGATIVE + MINOR_NEGATIVE) + if(2) + new_mob = owner.random_mutate_unique_identity() + if(3) + new_mob = owner.random_mutate_unique_features() else - new_mob = owner.easy_randmut(POSITIVE) + new_mob = owner.easy_random_mutate(POSITIVE) if(new_mob && ismob(new_mob)) owner = new_mob . = owner diff --git a/code/datums/weather/weather_types/radiation_storm.dm b/code/datums/weather/weather_types/radiation_storm.dm index 7e6284b5409c..90de74143284 100644 --- a/code/datums/weather/weather_types/radiation_storm.dm +++ b/code/datums/weather/weather_types/radiation_storm.dm @@ -36,12 +36,13 @@ var/mob/living/carbon/human/H = L if(H.dna && !HAS_TRAIT(H, TRAIT_GENELESS)) if(prob(max(0,100-resist))) - H.randmuti() + H.random_mutate_unique_identity() + H.random_mutate_unique_features() if(prob(50)) if(prob(90)) - H.easy_randmut(NEGATIVE+MINOR_NEGATIVE) + H.easy_random_mutate(NEGATIVE+MINOR_NEGATIVE) else - H.easy_randmut(POSITIVE) + H.easy_random_mutate(POSITIVE) H.domutcheck() L.rad_act(20) diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index 90fc5b0afe02..16dc6488d6bd 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -231,9 +231,9 @@ GLOBAL_VAR_INIT(clones, 0) var/list/unclean_mutations = (GLOB.not_good_mutations|GLOB.bad_mutations) H.dna.remove_mutation_group(unclean_mutations) if(efficiency > 5 && prob(20)) - H.easy_randmut(POSITIVE) + H.easy_random_mutate(POSITIVE) if(efficiency < 3 && prob(50)) - var/mob/M = H.easy_randmut(NEGATIVE+MINOR_NEGATIVE) + var/mob/M = H.easy_random_mutate(NEGATIVE+MINOR_NEGATIVE) if(ismob(M)) H = M if((AGENDER || MGENDER || FGENDER) in H.dna.species.species_traits) diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm index a7ad64fb772e..d0d273f272dd 100644 --- a/code/game/machinery/computer/cloning.dm +++ b/code/game/machinery/computer/cloning.dm @@ -580,7 +580,7 @@ R.fields["name"] = mob_occupant.real_name R.fields["id"] = copytext_char(md5(mob_occupant.real_name), 2, 6) R.fields["UE"] = dna.unique_enzymes - R.fields["UI"] = dna.uni_identity + R.fields["UI"] = dna.unique_identity R.fields["SE"] = dna.mutation_index R.fields["blood_type"] = dna.blood_type R.fields["features"] = dna.features @@ -616,7 +616,7 @@ var/datum/data/record/old_record = find_record("mindref", REF(mob_occupant.mind), records) if(body_only) old_record = find_record("UE", dna.unique_enzymes, records) //Body-only records cannot be identified by mind, so we use the DNA - if(old_record && ((old_record.fields["UI"] != dna.uni_identity) || (!old_record.fields["body_only"]))) //Never overwrite a mind-and-body record if it exists + if(old_record && ((old_record.fields["UI"] != dna.unique_identity) || (!old_record.fields["body_only"]))) //Never overwrite a mind-and-body record if it exists old_record = null if(old_record) records -= old_record diff --git a/code/game/machinery/computer/dna_console.dm b/code/game/machinery/computer/dna_console.dm index 2da37ff5174c..c613190d8fc7 100644 --- a/code/game/machinery/computer/dna_console.dm +++ b/code/game/machinery/computer/dna_console.dm @@ -34,6 +34,11 @@ /// Flag for the mutation ref search system. Search will include advanced injector mutations #define SEARCH_ADV_INJ 8 +#define ENZYME_COPY_BASE_COOLDOWN (60 SECONDS) + +#define RAD_PULSE_UNIQUE_IDENTITY "ui" +#define RAD_PULSE_UNIQUE_FEATURES "uf" + /obj/machinery/computer/scan_consolenew name = "DNA Console" desc = "Scan DNA." @@ -89,7 +94,11 @@ var/rad_pulse_index = 0 /// World time when the enzyme pulse should complete var/rad_pulse_timer = 0 - + /// Which dna string to edit with the pulse + var/rad_pulse_type + /// Cooldown for the genetic makeup transfer actions. + COOLDOWN_DECLARE(enzyme_copy_timer) + /// Used for setting tgui data - Whether the connected DNA Scanner is usable var/can_use_scanner = FALSE /// Used for setting tgui data - Whether the current DNA Scanner occupant is viable for genetic modification @@ -138,7 +147,7 @@ // This is for pulsing the UI element with radiation as part of genetic makeup // If rad_pulse_index > 0 then it means we're attempting a rad pulse - if((rad_pulse_index > 0) && (rad_pulse_timer <= world.time)) + if(((rad_pulse_index > 0) && (rad_pulse_timer <= world.time) && (rad_pulse_type == RAD_PULSE_UNIQUE_IDENTITY || rad_pulse_type == RAD_PULSE_UNIQUE_FEATURES))) rad_pulse() return @@ -289,7 +298,8 @@ data["subjectRads"] = scanner_occupant.radiation/(RAD_MOB_SAFE/100) data["subjectEnzymes"] = scanner_occupant.dna.unique_enzymes data["isMonkey"] = ismonkey(scanner_occupant) - data["subjectUNI"] = scanner_occupant.dna.uni_identity + data["subjectUNI"] = scanner_occupant.dna.unique_identity + data["subjectUF"] = scanner_occupant.dna.unique_features data["storage"]["occupant"] = tgui_occupant_mutations //data["subjectMutations"] = tgui_occupant_mutations else @@ -489,12 +499,12 @@ // X to allow highlighting logic to work on the tgui interface. if(newgene == "X") var/defaultseq = scanner_occupant.dna.default_mutation_genes[path] - defaultseq = copytext_char(defaultseq, 1, genepos) + newgene + copytext_char(defaultseq, genepos + 1) + defaultseq = copytext(defaultseq, 1, genepos) + newgene + copytext(defaultseq, genepos + 1) scanner_occupant.dna.default_mutation_genes[path] = defaultseq // Copy genome to scanner occupant and do some basic mutation checks as // we've increased the occupant rads - sequence = copytext_char(sequence, 1, genepos) + newgene + copytext_char(sequence, genepos + 1) + sequence = copytext(sequence, 1, genepos) + newgene + copytext(sequence, genepos + 1) scanner_occupant.dna.mutation_index[path] = sequence scanner_occupant.radiation += RADIATION_STRENGTH_MULTIPLIER/connected_scanner.damage_coeff scanner_occupant.domutcheck() @@ -1002,8 +1012,9 @@ // Set the new information genetic_makeup_buffer[buffer_index] = list( "label"="Slot [buffer_index]:[scanner_occupant.real_name]", - "UI"=scanner_occupant.dna.uni_identity, + "UI"=scanner_occupant.dna.unique_identity, "UE"=scanner_occupant.dna.unique_enzymes, + "UF"=scanner_occupant.dna.unique_features, "name"=scanner_occupant.real_name, "blood_type"=scanner_occupant.dna.blood_type) @@ -1050,6 +1061,7 @@ // Expected results: // "ue" - Unique Enzyme, changes name and blood type // "ui" - Unique Identity, changes looks + // "uf" - Unique Features, changes mutant bodyparts and mutcolors // "mixed" - Combination of both ue and ui if("makeup_injector") // Convert the index to a number and clamp within the array range, then @@ -1093,6 +1105,21 @@ I = new /obj/item/dnainjector/timed(loc) I.fields = list("name"=buffer_slot["name"], "UE"=buffer_slot["UE"], "blood_type"=buffer_slot["blood_type"]) + // If there is a connected scanner, we can use its upgrades to reduce + // the radiation generated by this injector + if(scanner_operational()) + I.damage_coeff = connected_scanner.damage_coeff + if("uf") + // GUARD CHECK - There's currently no way to save partial genetic data. + // However, if this is the case, we can't make a complete injector and + // this catches that edge case + if(!buffer_slot["name"] || !buffer_slot["UF"] || !buffer_slot["blood_type"]) + to_chat(usr,"Genetic data corrupted, unable to create injector.") + return + + I = new /obj/item/dnainjector/timed(loc) + I.fields = list("name"=buffer_slot["name"], "UF"=buffer_slot["UF"]) + // If there is a connected scanner, we can use its upgrades to reduce // the radiation generated by this injector if(scanner_operational()) @@ -1101,12 +1128,12 @@ // GUARD CHECK - There's currently no way to save partial genetic data. // However, if this is the case, we can't make a complete injector and // this catches that edge case - if(!buffer_slot["UI"] || !buffer_slot["name"] || !buffer_slot["UE"] || !buffer_slot["blood_type"]) + if(!buffer_slot["UI"] || !buffer_slot["name"] || !buffer_slot["UE"] || !buffer_slot["UF"] || !buffer_slot["blood_type"]) to_chat(usr,span_warning("Genetic data corrupted, unable to create injector.")) return I = new /obj/item/dnainjector/timed(loc) - I.fields = list("UI"=buffer_slot["UI"],"name"=buffer_slot["name"], "UE"=buffer_slot["UE"], "blood_type"=buffer_slot["blood_type"]) + I.fields = list("UI"=buffer_slot["UI"],"name"=buffer_slot["name"], "UE"=buffer_slot["UE"], "UF"=buffer_slot["UF"], "blood_type"=buffer_slot["blood_type"]) // If there is a connected scanner, we can use its upgrades to reduce // the radiation generated by this injector @@ -1129,6 +1156,7 @@ // Expected results: // "ue" - Unique Enzyme, changes name and blood type // "ui" - Unique Identity, changes looks + // "uf" - Unique Features, changes mutant bodyparts and mutcolors // "mixed" - Combination of both ue and ui if("makeup_apply") // GUARD CHECK - Can we genetically modify the occupant? Includes scanner @@ -1166,6 +1194,7 @@ // Expected results: // "ue" - Unique Enzyme, changes name and blood type // "ui" - Unique Identity, changes looks + // "uf" - Unique Features, changes mutant bodyparts and mutcolors // "mixed" - Combination of both ue and ui if("makeup_delay") // Convert the index to a number and clamp within the array range, then @@ -1189,6 +1218,10 @@ // Attempts to modify the indexed element of the Unique Identity string // This is a time delayed action that is handled in process() // ---------------------------------------------------------------------- // + // params["type"] - Type of genetic makeup string to edit + // Expected results: + // "ui" - Unique Identity, changes looks + // "uf" - Unique Features, changes mutant bodyparts and mutcolors // params["index"] - The BYOND index of the Unique Identity string to // attempt to modify if("makeup_pulse") @@ -1197,9 +1230,16 @@ if(!can_modify_occupant()) return - // Set the appropriate timer and index to pulse. This is then managed + // Set the appropriate timer, string, and index to pulse. This is then managed // later on in process() - var/len = length_char(scanner_occupant.dna.uni_identity) + var/type = params["type"] + rad_pulse_type = type + var/len + switch(type) + if("ui") + len = length(scanner_occupant.dna.unique_identity) + if("uf") + len = length(scanner_occupant.dna.unique_features) rad_pulse_timer = world.time + (radduration*10) rad_pulse_index = WRAP(text2num(params["index"]), 1, len+1) begin_processing() @@ -1424,11 +1464,24 @@ if(!buffer_slot["UI"]) to_chat(usr,span_warning("Genetic data corrupted, unable to apply genetic data.")) return FALSE - scanner_occupant.dna.uni_identity = buffer_slot["UI"] + scanner_occupant.dna.unique_identity = buffer_slot["UI"] scanner_occupant.updateappearance(mutations_overlay_update=1) scanner_occupant.radiation += rad_increase scanner_occupant.domutcheck() return TRUE + if("uf") + // GUARD CHECK - There's currently no way to save partial genetic data. + // However, if this is the case, we can't make a complete injector and + // this catches that edge case + if(!buffer_slot["UF"]) + to_chat(usr,"Genetic data corrupted, unable to apply genetic data.") + return FALSE + COOLDOWN_START(src, enzyme_copy_timer, ENZYME_COPY_BASE_COOLDOWN) + scanner_occupant.dna.unique_features = buffer_slot["UF"] + scanner_occupant.updateappearance(mutcolor_update=1, mutations_overlay_update=1) + scanner_occupant.radiation += rad_increase + scanner_occupant.domutcheck() + return TRUE if("ue") // GUARD CHECK - There's currently no way to save partial genetic data. // However, if this is the case, we can't make a complete injector and @@ -1436,6 +1489,7 @@ if(!buffer_slot["name"] || !buffer_slot["UE"] || !buffer_slot["blood_type"]) to_chat(usr,span_warning("Genetic data corrupted, unable to apply genetic data.")) return FALSE + COOLDOWN_START(src, enzyme_copy_timer, ENZYME_COPY_BASE_COOLDOWN) scanner_occupant.real_name = buffer_slot["name"] scanner_occupant.name = buffer_slot["name"] scanner_occupant.dna.unique_enzymes = buffer_slot["UE"] @@ -1447,11 +1501,13 @@ // GUARD CHECK - There's currently no way to save partial genetic data. // However, if this is the case, we can't make a complete injector and // this catches that edge case - if(!buffer_slot["UI"] || !buffer_slot["name"] || !buffer_slot["UE"] || !buffer_slot["blood_type"]) + if(!buffer_slot["UI"] || !buffer_slot["name"] || !buffer_slot["UE"] || !buffer_slot["UF"] || !buffer_slot["blood_type"]) to_chat(usr,span_warning("Genetic data corrupted, unable to apply genetic data.")) return FALSE - scanner_occupant.dna.uni_identity = buffer_slot["UI"] - scanner_occupant.updateappearance(mutations_overlay_update=1) + COOLDOWN_START(src, enzyme_copy_timer, ENZYME_COPY_BASE_COOLDOWN) + scanner_occupant.dna.unique_identity = buffer_slot["UI"] + scanner_occupant.dna.unique_features = buffer_slot["UF"] + scanner_occupant.updateappearance(mutcolor_update=1, mutations_overlay_update=1) scanner_occupant.real_name = buffer_slot["name"] scanner_occupant.name = buffer_slot["name"] scanner_occupant.dna.unique_enzymes = buffer_slot["UE"] @@ -1943,20 +1999,36 @@ // GUARD CHECK - Can we genetically modify the occupant? Includes scanner // operational guard checks. // If we can't, abort the procedure. - if(!can_modify_occupant()) + if(!can_modify_occupant()|| (rad_pulse_type != RAD_PULSE_UNIQUE_IDENTITY && rad_pulse_type != RAD_PULSE_UNIQUE_FEATURES)) rad_pulse_index = 0 end_processing() return - var/len = length_char(scanner_occupant.dna.uni_identity) + var/len + switch(rad_pulse_type) + if(RAD_PULSE_UNIQUE_IDENTITY) + len = length(scanner_occupant.dna.unique_identity) + if(RAD_PULSE_UNIQUE_FEATURES) + len = length(scanner_occupant.dna.unique_features) + var/num = randomize_radiation_accuracy(rad_pulse_index, radduration + (connected_scanner.precision_coeff ** 2), len) //Each manipulator level above 1 makes randomization as accurate as selected time + manipulator lvl^2 //Value is this high for the same reason as with laser - not worth the hassle of upgrading if the bonus is low - var/hex = copytext_char(scanner_occupant.dna.uni_identity, num, num+1) + var/hex + switch(rad_pulse_type) + if(RAD_PULSE_UNIQUE_IDENTITY) + hex = copytext(scanner_occupant.dna.unique_identity, num, num+1) + if(RAD_PULSE_UNIQUE_FEATURES) + hex = copytext(scanner_occupant.dna.unique_features, num, num+1) hex = scramble(hex, radstrength, radduration) - scanner_occupant.dna.uni_identity = copytext_char(scanner_occupant.dna.uni_identity, 1, num) + hex + copytext_char(scanner_occupant.dna.uni_identity, num + 1) - scanner_occupant.updateappearance(mutations_overlay_update=1) + switch(rad_pulse_type) + if(RAD_PULSE_UNIQUE_IDENTITY) + scanner_occupant.dna.unique_identity = copytext(scanner_occupant.dna.unique_identity, 1, num) + hex + copytext(scanner_occupant.dna.unique_identity, num + 1) + if(RAD_PULSE_UNIQUE_FEATURES) + scanner_occupant.dna.unique_features = copytext(scanner_occupant.dna.unique_features, 1, num) + hex + copytext(scanner_occupant.dna.unique_features, num + 1) + scanner_occupant.updateappearance(mutcolor_update=1, mutations_overlay_update=1) rad_pulse_index = 0 + rad_pulse_type = null end_processing() return diff --git a/code/game/machinery/exp_cloner.dm b/code/game/machinery/exp_cloner.dm index 416c43047ac2..4a83fcffc850 100644 --- a/code/game/machinery/exp_cloner.dm +++ b/code/game/machinery/exp_cloner.dm @@ -26,9 +26,9 @@ var/list/unclean_mutations = (GLOB.not_good_mutations|GLOB.bad_mutations) H.dna.remove_mutation_group(unclean_mutations) if(efficiency > 5 && prob(20)) - H.easy_randmut(POSITIVE) + H.easy_random_mutate(POSITIVE) if(efficiency < 3 && prob(50)) - var/mob/M = H.easy_randmut(NEGATIVE+MINOR_NEGATIVE) + var/mob/M = H.easy_random_mutate(NEGATIVE+MINOR_NEGATIVE) if(ismob(M)) H = M @@ -298,6 +298,6 @@ temp = "Cloning cycle already in progress." playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) else - pod.growclone(mob_occupant.real_name, dna.uni_identity, dna.mutation_index, null, null, clone_species, dna.features, mob_occupant.faction) + pod.growclone(mob_occupant.real_name, dna.unique_identity, dna.mutation_index, null, null, clone_species, dna.features, mob_occupant.faction) temp = "[mob_occupant.real_name] => Cloning data sent to pod." playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) diff --git a/code/game/objects/items/cosmetics.dm b/code/game/objects/items/cosmetics.dm index 5abcc9e2a30d..5e0ffa557ca4 100644 --- a/code/game/objects/items/cosmetics.dm +++ b/code/game/objects/items/cosmetics.dm @@ -259,7 +259,7 @@ if(!new_grad_style) return - var/new_grad_color = input(usr, "Choose a secondary hair color:", "Character Preference","#"+human_target.grad_color) as color|null + var/new_grad_color = input(usr, "Choose a secondary hair color:", "Character Preference",human_target.grad_color) as color|null if(!new_grad_color) return diff --git a/code/game/objects/items/dna_injector.dm b/code/game/objects/items/dna_injector.dm index d1f7fee482c6..662139521ebb 100644 --- a/code/game/objects/items/dna_injector.dm +++ b/code/game/objects/items/dna_injector.dm @@ -40,8 +40,11 @@ M.name = M.real_name M.dna.blood_type = fields["blood_type"] if(fields["UI"]) //UI+UE - M.dna.uni_identity = merge_text(M.dna.uni_identity, fields["UI"]) - M.updateappearance(mutations_overlay_update=1) + M.dna.unique_identity = merge_text(M.dna.unique_identity, fields["UI"]) + if(fields["UF"]) + M.dna.unique_features = merge_text(M.dna.unique_features, fields["UF"]) + if(fields["UI"] || fields["UF"]) + M.updateappearance(mutcolor_update=1, mutations_overlay_update=1) log_attack("[log_msg] [loc_name(user)]") return TRUE return FALSE @@ -503,10 +506,16 @@ M.dna.temporary_mutations[UE_CHANGED] = endtime if(fields["UI"]) //UI+UE if(!M.dna.previous["UI"]) - M.dna.previous["UI"] = M.dna.uni_identity - M.dna.uni_identity = merge_text(M.dna.uni_identity, fields["UI"]) - M.updateappearance(mutations_overlay_update=1) + M.dna.previous["UI"] = M.dna.unique_identity + M.dna.unique_identity = merge_text(M.dna.unique_identity, fields["UI"]) M.dna.temporary_mutations[UI_CHANGED] = endtime + if(fields["UF"]) //UI+UE + if(!M.dna.previous["UF"]) + M.dna.previous["UF"] = M.dna.unique_features + M.dna.unique_features = merge_text(M.dna.unique_features, fields["UF"]) + M.dna.temporary_mutations[UF_CHANGED] = endtime + if(fields["UI"] || fields["UF"]) + M.updateappearance(mutcolor_update=1, mutations_overlay_update=1) log_attack("[log_msg] [loc_name(user)]") return TRUE else diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index f7143171c420..f9c06f640130 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -173,15 +173,16 @@ H.dna.update_ui_block(DNA_SKIN_TONE_BLOCK) if((MUTCOLORS in H.dna.species.species_traits) && !(NOCOLORCHANGE in H.dna.species.species_traits)) - var/new_mutantcolor = input(user, "Choose your skin color:", "Race change","#"+H.dna.features["mcolor"]) as color|null - if(user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) - if(new_mutantcolor) - var/temp_hsv = RGBtoHSV(new_mutantcolor) - - if(ReadHSV(temp_hsv)[3] >= ReadHSV("#7F7F7F")[3]) // mutantcolors must be bright - H.dna.features["mcolor"] = sanitize_hexcolor(new_mutantcolor) + var/new_mutantcolor = input(user, "Choose your skin color:", "Race change", H.dna.features["mcolor"]) as color|null + if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) + return + if(new_mutantcolor) + var/temp_hsv = RGBtoHSV(new_mutantcolor) - else + if(ReadHSV(temp_hsv)[3] >= ReadHSV("#777777")[3]) // mutantcolors must be bright + H.dna.features["mcolor"] = sanitize_hexcolor(new_mutantcolor) + H.dna.update_uf_block(DNA_MUTANT_COLOR_BLOCK) + else to_chat(H, span_notice("Invalid color. Your color is not bright enough.")) H.update_body() @@ -220,21 +221,21 @@ if(hairchoice == "Style") //So you just want to use a mirror then? ..() else - var/new_hair_color = input(H, "Choose your hair color", "Hair Color","#"+H.hair_color) as color|null + var/new_hair_color = input(H, "Choose your hair color", "Hair Color",H.hair_color) as color|null if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) return if(new_hair_color) H.hair_color = sanitize_hexcolor(new_hair_color) H.dna.update_ui_block(DNA_HAIR_COLOR_BLOCK) if(H.gender == "male") - var/new_face_color = input(H, "Choose your facial hair color", "Hair Color","#"+H.facial_hair_color) as color|null + var/new_face_color = input(H, "Choose your facial hair color", "Hair Color",H.facial_hair_color) as color|null if(new_face_color) H.facial_hair_color = sanitize_hexcolor(new_face_color) H.dna.update_ui_block(DNA_FACIAL_HAIR_COLOR_BLOCK) H.update_hair() if(BODY_ZONE_PRECISE_EYES) - var/new_eye_color = input(H, "Choose your eye color", "Eye Color","#"+H.eye_color) as color|null + var/new_eye_color = input(H, "Choose your eye color", "Eye Color",H.eye_color) as color|null if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) return if(new_eye_color) diff --git a/code/modules/admin/create_mob.dm b/code/modules/admin/create_mob.dm index e497cb44f278..c3bb09e0b7f5 100644 --- a/code/modules/admin/create_mob.dm +++ b/code/modules/admin/create_mob.dm @@ -18,13 +18,13 @@ H.skin_tone = random_skin_tone() H.hair_style = random_hair_style(H.gender) H.facial_hair_style = random_facial_hair_style(H.gender) - H.hair_color = random_short_color() + H.hair_color = "#[random_color()]" H.facial_hair_color = H.hair_color H.eye_color = random_eye_color() H.dna.blood_type = random_blood_type() // Mutant randomizing, doesn't affect the mob appearance unless it's the specific mutant. - H.dna.features["mcolor"] = random_short_color() + H.dna.features["mcolor"] = "#[random_color()]" H.dna.features["ethcolor"] = GLOB.color_list_ethereal[pick(GLOB.color_list_ethereal)] H.dna.features["tail_lizard"] = pick(GLOB.tails_list_lizard) H.dna.features["tail_polysmorph"] = pick(GLOB.tails_list_polysmorph) diff --git a/code/modules/admin/secrets.dm b/code/modules/admin/secrets.dm index b1d5c03de041..81e6bf5a7abe 100644 --- a/code/modules/admin/secrets.dm +++ b/code/modules/admin/secrets.dm @@ -289,7 +289,7 @@ dat += "" for(var/mob/living/carbon/human/H in GLOB.carbon_list) if(H.ckey) - dat += "" + dat += "" dat += "
NameFingerprints
[H][md5(H.dna.uni_identity)]
[H][md5(H.dna.unique_identity)]
" usr << browse(dat, "window=fingerprints;size=440x410") diff --git a/code/modules/antagonists/abductor/equipment/gland.dm b/code/modules/antagonists/abductor/equipment/gland.dm index 33b2874df7a5..716c81ab6ed3 100644 --- a/code/modules/antagonists/abductor/equipment/gland.dm +++ b/code/modules/antagonists/abductor/equipment/gland.dm @@ -246,6 +246,7 @@ randomize_human(owner) var/species = pick(list(/datum/species/human, /datum/species/lizard, /datum/species/gorilla, /datum/species/moth, /datum/species/fly)) // yogs -- gorilla people owner.set_species(species) + owner.dna.update_dna_identity() /obj/item/organ/heart/gland/ventcrawling true_name = "pliant cartilage enabler" diff --git a/code/modules/antagonists/bloodsuckers/powers/veil.dm b/code/modules/antagonists/bloodsuckers/powers/veil.dm index 09538a1f7a41..372b044bf15f 100644 --- a/code/modules/antagonists/bloodsuckers/powers/veil.dm +++ b/code/modules/antagonists/bloodsuckers/powers/veil.dm @@ -67,7 +67,7 @@ user.skin_tone = random_skin_tone() user.hair_style = random_hair_style(user.gender) user.facial_hair_style = pick(random_facial_hair_style(user.gender), "Shaved") - user.hair_color = random_short_color() + user.hair_color = "#[random_color()]" user.facial_hair_color = user.hair_color user.underwear = random_underwear(user.gender) user.undershirt = random_undershirt(user.gender) diff --git a/code/modules/antagonists/eldritch_cult/eldritch_transmutations.dm b/code/modules/antagonists/eldritch_cult/eldritch_transmutations.dm index 5f88fa20c9d4..ca9c9af730b3 100644 --- a/code/modules/antagonists/eldritch_cult/eldritch_transmutations.dm +++ b/code/modules/antagonists/eldritch_cult/eldritch_transmutations.dm @@ -81,7 +81,7 @@ var/list/compiled_list = list() for(var/mob/living/carbon/human/H in GLOB.alive_mob_list) - if(fingerprints[md5(H.dna.uni_identity)]) + if(fingerprints[md5(H.dna.unique_identity)]) compiled_list |= H if(compiled_list.len == 0) @@ -217,4 +217,4 @@ name = "Codex Cicatrix" required_atoms = list(/obj/item/organ/eyes,/obj/item/stack/sheet/animalhide/human,/obj/item/storage/book/bible,/obj/item/pen) result_atoms = list(/obj/item/forbidden_book) - required_shit_list = "A bible, a sheet of human skin, a pen, and a pair of eyes." \ No newline at end of file + required_shit_list = "A bible, a sheet of human skin, a pen, and a pair of eyes." diff --git a/code/modules/antagonists/wizard/equipment/artefact.dm b/code/modules/antagonists/wizard/equipment/artefact.dm index 8bd1fa6b0ba9..ccd5162d5069 100644 --- a/code/modules/antagonists/wizard/equipment/artefact.dm +++ b/code/modules/antagonists/wizard/equipment/artefact.dm @@ -370,7 +370,7 @@ if(!length(prints)) return FALSE for(var/mob/living/carbon/human/H in GLOB.alive_mob_list) - if(prints[md5(H.dna.uni_identity)]) + if(prints[md5(H.dna.unique_identity)]) possible |= H /obj/item/voodoo/proc/GiveHint(mob/victim,force=0) diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 0e00fe379938..2d0aed69d9c7 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -66,13 +66,13 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/backbag = DBACKPACK //backpack type var/jumpsuit_style = PREF_SUIT //suit/skirt var/hair_style = "Bald" //Hair type - var/hair_color = "000" //Hair color + var/hair_color = "#000000" //Hair color var/facial_hair_style = "Shaved" //Face hair type - var/facial_hair_color = "000" //Facial hair color + var/facial_hair_color = "#000000" //Facial hair color var/skin_tone = "caucasian1" //Skin color - var/eye_color = "000" //Eye color + var/eye_color = "#000000" //Eye color var/datum/species/pref_species = new /datum/species/human() //Mutant race - var/list/features = list("mcolor" = "FFF", "gradientstyle" = "None", "gradientcolor" = "000", "ethcolor" = "9c3030", "tail_lizard" = "Smooth", "tail_human" = "None", "snout" = "Round", "horns" = "None", "ears" = "None", "wings" = "None", "frills" = "None", "spines" = "None", "body_markings" = "None", "legs" = "Normal Legs", "moth_wings" = "Plain", "tail_polysmorph" = "Polys", "teeth" = "None", "dome" = "None", "dorsal_tubes" = "No", "ethereal_mark" = "None", "pod_hair" = "Cabbage", "pod_flower" = "Cabbage") + var/list/features = list("mcolor" = "#FFFFFF", "gradientstyle" = "None", "gradientcolor" = "#000000", "ethcolor" = "#9c3030", "tail_lizard" = "Smooth", "tail_human" = "None", "snout" = "Round", "horns" = "None", "ears" = "None", "wings" = "None", "frills" = "None", "spines" = "None", "body_markings" = "None", "legs" = "Normal Legs", "moth_wings" = "Plain", "tail_polysmorph" = "Polys", "teeth" = "None", "dome" = "None", "dorsal_tubes" = "No", "ethereal_mark" = "None", "pod_hair" = "Cabbage", "pod_flower" = "Cabbage") var/list/genders = list(MALE, FEMALE, PLURAL) var/list/friendlyGenders = list("Male" = "male", "Female" = "female", "Other" = "plural") @@ -317,7 +317,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "

Mutant Color

" - dat += "   " + dat += "   " dat += "Change [random_locks["mcolor"] ? "Unlock" : "Lock"]
" mutant_colors = TRUE @@ -329,7 +329,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "

Ethereal Color

" - dat += "   " + dat += "   " dat += "Change [random_locks["ethcolor"] ? "Unlock" : "Lock"]
" @@ -340,7 +340,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "

Eye Color

" - dat += "   " + dat += "   " dat += "Change [random_locks["eyes"] ? "Unlock" : "Lock"]
" dat += "" @@ -358,7 +358,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "< >
" - dat += "    Change" + dat += "    Change" dat += "[random_locks["hair"] ? "Unlock" : "Lock"]
" dat += "

Facial Hair Style

" @@ -368,7 +368,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "< >
" - dat += "    Change" + dat += "    Change" dat += "[random_locks["facial"] ? "Unlock" : "Lock"]
" dat += "

Hair Gradient

" @@ -378,7 +378,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "< >
" - dat += "    Change" + dat += "    Change" dat += "[random_locks["gradientcolor"] ? "Unlock" : "Lock"]
" dat += "" @@ -575,7 +575,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "

Head Vegitation Style

" dat += "[features["pod_hair"]]" dat += "[random_locks["pod_hair"] ? "Unlock" : "Lock"]
" - dat += "    Change" + dat += "    Change" dat += "[random_locks["hair"] ? "Unlock" : "Lock"]
" mutant_category++ @@ -587,7 +587,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(!mutant_category) dat += APPEARANCE_CATEGORY_COLUMN dat += "

Head Flowers Color

" - dat += "    Change" + dat += "    Change" dat += "[random_locks["facial"] ? "Unlock" : "Lock"]
" mutant_category++ @@ -1388,11 +1388,11 @@ GLOBAL_LIST_EMPTY(preferences_datums) if("age") age = rand(AGE_MIN, AGE_MAX) if("hair") - hair_color = random_short_color() + hair_color = "#[random_color()]" if("hair_style") hair_style = random_hair_style(gender) if("facial") - facial_hair_color = random_short_color() + facial_hair_color = "#[random_color()]" if("facial_hair_style") facial_hair_style = random_facial_hair_style(gender) if("underwear") @@ -1495,7 +1495,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) age = max(min( round(text2num(new_age)), AGE_MAX),AGE_MIN) if("hair") - var/new_hair = input(user, "Choose your character's hair colour:", "Character Preference","#"+hair_color) as color|null + var/new_hair = input(user, "Choose your character's hair colour:", "Character Preference",hair_color) as color|null if(new_hair) hair_color = sanitize_hexcolor(new_hair) @@ -1527,7 +1527,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) hair_style = previous_list_item(hair_style, GLOB.hair_styles_list) if("facial") - var/new_facial = input(user, "Choose your character's facial-hair colour:", "Character Preference","#"+facial_hair_color) as color|null + var/new_facial = input(user, "Choose your character's facial-hair colour:", "Character Preference",facial_hair_color) as color|null if(new_facial) facial_hair_color = sanitize_hexcolor(new_facial) @@ -1559,7 +1559,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) facial_hair_style = previous_list_item(facial_hair_style, GLOB.facial_hair_styles_list) if("hair_gradient") - var/new_hair_gradient_color = input(user, "Choose your character's hair gradient colour:", "Character Preference","#"+features["gradientcolor"]) as color|null + var/new_hair_gradient_color = input(user, "Choose your character's hair gradient colour:", "Character Preference",features["gradientcolor"]) as color|null if(new_hair_gradient_color) features["gradientcolor"] = sanitize_hexcolor(new_hair_gradient_color) @@ -1604,7 +1604,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) socks = new_socks if(BODY_ZONE_PRECISE_EYES) - var/new_eyes = input(user, "Choose your character's eye colour:", "Character Preference","#"+eye_color) as color|null + var/new_eyes = input(user, "Choose your character's eye colour:", "Character Preference",eye_color) as color|null if(new_eyes) eye_color = sanitize_hexcolor(new_eyes) @@ -1617,16 +1617,16 @@ GLOBAL_LIST_EMPTY(preferences_datums) pref_species = new newtype() //Now that we changed our species, we must verify that the mutant colour is still allowed. var/temp_hsv = RGBtoHSV(features["mcolor"]) - if(features["mcolor"] == "#000" || (!(MUTCOLORS_PARTSONLY in pref_species.species_traits) && ReadHSV(temp_hsv)[3] < ReadHSV("#7F7F7F")[3])) + if(features["mcolor"] == "#000" || (!(MUTCOLORS_PARTSONLY in pref_species.species_traits) && ReadHSV(temp_hsv)[3] < ReadHSV("#777777")[3])) features["mcolor"] = pref_species.default_color if("mcolor") - var/new_mutantcolor = input(user, "Choose your character's alien/mutant color:", "Character Preference","#"+features["mcolor"]) as color|null + var/new_mutantcolor = input(user, "Choose your character's alien/mutant color:", "Character Preference",features["mcolor"]) as color|null if(new_mutantcolor) var/temp_hsv = RGBtoHSV(new_mutantcolor) if(new_mutantcolor == "#000000") features["mcolor"] = pref_species.default_color - else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#7F7F7F")[3]) // mutantcolors must be bright, but only if they affect the skin + else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#777777")[3]) // mutantcolors must be bright, but only if they affect the skin features["mcolor"] = sanitize_hexcolor(new_mutantcolor) else to_chat(user, span_danger("Invalid color. Your color is not bright enough.")) @@ -1739,24 +1739,24 @@ GLOBAL_LIST_EMPTY(preferences_datums) features["pod_hair"] = new_pod_hair features["pod_flower"] = new_pod_hair if("pod_hair_color") - var/new_hair = input(user, "Choose your character's \"hair\" colour:", "Character Preference","#"+hair_color) as color|null + var/new_hair = input(user, "Choose your character's \"hair\" colour:", "Character Preference",hair_color) as color|null if(new_hair) var/temp_hsv = RGBtoHSV(new_hair) if(new_hair == "#000000") hair_color = pref_species.default_color to_chat(user, span_danger("Invalid \"hair\" color. Your color is not bright enough.")) - else if(ReadHSV(temp_hsv)[3] >= ReadHSV("#7F7F7F")[3]) // mutantcolors must be bright, but only if they affect the skin + else if(ReadHSV(temp_hsv)[3] >= ReadHSV("#777777")[3]) // mutantcolors must be bright, but only if they affect the skin hair_color = sanitize_hexcolor(new_hair) else to_chat(user, span_danger("Invalid \"hair\" color. Your color is not bright enough.")) if("pod_flower_color") - var/new_facial = input(user, "Choose your character's head flower colour:", "Character Preference","#"+facial_hair_color) as color|null + var/new_facial = input(user, "Choose your character's head flower colour:", "Character Preference",facial_hair_color) as color|null if(new_facial) var/temp_hsv = RGBtoHSV(new_facial) if(new_facial == "#000000") facial_hair_color = pref_species.default_color to_chat(user, span_danger("Invalid \"hair\" color. Your color is not bright enough.")) - else if(ReadHSV(temp_hsv)[3] >= ReadHSV("#7F7F7F")[3]) // mutantcolors must be bright, but only if they affect the skin + else if(ReadHSV(temp_hsv)[3] >= ReadHSV("#777777")[3]) // mutantcolors must be bright, but only if they affect the skin facial_hair_color = sanitize_hexcolor(new_facial) else to_chat(user, span_danger("Invalid head flower color. Your color is not bright enough.")) diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 05fc4a1d845b..cad4800310e9 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -59,7 +59,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car if(current_version < 20) pda_color = "#808000" if((current_version < 21) && features["ethcolor"] && (features["ethcolor"] == "#9c3030")) - features["ethcolor"] = "9c3030" + features["ethcolor"] = "#9c3030" if(current_version < 22) job_preferences = list() //It loaded null from nonexistant savefile field. var/job_civilian_high = 0 @@ -241,8 +241,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car update_preferences(needs_update, S) //needs_update = savefile_version if we need an update (positive integer) //Sanitize - asaycolor = sanitize_ooccolor(sanitize_hexcolor(asaycolor, 6, 1, initial(asaycolor))) - ooccolor = sanitize_ooccolor(sanitize_hexcolor(ooccolor, 6, 1, initial(ooccolor))) + asaycolor = sanitize_ooccolor(sanitize_hexcolor(asaycolor, DEFAULT_HEX_COLOR_LEN, FALSE, initial(asaycolor))) + ooccolor = sanitize_ooccolor(sanitize_hexcolor(ooccolor, DEFAULT_HEX_COLOR_LEN, FALSE, initial(ooccolor))) lastchangelog = sanitize_text(lastchangelog, initial(lastchangelog)) UI_style = sanitize_inlist(UI_style, GLOB.available_ui_styles, GLOB.available_ui_styles[1]) hotkeys = sanitize_integer(hotkeys, FALSE, TRUE, initial(hotkeys)) @@ -270,7 +270,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car menuoptions = SANITIZE_LIST(menuoptions) be_special = SANITIZE_LIST(be_special) pda_style = sanitize_inlist(pda_style, GLOB.pda_styles, initial(pda_style)) - pda_color = sanitize_hexcolor(pda_color, 6, 1, initial(pda_color)) + pda_color = sanitize_hexcolor(pda_color, DEFAULT_HEX_COLOR_LEN, FALSE, initial(pda_color)) skillcape = sanitize_integer(skillcape, 1, 82, initial(skillcape)) skillcape_id = sanitize_text(skillcape_id, initial(skillcape_id)) @@ -498,7 +498,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car custom_names[custom_name_id] = get_default_name(custom_name_id) if(!features["mcolor"] || features["mcolor"] == "#000") - features["mcolor"] = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F") + + features["mcolor"] = "#[pick("7F","FF")][pick("7F","FF")][pick("7F","FF")]" if(!features["ethcolor"] || features["ethcolor"] == "#000") features["ethcolor"] = GLOB.color_list_ethereal[pick(GLOB.color_list_ethereal)] @@ -525,17 +526,17 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car socks = sanitize_inlist(socks, GLOB.socks_list) age = sanitize_integer(age, AGE_MIN, AGE_MAX, initial(age)) - hair_color = sanitize_hexcolor(hair_color, 3, 0) - facial_hair_color = sanitize_hexcolor(facial_hair_color, 3, 0) - eye_color = sanitize_hexcolor(eye_color, 3, 0) + hair_color = sanitize_hexcolor(hair_color, default = FALSE) + facial_hair_color = sanitize_hexcolor(facial_hair_color, default = FALSE) + eye_color = sanitize_hexcolor(eye_color, default = FALSE) skin_tone = sanitize_inlist(skin_tone, GLOB.skin_tones) backbag = sanitize_inlist(backbag, GLOB.backbaglist, initial(backbag)) jumpsuit_style = sanitize_inlist(jumpsuit_style, GLOB.jumpsuitlist, initial(jumpsuit_style)) uplink_spawn_loc = sanitize_inlist(uplink_spawn_loc, GLOB.uplink_spawn_loc_list, initial(uplink_spawn_loc)) - features["mcolor"] = sanitize_hexcolor(features["mcolor"], 3, 0) + features["mcolor"] = sanitize_hexcolor(features["mcolor"], default = FALSE) features["gradientstyle"] = sanitize_inlist(features["gradientstyle"], GLOB.hair_gradients_list) - features["gradientcolor"] = sanitize_hexcolor(features["gradientcolor"], 3, 0) - features["ethcolor"] = copytext_char(features["ethcolor"], 1, 7) + features["gradientcolor"] = sanitize_hexcolor(features["gradientcolor"], default = FALSE) + features["ethcolor"] = sanitize_hexcolor(sanitize_inlist(features["ethcolor"], GLOB.color_list_ethereal), include_crunch = FALSE,default = FALSE) features["tail_lizard"] = sanitize_inlist(features["tail_lizard"], GLOB.tails_list_lizard) features["tail_polysmorph"] = sanitize_inlist(features["tail_polysmorph"], GLOB.tails_list_polysmorph) features["tail_human"] = sanitize_inlist(features["tail_human"], GLOB.tails_list_human, "None") diff --git a/code/modules/detectivework/scanner.dm b/code/modules/detectivework/scanner.dm index 91c2b5a518ff..d3812dd5eabf 100644 --- a/code/modules/detectivework/scanner.dm +++ b/code/modules/detectivework/scanner.dm @@ -182,7 +182,7 @@ var/mob/living/carbon/human/H = A if(!H.gloves) - fingerprints += md5(H.dna.uni_identity) + fingerprints += md5(H.dna.unique_identity) else if(!ismob(A)) diff --git a/code/modules/events/disease_outbreak.dm b/code/modules/events/disease_outbreak.dm index ed31a3960fd5..036f976759cc 100644 --- a/code/modules/events/disease_outbreak.dm +++ b/code/modules/events/disease_outbreak.dm @@ -56,7 +56,7 @@ D = new virus_type() var/datum/disease/dnaspread/DS = D DS.strain_data["name"] = H.real_name - DS.strain_data["UI"] = H.dna.uni_identity + DS.strain_data["UI"] = H.dna.unique_identity DS.strain_data["SE"] = H.dna.mutation_index else D = new virus_type() diff --git a/code/modules/events/spacevine.dm b/code/modules/events/spacevine.dm index d11482e09675..8edff6de8150 100644 --- a/code/modules/events/spacevine.dm +++ b/code/modules/events/spacevine.dm @@ -421,8 +421,8 @@ var/parentcolor = parent.atom_colours[FIXED_COLOUR_PRIORITY] SV.add_atom_colour(parentcolor, FIXED_COLOUR_PRIORITY) if(prob(mutativeness)) - var/datum/spacevine_mutation/randmut = pick(vine_mutations_list - SV.mutations) - randmut.add_mutation_to_vinepiece(SV) + var/datum/spacevine_mutation/random_mutate = pick(vine_mutations_list - SV.mutations) + random_mutate.add_mutation_to_vinepiece(SV) for(var/datum/spacevine_mutation/SM in SV.mutations) SM.on_birth(SV) diff --git a/code/modules/goals/station_goals/dna_vault.dm b/code/modules/goals/station_goals/dna_vault.dm index bf8e7063909e..b7399f8d4a4e 100644 --- a/code/modules/goals/station_goals/dna_vault.dm +++ b/code/modules/goals/station_goals/dna_vault.dm @@ -112,10 +112,10 @@ //humans if(ishuman(target)) var/mob/living/carbon/human/H = target - if(dna[H.dna.uni_identity]) + if(dna[H.dna.unique_identity]) to_chat(user, span_notice("Humanoid data already present in local storage.")) return - dna[H.dna.uni_identity] = 1 + dna[H.dna.unique_identity] = 1 to_chat(user, span_notice("Humanoid data added to local storage.")) /obj/machinery/dna_vault diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 231877ebb78f..c59939ed07dc 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -214,7 +214,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) if(S) facial_hair_overlay = mutable_appearance(S.icon, "[S.icon_state]", -HAIR_LAYER) if(facial_hair_color) - facial_hair_overlay.color = "#" + facial_hair_color + facial_hair_overlay.color = facial_hair_color facial_hair_overlay.alpha = 200 add_overlay(facial_hair_overlay) if(hair_style) @@ -222,7 +222,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) if(S) hair_overlay = mutable_appearance(S.icon, "[S.icon_state]", -HAIR_LAYER) if(hair_color) - hair_overlay.color = "#" + hair_color + hair_overlay.color = hair_color hair_overlay.alpha = 200 add_overlay(hair_overlay) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 85fc9056735c..d631e07716f7 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -100,7 +100,7 @@ . += "Energy Charge: [round(SN.cell.charge/100)]%" . += "Smoke Bombs: \Roman [SN.s_bombs]" //Ninja status - . += "Fingerprints: [md5(dna.uni_identity)]" + . += "Fingerprints: [md5(dna.unique_identity)]" . += "Unique Identity: [dna.unique_enzymes]" . += "Overall Status: [stat > 1 ? "dead" : "[health]% healthy"]" . += "Nutrition Status: [nutrition]" diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index f7a3b4865315..66810fa82c42 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -307,7 +307,7 @@ GLOBAL_LIST_EMPTY(mentor_races) tail.Remove(C,1) QDEL_NULL(tail) if(should_have_tail && !tail) - tail = new mutanttail() + tail = new mutanttail if(iscatperson(C)) tail.tail_type = C.dna.features["tail_human"] if(ispolysmorph(C)) @@ -513,13 +513,13 @@ GLOBAL_LIST_EMPTY(mentor_races) if(!forced_colour) if(hair_color) if(hair_color == "mutcolor") - facial_overlay.color = "#" + H.dna.features["mcolor"] + facial_overlay.color = H.dna.features["mcolor"] else if(hair_color == "fixedmutcolor") - facial_overlay.color = "#[fixed_mut_color]" + facial_overlay.color = fixed_mut_color else - facial_overlay.color = "#" + hair_color + facial_overlay.color = hair_color else - facial_overlay.color = "#" + H.facial_hair_color + facial_overlay.color = H.facial_hair_color else facial_overlay.color = forced_colour @@ -576,13 +576,13 @@ GLOBAL_LIST_EMPTY(mentor_races) if(!forced_colour) if(hair_color) if(hair_color == "mutcolor") - hair_overlay.color = "#" + H.dna.features["mcolor"] + hair_overlay.color = H.dna.features["mcolor"] else if(hair_color == "fixedmutcolor") - hair_overlay.color = "#[fixed_mut_color]" + hair_overlay.color = fixed_mut_color else - hair_overlay.color = "#" + hair_color + hair_overlay.color = hair_color else - hair_overlay.color = "#" + H.hair_color + hair_overlay.color = H.hair_color //Gradients grad_style = H.grad_style @@ -593,7 +593,7 @@ GLOBAL_LIST_EMPTY(mentor_races) var/icon/temp_hair = icon(hair_file, hair_state) temp.Blend(temp_hair, ICON_ADD) gradient_overlay.icon = temp - gradient_overlay.color = "#" + grad_color + gradient_overlay.color = grad_color else hair_overlay.color = forced_colour @@ -615,7 +615,7 @@ GLOBAL_LIST_EMPTY(mentor_races) //if you're working with sprite code i hope this helps because i wish i was dead now. S = GLOB.pod_hair_list[H.dna.features["pod_hair"]] if(S) - if(ReadHSV(RGBtoHSV(H.hair_color))[3] <= ReadHSV("#7F7F7F")[3]) + if(ReadHSV(RGBtoHSV(H.hair_color))[3] <= ReadHSV("#777777")[3]) H.hair_color = H.dna.species.default_color var/hair_state = S.icon_state var/hair_file = S.icon @@ -624,13 +624,13 @@ GLOBAL_LIST_EMPTY(mentor_races) if(!forced_colour) if(hair_color) if(hair_color == "mutcolor") - hair_overlay.color = "#" + H.dna.features["mcolor"] + hair_overlay.color = H.dna.features["mcolor"] else if(hair_color == "fixedmutcolor") - hair_overlay.color = "#[fixed_mut_color]" + hair_overlay.color = fixed_mut_color else - hair_overlay.color = "#" + hair_color + hair_overlay.color = hair_color else - hair_overlay.color = "#" + H.hair_color + hair_overlay.color = H.hair_color hair_overlay.alpha = hair_alpha standing+=hair_overlay //var/mutable_appearance/pod_flower = mutable_appearance(GLOB.pod_flower_list[H.dna.features["pod_flower"]].icon, GLOB.pod_flower_list[H.dna.features["pod_flower"]].icon_state, -HAIR_LAYER) @@ -644,13 +644,13 @@ GLOBAL_LIST_EMPTY(mentor_races) if(!forced_colour) if(hair_color) if(hair_color == "mutcolor") - flower_overlay.color = "#" + H.dna.features["mcolor"] + flower_overlay.color = H.dna.features["mcolor"] else if(hair_color == "fixedmutcolor") - flower_overlay.color = "#[fixed_mut_color]" + flower_overlay.color = fixed_mut_color else - flower_overlay.color = "#" + hair_color + flower_overlay.color = hair_color else - flower_overlay.color = "#" + H.facial_hair_color + flower_overlay.color = H.facial_hair_color flower_overlay.alpha = hair_alpha standing += flower_overlay if(standing.len) @@ -684,7 +684,7 @@ GLOBAL_LIST_EMPTY(mentor_races) else eye_overlay = mutable_appearance('icons/mob/human_face.dmi', E.eye_icon_state, -BODY_LAYER) if((EYECOLOR in species_traits) && E) - eye_overlay.color = "#" + H.eye_color + eye_overlay.color = H.eye_color if(OFFSET_FACE in H.dna.species.offset_features) eye_overlay.pixel_x += H.dna.species.offset_features[OFFSET_FACE][1] eye_overlay.pixel_y += H.dna.species.offset_features[OFFSET_FACE][2] @@ -938,20 +938,20 @@ GLOBAL_LIST_EMPTY(mentor_races) if(H.dna.check_mutation(HULK) || H.dna.check_mutation(ACTIVE_HULK)) //HULK GO FIRST accessory_overlay.color = "#00aa00" else if(fixed_mut_color) //Then fixed color if applicable - accessory_overlay.color = "#[fixed_mut_color]" + accessory_overlay.color = fixed_mut_color else //Then snowflake color - accessory_overlay.color = "#[H.dna.features["mcolor"]]" + accessory_overlay.color = H.dna.features["mcolor"] if(HAIR) if(hair_color == "mutcolor") - accessory_overlay.color = "#[H.dna.features["mcolor"]]" + accessory_overlay.color = H.dna.features["mcolor"] else if(hair_color == "fixedmutcolor") - accessory_overlay.color = "#[fixed_mut_color]" + accessory_overlay.color = fixed_mut_color else - accessory_overlay.color = "#[H.hair_color]" + accessory_overlay.color = H.hair_color if(FACEHAIR) - accessory_overlay.color = "#[H.facial_hair_color]" + accessory_overlay.color = H.facial_hair_color if(EYECOLOR) - accessory_overlay.color = "#[H.eye_color]" + accessory_overlay.color = H.eye_color else accessory_overlay.color = forced_colour standing += accessory_overlay @@ -1322,7 +1322,7 @@ GLOBAL_LIST_EMPTY(mentor_races) if(radiation > RAD_MOB_MUTATE) if(prob(1)) to_chat(H, span_danger("You mutate!")) - H.easy_randmut(NEGATIVE+MINOR_NEGATIVE) + H.easy_random_mutate(NEGATIVE+MINOR_NEGATIVE) H.emote("gasp") H.domutcheck() diff --git a/code/modules/mob/living/carbon/human/species_types/eggpeople.dm b/code/modules/mob/living/carbon/human/species_types/eggpeople.dm index 9fbee5cc5017..90d1281d4c66 100644 --- a/code/modules/mob/living/carbon/human/species_types/eggpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/eggpeople.dm @@ -8,7 +8,7 @@ name = "Eggperson" id = "egg" say_mod = "blurbles" - fixed_mut_color = "FFE7C9" + fixed_mut_color = "#FFE7C9" offset_features = list(OFFSET_EARS = list(0,2), OFFSET_HEAD = list(0,2)) inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID) brutemod = EGG_MAXBRUTEMOD // not the toughest egg in the dozen (handled by the #defines above) diff --git a/code/modules/mob/living/carbon/human/species_types/ethereal.dm b/code/modules/mob/living/carbon/human/species_types/ethereal.dm index f035e61747fb..74ec899010aa 100644 --- a/code/modules/mob/living/carbon/human/species_types/ethereal.dm +++ b/code/modules/mob/living/carbon/human/species_types/ethereal.dm @@ -50,7 +50,7 @@ .=..() if(ishuman(C)) var/mob/living/carbon/human/H = C - default_color = "#" + H.dna.features["ethcolor"] + default_color = H.dna.features["ethcolor"] r1 = GETREDPART(default_color) g1 = GETGREENPART(default_color) b1 = GETBLUEPART(default_color) @@ -75,7 +75,7 @@ if(!emageffect) current_color = rgb(r2 + ((r1-r2)*healthpercent), g2 + ((g1-g2)*healthpercent), b2 + ((b1-b2)*healthpercent)) H.set_light(1 + (2 * healthpercent), 1 + (1 * healthpercent), current_color) - fixed_mut_color = copytext_char(current_color, 2) + fixed_mut_color = current_color else H.set_light(0) fixed_mut_color = rgb(128,128,128) diff --git a/code/modules/mob/living/carbon/human/species_types/felinid.dm b/code/modules/mob/living/carbon/human/species_types/felinid.dm index f25e7c9b70b6..00ed41ad3b35 100644 --- a/code/modules/mob/living/carbon/human/species_types/felinid.dm +++ b/code/modules/mob/living/carbon/human/species_types/felinid.dm @@ -29,7 +29,7 @@ var/mob/living/carbon/human/H = C 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(H.dna.features["tail_human"] == "None") - H.dna.features["tail_human"] = "Cat" + H.dna.features["tail_human"] = "Cat" if(H.dna.features["ears"] == "None") H.dna.features["ears"] = "Cat" if(H.dna.features["ears"] == "Cat") @@ -42,6 +42,8 @@ tail.Insert(H, drop_if_replaced = FALSE) else mutanttail = null + H.dna.update_uf_block(DNA_HUMAN_TAIL_BLOCK) + H.dna.update_uf_block(DNA_EARS_BLOCK) /datum/species/human/felinid/on_species_loss(mob/living/carbon/H, datum/species/new_species, pref_load) var/obj/item/organ/ears/cat/ears = H.getorgan(/obj/item/organ/ears/cat) @@ -58,7 +60,7 @@ // Go with default ears NE = new /obj/item/organ/ears NE.Insert(H, drop_if_replaced = FALSE) - + H.dna.update_uf_block(DNA_EARS_BLOCK) if(tail) var/obj/item/organ/tail/NT if(new_species && new_species.mutanttail) @@ -70,6 +72,8 @@ NT.Insert(H, drop_if_replaced = FALSE) else tail.Remove(H) + H.dna.update_uf_block(DNA_HUMAN_TAIL_BLOCK) + ///turn everyone into catgirls. Technically not girls specifically but you get the point. /proc/mass_purrbation() diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm index 75de5f595fea..58b4fcb99b69 100644 --- a/code/modules/mob/living/carbon/human/species_types/golems.dm +++ b/code/modules/mob/living/carbon/human/species_types/golems.dm @@ -21,7 +21,7 @@ // To prevent golem subtypes from overwhelming the odds when random species // changes, only the Random Golem type can be chosen limbs_id = "golem" - fixed_mut_color = "aaa" + fixed_mut_color = "#aaaaaa" swimming_component = /datum/component/swimming/golem var/info_text = "As an Iron Golem, you don't have any special traits." var/random_eligible = TRUE //If false, the golem subtype can't be made through golem mutation toxin @@ -67,7 +67,7 @@ id = "adamantine golem" meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/golem/adamantine mutant_organs = list(/obj/item/organ/adamantine_resonator, /obj/item/organ/vocal_cords/adamantine) - fixed_mut_color = "4ed" + fixed_mut_color = "#44eedd" info_text = "As an Adamantine Golem, you possess special vocal cords allowing you to \"resonate\" messages to all golems. Your unique mineral makeup makes you immune to most types of magic." prefix = "Adamantine" special_names = null @@ -84,7 +84,7 @@ /datum/species/golem/plasma name = "Plasma Golem" id = "plasma golem" - fixed_mut_color = "a3d" + fixed_mut_color = "#aa33dd" meat = /obj/item/stack/ore/plasma //Can burn and takes damage from heat inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_GENELESS,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER) //no RESISTHEAT, NOFIRE @@ -144,7 +144,7 @@ name = "Diamond Golem" id = "diamond golem" limbs_id = "cr_golem" - fixed_mut_color = "0ff" + fixed_mut_color = "#00ffff" armor = 70 //up from 55 meat = /obj/item/stack/ore/diamond info_text = "As a Diamond Golem, you are more resistant than the average golem." @@ -155,7 +155,7 @@ /datum/species/golem/gold name = "Gold Golem" id = "gold golem" - fixed_mut_color = "cc0" + fixed_mut_color = "#cccc00" speedmod = 1 armor = 25 //down from 55 meat = /obj/item/stack/ore/gold @@ -167,7 +167,7 @@ /datum/species/golem/silver name = "Silver Golem" id = "silver golem" - fixed_mut_color = "ddd" + fixed_mut_color = "#dddddd" punchstunthreshold = 9 //60% chance, from 40% meat = /obj/item/stack/ore/silver info_text = "As a Silver Golem, your attacks have a higher chance of stunning. Being made of silver, your body is immune to most types of magic." @@ -186,7 +186,7 @@ /datum/species/golem/plasteel name = "Plasteel Golem" id = "plasteel golem" - fixed_mut_color = "bbb" + fixed_mut_color = "#bbbbbb" stunmod = 0.4 punchdamagelow = 12 punchdamagehigh = 21 @@ -214,7 +214,7 @@ /datum/species/golem/titanium name = "Titanium Golem" id = "titanium golem" - fixed_mut_color = "fff" + fixed_mut_color = "#ffffff" meat = /obj/item/stack/ore/titanium info_text = "As a Titanium Golem, you are immune to ash storms, and slightly more resistant to burn damage." burnmod = 0.9 @@ -233,7 +233,7 @@ /datum/species/golem/plastitanium name = "Plastitanium Golem" id = "plastitanium golem" - fixed_mut_color = "888" + fixed_mut_color = "#888888" meat = /obj/item/stack/ore/titanium info_text = "As a Plastitanium Golem, you are immune to both ash storms and lava, and slightly more resistant to burn damage." burnmod = 0.8 @@ -254,7 +254,7 @@ /datum/species/golem/alloy name = "Alien Alloy Golem" id = "alloy golem" - fixed_mut_color = "333" + fixed_mut_color = "#333333" meat = /obj/item/stack/sheet/mineral/abductor mutanttongue = /obj/item/organ/tongue/abductor speedmod = 1 //faster @@ -274,7 +274,7 @@ /datum/species/golem/wood name = "Wood Golem" id = "wood golem" - fixed_mut_color = "9E704B" + fixed_mut_color = "#9E704B" meat = /obj/item/stack/sheet/mineral/wood //Can burn and take damage from heat inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_GENELESS,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER) @@ -332,7 +332,7 @@ /datum/species/golem/uranium name = "Uranium Golem" id = "uranium golem" - fixed_mut_color = "7f0" + fixed_mut_color = "#77ff00" meat = /obj/item/stack/ore/uranium info_text = "As an Uranium Golem, your very touch burns and irradiates organic lifeforms. You don't hit as hard as most golems, though." attack_verb = "burn" @@ -379,7 +379,7 @@ /datum/species/golem/sand name = "Sand Golem" id = "sand golem" - fixed_mut_color = "ffdc8f" + fixed_mut_color = "#ffdc8f" meat = /obj/item/stack/ore/glass //this is sand armor = 0 burnmod = 3 //melts easily @@ -411,7 +411,7 @@ name = "Glass Golem" id = "glass golem" limbs_id = "cr_golem" - fixed_mut_color = "5a96b4aa" //transparent body + fixed_mut_color = "#5a96b4aa" //transparent body meat = /obj/item/shard armor = 0 brutemod = 3 //very fragile @@ -449,7 +449,7 @@ name = "Bluespace Golem" id = "bluespace golem" limbs_id = "cr_golem" - fixed_mut_color = "33f" + fixed_mut_color = "#3333ff" meat = /obj/item/stack/ore/bluespace_crystal info_text = "As a Bluespace Golem, you are spatially unstable: You will teleport when hit, and you can teleport manually at a long distance." attack_verb = "bluespace punch" @@ -542,7 +542,7 @@ /datum/species/golem/bananium name = "Bananium Golem" id = "bananium golem" - fixed_mut_color = "ff0" + fixed_mut_color = "#ffff00" say_mod = "honks" punchdamagelow = 0 punchdamagehigh = 1 @@ -849,7 +849,7 @@ id = "plastic golem" prefix = "Plastic" special_names = list("Sheet", "Bag", "Bottle") - fixed_mut_color = "fff" + fixed_mut_color = "#ffffff" info_text = "As a Plastic Golem, you are capable of ventcrawling and passing through plastic flaps as long as you are naked." /datum/species/golem/plastic/on_species_gain(mob/living/carbon/C, datum/species/old_species) @@ -865,7 +865,7 @@ id = "bronze golem" prefix = "Bronze" special_names = list("Bell") - fixed_mut_color = "cd7f32" + fixed_mut_color = "#cd7f32" info_text = "As a Bronze Golem, you are very resistant to loud noises, and make loud noises if something hard hits you, however this ability does hurt your hearing." special_step_sounds = list('sound/machines/clockcult/integration_cog_install.ogg', 'sound/magic/clockwork/fellowship_armory.ogg' ) mutantears = /obj/item/organ/ears/bronze @@ -1033,7 +1033,7 @@ special_names = list("Face", "Man", "Belt") //Ah dude 4 strength 4 stam leather belt AHHH inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_GENELESS,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER, TRAIT_STRONG_GRABBER) prefix = "Leather" - fixed_mut_color = "624a2e" + fixed_mut_color = "#624a2e" info_text = "As a Leather Golem, you are flammable, but you can grab things with incredible ease, allowing all your grabs to start at a strong level." grab_sound = 'sound/weapons/whipgrab.ogg' attack_sound = 'sound/weapons/whip.ogg' @@ -1238,7 +1238,7 @@ /datum/species/golem/cheese name = "Cheese Golem" id = "cheese golem" - fixed_mut_color = "F1D127" + fixed_mut_color = "#F1D127" meat = /obj/item/stack/sheet/cheese inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_GENELESS,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER) armor = 10 @@ -1271,7 +1271,7 @@ /datum/species/golem/mhydrogen name = "Metallic Hydrogen Golem" id = "Metallic Hydrogen golem" - fixed_mut_color = "ddd" + fixed_mut_color = "#dddddd" info_text = "As a Metallic Hydrogen Golem, you were forged in the highest pressures and the highest heats. Your exotic makeup makes you tougher than diamond." prefix = "Hydrogen" stunmod = 0.6 //as opposed to plasteel's 0.4 @@ -1292,7 +1292,7 @@ name = "Telecrystal Golem" id = "telecrystal golem" limbs_id = "cr_golem" - fixed_mut_color = "e02828" + fixed_mut_color = "#e02828" speedmod = 1 //same as golden golem random_eligible = FALSE //too strong for a charged black extract info_text = "As a Telecrystal Golem, you are faster than an avarage golem. Being created out of telecrystal, a much stable but less powerful variation of bluespace, you possess the ability to make controlled short ranged phase jumps." diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm index 44e49f321609..55555dfc40c1 100644 --- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm @@ -221,6 +221,7 @@ spare.underwear = "Nude" H.dna.transfer_identity(spare, transfer_SE=1) spare.dna.features["mcolor"] = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F") + spare.dna.update_uf_block(DNA_MUTANT_COLOR_BLOCK) spare.real_name = spare.dna.real_name spare.name = spare.dna.real_name spare.updateappearance(mutcolor_update=1) diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm index f35e61b924dc..e8b38892c5db 100644 --- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm @@ -119,7 +119,7 @@ name = "Draconid" id = "draconid" limbs_id = "lizard" - fixed_mut_color = "A02720" //Deep red + fixed_mut_color = "#A02720" //Deep red species_traits = list(MUTCOLORS,EYECOLOR,LIPS,DIGITIGRADE,HAS_FLESH,HAS_BONE) inherent_traits = list(TRAIT_RESISTHEAT) //Dragons like fire burnmod = 0.8 diff --git a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm index 55a866552229..8fa141d0f82d 100644 --- a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm @@ -5,8 +5,8 @@ default_features = list("caps" = "Round") changesource_flags = MIRROR_BADMIN | WABBAJACK | ERT_SPAWN | SLIME_EXTRACT - fixed_mut_color = "DBBF92" - hair_color = "FF4B19" //cap color, spot color uses eye color + fixed_mut_color = "#DBBF92" + hair_color = "#FF4B19" //cap color, spot color uses eye color nojumpsuit = TRUE say_mod = "poofs" //what does a mushroom sound like diff --git a/code/modules/mob/living/carbon/human/species_types/podpeople.dm b/code/modules/mob/living/carbon/human/species_types/podpeople.dm index e069593fe10b..d411a90f9017 100644 --- a/code/modules/mob/living/carbon/human/species_types/podpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/podpeople.dm @@ -71,10 +71,11 @@ DISREGUARD THIS FILE IF YOU'RE INTENDING TO CHANGE ASPECTS OF PLAYER CONTROLLED H.Paralyze(100) H.visible_message(span_warning("[H] writhes in pain as [H.p_their()] vacuoles boil."), span_userdanger("You writhe in pain as your vacuoles boil!"), span_italics("You hear the crunching of leaves.")) if(prob(80)) - H.easy_randmut(NEGATIVE+MINOR_NEGATIVE) + H.easy_random_mutate(NEGATIVE+MINOR_NEGATIVE) else - H.easy_randmut(POSITIVE) - H.randmuti() + H.easy_random_mutate(POSITIVE) + H.random_mutate_unique_identity() + H.random_mutate_unique_features() H.domutcheck() else H.adjustFireLoss(rand(5,15)) diff --git a/code/modules/mob/living/carbon/human/species_types/polysmorphs.dm b/code/modules/mob/living/carbon/human/species_types/polysmorphs.dm index 739d6fa7e1de..60e2f4379ced 100644 --- a/code/modules/mob/living/carbon/human/species_types/polysmorphs.dm +++ b/code/modules/mob/living/carbon/human/species_types/polysmorphs.dm @@ -24,7 +24,7 @@ attack_verb = "slash" attack_sound = 'sound/weapons/slash.ogg' miss_sound = 'sound/weapons/slashmiss.ogg' - fixed_mut_color = "444466" //don't mess with this if you don't feel like manually adjusting the mutant bodypart sprites + fixed_mut_color = "#444466" //don't mess with this if you don't feel like manually adjusting the mutant bodypart sprites mutant_bodyparts = list("tail_polysmorph", "dome", "dorsal_tubes", "teeth", "legs") default_features = list("tail_polysmorph" = "Polys", "dome" = "None", "dorsal_tubes" = "No", "teeth" = "None", "legs" = "Normal Legs") mutanttongue = /obj/item/organ/tongue/polysmorph diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 99684c3c2c54..f7ccbee18c21 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -710,7 +710,7 @@ generate/load female uniform sprites matching all previously decided variables else eye_overlay = mutable_appearance('icons/mob/human_face.dmi', E.eye_icon_state, -BODY_LAYER) if((EYECOLOR in dna.species.species_traits) && E) - eye_overlay.color = "#" + eye_color + eye_overlay.color = eye_color if(OFFSET_FACE in dna.species.offset_features) eye_overlay.pixel_x += dna.species.offset_features[OFFSET_FACE][1] eye_overlay.pixel_y += dna.species.offset_features[OFFSET_FACE][2] diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 6ceb332b57f1..dd4141b74722 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -391,11 +391,18 @@ if(dna.temporary_mutations[mut] < world.time) if(mut == UI_CHANGED) if(dna.previous["UI"]) - dna.uni_identity = merge_text(dna.uni_identity,dna.previous["UI"]) + dna.unique_identity = merge_text(dna.unique_identity,dna.previous["UI"]) updateappearance(mutations_overlay_update=1) dna.previous.Remove("UI") dna.temporary_mutations.Remove(mut) continue + if(mut == UF_CHANGED) + if(dna.previous["UF"]) + dna.unique_features = merge_text(dna.unique_features,dna.previous["UF"]) + updateappearance(mutcolor_update=1, mutations_overlay_update=1) + dna.previous.Remove("UF") + dna.temporary_mutations.Remove(mut) + continue if(mut == UE_CHANGED) if(dna.previous["name"]) real_name = dna.previous["name"] diff --git a/code/modules/mob/living/carbon/monkey/life.dm b/code/modules/mob/living/carbon/monkey/life.dm index a9c27f9ab7e6..230fa3a150f5 100644 --- a/code/modules/mob/living/carbon/monkey/life.dm +++ b/code/modules/mob/living/carbon/monkey/life.dm @@ -36,7 +36,7 @@ if(radiation > RAD_MOB_MUTATE) if(prob(1)) to_chat(src, span_danger("You mutate!")) - easy_randmut(NEGATIVE+MINOR_NEGATIVE) + easy_random_mutate(NEGATIVE+MINOR_NEGATIVE) INVOKE_ASYNC(src, .proc/emote, "gasp") domutcheck() diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm index ecad236dcc90..b75544881262 100644 --- a/code/modules/projectiles/projectile/magic.dm +++ b/code/modules/projectiles/projectile/magic.dm @@ -878,11 +878,10 @@ . = ..() if(iscarbon(target)) var/mob/living/carbon/X = target - X.randmuti() if(prob(66)) - X.easy_randmut(NEGATIVE) + X.easy_random_mutate(NEGATIVE) else - X.easy_randmut(MINOR_NEGATIVE) + X.easy_random_mutate(MINOR_NEGATIVE) /obj/item/projectile/magic/runic_resizement diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index d2479cc39c72..da0466618d93 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -445,7 +445,7 @@ newcolor += ascii2text(ascii+31) //letters B to F - translates to lowercase else break - if(ReadHSV(newcolor)[3] >= ReadHSV("#7F7F7F")[3]) + if(ReadHSV(newcolor)[3] >= ReadHSV("#777777")[3]) N.dna.features["mcolor"] = newcolor N.regenerate_icons() @@ -700,6 +700,7 @@ to_chat(H, span_warning("You grit your teeth in pain as your body rapidly mutates!")) H.visible_message("[H] suddenly transforms!") randomize_human(H) + H.dna.update_dna_identity() /datum/reagent/aslimetoxin name = "Advanced Mutation Toxin" diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm index d3807053a69a..e71314cfc8fb 100644 --- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm @@ -37,11 +37,12 @@ if(!M.has_dna() || HAS_TRAIT(M, TRAIT_GENELESS) || HAS_TRAIT(M, TRAIT_BADDNA)) return //No robots, AIs, aliens, Ians or other mobs should be affected by this. if((method==VAPOR && prob(min(33, reac_volume))) || ((method==INGEST || method==PATCH || method==INJECT) && reac_volume >= 5)) - M.randmuti() + M.random_mutate_unique_identity() + M.random_mutate_unique_features() if(prob(98)) - M.easy_randmut(NEGATIVE+MINOR_NEGATIVE) + M.easy_random_mutate(NEGATIVE+MINOR_NEGATIVE) else - M.easy_randmut(POSITIVE) + M.easy_random_mutate(POSITIVE) M.updateappearance() M.domutcheck() ..() diff --git a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm index 5356e400de6f..bafeecf7bb06 100644 --- a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm +++ b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm @@ -776,6 +776,7 @@ datum/status_effect/stabilized/blue/on_remove() originalname = H.real_name H.dna.copy_dna(originalDNA) randomize_human(H) + H.dna.update_dna_identity() return ..() /datum/status_effect/stabilized/green/tick() //Only occasionally give examiners a warning. diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm index 8fe0cc2df830..881bab38a26f 100644 --- a/code/modules/research/xenobiology/xenobiology.dm +++ b/code/modules/research/xenobiology/xenobiology.dm @@ -604,6 +604,7 @@ switch(activation_type) if(SLIME_ACTIVATE_MINOR) user.dna.features["mcolor"] = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F") + user.dna.update_uf_block(DNA_MUTANT_COLOR_BLOCK) user.updateappearance(mutcolor_update=1) species.update_glow(user) to_chat(user, span_notice("You feel different...")) diff --git a/code/modules/ruins/icemoonruin_code/hotsprings.dm b/code/modules/ruins/icemoonruin_code/hotsprings.dm index 83d851a5b381..f0a70f246f12 100644 --- a/code/modules/ruins/icemoonruin_code/hotsprings.dm +++ b/code/modules/ruins/icemoonruin_code/hotsprings.dm @@ -26,6 +26,7 @@ GLOBAL_LIST_EMPTY(cursed_minds) randomize_human(H) var/random_race = GLOB.species_list[pick(GLOB.roundstart_races)] H.set_species(random_race) + H.dna.update_dna_identity() var/list/valid_jobs = list() for(var/random_job in subtypesof(/datum/job)) var/datum/job/J = new random_job() diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 42eb7df14eae..8076f58245da 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -755,7 +755,7 @@ species_color = "" if(!dropping_limb && (H.dna.check_mutation(HULK) || H.dna.check_mutation(ACTIVE_HULK))) - mutation_color = "00aa00" + mutation_color = "#00aa00" else mutation_color = "" @@ -861,9 +861,9 @@ if(should_draw_greyscale) var/draw_color = mutation_color || species_color || (skin_tone && skintone2hex(skin_tone)) if(draw_color) - limb.color = "#[draw_color]" + limb.color = "[draw_color]" if(aux_zone) - aux.color = "#[draw_color]" + aux.color = "[draw_color]" /obj/item/bodypart/deconstruct(disassembled = TRUE) drop_organs() diff --git a/code/modules/surgery/bodyparts/head.dm b/code/modules/surgery/bodyparts/head.dm index 3a2defe86c9d..332afe2a7199 100644 --- a/code/modules/surgery/bodyparts/head.dm +++ b/code/modules/surgery/bodyparts/head.dm @@ -151,7 +151,7 @@ if(S.hair_color == "mutcolor") facial_hair_color = H.dna.features["mcolor"] else if(hair_color == "fixedmutcolor") - facial_hair_color = "#[S.fixed_mut_color]" + facial_hair_color = "[S.fixed_mut_color]" else facial_hair_color = S.hair_color else @@ -168,7 +168,7 @@ if(S.hair_color == "mutcolor") hair_color = H.dna.features["mcolor"] else if(hair_color == "fixedmutcolor") - hair_color = "#[S.fixed_mut_color]" + hair_color = "[S.fixed_mut_color]" else hair_color = S.hair_color else @@ -208,7 +208,7 @@ var/datum/sprite_accessory/S = GLOB.facial_hair_styles_list[facial_hair_style] if(S) var/image/facial_overlay = image(S.icon, "[S.icon_state]", -HAIR_LAYER, SOUTH) - facial_overlay.color = "#" + facial_hair_color + facial_overlay.color = facial_hair_color facial_overlay.alpha = hair_alpha . += facial_overlay @@ -229,7 +229,7 @@ var/datum/sprite_accessory/S2 = GLOB.hair_styles_list[hair_style] if(S2) var/image/hair_overlay = image(S2.icon, "[S2.icon_state]", -HAIR_LAYER, SOUTH) - hair_overlay.color = "#" + hair_color + hair_overlay.color = hair_color hair_overlay.alpha = hair_alpha . += hair_overlay @@ -247,7 +247,7 @@ eyes_overlay.icon_state = eyes.eye_icon_state if(eyes.eye_color) - eyes_overlay.color = "#" + eyes.eye_color + eyes_overlay.color = eyes.eye_color /obj/item/bodypart/head/monkey icon = 'icons/mob/animal_parts.dmi' diff --git a/code/modules/surgery/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm index 594f36c97ca9..1f58776168e8 100644 --- a/code/modules/surgery/bodyparts/helpers.dm +++ b/code/modules/surgery/bodyparts/helpers.dm @@ -258,31 +258,31 @@ . = 0 switch(skin_tone) if("caucasian1") - . = "ffe0d1" + . = "#ffe0d1" if("caucasian2") - . = "fcccb3" + . = "#fcccb3" if("caucasian3") - . = "e8b59b" + . = "#e8b59b" if("latino") - . = "d9ae96" + . = "#d9ae96" if("mediterranean") - . = "c79b8b" + . = "#c79b8b" if("asian1") - . = "ffdeb3" + . = "#ffdeb3" if("asian2") - . = "e3ba84" + . = "#e3ba84" if("arab") - . = "c4915e" + . = "#c4915e" if("indian") - . = "b87840" + . = "#b87840" if("african1") - . = "754523" + . = "#754523" if("african2") - . = "471c18" + . = "#471c18" if("albino") - . = "fff4e6" + . = "#fff4e6" if("orange") - . = "ffc905" + . = "#ffc905" /mob/living/carbon/proc/Digitigrade_Leg_Swap(swap_back) var/body_plan_changed = FALSE diff --git a/code/modules/surgery/organs/tails.dm b/code/modules/surgery/organs/tails.dm index 74a6a821cb4d..875d7eed1336 100644 --- a/code/modules/surgery/organs/tails.dm +++ b/code/modules/surgery/organs/tails.dm @@ -6,6 +6,7 @@ icon_state = "severedtail" zone = BODY_ZONE_PRECISE_GROIN slot = ORGAN_SLOT_TAIL + /// The sprite accessory this tail gives to the human it's attached to. If null, it will inherit its value from the human's DNA once attached. var/tail_type = "None" /obj/item/organ/tail/Remove(mob/living/carbon/human/H, special = 0) @@ -21,10 +22,14 @@ /obj/item/organ/tail/cat/Insert(mob/living/carbon/human/H, special = 0, drop_if_replaced = TRUE) ..() if(istype(H)) - if(!("tail_human" in H.dna.species.mutant_bodyparts)) - H.dna.species.mutant_bodyparts |= "tail_human" - H.dna.features["tail_human"] = tail_type - H.update_body() + var/default_part = H.dna.species.mutant_bodyparts["tail_human"] + if(!default_part || default_part == "None") + if(tail_type) + H.dna.features["tail_human"] = H.dna.species.mutant_bodyparts["tail_human"] = tail_type + H.dna.update_uf_block(DNA_HUMAN_TAIL_BLOCK) + else + H.dna.species.mutant_bodyparts["tail_human"] = H.dna.features["tail_human"] + H.update_body() /obj/item/organ/tail/cat/Remove(mob/living/carbon/human/H, special = 0) ..() @@ -45,13 +50,21 @@ ..() if(istype(H)) // Checks here are necessary so it wouldn't overwrite the tail of a lizard it spawned in - if(!("tail_lizard" in H.dna.species.mutant_bodyparts)) - H.dna.features["tail_lizard"] = tail_type - H.dna.species.mutant_bodyparts |= "tail_lizard" - - if(!("spines" in H.dna.species.mutant_bodyparts)) - H.dna.features["spines"] = spines - H.dna.species.mutant_bodyparts |= "spines" + var/default_part = H.dna.species.mutant_bodyparts["tail_lizard"] + if(!default_part || default_part == "None") + if(tail_type) + H.dna.features["tail_lizard"] = H.dna.species.mutant_bodyparts["tail_lizard"] = tail_type + H.dna.update_uf_block(DNA_LIZARD_TAIL_BLOCK) + else + H.dna.species.mutant_bodyparts["tail_lizard"] = H.dna.features["tail_lizard"] + + default_part = H.dna.species.mutant_bodyparts["spines"] + if(!default_part || default_part == "None") + if(spines) + H.dna.features["spines"] = H.dna.species.mutant_bodyparts["spines"] = spines + H.dna.update_uf_block(DNA_SPINES_BLOCK) + else + H.dna.species.mutant_bodyparts["spines"] = H.dna.features["spines"] H.update_body() /obj/item/organ/tail/lizard/Remove(mob/living/carbon/human/H, special = 0) @@ -59,7 +72,7 @@ if(istype(H)) H.dna.species.mutant_bodyparts -= "tail_lizard" H.dna.species.mutant_bodyparts -= "spines" - color = "#" + H.dna.features["mcolor"] + color = H.dna.features["mcolor"] tail_type = H.dna.features["tail_lizard"] spines = H.dna.features["spines"] H.update_body() @@ -77,9 +90,13 @@ /obj/item/organ/tail/polysmorph/Insert(mob/living/carbon/human/H, special = 0, drop_if_replaced = FALSE) ..() if(istype(H)) - if(!("tail_polysmorph" in H.dna.species.mutant_bodyparts)) - H.dna.features["tail_polysmorph"] = tail_type - H.dna.species.mutant_bodyparts |= "tail_polysmorph" + var/default_part = H.dna.species.mutant_bodyparts["tail_polysmorph"] + if(!default_part || default_part == "None") + if(tail_type) + H.dna.features["tail_polysmorph"] = H.dna.species.mutant_bodyparts["tail_polysmorph"] = tail_type + H.dna.update_uf_block(DNA_POLY_TAIL_BLOCK) + else + H.dna.species.mutant_bodyparts["tail_polysmorph"] = H.dna.features["tail_polysmorph"] H.update_body() /obj/item/organ/tail/polysmorph/Remove(mob/living/carbon/human/H, special = 0) diff --git a/tgui/packages/tgui/interfaces/DnaConsole.js b/tgui/packages/tgui/interfaces/DnaConsole.js index 194b9a4a6b58..f62db82dc1a8 100644 --- a/tgui/packages/tgui/interfaces/DnaConsole.js +++ b/tgui/packages/tgui/interfaces/DnaConsole.js @@ -26,6 +26,7 @@ const GENE_COLORS = { const CONSOLE_MODE_STORAGE = 'storage'; const CONSOLE_MODE_SEQUENCER = 'sequencer'; const CONSOLE_MODE_ENZYMES = 'enzymes'; +const CONSOLE_MODE_FEATURES = 'features'; const CONSOLE_MODE_INJECTORS = 'injectors'; const STORAGE_MODE_CONSOLE = 'console'; @@ -73,6 +74,8 @@ export const DnaConsole = (props, context) => { const { isPulsingRads, radPulseSeconds, + subjectUNI, + subjectUF, } = data; const { consoleMode } = data.view; return ( @@ -104,7 +107,16 @@ export const DnaConsole = (props, context) => { )} {consoleMode === CONSOLE_MODE_ENZYMES && ( - + + )} + {consoleMode === CONSOLE_MODE_FEATURES && ( + )} @@ -308,6 +320,12 @@ export const DnaConsoleCommands = (props, context) => { onClick={() => act('set_view', { consoleMode: CONSOLE_MODE_ENZYMES, })} /> + + + + + + +