diff --git a/code/_helpers/mobs.dm b/code/_helpers/mobs.dm
index cb6cd511a5..6e2a7fae36 100644
--- a/code/_helpers/mobs.dm
+++ b/code/_helpers/mobs.dm
@@ -61,6 +61,13 @@ proc/random_facial_hair_style(gender, species = "Human")
f_style = pick(valid_facialhairstyles)
return f_style
+
+proc/sanitize_name(name, species = "Human")
+ var/datum/species/current_species
+ if(species)
+ current_species = all_species[species]
+
+ return current_species ? current_species.sanitize_name(name) : sanitizeName(name)
proc/random_name(gender, species = "Human")
diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm
index 875b6d4810..d3f71325eb 100644
--- a/code/modules/client/client procs.dm
+++ b/code/modules/client/client procs.dm
@@ -339,3 +339,9 @@ client/proc/MayRespawn()
// Something went wrong, client is usually kicked or transfered to a new mob at this point
return 0
+
+client/verb/character_setup()
+ set name = "Character Setup"
+ set category = "Preferences"
+ if(prefs)
+ prefs.ShowChoices(usr)
diff --git a/code/modules/client/preference_setup/general/01_basic.dm b/code/modules/client/preference_setup/general/01_basic.dm
index 2e17707a69..440cf90e59 100644
--- a/code/modules/client/preference_setup/general/01_basic.dm
+++ b/code/modules/client/preference_setup/general/01_basic.dm
@@ -1,6 +1,7 @@
/datum/category_item/player_setup_item/general/basic
name = "Basic"
sort_order = 1
+ var/list/valid_player_genders = list(MALE, FEMALE)
/datum/category_item/player_setup_item/general/basic/load_character(var/savefile/S)
S["real_name"] >> pref.real_name
@@ -19,12 +20,13 @@
S["OOC_Notes"] << pref.metadata
/datum/category_item/player_setup_item/general/basic/sanitize_character()
- pref.real_name = sanitizeName(pref.real_name)
+ pref.age = sanitize_integer(pref.age, AGE_MIN, AGE_MAX, initial(pref.age))
+ pref.gender = sanitize_inlist(pref.gender, valid_player_genders, pick(valid_player_genders))
+ pref.real_name = sanitize_name(pref.real_name, pref.species)
if(!pref.real_name)
pref.real_name = random_name(pref.gender, pref.species)
pref.spawnpoint = sanitize_inlist(pref.spawnpoint, spawntypes, initial(pref.spawnpoint))
pref.be_random_name = sanitize_integer(pref.be_random_name, 0, 1, initial(pref.be_random_name))
- pref.age = sanitize_integer(pref.age, AGE_MIN, AGE_MAX, initial(pref.age))
/datum/category_item/player_setup_item/general/basic/content()
. = "Name: "
@@ -32,7 +34,7 @@
. += "(Random Name) "
. += "(Always Random Name: [pref.be_random_name ? "Yes" : "No"])"
. += "
"
- . += "Gender: [pref.gender == MALE ? "Male" : "Female"]
"
+ . += "Gender: [capitalize(lowertext(pref.gender))]
"
. += "Age: [pref.age]
"
. += "Spawn Point: [pref.spawnpoint]
"
if(config.allow_Metadata)
@@ -42,7 +44,7 @@
if(href_list["rename"])
var/raw_name = input(user, "Choose your character's name:", "Character Name") as text|null
if (!isnull(raw_name) && CanUseTopic(user))
- var/new_name = sanitizeName(raw_name)
+ var/new_name = sanitize_name(raw_name, pref.species)
if(new_name)
pref.real_name = new_name
return TOPIC_REFRESH
@@ -59,10 +61,7 @@
return TOPIC_REFRESH
else if(href_list["gender"])
- if(pref.gender == MALE)
- pref.gender = FEMALE
- else
- pref.gender = MALE
+ pref.gender = next_in_list(pref.gender, valid_player_genders)
return TOPIC_REFRESH
else if(href_list["age"])
@@ -80,7 +79,6 @@
pref.spawnpoint = choice
return TOPIC_REFRESH
-
else if(href_list["metadata"])
var/new_metadata = sanitize(input(user, "Enter any information you'd like others to see, such as Roleplay-preferences:", "Game Preference" , pref.metadata)) as message|null
if(new_metadata && CanUseTopic(user))
diff --git a/code/modules/client/preference_setup/preference_setup.dm b/code/modules/client/preference_setup/preference_setup.dm
index 9cb4f943f8..4ac42920ae 100644
--- a/code/modules/client/preference_setup/preference_setup.dm
+++ b/code/modules/client/preference_setup/preference_setup.dm
@@ -46,6 +46,10 @@
selected_category = null
return ..()
+/datum/category_collection/player_setup_collection/proc/sanitize_setup()
+ for(var/datum/category_group/player_setup_category/PS in categories)
+ PS.sanitize_setup()
+
/datum/category_collection/player_setup_collection/proc/load_character(var/savefile/S)
for(var/datum/category_group/player_setup_category/PS in categories)
PS.load_character(S)
@@ -100,24 +104,37 @@
/datum/category_group/player_setup_category/dd_SortValue()
return sort_order
+/datum/category_group/player_setup_category/proc/sanitize_setup()
+ for(var/datum/category_item/player_setup_item/PI in items)
+ PI.sanitize_preferences()
+ for(var/datum/category_item/player_setup_item/PI in items)
+ PI.sanitize_character()
+
/datum/category_group/player_setup_category/proc/load_character(var/savefile/S)
+ // Load all data, then sanitize it.
+ // Need due to, for example, the 01_basic module relying on species having been loaded to sanitize correctly but that isn't loaded until module 03_body.
for(var/datum/category_item/player_setup_item/PI in items)
PI.load_character(S)
+ for(var/datum/category_item/player_setup_item/PI in items)
PI.sanitize_character()
/datum/category_group/player_setup_category/proc/save_character(var/savefile/S)
+ // Sanitize all data, then save it
for(var/datum/category_item/player_setup_item/PI in items)
PI.sanitize_character()
+ for(var/datum/category_item/player_setup_item/PI in items)
PI.save_character(S)
/datum/category_group/player_setup_category/proc/load_preferences(var/savefile/S)
for(var/datum/category_item/player_setup_item/PI in items)
PI.load_preferences(S)
+ for(var/datum/category_item/player_setup_item/PI in items)
PI.sanitize_preferences()
/datum/category_group/player_setup_category/proc/save_preferences(var/savefile/S)
for(var/datum/category_item/player_setup_item/PI in items)
PI.sanitize_preferences()
+ for(var/datum/category_item/player_setup_item/PI in items)
PI.save_preferences(S)
/datum/category_group/player_setup_category/proc/content(var/mob/user)
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 61bf6939ff..66a029900b 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -113,7 +113,6 @@ datum/preferences
/datum/preferences/New(client/C)
player_setup = new(src)
-
gender = pick(MALE, FEMALE)
real_name = random_name(gender,species)
b_type = pick(4;"O-", 36;"O+", 3;"A-", 28;"A+", 1;"B-", 20;"B+", 1;"AB-", 5;"AB+")
@@ -235,6 +234,8 @@ datum/preferences
return 1
/datum/preferences/proc/copy_to(mob/living/carbon/human/character, safety = 0)
+ // Sanitizing rather than saving as someone might still be editing when copy_to occurs.
+ player_setup.sanitize_setup()
if(be_random_name)
real_name = random_name(gender,species)
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index 66709917e0..11e5857cba 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -85,6 +85,9 @@
player_setup.save_character(S)
return 1
+/datum/preferences/proc/sanitize_preferences()
+ player_setup.sanitize_setup()
+ return 1
#undef SAVEFILE_VERSION_MAX
#undef SAVEFILE_VERSION_MIN
diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm
index d77493b0b3..d6e32722b1 100644
--- a/code/modules/mob/living/carbon/human/species/species.dm
+++ b/code/modules/mob/living/carbon/human/species/species.dm
@@ -198,6 +198,9 @@
if(covered)
H << "[pick(heat_discomfort_strings)]"
+/datum/species/proc/sanitize_name(var/name)
+ return sanitizeName(name)
+
/datum/species/proc/get_random_name(var/gender)
if(!name_language)
if(gender == FEMALE)
diff --git a/code/modules/mob/living/carbon/human/species/station/station.dm b/code/modules/mob/living/carbon/human/species/station/station.dm
index e4c31a1447..e5b3ae6b0f 100644
--- a/code/modules/mob/living/carbon/human/species/station/station.dm
+++ b/code/modules/mob/living/carbon/human/species/station/station.dm
@@ -330,3 +330,6 @@
H.h_style = ""
spawn(100)
if(H) H.update_hair()
+
+/datum/species/machine/sanitize_name(var/name)
+ return sanitizeName(name, allow_numbers = 1)