diff --git a/code/datums/dna.dm b/code/datums/dna.dm
index b3f3f7efa1..938515625d 100644
--- a/code/datums/dna.dm
+++ b/code/datums/dna.dm
@@ -9,6 +9,7 @@
var/list/features = list("FFF") //first value is mutant color
var/real_name //Stores the real name of the person who originally got this dna datum. Used primarely for changelings,
var/nameless = FALSE
+ var/custom_species //siiiiigh I guess this is important
var/list/mutations = list() //All mutations are from now on here
var/list/temporary_mutations = list() //Timers for temporary mutations
var/list/previous = list() //For temporary name/ui/ue/blood_type modifications
@@ -45,6 +46,7 @@
destination.dna.features = features.Copy()
destination.dna.real_name = real_name
destination.dna.nameless = nameless
+ destination.dna.custom_species = custom_species
destination.dna.temporary_mutations = temporary_mutations.Copy()
if(ishuman(destination))
var/mob/living/carbon/human/H = destination
@@ -62,6 +64,7 @@
new_dna.species = new species.type
new_dna.real_name = real_name
new_dna.nameless = nameless
+ new_dna.custom_species = custom_species
new_dna.mutations = mutations.Copy()
/datum/dna/proc/add_mutation(mutation_name)
@@ -202,7 +205,7 @@
/datum/dna/proc/is_same_as(datum/dna/D)
- if(uni_identity == D.uni_identity && struc_enzymes == D.struc_enzymes && real_name == D.real_name && nameless == D.nameless)
+ if(uni_identity == D.uni_identity && struc_enzymes == D.struc_enzymes && real_name == D.real_name && nameless == D.nameless && custom_species == D.custom_species)
if(species.type == D.species.type && features == D.features && blood_type == D.blood_type)
return 1
return 0
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index 5a68a8423a..79b04c771b 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -98,10 +98,12 @@ SLIME SCANNER
if ((user.has_trait(TRAIT_CLUMSY) || user.has_trait(TRAIT_DUMB)) && prob(50))
to_chat(user, "You stupidly try to analyze the floor's vitals!")
user.visible_message("[user] has analyzed the floor's vitals!")
- to_chat(user, "Analyzing results for The floor:\n\tOverall status: Healthy")
- to_chat(user, "Key: Suffocation/Toxin/Burn/Brute")
- to_chat(user, "\tDamage specifics: 0-0-0-0")
- to_chat(user, "Body temperature: ???")
+ var/msg = "*---------*\nAnalyzing results for The floor:\n\tOverall status: Healthy\n"
+ msg += "Key: Suffocation/Toxin/Burn/Brute\n"
+ msg += "\tDamage specifics: 0-0-0-0\n"
+ msg += "Body temperature: ???\n"
+ msg += "*---------*"
+ to_chat(user, msg)
return
user.visible_message("[user] has analyzed [M]'s vitals.")
@@ -136,31 +138,31 @@ SLIME SCANNER
if(H.undergoing_liver_failure() && H.stat != DEAD)
to_chat(user, "Subject is suffering from liver failure: Apply Corazone and begin a liver transplant immediately!")
- to_chat(user, "Analyzing results for [M]:\n\tOverall status: [mob_status]")
+ var/msg = "*---------*\nAnalyzing results for [M]:\n\tOverall status: [mob_status]\n"
// Damage descriptions
if(brute_loss > 10)
- to_chat(user, "\t[brute_loss > 50 ? "Severe" : "Minor"] tissue damage detected.")
+ msg += "\t[brute_loss > 50 ? "Severe" : "Minor"] tissue damage detected.\n"
if(fire_loss > 10)
- to_chat(user, "\t[fire_loss > 50 ? "Severe" : "Minor"] burn damage detected.")
+ msg += "\t[fire_loss > 50 ? "Severe" : "Minor"] burn damage detected.\n"
if(oxy_loss > 10)
- to_chat(user, "\t[oxy_loss > 50 ? "Severe" : "Minor"] oxygen deprivation detected.")
+ msg += "\t[oxy_loss > 50 ? "Severe" : "Minor"] oxygen deprivation detected.\n"
if(tox_loss > 10)
- to_chat(user, "\t[tox_loss > 50 ? "Severe" : "Minor"] amount of toxin damage detected.")
+ msg += "\t[tox_loss > 50 ? "Severe" : "Minor"] amount of toxin damage detected.\n"
if(M.getStaminaLoss())
- to_chat(user, "\tSubject appears to be suffering from fatigue.")
+ msg += "\tSubject appears to be suffering from fatigue.\n"
if(advanced)
- to_chat(user, "\tFatigue Level: [M.getStaminaLoss()]%.")
+ msg += "\tFatigue Level: [M.getStaminaLoss()]%.\n"
if (M.getCloneLoss())
- to_chat(user, "\tSubject appears to have [M.getCloneLoss() > 30 ? "Severe" : "Minor"] cellular damage.")
+ msg += "\tSubject appears to have [M.getCloneLoss() > 30 ? "Severe" : "Minor"] cellular damage.\n"
if(advanced)
- to_chat(user, "\tCellular Damage Level: [M.getCloneLoss()].")
+ msg += "\tCellular Damage Level: [M.getCloneLoss()].\n"
if (M.getBrainLoss() >= 200 || !M.getorgan(/obj/item/organ/brain))
- to_chat(user, "\tSubject's brain function is non-existent.")
+ msg += "\tSubject's brain function is non-existent.\n"
else if (M.getBrainLoss() >= 120)
- to_chat(user, "\tSevere brain damage detected. Subject likely to have mental traumas.")
+ msg += "\tSevere brain damage detected. Subject likely to have mental traumas.\n"
else if (M.getBrainLoss() >= 45)
- to_chat(user, "\tBrain damage detected.")
+ msg += "\tBrain damage detected.\n"
if(iscarbon(M))
var/mob/living/carbon/C = M
if(LAZYLEN(C.get_traumas()))
@@ -176,83 +178,83 @@ SLIME SCANNER
trauma_desc += "permanent "
trauma_desc += B.scan_desc
trauma_text += trauma_desc
- to_chat(user, "\tCerebral traumas detected: subject appears to be suffering from [english_list(trauma_text)].")
+ msg += "\tCerebral traumas detected: subject appears to be suffering from [english_list(trauma_text)].\n"
if(C.roundstart_quirks.len)
- to_chat(user, "\tSubject has the following physiological traits: [C.get_trait_string()].")
+ msg += "\tSubject has the following physiological traits: [C.get_trait_string()].\n"
if(advanced)
- to_chat(user, "\tBrain Activity Level: [(200 - M.getBrainLoss())/2]%.")
+ msg += "\tBrain Activity Level: [(200 - M.getBrainLoss())/2]%.\n"
if (M.radiation)
- to_chat(user, "\tSubject is irradiated.")
+ msg += "\tSubject is irradiated.\n"
if(advanced)
- to_chat(user, "\tRadiation Level: [M.radiation]%.")
+ msg += "\tRadiation Level: [M.radiation]%.\n"
if(advanced && M.hallucinating())
- to_chat(user, "\tSubject is hallucinating.")
+ msg += "\tSubject is hallucinating.\n"
//Eyes and ears
if(advanced)
if(iscarbon(M))
var/mob/living/carbon/C = M
var/obj/item/organ/ears/ears = C.getorganslot(ORGAN_SLOT_EARS)
- to_chat(user, "\t==EAR STATUS==")
+ msg += "\t==EAR STATUS==\n"
if(istype(ears))
var/healthy = TRUE
if(C.has_trait(TRAIT_DEAF, GENETIC_MUTATION))
healthy = FALSE
- to_chat(user, "\tSubject is genetically deaf.")
+ msg += "\tSubject is genetically deaf.\n"
else if(C.has_trait(TRAIT_DEAF))
healthy = FALSE
- to_chat(user, "\tSubject is deaf.")
+ msg += "\tSubject is deaf.\n"
else
if(ears.ear_damage)
- to_chat(user, "\tSubject has [ears.ear_damage > UNHEALING_EAR_DAMAGE? "permanent ": "temporary "]hearing damage.")
+ msg += "\tSubject has [ears.ear_damage > UNHEALING_EAR_DAMAGE? "permanent ": "temporary "]hearing damage.\n"
healthy = FALSE
if(ears.deaf)
- to_chat(user, "\tSubject is [ears.ear_damage > UNHEALING_EAR_DAMAGE ? "permanently ": "temporarily "] deaf.")
+ msg += "\tSubject is [ears.ear_damage > UNHEALING_EAR_DAMAGE ? "permanently ": "temporarily "] deaf.\n"
healthy = FALSE
if(healthy)
- to_chat(user, "\tHealthy.")
+ msg += "\tHealthy.\n"
else
- to_chat(user, "\tSubject does not have ears.")
+ msg += "\tSubject does not have ears.\n"
var/obj/item/organ/eyes/eyes = C.getorganslot(ORGAN_SLOT_EYES)
- to_chat(user, "\t==EYE STATUS==")
+ msg += "\t==EYE STATUS==\n"
if(istype(eyes))
var/healthy = TRUE
if(C.has_trait(TRAIT_BLIND))
- to_chat(user, "\tSubject is blind.")
+ msg += "\tSubject is blind.\n"
healthy = FALSE
if(C.has_trait(TRAIT_NEARSIGHT))
- to_chat(user, "\tSubject is nearsighted.")
+ msg += "\tSubject is nearsighted.\n"
healthy = FALSE
if(eyes.eye_damage > 30)
- to_chat(user, "\tSubject has severe eye damage.")
+ msg += "\tSubject has severe eye damage.\n"
healthy = FALSE
else if(eyes.eye_damage > 20)
- to_chat(user, "\tSubject has significant eye damage.")
+ msg += "\tSubject has significant eye damage.\n"
healthy = FALSE
else if(eyes.eye_damage)
- to_chat(user, "\tSubject has minor eye damage.")
+ msg += "\tSubject has minor eye damage.\n"
healthy = FALSE
if(healthy)
- to_chat(user, "\tHealthy.")
+ msg += "\tHealthy.\n"
else
- to_chat(user, "\tSubject does not have eyes.")
+ msg += "\tSubject does not have eyes.\n"
if(ishuman(M))
var/mob/living/carbon/human/H = M
var/ldamage = H.return_liver_damage()
if(ldamage > 10)
- to_chat(user, "\t[ldamage > 45 ? "Severe" : "Minor"] liver damage detected.")
+ msg += "\t[ldamage > 45 ? "Severe" : "Minor"] liver damage detected.\n"
// Body part damage report
if(iscarbon(M) && mode == 1)
var/mob/living/carbon/C = M
var/list/damaged = C.get_damaged_bodyparts(1,1)
if(length(damaged)>0 || oxy_loss>0 || tox_loss>0 || fire_loss>0)
- to_chat(user, "\tDamage: Brute-Burn-Toxin-Suffocation\n\t\tSpecifics: [brute_loss]-[fire_loss]-[tox_loss]-[oxy_loss]")
+ msg += "\tDamage: Brute-Burn-Toxin-Suffocation\n\t\tSpecifics: [brute_loss]-[fire_loss]-[tox_loss]-[oxy_loss]\n"
for(var/obj/item/bodypart/org in damaged)
- to_chat(user, "\t\t[capitalize(org.name)]: [(org.brute_dam > 0) ? "[org.brute_dam]" : "0"]-[(org.burn_dam > 0) ? "[org.burn_dam]" : "0"]")
+ msg += "\t\t[capitalize(org.name)]: [(org.brute_dam > 0) ? "[org.brute_dam]" : "0"]-[(org.burn_dam > 0) ? "[org.burn_dam]" : "0"]\n"
// Species and body temperature
if(ishuman(M))
@@ -282,20 +284,22 @@ SLIME SCANNER
else if (S.mutantstomach != initial(S.mutantstomach))
mutant = TRUE
- to_chat(user, "Species: [S.name][mutant ? "-derived mutant" : ""]")
- to_chat(user, "Body temperature: [round(M.bodytemperature-T0C,0.1)] °C ([round(M.bodytemperature*1.8-459.67,0.1)] °F)")
+ msg += "Species: [H.dna.custom_species ? H.dna.custom_species : S.name] Base: [S.name]\n"
+ if(mutant)
+ msg += "Subject has mutations present."
+ msg += "Body temperature: [round(M.bodytemperature-T0C,0.1)] °C ([round(M.bodytemperature*1.8-459.67,0.1)] °F)\n"
// Time of death
if(M.tod && (M.stat == DEAD || ((M.has_trait(TRAIT_FAKEDEATH)) && !advanced)))
- to_chat(user, "Time of Death: [M.tod]")
+ msg += "Time of Death: [M.tod]\n"
var/tdelta = round(world.time - M.timeofdeath)
if(tdelta < (DEFIB_TIME_LIMIT * 10))
- to_chat(user, "Subject died [DisplayTimeText(tdelta)] ago, defibrillation may be possible!")
+ msg += "Subject died [DisplayTimeText(tdelta)] ago, defibrillation may be possible!\n"
for(var/thing in M.diseases)
var/datum/disease/D = thing
if(!(D.visibility_flags & HIDDEN_SCANNER))
- to_chat(user, "Warning: [D.form] detected\nName: [D.name].\nType: [D.spread_text].\nStage: [D.stage]/[D.max_stages].\nPossible Cure: [D.cure_text]")
+ msg += "Warning: [D.form] detected\nName: [D.name].\nType: [D.spread_text].\nStage: [D.stage]/[D.max_stages].\nPossible Cure: [D.cure_text]\n"
// Blood Level
if(M.has_dna())
@@ -305,7 +309,7 @@ SLIME SCANNER
if(ishuman(C))
var/mob/living/carbon/human/H = C
if(H.bleed_rate)
- to_chat(user, "Subject is bleeding!")
+ msg += "Subject is bleeding!\n"
var/blood_percent = round((C.blood_volume / BLOOD_VOLUME_NORMAL)*100)
var/blood_type = C.dna.blood_type
if(blood_id != "blood")//special blood substance
@@ -315,36 +319,41 @@ SLIME SCANNER
else
blood_type = blood_id
if(C.blood_volume <= BLOOD_VOLUME_SAFE && C.blood_volume > BLOOD_VOLUME_OKAY)
- to_chat(user, "LOW blood level [blood_percent] %, [C.blood_volume] cl, type: [blood_type]")
+ msg += "LOW blood level [blood_percent] %, [C.blood_volume] cl, type: [blood_type]\n"
else if(C.blood_volume <= BLOOD_VOLUME_OKAY)
- to_chat(user, "CRITICAL blood level [blood_percent] %, [C.blood_volume] cl, type: [blood_type]")
+ msg += "CRITICAL blood level [blood_percent] %, [C.blood_volume] cl, type: [blood_type]\n"
else
- to_chat(user, "Blood level [blood_percent] %, [C.blood_volume] cl, type: [blood_type]")
+ msg += "Blood level [blood_percent] %, [C.blood_volume] cl, type: [blood_type]\n"
var/cyberimp_detect
for(var/obj/item/organ/cyberimp/CI in C.internal_organs)
if(CI.status == ORGAN_ROBOTIC && !CI.syndicate_implant)
cyberimp_detect += "[C.name] is modified with a [CI.name].
"
if(cyberimp_detect)
- to_chat(user, "Detected cybernetic modifications:")
- to_chat(user, "[cyberimp_detect]")
+ msg += "Detected cybernetic modifications:\n"
+ msg += "[cyberimp_detect]\n"
+ msg += "*---------*"
+ to_chat(user, msg)
SEND_SIGNAL(M, COMSIG_NANITE_SCAN, user, FALSE)
/proc/chemscan(mob/living/user, mob/living/M)
if(istype(M))
if(M.reagents)
+ var/msg = "*---------*\n"
if(M.reagents.reagent_list.len)
- to_chat(user, "Subject contains the following reagents:")
+ msg += "Subject contains the following reagents:\n"
for(var/datum/reagent/R in M.reagents.reagent_list)
- to_chat(user, "[R.volume] units of [R.name][R.overdosed == 1 ? " - OVERDOSING" : "."]")
+ msg += "[R.volume] units of [R.name][R.overdosed == 1 ? " - OVERDOSING" : "."]\n"
else
- to_chat(user, "Subject contains no reagents.")
+ msg += "Subject contains no reagents.\n"
if(M.reagents.addiction_list.len)
- to_chat(user, "Subject is addicted to the following reagents:")
+ msg += "Subject is addicted to the following reagents:\n"
for(var/datum/reagent/R in M.reagents.addiction_list)
- to_chat(user, "[R.name]")
+ msg += "[R.name]\n"
else
- to_chat(user, "Subject is not addicted to any reagents.")
+ msg += "Subject is not addicted to any reagents.\n"
+ msg += "*---------*"
+ to_chat(user, msg)
/obj/item/healthanalyzer/verb/toggle_mode()
set name = "Switch Verbosity"
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 4f17f5d762..24768279b8 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -82,6 +82,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/list/custom_names = list()
var/prefered_security_department = SEC_DEPT_RANDOM
+ var/custom_species = null
//Quirk list
var/list/positive_quirks = list()
@@ -269,6 +270,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "Body
"
dat += "Gender:[gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))]
"
dat += "Species:[pref_species.id]
"
+ dat += "Custom Species Name:[custom_species ? custom_species : "None"]
"
dat += "Random Body
"
dat += "Always Random Body:[be_random_body ? "Yes" : "No"]
"
dat += "
Cycle background:[bgstate]
"
@@ -1456,6 +1458,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/newtype = GLOB.species_list[result]
pref_species = new newtype()
//let's ensure that no weird shit happens on species swapping.
+ custom_species = null
if(!("body_markings" in pref_species.default_features))
features["body_markings"] = "None"
if(!("mam_body_markings" in pref_species.default_features))
@@ -1477,6 +1480,13 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(features["mcolor3"] == "#000" || (!(MUTCOLORS_PARTSONLY in pref_species.species_traits) && ReadHSV(temp_hsv)[3] < ReadHSV("#202020")[3]))
features["mcolor3"] = pref_species.default_color
+ if("custom_species")
+ var/new_species = reject_bad_name(input(user, "Choose your species subtype, if unique. This will show up on examinations and health scans. Do not abuse this:", "Character Preference", custom_species) as null|text)
+ if(new_species)
+ custom_species = new_species
+ else
+ custom_species = null
+
if("mutant_color")
var/new_mutantcolor = input(user, "Choose your character's alien/mutant color:", "Character Preference","#"+features["mcolor"]) as color|null
if(new_mutantcolor)
@@ -2115,6 +2125,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
character.real_name = nameless ? "[real_name] #[rand(10000, 99999)]" : real_name
character.name = character.real_name
character.nameless = nameless
+ character.custom_species = custom_species
character.gender = gender
character.age = age
@@ -2149,6 +2160,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
character.dna.features = features.Copy()
character.dna.real_name = character.real_name
character.dna.nameless = character.nameless
+ character.dna.custom_species = character.custom_species
if("tail_lizard" in pref_species.default_features)
character.dna.species.mutant_bodyparts |= "tail_lizard"
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index b6210d94b8..6d165bc531 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -236,6 +236,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
//Character
S["real_name"] >> real_name
S["nameless"] >> nameless
+ S["custom_species"] >> custom_species
S["name_is_always_random"] >> be_random_name
S["body_is_always_random"] >> be_random_body
S["gender"] >> gender
@@ -350,7 +351,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
gender = sanitize_gender(gender, TRUE, TRUE)
if(!real_name)
real_name = random_unique_name(gender)
-
+ custom_species = reject_bad_name(custom_species)
for(var/custom_name_id in GLOB.preferences_custom_names)
var/namedata = GLOB.preferences_custom_names[custom_name_id]
custom_names[custom_name_id] = reject_bad_name(custom_names[custom_name_id],namedata["allow_numbers"])
@@ -427,6 +428,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
//Character
WRITE_FILE(S["real_name"] , real_name)
WRITE_FILE(S["nameless"] , nameless)
+ WRITE_FILE(S["custom_species"] , custom_species)
WRITE_FILE(S["name_is_always_random"] , be_random_name)
WRITE_FILE(S["body_is_always_random"] , be_random_body)
WRITE_FILE(S["gender"] , gender)
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index c6ba900b13..26e19ff376 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -18,6 +18,16 @@
var/list/obscured = check_obscured_slots()
var/skipface = (wear_mask && (wear_mask.flags_inv & HIDEFACE)) || (head && (head.flags_inv & HIDEFACE))
+ if(ishuman(src)) //user just returned, y'know, the user's own species. dumb.
+ var/mob/living/carbon/human/H = src
+ var/datum/species/pref_species = H.dna.species
+ if(get_visible_name() == "Unknown") // same as flavor text, but hey it works.
+ msg += "You can't make out what species they are.\n"
+ else if(skipface)
+ msg += "You can't make out what species they are.\n"
+ else
+ msg += "[t_He] [t_is] a [H.dna.custom_species ? H.dna.custom_species : pref_species.name]!\n"
+
//uniform
if(w_uniform && !(SLOT_W_UNIFORM in obscured))
//accessory
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index 4f168d97fc..d1ec7f3e4b 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -47,6 +47,8 @@
var/nameless = FALSE //For drones of both the insectoid and robotic kind. And other types of nameless critters.
+ var/custom_species = null
+
var/datum/personal_crafting/handcrafting
var/datum/physiology/physiology