diff --git a/code/datums/dna.dm b/code/datums/dna.dm
index 5759cb356131..1f63ec6b2908 100644
--- a/code/datums/dna.dm
+++ b/code/datums/dna.dm
@@ -55,8 +55,9 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
var/datum/blood_type/blood_type
///The type of mutant race the player is if applicable (i.e. potato-man)
var/datum/species/species = new /datum/species/human
- ///first value is mutant color
- var/list/features = list("FFF")
+ /// Assoc list of feature keys to their value
+ /// Note if you set these manually, and do not update [unique_features] afterwards, it will likely be reset.
+ var/list/features = list("mcolor" = COLOR_WHITE)
///Stores the hashed values of the person's non-human features
var/unique_features
///Stores the real name of the person who originally got this dna datum. Used primarely for changelings,
@@ -548,27 +549,28 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
return dna
-/mob/living/carbon/human/proc/hardset_dna(ui, list/mutation_index, list/default_mutation_genes, newreal_name, newblood_type, datum/species/mrace, newfeatures, list/mutations, force_transfer_mutations)
+/// Sets the DNA of the mob to the given DNA.
+/mob/living/carbon/human/proc/hardset_dna(unique_identity, list/mutation_index, list/default_mutation_genes, newreal_name, newblood_type, datum/species/mrace, newfeatures, list/mutations, force_transfer_mutations)
//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
newrace.copy_properties_from(mrace)
- set_species(newrace, icon_update=0)
+ set_species(newrace, icon_update = 0)
if(newreal_name)
- real_name = newreal_name
+ dna.real_name = newreal_name
dna.generate_unique_enzymes()
if(newblood_type)
dna.blood_type = newblood_type
- if(ui)
- dna.unique_identity = ui
- updateappearance(icon_update=0)
+ if(unique_identity)
+ dna.unique_identity = unique_identity
+ updateappearance(icon_update = 0)
+
+ if(newfeatures)
+ dna.features = newfeatures
+ dna.generate_unique_features()
if(LAZYLEN(mutation_index))
dna.mutation_index = mutation_index.Copy()
@@ -578,17 +580,14 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
dna.default_mutation_genes = mutation_index.Copy()
domutcheck()
- if(mrace || newfeatures || ui)
+ if(mrace || newfeatures || unique_identity)
update_body()
update_hair()
- update_body_parts()
update_mutations_overlay()
- if(LAZYLEN(mutations))
- for(var/M in mutations)
- var/datum/mutation/human/HM = M
- if(HM.allow_transfer || force_transfer_mutations)
- dna.force_give(new HM.type(HM.class, copymut=HM)) //using force_give since it may include exotic mutations that otherwise wont be handled properly
+ if(LAZYLEN(mutations) && force_transfer_mutations)
+ for(var/datum/mutation/human/mutation as anything in mutations)
+ dna.force_give(new mutation.type(mutation.class, copymut = mutation)) //using force_give since it may include exotic mutations that otherwise won't be handled properly
/mob/living/carbon/proc/create_dna()
dna = new /datum/dna(src)
diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm
index a2bd62aa885f..c1872e0782c2 100644
--- a/code/game/machinery/computer/cloning.dm
+++ b/code/game/machinery/computer/cloning.dm
@@ -19,6 +19,7 @@
//select which parts of the diskette to load
var/include_se = FALSE //mutations
var/include_ui = FALSE //appearance
+ var/include_uf = FALSE //features
var/include_ue = FALSE //blood type, UE, and name
var/loading = FALSE // Nice loading text
@@ -63,7 +64,22 @@
. = pod
/proc/grow_clone_from_record(obj/machinery/clonepod/pod, datum/data/record/R, empty)
- return pod.growclone(R.fields["name"], R.fields["UI"], R.fields["SE"], R.fields["makeup"], R.fields["mindref"], R.fields["last_death"], R.fields["mrace"], R.fields["features"], R.fields["factions"], R.fields["quirks"], R.fields["bank_account"], R.fields["traumas"], empty, R.fields["mood"])
+ return pod.growclone(
+ clonename = R.fields["name"],
+ ui = R.fields["UI"],
+ mutation_index = R.fields["SE"],
+ makeup = R.fields["makeup"],
+ mindref = R.fields["mindref"],
+ last_death = R.fields["last_death"],
+ mrace = R.fields["mrace"],
+ features = R.fields["features"],
+ factions = R.fields["factions"],
+ quirks = R.fields["quirks"],
+ insurance = R.fields["bank_account"],
+ traumas = R.fields["traumas"],
+ empty = empty,
+ mood = R.fields["mood"],
+ )
/obj/machinery/computer/cloning/process()
if(!(scanner && LAZYLEN(pods) && autoprocess))
@@ -259,6 +275,7 @@
dat += "Unable to locate Health Implant.
"
dat += "Unique Identifier:
[span_highlight("[active_record.fields["UI"]]")]
"
+ dat += "Unique Features:
[span_highlight("[active_record.fields["UF"]]")]
"
dat += "Structural Enzymes:
"
for(var/key in active_record.fields["SE"])
if(key != RACEMUT)
@@ -273,10 +290,13 @@
dat += "Inserted Disk
"
dat += "Contents: "
var/list/L = list()
- if(diskette.fields["UI"])
- L += "Unique Identifier"
+
if(diskette.fields["UE"] && diskette.fields["name"] && diskette.fields["blood_type"])
L += "Unique Enzymes"
+ if(diskette.fields["UI"])
+ L += "Unique Identifier"
+ if(diskette.fields["UF"])
+ L += "Unique Features"
if(diskette.fields["SE"])
L += "Structural Enzymes"
dat += english_list(L, "Empty", " + ", " + ")
@@ -441,6 +461,7 @@
overwrite_field_if_available(active_record, diskette, "blood_type")
if(include_ui)
overwrite_field_if_available(active_record, diskette, "UI")
+ overwrite_field_if_available(active_record, diskette, "UF")
if(include_se)
overwrite_field_if_available(active_record, diskette, "SE")
@@ -552,11 +573,12 @@
R.fields["name"] = mob_occupant.real_name
R.fields["id"] = copytext_char(md5(mob_occupant.real_name), 2, 6)
- R.fields["UE"] = dna.unique_enzymes
- R.fields["UI"] = dna.unique_identity
+ R.fields["UE"] = "[dna.unique_enzymes]"
+ R.fields["UI"] = "[dna.unique_identity]"
+ R.fields["UF"] = "[dna.unique_features]"
R.fields["SE"] = dna.mutation_index
R.fields["blood_type"] = dna.blood_type
- R.fields["features"] = dna.features
+ R.fields["features"] = dna.features.Copy()
R.fields["makeup"] = dna.default_mutation_genes
R.fields["factions"] = mob_occupant.faction
R.fields["quirks"] = list()
diff --git a/code/game/machinery/computer/dna_console.dm b/code/game/machinery/computer/dna_console.dm
index 451b2b09bbb0..6886963b44f9 100644
--- a/code/game/machinery/computer/dna_console.dm
+++ b/code/game/machinery/computer/dna_console.dm
@@ -210,7 +210,7 @@
stored_research = SSresearch.science_tech
/obj/machinery/computer/scan_consolenew/ui_interact(mob/user, datum/tgui/ui)
-
+ . = ..()
// Most of ui_interact is spent setting variables for passing to the tgui
// interface.
// We can also do some general state processing here too as it's a good
@@ -302,7 +302,7 @@
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
data["subjectName"] = null
data["subjectStatus"] = null
@@ -1143,7 +1143,13 @@
return
I = new /obj/item/dnainjector/timed(loc)
- 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"])
+ 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
@@ -1506,7 +1512,7 @@
scanner_occupant.real_name = buffer_slot["name"]
scanner_occupant.name = buffer_slot["name"]
scanner_occupant.dna.unique_enzymes = buffer_slot["UE"]
- scanner_occupant.dna.blood_type = buffer_slot["blood_type"]
+ scanner_occupant.dna.blood_type = get_blood_type(buffer_slot["blood_type"])
scanner_occupant.radiation += rad_increase
scanner_occupant.domutcheck()
return TRUE
@@ -1524,7 +1530,7 @@
scanner_occupant.real_name = buffer_slot["name"]
scanner_occupant.name = buffer_slot["name"]
scanner_occupant.dna.unique_enzymes = buffer_slot["UE"]
- scanner_occupant.dna.blood_type = buffer_slot["blood_type"]
+ scanner_occupant.dna.blood_type = get_blood_type(buffer_slot["blood_type"])
scanner_occupant.radiation += rad_increase
scanner_occupant.domutcheck()
return TRUE
diff --git a/code/game/machinery/exp_cloner.dm b/code/game/machinery/exp_cloner.dm
index 33951f8e8d4b..906deac653f9 100644
--- a/code/game/machinery/exp_cloner.dm
+++ b/code/game/machinery/exp_cloner.dm
@@ -9,7 +9,7 @@
internal_radio = FALSE
//Start growing a human clone in the pod!
-/obj/machinery/clonepod/experimental/growclone(clonename, ui, mutation_index, makeup, mindref, last_death, datum/species/mrace, list/features, factions, list/quirks, datum/bank_account/insurance)
+/obj/machinery/clonepod/experimental/growclone(clonename, ui, mutation_index, makeup, mindref, last_death, datum/species/mrace, list/features, factions, list/quirks, datum/bank_account/insurance, list/traumas, empty, mood)
if(panel_open)
return NONE
if(mess || attempting)
diff --git a/code/game/objects/items/dna_injector.dm b/code/game/objects/items/dna_injector.dm
index be60945b4233..747b52904c15 100644
--- a/code/game/objects/items/dna_injector.dm
+++ b/code/game/objects/items/dna_injector.dm
@@ -45,7 +45,7 @@
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)
+ M.updateappearance(mutcolor_update = TRUE, mutations_overlay_update = TRUE)
log_attack("[log_msg] [loc_name(user)]")
return TRUE
return FALSE
diff --git a/code/modules/hydroponics/grown/replicapod.dm b/code/modules/hydroponics/grown/replicapod.dm
index 059974178c25..256fb0feb04a 100644
--- a/code/modules/hydroponics/grown/replicapod.dm
+++ b/code/modules/hydroponics/grown/replicapod.dm
@@ -112,12 +112,11 @@
podman.ckey = ckey_holder
podman.gender = blood_gender
podman.faction |= factions
- if(!features["mcolor"])
- features["mcolor"] = "#59CE00"
+
for(var/V in quirks)
new V(podman)
- podman.hardset_dna(null,null,null,podman.real_name,blood_type, new /datum/species/pod,features)//Discard SE's and UI's, podman cloning is inaccurate, and always make them a podman
- podman.set_cloned_appearance()
+ podman.hardset_dna(null, null, null, podman.real_name, blood_type, /datum/species/pod, features)//Discard SE's and UI's, podman cloning is inaccurate, and always make them a podman
+
podman.dna.species.exotic_blood = max(reagents_add) || /datum/reagent/water
log_cloning("[key_name(mind)] cloned as a podman via [src] in [parent] at [AREACOORD(parent)].")
to_chat(podman, span_userdanger("You do not remember your death, how you died, or who killed you. See rule 1.6.")) //yogs
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index af39fdd088d5..6cb8f5e9b1e9 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -514,6 +514,7 @@
underwear = "Nude"
update_body()
update_hair()
+ dna.update_dna_identity()
/mob/living/carbon/human/singularity_pull(S, current_size)
..()
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index a892565fa24f..e48767e4b7c7 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -55,12 +55,10 @@ There are several things that need to be remembered:
//used when putting/removing clothes that hide certain mutant body parts to just update those and not update the whole body.
/mob/living/carbon/human/proc/update_mutant_bodyparts()
- dna.species.handle_mutant_bodyparts(src)
-
+ dna?.species.handle_mutant_bodyparts(src)
/mob/living/carbon/human/update_body()
- remove_overlay(BODY_LAYER)
- dna.species.handle_body(src)
+ dna?.species.handle_body(src)
..()
/mob/living/carbon/human/update_fire()
@@ -887,4 +885,3 @@ generate/load female uniform sprites matching all previously decided variables
update_inv_wear_mask()
#undef RESOLVE_ICON_STATE
-
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index 8a9406445741..4c4036b9b159 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -1,5 +1,4 @@
/datum/reagent/blood
- data = list("donor"=null,"viruses"=null,"blood_DNA"=null,"blood_type"=null,"resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null,"cloneable"=null,"factions"=null,"quirks"=null)
name = "Blood"
color = COLOR_BLOOD
metabolization_rate = 5 //fast rate so it disappears fast.
@@ -10,6 +9,22 @@
glass_desc = "Are you sure this is tomato juice?"
shot_glass_icon_state = "shotglassred"
+ data = list(
+ "donor" = null,
+ "viruses" = null,
+ "blood_DNA" = null,
+ "blood_type" = null,
+ "resistances" = null,
+ "trace_chem" = null,
+ "mind" = null,
+ "ckey" = null,
+ "gender" = null,
+ "real_name" = null,
+ "cloneable" = null,
+ "factions" = null,
+ "quirks" = null
+ )
+
/datum/reagent/blood/reaction_mob(mob/living/L, methods=TOUCH, reac_volume, show_message = TRUE, permeability = 1)
var/datum/antagonist/bloodsucker/bloodsuckerdatum = IS_BLOODSUCKER(L) //bloodsucker start
if(bloodsuckerdatum)