diff --git a/code/_helpers/global_lists.dm b/code/_helpers/global_lists.dm
index 9ffc08ca92f..863f33177eb 100644
--- a/code/_helpers/global_lists.dm
+++ b/code/_helpers/global_lists.dm
@@ -120,9 +120,7 @@ var/global/list/syndicate_access = list(access_maint_tunnels, access_syndicate,
for (var/language_name in all_languages)
var/datum/language/L = all_languages[language_name]
if(!(L.flags & NONGLOBAL))
- language_keys[":[lowertext(L.key)]"] = L
- language_keys[".[lowertext(L.key)]"] = L
- language_keys["#[lowertext(L.key)]"] = L
+ language_keys[lowertext(L.key)] = L
var/rkey = 0
paths = typesof(/datum/species)-/datum/species
diff --git a/code/_helpers/text.dm b/code/_helpers/text.dm
index 5aa80299c74..549060b0af0 100644
--- a/code/_helpers/text.dm
+++ b/code/_helpers/text.dm
@@ -314,3 +314,19 @@ proc/TextPreview(var/string,var/len=40)
if(C && (C.prefs.toggles & CHAT_NOICONS))
return tagdesc
return "
"
+
+/proc/contains_az09(var/input)
+ for(var/i=1, i<=length(input), i++)
+ var/ascii_char = text2ascii(input,i)
+ switch(ascii_char)
+ // A .. Z
+ if(65 to 90) //Uppercase Letters
+ return 1
+ // a .. z
+ if(97 to 122) //Lowercase Letters
+ return 1
+
+ // 0 .. 9
+ if(48 to 57) //Numbers
+ return 1
+ return 0
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index a9e63045bd0..17e45736c05 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -210,6 +210,8 @@ var/list/gamemode_cache = list()
var/aggressive_changelog = 0
+ var/list/language_prefixes = list(",","#","-")//Default language prefixes
+
/datum/configuration/New()
var/list/L = typesof(/datum/game_mode) - /datum/game_mode
for (var/T in L)
@@ -679,6 +681,11 @@ var/list/gamemode_cache = list()
if("aggressive_changelog")
config.aggressive_changelog = 1
+ if("default_language_prefixes")
+ var/list/values = text2list(value, " ")
+ if(values.len > 0)
+ language_prefixes = values
+
else
log_misc("Unknown setting in configuration: '[name]'")
diff --git a/code/game/antagonist/station/changeling.dm b/code/game/antagonist/station/changeling.dm
index f6307b8ae8b..ded3361cd2f 100644
--- a/code/game/antagonist/station/changeling.dm
+++ b/code/game/antagonist/station/changeling.dm
@@ -7,7 +7,7 @@
feedback_tag = "changeling_objective"
restricted_jobs = list("AI", "Cyborg")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain")
- welcome_text = "Use say \":g message\" to communicate with your fellow changelings. Remember: you get all of their absorbed DNA if you absorb them."
+ welcome_text = "Use say \"#g message\" to communicate with your fellow changelings. Remember: you get all of their absorbed DNA if you absorb them."
flags = ANTAG_SUSPICIOUS | ANTAG_RANDSPAWN | ANTAG_VOTABLE
/datum/antagonist/changeling/get_special_objective_text(var/datum/mind/player)
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index caed5c70e8a..fa08c3360ff 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -76,6 +76,7 @@ datum/preferences
var/species = "Human" //Species datum to use.
var/species_preview //Used for the species selection window.
var/list/alternate_languages = list() //Secondary language(s)
+ var/list/language_prefixes = list() //Kanguage prefix keys
var/list/gear //Custom/fluff item loadout.
//Some faction information.
@@ -401,8 +402,11 @@ datum/preferences
dat += "- add ([S.num_alternate_languages - alternate_languages.len] remaining)
"
else
dat += "- [species] cannot choose secondary languages.
"
- dat += "
"
+ dat += "Language Keys
"
+ dat += " [english_list(language_prefixes, and_text = " ", comma_text = " ")] Change
"
+
+ dat += "
"
var/list/undies = gender == MALE ? underwear_m : underwear_f
dat += "Underwear: [get_key_by_value(undies,underwear)]
"
@@ -1175,6 +1179,26 @@ datum/preferences
if(new_lang)
alternate_languages |= new_lang
+ else if(href_list["preference"] == "language_prefix")
+ var/char
+ var/keys[0]
+ do
+ char = input("Enter a single special character.\nYou may re-select the same characters.\nThe following characters are already in use by radio: ; : .\nThe following characters are already in use by special say commands: ! *", "Enter Character - [3 - keys.len] remaining") as null|text
+ if(char)
+ if(length(char) > 1)
+ alert("Only single characters allowed.", "Error", "Ok")
+ else if(char in list(";", ":", "."))
+ alert("Radio character. Rejected.", "Error", "Ok")
+ else if(char in list("!","*"))
+ alert("Say character. Rejected.", "Error", "Ok")
+ else if(contains_az09(char))
+ alert("Non-special character. Rejected.", "Error", "Ok")
+ else
+ keys.Add(char)
+ while(char && keys.len < 3)
+
+ if(keys.len == 3)
+ language_prefixes = keys
switch(href_list["task"])
if("change")
if(href_list["preference"] == "species")
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index cce0b01afe2..cc721a62eed 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -110,8 +110,11 @@
S["spawnpoint"] >> spawnpoint
S["language"] >> alternate_languages
+ S["language_prefixes"] >> language_prefixes
if(isnull(alternate_languages))
alternate_languages = list()
+ if(isnull(language_prefixes) || !language_prefixes.len)
+ language_prefixes = config.language_prefixes.Copy()
if(!islist(alternate_languages))
if(client)
// Warn them that we (probably) just broke their languages
@@ -287,6 +290,7 @@
S["age"] << age
S["species"] << species
S["language"] << alternate_languages
+ S["language_prefixes"] << language_prefixes
S["hair_red"] << r_hair
S["hair_green"] << g_hair
S["hair_blue"] << b_hair
diff --git a/code/modules/mob/language/language.dm b/code/modules/mob/language/language.dm
index bf90079db86..3aa5e2aa628 100644
--- a/code/modules/mob/language/language.dm
+++ b/code/modules/mob/language/language.dm
@@ -101,15 +101,17 @@
log_say("[key_name(speaker)] : ([name]) [message]")
if(!speaker_mask) speaker_mask = speaker.name
- for(var/mob/player in player_list)
- player.hear_broadcast(src, speaker, speaker_mask, format_message(message, get_spoken_verb(message)))
+ message = format_message(message, get_spoken_verb(message))
-/mob/proc/hear_broadcast(var/datum/language/language, var/speaker, var/message)
+ for(var/mob/player in player_list)
+ player.hear_broadcast(src, speaker, speaker_mask, message)
+
+/mob/proc/hear_broadcast(var/datum/language/language, var/mob/speaker, var/speaker_name, var/message)
if((language in languages) && language.check_special_condition(src))
- var/msg = "[language.name], [speaker] [message]"
+ var/msg = "[language.name], [speaker_name] [message]"
src << msg
-/mob/new_player/hear_broadcast()
+/mob/new_player/hear_broadcast(var/datum/language/language, var/mob/speaker, var/speaker_name, var/message)
return
/mob/dead/observer/hear_broadcast(var/datum/language/language, var/mob/speaker, var/speaker_name, var/message)
@@ -153,9 +155,20 @@
// Can we speak this language, as opposed to just understanding it?
/mob/proc/can_speak(datum/language/speaking)
-
return (universal_speak || (speaking && speaking.flags & INNATE) || speaking in src.languages)
+/mob/proc/get_language_prefix()
+ if(client && client.prefs.language_prefixes && client.prefs.language_prefixes.len)
+ return client.prefs.language_prefixes[1]
+
+ return config.language_prefixes[1]
+
+/mob/proc/is_language_prefix(var/prefix)
+ if(client && client.prefs.language_prefixes && client.prefs.language_prefixes.len)
+ return prefix in client.prefs.language_prefixes
+
+ return prefix in config.language_prefixes
+
//TBD
/mob/verb/check_languages()
set name = "Check Known Languages"
@@ -166,7 +179,7 @@
for(var/datum/language/L in languages)
if(!(L.flags & NONGLOBAL))
- dat += "[L.name] (:[L.key])
[L.desc]
"
+ dat += "[L.name] ([get_language_prefix()][L.key])
[L.desc]
"
src << browse(dat, "window=checklanguage")
return
@@ -180,9 +193,9 @@
for(var/datum/language/L in languages)
if(!(L.flags & NONGLOBAL))
if(L == default_language)
- dat += "[L.name] (:[L.key]) - default - reset
[L.desc]
"
+ dat += "[L.name] ([get_language_prefix()][L.key]) - default - reset
[L.desc]
"
else
- dat += "[L.name] (:[L.key]) - set default
[L.desc]
"
+ dat += "[L.name] ([get_language_prefix()][L.key]) - set default
[L.desc]
"
src << browse(dat, "window=checklanguage")
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index e40c0d955e0..c2f1f297a92 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -1,49 +1,49 @@
var/list/department_radio_keys = list(
- ":r" = "right ear", "#r" = "right ear", ".r" = "right ear",
- ":l" = "left ear", "#l" = "left ear", ".l" = "left ear",
- ":i" = "intercom", "#i" = "intercom", ".i" = "intercom",
- ":h" = "department", "#h" = "department", ".h" = "department",
- ":+" = "special", "#+" = "special", ".+" = "special", //activate radio-specific special functions
- ":c" = "Command", "#c" = "Command", ".c" = "Command",
- ":n" = "Science", "#n" = "Science", ".n" = "Science",
- ":m" = "Medical", "#m" = "Medical", ".m" = "Medical",
- ":e" = "Engineering", "#e" = "Engineering", ".e" = "Engineering",
- ":s" = "Security", "#s" = "Security", ".s" = "Security",
- ":w" = "whisper", "#w" = "whisper", ".w" = "whisper",
- ":t" = "Mercenary", "#t" = "Mercenary", ".t" = "Mercenary",
- ":u" = "Supply", "#u" = "Supply", ".u" = "Supply",
- ":v" = "Service", "#v" = "Service", ".v" = "Service",
- ":p" = "AI Private", "#p" = "AI Private", ".p" = "AI Private",
+ ":r" = "right ear", ".r" = "right ear",
+ ":l" = "left ear", ".l" = "left ear",
+ ":i" = "intercom", ".i" = "intercom",
+ ":h" = "department", ".h" = "department",
+ ":+" = "special", ".+" = "special", //activate radio-specific special functions
+ ":c" = "Command", ".c" = "Command",
+ ":n" = "Science", ".n" = "Science",
+ ":m" = "Medical", ".m" = "Medical",
+ ":e" = "Engineering", ".e" = "Engineering",
+ ":s" = "Security", ".s" = "Security",
+ ":w" = "whisper", ".w" = "whisper",
+ ":t" = "Mercenary", ".t" = "Mercenary",
+ ":u" = "Supply", ".u" = "Supply",
+ ":v" = "Service", ".v" = "Service",
+ ":p" = "AI Private", ".p" = "AI Private",
- ":R" = "right ear", "#R" = "right ear", ".R" = "right ear",
- ":L" = "left ear", "#L" = "left ear", ".L" = "left ear",
- ":I" = "intercom", "#I" = "intercom", ".I" = "intercom",
- ":H" = "department", "#H" = "department", ".H" = "department",
- ":C" = "Command", "#C" = "Command", ".C" = "Command",
- ":N" = "Science", "#N" = "Science", ".N" = "Science",
- ":M" = "Medical", "#M" = "Medical", ".M" = "Medical",
- ":E" = "Engineering", "#E" = "Engineering", ".E" = "Engineering",
- ":S" = "Security", "#S" = "Security", ".S" = "Security",
- ":W" = "whisper", "#W" = "whisper", ".W" = "whisper",
- ":T" = "Mercenary", "#T" = "Mercenary", ".T" = "Mercenary",
- ":U" = "Supply", "#U" = "Supply", ".U" = "Supply",
- ":V" = "Service", "#V" = "Service", ".V" = "Service",
- ":P" = "AI Private", "#P" = "AI Private", ".P" = "AI Private",
+ ":R" = "right ear", ".R" = "right ear",
+ ":L" = "left ear", ".L" = "left ear",
+ ":I" = "intercom", ".I" = "intercom",
+ ":H" = "department", ".H" = "department",
+ ":C" = "Command", ".C" = "Command",
+ ":N" = "Science", ".N" = "Science",
+ ":M" = "Medical", ".M" = "Medical",
+ ":E" = "Engineering", ".E" = "Engineering",
+ ":S" = "Security", ".S" = "Security",
+ ":W" = "whisper", ".W" = "whisper",
+ ":T" = "Mercenary", ".T" = "Mercenary",
+ ":U" = "Supply", ".U" = "Supply",
+ ":V" = "Service", ".V" = "Service",
+ ":P" = "AI Private", ".P" = "AI Private",
//kinda localization -- rastaf0
//same keys as above, but on russian keyboard layout. This file uses cp1251 as encoding.
- ":ê" = "right ear", "#ê" = "right ear", ".ê" = "right ear",
- ":ä" = "left ear", "#ä" = "left ear", ".ä" = "left ear",
- ":ø" = "intercom", "#ø" = "intercom", ".ø" = "intercom",
- ":ð" = "department", "#ð" = "department", ".ð" = "department",
- ":ñ" = "Command", "#ñ" = "Command", ".ñ" = "Command",
- ":ò" = "Science", "#ò" = "Science", ".ò" = "Science",
- ":ü" = "Medical", "#ü" = "Medical", ".ü" = "Medical",
- ":ó" = "Engineering", "#ó" = "Engineering", ".ó" = "Engineering",
- ":û" = "Security", "#û" = "Security", ".û" = "Security",
- ":ö" = "whisper", "#ö" = "whisper", ".ö" = "whisper",
- ":å" = "Mercenary", "#å" = "Mercenary", ".å" = "Mercenary",
- ":é" = "Supply", "#é" = "Supply", ".é" = "Supply",
+ ":ê" = "right ear", ".ê" = "right ear",
+ ":ä" = "left ear", ".ä" = "left ear",
+ ":ø" = "intercom", ".ø" = "intercom",
+ ":ð" = "department", ".ð" = "department",
+ ":ñ" = "Command", ".ñ" = "Command",
+ ":ò" = "Science", ".ò" = "Science",
+ ":ü" = "Medical", ".ü" = "Medical",
+ ":ó" = "Engineering", ".ó" = "Engineering",
+ ":û" = "Security", ".û" = "Security",
+ ":ö" = "whisper", ".ö" = "whisper",
+ ":å" = "Mercenary", ".å" = "Mercenary",
+ ":é" = "Supply", ".é" = "Supply",
)
diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm
index 899d0a9c9b4..8eabd679516 100644
--- a/code/modules/mob/say.dm
+++ b/code/modules/mob/say.dm
@@ -147,11 +147,12 @@
//parses the language code (e.g. :j) from text, such as that supplied to say.
//returns the language object only if the code corresponds to a language that src can speak, otherwise null.
/mob/proc/parse_language(var/message)
- if(length(message) >= 1 && copytext(message,1,2) == "!")
+ var/prefix = copytext(message,1,2)
+ if(length(message) >= 1 && prefix == "!")
return all_languages["Noise"]
- if(length(message) >= 2)
- var/language_prefix = lowertext(copytext(message, 1 ,3))
+ if(length(message) >= 2 && is_language_prefix(prefix))
+ var/language_prefix = lowertext(copytext(message, 2 ,3))
var/datum/language/L = language_keys[language_prefix]
if (can_speak(L))
return L
diff --git a/config/example/config.txt b/config/example/config.txt
index 7f94edde443..96f44ae19a7 100644
--- a/config/example/config.txt
+++ b/config/example/config.txt
@@ -362,6 +362,8 @@ STARLIGHT 0
## Enable asteroid tunnel/cave generation. Will behave strangely if turned off with a map that expects it on.
# GENERATE_ASTEROID
+
+
## Uncomment to enable organ decay outside of a body or storage item.
#ORGANS_CAN_DECAY
@@ -369,4 +371,7 @@ STARLIGHT 0
#AGGRESSIVE_CHANGELOG
## Uncomment to override default brain health.
-#DEFAULT_BRAIN_HEALTH 400
\ No newline at end of file
+#DEFAULT_BRAIN_HEALTH 400
+
+## Default language prefix keys, separated with spaces. Only single character keys are supported. If unset, defaults to , # and -
+# DEFAULT_LANGUAGE_PREFIXES , # -
diff --git a/html/changelogs/PsiOmegaDelta-LanguageKeys.yml b/html/changelogs/PsiOmegaDelta-LanguageKeys.yml
new file mode 100644
index 00000000000..427bad7a226
--- /dev/null
+++ b/html/changelogs/PsiOmegaDelta-LanguageKeys.yml
@@ -0,0 +1,5 @@
+author: PsiOmegaDelta
+delete-after: True
+changes:
+ - tweak: "Changed the language prefix keys to the following: , # -"
+ - rscadd: "Language prefix keys can be changed in the Character Setup. Changes are currently not global, but per character."