diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm index 1c6b4b90bc6..6f7d9c987f7 100644 --- a/code/_globalvars/lists/mobs.dm +++ b/code/_globalvars/lists/mobs.dm @@ -57,6 +57,8 @@ GLOBAL_LIST_EMPTY(narcd_underages) GLOBAL_LIST_EMPTY(language_datum_instances) GLOBAL_LIST_EMPTY(all_languages) +///List of all languages ("name" = type) +GLOBAL_LIST_EMPTY(language_types_by_name) GLOBAL_LIST_EMPTY(sentient_disease_instances) diff --git a/code/controllers/subsystem/language.dm b/code/controllers/subsystem/language.dm index c13711db364..88e92e2f93c 100644 --- a/code/controllers/subsystem/language.dm +++ b/code/controllers/subsystem/language.dm @@ -4,15 +4,14 @@ SUBSYSTEM_DEF(language) flags = SS_NO_FIRE /datum/controller/subsystem/language/Initialize() - for(var/L in subtypesof(/datum/language)) - var/datum/language/language = L + 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/controllers/subsystem/processing/quirks.dm b/code/controllers/subsystem/processing/quirks.dm index 000f5b9b64d..3a796c3f5b0 100644 --- a/code/controllers/subsystem/processing/quirks.dm +++ b/code/controllers/subsystem/processing/quirks.dm @@ -32,6 +32,7 @@ PROCESSING_SUBSYSTEM_DEF(quirks) list("Social Anxiety", "Mute"), list("Mute", "Soft-Spoken"), list("Stormtrooper Aim", "Big Hands"), + list("Bilingual", "Foreigner"), ) /datum/controller/subsystem/processing/quirks/Initialize() diff --git a/code/datums/quirks/positive_quirks.dm b/code/datums/quirks/positive_quirks.dm index a82315aacbe..4283afe69be 100644 --- a/code/datums/quirks/positive_quirks.dm +++ b/code/datums/quirks/positive_quirks.dm @@ -215,46 +215,22 @@ gain_text = span_notice("Some of the words of the people around you certainly aren't common. Good thing you studied for this.") lose_text = span_notice("You seem to have forgotten your second language.") medical_record_text = "Patient speaks multiple languages." - var/list/possible_languages = list( - /datum/language/aphasia, - /datum/language/beachbum, - /datum/language/calcic, - /datum/language/draconic, - /datum/language/moffic, - /datum/language/monkey, - /datum/language/mushroom, - /datum/language/nekomimetic, - /datum/language/piratespeak, - /datum/language/shadowtongue, - /datum/language/slime, - /datum/language/sylvan, - /datum/language/terrum, - /datum/language/voltaic, - ) - var/datum/language/extra_language mail_goodies = list(/obj/item/taperecorder, /obj/item/clothing/head/frenchberet, /obj/item/clothing/mask/fakemoustache/italian) -/datum/quirk/bilingual/add(client/client_source) - //prevents yourself from learning a language you already have - for(var/datum/language/spoken as anything in possible_languages) - if(quirk_holder.has_language(spoken)) - possible_languages -= spoken - if(!length(possible_languages)) - return - extra_language = pick(possible_languages) - quirk_holder.grant_language(extra_language, understood = TRUE, spoken = TRUE, source = LANGUAGE_QUIRK) - -/datum/quirk/bilingual/post_add() - if(extra_language) - to_chat(quirk_holder, span_info("From your bilingualism, you are additionally fluent in [initial(extra_language.name)].")) +/datum/quirk/bilingual/add_unique(client/client_source) + var/wanted_language = client_source?.prefs.read_preference(/datum/preference/choiced/language) + var/datum/language/language_type + if(wanted_language == "Random") + language_type = pick(GLOB.roundstart_languages) else - to_chat(quirk_holder, span_info("You are already fluent in all languages, making you far more than bilingual.")) - -/datum/quirk/bilingual/remove() - if(!extra_language) - return - - quirk_holder.remove_language(extra_language) + language_type = GLOB.language_types_by_name[wanted_language] + if(quirk_holder.has_language(language_type)) + language_type = /datum/language/uncommon + if(quirk_holder.has_language(language_type)) + to_chat(quirk_holder, span_boldnotice("You are already familiar with the quirk in your preferences, so you did not learn one.")) + return + to_chat(quirk_holder, span_boldnotice("You are already familiar with the quirk in your preferences, so you learned Galactic Uncommon instead.")) + quirk_holder.grant_language(language_type, source = LANGUAGE_QUIRK) /datum/quirk/item_quirk/poster_boy name = "Poster Boy" diff --git a/code/modules/client/preferences/language.dm b/code/modules/client/preferences/language.dm new file mode 100644 index 00000000000..d6baec86ddf --- /dev/null +++ b/code/modules/client/preferences/language.dm @@ -0,0 +1,34 @@ +/datum/preference/choiced/language + category = PREFERENCE_CATEGORY_SECONDARY_FEATURES + savefile_key = "language" + savefile_identifier = PREFERENCE_CHARACTER + +/datum/preference/choiced/language/is_accessible(datum/preferences/preferences) + if (!..(preferences)) + return FALSE + + return "Bilingual" in preferences.all_quirks + +/datum/preference/choiced/language/init_possible_values() + var/list/values = list() + + if(!GLOB.roundstart_languages.len) + generate_selectable_species_and_languages() + + values += "Random" + + //we add uncommon as it's foreigner-only. + var/datum/language/uncommon/uncommon_language = /datum/language/uncommon + values += initial(uncommon_language.name) + + for(var/datum/language/language_type as anything in GLOB.roundstart_languages) + if(ispath(language_type, /datum/language/common)) + continue + if(initial(language_type.name) in values) + continue + values += initial(language_type.name) + + return values + +/datum/preference/choiced/language/apply_to_human(mob/living/carbon/human/target, value) + return diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index ea4830e3e4d..c9e1a55615c 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -1,4 +1,6 @@ GLOBAL_LIST_EMPTY(roundstart_races) +///List of all roundstart languages by path +GLOBAL_LIST_EMPTY(roundstart_languages) /// An assoc list of species types to their features (from get_features()) GLOBAL_LIST_EMPTY(features_by_species) @@ -52,7 +54,7 @@ GLOBAL_LIST_EMPTY(features_by_species) ///flags for inventory slots the race can't equip stuff to. Golems cannot wear jumpsuits, for example. var/no_equip_flags ///What languages this species can understand and say. Use a [language holder datum][/datum/language_holder] in this var. - var/species_language_holder = /datum/language_holder + var/datum/language_holder/species_language_holder = /datum/language_holder /** * Visible CURRENT bodyparts that are unique to a species. * DO NOT USE THIS AS A LIST OF ALL POSSIBLE BODYPARTS AS IT WILL FUCK @@ -207,23 +209,28 @@ GLOBAL_LIST_EMPTY(features_by_species) RETURN_TYPE(/list) if (!GLOB.roundstart_races.len) - GLOB.roundstart_races = generate_selectable_species() + GLOB.roundstart_races = generate_selectable_species_and_languages() return GLOB.roundstart_races - /** * Generates species available to choose in character setup at roundstart * * This proc generates which species are available to pick from in character setup. * If there are no available roundstart species, defaults to human. */ -/proc/generate_selectable_species() +/proc/generate_selectable_species_and_languages() var/list/selectable_species = list() for(var/species_type in subtypesof(/datum/species)) var/datum/species/species = new species_type if(species.check_roundstart_eligible()) selectable_species += species.id + var/datum/language_holder/temp_holder = new species.species_language_holder + for(var/datum/language/spoken_languages as anything in temp_holder.understood_languages) + if(spoken_languages in GLOB.roundstart_languages) + continue + GLOB.roundstart_languages += spoken_languages + qdel(temp_holder) qdel(species) if(!selectable_species.len) @@ -235,7 +242,7 @@ GLOBAL_LIST_EMPTY(features_by_species) * Checks if a species is eligible to be picked at roundstart. * * Checks the config to see if this species is allowed to be picked in the character setup menu. - * Used by [/proc/generate_selectable_species]. + * Used by [/proc/generate_selectable_species_and_languages]. */ /datum/species/proc/check_roundstart_eligible() if(id in (CONFIG_GET(keyed_list/roundstart_races))) diff --git a/tgstation.dme b/tgstation.dme index 9e292a78546..3cc12d27771 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -3109,6 +3109,7 @@ #include "code\modules\client\preferences\hotkeys.dm" #include "code\modules\client\preferences\item_outlines.dm" #include "code\modules\client\preferences\jobless_role.dm" +#include "code\modules\client\preferences\language.dm" #include "code\modules\client\preferences\mod_select.dm" #include "code\modules\client\preferences\multiz_parallax.dm" #include "code\modules\client\preferences\multiz_performance.dm" diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/language.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/language.tsx new file mode 100644 index 00000000000..6b1a1be1220 --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/language.tsx @@ -0,0 +1,6 @@ +import { FeatureChoiced, FeatureDropdownInput } from '../base'; + +export const language: FeatureChoiced = { + name: 'Language', + component: FeatureDropdownInput, +};