Random Name Generation refactor, generate random names based on languages (for species without name lists, like Felinids and Podpeople) (#83021)

## About The Pull Request

This PR moves random name generation for species onto their languages. 

What does this mean? 

- For species with a predefined name list, such as Lizards and Moths,
nothing.

- For species without predefined name lists, such as Felinids, their
names will now be randomly generated from their language's syllables.


![image](https://github.com/tgstation/tgstation/assets/51863163/dddce7a6-5882-4f97-b817-c8922033c8d2)


![image](https://github.com/tgstation/tgstation/assets/51863163/e34e03e9-bcca-45ff-84e4-239e606cd24f)

(In the prefs menu:) 


![image](https://github.com/tgstation/tgstation/assets/51863163/eb6ccf9b-8b1c-4637-b46e-66cab9c8aac0)

Why? 

- Well, we actually had some dead code that did this. All I did was fix
it up and re-enable it.
- Generates some pretty believable in-universe names for various
languages that are lacking name lists. Obviously defined lists would be
preferred, but until they are added, at least.
- Moves some stuff off of species, which is always nice. 
- Also hopefully makes it a tad easier to work with name generation.
There's now a standard framework for getting a random name for a mob,
and for getting a random name based on a species.

Misc: 

- Adds a generic `species_prototype` global, uses it in a lot of places
in prefs code.
- Makes `GLOB.species_list` init via the global defines
- Deletes Language SS
- Alphabetizes some instances of admin tooling using the list of all
species IDs
- Docs language stuff
- Deletes random_skin_tone, it does pretty much nothin

## Changelog

🆑 Melbert
refactor: Random Name Generation has been refactored. Report any
instances of people having weird (or "Unknown") names.
qol: Felinids, Slimepeople, Podpeople, and some other species without
defined namelists now automatically generate names based on their
primary language(s).
qol: More non-human names can be generated in codewords (and other misc.
areas) than just lizard names.
/🆑
This commit is contained in:
MrMelbert
2024-05-04 12:21:26 -06:00
committed by GitHub
parent 6e57b94657
commit 0cc5cfb178
68 changed files with 532 additions and 432 deletions
-8
View File
@@ -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()
-44
View File
@@ -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)
+72 -22
View File
@@ -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)
+47 -4
View File
@@ -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)
+2 -2
View File
@@ -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"))
-17
View File
@@ -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
+2 -2
View File
@@ -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()
@@ -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)
+2 -8
View File
@@ -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()]"
@@ -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)
+1 -1
View File
@@ -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"
+1 -2
View File
@@ -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)
+1 -1
View File
@@ -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)
+2 -2
View File
@@ -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)
+1 -2
View File
@@ -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).
+1 -2
View File
@@ -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)
@@ -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
+1 -1
View File
@@ -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()
+6 -9
View File
@@ -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"
+1 -3
View File
@@ -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
@@ -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()
@@ -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)
+11 -9
View File
@@ -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.
+164
View File
@@ -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
+1
View File
@@ -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
+1 -1
View File
@@ -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
+1
View File
@@ -8,3 +8,4 @@
)
icon_state = "buzz"
default_priority = 90
always_use_default_namelist = TRUE // Otherwise we get Bzzbzbz Zzzbzbz.
+12
View File
@@ -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.
+1
View File
@@ -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)
+48 -47
View File
@@ -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",
),
)
+20
View File
@@ -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)]"
+1
View File
@@ -11,3 +11,4 @@
default_priority = 20
icon_state = "drone"
always_use_default_namelist = TRUE // Nonsense language
-107
View File
@@ -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
+10 -1
View File
@@ -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)
+16
View File
@@ -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.
+9
View File
@@ -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)])"
+2
View File
@@ -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
+13
View File
@@ -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 ..()
+1
View File
@@ -10,3 +10,4 @@
"shiver", "timbers", "matey", "swashbuckler"
)
icon_state = "pirate"
always_use_default_namelist = TRUE
+2
View File
@@ -16,3 +16,5 @@
)
icon_state = "shadow"
default_priority = 90
default_name_syllable_min = 2
default_name_syllable_max = 3
+2 -1
View File
@@ -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"
+2
View File
@@ -13,3 +13,5 @@
)
icon_state = "plant"
default_priority = 90
default_name_syllable_min = 2
default_name_syllable_max = 3
+18 -1
View File
@@ -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
+18
View File
@@ -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
+1
View File
@@ -6,3 +6,4 @@
default_priority = 50
icon_state = "xeno"
always_use_default_namelist = TRUE // Sssss Ssss?
+1 -2
View File
@@ -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
+6 -13
View File
@@ -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)
@@ -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 <a href=\"https://tgstation13.org/wiki/Revenant\">the wiki page</a> 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
@@ -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.
*
@@ -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
@@ -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
@@ -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)]
@@ -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."
@@ -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)
@@ -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)
@@ -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))
@@ -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',
+3 -3
View File
@@ -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")
@@ -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)
@@ -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, "<b>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!</b>")
spawned_human.mind.add_antag_datum(/datum/antagonist/ashwalker, team)
+1 -1
View File
@@ -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)
+1 -2
View File
@@ -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
+3 -3
View File
@@ -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
@@ -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)
+4 -5
View File
@@ -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"