diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm
index 84299fc3021..bd991f29d01 100644
--- a/code/__HELPERS/global_lists.dm
+++ b/code/__HELPERS/global_lists.dm
@@ -2,13 +2,6 @@
/////Initial Building/////
//////////////////////////
-/// Inits GLOB.species_list. Not using GLOBAL_LIST_INIT b/c it depends on GLOB.string_lists
-/proc/init_species_list()
- for(var/species_path in subtypesof(/datum/species))
- var/datum/species/species = new species_path()
- GLOB.species_list[species.id] = species_path
- sort_list(GLOB.species_list, GLOBAL_PROC_REF(cmp_typepaths_asc))
-
/// Inits GLOB.surgeries
/proc/init_surgeries()
var/surgeries = list()
@@ -20,7 +13,6 @@
/// Legacy procs that really should be replaced with proper _INIT macros
/proc/make_datum_reference_lists()
// I tried to eliminate this proc but I couldn't untangle their init-order interdependencies -Dominion/Cyberboss
- init_species_list()
init_keybindings()
GLOB.emote_list = init_emote_list() // WHY DOES THIS NEED TO GO HERE? IT JUST INITS DATUMS
init_crafting_recipes()
diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm
index 9bc3beb3a1b..084e51167ea 100644
--- a/code/__HELPERS/mobs.dm
+++ b/code/__HELPERS/mobs.dm
@@ -76,47 +76,6 @@
else
return pick(SSaccessories.facial_hairstyles_list)
-/proc/random_unique_name(gender, attempts_to_find_unique_name=10)
- for(var/i in 1 to attempts_to_find_unique_name)
- if(gender == FEMALE)
- . = capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names))
- else
- . = capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names))
-
- if(!findname(.))
- break
-
-/proc/random_unique_lizard_name(gender, attempts_to_find_unique_name=10)
- for(var/i in 1 to attempts_to_find_unique_name)
- . = capitalize(lizard_name(gender))
-
- if(!findname(.))
- break
-
-/proc/random_unique_plasmaman_name(attempts_to_find_unique_name=10)
- for(var/i in 1 to attempts_to_find_unique_name)
- . = capitalize(plasmaman_name())
-
- if(!findname(.))
- break
-
-/proc/random_unique_ethereal_name(attempts_to_find_unique_name=10)
- for(var/i in 1 to attempts_to_find_unique_name)
- . = capitalize(ethereal_name())
-
- if(!findname(.))
- break
-
-/proc/random_unique_moth_name(attempts_to_find_unique_name=10)
- for(var/i in 1 to attempts_to_find_unique_name)
- . = capitalize(pick(GLOB.moth_first)) + " " + capitalize(pick(GLOB.moth_last))
-
- if(!findname(.))
- break
-
-/proc/random_skin_tone()
- return pick(GLOB.skin_tones)
-
GLOBAL_LIST_INIT(skin_tones, sort_list(list(
"albino",
"caucasian1",
@@ -155,9 +114,6 @@ GLOBAL_LIST_INIT(skin_tone_names, list(
"mixed4" = "Macadamia",
))
-/// An assoc list of species IDs to type paths
-GLOBAL_LIST_EMPTY(species_list)
-
/proc/age2agedescription(age)
switch(age)
if(0 to 1)
diff --git a/code/__HELPERS/names.dm b/code/__HELPERS/names.dm
index 12c34d3a705..3a82c8dc1a6 100644
--- a/code/__HELPERS/names.dm
+++ b/code/__HELPERS/names.dm
@@ -1,20 +1,75 @@
-/proc/lizard_name(gender)
- if(gender == MALE)
- return "[pick(GLOB.lizard_names_male)]-[pick(GLOB.lizard_names_male)]"
- else
- return "[pick(GLOB.lizard_names_female)]-[pick(GLOB.lizard_names_female)]"
+/**
+ * Generate a random name based off of one of the roundstart languages
+ *
+ * * gender - What gender to pick from. Picks between male, female if not provided.
+ * * unique - If the name should be unique, IE, avoid picking names that mobs already have.
+ * * list/language_weights - A list of language weights to pick from.
+ * If not provided, it will default to a list of roundstart languages, with common being the most likely.
+ */
+/proc/generate_random_name(gender, unique, list/language_weights)
+ if(isnull(language_weights))
+ language_weights = list()
+ for(var/lang_type in GLOB.uncommon_roundstart_languages)
+ language_weights[lang_type] = 1
+ language_weights[/datum/language/common] = 20
-/proc/ethereal_name()
- var/tempname = "[pick(GLOB.ethereal_names)] [random_capital_letter()]"
- if(prob(65))
- tempname += random_capital_letter()
- return tempname
+ var/datum/language/picked = GLOB.language_datum_instances[pick_weight(language_weights)]
+ if(unique)
+ return picked.get_random_unique_name(gender)
+ return picked.get_random_name(gender)
-/proc/plasmaman_name()
- return "[pick(GLOB.plasmaman_names)] \Roman[rand(1,99)]"
+/**
+ * Generate a random name based off of a species
+ * This will pick a name from the species language, and avoid picking common if there are alternatives
+ *
+ * * gender - What gender to pick from. Picks between male, female if not provided.
+ * * unique - If the name should be unique, IE, avoid picking names that mobs already have.
+ * * datum/species/species_type - The species to pick from
+ * * include_all - Makes the generated name a mix of all the languages the species can speak rather than just one of them
+ * Does this on a per-name basis, IE "Lizard first name, uncommon last name".
+ */
+/proc/generate_random_name_species_based(gender, unique, datum/species/species_type, include_all = FALSE)
+ ASSERT(ispath(species_type, /datum/species))
+ var/datum/language_holder/holder = GLOB.prototype_language_holders[species_type::species_language_holder]
-/proc/moth_name()
- return "[pick(GLOB.moth_first)] [pick(GLOB.moth_last)]"
+ var/list/languages_to_pick_from = list()
+ for(var/language in holder.spoken_languages)
+ languages_to_pick_from[language] = 1
+
+ if(length(languages_to_pick_from) >= 2)
+ // Basically, if we have alternatives, don't pick common it's boring
+ languages_to_pick_from -= /datum/language/common
+
+ if(!include_all || length(languages_to_pick_from) <= 1)
+ return generate_random_name(gender, unique, languages_to_pick_from)
+
+ var/list/name_parts = list()
+ for(var/lang_type in shuffle(languages_to_pick_from))
+ name_parts += GLOB.language_datum_instances[lang_type].get_random_name(gender, name_count = 1, force_use_syllables = TRUE)
+ return jointext(name_parts, " ")
+
+/**
+ * Generates a random name for the mob based on their gender or species (for humans)
+ *
+ * * unique - If the name should be unique, IE, avoid picking names that mobs already have.
+ */
+/mob/proc/generate_random_mob_name(unique)
+ return generate_random_name_species_based(gender, unique, /datum/species/human)
+
+/mob/living/carbon/generate_random_mob_name(unique)
+ return generate_random_name_species_based(gender, unique, dna?.species?.type || /datum/species/human)
+
+/mob/living/silicon/generate_random_mob_name(unique)
+ return generate_random_name(gender, unique, list(/datum/language/machine = 1))
+
+/mob/living/basic/drone/generate_random_mob_name(unique)
+ return generate_random_name(gender, unique, list(/datum/language/machine = 1))
+
+/mob/living/basic/bot/generate_random_mob_name(unique)
+ return generate_random_name(gender, unique, list(/datum/language/machine = 1))
+
+/mob/living/simple_animal/bot/generate_random_mob_name(unique)
+ return generate_random_name(gender, unique, list(/datum/language/machine = 1))
GLOBAL_VAR(command_name)
/proc/command_name()
@@ -194,16 +249,11 @@ GLOBAL_DATUM(syndicate_code_response_regex, /regex)
if(1)//1 and 2 can only be selected once each to prevent more than two specific names/places/etc.
switch(rand(1,2))//Mainly to add more options later.
if(1)
- if(names.len && prob(70))
+ if(length(names) && prob(70))
. += pick(names)
else
- if(prob(10))
- . += pick(lizard_name(MALE),lizard_name(FEMALE))
- else
- var/new_name = pick(pick(GLOB.first_names_male,GLOB.first_names_female))
- new_name += " "
- new_name += pick(GLOB.last_names)
- . += new_name
+ . += generate_random_name()
+
if(2)
var/datum/job/job = pick(SSjob.joinable_occupations)
if(job)
diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm
index 4e33aa43708..692704be0ff 100644
--- a/code/_globalvars/lists/mobs.dm
+++ b/code/_globalvars/lists/mobs.dm
@@ -85,11 +85,54 @@ GLOBAL_LIST_EMPTY(revenant_relay_mobs)
///underages who have been reported to security for trying to buy things they shouldn't, so they can't spam
GLOBAL_LIST_EMPTY(narcd_underages)
+/// List of language prototypes to reference, assoc [type] = prototype
+GLOBAL_LIST_INIT_TYPED(language_datum_instances, /datum/language, init_language_prototypes())
+/// List if all language typepaths learnable, IE, those with keys
+GLOBAL_LIST_INIT(all_languages, init_all_languages())
+// /List of language prototypes to reference, assoc "name" = typepath
+GLOBAL_LIST_INIT(language_types_by_name, init_language_types_by_name())
-GLOBAL_LIST_EMPTY(language_datum_instances)
-GLOBAL_LIST_EMPTY(all_languages)
-///List of all languages ("name" = type)
-GLOBAL_LIST_EMPTY(language_types_by_name)
+/proc/init_language_prototypes()
+ var/list/lang_list = list()
+ for(var/datum/language/lang_type as anything in typesof(/datum/language))
+ if(!initial(lang_type.key))
+ continue
+
+ lang_list[lang_type] = new lang_type()
+ return lang_list
+
+/proc/init_all_languages()
+ var/list/lang_list = list()
+ for(var/datum/language/lang_type as anything in typesof(/datum/language))
+ if(!initial(lang_type.key))
+ continue
+ lang_list += lang_type
+ return lang_list
+
+/proc/init_language_types_by_name()
+ var/list/lang_list = list()
+ for(var/datum/language/lang_type as anything in typesof(/datum/language))
+ if(!initial(lang_type.key))
+ continue
+ lang_list[initial(lang_type.name)] = lang_type
+ return lang_list
+
+/// An assoc list of species IDs to type paths
+GLOBAL_LIST_INIT(species_list, init_species_list())
+/// List of all species prototypes to reference, assoc [type] = prototype
+GLOBAL_LIST_INIT_TYPED(species_prototypes, /datum/species, init_species_prototypes())
+
+/proc/init_species_list()
+ var/list/species_list = list()
+ for(var/datum/species/species_path as anything in subtypesof(/datum/species))
+ species_list[initial(species_path.id)] = species_path
+ return species_list
+
+/proc/init_species_prototypes()
+ var/list/species_list = list()
+ for(var/species_type in subtypesof(/datum/species))
+ species_list[species_type] = new species_type()
+ return species_list
GLOBAL_LIST_EMPTY(sentient_disease_instances)
diff --git a/code/_globalvars/lists/names.dm b/code/_globalvars/lists/names.dm
index c51fbaa9eb7..81fe08373b3 100644
--- a/code/_globalvars/lists/names.dm
+++ b/code/_globalvars/lists/names.dm
@@ -8,12 +8,12 @@ GLOBAL_LIST_INIT(first_names, world.file2list("strings/names/first.txt"))
GLOBAL_LIST_INIT(first_names_male, world.file2list("strings/names/first_male.txt"))
GLOBAL_LIST_INIT(first_names_female, world.file2list("strings/names/first_female.txt"))
GLOBAL_LIST_INIT(last_names, world.file2list("strings/names/last.txt"))
-GLOBAL_LIST_INIT(lizard_names_male, world.file2list("strings/names/lizard_male.txt"))
-GLOBAL_LIST_INIT(lizard_names_female, world.file2list("strings/names/lizard_female.txt"))
GLOBAL_LIST_INIT(clown_names, world.file2list("strings/names/clown.txt"))
GLOBAL_LIST_INIT(mime_names, world.file2list("strings/names/mime.txt"))
GLOBAL_LIST_INIT(religion_names, world.file2list("strings/names/religion.txt"))
GLOBAL_LIST_INIT(carp_names, world.file2list("strings/names/carp.txt"))
+GLOBAL_LIST_INIT(lizard_names_male, world.file2list("strings/names/lizard_male.txt"))
+GLOBAL_LIST_INIT(lizard_names_female, world.file2list("strings/names/lizard_female.txt"))
GLOBAL_LIST_INIT(golem_names, world.file2list("strings/names/golem.txt"))
GLOBAL_LIST_INIT(moth_first, world.file2list("strings/names/moth_first.txt"))
GLOBAL_LIST_INIT(moth_last, world.file2list("strings/names/moth_last.txt"))
diff --git a/code/controllers/subsystem/language.dm b/code/controllers/subsystem/language.dm
deleted file mode 100644
index 88e92e2f93c..00000000000
--- a/code/controllers/subsystem/language.dm
+++ /dev/null
@@ -1,17 +0,0 @@
-SUBSYSTEM_DEF(language)
- name = "Language"
- init_order = INIT_ORDER_LANGUAGE
- flags = SS_NO_FIRE
-
-/datum/controller/subsystem/language/Initialize()
- for(var/datum/language/language as anything in subtypesof(/datum/language))
- if(!initial(language.key))
- continue
-
- GLOB.all_languages += language
- GLOB.language_types_by_name[initial(language.name)] = language
-
- var/datum/language/instance = new language
- GLOB.language_datum_instances[language] = instance
-
- return SS_INIT_SUCCESS
diff --git a/code/datums/brain_damage/imaginary_friend.dm b/code/datums/brain_damage/imaginary_friend.dm
index e3891392d1a..251414241c9 100644
--- a/code/datums/brain_damage/imaginary_friend.dm
+++ b/code/datums/brain_damage/imaginary_friend.dm
@@ -129,8 +129,8 @@
/// Randomise friend name and appearance
/mob/camera/imaginary_friend/proc/setup_friend()
- var/gender = pick(MALE, FEMALE)
- real_name = random_unique_name(gender)
+ gender = pick(MALE, FEMALE)
+ real_name = generate_random_name_species_based(gender, FALSE, /datum/species/human)
name = real_name
human_image = get_flat_human_icon(null, pick(SSjob.joinable_occupations))
Show()
diff --git a/code/datums/diseases/advance/symptoms/voice_change.dm b/code/datums/diseases/advance/symptoms/voice_change.dm
index 255c2a3f3a7..9654365c49d 100644
--- a/code/datums/diseases/advance/symptoms/voice_change.dm
+++ b/code/datums/diseases/advance/symptoms/voice_change.dm
@@ -54,7 +54,7 @@
else
if(ishuman(M))
var/mob/living/carbon/human/H = M
- H.SetSpecialVoice(H.dna.species.random_name(H.gender))
+ H.SetSpecialVoice(H.generate_random_mob_name())
if(scramble_language && !current_language) // Last part prevents rerolling language with small amounts of cure.
current_language = pick(subtypesof(/datum/language) - /datum/language/common)
H.add_blocked_language(subtypesof(/datum/language) - current_language, LANGUAGE_VOICECHANGE)
diff --git a/code/datums/dna.dm b/code/datums/dna.dm
index ab5407bc78c..8f5844aa480 100644
--- a/code/datums/dna.dm
+++ b/code/datums/dna.dm
@@ -451,14 +451,8 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
if(create_mutation_blocks) //I hate this
generate_dna_blocks()
if(randomize_features)
- var/static/list/all_species_protoypes
- if(isnull(all_species_protoypes))
- all_species_protoypes = list()
- for(var/species_path in subtypesof(/datum/species))
- all_species_protoypes += new species_path()
-
- for(var/datum/species/random_species as anything in all_species_protoypes)
- features |= random_species.randomize_features()
+ for(var/species_type in GLOB.species_prototypes)
+ features |= GLOB.species_prototypes[species_type].randomize_features()
features["mcolor"] = "#[random_color()]"
diff --git a/code/game/machinery/computer/records/security.dm b/code/game/machinery/computer/records/security.dm
index 0797b4d1890..c41779e7384 100644
--- a/code/game/machinery/computer/records/security.dm
+++ b/code/game/machinery/computer/records/security.dm
@@ -49,10 +49,8 @@
if(prob(10/severity))
switch(rand(1,5))
if(1)
- if(prob(10))
- target.name = "[pick(lizard_name(MALE),lizard_name(FEMALE))]"
- else
- target.name = "[pick(pick(GLOB.first_names_male), pick(GLOB.first_names_female))] [pick(GLOB.last_names)]"
+ target.name = generate_random_name()
+
if(2)
target.gender = pick("Male", "Female", "Other")
if(3)
diff --git a/code/game/objects/items/cardboard_cutouts.dm b/code/game/objects/items/cardboard_cutouts.dm
index 71f3a244a30..1e6c2b35ede 100644
--- a/code/game/objects/items/cardboard_cutouts.dm
+++ b/code/game/objects/items/cardboard_cutouts.dm
@@ -317,7 +317,7 @@
outfit = /datum/outfit/ashwalker/spear
/datum/cardboard_cutout/ash_walker/get_name()
- return lizard_name(pick(MALE, FEMALE))
+ return generate_random_name_species_based(species_type = /datum/species/lizard)
/datum/cardboard_cutout/death_squad
name = "Deathsquad Officer"
diff --git a/code/game/objects/items/debug_items.dm b/code/game/objects/items/debug_items.dm
index 4f6239acbe8..44f53df2c2b 100644
--- a/code/game/objects/items/debug_items.dm
+++ b/code/game/objects/items/debug_items.dm
@@ -21,7 +21,7 @@
/obj/item/debug/human_spawner/attack_self(mob/user)
..()
- var/choice = input("Select a species", "Human Spawner", null) in GLOB.species_list
+ var/choice = input("Select a species", "Human Spawner", null) in sortTim(GLOB.species_list, GLOBAL_PROC_REF(cmp_text_asc))
selected_species = GLOB.species_list[choice]
/obj/item/debug/omnitool
@@ -168,4 +168,3 @@
var/turf/loc_turf = get_turf(src)
for(var/spawn_atom in (choice == "No" ? typesof(path) : subtypesof(path)))
new spawn_atom(loc_turf)
-
diff --git a/code/game/objects/structures/headpike.dm b/code/game/objects/structures/headpike.dm
index b4cffdb654d..fca32574455 100644
--- a/code/game/objects/structures/headpike.dm
+++ b/code/game/objects/structures/headpike.dm
@@ -36,7 +36,7 @@
victim = locate() in parts_list
if(!victim) //likely a mapspawned one
victim = new(src)
- victim.real_name = random_unique_name(prob(50))
+ victim.real_name = generate_random_name()
spear = locate(speartype) in parts_list
if(!spear)
spear = new speartype(src)
diff --git a/code/modules/admin/create_mob.dm b/code/modules/admin/create_mob.dm
index fcf9693731e..509787ffd3a 100644
--- a/code/modules/admin/create_mob.dm
+++ b/code/modules/admin/create_mob.dm
@@ -16,7 +16,7 @@
/proc/randomize_human(mob/living/carbon/human/human, randomize_mutations = FALSE)
human.gender = human.dna.species.sexes ? pick(MALE, FEMALE, PLURAL, NEUTER) : PLURAL
human.physique = human.gender
- human.real_name = human.dna?.species.random_name(human.gender) || random_unique_name(human.gender)
+ human.real_name = human.generate_random_mob_name()
human.name = human.get_visible_name()
human.set_hairstyle(random_hairstyle(human.gender), update = FALSE)
human.set_facial_hairstyle(random_facial_hairstyle(human.gender), update = FALSE)
@@ -24,7 +24,7 @@
human.set_facial_haircolor(human.hair_color, update = FALSE)
human.eye_color_left = random_eye_color()
human.eye_color_right = human.eye_color_left
- human.skin_tone = random_skin_tone()
+ human.skin_tone = pick(GLOB.skin_tones)
human.dna.species.randomize_active_underwear_only(human)
// Needs to be called towards the end to update all the UIs just set above
human.dna.initialize_dna(newblood_type = random_blood_type(), create_mutation_blocks = randomize_mutations, randomize_features = TRUE)
diff --git a/code/modules/admin/verbs/anonymousnames.dm b/code/modules/admin/verbs/anonymousnames.dm
index 9a71d68637a..10edb49d993 100644
--- a/code/modules/admin/verbs/anonymousnames.dm
+++ b/code/modules/admin/verbs/anonymousnames.dm
@@ -131,8 +131,7 @@ GLOBAL_DATUM(current_anonymous_theme, /datum/anonymous_theme)
/datum/anonymous_theme/proc/anonymous_name(mob/target)
var/datum/client_interface/client = GET_CLIENT(target)
var/species_type = client.prefs.read_preference(/datum/preference/choiced/species)
- var/datum/species/species = new species_type
- return species.random_name(target.gender,1)
+ return generate_random_name_species_based(target.gender, TRUE, species_type)
/**
* anonymous_ai_name: generates a random name, based off of whatever the round's anonymousnames is set to (but for sillycones).
diff --git a/code/modules/admin/verbs/secrets.dm b/code/modules/admin/verbs/secrets.dm
index b7aa16b6b5f..5f5b5f245bb 100644
--- a/code/modules/admin/verbs/secrets.dm
+++ b/code/modules/admin/verbs/secrets.dm
@@ -222,7 +222,7 @@ ADMIN_VERB(secrets, R_NONE, "Secrets", "Abuse harder than you ever have before w
if("allspecies")
if(!is_funmin)
return
- var/result = input(holder, "Please choose a new species","Species") as null|anything in GLOB.species_list
+ var/result = input(holder, "Please choose a new species","Species") as null|anything in sortTim(GLOB.species_list, GLOBAL_PROC_REF(cmp_text_asc))
if(result)
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Mass Species Change", "[result]"))
log_admin("[key_name(holder)] turned all humans into [result]")
@@ -724,4 +724,3 @@ ADMIN_VERB(secrets, R_NONE, "Secrets", "Abuse harder than you ever have before w
var/datum/antagonist/malf_ai/antag_datum = new
antag_datum.give_objectives = keep_generic_objecives
assign_admin_objective_and_antag(player, antag_datum)
-
diff --git a/code/modules/client/preferences/_preference.dm b/code/modules/client/preferences/_preference.dm
index 644d57b6d24..5fbf5c6953d 100644
--- a/code/modules/client/preferences/_preference.dm
+++ b/code/modules/client/preferences/_preference.dm
@@ -331,7 +331,7 @@ GLOBAL_LIST_INIT(preference_entries_by_key, init_preference_entries_by_key())
)
var/species_type = preferences.read_preference(/datum/preference/choiced/species)
- var/datum/species/species = new species_type
+ var/datum/species/species = GLOB.species_prototypes[species_type]
if (!(savefile_key in species.get_features()))
return FALSE
diff --git a/code/modules/client/preferences/clothing.dm b/code/modules/client/preferences/clothing.dm
index 002a7f8c13a..d0ec072ba47 100644
--- a/code/modules/client/preferences/clothing.dm
+++ b/code/modules/client/preferences/clothing.dm
@@ -175,7 +175,7 @@
return FALSE
var/species_type = preferences.read_preference(/datum/preference/choiced/species)
- var/datum/species/species = new species_type
+ var/datum/species/species = GLOB.species_prototypes[species_type]
return !(TRAIT_NO_UNDERWEAR in species.inherent_traits)
/datum/preference/choiced/underwear/compile_constant_data()
diff --git a/code/modules/client/preferences/names.dm b/code/modules/client/preferences/names.dm
index 476fc7381a2..9afc8da18c1 100644
--- a/code/modules/client/preferences/names.dm
+++ b/code/modules/client/preferences/names.dm
@@ -45,12 +45,11 @@
target.log_mob_tag("TAG: [target.tag] RENAMED: [key_name(target)]")
/datum/preference/name/real_name/create_informed_default_value(datum/preferences/preferences)
- var/species_type = preferences.read_preference(/datum/preference/choiced/species)
- var/gender = preferences.read_preference(/datum/preference/choiced/gender)
-
- var/datum/species/species = new species_type
-
- return species.random_name(gender, unique = TRUE)
+ return generate_random_name_species_based(
+ preferences.read_preference(/datum/preference/choiced/gender),
+ TRUE,
+ preferences.read_preference(/datum/preference/choiced/species),
+ )
/datum/preference/name/real_name/deserialize(input, datum/preferences/preferences)
input = ..(input)
@@ -73,9 +72,7 @@
savefile_key = "human_name"
/datum/preference/name/backup_human/create_informed_default_value(datum/preferences/preferences)
- var/gender = preferences.read_preference(/datum/preference/choiced/gender)
-
- return random_unique_name(gender)
+ return generate_random_name(preferences.read_preference(/datum/preference/choiced/gender))
/datum/preference/name/clown
savefile_key = "clown_name"
diff --git a/code/modules/client/preferences/species.dm b/code/modules/client/preferences/species.dm
index 9e4923d2b11..1c74d7981b6 100644
--- a/code/modules/client/preferences/species.dm
+++ b/code/modules/client/preferences/species.dm
@@ -34,7 +34,7 @@
for (var/species_id in get_selectable_species())
var/species_type = GLOB.species_list[species_id]
- var/datum/species/species = new species_type()
+ var/datum/species/species = GLOB.species_prototypes[species_type]
data[species_id] = list()
data[species_id]["name"] = species.name
@@ -47,6 +47,4 @@
data[species_id]["perks"] = species.get_species_perks()
data[species_id]["diet"] = species.get_species_diet()
- qdel(species)
-
return data
diff --git a/code/modules/client/preferences/species_features/mutants.dm b/code/modules/client/preferences/species_features/mutants.dm
index 7ecf25d9abc..1d18c78ee1a 100644
--- a/code/modules/client/preferences/species_features/mutants.dm
+++ b/code/modules/client/preferences/species_features/mutants.dm
@@ -9,7 +9,7 @@
return FALSE
var/species_type = preferences.read_preference(/datum/preference/choiced/species)
- var/datum/species/species = new species_type
+ var/datum/species/species = GLOB.species_prototypes[species_type]
return !(TRAIT_FIXED_MUTANT_COLORS in species.inherent_traits)
/datum/preference/color/mutant_color/create_default_value()
diff --git a/code/modules/client/preferences/underwear_color.dm b/code/modules/client/preferences/underwear_color.dm
index 6e64b4423e5..1304bdaf2da 100644
--- a/code/modules/client/preferences/underwear_color.dm
+++ b/code/modules/client/preferences/underwear_color.dm
@@ -8,7 +8,7 @@
return FALSE
var/species_type = preferences.read_preference(/datum/preference/choiced/species)
- var/datum/species/species = new species_type
+ var/datum/species/species = GLOB.species_prototypes[species_type]
return !(TRAIT_NO_UNDERWEAR in species.inherent_traits)
/datum/preference/color/underwear_color/apply_to_human(mob/living/carbon/human/target, value)
diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm
index 6c5c2f4f039..9cbd711d981 100644
--- a/code/modules/jobs/job_types/_job.dm
+++ b/code/modules/jobs/job_types/_job.dm
@@ -117,7 +117,7 @@
/// RPG job names, for the memes
var/rpg_title
- /// Alternate titles to register as pointing to this job.
+ /// Alternate titles to register as pointing to this job.
var/list/alternate_titles
/// Does this job ignore human authority?
@@ -543,11 +543,11 @@
dna.species.roundstart_changed = TRUE
apply_pref_name(/datum/preference/name/backup_human, player_client)
if(CONFIG_GET(flag/force_random_names))
- var/species_type = player_client.prefs.read_preference(/datum/preference/choiced/species)
- var/datum/species/species = new species_type
-
- var/gender = player_client.prefs.read_preference(/datum/preference/choiced/gender)
- real_name = species.random_name(gender, TRUE)
+ real_name = generate_random_name_species_based(
+ player_client.prefs.read_preference(/datum/preference/choiced/gender),
+ TRUE,
+ player_client.prefs.read_preference(/datum/preference/choiced/species),
+ )
dna.update_dna_identity()
@@ -569,9 +569,11 @@
if(!player_client)
return // Disconnected while checking the appearance ban.
- var/species_type = player_client.prefs.read_preference(/datum/preference/choiced/species)
- var/datum/species/species = new species_type
- organic_name = species.random_name(player_client.prefs.read_preference(/datum/preference/choiced/gender), TRUE)
+ organic_name = generate_random_name_species_based(
+ player_client.prefs.read_preference(/datum/preference/choiced/gender),
+ TRUE,
+ player_client.prefs.read_preference(/datum/preference/choiced/species),
+ )
else
if(!player_client)
return // Disconnected while checking the appearance ban.
diff --git a/code/modules/language/_language.dm b/code/modules/language/_language.dm
new file mode 100644
index 00000000000..94ea4a6aa40
--- /dev/null
+++ b/code/modules/language/_language.dm
@@ -0,0 +1,164 @@
+/// maximum of 50 specific scrambled lines per language
+#define SCRAMBLE_CACHE_LEN 50
+
+/// Datum based languages. Easily editable and modular.
+/datum/language
+ /// Fluff name of language if any.
+ var/name = "an unknown language"
+ /// Short description for 'Check Languages'.
+ var/desc = "A language."
+ /// Character used to speak in language
+ /// If key is null, then the language isn't real or learnable.
+ var/key
+ /// Various language flags.
+ var/flags = NONE
+ /// Used when scrambling text for a non-speaker.
+ var/list/syllables
+ /// List of characters that will randomly be inserted between syllables.
+ var/list/special_characters
+ /// Likelihood of making a new sentence after each syllable.
+ var/sentence_chance = 5
+ /// Likelihood of getting a space in the random scramble string
+ var/space_chance = 55
+ /// Spans to apply from this language
+ var/list/spans
+ /// Cache of recently scrambled text
+ /// This allows commonly reused words to not require a full re-scramble every time.
+ var/list/scramble_cache = list()
+ /// The language that an atom knows with the highest "default_priority" is selected by default.
+ var/default_priority = 0
+ /// If TRUE, when generating names, we will always use the default human namelist, even if we have syllables set.
+ /// This is to be used for languages with very outlandish syllable lists (like pirates).
+ var/always_use_default_namelist = FALSE
+ /// Icon displayed in the chat window when speaking this language.
+ /// if you are seeing someone speak popcorn language, then something is wrong.
+ var/icon = 'icons/misc/language.dmi'
+ /// Icon state displayed in the chat window when speaking this language.
+ var/icon_state = "popcorn"
+
+ /// By default, random names picks this many names
+ var/default_name_count = 2
+ /// By default, random names picks this many syllables (min)
+ var/default_name_syllable_min = 2
+ /// By default, random names picks this many syllables (max)
+ var/default_name_syllable_max = 4
+ /// What char to place in between randomly generated names
+ var/random_name_spacer = " "
+
+/// Checks whether we should display the language icon to the passed hearer.
+/datum/language/proc/display_icon(atom/movable/hearer)
+ var/understands = hearer.has_language(src.type)
+ if((flags & LANGUAGE_HIDE_ICON_IF_UNDERSTOOD) && understands)
+ return FALSE
+ if((flags & LANGUAGE_HIDE_ICON_IF_NOT_UNDERSTOOD) && !understands)
+ return FALSE
+ return TRUE
+
+/// Returns the icon to display in the chat window when speaking this language.
+/datum/language/proc/get_icon()
+ var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/chat)
+ return sheet.icon_tag("language-[icon_state]")
+
+/// Simple helper for getting a default firstname lastname
+/datum/language/proc/default_name(gender = NEUTER)
+ if(gender != MALE)
+ gender = pick(MALE, FEMALE)
+ if(gender == FEMALE)
+ return capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names))
+ return capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names))
+
+
+/**
+ * Generates a random name this language would use.
+ *
+ * * gender: What gender to generate from, if neuter / plural coin flips between male and female
+ * * name_count: How many names to generate in, by default 2, for firstname lastname
+ * * syllable_count: How many syllables to generate in each name, min
+ * * syllable_max: How many syllables to generate in each name, max
+ * * force_use_syllables: If the name should be generated from the syllables list.
+ * Only used for subtypes which implement custom name lists. Also requires the language has syllables set.
+ */
+/datum/language/proc/get_random_name(
+ gender = NEUTER,
+ name_count = default_name_count,
+ syllable_min = default_name_syllable_min,
+ syllable_max = default_name_syllable_max,
+ force_use_syllables = FALSE,
+)
+ if(gender != MALE)
+ gender = pick(MALE, FEMALE)
+ if(!length(syllables) || always_use_default_namelist)
+ return default_name(gender)
+
+ var/list/full_name = list()
+ for(var/i in 1 to name_count)
+ var/new_name = ""
+ for(var/j in 1 to rand(default_name_syllable_min, default_name_syllable_max))
+ new_name += pick_weight_recursive(syllables)
+ full_name += capitalize(LOWER_TEXT(new_name))
+
+ return jointext(full_name, random_name_spacer)
+
+/// Generates a random name, and attempts to ensure it is unique (IE, no other mob in the world has it)
+/datum/language/proc/get_random_unique_name(...)
+ var/result = get_random_name(arglist(args))
+ for(var/i in 1 to 10)
+ if(!findname(result))
+ break
+ result = get_random_name(arglist(args))
+
+ return result
+
+/datum/language/proc/check_cache(input)
+ var/lookup = scramble_cache[input]
+ if(lookup)
+ scramble_cache -= input
+ scramble_cache[input] = lookup
+ . = lookup
+
+/datum/language/proc/add_to_cache(input, scrambled_text)
+ // Add it to cache, cutting old entries if the list is too long
+ scramble_cache[input] = scrambled_text
+ if(scramble_cache.len > SCRAMBLE_CACHE_LEN)
+ scramble_cache.Cut(1, scramble_cache.len-SCRAMBLE_CACHE_LEN-1)
+
+/datum/language/proc/scramble(input)
+
+ if(!length(syllables))
+ return stars(input)
+
+ // If the input is cached already, move it to the end of the cache and return it
+ var/lookup = check_cache(input)
+ if(lookup)
+ return lookup
+
+ var/input_size = length_char(input)
+ var/scrambled_text = ""
+ var/capitalize = TRUE
+
+ while(length_char(scrambled_text) < input_size)
+ var/next = (length(scrambled_text) && length(special_characters) && prob(1)) ? pick(special_characters) : pick_weight_recursive(syllables)
+ if(capitalize)
+ next = capitalize(next)
+ capitalize = FALSE
+ scrambled_text += next
+ var/chance = rand(100)
+ if(chance <= sentence_chance)
+ scrambled_text += ". "
+ capitalize = TRUE
+ else if(chance > sentence_chance && chance <= space_chance)
+ scrambled_text += " "
+
+ scrambled_text = trim(scrambled_text)
+ var/ending = copytext_char(scrambled_text, -1)
+ if(ending == ".")
+ scrambled_text = copytext_char(scrambled_text, 1, -2)
+ var/input_ending = copytext_char(input, -1)
+ if(input_ending in list("!","?","."))
+ scrambled_text += input_ending
+
+ add_to_cache(input, scrambled_text)
+
+ return scrambled_text
+
+#undef SCRAMBLE_CACHE_LEN
diff --git a/code/modules/language/language_holder.dm b/code/modules/language/_language_holder.dm
similarity index 100%
rename from code/modules/language/language_holder.dm
rename to code/modules/language/_language_holder.dm
diff --git a/code/modules/language/language_manuals.dm b/code/modules/language/_language_manuals.dm
similarity index 100%
rename from code/modules/language/language_manuals.dm
rename to code/modules/language/_language_manuals.dm
diff --git a/code/modules/language/language_menu.dm b/code/modules/language/_language_menu.dm
similarity index 100%
rename from code/modules/language/language_menu.dm
rename to code/modules/language/_language_menu.dm
diff --git a/code/modules/language/aphasia.dm b/code/modules/language/aphasia.dm
index 9d4e317c4d8..2d82b79892e 100644
--- a/code/modules/language/aphasia.dm
+++ b/code/modules/language/aphasia.dm
@@ -7,3 +7,4 @@
space_chance = 20
default_priority = 10
icon_state = "aphasia"
+ always_use_default_namelist = TRUE // Shouldn't generate names for this anyways
diff --git a/code/modules/language/beachbum.dm b/code/modules/language/beachbum.dm
index d78be9788f3..bd319e717ff 100644
--- a/code/modules/language/beachbum.dm
+++ b/code/modules/language/beachbum.dm
@@ -17,5 +17,5 @@
"heavy", "stellar", "excellent", "triumphant", "babe", "four",
"tail", "trim", "tube", "wobble", "roll", "gnarly", "epic",
)
-
icon_state = "beach"
+ always_use_default_namelist = TRUE
diff --git a/code/modules/language/buzzwords.dm b/code/modules/language/buzzwords.dm
index c46088c0ad5..2ed033bca34 100644
--- a/code/modules/language/buzzwords.dm
+++ b/code/modules/language/buzzwords.dm
@@ -8,3 +8,4 @@
)
icon_state = "buzz"
default_priority = 90
+ always_use_default_namelist = TRUE // Otherwise we get Bzzbzbz Zzzbzbz.
diff --git a/code/modules/language/calcic.dm b/code/modules/language/calcic.dm
index f4882e1105b..477e442203b 100644
--- a/code/modules/language/calcic.dm
+++ b/code/modules/language/calcic.dm
@@ -13,4 +13,16 @@
icon_state = "calcic"
default_priority = 90
+/datum/language/calcic/get_random_name(
+ gender = NEUTER,
+ name_count = default_name_count,
+ syllable_min = default_name_syllable_min,
+ syllable_max = default_name_syllable_max,
+ force_use_syllables = FALSE,
+)
+ if(force_use_syllables)
+ return ..()
+
+ return "[pick(GLOB.plasmaman_names)] \Roman[rand(1, 99)]"
+
// Yeah, this goes to skeletons too, since it's basically just skeleton clacking.
diff --git a/code/modules/language/codespeak.dm b/code/modules/language/codespeak.dm
index 09db7ef511b..242095b3bb7 100644
--- a/code/modules/language/codespeak.dm
+++ b/code/modules/language/codespeak.dm
@@ -5,6 +5,7 @@
default_priority = 0
flags = TONGUELESS_SPEECH | LANGUAGE_HIDE_ICON_IF_NOT_UNDERSTOOD
icon_state = "codespeak"
+ always_use_default_namelist = TRUE // No syllables anyways
/datum/language/codespeak/scramble(input)
var/lookup = check_cache(input)
diff --git a/code/modules/language/common.dm b/code/modules/language/common.dm
index 2dc7294983c..6bad808fef2 100644
--- a/code/modules/language/common.dm
+++ b/code/modules/language/common.dm
@@ -7,50 +7,51 @@
default_priority = 100
icon_state = "galcom"
-
-//Syllable Lists
-/*
- This list really long, mainly because I can't make up my mind about which mandarin syllables should be removed,
- and the english syllables had to be duplicated so that there is roughly a 50-50 weighting.
-
- Sources:
- http://www.sttmedia.com/syllablefrequency-english
- http://www.chinahighlights.com/travelguide/learning-chinese/pinyin-syllables.htm
-*/
-/datum/language/common/syllables = list(
- // each sublist has an equal chance of being picked, so each syllable has an equal chance of being english or chinese
- list(
- "a", "ai", "an", "ang", "ao", "ba", "bai", "ban", "bang", "bao", "bei", "ben", "beng", "bi", "bian", "biao",
- "bie", "bin", "bing", "bo", "bu", "ca", "cai", "can", "cang", "cao", "ce", "cei", "cen", "ceng", "cha", "chai",
- "chan", "chang", "chao", "che", "chen", "cheng", "chi", "chong", "chou", "chu", "chua", "chuai", "chuan", "chuang", "chui", "chun",
- "chuo", "ci", "cong", "cou", "cu", "cuan", "cui", "cun", "cuo", "da", "dai", "dan", "dang", "dao", "de", "dei",
- "den", "deng", "di", "dian", "diao", "die", "ding", "diu", "dong", "dou", "du", "duan", "dui", "dun", "duo", "e",
- "ei", "en", "er", "fa", "fan", "fang", "fei", "fen", "feng", "fo", "fou", "fu", "ga", "gai", "gan", "gang",
- "gao", "ge", "gei", "gen", "geng", "gong", "gou", "gu", "gua", "guai", "guan", "guang", "gui", "gun", "guo", "ha",
- "hai", "han", "hang", "hao", "he", "hei", "hen", "heng", "hm", "hng", "hong", "hou", "hu", "hua", "huai", "huan",
- "huang", "hui", "hun", "huo", "ji", "jia", "jian", "jiang", "jiao", "jie", "jin", "jing", "jiong", "jiu", "ju", "juan",
- "jue", "jun", "ka", "kai", "kan", "kang", "kao", "ke", "kei", "ken", "keng", "kong", "kou", "ku", "kua", "kuai",
- "kuan", "kuang", "kui", "kun", "kuo", "la", "lai", "lan", "lang", "lao", "le", "lei", "leng", "li", "lia", "lian",
- "liang", "liao", "lie", "lin", "ling", "liu", "long", "lou", "lu", "luan", "lun", "luo", "ma", "mai", "man", "mang",
- "mao", "me", "mei", "men", "meng", "mi", "mian", "miao", "mie", "min", "ming", "miu", "mo", "mou", "mu", "na",
- "nai", "nan", "nang", "nao", "ne", "nei", "nen", "neng", "ng", "ni", "nian", "niang", "niao", "nie", "nin", "ning",
- "niu", "nong", "nou", "nu", "nuan", "nuo", "o", "ou", "pa", "pai", "pan", "pang", "pao", "pei", "pen", "peng",
- "pi", "pian", "piao", "pie", "pin", "ping", "po", "pou", "pu", "qi", "qia", "qian", "qiang", "qiao", "qie", "qin",
- "qing", "qiong", "qiu", "qu", "quan", "que", "qun", "ran", "rang", "rao", "re", "ren", "reng", "ri", "rong", "rou",
- "ru", "rua", "ruan", "rui", "run", "ruo", "sa", "sai", "san", "sang", "sao", "se", "sei", "sen", "seng", "sha",
- "shai", "shan", "shang", "shao", "she", "shei", "shen", "sheng", "shi", "shou", "shu", "shua", "shuai", "shuan", "shuang", "shui",
- "shun", "shuo", "si", "song", "sou", "su", "suan", "sui", "sun", "suo", "ta", "tai", "tan", "tang", "tao", "te",
- "teng", "ti", "tian", "tiao", "tie", "ting", "tong", "tou", "tu", "tuan", "tui", "tun", "tuo", "wa", "wai", "wan",
- "wang", "wei", "wen", "weng", "wo", "wu", "xi", "xia", "xian", "xiang", "xiao", "xie", "xin", "xing", "xiong", "xiu",
- "xu", "xuan", "xue", "xun", "ya", "yan", "yang", "yao", "ye", "yi", "yin", "ying", "yong", "you", "yu", "yuan",
- "yue", "yun", "za", "zai", "zan", "zang", "zao", "ze", "zei", "zen", "zeng", "zha", "zhai", "zhan", "zhang", "zhao",
- "zhe", "zhei", "zhen", "zheng", "zhi", "zhong", "zhou", "zhu", "zhua", "zhuai", "zhuan", "zhuang", "zhui", "zhun", "zhuo", "zi",
- "zong", "zou", "zuan", "zui", "zun", "zuo", "zu",
- ),
- list(
- "al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it",
- "le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to",
- "ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin",
- "his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi",
- ),
-)
+ // Default namelist is the human namelist, and common is the human language, so might as well.
+ // Feel free to remove this at some point because common can generate some pretty cool names.
+ always_use_default_namelist = TRUE
+ /**
+ * This list really long, mainly because I can't make up my mind about which mandarin syllables should be removed,
+ * and the english syllables had to be duplicated so that there is roughly a 50-50 weighting.
+ *
+ * Sources:
+ * http://www.sttmedia.com/syllablefrequency-english
+ * http://www.chinahighlights.com/travelguide/learning-chinese/pinyin-syllables.htm
+ */
+ syllables = list(
+ // each sublist has an equal chance of being picked, so each syllable has an equal chance of being english or chinese
+ list(
+ "a", "ai", "an", "ang", "ao", "ba", "bai", "ban", "bang", "bao", "bei", "ben", "beng", "bi", "bian", "biao",
+ "bie", "bin", "bing", "bo", "bu", "ca", "cai", "can", "cang", "cao", "ce", "cei", "cen", "ceng", "cha", "chai",
+ "chan", "chang", "chao", "che", "chen", "cheng", "chi", "chong", "chou", "chu", "chua", "chuai", "chuan", "chuang", "chui", "chun",
+ "chuo", "ci", "cong", "cou", "cu", "cuan", "cui", "cun", "cuo", "da", "dai", "dan", "dang", "dao", "de", "dei",
+ "den", "deng", "di", "dian", "diao", "die", "ding", "diu", "dong", "dou", "du", "duan", "dui", "dun", "duo", "e",
+ "ei", "en", "er", "fa", "fan", "fang", "fei", "fen", "feng", "fo", "fou", "fu", "ga", "gai", "gan", "gang",
+ "gao", "ge", "gei", "gen", "geng", "gong", "gou", "gu", "gua", "guai", "guan", "guang", "gui", "gun", "guo", "ha",
+ "hai", "han", "hang", "hao", "he", "hei", "hen", "heng", "hm", "hng", "hong", "hou", "hu", "hua", "huai", "huan",
+ "huang", "hui", "hun", "huo", "ji", "jia", "jian", "jiang", "jiao", "jie", "jin", "jing", "jiong", "jiu", "ju", "juan",
+ "jue", "jun", "ka", "kai", "kan", "kang", "kao", "ke", "kei", "ken", "keng", "kong", "kou", "ku", "kua", "kuai",
+ "kuan", "kuang", "kui", "kun", "kuo", "la", "lai", "lan", "lang", "lao", "le", "lei", "leng", "li", "lia", "lian",
+ "liang", "liao", "lie", "lin", "ling", "liu", "long", "lou", "lu", "luan", "lun", "luo", "ma", "mai", "man", "mang",
+ "mao", "me", "mei", "men", "meng", "mi", "mian", "miao", "mie", "min", "ming", "miu", "mo", "mou", "mu", "na",
+ "nai", "nan", "nang", "nao", "ne", "nei", "nen", "neng", "ng", "ni", "nian", "niang", "niao", "nie", "nin", "ning",
+ "niu", "nong", "nou", "nu", "nuan", "nuo", "o", "ou", "pa", "pai", "pan", "pang", "pao", "pei", "pen", "peng",
+ "pi", "pian", "piao", "pie", "pin", "ping", "po", "pou", "pu", "qi", "qia", "qian", "qiang", "qiao", "qie", "qin",
+ "qing", "qiong", "qiu", "qu", "quan", "que", "qun", "ran", "rang", "rao", "re", "ren", "reng", "ri", "rong", "rou",
+ "ru", "rua", "ruan", "rui", "run", "ruo", "sa", "sai", "san", "sang", "sao", "se", "sei", "sen", "seng", "sha",
+ "shai", "shan", "shang", "shao", "she", "shei", "shen", "sheng", "shi", "shou", "shu", "shua", "shuai", "shuan", "shuang", "shui",
+ "shun", "shuo", "si", "song", "sou", "su", "suan", "sui", "sun", "suo", "ta", "tai", "tan", "tang", "tao", "te",
+ "teng", "ti", "tian", "tiao", "tie", "ting", "tong", "tou", "tu", "tuan", "tui", "tun", "tuo", "wa", "wai", "wan",
+ "wang", "wei", "wen", "weng", "wo", "wu", "xi", "xia", "xian", "xiang", "xiao", "xie", "xin", "xing", "xiong", "xiu",
+ "xu", "xuan", "xue", "xun", "ya", "yan", "yang", "yao", "ye", "yi", "yin", "ying", "yong", "you", "yu", "yuan",
+ "yue", "yun", "za", "zai", "zan", "zang", "zao", "ze", "zei", "zen", "zeng", "zha", "zhai", "zhan", "zhang", "zhao",
+ "zhe", "zhei", "zhen", "zheng", "zhi", "zhong", "zhou", "zhu", "zhua", "zhuai", "zhuan", "zhuang", "zhui", "zhun", "zhuo", "zi",
+ "zong", "zou", "zuan", "zui", "zun", "zuo", "zu",
+ ),
+ list(
+ "al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it",
+ "le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to",
+ "ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin",
+ "his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi",
+ ),
+ )
diff --git a/code/modules/language/draconic.dm b/code/modules/language/draconic.dm
index f812c8dc131..55ebd1ec202 100644
--- a/code/modules/language/draconic.dm
+++ b/code/modules/language/draconic.dm
@@ -13,5 +13,25 @@
"ra", "ar", "re", "er", "ri", "ir", "ro", "or", "ru", "ur", "rs", "sr",
"a", "a", "e", "e", "i", "i", "o", "o", "u", "u", "s", "s"
)
+ special_characters = list("-")
icon_state = "lizard"
default_priority = 90
+ default_name_syllable_min = 3
+ default_name_syllable_max = 5
+ random_name_spacer = "-"
+
+/datum/language/draconic/get_random_name(
+ gender = NEUTER,
+ name_count = default_name_count,
+ syllable_min = default_name_syllable_min,
+ syllable_max = default_name_syllable_max,
+ force_use_syllables = FALSE,
+)
+ if(force_use_syllables)
+ return ..()
+ if(gender != MALE)
+ gender = pick(MALE, FEMALE)
+
+ if(gender == MALE)
+ return "[pick(GLOB.lizard_names_male)][random_name_spacer][pick(GLOB.lizard_names_male)]"
+ return "[pick(GLOB.lizard_names_female)][random_name_spacer][pick(GLOB.lizard_names_female)]"
diff --git a/code/modules/language/drone.dm b/code/modules/language/drone.dm
index 5b47533d45e..09fb6546e4a 100644
--- a/code/modules/language/drone.dm
+++ b/code/modules/language/drone.dm
@@ -11,3 +11,4 @@
default_priority = 20
icon_state = "drone"
+ always_use_default_namelist = TRUE // Nonsense language
diff --git a/code/modules/language/language.dm b/code/modules/language/language.dm
deleted file mode 100644
index 9fc2abf0f5a..00000000000
--- a/code/modules/language/language.dm
+++ /dev/null
@@ -1,107 +0,0 @@
-#define SCRAMBLE_CACHE_LEN 50 //maximum of 50 specific scrambled lines per language
-
-/*
- Datum based languages. Easily editable and modular.
-*/
-
-/datum/language
- var/name = "an unknown language" // Fluff name of language if any.
- var/desc = "A language." // Short description for 'Check Languages'.
- var/key // Character used to speak in language
- // If key is null, then the language isn't real or learnable.
- var/flags // Various language flags.
- var/list/syllables // Used when scrambling text for a non-speaker.
- var/sentence_chance = 5 // Likelihood of making a new sentence after each syllable.
- var/space_chance = 55 // Likelihood of getting a space in the random scramble string
- var/list/spans = list()
- var/list/scramble_cache = list()
- var/default_priority = 0 // the language that an atom knows with the highest "default_priority" is selected by default.
-
- // if you are seeing someone speak popcorn language, then something is wrong.
- var/icon = 'icons/misc/language.dmi'
- var/icon_state = "popcorn"
-
-/datum/language/proc/display_icon(atom/movable/hearer)
- var/understands = hearer.has_language(src.type)
- if(flags & LANGUAGE_HIDE_ICON_IF_UNDERSTOOD && understands)
- return FALSE
- if(flags & LANGUAGE_HIDE_ICON_IF_NOT_UNDERSTOOD && !understands)
- return FALSE
- return TRUE
-
-/datum/language/proc/get_icon()
- var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/chat)
- return sheet.icon_tag("language-[icon_state]")
-
-/datum/language/proc/get_random_name(gender, name_count=2, syllable_count=4, syllable_divisor=2)
- if(!syllables || !syllables.len)
- if(gender == FEMALE)
- return capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names))
- else
- return capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names))
-
- var/full_name = ""
- var/new_name = ""
-
- for(var/i in 0 to name_count)
- new_name = ""
- var/Y = rand(FLOOR(syllable_count/syllable_divisor, 1), syllable_count)
- for(var/x in Y to 0)
- new_name += pick_weight_recursive(syllables)
- full_name += " [capitalize(LOWER_TEXT(new_name))]"
-
- return "[trim(full_name)]"
-
-/datum/language/proc/check_cache(input)
- var/lookup = scramble_cache[input]
- if(lookup)
- scramble_cache -= input
- scramble_cache[input] = lookup
- . = lookup
-
-/datum/language/proc/add_to_cache(input, scrambled_text)
- // Add it to cache, cutting old entries if the list is too long
- scramble_cache[input] = scrambled_text
- if(scramble_cache.len > SCRAMBLE_CACHE_LEN)
- scramble_cache.Cut(1, scramble_cache.len-SCRAMBLE_CACHE_LEN-1)
-
-/datum/language/proc/scramble(input)
-
- if(!syllables || !syllables.len)
- return stars(input)
-
- // If the input is cached already, move it to the end of the cache and return it
- var/lookup = check_cache(input)
- if(lookup)
- return lookup
-
- var/input_size = length_char(input)
- var/scrambled_text = ""
- var/capitalize = TRUE
-
- while(length_char(scrambled_text) < input_size)
- var/next = pick_weight_recursive(syllables)
- if(capitalize)
- next = capitalize(next)
- capitalize = FALSE
- scrambled_text += next
- var/chance = rand(100)
- if(chance <= sentence_chance)
- scrambled_text += ". "
- capitalize = TRUE
- else if(chance > sentence_chance && chance <= space_chance)
- scrambled_text += " "
-
- scrambled_text = trim(scrambled_text)
- var/ending = copytext_char(scrambled_text, -1)
- if(ending == ".")
- scrambled_text = copytext_char(scrambled_text, 1, -2)
- var/input_ending = copytext_char(input, -1)
- if(input_ending in list("!","?","."))
- scrambled_text += input_ending
-
- add_to_cache(input, scrambled_text)
-
- return scrambled_text
-
-#undef SCRAMBLE_CACHE_LEN
diff --git a/code/modules/language/machine.dm b/code/modules/language/machine.dm
index 36962a712a1..4be282a5e28 100644
--- a/code/modules/language/machine.dm
+++ b/code/modules/language/machine.dm
@@ -14,7 +14,16 @@
icon_state = "eal"
-/datum/language/machine/get_random_name()
+/datum/language/machine/get_random_name(
+ gender = NEUTER,
+ name_count = 2,
+ syllable_min = 2,
+ syllable_max = 4,
+ unique = FALSE,
+ force_use_syllables = FALSE,
+)
+ if(force_use_syllables)
+ return ..()
if(prob(70))
return "[pick(GLOB.posibrain_names)]-[rand(100, 999)]"
return pick(GLOB.ai_names)
diff --git a/code/modules/language/moffic.dm b/code/modules/language/moffic.dm
index 1d0aea96697..fb8dea63dcc 100644
--- a/code/modules/language/moffic.dm
+++ b/code/modules/language/moffic.dm
@@ -13,4 +13,20 @@
icon_state = "moth"
default_priority = 90
+ default_name_syllable_min = 5
+ default_name_syllable_max = 10
+
+/datum/language/moffic/get_random_name(
+ gender = NEUTER,
+ name_count = default_name_count,
+ syllable_min = default_name_syllable_min,
+ syllable_max = default_name_syllable_max,
+ force_use_syllables = FALSE,
+)
+ if(force_use_syllables)
+ return ..()
+
+ return "[pick(GLOB.moth_first)] [pick(GLOB.moth_last)]"
+
+
// Fuck guest accounts, and fuck language testing.
diff --git a/code/modules/language/monkey.dm b/code/modules/language/monkey.dm
index e44f6a6268e..423e94f22bd 100644
--- a/code/modules/language/monkey.dm
+++ b/code/modules/language/monkey.dm
@@ -7,3 +7,12 @@
default_priority = 80
icon_state = "animal"
+
+/datum/language/monkey/get_random_name(
+ gender = NEUTER,
+ name_count = 2,
+ syllable_min = 2,
+ syllable_max = 4,
+ force_use_syllables = FALSE,
+)
+ return "monkey ([rand(1, 999)])"
diff --git a/code/modules/language/mushroom.dm b/code/modules/language/mushroom.dm
index 08d494cc04d..910489fd6dd 100644
--- a/code/modules/language/mushroom.dm
+++ b/code/modules/language/mushroom.dm
@@ -5,3 +5,5 @@
sentence_chance = 0
default_priority = 80
syllables = list("poof", "pff", "pFfF", "piff", "puff", "pooof", "pfffff", "piffpiff", "puffpuff", "poofpoof", "pifpafpofpuf")
+ default_name_syllable_min = 1
+ default_name_syllable_max = 2
diff --git a/code/modules/language/nekomimetic.dm b/code/modules/language/nekomimetic.dm
index 82edc2afcb5..4be943f8441 100644
--- a/code/modules/language/nekomimetic.dm
+++ b/code/modules/language/nekomimetic.dm
@@ -12,3 +12,16 @@
)
icon_state = "neko"
default_priority = 90
+ default_name_syllable_min = 2
+ default_name_syllable_max = 2
+
+/datum/language/nekomimetic/get_random_name(
+ gender = NEUTER,
+ name_count = default_name_count,
+ syllable_min = default_name_syllable_min,
+ syllable_max = default_name_syllable_max,
+ force_use_syllables = FALSE,
+)
+ if(prob(33))
+ return default_name(gender)
+ return ..()
diff --git a/code/modules/language/piratespeak.dm b/code/modules/language/piratespeak.dm
index 5f6cb489771..a2faddb544f 100644
--- a/code/modules/language/piratespeak.dm
+++ b/code/modules/language/piratespeak.dm
@@ -10,3 +10,4 @@
"shiver", "timbers", "matey", "swashbuckler"
)
icon_state = "pirate"
+ always_use_default_namelist = TRUE
diff --git a/code/modules/language/shadowtongue.dm b/code/modules/language/shadowtongue.dm
index 9c0adb5eea3..35158939385 100644
--- a/code/modules/language/shadowtongue.dm
+++ b/code/modules/language/shadowtongue.dm
@@ -16,3 +16,5 @@
)
icon_state = "shadow"
default_priority = 90
+ default_name_syllable_min = 2
+ default_name_syllable_max = 3
diff --git a/code/modules/language/slime.dm b/code/modules/language/slime.dm
index fcb47177411..15960898673 100644
--- a/code/modules/language/slime.dm
+++ b/code/modules/language/slime.dm
@@ -2,7 +2,8 @@
name = "Slime"
desc = "A melodic and complex language spoken by slimes. Some of the notes are inaudible to humans."
key = "k"
- syllables = list("qr","qrr","xuq","qil","quum","xuqm","vol","xrim","zaoo","qu-uu","qix","qoo","zix","*","!")
+ syllables = list("qr","qrr","xuq","qil","quum","xuqm","vol","xrim","zaoo","qu-uu","qix","qoo","zix")
+ special_characters = list("!","*")
default_priority = 70
icon_state = "slime"
diff --git a/code/modules/language/sylvan.dm b/code/modules/language/sylvan.dm
index 68cb73f9d52..4f66fb5931c 100644
--- a/code/modules/language/sylvan.dm
+++ b/code/modules/language/sylvan.dm
@@ -13,3 +13,5 @@
)
icon_state = "plant"
default_priority = 90
+ default_name_syllable_min = 2
+ default_name_syllable_max = 3
diff --git a/code/modules/language/terrum.dm b/code/modules/language/terrum.dm
index 361106ed16c..63b527202f4 100644
--- a/code/modules/language/terrum.dm
+++ b/code/modules/language/terrum.dm
@@ -7,8 +7,25 @@
"sha", "vu", "nah", "ha", "yom", "ma", "cha", "ar", "et", "mol", "lua",
"ch", "na", "sh", "ni", "yah", "bes", "ol", "hish", "ev", "la", "ot", "la",
"khe", "tza", "chak", "hak", "hin", "hok", "lir", "tov", "yef", "yfe",
- "cho", "ar", "kas", "kal", "ra", "lom", "im", "'", "'", "'", "'", "bok",
+ "cho", "ar", "kas", "kal", "ra", "lom", "im", "bok",
"erev", "shlo", "lo", "ta", "im", "yom"
)
+ special_characters = list("'")
icon_state = "golem"
default_priority = 90
+
+/datum/language/terrum/get_random_name(
+ gender = NEUTER,
+ name_count = default_name_count,
+ syllable_min = default_name_syllable_min,
+ syllable_max = default_name_syllable_max,
+ force_use_syllables = FALSE,
+)
+ if(force_use_syllables)
+ return ..()
+
+ var/name = pick(GLOB.golem_names)
+ // 3% chance to be given a human surname for "lore reasons"
+ if (prob(3))
+ name += " [pick(GLOB.last_names)]"
+ return name
diff --git a/code/modules/language/voltaic.dm b/code/modules/language/voltaic.dm
index 40fa9dcb1e8..90ab90dbe48 100644
--- a/code/modules/language/voltaic.dm
+++ b/code/modules/language/voltaic.dm
@@ -12,3 +12,21 @@
)
icon_state = "volt"
default_priority = 90
+ default_name_syllable_min = 2
+ default_name_syllable_max = 3
+
+
+/datum/language/voltaic/get_random_name(
+ gender = NEUTER,
+ name_count = default_name_count,
+ syllable_min = default_name_syllable_min,
+ syllable_max = default_name_syllable_max,
+ force_use_syllables = FALSE,
+)
+ if(force_use_syllables)
+ return ..()
+
+ var/picked = "[pick(GLOB.ethereal_names)] [random_capital_letter()]"
+ if(prob(65))
+ picked += random_capital_letter()
+ return picked
diff --git a/code/modules/language/xenocommon.dm b/code/modules/language/xenocommon.dm
index c5e6366715d..f4949b7d73c 100644
--- a/code/modules/language/xenocommon.dm
+++ b/code/modules/language/xenocommon.dm
@@ -6,3 +6,4 @@
default_priority = 50
icon_state = "xeno"
+ always_use_default_namelist = TRUE // Sssss Ssss?
diff --git a/code/modules/mapping/mapping_helpers.dm b/code/modules/mapping/mapping_helpers.dm
index a2ffa244679..ff46cfc0b64 100644
--- a/code/modules/mapping/mapping_helpers.dm
+++ b/code/modules/mapping/mapping_helpers.dm
@@ -914,8 +914,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava)
var/datum/species/new_human_species = GLOB.species_list[species_to_pick]
if(new_human_species)
new_human.set_species(new_human_species)
- new_human_species = new_human.dna.species
- new_human.fully_replace_character_name(new_human.real_name, new_human_species.random_name(new_human.gender, TRUE, TRUE))
+ new_human.fully_replace_character_name(new_human.real_name, new_human.generate_random_mob_name())
else
stack_trace("failed to spawn cadaver with species ID [species_to_pick]") //if it's invalid they'll just be a human, so no need to worry too much aside from yelling at the server owner lol.
else
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index f7e4b56cab2..1d2a8d1570f 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -89,15 +89,10 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
gender = body.gender
if(body.mind && body.mind.name)
- if(body.mind.ghostname)
- name = body.mind.ghostname
- else
- name = body.mind.name
+ name = body.mind.ghostname || body.mind.name
else
- if(body.real_name)
- name = body.real_name
- else
- name = random_unique_name(gender)
+ name = body.real_name || generate_random_mob_name(gender)
+
mind = body.mind //we don't transfer the mind but we keep a reference to it.
@@ -125,8 +120,8 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
abstract_move(T)
- if(!name) //To prevent nameless ghosts
- name = random_unique_name(gender)
+ //To prevent nameless ghosts
+ name ||= generate_random_mob_name(FALSE)
real_name = name
if(!fun_verbs)
@@ -838,7 +833,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
client.prefs.apply_character_randomization_prefs()
var/species_type = client.prefs.read_preference(/datum/preference/choiced/species)
- var/datum/species/species = new species_type
+ var/datum/species/species = GLOB.species_prototypes[species_type]
if(species.check_head_flags(HEAD_HAIR))
hairstyle = client.prefs.read_preference(/datum/preference/choiced/hairstyle)
hair_color = ghostify_color(client.prefs.read_preference(/datum/preference/color/hair_color))
@@ -847,8 +842,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
facial_hairstyle = client.prefs.read_preference(/datum/preference/choiced/facial_hairstyle)
facial_hair_color = ghostify_color(client.prefs.read_preference(/datum/preference/color/facial_hair_color))
- qdel(species)
-
update_appearance()
/mob/dead/observer/can_perform_action(atom/movable/target, action_bitflags)
diff --git a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm
index 21943d39d3d..d2b5edc58cc 100644
--- a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm
+++ b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm
@@ -102,7 +102,7 @@
RegisterSignal(src, COMSIG_LIVING_BANED, PROC_REF(on_baned))
RegisterSignal(src, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(on_move))
RegisterSignal(src, COMSIG_LIVING_LIFE, PROC_REF(on_life))
- set_random_revenant_name()
+ name = generate_random_mob_name()
GLOB.revenant_relay_mobs |= src
@@ -357,13 +357,13 @@
returnable_list += span_bold("Be sure to read the wiki page to learn more.")
return returnable_list
-/mob/living/basic/revenant/proc/set_random_revenant_name()
+/mob/living/basic/revenant/generate_random_mob_name()
var/list/built_name_strings = list()
built_name_strings += pick(strings(REVENANT_NAME_FILE, "spirit_type"))
built_name_strings += " of "
built_name_strings += pick(strings(REVENANT_NAME_FILE, "adverb"))
built_name_strings += pick(strings(REVENANT_NAME_FILE, "theme"))
- name = built_name_strings.Join("")
+ return built_name_strings.Join("")
/mob/living/basic/revenant/proc/on_baned(obj/item/weapon, mob/living/user)
SIGNAL_HANDLER
diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm
index adfe93d318d..24a35e683e3 100644
--- a/code/modules/mob/living/carbon/human/_species.dm
+++ b/code/modules/mob/living/carbon/human/_species.dm
@@ -222,14 +222,12 @@ GLOBAL_LIST_EMPTY(features_by_species)
var/list/selectable_species = list()
for(var/species_type in subtypesof(/datum/species))
- var/datum/species/species = new species_type
+ var/datum/species/species = GLOB.species_prototypes[species_type]
if(species.check_roundstart_eligible())
selectable_species += species.id
- var/datum/language_holder/temp_holder = new species.species_language_holder
+ var/datum/language_holder/temp_holder = GLOB.prototype_language_holders[species.species_language_holder]
for(var/datum/language/spoken_language as anything in temp_holder.understood_languages)
GLOB.uncommon_roundstart_languages |= spoken_language
- qdel(temp_holder)
- qdel(species)
GLOB.uncommon_roundstart_languages -= /datum/language/common
if(!selectable_species.len)
@@ -248,32 +246,6 @@ GLOBAL_LIST_EMPTY(features_by_species)
return TRUE
return FALSE
-/**
- * Generates a random name for a carbon.
- *
- * This generates a random unique name based on a human's species and gender.
- * Arguments:
- * * gender - The gender that the name should adhere to. Use MALE for male names, use anything else for female names.
- * * unique - If true, ensures that this new name is not a duplicate of anyone else's name currently on the station.
- * * last_name - Do we use a given last name or pick a random new one?
- */
-/datum/species/proc/random_name(gender, unique, last_name)
- if(unique)
- return random_unique_name(gender)
-
- var/randname
- if(gender == MALE)
- randname = pick(GLOB.first_names_male)
- else
- randname = pick(GLOB.first_names_female)
-
- if(last_name)
- randname += " [last_name]"
- else
- randname += " [pick(GLOB.last_names)]"
-
- return randname
-
/**
* Copies some vars and properties over that should be kept when creating a copy of this species.
*
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 07135351a91..9d3d8c2d5a8 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -815,7 +815,7 @@
if(href_list[VV_HK_SET_SPECIES])
if(!check_rights(R_SPAWN))
return
- var/result = input(usr, "Please choose a new species","Species") as null|anything in GLOB.species_list
+ var/result = input(usr, "Please choose a new species","Species") as null|anything in sortTim(GLOB.species_list, GLOBAL_PROC_REF(cmp_text_asc))
if(result)
var/newtype = GLOB.species_list[result]
admin_ticket_log("[key_name_admin(usr)] has modified the bodyparts of [src] to [result]")
@@ -1019,7 +1019,7 @@
/mob/living/carbon/human/species/set_species(datum/species/mrace, icon_update, pref_load)
. = ..()
if(use_random_name)
- fully_replace_character_name(real_name, dna.species.random_name())
+ fully_replace_character_name(real_name, generate_random_mob_name())
/mob/living/carbon/human/species/abductor
race = /datum/species/abductor
diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm
index c7069ad056d..3315c5421d3 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -259,7 +259,7 @@
if (preference.is_randomizable())
preference.apply_to_human(src, preference.create_random_value(preferences))
- fully_replace_character_name(real_name, dna.species.random_name())
+ fully_replace_character_name(real_name, generate_random_mob_name())
/**
* Setter for mob height
diff --git a/code/modules/mob/living/carbon/human/species_types/ethereal.dm b/code/modules/mob/living/carbon/human/species_types/ethereal.dm
index e37e7ca8144..4c307107f15 100644
--- a/code/modules/mob/living/carbon/human/species_types/ethereal.dm
+++ b/code/modules/mob/living/carbon/human/species_types/ethereal.dm
@@ -80,14 +80,6 @@
QDEL_NULL(ethereal_light)
return ..()
-/datum/species/ethereal/random_name(gender,unique,lastname)
- if(unique)
- return random_unique_ethereal_name()
-
- var/randname = ethereal_name()
-
- return randname
-
/datum/species/ethereal/randomize_features()
var/list/features = ..()
features["ethcolor"] = GLOB.color_list_ethereal[pick(GLOB.color_list_ethereal)]
diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm
index 4e860014554..13471b2872b 100644
--- a/code/modules/mob/living/carbon/human/species_types/golems.dm
+++ b/code/modules/mob/living/carbon/human/species_types/golems.dm
@@ -51,15 +51,6 @@
BODY_ZONE_CHEST = /obj/item/bodypart/chest/golem,
)
- /// Chance that we will generate a human surname, for lore reasons
- var/human_surname_chance = 3
-
-/datum/species/golem/random_name(gender,unique,lastname)
- var/name = pick(GLOB.golem_names)
- if (prob(human_surname_chance))
- name += " [pick(GLOB.last_names)]"
- return name
-
/datum/species/golem/get_physical_attributes()
return "Golems are hardy creatures made out of stone, which are thus naturally resistant to many dangers, including asphyxiation, fire, radiation, electricity, and viruses.\
They gain special abilities depending on the type of material consumed, but they need to consume material to keep their body animated."
diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
index 1b478162de4..488d76cbd21 100644
--- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
@@ -47,18 +47,6 @@
/datum/species/lizard/body_temperature_core(mob/living/carbon/human/humi, seconds_per_tick, times_fired)
return
-/datum/species/lizard/random_name(gender,unique,lastname)
- if(unique)
- return random_unique_lizard_name(gender)
-
- var/randname = lizard_name(gender)
-
- if(lastname)
- randname += " [lastname]"
-
- return randname
-
-
/datum/species/lizard/randomize_features()
var/list/features = ..()
features["body_markings"] = pick(SSaccessories.body_markings_list)
diff --git a/code/modules/mob/living/carbon/human/species_types/monkeys.dm b/code/modules/mob/living/carbon/human/species_types/monkeys.dm
index cbd2df699ea..ddf0963bb5d 100644
--- a/code/modules/mob/living/carbon/human/species_types/monkeys.dm
+++ b/code/modules/mob/living/carbon/human/species_types/monkeys.dm
@@ -41,9 +41,6 @@
payday_modifier = 1.5
ai_controlled_species = TRUE
-/datum/species/monkey/random_name(gender,unique,lastname)
- return "monkey ([rand(1, 999)])"
-
/datum/species/monkey/on_species_gain(mob/living/carbon/human/human_who_gained_species, datum/species/old_species, pref_load)
. = ..()
passtable_on(human_who_gained_species, SPECIES_TRAIT)
diff --git a/code/modules/mob/living/carbon/human/species_types/mothmen.dm b/code/modules/mob/living/carbon/human/species_types/mothmen.dm
index e52a19b587b..54d6fe027e3 100644
--- a/code/modules/mob/living/carbon/human/species_types/mothmen.dm
+++ b/code/modules/mob/living/carbon/human/species_types/mothmen.dm
@@ -34,17 +34,6 @@
var/mob/living/carbon/human/H = C
handle_mutant_bodyparts(H)
-/datum/species/moth/random_name(gender,unique,lastname)
- if(unique)
- return random_unique_moth_name()
-
- var/randname = moth_name()
-
- if(lastname)
- randname += " [lastname]"
-
- return randname
-
/datum/species/moth/on_species_gain(mob/living/carbon/human/human_who_gained_species, datum/species/old_species, pref_load)
. = ..()
RegisterSignal(human_who_gained_species, COMSIG_MOB_APPLY_DAMAGE_MODIFIERS, PROC_REF(damage_weakness))
diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
index 2d053813e5b..e63e3c39c48 100644
--- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
+++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
@@ -129,17 +129,6 @@
else
give_important_for_life(equipping)
-/datum/species/plasmaman/random_name(gender,unique,lastname)
- if(unique)
- return random_unique_plasmaman_name()
-
- var/randname = plasmaman_name()
-
- if(lastname)
- randname += " [lastname]"
-
- return randname
-
/datum/species/plasmaman/get_scream_sound(mob/living/carbon/human)
return pick(
'sound/voice/plasmaman/plasmeme_scream_1.ogg',
diff --git a/code/modules/mob/living/living_say.dm b/code/modules/mob/living/living_say.dm
index 36a020ce3e7..bbcf77986ac 100644
--- a/code/modules/mob/living/living_say.dm
+++ b/code/modules/mob/living/living_say.dm
@@ -208,9 +208,9 @@ GLOBAL_LIST_INIT(message_modes_stat_limits, list(
spans |= speech_span
- if(language)
- var/datum/language/L = GLOB.language_datum_instances[language]
- spans |= L.spans
+ var/datum/language/spoken_lang = GLOB.language_datum_instances[language]
+ if(LAZYLEN(spoken_lang?.spans))
+ spans |= spoken_lang.spans
if(message_mods[MODE_SING])
var/randomnote = pick("\u2669", "\u266A", "\u266B")
diff --git a/code/modules/mob_spawn/ghost_roles/golem_roles.dm b/code/modules/mob_spawn/ghost_roles/golem_roles.dm
index b3475e9207f..5fc643bffa6 100644
--- a/code/modules/mob_spawn/ghost_roles/golem_roles.dm
+++ b/code/modules/mob_spawn/ghost_roles/golem_roles.dm
@@ -36,8 +36,7 @@
if(forced_name || !iscarbon(spawned_mob))
return ..()
- var/datum/species/golem/golem_species = new()
- forced_name = golem_species.random_name()
+ forced_name = generate_random_name_species_based(spawned_mob.gender, TRUE, species_type = /datum/species/golem)
return ..()
/obj/effect/mob_spawn/ghost_role/human/golem/special(mob/living/new_spawn, mob/mob_possessor)
diff --git a/code/modules/mob_spawn/ghost_roles/mining_roles.dm b/code/modules/mob_spawn/ghost_roles/mining_roles.dm
index 208a74a3edb..53fa0010970 100644
--- a/code/modules/mob_spawn/ghost_roles/mining_roles.dm
+++ b/code/modules/mob_spawn/ghost_roles/mining_roles.dm
@@ -194,9 +194,9 @@
/obj/structure/ash_walker_eggshell/Destroy()
if(!egg)
return ..()
- var/mob/living/carbon/human/yolk = new /mob/living/carbon/human/(get_turf(src))
- yolk.fully_replace_character_name(null,random_unique_lizard_name(gender))
+ var/mob/living/carbon/human/yolk = new(get_turf(src))
yolk.set_species(/datum/species/lizard/ashwalker)
+ yolk.fully_replace_character_name(null, yolk.generate_random_mob_name(TRUE))
yolk.underwear = "Nude"
yolk.equipOutfit(/datum/outfit/ashwalker)//this is an authentic mess we're making
yolk.update_body()
@@ -235,7 +235,7 @@
/obj/effect/mob_spawn/ghost_role/human/ash_walker/special(mob/living/carbon/human/spawned_human)
. = ..()
- spawned_human.fully_replace_character_name(null,random_unique_lizard_name(gender))
+ spawned_human.fully_replace_character_name(null, spawned_human.generate_random_mob_name(TRUE))
to_chat(spawned_human, "Drag the corpses of men and beasts to your nest. It will absorb them to create more of your kind. Invade the strange structure of the outsiders if you must. Do not cause unnecessary destruction, as littering the wastes with ugly wreckage is certain to not gain you favor. Glory to the Necropolis!")
spawned_human.mind.add_antag_datum(/datum/antagonist/ashwalker, team)
diff --git a/code/modules/mob_spawn/mob_spawn.dm b/code/modules/mob_spawn/mob_spawn.dm
index 086254aae38..ad8c7e6a03e 100644
--- a/code/modules/mob_spawn/mob_spawn.dm
+++ b/code/modules/mob_spawn/mob_spawn.dm
@@ -78,7 +78,7 @@
if(skin_tone)
spawned_human.skin_tone = skin_tone
else
- spawned_human.skin_tone = random_skin_tone()
+ spawned_human.skin_tone = pick(GLOB.skin_tones)
spawned_human.update_body(is_creating = TRUE)
/obj/effect/mob_spawn/proc/name_mob(mob/living/spawned_mob, forced_name)
diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm
index 62e13ecb7f9..6ac45f9424d 100644
--- a/code/modules/shuttle/emergency.dm
+++ b/code/modules/shuttle/emergency.dm
@@ -293,13 +293,12 @@
obj_flags |= EMAGGED
SSshuttle.emergency.movement_force = list("KNOCKDOWN" = 60, "THROW" = 20)//YOUR PUNY SEATBELTS can SAVE YOU NOW, MORTAL
- var/datum/species/S = new
for(var/i in 1 to 10)
// the shuttle system doesn't know who these people are, but they
// must be important, surely
var/obj/item/card/id/ID = new(src)
var/datum/job/J = pick(SSjob.joinable_occupations)
- ID.registered_name = S.random_name(pick(MALE, FEMALE))
+ ID.registered_name = generate_random_name_species_based(species_type = /datum/species/human)
ID.assignment = J.title
authorized += ID
diff --git a/code/modules/surgery/plastic_surgery.dm b/code/modules/surgery/plastic_surgery.dm
index 9224c29b2db..8be13802e7c 100644
--- a/code/modules/surgery/plastic_surgery.dm
+++ b/code/modules/surgery/plastic_surgery.dm
@@ -94,11 +94,11 @@
else
user.visible_message(span_warning("You have no picture to base the appearance on, reverting to random appearances."))
for(var/i in 1 to 10)
- names += target.dna.species.random_name(target.gender, TRUE)
+ names += target.generate_random_mob_name(TRUE)
else
- for(var/_i in 1 to 9)
+ for(var/j in 1 to 9)
names += "Subject [target.gender == MALE ? "i" : "o"]-[pick("a", "b", "c", "d", "e")]-[rand(10000, 99999)]"
- names += target.dna.species.random_name(target.gender, TRUE) //give one normal name in case they want to do regular plastic surgery
+ names += target.generate_random_mob_name(TRUE) //give one normal name in case they want to do regular plastic surgery
var/chosen_name = tgui_input_list(user, "New name to assign", "Plastic Surgery", names)
if(isnull(chosen_name))
return
diff --git a/code/modules/unit_tests/preference_species.dm b/code/modules/unit_tests/preference_species.dm
index 8e49f49cdd6..8d913cc8fb6 100644
--- a/code/modules/unit_tests/preference_species.dm
+++ b/code/modules/unit_tests/preference_species.dm
@@ -12,7 +12,7 @@
for(var/species_id in get_selectable_species())
var/species_type = GLOB.species_list[species_id]
- var/datum/species/species = new species_type()
+ var/datum/species/species = GLOB.species_prototypes[species_type]
// Check the species decription.
// If it's not overridden, a stack trace will be thrown (and fail the test).
@@ -29,5 +29,3 @@
TEST_FAIL("Species [species] ([species_type]) is selectable, but did not properly implement get_species_lore().")
else if(!islist(species_lore))
TEST_FAIL("Species [species] ([species_type]) is selectable, but did not properly implement get_species_lore() (Did not return a list).")
-
- qdel(species)
diff --git a/tgstation.dme b/tgstation.dme
index 7e6bf667f0c..c7cea8aae3a 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -651,7 +651,6 @@
#include "code\controllers\subsystem\ipintel.dm"
#include "code\controllers\subsystem\job.dm"
#include "code\controllers\subsystem\lag_switch.dm"
-#include "code\controllers\subsystem\language.dm"
#include "code\controllers\subsystem\library.dm"
#include "code\controllers\subsystem\lighting.dm"
#include "code\controllers\subsystem\lua.dm"
@@ -4333,6 +4332,10 @@
#include "code\modules\keybindings\bindings_client.dm"
#include "code\modules\keybindings\focus.dm"
#include "code\modules\keybindings\setup.dm"
+#include "code\modules\language\_language.dm"
+#include "code\modules\language\_language_holder.dm"
+#include "code\modules\language\_language_manuals.dm"
+#include "code\modules\language\_language_menu.dm"
#include "code\modules\language\aphasia.dm"
#include "code\modules\language\beachbum.dm"
#include "code\modules\language\buzzwords.dm"
@@ -4341,10 +4344,6 @@
#include "code\modules\language\common.dm"
#include "code\modules\language\draconic.dm"
#include "code\modules\language\drone.dm"
-#include "code\modules\language\language.dm"
-#include "code\modules\language\language_holder.dm"
-#include "code\modules\language\language_manuals.dm"
-#include "code\modules\language\language_menu.dm"
#include "code\modules\language\machine.dm"
#include "code\modules\language\moffic.dm"
#include "code\modules\language\monkey.dm"