diff --git a/code/__DEFINES/DNA.dm b/code/__DEFINES/DNA.dm
index 34bbaf45444..3e3f140a711 100644
--- a/code/__DEFINES/DNA.dm
+++ b/code/__DEFINES/DNA.dm
@@ -64,6 +64,7 @@
#define UE_CHANGED "ue changed"
#define UI_CHANGED "ui changed"
+#define UF_CHANGED "uf changed"
#define CHAMELEON_MUTATION_DEFAULT_TRANSPARENCY 204
@@ -92,6 +93,37 @@
#define DNA_SKIN_TONE_BLOCK 3
#define DNA_UNI_IDENTITY_BLOCKS 7
+//SKYRAT EDIT REMOVAL BEGIN - CUSTOMIZATION (moved to modular_skyrat/modules/customization/_DEFINES/DNA.dm)
+/*
+#define DNA_FEATURE_BLOCKS 15
+#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_MOTH_ANTENNAE_BLOCK 12
+#define DNA_MOTH_MARKINGS_BLOCK 13
+#define DNA_MUSHROOM_CAPS_BLOCK 14
+#define DNA_MONKEY_TAIL_BLOCK 15
+*/ //SKYRAT EDIT CHANGE - ORIGINAL
+#define DNA_FEATURE_BLOCKS GLOB.dna_total_feature_blocks
+
+#define DNA_MANDATORY_COLOR_BLOCKS 5
+#define DNA_MUTANT_COLOR_BLOCK 1
+#define DNA_MUTANT_COLOR_2_BLOCK 2
+#define DNA_MUTANT_COLOR_3_BLOCK 3
+#define DNA_ETHEREAL_COLOR_BLOCK 4
+#define DNA_SKIN_COLOR_BLOCK 5
+
+// SKYRAT EDIT CHANGE END
+
+
#define DNA_SEQUENCE_LENGTH 4
#define DNA_MUTATION_BLOCKS 8
#define DNA_UNIQUE_ENZYMES_LEN 32
diff --git a/code/__HELPERS/sanitize_values.dm b/code/__HELPERS/sanitize_values.dm
index 75ed837aae9..7cc24570a36 100644
--- a/code/__HELPERS/sanitize_values.dm
+++ b/code/__HELPERS/sanitize_values.dm
@@ -53,6 +53,11 @@
/proc/sanitize_hexcolor(color, desired_format = 3, include_crunch = FALSE, default)
var/crunch = include_crunch ? "#" : ""
+ //SKYRAT EDIT ADDITION BEGIN - CUSTOMIZATION
+ if(islist(color))
+ var/list/color_list = color
+ color = color_list.Join()
+ //SKYRAT EDIT ADDITION END
if(!istext(color))
color = ""
diff --git a/code/datums/components/forensics.dm b/code/datums/components/forensics.dm
index 55244d83a7d..1b3ea517dd9 100644
--- a/code/datums/components/forensics.dm
+++ b/code/datums/components/forensics.dm
@@ -91,7 +91,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 4b5dacfab62..9914c183ab1 100644
--- a/code/datums/datacore.dm
+++ b/code/datums/datacore.dm
@@ -266,7 +266,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
@@ -333,7 +333,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/advance/symptoms/genetics.dm b/code/datums/diseases/advance/symptoms/genetics.dm
index b6395920f4c..094d12eb051 100644
--- a/code/datums/diseases/advance/symptoms/genetics.dm
+++ b/code/datums/diseases/advance/symptoms/genetics.dm
@@ -61,7 +61,7 @@ Bonus
switch(A.stage)
if(4, 5)
to_chat(C, span_warning("[pick("Your skin feels itchy.", "You feel light headed.")]"))
- C.easy_randmut((NEGATIVE | MINOR_NEGATIVE | POSITIVE) - excludemuts, TRUE, TRUE, TRUE, mutadone_proof)
+ C.easy_random_mutate((NEGATIVE | MINOR_NEGATIVE | POSITIVE) - excludemuts, TRUE, TRUE, TRUE, mutadone_proof)
/datum/symptom/genetic_mutation/End(datum/disease/advance/A)
. = ..()
diff --git a/code/datums/diseases/retrovirus.dm b/code/datums/diseases/retrovirus.dm
index 954ca675ab5..7cbcbb97394 100644
--- a/code/datums/diseases/retrovirus.dm
+++ b/code/datums/diseases/retrovirus.dm
@@ -61,20 +61,26 @@
if(DT_PROB(5, delta_time))
to_chat(affected_mob, span_danger("Your entire body vibrates."))
if(DT_PROB(19, delta_time))
- 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(restcure && affected_mob.body_position == LYING_DOWN && DT_PROB(10, delta_time))
to_chat(affected_mob, span_notice("You feel better."))
cure()
return FALSE
if(4)
if(DT_PROB(37, delta_time))
- if(prob(50))
- scramble_dna(affected_mob, 1, 0, rand(50,75))
- else
- scramble_dna(affected_mob, 0, 1, rand(50,75))
+ 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))
if(restcure && affected_mob.body_position == LYING_DOWN && DT_PROB(2.5, delta_time))
to_chat(affected_mob, span_notice("You feel better."))
cure()
diff --git a/code/datums/dna.dm b/code/datums/dna.dm
index 191adf5db1f..9c16b90a20a 100644
--- a/code/datums/dna.dm
+++ b/code/datums/dna.dm
@@ -1,11 +1,15 @@
/////////////////////////// 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
@@ -39,10 +43,11 @@
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) //ORIGINAL
destination.set_species(species.type, TRUE, null, features.Copy(), mutant_bodyparts.Copy(), body_markings.Copy()) //SKYRAT EDIT CHANGE - CUSTOMIZATION
+ destination.dna.unique_features = unique_features
destination.dna.features = features.Copy()
destination.dna.real_name = real_name
destination.dna.temporary_mutations = temporary_mutations.Copy()
@@ -54,7 +59,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()
//SKYRAT EDIT ADDITION BEGIN - CUSTOMIZATION
@@ -96,7 +102,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)
@@ -127,6 +133,51 @@
. += random_string(DNA_BLOCK_SIZE,GLOB.hex_characters)
return .
+//SKYRAT EDIT REMOVAL BEGIN - CUSTOMIZATION (moved to modular_skyrat/modules/customization/code/datums/dna.dm)
+/*
+/datum/dna/proc/generate_unique_features()
+ var/list/data = list()
+
+ var/list/L = new /list(DNA_FEATURE_BLOCKS)
+
+ if(features["mcolor"])
+ L[DNA_MUTANT_COLOR_BLOCK] = sanitize_hexcolor(features["mcolor"])
+ if(features["ethcolor"])
+ L[DNA_ETHEREAL_COLOR_BLOCK] = sanitize_hexcolor(features["ethcolor"])
+ 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["moth_antennae"] != "Burnt Off")
+ L[DNA_MOTH_ANTENNAE_BLOCK] = construct_block(GLOB.moth_antennae_list.Find(features["moth_antennae"]), GLOB.moth_antennae_list.len)
+ if(features["moth_markings"])
+ L[DNA_MOTH_MARKINGS_BLOCK] = construct_block(GLOB.moth_markings_list.Find(features["moth_markings"]), GLOB.moth_markings_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_monkey"])
+ L[DNA_MONKEY_TAIL_BLOCK] = construct_block(GLOB.tails_list_monkey.Find(features["tail_monkey"]), GLOB.tails_list_monkey.len)
+
+ for(var/i in 1 to DNA_FEATURE_BLOCKS)
+ data += (L[i] || random_string(DNA_BLOCK_SIZE,GLOB.hex_characters))
+
+ return data.Join()
+*/
+//SKYRAT EDIT REMOVAL END
+
/datum/dna/proc/generate_dna_blocks()
var/bonus
if(species?.inert_mutation)
@@ -165,8 +216,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
@@ -180,30 +231,73 @@
return .
/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)
- setblock(uni_identity, blocknumber, sanitize_hexcolor(H.hair_color))
+ setblock(unique_identity, blocknumber, sanitize_hexcolor(H.hair_color))
if(DNA_FACIAL_HAIR_COLOR_BLOCK)
- setblock(uni_identity, blocknumber, sanitize_hexcolor(H.facial_hair_color))
+ setblock(unique_identity, blocknumber, sanitize_hexcolor(H.facial_hair_color))
if(DNA_SKIN_TONE_BLOCK)
- setblock(uni_identity, blocknumber, construct_block(GLOB.skin_tones.Find(H.skin_tone), GLOB.skin_tones.len))
+ setblock(unique_identity, blocknumber, construct_block(GLOB.skin_tones.Find(H.skin_tone), GLOB.skin_tones.len))
if(DNA_EYE_COLOR_BLOCK)
- setblock(uni_identity, blocknumber, sanitize_hexcolor(H.eye_color))
+ setblock(unique_identity, blocknumber, sanitize_hexcolor(H.eye_color))
if(DNA_GENDER_BLOCK)
switch(H.gender)
if(MALE)
- setblock(uni_identity, blocknumber, construct_block(G_MALE, 3))
+ setblock(unique_identity, blocknumber, construct_block(G_MALE, 3))
if(FEMALE)
- setblock(uni_identity, blocknumber, construct_block(G_FEMALE, 3))
+ setblock(unique_identity, blocknumber, construct_block(G_FEMALE, 3))
else
- setblock(uni_identity, blocknumber, construct_block(G_PLURAL, 3))
+ setblock(unique_identity, blocknumber, construct_block(G_PLURAL, 3))
if(DNA_FACIAL_HAIRSTYLE_BLOCK)
- setblock(uni_identity, blocknumber, construct_block(GLOB.facial_hairstyles_list.Find(H.facial_hairstyle), GLOB.facial_hairstyles_list.len))
+ setblock(unique_identity, blocknumber, construct_block(GLOB.facial_hairstyles_list.Find(H.facial_hairstyle), GLOB.facial_hairstyles_list.len))
if(DNA_HAIRSTYLE_BLOCK)
- setblock(uni_identity, blocknumber, construct_block(GLOB.hairstyles_list.Find(H.hairstyle), GLOB.hairstyles_list.len))
+ setblock(unique_identity, blocknumber, construct_block(GLOB.hairstyles_list.Find(H.hairstyle), GLOB.hairstyles_list.len))
+
+//SKYRAT EDIT REMOVAL BEGIN - CUSTOMIZATION (moved to modular_skyrat/modules/customization/code/datums/dna.dm)
+/*
+/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)
+ setblock(unique_features, blocknumber, sanitize_hexcolor(features["mcolor"]))
+ if(DNA_ETHEREAL_COLOR_BLOCK)
+ setblock(unique_features, blocknumber, sanitize_hexcolor(features["ethcolor"]))
+ if(DNA_LIZARD_MARKINGS_BLOCK)
+ setblock(unique_features, blocknumber, construct_block(GLOB.body_markings_list.Find(features["body_markings"]), GLOB.body_markings_list.len))
+ if(DNA_LIZARD_TAIL_BLOCK)
+ setblock(unique_features, blocknumber, construct_block(GLOB.tails_list_lizard.Find(features["tail_lizard"]), GLOB.tails_list_lizard.len))
+ if(DNA_SNOUT_BLOCK)
+ setblock(unique_features, blocknumber, construct_block(GLOB.snouts_list.Find(features["snout"]), GLOB.snouts_list.len))
+ if(DNA_HORNS_BLOCK)
+ setblock(unique_features, blocknumber, construct_block(GLOB.horns_list.Find(features["horns"]), GLOB.horns_list.len))
+ if(DNA_FRILLS_BLOCK)
+ setblock(unique_features, blocknumber, construct_block(GLOB.frills_list.Find(features["frills"]), GLOB.frills_list.len))
+ if(DNA_SPINES_BLOCK)
+ setblock(unique_features, blocknumber, construct_block(GLOB.spines_list.Find(features["spines"]), GLOB.spines_list.len))
+ if(DNA_HUMAN_TAIL_BLOCK)
+ setblock(unique_features, blocknumber, construct_block(GLOB.tails_list_human.Find(features["tail_human"]), GLOB.tails_list_human.len))
+ if(DNA_EARS_BLOCK)
+ setblock(unique_features, blocknumber, construct_block(GLOB.ears_list.Find(features["ears"]), GLOB.ears_list.len))
+ if(DNA_MOTH_WINGS_BLOCK)
+ setblock(unique_features, blocknumber, construct_block(GLOB.moth_wings_list.Find(features["moth_wings"]), GLOB.moth_wings_list.len))
+ if(DNA_MOTH_ANTENNAE_BLOCK)
+ setblock(unique_features, blocknumber, construct_block(GLOB.moth_antennae_list.Find(features["moth_antennae"]), GLOB.moth_antennae_list.len))
+ if(DNA_MOTH_MARKINGS_BLOCK)
+ setblock(unique_features, blocknumber, construct_block(GLOB.moth_markings_list.Find(features["moth_markings"]), GLOB.moth_markings_list.len))
+ if(DNA_MUSHROOM_CAPS_BLOCK)
+ setblock(unique_features, blocknumber, construct_block(GLOB.caps_list.Find(features["caps"]), GLOB.caps_list.len))
+ if(DNA_MONKEY_TAIL_BLOCK)
+ setblock(unique_features, blocknumber, construct_block(GLOB.tails_list_monkey.Find(features["tail_monkey"]), GLOB.tails_list_monkey.len))
+*/
+//SKYRAT EDIT REMOVAL END
//Please use add_mutation or activate_mutation instead
/datum/dna/proc/force_give(datum/mutation/human/HM)
@@ -230,7 +324,7 @@
* * target_dna The DNA that we are comparing to
*/
/datum/dna/proc/is_same_as(datum/dna/target_dna)
- if(uni_identity == target_dna.uni_identity && mutation_index == target_dna.mutation_index && real_name == target_dna.real_name)
+ if(unique_identity == target_dna.unique_identity && mutation_index == target_dna.mutation_index && real_name == target_dna.real_name)
if(species.type == target_dna.species.type && compare_list(features, target_dna.features) && blood_type == target_dna.blood_type)
return TRUE
return FALSE
@@ -263,8 +357,9 @@
//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()
//SKYRAT EDIT REMOVAL BEGIN - CUSTOMIZATION (moved to modular)
/*
@@ -272,10 +367,11 @@
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()
*/
//SKYRAT EDIT REMOVAL END
@@ -309,7 +405,7 @@
stored_dna.species = mrace //not calling any species update procs since we're a brain, not a monkey/human
-//SKYRAT EDIT REMOVAL BEGIN - CUSTOMIZATION (moved to modular)
+//SKYRAT EDIT REMOVAL BEGIN - CUSTOMIZATION (moved to modular_skyrat/modules/customization/code/datums/dna.dm)
/*
/mob/living/carbon/set_species(datum/species/mrace, icon_update = TRUE, pref_load = FALSE)
if(QDELETED(src))
@@ -355,6 +451,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
@@ -369,7 +466,7 @@
dna.blood_type = newblood_type
if(ui)
- dna.uni_identity = ui
+ dna.unique_identity = ui
updateappearance(icon_update=0)
if(LAZYLEN(mutation_index))
@@ -403,7 +500,7 @@
if(!has_dna())
return
- switch(deconstruct_block(getblock(dna.uni_identity, DNA_GENDER_BLOCK), 3))
+ switch(deconstruct_block(getblock(dna.unique_identity, DNA_GENDER_BLOCK), 3))
if(G_MALE)
gender = MALE
if(G_FEMALE)
@@ -411,15 +508,55 @@
else
gender = PLURAL
+//SKYRAT EDIT REMOVAL BEGIN - CUSTOMIZATION (moved to modular_skyrat/modules/customization/code/datums/dna.dm)
+/*
/mob/living/carbon/human/updateappearance(icon_update=1, mutcolor_update=0, mutations_overlay_update=0)
..()
- var/structure = dna.uni_identity
+ var/structure = dna.unique_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_hairstyle = GLOB.facial_hairstyles_list[deconstruct_block(getblock(structure, DNA_FACIAL_HAIRSTYLE_BLOCK), GLOB.facial_hairstyles_list.len)]
hairstyle = GLOB.hairstyles_list[deconstruct_block(getblock(structure, DNA_HAIRSTYLE_BLOCK), GLOB.hairstyles_list.len)]
+ var/features = dna.unique_features
+ if(dna.features["mcolor"])
+ dna.features["mcolor"] = sanitize_hexcolor(getblock(features, DNA_MUTANT_COLOR_BLOCK))
+ if(dna.features["ethcolor"])
+ dna.features["ethcolor"] = sanitize_hexcolor(getblock(features, DNA_ETHEREAL_COLOR_BLOCK))
+ if(dna.features["body_markings"])
+ dna.features["body_markings"] = GLOB.body_markings_list[deconstruct_block(getblock(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(getblock(features, DNA_LIZARD_TAIL_BLOCK), GLOB.tails_list_lizard.len)]
+ if(dna.features["snout"])
+ dna.features["snout"] = GLOB.snouts_list[deconstruct_block(getblock(features, DNA_SNOUT_BLOCK), GLOB.snouts_list.len)]
+ if(dna.features["horns"])
+ dna.features["horns"] = GLOB.horns_list[deconstruct_block(getblock(features, DNA_HORNS_BLOCK), GLOB.horns_list.len)]
+ if(dna.features["frills"])
+ dna.features["frills"] = GLOB.frills_list[deconstruct_block(getblock(features, DNA_FRILLS_BLOCK), GLOB.frills_list.len)]
+ if(dna.features["spines"])
+ dna.features["spines"] = GLOB.spines_list[deconstruct_block(getblock(features, DNA_SPINES_BLOCK), GLOB.spines_list.len)]
+ if(dna.features["tail_human"])
+ dna.features["tail_human"] = GLOB.tails_list_human[deconstruct_block(getblock(features, DNA_HUMAN_TAIL_BLOCK), GLOB.tails_list_human.len)]
+ if(dna.features["ears"])
+ dna.features["ears"] = GLOB.ears_list[deconstruct_block(getblock(features, DNA_EARS_BLOCK), GLOB.ears_list.len)]
+ if(dna.features["moth_wings"])
+ var/genetic_value = GLOB.moth_wings_list[deconstruct_block(getblock(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["moth_antennae"])
+ var/genetic_value = GLOB.moth_antennae_list[deconstruct_block(getblock(features, DNA_MOTH_ANTENNAE_BLOCK), GLOB.moth_antennae_list.len)]
+ dna.features["original_moth_antennae"] = genetic_value
+ if(dna.features["moth_antennae"] != "Burnt Off")
+ dna.features["moth_antennae"] = genetic_value
+ if(dna.features["moth_markings"])
+ dna.features["moth_markings"] = GLOB.moth_markings_list[deconstruct_block(getblock(features, DNA_MOTH_MARKINGS_BLOCK), GLOB.moth_markings_list.len)]
+ if(dna.features["caps"])
+ dna.features["caps"] = GLOB.caps_list[deconstruct_block(getblock(features, DNA_MUSHROOM_CAPS_BLOCK), GLOB.caps_list.len)]
+ if(dna.features["tail_monkey"])
+ dna.features["tail_monkey"] = GLOB.tails_list_monkey[deconstruct_block(getblock(features, DNA_MONKEY_TAIL_BLOCK), GLOB.tails_list_monkey.len)]
+
if(icon_update)
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()
@@ -427,7 +564,8 @@
update_body_parts()
if(mutations_overlay_update)
update_mutations_overlay()
-
+*/
+//SKYRAT EDIT REMOVAL END
/mob/proc/domutcheck()
return
@@ -491,14 +629,14 @@
/proc/getleftblocks(input,blocknumber,blocksize)
if(blocknumber > 1)
- return copytext_char(input,1,((blocksize*blocknumber)-(blocksize-1)))
+ return copytext(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)
+ return copytext(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)
+ return copytext(input, blocksize*(blocknumber-1)+1, (blocksize*blocknumber)+1)
/proc/setblock(istring, blocknumber, replacement, blocksize=DNA_BLOCK_SIZE)
if(!istring || !blocknumber || !replacement || !blocksize)
@@ -516,15 +654,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, resilient = NONE)
+/mob/living/carbon/proc/easy_random_mutate(quality = POSITIVE + NEGATIVE + MINOR_NEGATIVE, scrambled = TRUE, sequence = TRUE, exclude_monkey = TRUE, resilient = NONE)
if(!has_dna())
- return
+ CRASH("[src] does not have DNA")
var/list/mutations = list()
if(quality & POSITIVE)
mutations += GLOB.good_mutations
@@ -549,26 +687,34 @@
HM.mutadone_proof = 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
+ var/newdna = setblock(dna.unique_identity, num, random_string(DNA_BLOCK_SIZE, GLOB.hex_characters))
+ dna.unique_identity = newdna
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)
+ var/newdna = setblock(dna.unique_features, num, random_string(DNA_BLOCK_SIZE, GLOB.hex_characters))
+ dna.unique_features = newdna
+ 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 FALSE
+ CRASH("[M] does not have DNA")
if(se)
for(var/i=1, i<=DNA_MUTATION_BLOCKS, i++)
if(prob(probability))
@@ -577,9 +723,13 @@
if(ui)
for(var/i=1, i<=DNA_UNI_IDENTITY_BLOCKS, i++)
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 TRUE
+ M.dna.unique_identity = setblock(M.dna.unique_identity, i, random_string(DNA_BLOCK_SIZE, GLOB.hex_characters))
+ if(uf)
+ for(var/i in 1 to DNA_FEATURE_BLOCKS)
+ if(prob(probability))
+ M.dna.unique_features = setblock(M.dna.unique_features, i, random_string(DNA_BLOCK_SIZE, 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
diff --git a/code/datums/mutations/actions.dm b/code/datums/mutations/actions.dm
index fbeb30dafaa..0af9fe6d2cc 100644
--- a/code/datums/mutations/actions.dm
+++ b/code/datums/mutations/actions.dm
@@ -56,7 +56,7 @@
var/list/prints = sniffed.return_fingerprints()
if(prints)
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 6b9db21b3be..5c28eec9e0d 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 6a22e6c002c..bdb2f068012 100644
--- a/code/datums/weather/weather_types/radiation_storm.dm
+++ b/code/datums/weather/weather_types/radiation_storm.dm
@@ -35,12 +35,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/computer/dna_console.dm b/code/game/machinery/computer/dna_console.dm
index ad2d7544133..1971f67b239 100644
--- a/code/game/machinery/computer/dna_console.dm
+++ b/code/game/machinery/computer/dna_console.dm
@@ -37,6 +37,9 @@
/// The base cooldown of the ability to copy enzymes and genetic makeup to people.
#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."
@@ -88,6 +91,8 @@
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)
@@ -144,7 +149,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
@@ -308,7 +313,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
@@ -510,12 +516,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()
@@ -1161,8 +1167,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)
@@ -1203,6 +1210,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")
if(!COOLDOWN_FINISHED(src, enzyme_copy_timer))
@@ -1248,6 +1256,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())
@@ -1256,12 +1279,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
@@ -1284,7 +1307,8 @@
// Expected results:
// "ue" - Unique Enzyme, changes name and blood type
// "ui" - Unique Identity, changes looks
- // "mixed" - Combination of both ue and ui
+ // "uf" - Unique Features, changes mutant bodyparts and mutcolors
+ // "mixed" - Combination of ue, ui, and uf
if("makeup_apply")
// GUARD CHECK - Can we genetically modify the occupant? Includes scanner
// operational guard checks.
@@ -1324,7 +1348,8 @@
// Expected results:
// "ue" - Unique Enzyme, changes name and blood type
// "ui" - Unique Identity, changes looks
- // "mixed" - Combination of both ue and ui
+ // "uf" - Unique Features, changes mutant bodyparts and mutcolors
+ // "mixed" - Combination of ue, ui, and uf
if("makeup_delay")
// Convert the index to a number and clamp within the array range, then
// copy the data from the disk to that buffer
@@ -1347,6 +1372,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")
@@ -1355,9 +1384,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()
@@ -1583,11 +1619,24 @@
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.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
@@ -1607,12 +1656,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
COOLDOWN_START(src, enzyme_copy_timer, ENZYME_COPY_BASE_COOLDOWN)
- scanner_occupant.dna.uni_identity = buffer_slot["UI"]
- scanner_occupant.updateappearance(mutations_overlay_update=1)
+ 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"]
@@ -2099,20 +2149,38 @@
// 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/objects/items/dna_injector.dm b/code/game/objects/items/dna_injector.dm
index de411e38e2c..d5ccf441bd1 100644
--- a/code/game/objects/items/dna_injector.dm
+++ b/code/game/objects/items/dna_injector.dm
@@ -41,8 +41,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
@@ -484,10 +487,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 227b922e79b..7a2a91161ff 100644
--- a/code/game/objects/structures/mirror.dm
+++ b/code/game/objects/structures/mirror.dm
@@ -216,6 +216,7 @@
if(ReadHSV(temp_hsv)[3] >= ReadHSV("#7F7F7F")[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."))
diff --git a/code/modules/admin/verbs/anonymousnames.dm b/code/modules/admin/verbs/anonymousnames.dm
index 83e4bf43cc2..fdbf33dd777 100644
--- a/code/modules/admin/verbs/anonymousnames.dm
+++ b/code/modules/admin/verbs/anonymousnames.dm
@@ -93,11 +93,13 @@ GLOBAL_DATUM(current_anonymous_theme, /datum/anonymous_theme)
if(issilicon(player))
player.fully_replace_character_name(player.real_name, theme.anonymous_ai_name(isAI(player)))
else
+ var/mob/living/carbon/human/human_mob = player
var/original_name = player.real_name //id will not be changed if you do not do this
randomize_human(player) //do this first so the special name can be given
player.fully_replace_character_name(original_name, theme.anonymous_name(player))
if(extras_enabled)
player_extras(player)
+ human_mob.dna.update_dna_identity()
/**
* restore_all_players: sets all crewmembers on station back to their preference name.
diff --git a/code/modules/admin/verbs/secrets.dm b/code/modules/admin/verbs/secrets.dm
index 0baf2b45c4f..e6ebd73c6b1 100644
--- a/code/modules/admin/verbs/secrets.dm
+++ b/code/modules/admin/verbs/secrets.dm
@@ -138,7 +138,7 @@
for(var/i in GLOB.human_list)
var/mob/living/carbon/human/H = i
if(H.ckey)
- dat += "
| [H] | [md5(H.dna.uni_identity)] |
"
+ dat += "| [H] | [md5(H.dna.unique_identity)] |
"
dat += ""
holder << browse(dat, "window=fingerprints;size=440x410")
if("ctfbutton")
diff --git a/code/modules/antagonists/abductor/equipment/glands/transform.dm b/code/modules/antagonists/abductor/equipment/glands/transform.dm
index 71c8acc376b..7b7a00fde8a 100644
--- a/code/modules/antagonists/abductor/equipment/glands/transform.dm
+++ b/code/modules/antagonists/abductor/equipment/glands/transform.dm
@@ -13,3 +13,4 @@
randomize_human(owner)
var/species = pick(list(/datum/species/human, /datum/species/lizard, /datum/species/moth, /datum/species/fly))
owner.set_species(species)
+ owner.dna.update_dna_identity()
diff --git a/code/modules/antagonists/eldritch_cult/eldritch_knowledge.dm b/code/modules/antagonists/eldritch_cult/eldritch_knowledge.dm
index 4e8d50da730..955b6c8575e 100644
--- a/code/modules/antagonists/eldritch_cult/eldritch_knowledge.dm
+++ b/code/modules/antagonists/eldritch_cult/eldritch_knowledge.dm
@@ -156,7 +156,7 @@
var/list/compiled_list = list()
for(var/mob/living/carbon/human/human_to_check as anything in GLOB.human_list)
- if(fingerprints[md5(human_to_check.dna.uni_identity)])
+ if(fingerprints[md5(human_to_check.dna.unique_identity)])
compiled_list |= human_to_check.real_name
compiled_list[human_to_check.real_name] = human_to_check
diff --git a/code/modules/detectivework/scanner.dm b/code/modules/detectivework/scanner.dm
index 0ca22a13d7c..04d92cfb662 100644
--- a/code/modules/detectivework/scanner.dm
+++ b/code/modules/detectivework/scanner.dm
@@ -98,7 +98,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 72493ab6a71..9cae45b5b8b 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 31864ed2769..2d08583d760 100644
--- a/code/modules/events/spacevine.dm
+++ b/code/modules/events/spacevine.dm
@@ -474,8 +474,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/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 792a51f711e..e8d318d2c43 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -1285,7 +1285,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if(radiation > RAD_MOB_MUTATE && DT_PROB(RAD_MOB_MUTATE_PROB, delta_time))
to_chat(source, span_danger("You mutate!"))
- source.easy_randmut(NEGATIVE + MINOR_NEGATIVE)
+ source.easy_random_mutate(NEGATIVE + MINOR_NEGATIVE)
source.emote("gasp")
source.domutcheck()
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 ddc21c64f6b..a6e9f682e12 100644
--- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
@@ -242,6 +242,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/life.dm b/code/modules/mob/living/carbon/life.dm
index 3574646d94e..c8f3ff39510 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -437,11 +437,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/ninja/suit/ninja_equipment_actions/ninja_status_read.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_status_read.dm
index 90824fe934b..720aa7967b5 100644
--- a/code/modules/ninja/suit/ninja_equipment_actions/ninja_status_read.dm
+++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_status_read.dm
@@ -19,7 +19,7 @@
info_list += "[span_info("SpiderOS Status: [s_initialized ? "Initialized" : "Disabled"]")]\n"
info_list += "[span_info("Current Time: [station_time_timestamp()]")]\n"
//Ninja status
- info_list += "[span_info("Fingerprints: [md5(ninja.dna.uni_identity)]")]\n"
+ info_list += "[span_info("Fingerprints: [md5(ninja.dna.unique_identity)]")]\n"
info_list += "[span_info("Unique Identity: [ninja.dna.unique_enzymes]")]\n"
info_list += "[span_info("Overall Status: [ninja.stat > 1 ? "dead" : "[ninja.health]% healthy"]")]\n"
info_list += "[span_info("Nutrition Status: [ninja.nutrition]")]\n"
diff --git a/code/modules/projectiles/projectile/special/floral.dm b/code/modules/projectiles/projectile/special/floral.dm
index eec59e009bd..221a19dce07 100644
--- a/code/modules/projectiles/projectile/special/floral.dm
+++ b/code/modules/projectiles/projectile/special/floral.dm
@@ -18,10 +18,11 @@
if(iscarbon(L) && L.has_dna())
var/mob/living/carbon/C = L
if(prob(80))
- C.easy_randmut(NEGATIVE + MINOR_NEGATIVE)
+ C.easy_random_mutate(NEGATIVE + MINOR_NEGATIVE)
else
- C.easy_randmut(POSITIVE)
- C.randmuti()
+ C.easy_random_mutate(POSITIVE)
+ C.random_mutate_unique_identity()
+ C.random_mutate_unique_features()
C.domutcheck()
else
L.adjustFireLoss(rand(5, 15))
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index a21e5f4e550..6db590f9b48 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -717,6 +717,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 007a0c6310d..0ad7cb5541b 100644
--- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
@@ -50,11 +50,12 @@
if(!exposed_mob.has_dna() || HAS_TRAIT(exposed_mob, TRAIT_GENELESS) || HAS_TRAIT(exposed_mob, TRAIT_BADDNA))
return //No robots, AIs, aliens, Ians or other mobs should be affected by this.
if(((methods & VAPOR) && prob(min(33, reac_volume))) || (methods & (INGEST|PATCH|INJECT)))
- exposed_mob.randmuti()
+ exposed_mob.random_mutate_unique_identity()
+ exposed_mob.random_mutate_unique_features()
if(prob(98))
- exposed_mob.easy_randmut(NEGATIVE+MINOR_NEGATIVE)
+ exposed_mob.easy_random_mutate(NEGATIVE+MINOR_NEGATIVE)
else
- exposed_mob.easy_randmut(POSITIVE)
+ exposed_mob.easy_random_mutate(POSITIVE)
exposed_mob.updateappearance()
exposed_mob.domutcheck()
diff --git a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
index 7b279fd72ab..906ade0b1f7 100644
--- a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
+++ b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
@@ -776,6 +776,7 @@
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 174af38a95e..68f07a8b71b 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -606,6 +606,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 6bba1917aae..f58361a85b3 100644
--- a/code/modules/ruins/icemoonruin_code/hotsprings.dm
+++ b/code/modules/ruins/icemoonruin_code/hotsprings.dm
@@ -42,7 +42,7 @@ GLOBAL_LIST_EMPTY(cursed_minds)
all_species += stype
var/random_race = pick(all_species)
H.set_species(random_race)
- H.dna.unique_enzymes = H.dna.generate_unique_enzymes()
+ H.dna.update_dna_identity()
L = H
var/turf/T = find_safe_turf()
L.forceMove(T)
diff --git a/code/modules/shuttle/medisim.dm b/code/modules/shuttle/medisim.dm
index b9f06143ff2..d51297a786d 100644
--- a/code/modules/shuttle/medisim.dm
+++ b/code/modules/shuttle/medisim.dm
@@ -26,6 +26,7 @@
return
var/mob/living/carbon/human/human_knight = .
randomize_human(human_knight)
+ human_knight.dna.update_dna_identity()
human_knight.dna.add_mutation(MEDIEVAL, MUT_OTHER)
var/oldname = human_knight.name
var/title = "error"
diff --git a/code/modules/station_goals/dna_vault.dm b/code/modules/station_goals/dna_vault.dm
index f0f6251feff..12ae1cc52ac 100644
--- a/code/modules/station_goals/dna_vault.dm
+++ b/code/modules/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/surgery/advanced/wingreconstruction.dm b/code/modules/surgery/advanced/wingreconstruction.dm
index 0d5517fb617..9670ce11765 100644
--- a/code/modules/surgery/advanced/wingreconstruction.dm
+++ b/code/modules/surgery/advanced/wingreconstruction.dm
@@ -39,5 +39,10 @@
human_target.dna.features["moth_wings"] = human_target.dna.features["original_moth_wings"]
else
human_target.dna.features["moth_wings"] = "Plain"
+ //SKYRAT EDIT REMOVAL BEGIN - CUSTOMIZATION
+ /*
+ human_target.dna.update_uf_block(DNA_MOTH_WINGS_BLOCK)
+ */
+ //SKYRAT EDIT REMOVAL END
human_target.update_mutant_bodyparts()
return ..()
diff --git a/code/modules/surgery/organs/tails.dm b/code/modules/surgery/organs/tails.dm
index 8e05321c8b3..84be97c3fa5 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/Insert(mob/living/carbon/human/tail_owner, special = FALSE, drop_if_replaced = TRUE)
@@ -28,13 +29,16 @@
if(istype(tail_owner))
var/default_part = tail_owner.dna.species.mutant_bodyparts["tail_human"]
if(!default_part || default_part == "None")
- tail_owner.dna.features["tail_human"] = tail_owner.dna.species.mutant_bodyparts["tail_human"] = tail_type
+ if(tail_type)
+ tail_owner.dna.features["tail_human"] = tail_owner.dna.species.mutant_bodyparts["tail_human"] = tail_type
+ tail_owner.dna.update_uf_block(DNA_HUMAN_TAIL_BLOCK)
+ else
+ tail_owner.dna.species.mutant_bodyparts["tail_human"] = tail_owner.dna.features["tail_human"]
tail_owner.update_body()
/obj/item/organ/tail/cat/Remove(mob/living/carbon/human/tail_owner, special = FALSE)
..()
if(istype(tail_owner))
- tail_owner.dna.features["tail_human"] = "None"
tail_owner.dna.species.mutant_bodyparts -= "tail_human"
color = tail_owner.hair_color
tail_owner.update_body()
@@ -46,6 +50,7 @@
desc = "A severed lizard tail. Somewhere, no doubt, a lizard hater is very pleased with themselves."
color = "#116611"
tail_type = "Smooth"
+ /// 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/spines = "None"
//SKYRAT EDIT REMOVAL BEGIN - CUSTOMIZATION
@@ -60,18 +65,25 @@
// Checks here are necessary so it wouldn't overwrite the tail of a lizard it spawned in
var/default_part = tail_owner.dna.species.mutant_bodyparts["tail_lizard"]
if(!default_part || default_part == "None")
- tail_owner.dna.features["tail_lizard"] = tail_owner.dna.species.mutant_bodyparts["tail_lizard"] = tail_type
+ if(tail_type)
+ tail_owner.dna.features["tail_lizard"] = tail_owner.dna.species.mutant_bodyparts["tail_lizard"] = tail_type
+ tail_owner.dna.update_uf_block(DNA_LIZARD_TAIL_BLOCK)
+ else
+ tail_owner.dna.species.mutant_bodyparts["tail_lizard"] = tail_owner.dna.features["tail_lizard"]
default_part = tail_owner.dna.species.mutant_bodyparts["spines"]
if(!default_part || default_part == "None")
- tail_owner.dna.features["spines"] = tail_owner.dna.species.mutant_bodyparts["spines"] = spines
+ if(spines)
+ tail_owner.dna.features["spines"] = tail_owner.dna.species.mutant_bodyparts["spines"] = spines
+ tail_owner.dna.update_uf_block(DNA_SPINES_BLOCK)
+ else
+ tail_owner.dna.species.mutant_bodyparts["spines"] = tail_owner.dna.features["spines"]
tail_owner.update_body()
/obj/item/organ/tail/lizard/Remove(mob/living/carbon/human/tail_owner, special = FALSE)
..()
if(istype(tail_owner))
tail_owner.dna.species.mutant_bodyparts -= "tail_lizard"
- tail_owner.dna.species.mutant_bodyparts -= "spines"
color = "#" + tail_owner.dna.features["mcolor"]
tail_type = tail_owner.dna.features["tail_lizard"]
spines = tail_owner.dna.features["spines"]
@@ -92,6 +104,8 @@
/obj/item/organ/tail/lizard/fake
name = "fabricated lizard tail"
desc = "A fabricated severed lizard tail. This one's made of synthflesh. Probably not usable for lizard wine."
+ tail_type = null
+ spines = null
/obj/item/organ/tail/monkey
name = "monkey tail"
@@ -106,13 +120,14 @@
if(istype(tail_owner))
if(!("tail_monkey" in tail_owner.dna.species.mutant_bodyparts))
tail_owner.dna.species.mutant_bodyparts |= "tail_monkey"
- tail_owner.dna.features["tail_monkey"] = tail_type
+ if(tail_type)
+ tail_owner.dna.features["tail_monkey"] = tail_type
+ tail_owner.dna.update_uf_block(DNA_MONKEY_TAIL_BLOCK)
tail_owner.update_body()
/obj/item/organ/tail/monkey/Remove(mob/living/carbon/human/tail_owner, special = FALSE)
..()
if(istype(tail_owner))
- tail_owner.dna.features["tail_monkey"] = "None"
tail_owner.dna.species.mutant_bodyparts -= "tail_monkey"
tail_owner.update_body()
*/
diff --git a/modular_skyrat/modules/customization/__DEFINES/DNA.dm b/modular_skyrat/modules/customization/__DEFINES/DNA.dm
new file mode 100644
index 00000000000..390a60a87eb
--- /dev/null
+++ b/modular_skyrat/modules/customization/__DEFINES/DNA.dm
@@ -0,0 +1,3 @@
+#define DNA_BLOCKS_PER_FEATURE 4
+#define DNA_BLOCKS_PER_MARKING 2
+#define DNA_BLOCKS_PER_MARKING_ZONE 1+MAXIMUM_MARKINGS_PER_LIMB*DNA_BLOCKS_PER_MARKING
diff --git a/modular_skyrat/modules/customization/__DEFINES/lists.dm b/modular_skyrat/modules/customization/__DEFINES/lists.dm
index 2973dbdfaa6..3be48a849c3 100644
--- a/modular_skyrat/modules/customization/__DEFINES/lists.dm
+++ b/modular_skyrat/modules/customization/__DEFINES/lists.dm
@@ -1,5 +1,6 @@
GLOBAL_LIST_EMPTY(sprite_accessories)
GLOBAL_LIST_EMPTY(generic_accessories)
+GLOBAL_LIST_EMPTY(genetic_accessories)
GLOBAL_LIST_EMPTY(body_markings)
GLOBAL_LIST_EMPTY_TYPED(body_markings_per_limb, /list)
@@ -11,3 +12,6 @@ GLOBAL_LIST_EMPTY(loadout_category_to_subcategory_to_items)
GLOBAL_LIST_EMPTY(augment_items)
GLOBAL_LIST_EMPTY(augment_categories_to_slots)
GLOBAL_LIST_EMPTY(augment_slot_to_items)
+
+GLOBAL_LIST_EMPTY(dna_mutant_bodypart_blocks)
+GLOBAL_LIST_EMPTY(dna_body_marking_blocks)
diff --git a/modular_skyrat/modules/customization/__HELPERS/dna.dm b/modular_skyrat/modules/customization/__HELPERS/dna.dm
new file mode 100644
index 00000000000..188f4d821da
--- /dev/null
+++ b/modular_skyrat/modules/customization/__HELPERS/dna.dm
@@ -0,0 +1 @@
+GLOBAL_VAR_INIT(dna_total_feature_blocks, DNA_MANDATORY_COLOR_BLOCKS)
diff --git a/modular_skyrat/modules/customization/__HELPERS/global_lists.dm b/modular_skyrat/modules/customization/__HELPERS/global_lists.dm
index e69e469f8db..e17f955fbe4 100644
--- a/modular_skyrat/modules/customization/__HELPERS/global_lists.dm
+++ b/modular_skyrat/modules/customization/__HELPERS/global_lists.dm
@@ -2,6 +2,7 @@
make_sprite_accessory_references()
make_body_marking_references()
make_body_marking_set_references()
+ make_body_marking_dna_block_references()
make_loadout_references()
make_augment_references()
make_culture_references()
@@ -38,6 +39,13 @@
if(!GLOB.sprite_accessories[P.key])
GLOB.sprite_accessories[P.key] = list()
GLOB.sprite_accessories[P.key][P.name] = P
+ if(P.genetic)
+ if(!GLOB.dna_mutant_bodypart_blocks[P.key])
+ GLOB.dna_mutant_bodypart_blocks[P.key] = GLOB.dna_total_feature_blocks+1
+ if(!GLOB.genetic_accessories[P.key])
+ GLOB.genetic_accessories[P.key] = list()
+ GLOB.dna_total_feature_blocks += DNA_BLOCKS_PER_FEATURE
+ GLOB.genetic_accessories[P.key] += P.name
//TODO: Replace "generic" definitions with something better
if(P.generic && !GLOB.generic_accessories[P.key])
GLOB.generic_accessories[P.key] = P.generic
@@ -65,6 +73,11 @@
BM = new path()
GLOB.body_marking_sets[BM.name] = BM
+/proc/make_body_marking_dna_block_references()
+ for(var/marking_zone in GLOB.marking_zones)
+ GLOB.dna_body_marking_blocks[marking_zone] = GLOB.dna_total_feature_blocks+1
+ GLOB.dna_total_feature_blocks += DNA_BLOCKS_PER_MARKING_ZONE
+
/proc/make_loadout_references()
// Here we build the global loadout lists
for(var/path in subtypesof(/datum/loadout_item))
diff --git a/modular_skyrat/modules/customization/datums/dna.dm b/modular_skyrat/modules/customization/datums/dna.dm
index 4ae0cac112e..310f6619dd9 100644
--- a/modular_skyrat/modules/customization/datums/dna.dm
+++ b/modular_skyrat/modules/customization/datums/dna.dm
@@ -10,11 +10,117 @@
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 = species.get_random_features()
mutant_bodyparts = species.get_random_mutant_bodyparts(features)
+ unique_features = generate_unique_features()
+
+/datum/dna/proc/generate_unique_features()
+ var/list/data = list()
+
+ if(features["mcolor"])
+ data += sanitize_hexcolor(features["mcolor"])
+ else
+ data += random_string(DNA_BLOCK_SIZE,GLOB.hex_characters)
+ if(features["mcolor2"])
+ data += sanitize_hexcolor(features["mcolor2"])
+ else
+ data += random_string(DNA_BLOCK_SIZE,GLOB.hex_characters)
+ if(features["mcolor3"])
+ data += sanitize_hexcolor(features["mcolor3"])
+ else
+ data += random_string(DNA_BLOCK_SIZE,GLOB.hex_characters)
+ if(features["ethcolor"])
+ data += sanitize_hexcolor(features["ethcolor"])
+ else
+ data += random_string(DNA_BLOCK_SIZE,GLOB.hex_characters)
+ if(features["skin_color"])
+ data += sanitize_hexcolor(features["skin_color"])
+ else
+ data += random_string(DNA_BLOCK_SIZE,GLOB.hex_characters)
+ for(var/key in GLOB.genetic_accessories)
+ if(mutant_bodyparts[key] && (mutant_bodyparts[key][MUTANT_INDEX_NAME] in GLOB.genetic_accessories[key]))
+ var/list/accessories_for_key = GLOB.genetic_accessories[key]
+ data += construct_block(accessories_for_key.Find(mutant_bodyparts[key][MUTANT_INDEX_NAME]), accessories_for_key.len)
+ var/colors_to_randomize = DNA_BLOCKS_PER_FEATURE-1
+ for(var/color in mutant_bodyparts[key][MUTANT_INDEX_COLOR_LIST])
+ colors_to_randomize--
+ data += sanitize_hexcolor(color)
+ if(colors_to_randomize)
+ data += random_string(DNA_BLOCK_SIZE*colors_to_randomize,GLOB.hex_characters)
+ else
+ data += random_string(DNA_BLOCK_SIZE*DNA_BLOCKS_PER_FEATURE,GLOB.hex_characters)
+ for(var/zone in GLOB.marking_zones)
+ if(body_markings[zone])
+ data += construct_block(body_markings[zone].len+1, MAXIMUM_MARKINGS_PER_LIMB+1)
+ var/list/marking_list = GLOB.body_markings_per_limb[zone]
+ var/markings_to_randomize = MAXIMUM_MARKINGS_PER_LIMB
+ for(var/marking in body_markings[zone])
+ markings_to_randomize--
+ data += construct_block(marking_list.Find(marking), marking_list.len)
+ data += sanitize_hexcolor(body_markings[zone][marking])
+ if(markings_to_randomize)
+ data += random_string(DNA_BLOCK_SIZE*markings_to_randomize*DNA_BLOCKS_PER_MARKING,GLOB.hex_characters)
+ else
+ data += construct_block(1, MAXIMUM_MARKINGS_PER_LIMB+1)
+ data += random_string(DNA_BLOCK_SIZE*MAXIMUM_MARKINGS_PER_LIMB*DNA_BLOCKS_PER_MARKING,GLOB.hex_characters)
+ return data.Join()
+
+/datum/dna/proc/update_uf_block(blocknumber)
+ if(!blocknumber)
+ CRASH("UF block index is null")
+ if(blocknumber<1 || blocknumber>DNA_FEATURE_BLOCKS)
+ CRASH("UF block index out of bounds")
+ if(!ishuman(holder))
+ CRASH("Non-human mobs shouldn't have DNA")
+ if(blocknumber <= DNA_MANDATORY_COLOR_BLOCKS)
+ switch(blocknumber)
+ if(DNA_MUTANT_COLOR_BLOCK)
+ setblock(unique_features, blocknumber, sanitize_hexcolor(features["mcolor"]))
+ if(DNA_MUTANT_COLOR_2_BLOCK)
+ setblock(unique_features, blocknumber, sanitize_hexcolor(features["mcolor2"]))
+ if(DNA_MUTANT_COLOR_3_BLOCK)
+ setblock(unique_features, blocknumber, sanitize_hexcolor(features["mcolor3"]))
+ if(DNA_ETHEREAL_COLOR_BLOCK)
+ setblock(unique_features, blocknumber, sanitize_hexcolor(features["ethcolor"]))
+ if(DNA_SKIN_COLOR_BLOCK)
+ setblock(unique_features, blocknumber, sanitize_hexcolor(features["skin_color"]))
+ else if(blocknumber <= DNA_MANDATORY_COLOR_BLOCKS+(GLOB.genetic_accessories.len*DNA_BLOCKS_PER_FEATURE))
+ var/block_index = blocknumber - DNA_MANDATORY_COLOR_BLOCKS
+ var/block_zero_index = block_index-1
+ var/bodypart_index = (block_zero_index/DNA_BLOCKS_PER_FEATURE)+1
+ var/color_index = block_zero_index%DNA_BLOCKS_PER_FEATURE
+ var/key = GLOB.genetic_accessories[bodypart_index]
+ if(mutant_bodyparts[key])
+ var/list/color_list = mutant_bodyparts[key][MUTANT_INDEX_COLOR_LIST]
+ if(color_index && color_index <= color_list.len)
+ setblock(unique_features, blocknumber, sanitize_hexcolor(color_list[color_index]))
+ else
+ var/list/accessories_for_key = GLOB.genetic_accessories[key]
+ if(mutant_bodyparts[key][MUTANT_INDEX_NAME] in accessories_for_key)
+ setblock(unique_features, blocknumber, construct_block(mutant_bodyparts.Find(mutant_bodyparts[key][MUTANT_INDEX_NAME]), accessories_for_key.len))
+ else
+ var/block_index = blocknumber - (DNA_MANDATORY_COLOR_BLOCKS+(GLOB.genetic_accessories.len*DNA_BLOCKS_PER_FEATURE))
+ var/block_zero_index = block_index-1
+ var/zone_index = (block_zero_index/DNA_BLOCKS_PER_MARKING_ZONE)+1
+ var/zone = GLOB.marking_zones[zone_index]
+ if(blocknumber == GLOB.dna_body_marking_blocks[zone])
+ var/markings = 0
+ if(body_markings[zone])
+ markings = body_markings[zone].len
+ setblock(unique_features, blocknumber, construct_block(markings+1, MAXIMUM_MARKINGS_PER_LIMB+1))
+ else
+ var/color_block = ((block_zero_index%DNA_BLOCKS_PER_MARKING_ZONE)+1)%DNA_BLOCKS_PER_MARKING
+ var/marking_index = (((block_zero_index-1)%DNA_BLOCKS_PER_MARKING_ZONE)/DNA_BLOCKS_PER_MARKING)+1
+ if(body_markings[zone] && marking_index <= body_markings[zone].len)
+ var/marking = body_markings[zone][marking_index]
+ if(color_block)
+ setblock(unique_features, blocknumber, sanitize_hexcolor(body_markings[zone][marking]))
+ else
+ var/list/marking_list = GLOB.body_markings_per_limb[zone]
+ setblock(unique_features, blocknumber, construct_block(marking_list.Find(marking), marking_list.len))
/datum/dna/proc/update_body_size()
if(!holder || current_body_size == features["body_size"])
@@ -42,7 +148,6 @@
var/datum/species/old_species = dna.species
dna.species = new_race
//BODYPARTS AND FEATURES
- var/list/bodyparts_to_add
if(pref_load)
dna.features = pref_load.features.Copy()
dna.real_name = pref_load.real_name
@@ -65,15 +170,8 @@
dna.body_markings = override_markings || new_race.get_random_body_markings(dna.features)
dna.species.body_markings = dna.body_markings.Copy()
- bodyparts_to_add = dna.mutant_bodyparts.Copy()
-
- for(var/key in bodyparts_to_add)
- var/datum/sprite_accessory/SP = GLOB.sprite_accessories[key][bodyparts_to_add[key][MUTANT_INDEX_NAME]]
- if(!SP.factual)
- bodyparts_to_add -= key
- continue
-
- dna.species.mutant_bodyparts = bodyparts_to_add.Copy()
+ copy_mutant_parts_to_species()
+ dna.unique_features = dna.generate_unique_features()
dna.update_body_size()
@@ -84,3 +182,73 @@
var/species_holder = initial(mrace.species_language_holder)
language_holder = new species_holder(src, pref_load)
update_atom_languages()
+
+/mob/living/carbon/proc/copy_mutant_parts_to_species()
+ if(!has_dna())
+ CRASH("[src] does not have DNA")
+ var/list/bodyparts_to_add = dna.mutant_bodyparts.Copy()
+ for(var/key in bodyparts_to_add)
+ var/datum/sprite_accessory/SP = GLOB.sprite_accessories[key][bodyparts_to_add[key][MUTANT_INDEX_NAME]]
+ if(!SP.factual)
+ bodyparts_to_add -= key
+ continue
+ dna.species.mutant_bodyparts = bodyparts_to_add.Copy()
+
+/mob/living/carbon/human/updateappearance(icon_update=1, mutcolor_update=0, mutations_overlay_update=0)
+ ..()
+ var/structure = dna.unique_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_hairstyle = GLOB.facial_hairstyles_list[deconstruct_block(getblock(structure, DNA_FACIAL_HAIRSTYLE_BLOCK), GLOB.facial_hairstyles_list.len)]
+ hairstyle = GLOB.hairstyles_list[deconstruct_block(getblock(structure, DNA_HAIRSTYLE_BLOCK), GLOB.hairstyles_list.len)]
+ var/features = dna.unique_features
+ if(dna.features["mcolor"])
+ dna.features["mcolor"] = sanitize_hexcolor(getblock(features, DNA_MUTANT_COLOR_BLOCK))
+ if(dna.features["mcolor2"])
+ dna.features["mcolor2"] = sanitize_hexcolor(getblock(features, DNA_MUTANT_COLOR_2_BLOCK))
+ if(dna.features["mcolor3"])
+ dna.features["mcolor3"] = sanitize_hexcolor(getblock(features, DNA_MUTANT_COLOR_3_BLOCK))
+ if(dna.features["ethcolor"])
+ dna.features["ethcolor"] = sanitize_hexcolor(getblock(features, DNA_ETHEREAL_COLOR_BLOCK))
+ if(dna.features["skin_color"])
+ dna.features["skin_color"] = sanitize_hexcolor(getblock(features, DNA_SKIN_COLOR_BLOCK))
+ for(var/key in GLOB.genetic_accessories)
+ if(dna.mutant_bodyparts[key] && (dna.mutant_bodyparts[key][MUTANT_INDEX_NAME] in GLOB.genetic_accessories[key]))
+ var/bodypart_block = GLOB.dna_mutant_bodypart_blocks[key]
+ var/list/accessories_for_key = GLOB.sprite_accessories[key]
+ var/list/possible_accessories = GLOB.genetic_accessories[key]
+ var/accessory_name = GLOB.genetic_accessories[key][deconstruct_block(getblock(features, bodypart_block), possible_accessories.len)]
+ dna.mutant_bodyparts[key][MUTANT_INDEX_NAME] = accessory_name
+ var/datum/sprite_accessory/accessory_to_apply = accessories_for_key[accessory_name]
+ if(accessory_to_apply.factual)
+ switch(accessory_to_apply.color_src)
+ if(USE_ONE_COLOR)
+ dna.mutant_bodyparts[key][MUTANT_INDEX_COLOR_LIST] = list(sanitize_hexcolor(getblock(features,bodypart_block+1)))
+ if(USE_MATRIXED_COLORS)
+ dna.mutant_bodyparts[key][MUTANT_INDEX_COLOR_LIST] = list(sanitize_hexcolor(getblock(features,bodypart_block+1)), sanitize_hexcolor(getblock(features,bodypart_block+2)), sanitize_hexcolor(getblock(features,bodypart_block+3)))
+ for(var/zone in GLOB.marking_zones)
+ var/marking_count_block = GLOB.dna_body_marking_blocks[zone]
+ var/first_marking_block = marking_count_block+1
+ var/marking_count = deconstruct_block(getblock(features, marking_count_block), 4)-1
+ if(!marking_count && dna.body_markings[zone])
+ dna.body_markings -= zone
+ if(marking_count)
+ if(!dna.body_markings[zone])
+ dna.body_markings[zone] = list()
+ dna.body_markings[zone].len = marking_count
+ for(var/i in 1 to marking_count)
+ var/marking = GLOB.body_markings_per_limb[zone][deconstruct_block(getblock(features, first_marking_block+(i-1)*DNA_BLOCKS_PER_MARKING), GLOB.body_markings_per_limb[zone].len)]
+ dna.body_markings[zone][i] = marking
+ dna.body_markings[zone][marking] = sanitize_hexcolor(getblock(features, first_marking_block+(i-1)*DNA_BLOCKS_PER_MARKING+1))
+ dna.species.body_markings = dna.body_markings.Copy()
+ copy_mutant_parts_to_species()
+
+ if(icon_update)
+ 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()
+ if(mutations_overlay_update)
+ update_mutations_overlay()
diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories.dm
index 3dcab75c3dd..0faa779a232 100644
--- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories.dm
+++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories.dm
@@ -39,6 +39,8 @@
var/extra2_color_src
///If defined, the accessory will be only available to ckeys inside the list. ITS ASSOCIATIVE, ie. ("ckey" = TRUE). For speed
var/list/ckey_whitelist
+ ///Whether this feature is genetic, and thus modifiable by DNA consoles
+ var/genetic = FALSE
/datum/sprite_accessory/New()
if(!default_color)
@@ -106,6 +108,7 @@
default_color = DEFAULT_SECONDARY
recommended_species = list("lizard", "unathi", "ashlizard", "silverlizard")
relevent_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER)
+ genetic = TRUE
/datum/sprite_accessory/spines/is_hidden(mob/living/carbon/human/H, obj/item/bodypart/HD)
var/obj/item/organ/tail/T = H.getorganslot(ORGAN_SLOT_TAIL)
@@ -132,6 +135,7 @@
key = "legs"
generic = "Leg Type"
color_src = null
+ genetic = TRUE
/datum/sprite_accessory/socks
icon = 'modular_skyrat/master_files/icons/mob/clothing/underwear.dmi'
diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/ears.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/ears.dm
index c8121d9ef75..758cd534b41 100644
--- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/ears.dm
+++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/ears.dm
@@ -3,6 +3,7 @@
generic = "Ears"
organ_type = /obj/item/organ/ears/mutant
relevent_layers = list(BODY_ADJ_LAYER, BODY_FRONT_LAYER)
+ genetic = TRUE
/datum/sprite_accessory/ears/is_hidden(mob/living/carbon/human/H, obj/item/bodypart/HD)
if(H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD)
diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/fluff.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/fluff.dm
index 86519df41fd..3a3876e678d 100644
--- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/fluff.dm
+++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/fluff.dm
@@ -5,6 +5,7 @@
generic = "Fluff"
recommended_species = list("moth", "synthmammal", "mammal", "insect")
relevent_layers = list(BODY_ADJ_LAYER, BODY_FRONT_LAYER)
+ genetic = TRUE
/datum/sprite_accessory/fluff/moth/none
name = "None"
diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/frills.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/frills.dm
index 6265a7384b1..4d31102a957 100644
--- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/frills.dm
+++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/frills.dm
@@ -3,6 +3,7 @@
generic = "Frills"
default_color = DEFAULT_SECONDARY
relevent_layers = list(BODY_ADJ_LAYER)
+ genetic = TRUE
/datum/sprite_accessory/frills/is_hidden(mob/living/carbon/human/H, obj/item/bodypart/HD)
if(H.head && (H.try_hide_mutant_parts || (H.head.flags_inv & HIDEEARS) || !HD || HD.status == BODYPART_ROBOTIC))
diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/genitals.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/genitals.dm
index f71f3fd65bc..2192abb2d8a 100644
--- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/genitals.dm
+++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/genitals.dm
@@ -39,6 +39,7 @@
special_x_dimension = TRUE
//default_color = DEFAULT_SKIN_OR_PRIMARY //This is the price we're paying for sheaths
relevent_layers = list(BODY_BEHIND_LAYER, BODY_FRONT_LAYER)
+ genetic = TRUE
var/can_have_sheath = TRUE
/datum/sprite_accessory/genital/penis/is_hidden(mob/living/carbon/human/H, obj/item/bodypart/HD)
@@ -118,6 +119,7 @@
special_x_dimension = TRUE
default_color = DEFAULT_SKIN_OR_PRIMARY
relevent_layers = list(BODY_ADJ_LAYER, BODY_BEHIND_LAYER)
+ genetic = TRUE
var/has_size = TRUE
/datum/sprite_accessory/genital/testicles/is_hidden(mob/living/carbon/human/H, obj/item/bodypart/HD)
@@ -166,6 +168,7 @@
always_color_customizable = TRUE
default_color = "fcc"
relevent_layers = list(BODY_FRONT_LAYER)
+ genetic = TRUE
var/alt_aroused = TRUE
/datum/sprite_accessory/genital/vagina/is_hidden(mob/living/carbon/human/H, obj/item/bodypart/HD)
@@ -226,6 +229,7 @@
organ_type = /obj/item/organ/genital/womb
associated_organ_slot = ORGAN_SLOT_WOMB
key = "womb"
+ genetic = TRUE
/datum/sprite_accessory/genital/womb/none
icon_state = "none"
@@ -248,6 +252,7 @@
relevent_layers = list(BODY_BEHIND_LAYER, BODY_FRONT_LAYER)
uses_skintones = TRUE
genital_location = CHEST
+ genetic = TRUE
/datum/sprite_accessory/genital/breasts/is_hidden(mob/living/carbon/human/H, obj/item/bodypart/HD)
if(H.undershirt != "Nude" && !(H.underwear_visibility & UNDERWEAR_HIDE_SHIRT))
diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/head_accessory.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/head_accessory.dm
index 89d8d253885..d3bb3156229 100644
--- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/head_accessory.dm
+++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/head_accessory.dm
@@ -3,6 +3,7 @@
key = "head_acc"
generic = "Head Accessory"
relevent_layers = list(BODY_ADJ_LAYER, BODY_FRONT_LAYER)
+ genetic = TRUE
/datum/sprite_accessory/head_accessory/none
name = "None"
diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/horns.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/horns.dm
index 81baebcb39e..b48dc588bdf 100644
--- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/horns.dm
+++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/horns.dm
@@ -4,6 +4,7 @@
relevent_layers = list(BODY_FRONT_LAYER)
icon = 'modular_skyrat/master_files/icons/mob/sprite_accessory/horns.dmi'
default_color = "555"
+ genetic = TRUE
/datum/sprite_accessory/horns/is_hidden(mob/living/carbon/human/H, obj/item/bodypart/HD)
if(H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD)
diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/ipc.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/ipc.dm
index eaf77ef6689..2814febdb6e 100644
--- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/ipc.dm
+++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/ipc.dm
@@ -141,6 +141,7 @@
key = "ipc_antenna"
generic = "Antenna"
relevent_layers = list(BODY_ADJ_LAYER)
+ genetic = FALSE
/datum/sprite_accessory/antenna/is_hidden(mob/living/carbon/human/H, obj/item/bodypart/HD)
if(H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD)
diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/moth_antennae.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/moth_antennae.dm
index 325ddc95c58..9765eb549df 100644
--- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/moth_antennae.dm
+++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/moth_antennae.dm
@@ -2,6 +2,7 @@
generic = "Moth Antennae"
key = "moth_antennae"
relevent_layers = list(BODY_BEHIND_LAYER, BODY_FRONT_LAYER)
+ genetic = TRUE
/datum/sprite_accessory/moth_antennae/is_hidden(mob/living/carbon/human/H, obj/item/bodypart/HD)
if(H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD)
diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/neck_accessory.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/neck_accessory.dm
index 3c1223d2252..187e9bb7afc 100644
--- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/neck_accessory.dm
+++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/neck_accessory.dm
@@ -3,6 +3,7 @@
key = "neck_acc"
generic = "Neck Accessory"
relevent_layers = list(BODY_ADJ_LAYER, BODY_FRONT_LAYER)
+ genetic = TRUE
/datum/sprite_accessory/neck_accessory/none
name = "None"
diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/skrell_hair.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/skrell_hair.dm
index 9db3327cc51..84934a2f3b5 100644
--- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/skrell_hair.dm
+++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/skrell_hair.dm
@@ -4,6 +4,7 @@
key = "skrell_hair"
color_src = USE_ONE_COLOR
relevent_layers = list(BODY_ADJ_LAYER, BODY_FRONT_LAYER)
+ genetic = TRUE
/datum/sprite_accessory/skrell_hair/is_hidden(mob/living/carbon/human/H, obj/item/bodypart/HD)
if(H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)))
diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/snout.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/snout.dm
index 609b0c9ed2a..4e7cbd05299 100644
--- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/snout.dm
+++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/snout.dm
@@ -5,6 +5,7 @@
var/use_muzzled_sprites = TRUE
recommended_species = list("synthmammal", "mammal", "lizard", "unathi", "ashlizard", "silverlizard")
relevent_layers = list(BODY_ADJ_LAYER, BODY_FRONT_LAYER)
+ genetic = TRUE
/datum/sprite_accessory/snouts/is_hidden(mob/living/carbon/human/H, obj/item/bodypart/HD)
if((H.wear_mask && (H.wear_mask.flags_inv & HIDEFACE)) || (H.head && (H.head.flags_inv & HIDEFACE)) || !HD)
diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/synthliz.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/synthliz.dm
index 2e3589da443..5beb11e7b1b 100644
--- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/synthliz.dm
+++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/synthliz.dm
@@ -6,6 +6,7 @@
default_color = null
name = "Synthetic Lizard - Snout"
icon_state = "synthliz_basic"
+ genetic = FALSE
/datum/sprite_accessory/snouts/synthliz/synthliz_under
color_src = USE_MATRIXED_COLORS
@@ -77,6 +78,7 @@
name = "Synthetic Lizard"
icon_state = "synthliz"
general_type = "lizard"
+ genetic = FALSE
//Synth Antennae
/datum/sprite_accessory/antenna/synthliz
@@ -143,6 +145,7 @@
icon_state = "synthlizard"
taur_mode = STYLE_TAUR_PAW
recommended_species = list("synthliz")
+ genetic = FALSE
/datum/sprite_accessory/taur/synthliz/inv
name = "Cybernetic Lizard (Inverted)"
diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/tails.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/tails.dm
index d365b5608db..952bd6dacd0 100644
--- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/tails.dm
+++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/tails.dm
@@ -7,6 +7,7 @@
special_icon_case = TRUE
special_colorize = TRUE
relevent_layers = list(BODY_BEHIND_LAYER, BODY_FRONT_LAYER)
+ genetic = TRUE
/// A generalisation of the tail-type, e.g. lizard or feline, for hardsuit or other sprites
var/general_type
diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/taur_types.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/taur_types.dm
index 0de965e9bd7..3fc25a80eb9 100644
--- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/taur_types.dm
+++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/taur_types.dm
@@ -6,6 +6,7 @@
dimension_x = 64
center = TRUE
relevent_layers = list(BODY_ADJ_LAYER, BODY_FRONT_LAYER)
+ genetic = TRUE
var/taur_mode = NONE //Must be a single specific tauric suit variation bitflag. Don't do FLAG_1|FLAG_2
var/alt_taur_mode = NONE //Same as above.
var/hide_legs = TRUE
diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/wings.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/wings.dm
index 827ff49be5e..af14d5f20f1 100644
--- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/wings.dm
+++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/wings.dm
@@ -9,6 +9,7 @@
recommended_species = list("human", "synthhuman", "felinid", "lizard", "synthmammal", "mammal", "synthliz")
organ_type = /obj/item/organ/wings
relevent_layers = list(BODY_BEHIND_LAYER, BODY_FRONT_LAYER, BODY_ADJ_LAYER)
+ genetic = TRUE
/datum/sprite_accessory/wings/is_hidden(mob/living/carbon/human/H, obj/item/bodypart/HD)
if(H.wear_suit && H.try_hide_mutant_parts)
@@ -165,6 +166,7 @@
name = "Dragon (synthetic alt)"
icon_state = "dragonsynth"
color_src = USE_MATRIXED_COLORS
+ genetic = FALSE
/datum/sprite_accessory/wings/mammal/dragon_alt1
name = "Dragon (alt 1)"
diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/xeno.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/xeno.dm
index 00a77bb8660..9dde393d798 100644
--- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/xeno.dm
+++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/xeno.dm
@@ -4,6 +4,7 @@
key = "xenodorsal"
color_src = USE_ONE_COLOR
relevent_layers = list(BODY_BEHIND_LAYER, BODY_FRONT_LAYER)
+ genetic = TRUE
/datum/sprite_accessory/xenodorsal/standard
name = "Standard"
@@ -30,6 +31,7 @@
generic = "Caste Head"
key = "xenohead"
relevent_layers = list(BODY_ADJ_LAYER)
+ genetic = TRUE
/datum/sprite_accessory/xenohead/standard
name = "Standard"
diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/roundstartslime.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/roundstartslime.dm
index 0234524268b..60d918ce3db 100644
--- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/roundstartslime.dm
+++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/roundstartslime.dm
@@ -71,15 +71,25 @@
DNA.features["mcolor"] = sanitize_hexcolor(new_mutantcolor)
DNA.features["mcolor2"] = sanitize_hexcolor(new_mutantcolor)
DNA.features["mcolor3"] = sanitize_hexcolor(new_mutantcolor)
+ DNA.update_uf_block(DNA_MUTANT_COLOR_BLOCK)
+ DNA.update_uf_block(DNA_MUTANT_COLOR_2_BLOCK)
+ DNA.update_uf_block(DNA_MUTANT_COLOR_3_BLOCK)
else
DNA.features[color_target] = sanitize_hexcolor(new_mutantcolor)
+ switch(color_target)
+ if("mcolor")
+ DNA.update_uf_block(DNA_MUTANT_COLOR_BLOCK)
+ if("mcolor2")
+ DNA.update_uf_block(DNA_MUTANT_COLOR_2_BLOCK)
+ if("mcolor3")
+ DNA.update_uf_block(DNA_MUTANT_COLOR_3_BLOCK)
if(marking_reset && marking_reset == "Yes")
- for(var/zone in DNA.body_markings)
- for(var/key in DNA.body_markings[zone])
+ for(var/zone in DNA.species.body_markings)
+ for(var/key in DNA.species.body_markings[zone])
var/datum/body_marking/BD = GLOB.body_markings[key]
if(BD.always_color_customizable)
continue
- DNA.body_markings[zone][key] = BD.get_default_color(DNA.features, DNA.species)
+ DNA.species.body_markings[zone][key] = BD.get_default_color(DNA.features, DNA.species)
H.icon_render_key = "" //Currently the render key doesnt recognize the markings colors
if(mutantpart_reset && mutantpart_reset == "Yes")
H.mutant_renderkey = "" //Just in case
@@ -146,6 +156,7 @@
new_acc_list[MUTANT_INDEX_COLOR_LIST] = SA.get_default_color(DNA.features, DNA.species)
DNA.species.mutant_bodyparts[chosen_key] = new_acc_list
DNA.mutant_bodyparts[chosen_key] = new_acc_list.Copy()
+ DNA.update_uf_block(GLOB.dna_mutant_bodypart_blocks[chosen_key])
if (chosen_key == "legs" && chosen_name_key != "Cancel")
if (chosen_name_key == "Digitigrade Legs" && !(DIGITIGRADE in DNA.species.species_traits))
DNA.species.species_traits += DIGITIGRADE
diff --git a/tgstation.dme b/tgstation.dme
index 632af6e52d1..6b6c0ffc346 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -3950,8 +3950,10 @@
#include "modular_skyrat\modules\cum\effects\cumface.dm"
#include "modular_skyrat\modules\cum\effects\cumstain.dm"
#include "modular_skyrat\modules\customization\__DEFINES\augment.dm"
+#include "modular_skyrat\modules\customization\__DEFINES\DNA.dm"
#include "modular_skyrat\modules\customization\__DEFINES\lists.dm"
#include "modular_skyrat\modules\customization\__DEFINES\loadout.dm"
+#include "modular_skyrat\modules\customization\__HELPERS\dna.dm"
#include "modular_skyrat\modules\customization\__HELPERS\global_lists.dm"
#include "modular_skyrat\modules\customization\__HELPERS\mobs.dm"
#include "modular_skyrat\modules\customization\__HELPERS\names.dm"
diff --git a/tgui/packages/tgui/interfaces/DnaConsole/DnaConsoleEnzymes.js b/tgui/packages/tgui/interfaces/DnaConsole/DnaConsoleEnzymes.js
index 23819a67c97..fa4eb9fc15d 100644
--- a/tgui/packages/tgui/interfaces/DnaConsole/DnaConsoleEnzymes.js
+++ b/tgui/packages/tgui/interfaces/DnaConsole/DnaConsoleEnzymes.js
@@ -69,6 +69,25 @@ const GeneticMakeupBufferInfo = (props, context) => {
{!isViableSubject && ' (Delayed)'}
+
+
{
};
const RadiationEmitterPulseBoard = (props, context) => {
- const { data, act } = useBackend(context);
+ const { act } = useBackend(context);
const {
- subjectUNI = [],
- } = data;
+ subjectBlock = [],
+ type,
+ name,
+ } = props;
// Build blocks of buttons of unique enzymes
const blocks = [];
let buffer = [];
- for (let i = 0; i < subjectUNI.length; i++) {
- const char = subjectUNI.charAt(i);
+ for (let i = 0; i < subjectBlock.length; i++) {
+ const char = subjectBlock.charAt(i);
// Push a button into the buffer
const button = (
{
content={char}
onClick={() => act('makeup_pulse', {
index: i + 1,
+ type: type,
})} />
);
buffer.push(button);
@@ -241,7 +263,7 @@ const RadiationEmitterPulseBoard = (props, context) => {
}
return (
@@ -296,6 +318,11 @@ export const DnaConsoleEnzymes = (props, context) => {
const {
isScannerConnected,
} = data;
+ const {
+ subjectBlock,
+ type,
+ name,
+ } = props;
if (!isScannerConnected) {
return (
@@ -313,7 +340,10 @@ export const DnaConsoleEnzymes = (props, context) => {
-
+
diff --git a/tgui/packages/tgui/interfaces/DnaConsole/GeneticMakeupInfo.js b/tgui/packages/tgui/interfaces/DnaConsole/GeneticMakeupInfo.js
index f78f5d1ef6b..a53706e2211 100644
--- a/tgui/packages/tgui/interfaces/DnaConsole/GeneticMakeupInfo.js
+++ b/tgui/packages/tgui/interfaces/DnaConsole/GeneticMakeupInfo.js
@@ -18,6 +18,9 @@ export const GeneticMakeupInfo = (props, context) => {
{makeup.UI || 'None'}
+
+ {makeup.UF || 'None'}
+
);
diff --git a/tgui/packages/tgui/interfaces/DnaConsole/constants.js b/tgui/packages/tgui/interfaces/DnaConsole/constants.js
index 49fe557d361..ca3b732582f 100644
--- a/tgui/packages/tgui/interfaces/DnaConsole/constants.js
+++ b/tgui/packages/tgui/interfaces/DnaConsole/constants.js
@@ -3,6 +3,7 @@ export const CHROMOSOME_NONE = 1;
export const CHROMOSOME_USED = 2;
export const CONSOLE_MODE_ENZYMES = 'enzymes';
+export const CONSOLE_MODE_FEATURES = 'features';
export const CONSOLE_MODE_SEQUENCER = 'sequencer';
export const CONSOLE_MODE_STORAGE = 'storage';
diff --git a/tgui/packages/tgui/interfaces/DnaConsole/index.js b/tgui/packages/tgui/interfaces/DnaConsole/index.js
index 3b55c4d47a3..e456ee8270d 100644
--- a/tgui/packages/tgui/interfaces/DnaConsole/index.js
+++ b/tgui/packages/tgui/interfaces/DnaConsole/index.js
@@ -5,7 +5,7 @@ import { DnaConsoleEnzymes } from './DnaConsoleEnzymes';
import { DnaConsoleSequencer } from './DnaConsoleSequencer';
import { DnaConsoleStorage } from './DnaConsoleStorage';
import { DnaScanner } from './DnaScanner';
-import { CONSOLE_MODE_ENZYMES, CONSOLE_MODE_SEQUENCER, CONSOLE_MODE_STORAGE, STORAGE_MODE_CONSOLE } from './constants';
+import { CONSOLE_MODE_ENZYMES, CONSOLE_MODE_FEATURES, CONSOLE_MODE_SEQUENCER, CONSOLE_MODE_STORAGE, STORAGE_MODE_CONSOLE } from './constants';
const DnaConsoleCommands = (props, context) => {
const { data, act } = useBackend(context);
@@ -42,6 +42,12 @@ const DnaConsoleCommands = (props, context) => {
onClick={() => act('set_view', {
consoleMode: CONSOLE_MODE_ENZYMES,
})} />
+ act('set_view', {
+ consoleMode: CONSOLE_MODE_FEATURES,
+ })} />
{!!hasDisk && (
@@ -66,6 +72,8 @@ export const DnaConsole = (props, context) => {
const {
isPulsingRads,
radPulseSeconds,
+ subjectUNI,
+ subjectUF,
} = data;
const { consoleMode } = data.view;
return (
@@ -96,7 +104,16 @@ export const DnaConsole = (props, context) => {
)}
{consoleMode === CONSOLE_MODE_ENZYMES && (
-
+
+ )}
+ {consoleMode === CONSOLE_MODE_FEATURES && (
+
)}