Refactors language holder (#48106)

* Language holder refactor

* Ironed out bugs, testing

* adds sourced language, blocking list. more useful helpers.

* Replaced old usage

* Adresses requests

* Autodoc attempt #1

* Fixed monkeyize (again)

* Travis happy

* Language menu updated

* Final pass
This commit is contained in:
skoglol
2019-12-18 22:22:12 +01:00
committed by AnturK
parent 2e1d2db862
commit 4a487ca803
54 changed files with 533 additions and 340 deletions

View File

@@ -3,5 +3,21 @@
#define LANGUAGE_HIDE_ICON_IF_UNDERSTOOD 4 #define LANGUAGE_HIDE_ICON_IF_UNDERSTOOD 4
#define LANGUAGE_HIDE_ICON_IF_NOT_UNDERSTOOD 8 #define LANGUAGE_HIDE_ICON_IF_NOT_UNDERSTOOD 8
#define LANGUAGE_KNOWN "language_known" // LANGUAGE SOURCE DEFINES
#define LANGUAGE_SHADOWED "language_shadowed" #define LANGUAGE_ALL "all" // For use in full removal only.
#define LANGUAGE_ATOM "atom"
#define LANGUAGE_MIND "mind"
#define LANGUAGE_ABSORB "absorb"
#define LANGUAGE_APHASIA "aphasia"
#define LANGUAGE_CULTIST "cultist"
#define LANGUAGE_CURATOR "curator"
#define LANGUAGE_DEVIL "devil"
#define LANGUAGE_GLAND "gland"
#define LANGUAGE_HAT "hat"
#define LANGUAGE_HIGH "high"
#define LANGUAGE_MALF "malf"
#define LANGUAGE_MASTER "master"
#define LANGUAGE_SOFTWARE "software"
#define LANGUAGE_STONER "stoner"
#define LANGUAGE_VOICECHANGE "voicechange"

View File

@@ -91,7 +91,6 @@
trauma = _trauma trauma = _trauma
owner = trauma.owner owner = trauma.owner
copy_known_languages_from(owner, TRUE)
setup_friend() setup_friend()

View File

@@ -26,21 +26,15 @@
scan_desc = "extensive damage to the brain's language center" scan_desc = "extensive damage to the brain's language center"
gain_text = "<span class='warning'>You have trouble forming words in your head...</span>" gain_text = "<span class='warning'>You have trouble forming words in your head...</span>"
lose_text = "<span class='notice'>You suddenly remember how languages work.</span>" lose_text = "<span class='notice'>You suddenly remember how languages work.</span>"
var/datum/language_holder/prev_language
var/datum/language_holder/mob_language
/datum/brain_trauma/severe/aphasia/on_gain() /datum/brain_trauma/severe/aphasia/on_gain()
mob_language = owner.get_language_holder() owner.add_blocked_language(subtypesof(/datum/language/) - /datum/language/aphasia, LANGUAGE_APHASIA)
prev_language = mob_language.copy() owner.grant_language(/datum/language/aphasia, TRUE, TRUE, LANGUAGE_APHASIA)
mob_language.remove_all_languages()
mob_language.grant_language(/datum/language/aphasia)
..() ..()
/datum/brain_trauma/severe/aphasia/on_lose() /datum/brain_trauma/severe/aphasia/on_lose()
mob_language.remove_language(/datum/language/aphasia) owner.remove_blocked_language(subtypesof(/datum/language/), LANGUAGE_APHASIA)
mob_language.copy_known_languages_from(prev_language) //this will also preserve languages learned during the trauma owner.remove_language(/datum/language/aphasia, TRUE, TRUE, LANGUAGE_APHASIA)
QDEL_NULL(prev_language)
mob_language = null
..() ..()
/datum/brain_trauma/severe/blindness /datum/brain_trauma/severe/blindness

View File

@@ -30,8 +30,6 @@ Bonus
symptom_delay_max = 120 symptom_delay_max = 120
var/scramble_language = FALSE var/scramble_language = FALSE
var/datum/language/current_language var/datum/language/current_language
var/datum/language_holder/original_language
var/datum/language_holder/mob_language
threshold_descs = list( threshold_descs = list(
"Transmission 14" = "The host's language center of the brain is damaged, leading to complete inability to speak or understand any language.", "Transmission 14" = "The host's language center of the brain is damaged, leading to complete inability to speak or understand any language.",
"Stage Speed 7" = "Changes voice more often.", "Stage Speed 7" = "Changes voice more often.",
@@ -49,9 +47,6 @@ Bonus
symptom_delay_max = 85 symptom_delay_max = 85
if(A.properties["transmittable"] >= 14) //random language if(A.properties["transmittable"] >= 14) //random language
scramble_language = TRUE scramble_language = TRUE
var/mob/living/M = A.affected_mob
mob_language = M.get_language_holder()
original_language = mob_language.copy()
/datum/symptom/voice_change/Activate(datum/disease/advance/A) /datum/symptom/voice_change/Activate(datum/disease/advance/A)
if(!..()) if(!..())
@@ -65,12 +60,10 @@ Bonus
if(ishuman(M)) if(ishuman(M))
var/mob/living/carbon/human/H = M var/mob/living/carbon/human/H = M
H.SetSpecialVoice(H.dna.species.random_name(H.gender)) H.SetSpecialVoice(H.dna.species.random_name(H.gender))
if(scramble_language) if(scramble_language && !current_language) // Last part prevents rerolling language with small amounts of cure.
H.remove_language(current_language)
current_language = pick(subtypesof(/datum/language) - /datum/language/common) current_language = pick(subtypesof(/datum/language) - /datum/language/common)
H.grant_language(current_language) H.add_blocked_language(subtypesof(/datum/language) - current_language, LANGUAGE_VOICECHANGE)
mob_language = H.get_language_holder() H.grant_language(current_language, TRUE, TRUE, LANGUAGE_VOICECHANGE)
mob_language.only_speaks_language = current_language
/datum/symptom/voice_change/End(datum/disease/advance/A) /datum/symptom/voice_change/End(datum/disease/advance/A)
..() ..()
@@ -78,10 +71,5 @@ Bonus
var/mob/living/carbon/human/H = A.affected_mob var/mob/living/carbon/human/H = A.affected_mob
H.UnsetSpecialVoice() H.UnsetSpecialVoice()
if(scramble_language) if(scramble_language)
var/mob/living/M = A.affected_mob A.affected_mob.remove_blocked_language(subtypesof(/datum/language), LANGUAGE_VOICECHANGE)
M.copy_known_languages_from(original_language, TRUE) A.affected_mob.remove_all_languages(LANGUAGE_VOICECHANGE) // In case someone managed to get more than one anyway.
mob_language = M.get_language_holder()
mob_language.only_speaks_language = null
M.selected_default_language = original_language
current_language = null
QDEL_NULL(original_language)

View File

@@ -124,8 +124,6 @@
if(ishuman(affected_mob)) if(ishuman(affected_mob))
var/mob/living/carbon/monkey/M = affected_mob.monkeyize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_KEEPSTUNS | TR_KEEPREAGENTS | TR_KEEPSE) var/mob/living/carbon/monkey/M = affected_mob.monkeyize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_KEEPSTUNS | TR_KEEPREAGENTS | TR_KEEPSE)
M.ventcrawler = VENTCRAWLER_ALWAYS M.ventcrawler = VENTCRAWLER_ALWAYS
M.mind?.language_holder = new M.initial_language_holder(M.mind) // make sure they speak normal monkey
/datum/disease/transformation/jungle_fever/stage_act() /datum/disease/transformation/jungle_fever/stage_act()
..() ..()

View File

@@ -305,6 +305,11 @@
var/datum/species/old_species = dna.species var/datum/species/old_species = dna.species
dna.species = new_race dna.species = new_race
dna.species.on_species_gain(src, old_species, pref_load) dna.species.on_species_gain(src, old_species, pref_load)
if(ishuman(src))
qdel(language_holder)
var/species_holder = initial(mrace.species_language_holder)
language_holder = new species_holder(src)
update_atom_languages()
/mob/living/carbon/human/set_species(datum/species/mrace, icon_update = TRUE, pref_load = FALSE) /mob/living/carbon/human/set_species(datum/species/mrace, icon_update = TRUE, pref_load = FALSE)
..() ..()
@@ -510,7 +515,7 @@
var/datum/mutation/human/HM = dna.get_mutation(mutation) var/datum/mutation/human/HM = dna.get_mutation(mutation)
if(HM) if(HM)
HM.scrambled = TRUE HM.scrambled = TRUE
if(HM.quality & resilient) if(HM.quality & resilient)
HM.mutadone_proof = TRUE HM.mutadone_proof = TRUE
return TRUE return TRUE

View File

@@ -85,9 +85,7 @@
/datum/mind/proc/get_language_holder() /datum/mind/proc/get_language_holder()
if(!language_holder) if(!language_holder)
var/datum/language_holder/L = current.get_language_holder(shadow=FALSE) language_holder = new (src)
language_holder = L.copy(src)
return language_holder return language_holder
/datum/mind/proc/transfer_to(mob/new_character, force_key_move = 0) /datum/mind/proc/transfer_to(mob/new_character, force_key_move = 0)
@@ -96,10 +94,6 @@
UnregisterSignal(current, COMSIG_MOB_DEATH) UnregisterSignal(current, COMSIG_MOB_DEATH)
SStgui.on_transfer(current, new_character) SStgui.on_transfer(current, new_character)
if(!language_holder)
var/datum/language_holder/mob_holder = new_character.get_language_holder(shadow = FALSE)
language_holder = mob_holder.copy(src)
if(key) if(key)
if(new_character.key != key) //if we're transferring into a body with a key associated which is not ours if(new_character.key != key) //if we're transferring into a body with a key associated which is not ours
new_character.ghostize(1) //we'll need to ghostize so that key isn't mobless. new_character.ghostize(1) //we'll need to ghostize so that key isn't mobless.
@@ -127,9 +121,10 @@
RegisterSignal(new_character, COMSIG_MOB_DEATH, .proc/set_death_time) RegisterSignal(new_character, COMSIG_MOB_DEATH, .proc/set_death_time)
if(active || force_key_move) if(active || force_key_move)
new_character.key = key //now transfer the key to link the client to our new body new_character.key = key //now transfer the key to link the client to our new body
current.update_atom_languages()
///Adjust experience of a specific skill ///Adjust experience of a specific skill
/datum/mind/proc/adjust_experience(skill, amt, silent = FALSE) /datum/mind/proc/adjust_experience(skill, amt, silent = FALSE)
var/datum/skill/S = GetSkillRef(skill) var/datum/skill/S = GetSkillRef(skill)
skill_experience[S] = max(0, skill_experience[S] + amt) //Prevent going below 0 skill_experience[S] = max(0, skill_experience[S] + amt) //Prevent going below 0

View File

@@ -266,10 +266,10 @@
/datum/mutation/human/stoner/on_acquiring(mob/living/carbon/human/owner) /datum/mutation/human/stoner/on_acquiring(mob/living/carbon/human/owner)
..() ..()
owner.grant_language(/datum/language/beachbum) owner.grant_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_STONER)
owner.remove_language(/datum/language/common) owner.add_blocked_language(subtypesof(/datum/language) - /datum/language/beachbum, LANGUAGE_STONER)
/datum/mutation/human/stoner/on_losing(mob/living/carbon/human/owner) /datum/mutation/human/stoner/on_losing(mob/living/carbon/human/owner)
..() ..()
owner.grant_language(/datum/language/common) owner.remove_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_STONER)
owner.remove_language(/datum/language/beachbum) owner.remove_blocked_language(subtypesof(/datum/language) - /datum/language/beachbum, LANGUAGE_STONER)

View File

@@ -11,7 +11,7 @@
var/throw_range = 7 var/throw_range = 7
var/mob/pulledby = null var/mob/pulledby = null
var/initial_language_holder = /datum/language_holder var/initial_language_holder = /datum/language_holder
var/datum/language_holder/language_holder var/datum/language_holder/language_holder // Mindless mobs and objects need language too, some times. Mind holder takes prescedence.
var/verb_say = "says" var/verb_say = "says"
var/verb_ask = "asks" var/verb_ask = "asks"
var/verb_exclaim = "exclaims" var/verb_exclaim = "exclaims"
@@ -264,7 +264,7 @@
continue continue
var/atom/movable/thing = i var/atom/movable/thing = i
thing.Crossed(src) thing.Crossed(src)
//////////////////////////////////////// ////////////////////////////////////////
/atom/movable/Move(atom/newloc, direct, glide_size_override = 0) /atom/movable/Move(atom/newloc, direct, glide_size_override = 0)
@@ -788,88 +788,94 @@
animate(src, pixel_y = initial(pixel_y), time = 10) animate(src, pixel_y = initial(pixel_y), time = 10)
setMovetype(movement_type & ~FLOATING) setMovetype(movement_type & ~FLOATING)
/* Language procs */
/atom/movable/proc/get_language_holder(shadow=TRUE) /* Language procs
if(language_holder) * Unless you are doing something very specific, these are the ones you want to use.
return language_holder */
else
/// Gets or creates the relevant language holder. For mindless atoms, gets the local one. For atom with mind, gets the mind one.
/atom/movable/proc/get_language_holder(get_minds = TRUE)
if(!language_holder)
language_holder = new initial_language_holder(src) language_holder = new initial_language_holder(src)
return language_holder return language_holder
/atom/movable/proc/grant_language(datum/language/dt, body = FALSE) /// Grants the supplied language and sets omnitongue true.
var/datum/language_holder/H = get_language_holder(!body) /atom/movable/proc/grant_language(language, understood = TRUE, spoken = TRUE, source = LANGUAGE_ATOM)
H.grant_language(dt, body) var/datum/language_holder/LH = get_language_holder()
return LH.grant_language(language, understood, spoken, source)
/atom/movable/proc/grant_all_languages(omnitongue=FALSE) /// Grants every language.
var/datum/language_holder/H = get_language_holder() /atom/movable/proc/grant_all_languages(understood = TRUE, spoken = TRUE, grant_omnitongue = TRUE, source = LANGUAGE_MIND)
H.grant_all_languages(omnitongue) var/datum/language_holder/LH = get_language_holder()
return LH.grant_all_languages(understood, spoken, grant_omnitongue, source)
/// Removes a single language.
/atom/movable/proc/remove_language(language, understood = TRUE, spoken = TRUE, source = LANGUAGE_ALL)
var/datum/language_holder/LH = get_language_holder()
return LH.remove_language(language, understood, spoken, source)
/// Removes every language and sets omnitongue false.
/atom/movable/proc/remove_all_languages(source = LANGUAGE_ALL, remove_omnitongue = FALSE)
var/datum/language_holder/LH = get_language_holder()
return LH.remove_all_languages(source, remove_omnitongue)
/// Adds a language to the blocked language list. Use this over remove_language in cases where you will give languages back later.
/atom/movable/proc/add_blocked_language(language, source = LANGUAGE_ATOM)
var/datum/language_holder/LH = get_language_holder()
return LH.add_blocked_language(language, source)
/// Removes a language from the blocked language list.
/atom/movable/proc/remove_blocked_language(language, source = LANGUAGE_ATOM)
var/datum/language_holder/LH = get_language_holder()
return LH.remove_blocked_language(language, source)
/// Checks if atom has the language. If spoken is true, only checks if atom can speak the language.
/atom/movable/proc/has_language(language, spoken = FALSE)
var/datum/language_holder/LH = get_language_holder()
return LH.has_language(language, spoken)
/// Checks if atom can speak the language.
/atom/movable/proc/can_speak_language(language)
var/datum/language_holder/LH = get_language_holder()
return LH.can_speak_language(language)
/// Returns the result of tongue specific limitations on spoken languages.
/atom/movable/proc/could_speak_language(language)
return TRUE
/// Returns selected language, if it can be spoken, or finds, sets and returns a new selected language if possible.
/atom/movable/proc/get_selected_language()
var/datum/language_holder/LH = get_language_holder()
return LH.get_selected_language()
/// Gets a random understood language, useful for hallucinations and such.
/atom/movable/proc/get_random_understood_language() /atom/movable/proc/get_random_understood_language()
var/datum/language_holder/H = get_language_holder() var/datum/language_holder/LH = get_language_holder()
. = H.get_random_understood_language() return LH.get_random_understood_language()
/atom/movable/proc/remove_language(datum/language/dt, body = FALSE) /// Gets a random spoken language, useful for forced speech and such.
var/datum/language_holder/H = get_language_holder(!body) /atom/movable/proc/get_random_spoken_language()
H.remove_language(dt, body) var/datum/language_holder/LH = get_language_holder()
return LH.get_random_spoken_language()
/atom/movable/proc/remove_all_languages() /// Copies all languages into the supplied atom/language holder. Source should be overridden when you
var/datum/language_holder/H = get_language_holder() /// do not want the language overwritten by later atom updates or want to avoid blocked languages.
H.remove_all_languages() /atom/movable/proc/copy_languages(from_holder, source_override)
if(isatom(from_holder))
var/atom/movable/thing = from_holder
from_holder = thing.get_language_holder()
var/datum/language_holder/LH = get_language_holder()
return LH.copy_languages(from_holder, source_override)
/atom/movable/proc/has_language(datum/language/dt) /// Empties out the atom specific languages and updates them according to the current atoms language holder.
var/datum/language_holder/H = get_language_holder() /// As a side effect, it also creates missing language holders in the process.
. = H.has_language(dt) /atom/movable/proc/update_atom_languages()
var/datum/language_holder/LH = get_language_holder()
/atom/movable/proc/copy_known_languages_from(thing, replace=FALSE) return LH.update_atom_languages(src)
var/datum/language_holder/H = get_language_holder()
. = H.copy_known_languages_from(thing, replace)
// Whether an AM can speak in a language or not, independent of whether
// it KNOWS the language
/atom/movable/proc/could_speak_in_language(datum/language/dt)
. = TRUE
/atom/movable/proc/can_speak_in_language(datum/language/dt)
var/datum/language_holder/H = get_language_holder()
if(!H.has_language(dt))
return FALSE
else if(H.omnitongue)
return TRUE
else if(could_speak_in_language(dt) && (!H.only_speaks_language || H.only_speaks_language == dt))
return TRUE
else
return FALSE
/atom/movable/proc/get_default_language()
// if no language is specified, and we want to say() something, which
// language do we use?
var/datum/language_holder/H = get_language_holder()
if(H.selected_default_language)
if(can_speak_in_language(H.selected_default_language))
return H.selected_default_language
else
H.selected_default_language = null
var/datum/language/chosen_langtype
var/highest_priority
for(var/lt in H.languages)
var/datum/language/langtype = lt
if(!can_speak_in_language(langtype))
continue
var/pri = initial(langtype.default_priority)
if(!highest_priority || (pri > highest_priority))
chosen_langtype = langtype
highest_priority = pri
H.selected_default_language = .
. = chosen_langtype
/* End language procs */ /* End language procs */
/atom/movable/proc/ConveyorMove(movedir) /atom/movable/proc/ConveyorMove(movedir)
set waitfor = FALSE set waitfor = FALSE
if(!anchored && has_gravity()) if(!anchored && has_gravity())

View File

@@ -415,7 +415,6 @@ obj/machinery/holopad/secure/Initialize()
Hologram.add_atom_colour("#77abff", FIXED_COLOUR_PRIORITY) Hologram.add_atom_colour("#77abff", FIXED_COLOUR_PRIORITY)
Hologram.Impersonation = user Hologram.Impersonation = user
Hologram.copy_known_languages_from(user,replace = TRUE)
Hologram.mouse_opacity = MOUSE_OPACITY_TRANSPARENT//So you can't click on it. Hologram.mouse_opacity = MOUSE_OPACITY_TRANSPARENT//So you can't click on it.
Hologram.layer = FLY_LAYER//Above all the other objects/mobs. Or the vast majority of them. Hologram.layer = FLY_LAYER//Above all the other objects/mobs. Or the vast majority of them.
Hologram.setAnchored(TRUE)//So space wind cannot drag it. Hologram.setAnchored(TRUE)//So space wind cannot drag it.
@@ -572,9 +571,8 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
Hologram.alpha = 170 Hologram.alpha = 170
Hologram.add_atom_colour("#77abff", FIXED_COLOUR_PRIORITY) Hologram.add_atom_colour("#77abff", FIXED_COLOUR_PRIORITY)
Hologram.dir = SOUTH //for now Hologram.dir = SOUTH //for now
Hologram.grant_all_languages(omnitongue=TRUE)
var/datum/language_holder/holder = Hologram.get_language_holder() var/datum/language_holder/holder = Hologram.get_language_holder()
holder.selected_default_language = record.language holder.selected_language = record.language
Hologram.mouse_opacity = MOUSE_OPACITY_TRANSPARENT//So you can't click on it. Hologram.mouse_opacity = MOUSE_OPACITY_TRANSPARENT//So you can't click on it.
Hologram.layer = FLY_LAYER//Above all the other objects/mobs. Or the vast majority of them. Hologram.layer = FLY_LAYER//Above all the other objects/mobs. Or the vast majority of them.
Hologram.setAnchored(TRUE)//So space wind cannot drag it. Hologram.setAnchored(TRUE)//So space wind cannot drag it.
@@ -666,7 +664,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
return return
if(HOLORECORD_LANGUAGE) if(HOLORECORD_LANGUAGE)
var/datum/language_holder/holder = replay_holo.get_language_holder() var/datum/language_holder/holder = replay_holo.get_language_holder()
holder.selected_default_language = entry[2] holder.selected_language = entry[2]
if(HOLORECORD_PRESET) if(HOLORECORD_PRESET)
var/preset_type = entry[2] var/preset_type = entry[2]
var/datum/preset_holoimage/H = new preset_type var/datum/preset_holoimage/H = new preset_type
@@ -689,6 +687,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
updateDialog() updateDialog()
/obj/effect/overlay/holo_pad_hologram /obj/effect/overlay/holo_pad_hologram
initial_language_holder = /datum/language_holder/universal
var/mob/living/Impersonation var/mob/living/Impersonation
var/datum/holocall/HC var/datum/holocall/HC

View File

@@ -100,7 +100,7 @@
obj/source, // the originating radio obj/source, // the originating radio
frequency, // the frequency the signal is taking place on frequency, // the frequency the signal is taking place on
atom/movable/virtualspeaker/speaker, // representation of the method's speaker atom/movable/virtualspeaker/speaker, // representation of the method's speaker
datum/language/language, // the langauge of the message datum/language/language, // the language of the message
message, // the text content of the message message, // the text content of the message
spans // the list of spans applied to the message spans // the list of spans applied to the message
) )

View File

@@ -198,7 +198,7 @@
if(!spans) if(!spans)
spans = list(M.speech_span) spans = list(M.speech_span)
if(!language) if(!language)
language = M.get_default_language() language = M.get_selected_language()
INVOKE_ASYNC(src, .proc/talk_into_impl, M, message, channel, spans.Copy(), language) INVOKE_ASYNC(src, .proc/talk_into_impl, M, message, channel, spans.Copy(), language)
return ITALICS | REDUCE_RANGE return ITALICS | REDUCE_RANGE

View File

@@ -452,7 +452,9 @@
S.ckey = C.ckey S.ckey = C.ckey
S.fully_replace_character_name(null, "The spirit of [name]") S.fully_replace_character_name(null, "The spirit of [name]")
S.status_flags |= GODMODE S.status_flags |= GODMODE
S.language_holder = user.language_holder.copy(S) S.copy_languages(user, LANGUAGE_MASTER) //Make sure the sword can understand and communicate with the user.
S.update_atom_languages()
grant_all_languages(FALSE, FALSE, TRUE) //Grants omnitongue
var/input = sanitize_name(stripped_input(S,"What are you named?", ,"", MAX_NAME_LEN)) var/input = sanitize_name(stripped_input(S,"What are you named?", ,"", MAX_NAME_LEN))
if(src && input) if(src && input)

View File

@@ -57,10 +57,6 @@
new_spawn.fully_replace_character_name(null,random_unique_lizard_name(gender)) new_spawn.fully_replace_character_name(null,random_unique_lizard_name(gender))
to_chat(new_spawn, "<b>Drag the corpses of men and beasts to your nest. It will absorb them to create more of your kind. Don't leave your nest undefended, protect it with your life. Glory to the Necropolis!</b>") to_chat(new_spawn, "<b>Drag the corpses of men and beasts to your nest. It will absorb them to create more of your kind. Don't leave your nest undefended, protect it with your life. Glory to the Necropolis!</b>")
new_spawn.grant_language(/datum/language/draconic)
var/datum/language_holder/holder = new_spawn.get_language_holder()
holder.selected_default_language = /datum/language/draconic
new_spawn.mind.add_antag_datum(/datum/antagonist/ashwalker, team) new_spawn.mind.add_antag_datum(/datum/antagonist/ashwalker, team)
if(ishuman(new_spawn)) if(ishuman(new_spawn))

View File

@@ -25,7 +25,7 @@ GLOBAL_LIST_INIT(freqtospan, list(
return return
spans |= speech_span spans |= speech_span
if(!language) if(!language)
language = get_default_language() language = get_selected_language()
send_speech(message, 7, src, , spans, message_language=language) send_speech(message, 7, src, , spans, message_language=language)
/atom/movable/proc/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode) /atom/movable/proc/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)

View File

@@ -10,7 +10,12 @@
/obj/item/organ/heart/gland/slime/Insert(mob/living/carbon/M, special = 0) /obj/item/organ/heart/gland/slime/Insert(mob/living/carbon/M, special = 0)
..() ..()
owner.faction |= "slime" owner.faction |= "slime"
owner.grant_language(/datum/language/slime) owner.grant_language(/datum/language/slime, TRUE, TRUE, LANGUAGE_GLAND)
/obj/item/organ/heart/gland/slime/Remove(mob/living/carbon/M, special = 0)
..()
owner.faction -= "slime"
owner.remove_language(/datum/language/slime, TRUE, TRUE, LANGUAGE_GLAND)
/obj/item/organ/heart/gland/slime/activate() /obj/item/organ/heart/gland/slime/activate()
to_chat(owner, "<span class='warning'>You feel nauseated!</span>") to_chat(owner, "<span class='warning'>You feel nauseated!</span>")

View File

@@ -90,6 +90,7 @@
if(team_mode) if(team_mode)
forge_team_objectives() forge_team_objectives()
forge_objectives() forge_objectives()
owner.current.grant_all_languages(FALSE, FALSE, TRUE) //Grants omnitongue. We are able to transform our body after all.
. = ..() . = ..()
/datum/antagonist/changeling/on_removal() /datum/antagonist/changeling/on_removal()

View File

@@ -59,10 +59,10 @@
if(user.nutrition < NUTRITION_LEVEL_WELL_FED) if(user.nutrition < NUTRITION_LEVEL_WELL_FED)
user.set_nutrition(min((user.nutrition + target.nutrition), NUTRITION_LEVEL_WELL_FED)) user.set_nutrition(min((user.nutrition + target.nutrition), NUTRITION_LEVEL_WELL_FED))
if(target.mind && user.mind)//if the victim and user have minds // Absorb a lizard, speak Draconic.
// Absorb a lizard, speak Draconic. owner.copy_languages(target, LANGUAGE_ABSORB)
user.copy_known_languages_from(target)
if(target.mind && user.mind)//if the victim and user have minds
var/datum/mind/suckedbrain = target.mind var/datum/mind/suckedbrain = target.mind
user.mind.memory += "<BR><b>We've absorbed [target]'s memories into our own...</b><BR>[suckedbrain.memory]<BR>" user.mind.memory += "<BR><b>We've absorbed [target]'s memories into our own...</b><BR>[suckedbrain.memory]<BR>"
for(var/A in suckedbrain.antag_datums) for(var/A in suckedbrain.antag_datums)

View File

@@ -103,7 +103,7 @@
add_antag_hud(antag_hud_type, antag_hud_name, current) add_antag_hud(antag_hud_type, antag_hud_name, current)
handle_clown_mutation(current, mob_override ? null : "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.") handle_clown_mutation(current, mob_override ? null : "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
current.faction |= "cult" current.faction |= "cult"
current.grant_language(/datum/language/narsie) current.grant_language(/datum/language/narsie, TRUE, TRUE, LANGUAGE_CULTIST)
if(!cult_team.cult_master) if(!cult_team.cult_master)
vote.Grant(current) vote.Grant(current)
communion.Grant(current) communion.Grant(current)
@@ -123,7 +123,7 @@
remove_antag_hud(antag_hud_type, current) remove_antag_hud(antag_hud_type, current)
handle_clown_mutation(current, removing = FALSE) handle_clown_mutation(current, removing = FALSE)
current.faction -= "cult" current.faction -= "cult"
current.remove_language(/datum/language/narsie) current.remove_language(/datum/language/narsie, TRUE, TRUE, LANGUAGE_CULTIST)
vote.Remove(current) vote.Remove(current)
communion.Remove(current) communion.Remove(current)
magic.Remove(current) magic.Remove(current)

View File

@@ -523,7 +523,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
var/mob/living/M = mob_override || owner.current var/mob/living/M = mob_override || owner.current
add_antag_hud(antag_hud_type, antag_hud_name, M) add_antag_hud(antag_hud_type, antag_hud_name, M)
handle_clown_mutation(M, mob_override ? null : "Your infernal nature has allowed you to overcome your clownishness.") handle_clown_mutation(M, mob_override ? null : "Your infernal nature has allowed you to overcome your clownishness.")
owner.current.grant_all_languages(TRUE) owner.current.grant_all_languages(TRUE, TRUE, TRUE, LANGUAGE_DEVIL)
update_hud() update_hud()
.=..() .=..()
@@ -535,6 +535,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
var/mob/living/M = mob_override || owner.current var/mob/living/M = mob_override || owner.current
remove_antag_hud(antag_hud_type, M) remove_antag_hud(antag_hud_type, M)
handle_clown_mutation(M, removing = FALSE) handle_clown_mutation(M, removing = FALSE)
owner.current.remove_all_languages(LANGUAGE_DEVIL)
.=..() .=..()
/datum/antagonist/devil/proc/printdevilinfo() /datum/antagonist/devil/proc/printdevilinfo()

View File

@@ -29,7 +29,7 @@
/mob/living/carbon/true_devil/Initialize() /mob/living/carbon/true_devil/Initialize()
create_bodyparts() //initialize bodyparts create_bodyparts() //initialize bodyparts
create_internal_organs() create_internal_organs()
grant_all_languages(omnitongue=TRUE) grant_all_languages()
..() ..()
/mob/living/carbon/true_devil/create_internal_organs() /mob/living/carbon/true_devil/create_internal_organs()

View File

@@ -203,7 +203,7 @@
if(TRAITOR_AI) if(TRAITOR_AI)
add_law_zero() add_law_zero()
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/malf.ogg', 100, FALSE, pressure_affected = FALSE) owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/malf.ogg', 100, FALSE, pressure_affected = FALSE)
owner.current.grant_language(/datum/language/codespeak) owner.current.grant_language(/datum/language/codespeak, TRUE, TRUE, LANGUAGE_MALF)
if(TRAITOR_HUMAN) if(TRAITOR_HUMAN)
if(should_equip) if(should_equip)
equip(silent) equip(silent)

View File

@@ -292,7 +292,10 @@
S.name = "Shade of [T.real_name]" S.name = "Shade of [T.real_name]"
S.real_name = "Shade of [T.real_name]" S.real_name = "Shade of [T.real_name]"
S.key = shade_controller.key S.key = shade_controller.key
S.language_holder = user.language_holder.copy(S) S.copy_languages(T, LANGUAGE_MIND)//Copies the old mobs languages into the new mob holder.
S.copy_languages(user, LANGUAGE_MASTER)
S.update_atom_languages()
grant_all_languages(FALSE, FALSE, TRUE) //Grants omnitongue
if(user) if(user)
S.faction |= "[REF(user)]" //Add the master as a faction, allowing inter-mob cooperation S.faction |= "[REF(user)]" //Add the master as a faction, allowing inter-mob cooperation
if(user && iscultist(user)) if(user && iscultist(user))

View File

@@ -134,7 +134,7 @@
if(!ishuman(user)) if(!ishuman(user))
return return
if(slot == ITEM_SLOT_HEAD) if(slot == ITEM_SLOT_HEAD)
user.grant_language(/datum/language/piratespeak/) user.grant_language(/datum/language/piratespeak/, TRUE, TRUE, LANGUAGE_HAT)
to_chat(user, "<span class='boldnotice'>You suddenly know how to speak like a pirate!</span>") to_chat(user, "<span class='boldnotice'>You suddenly know how to speak like a pirate!</span>")
/obj/item/clothing/head/pirate/dropped(mob/user) /obj/item/clothing/head/pirate/dropped(mob/user)
@@ -143,7 +143,7 @@
return return
var/mob/living/carbon/human/H = user var/mob/living/carbon/human/H = user
if(H.get_item_by_slot(ITEM_SLOT_HEAD) == src) if(H.get_item_by_slot(ITEM_SLOT_HEAD) == src)
user.remove_language(/datum/language/piratespeak/) user.remove_language(/datum/language/piratespeak/, TRUE, TRUE, LANGUAGE_HAT)
to_chat(user, "<span class='boldnotice'>You can no longer speak like a pirate.</span>") to_chat(user, "<span class='boldnotice'>You can no longer speak like a pirate.</span>")
/obj/item/clothing/head/pirate/captain /obj/item/clothing/head/pirate/captain

View File

@@ -84,7 +84,7 @@ GLOBAL_LIST_INIT(high_priority_sentience, typecacheof(list(
SA.key = SG.key SA.key = SG.key
SA.grant_all_languages(TRUE) SA.grant_all_languages(TRUE, FALSE, FALSE)
SA.sentience_act() SA.sentience_act()

View File

@@ -42,4 +42,4 @@
if(visualsOnly) if(visualsOnly)
return return
H.grant_all_languages(omnitongue=TRUE) H.grant_all_languages(TRUE, TRUE, TRUE, LANGUAGE_CURATOR)

View File

@@ -46,7 +46,7 @@
return return
to_chat(user, "<span class='boldannounce'>You start skimming through [src], and suddenly your mind is filled with codewords and responses.</span>") to_chat(user, "<span class='boldannounce'>You start skimming through [src], and suddenly your mind is filled with codewords and responses.</span>")
user.grant_language(/datum/language/codespeak) user.grant_language(/datum/language/codespeak, TRUE, TRUE, LANGUAGE_MIND)
use_charge(user) use_charge(user)
@@ -65,7 +65,7 @@
M.visible_message("<span class='danger'>[user] beats [M] over the head with [src]!</span>", "<span class='userdanger'>[user] beats you over the head with [src]!</span>", "<span class='hear'>You hear smacking.</span>") M.visible_message("<span class='danger'>[user] beats [M] over the head with [src]!</span>", "<span class='userdanger'>[user] beats you over the head with [src]!</span>", "<span class='hear'>You hear smacking.</span>")
else else
M.visible_message("<span class='notice'>[user] teaches [M] by beating [M.p_them()] over the head with [src]!</span>", "<span class='boldnotice'>As [user] hits you with [src], codewords and responses flow through your mind.</span>", "<span class='hear'>You hear smacking.</span>") M.visible_message("<span class='notice'>[user] teaches [M] by beating [M.p_them()] over the head with [src]!</span>", "<span class='boldnotice'>As [user] hits you with [src], codewords and responses flow through your mind.</span>", "<span class='hear'>You hear smacking.</span>")
M.grant_language(/datum/language/codespeak) M.grant_language(/datum/language/codespeak, TRUE, TRUE, LANGUAGE_MIND)
use_charge(user) use_charge(user)
/obj/item/codespeak_manual/proc/use_charge(mob/user) /obj/item/codespeak_manual/proc/use_charge(mob/user)

View File

@@ -1,141 +1,310 @@
/datum/language_holder /*!Language holders will either exist in an atom/movable or a mind. Creation of language holders happens
var/list/languages = list(/datum/language/common) automatically when they are needed, for example when something tries to speak.
var/list/shadow_languages = list() Where a mind is available, the mind language holder will be the one "in charge". The mind holder
var/only_speaks_language = null will update its languages based on the atom holder, and will get updated as part of
var/selected_default_language = null transformations and other events that cause new languages to become available.
var/datum/language_menu/language_menu
Every language holder has three lists of languages (and sources for each of them):
- understood_languages
- spoken_languages
- blocked_languages
Understood languages let you understand them, spoken languages lets you speak them
(if your tongue is compatible), and blocked languages will let you do neither no matter
what the source of the language is.
Language holders are designed to mostly only ever require the use the helpers in atom/movable
to achieve your goals, but it is also possible to work on them directly if needed. Any adding
and removing of languages and sources should only happen through the procs, as directly changing
these will mess something up somewhere down the line.
All atom movables have the initial_language_holder var which allows you to set the default language
holder to create. For example, /datum/language_holder/alien will give you xenocommon and a block for
galactic common. Human species also have a default language holder var that will be updated on
species change, initial_species_holder.
Key procs
* [grant_language](atom/movable.html#proc/grant_language)
* [remove_language](atom/movable.html#proc/remove_language)
* [add_blocked_language](atom/movable.html#proc/add_blocked_language)
* [remove_blocked_language](atom/movable.html#proc/remove_blocked_language)
* [grant_all_languages](atom/movable.html#proc/grant_all_languages)
* [remove_all_languages](atom/movable.html#proc/remove_all_languages)
* [has_language](atom/movable.html#proc/has_language)
* [can_speak_language](atom/movable.html#proc/can_speak_language)
* [get_selected_language](atom/movable.html#proc/get_selected_language)
* [update_atom_languages](atom/movable.html#proc/update_atom_languages)
*/
/datum/language_holder
/// Understood languages.
var/list/understood_languages = list(/datum/language/common = list(LANGUAGE_MIND))
/// A list of languages that can be spoken. Tongue organ may also set limits beyond this list.
var/list/spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM))
/// A list of blocked languages. Used to prevent understanding and speaking certain languages, ie for certain mobs, mutations etc.
var/list/blocked_languages = list()
/// If true, overrides tongue limitations.
var/omnitongue = FALSE var/omnitongue = FALSE
/// Handles displaying the language menu UI.
var/datum/language_menu/language_menu
/// Currently spoken language
var/selected_language
/// Tracks the entity that owns the holder.
var/owner var/owner
/datum/language_holder/New(owner) /// Initializes, and copies in the languages from the current atom if available.
src.owner = owner /datum/language_holder/New(_owner)
owner = _owner
languages = typecacheof(languages) if(istype(owner, /datum/mind))
shadow_languages = typecacheof(shadow_languages)
/datum/language_holder/Destroy()
owner = null
QDEL_NULL(language_menu)
languages.Cut()
shadow_languages.Cut()
return ..()
/datum/language_holder/proc/copy(newowner)
var/datum/language_holder/copy = new(newowner)
copy.languages = src.languages.Copy()
// shadow languages are not copied.
copy.only_speaks_language = src.only_speaks_language
copy.selected_default_language = src.selected_default_language
// language menu is not copied, that's tied to the holder.
copy.omnitongue = src.omnitongue
return copy
/datum/language_holder/proc/grant_language(datum/language/dt, shadow = FALSE)
if(shadow)
shadow_languages[dt] = TRUE
else
languages[dt] = TRUE
/datum/language_holder/proc/grant_all_languages(omnitongue=FALSE)
for(var/la in GLOB.all_languages)
grant_language(la)
if(omnitongue)
src.omnitongue = TRUE
/datum/language_holder/proc/get_random_understood_language()
var/list/possible = list()
for(var/dt in languages)
possible += dt
. = safepick(possible)
/datum/language_holder/proc/remove_language(datum/language/dt, shadow = FALSE)
if(shadow)
shadow_languages -= dt
else
languages -= dt
/datum/language_holder/proc/remove_all_languages()
languages.Cut()
/datum/language_holder/proc/has_language(datum/language/dt)
if(is_type_in_typecache(dt, languages))
return LANGUAGE_KNOWN
else
var/atom/movable/AM = get_atom()
var/datum/language_holder/L = AM.get_language_holder(shadow=FALSE)
if(L != src)
if(is_type_in_typecache(dt, L.shadow_languages))
return LANGUAGE_SHADOWED
return FALSE
/datum/language_holder/proc/copy_known_languages_from(thing, replace=FALSE)
var/datum/language_holder/other
if(istype(thing, /datum/language_holder))
other = thing
else if(ismovableatom(thing))
var/atom/movable/AM = thing
other = AM.get_language_holder()
else if(istype(thing, /datum/mind))
var/datum/mind/M = thing
other = M.get_language_holder()
if(replace)
src.remove_all_languages()
for(var/l in other.languages)
src.grant_language(l)
/datum/language_holder/proc/open_language_menu(mob/user)
if(!language_menu)
language_menu = new(src)
language_menu.ui_interact(user)
/datum/language_holder/proc/get_atom()
if(ismovableatom(owner))
. = owner
else if(istype(owner, /datum/mind))
var/datum/mind/M = owner var/datum/mind/M = owner
if(M.current) if(M.current)
. = M.current update_atom_languages(M.current)
get_selected_language()
/datum/language_holder/Destroy()
QDEL_NULL(language_menu)
return ..()
/// Grants the supplied language.
/datum/language_holder/proc/grant_language(language, understood = TRUE, spoken = TRUE, source = LANGUAGE_MIND)
if(understood)
if(!understood_languages[language])
understood_languages[language] = list()
understood_languages[language] |= source
. = TRUE
if(spoken)
if(!spoken_languages[language])
spoken_languages[language] = list()
spoken_languages[language] |= source
. = TRUE
/// Grants every language to understood and spoken, and gives omnitongue.
/datum/language_holder/proc/grant_all_languages(understood = TRUE, spoken = TRUE, grant_omnitongue = TRUE, source = LANGUAGE_MIND)
for(var/language in GLOB.all_languages)
grant_language(language, understood, spoken, source)
if(grant_omnitongue) // Overrides tongue limitations.
omnitongue = TRUE
return TRUE
/// Removes a single language or source, removing all sources returns the pre-removal state of the language.
/datum/language_holder/proc/remove_language(language, understood = TRUE, spoken = TRUE, source = LANGUAGE_ALL)
if(understood && understood_languages[language])
if(source == LANGUAGE_ALL)
understood_languages -= language
else
understood_languages[language] -= source
if(!length(understood_languages[language]))
understood_languages -= language
. = TRUE
if(spoken && spoken_languages[language])
if(source == LANGUAGE_ALL)
spoken_languages -= language
else
spoken_languages[language] -= source
if(!length(spoken_languages[language]))
spoken_languages -= language
. = TRUE
/// Removes every language and optionally sets omnitongue false. If a non default source is supplied, only removes that source.
/datum/language_holder/proc/remove_all_languages(source = LANGUAGE_ALL, remove_omnitongue = FALSE)
for(var/language in GLOB.all_languages)
remove_language(language, TRUE, TRUE, source)
if(remove_omnitongue)
omnitongue = FALSE
return TRUE
/// Adds a single language or list of languages to the blocked language list.
/datum/language_holder/proc/add_blocked_language(languages, source = LANGUAGE_MIND)
if(!islist(languages))
languages = list(languages)
for(var/language in languages)
if(!blocked_languages[language])
blocked_languages[language] = list()
blocked_languages[language] |= source
return TRUE
/// Removes a single language or list of languages from the blocked language list.
/datum/language_holder/proc/remove_blocked_language(languages, source = LANGUAGE_MIND)
if(!islist(languages))
languages = list(languages)
for(var/language in languages)
if(blocked_languages[language])
if(source == LANGUAGE_ALL)
blocked_languages -= language
else
blocked_languages[language] -= source
if(!length(blocked_languages[language]))
blocked_languages -= language
return TRUE
/// Checks if you have the language. If spoken is true, only checks if you can speak the language.
/datum/language_holder/proc/has_language(language, spoken = FALSE)
if(language in blocked_languages)
return FALSE
if(spoken)
return language in spoken_languages
return language in understood_languages
/// Checks if you can speak the language. Tongue limitations should be supplied as an argument.
/datum/language_holder/proc/can_speak_language(language)
var/atom/movable/ouratom = get_atom()
var/tongue = ouratom.could_speak_language(language)
if((omnitongue || tongue) && has_language(language, TRUE))
return TRUE
return FALSE
/// Returns selected language if it can be spoken, or decides, sets and returns a new selected language if possible.
/datum/language_holder/proc/get_selected_language()
if(selected_language && can_speak_language(selected_language))
return selected_language
selected_language = null
var/highest_priority
for(var/lang in spoken_languages)
var/datum/language/language = lang
var/priority = initial(language.default_priority)
if((!highest_priority || (priority > highest_priority)) && !(language in blocked_languages))
if(can_speak_language(language))
selected_language = language
highest_priority = priority
return selected_language
/// Gets a random understood language, useful for hallucinations and such.
/datum/language_holder/proc/get_random_understood_language()
return pick(understood_languages)
/// Gets a random spoken language, useful for forced speech and such.
/datum/language_holder/proc/get_random_spoken_language()
return pick(spoken_languages)
/// Opens a language menu reading from the language holder.
/datum/language_holder/proc/open_language_menu(mob/user)
if(!language_menu)
language_menu = new (src)
language_menu.ui_interact(user)
/// Gets the atom, since we some times need to check if the tongue has limitations.
/datum/language_holder/proc/get_atom()
if(owner)
if(istype(owner, /datum/mind))
var/datum/mind/M = owner
return M.current
return owner
return FALSE
/// Empties out the atom specific languages and updates them according to the supplied atoms language holder.
/datum/language_holder/proc/update_atom_languages(atom/movable/thing)
var/datum/language_holder/from_atom = thing.get_language_holder(FALSE) //Gets the atoms language holder
if(from_atom == src) //This could happen if called on an atom without a mind.
return FALSE
for(var/language in understood_languages)
remove_language(language, TRUE, FALSE, LANGUAGE_ATOM)
for(var/language in spoken_languages)
remove_language(language, FALSE, TRUE, LANGUAGE_ATOM)
for(var/language in blocked_languages)
remove_blocked_language(language, LANGUAGE_ATOM)
copy_languages(from_atom)
get_selected_language()
return TRUE
/// Copies all languages from the supplied atom/language holder. Source should be overridden when you
/// do not want the language overwritten by later atom updates or want to avoid blocked languages.
/datum/language_holder/proc/copy_languages(var/datum/language_holder/from_holder, source_override)
if(source_override) //No blocked languages here, for now only used by ling absorb.
for(var/language in from_holder.understood_languages)
grant_language(language, TRUE, FALSE, source_override)
for(var/language in from_holder.spoken_languages)
grant_language(language, FALSE, TRUE, source_override)
else
for(var/language in from_holder.understood_languages)
grant_language(language, TRUE, FALSE, from_holder.understood_languages[language])
for(var/language in from_holder.spoken_languages)
grant_language(language, FALSE, TRUE, from_holder.spoken_languages[language])
for(var/language in from_holder.blocked_languages)
add_blocked_language(language, from_holder.blocked_languages[language])
return TRUE
//************************************************
//* Specific language holders *
//* Use atom language sources only. *
//************************************************/
/datum/language_holder/alien /datum/language_holder/alien
languages = list(/datum/language/xenocommon) understood_languages = list(/datum/language/xenocommon = list(LANGUAGE_ATOM))
spoken_languages = list(/datum/language/xenocommon = list(LANGUAGE_ATOM))
/datum/language_holder/monkey blocked_languages = list(/datum/language/common = list(LANGUAGE_ATOM))
languages = list(/datum/language/monkey)
/datum/language_holder/swarmer
languages = list(/datum/language/swarmer)
/datum/language_holder/construct /datum/language_holder/construct
languages = list(/datum/language/common, /datum/language/narsie) understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM),
/datum/language/narsie = list(LANGUAGE_ATOM))
spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM),
/datum/language/narsie = list(LANGUAGE_ATOM))
/datum/language_holder/drone /datum/language_holder/drone
languages = list(/datum/language/common, /datum/language/drone, /datum/language/machine) understood_languages = list(/datum/language/drone = list(LANGUAGE_ATOM),
only_speaks_language = /datum/language/drone /datum/language/machine = list(LANGUAGE_ATOM))
spoken_languages = list(/datum/language/drone = list(LANGUAGE_ATOM))
blocked_languages = list(/datum/language/common = list(LANGUAGE_ATOM))
/datum/language_holder/drone/syndicate /datum/language_holder/drone/syndicate
only_speaks_language = null blocked_languages = list()
/datum/language_holder/slime /datum/language_holder/jelly
languages = list(/datum/language/common, /datum/language/slime) understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM),
only_speaks_language = /datum/language/slime /datum/language/slime = list(LANGUAGE_ATOM))
spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM),
/datum/language/slime = list(LANGUAGE_ATOM))
/datum/language_holder/lightbringer /datum/language_holder/lightbringer
// TODO change to a lightbringer specific sign language understood_languages = list(/datum/language/slime = list(LANGUAGE_ATOM))
languages = list(/datum/language/slime) spoken_languages = list(/datum/language/slime = list(LANGUAGE_ATOM))
blocked_languages = list(/datum/language/common = list(LANGUAGE_ATOM))
/datum/language_holder/lizard
understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM),
/datum/language/draconic = list(LANGUAGE_ATOM))
spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM),
/datum/language/draconic = list(LANGUAGE_ATOM))
/datum/language_holder/lizard/ash
selected_language = /datum/language/draconic
/datum/language_holder/monkey
understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM),
/datum/language/monkey = list(LANGUAGE_ATOM))
spoken_languages = list(/datum/language/monkey = list(LANGUAGE_ATOM))
/datum/language_holder/mushroom
understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM),
/datum/language/mushroom = list(LANGUAGE_ATOM))
spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM),
/datum/language/mushroom = list(LANGUAGE_ATOM))
/datum/language_holder/slime
understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM),
/datum/language/slime = list(LANGUAGE_ATOM))
spoken_languages = list(/datum/language/slime = list(LANGUAGE_ATOM))
/datum/language_holder/swarmer
understood_languages = list(/datum/language/swarmer = list(LANGUAGE_ATOM))
spoken_languages = list(/datum/language/swarmer = list(LANGUAGE_ATOM))
blocked_languages = list(/datum/language/common = list(LANGUAGE_ATOM))
/datum/language_holder/synthetic /datum/language_holder/synthetic
languages = list(/datum/language/common) understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM),
shadow_languages = list(/datum/language/common, /datum/language/machine, /datum/language/draconic) /datum/language/machine = list(LANGUAGE_ATOM),
/datum/language/draconic = list(LANGUAGE_ATOM))
spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM),
/datum/language/machine = list(LANGUAGE_ATOM),
/datum/language/draconic = list(LANGUAGE_ATOM))
/datum/language_holder/empty /datum/language_holder/empty
languages = list() understood_languages = list()
shadow_languages = list() spoken_languages = list()
/datum/language_holder/universal/New() /datum/language_holder/universal/New()
..() ..()
grant_all_languages(omnitongue=TRUE) grant_all_languages()

View File

@@ -1,8 +1,8 @@
/datum/language_menu /datum/language_menu
var/datum/language_holder/language_holder var/datum/language_holder/language_holder
/datum/language_menu/New(language_holder) /datum/language_menu/New(_language_holder)
src.language_holder = language_holder language_holder = _language_holder
/datum/language_menu/Destroy() /datum/language_menu/Destroy()
language_holder = null language_holder = null
@@ -24,21 +24,20 @@
data["is_living"] = FALSE data["is_living"] = FALSE
data["languages"] = list() data["languages"] = list()
for(var/ld in GLOB.all_languages) for(var/lang in GLOB.all_languages)
var/result = language_holder.has_language(ld) var/result = language_holder.has_language(lang) || language_holder.has_language(lang, TRUE)
if(!result) if(!result)
continue continue
var/shadow = result == LANGUAGE_SHADOWED var/datum/language/language = lang
var/datum/language/LD = ld
var/list/L = list() var/list/L = list()
L["name"] = initial(LD.name) L["name"] = initial(language.name)
L["desc"] = initial(LD.desc) L["desc"] = initial(language.desc)
L["key"] = initial(LD.key) L["key"] = initial(language.key)
L["is_default"] = (LD == language_holder.selected_default_language) L["is_default"] = (language == language_holder.selected_language)
L["shadow"] = shadow
if(AM) if(AM)
L["can_speak"] = AM.can_speak_in_language(LD) L["can_speak"] = AM.can_speak_language(language)
L["can_understand"] = AM.has_language(language)
data["languages"] += list(L) data["languages"] += list(L)
@@ -47,15 +46,15 @@
data["omnitongue"] = language_holder.omnitongue data["omnitongue"] = language_holder.omnitongue
data["unknown_languages"] = list() data["unknown_languages"] = list()
for(var/ld in GLOB.all_languages) for(var/lang in GLOB.all_languages)
if(language_holder.has_language(ld)) if(language_holder.has_language(lang) || language_holder.has_language(lang, TRUE))
continue continue
var/datum/language/LD = ld var/datum/language/language = lang
var/list/L = list() var/list/L = list()
L["name"] = initial(LD.name) L["name"] = initial(language.name)
L["desc"] = initial(LD.desc) L["desc"] = initial(language.desc)
L["key"] = initial(LD.key) L["key"] = initial(language.key)
data["unknown_languages"] += list(L) data["unknown_languages"] += list(L)
return data return data
@@ -68,27 +67,51 @@
var/language_name = params["language_name"] var/language_name = params["language_name"]
var/datum/language/language_datum var/datum/language/language_datum
for(var/ld in GLOB.all_languages) for(var/lang in GLOB.all_languages)
var/datum/language/LD = ld var/datum/language/language = lang
if(language_name == initial(LD.name)) if(language_name == initial(language.name))
language_datum = LD language_datum = language
var/is_admin = check_rights_for(user.client, R_ADMIN) var/is_admin = check_rights_for(user.client, R_ADMIN)
switch(action) switch(action)
if("select_default") if("select_default")
if(language_datum && AM.can_speak_in_language(language_datum)) if(language_datum && AM.can_speak_language(language_datum))
language_holder.selected_default_language = language_datum language_holder.selected_language = language_datum
. = TRUE . = TRUE
if("grant_language") if("grant_language")
if((is_admin || isobserver(AM)) && language_datum) if((is_admin || isobserver(AM)) && language_datum)
language_holder.grant_language(language_datum) var/list/choices = list("Only Spoken", "Only Understood", "Both")
var/choice = input(user,"How do you want to add this language?","[language_datum]",null) as null|anything in choices
var/spoken = FALSE
var/understood = FALSE
switch(choice)
if("Only Spoken")
spoken = TRUE
if("Only Understood")
understood = TRUE
if("Both")
spoken = TRUE
understood = TRUE
language_holder.grant_language(language_datum, understood, spoken)
if(is_admin) if(is_admin)
message_admins("[key_name_admin(user)] granted the [language_name] language to [key_name_admin(AM)].") message_admins("[key_name_admin(user)] granted the [language_name] language to [key_name_admin(AM)].")
log_admin("[key_name(user)] granted the language [language_name] to [key_name(AM)].") log_admin("[key_name(user)] granted the language [language_name] to [key_name(AM)].")
. = TRUE . = TRUE
if("remove_language") if("remove_language")
if((is_admin || isobserver(AM)) && language_datum) if((is_admin || isobserver(AM)) && language_datum)
language_holder.remove_language(language_datum) var/list/choices = list("Only Spoken", "Only Understood", "Both")
var/choice = input(user,"Which part do you wish to remove?","[language_datum]",null) as null|anything in choices
var/spoken = FALSE
var/understood = FALSE
switch(choice)
if("Only Spoken")
spoken = TRUE
if("Only Understood")
understood = TRUE
if("Both")
spoken = TRUE
understood = TRUE
language_holder.remove_language(language_datum, understood, spoken)
if(is_admin) if(is_admin)
message_admins("[key_name_admin(user)] removed the [language_name] language to [key_name_admin(AM)].") message_admins("[key_name_admin(user)] removed the [language_name] language to [key_name_admin(AM)].")
log_admin("[key_name(user)] removed the language [language_name] to [key_name(AM)].") log_admin("[key_name(user)] removed the language [language_name] to [key_name(AM)].")

View File

@@ -577,7 +577,7 @@
if(!user.can_read(src)) if(!user.can_read(src))
return FALSE return FALSE
to_chat(user, "<span class='notice'>You flip through the pages of the book, quickly and conveniently learning every language in existence. Somewhat less conveniently, the aging book crumbles to dust in the process. Whoops.</span>") to_chat(user, "<span class='notice'>You flip through the pages of the book, quickly and conveniently learning every language in existence. Somewhat less conveniently, the aging book crumbles to dust in the process. Whoops.</span>")
user.grant_all_languages(omnitongue=TRUE) user.grant_all_languages()
new /obj/effect/decal/cleanable/ash(get_turf(user)) new /obj/effect/decal/cleanable/ash(get_turf(user))
qdel(src) qdel(src)

View File

@@ -481,11 +481,11 @@
if(frn) if(frn)
client.prefs.random_character() client.prefs.random_character()
client.prefs.real_name = client.prefs.pref_species.random_name(gender,1) client.prefs.real_name = client.prefs.pref_species.random_name(gender,1)
var/is_antag var/is_antag
if(mind in GLOB.pre_setup_antags) if(mind in GLOB.pre_setup_antags)
is_antag = TRUE is_antag = TRUE
client.prefs.copy_to(H, antagonist = is_antag) client.prefs.copy_to(H, antagonist = is_antag)
H.dna.update_dna_identity() H.dna.update_dna_identity()
if(mind) if(mind)
@@ -504,7 +504,7 @@
/mob/dead/new_player/proc/transfer_character() /mob/dead/new_player/proc/transfer_character()
. = new_character . = new_character
if(.) if(.)
new_character.key = key //Manually transfer the key to log them in new_character.key = key //Manually transfer the key to log them in,
new_character.stop_sound_channel(CHANNEL_LOBBYMUSIC) new_character.stop_sound_channel(CHANNEL_LOBBYMUSIC)
new_character = null new_character = null
qdel(src) qdel(src)

View File

@@ -26,6 +26,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
var/list/no_equip = list() // slots the race can't equip stuff to var/list/no_equip = list() // slots the race can't equip stuff to
var/nojumpsuit = 0 // this is sorta... weird. it basically lets you equip stuff that usually needs jumpsuits without one, like belts and pockets and ids var/nojumpsuit = 0 // this is sorta... weird. it basically lets you equip stuff that usually needs jumpsuits without one, like belts and pockets and ids
var/say_mod = "says" // affects the speech message var/say_mod = "says" // affects the speech message
var/species_language_holder = /datum/language_holder
var/list/default_features = list() // Default mutant bodyparts for this species. Don't forget to set one for every mutant bodypart you allow this species to have. var/list/default_features = list() // Default mutant bodyparts for this species. Don't forget to set one for every mutant bodypart you allow this species to have.
var/list/mutant_bodyparts = list() // Visible CURRENT bodyparts that are unique to a species. DO NOT USE THIS AS A LIST OF ALL POSSIBLE BODYPARTS AS IT WILL FUCK SHIT UP! Changes to this list for non-species specific bodyparts (ie cat ears and tails) should be assigned at organ level if possible. Layer hiding is handled by handle_mutant_bodyparts() below. var/list/mutant_bodyparts = list() // Visible CURRENT bodyparts that are unique to a species. DO NOT USE THIS AS A LIST OF ALL POSSIBLE BODYPARTS AS IT WILL FUCK SHIT UP! Changes to this list for non-species specific bodyparts (ie cat ears and tails) should be assigned at organ level if possible. Layer hiding is handled by handle_mutant_bodyparts() below.
var/list/mutant_organs = list() //Internal organs that are unique to this race. var/list/mutant_organs = list() //Internal organs that are unique to this race.

View File

@@ -8,6 +8,7 @@
meat = null meat = null
damage_overlay_type = "synth" damage_overlay_type = "synth"
mutanttongue = /obj/item/organ/tongue/robot mutanttongue = /obj/item/organ/tongue/robot
species_language_holder = /datum/language_holder/synthetic
limbs_id = "synth" limbs_id = "synth"
changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT

View File

@@ -17,16 +17,15 @@
burnmod = 0.5 // = 1/2x generic burn damage burnmod = 0.5 // = 1/2x generic burn damage
changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT
inherent_factions = list("slime") inherent_factions = list("slime")
species_language_holder = /datum/language_holder/jelly
/datum/species/jelly/on_species_loss(mob/living/carbon/C) /datum/species/jelly/on_species_loss(mob/living/carbon/C)
if(regenerate_limbs) if(regenerate_limbs)
regenerate_limbs.Remove(C) regenerate_limbs.Remove(C)
C.remove_language(/datum/language/slime)
..() ..()
/datum/species/jelly/on_species_gain(mob/living/carbon/C, datum/species/old_species) /datum/species/jelly/on_species_gain(mob/living/carbon/C, datum/species/old_species)
..() ..()
C.grant_language(/datum/language/slime)
if(ishuman(C)) if(ishuman(C))
regenerate_limbs = new regenerate_limbs = new
regenerate_limbs.Grant(C) regenerate_limbs.Grant(C)

View File

@@ -24,9 +24,7 @@
inert_mutation = FIREBREATH inert_mutation = FIREBREATH
deathsound = 'sound/voice/lizard/deathsound.ogg' deathsound = 'sound/voice/lizard/deathsound.ogg'
wings_icon = "Dragon" wings_icon = "Dragon"
species_language_holder = /datum/language_holder/lizard
/datum/species/lizard/after_equip_job(datum/job/J, mob/living/carbon/human/H)
H.grant_language(/datum/language/draconic)
/datum/species/lizard/random_name(gender,unique,lastname) /datum/species/lizard/random_name(gender,unique,lastname)
if(unique) if(unique)
@@ -80,3 +78,4 @@
limbs_id = "lizard" limbs_id = "lizard"
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,DIGITIGRADE) species_traits = list(MUTCOLORS,EYECOLOR,LIPS,DIGITIGRADE)
inherent_traits = list(TRAIT_CHUNKYFINGERS,TRAIT_NOBREATH) inherent_traits = list(TRAIT_CHUNKYFINGERS,TRAIT_NOBREATH)
species_language_holder = /datum/language_holder/lizard/ash

View File

@@ -27,13 +27,11 @@
mutanteyes = /obj/item/organ/eyes/night_vision/mushroom mutanteyes = /obj/item/organ/eyes/night_vision/mushroom
use_skintones = FALSE use_skintones = FALSE
var/datum/martial_art/mushpunch/mush var/datum/martial_art/mushpunch/mush
species_language_holder = /datum/language_holder/mushroom
/datum/species/mush/check_roundstart_eligible() /datum/species/mush/check_roundstart_eligible()
return FALSE //hard locked out of roundstart on the order of design lead kor, this can be removed in the future when planetstation is here OR SOMETHING but right now we have a problem with races. return FALSE //hard locked out of roundstart on the order of design lead kor, this can be removed in the future when planetstation is here OR SOMETHING but right now we have a problem with races.
/datum/species/mush/after_equip_job(datum/job/J, mob/living/carbon/human/H)
H.grant_language(/datum/language/mushroom) //pomf pomf
/datum/species/mush/on_species_gain(mob/living/carbon/C, datum/species/old_species) /datum/species/mush/on_species_gain(mob/living/carbon/C, datum/species/old_species)
. = ..() . = ..()
if(ishuman(C)) if(ishuman(C))

View File

@@ -14,6 +14,7 @@
var/list/initial_species_traits //for getting these values back for assume_disguise() var/list/initial_species_traits //for getting these values back for assume_disguise()
var/list/initial_inherent_traits var/list/initial_inherent_traits
changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC
species_language_holder = /datum/language_holder/synthetic
/datum/species/synth/New() /datum/species/synth/New()
initial_species_traits = species_traits.Copy() initial_species_traits = species_traits.Copy()

View File

@@ -42,12 +42,11 @@
/mob/living/carbon/human/set_drugginess(amount) /mob/living/carbon/human/set_drugginess(amount)
..() ..()
if(!amount) if(!amount)
remove_language(/datum/language/beachbum) remove_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_HIGH)
/mob/living/carbon/human/adjust_drugginess(amount) /mob/living/carbon/human/adjust_drugginess(amount)
..() ..()
if(!dna.check_mutation(STONER)) if(druggy)
if(druggy) grant_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_HIGH)
grant_language(/datum/language/beachbum) else
else remove_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_HIGH)
remove_language(/datum/language/beachbum)

View File

@@ -12,9 +12,9 @@
return 0 return 0
return ..() return ..()
/mob/living/carbon/could_speak_in_language(datum/language/dt) /mob/living/carbon/could_speak_language(datum/language/language)
var/obj/item/organ/tongue/T = getorganslot(ORGAN_SLOT_TONGUE) var/obj/item/organ/tongue/T = getorganslot(ORGAN_SLOT_TONGUE)
if(T) if(T)
. = T.could_speak_in_language(dt) return T.could_speak_language(language)
else else
. = initial(dt.flags) & TONGUELESS_SPEECH return initial(language.flags) & TONGUELESS_SPEECH

View File

@@ -103,8 +103,6 @@
var/datum/riding/riding_datum var/datum/riding/riding_datum
var/datum/language/selected_default_language
var/last_words //used for database logging var/last_words //used for database logging
var/list/obj/effect/proc_holder/abilities = list() var/list/obj/effect/proc_holder/abilities = list()

View File

@@ -144,7 +144,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
var/datum/language/message_language = get_message_language(message) var/datum/language/message_language = get_message_language(message)
if(message_language) if(message_language)
// No, you cannot speak in xenocommon just because you know the key // No, you cannot speak in xenocommon just because you know the key
if(can_speak_in_language(message_language)) if(can_speak_language(message_language))
language = message_language language = message_language
message = copytext(message, 3) message = copytext(message, 3)
@@ -153,7 +153,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
message = copytext(message, 2) message = copytext(message, 2)
if(!language) if(!language)
language = get_default_language() language = get_selected_language()
// Detection of language needs to be before inherent channels, because // Detection of language needs to be before inherent channels, because
// AIs use inherent channels for the holopad. Most inherent channels // AIs use inherent channels for the holopad. Most inherent channels
@@ -404,11 +404,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
/mob/living/whisper(message, bubble_type, list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null) /mob/living/whisper(message, bubble_type, list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null)
say("#[message]", bubble_type, spans, sanitize, language, ignore_spam, forced) say("#[message]", bubble_type, spans, sanitize, language, ignore_spam, forced)
/mob/living/get_language_holder(shadow=TRUE) /mob/living/get_language_holder(get_minds = TRUE)
if(mind && shadow) if(get_minds && mind)
// Mind language holders shadow mob holders. return mind.get_language_holder()
. = mind.get_language_holder()
if(.)
return .
. = ..() . = ..()

View File

@@ -24,7 +24,7 @@
derpspeech = 1 derpspeech = 1
to_chat(src, "<span class='danger'>Warning: Vocabulary databank corrupted.</span>") to_chat(src, "<span class='danger'>Warning: Vocabulary databank corrupted.</span>")
if(prob(40)) if(prob(40))
mind.language_holder.selected_default_language = pick(mind.language_holder.languages) mind.language_holder.selected_language = get_random_spoken_language()
/mob/living/silicon/pai/ex_act(severity, target) /mob/living/silicon/pai/ex_act(severity, target)

View File

@@ -279,9 +279,8 @@
encryptmod = TRUE encryptmod = TRUE
if("translator") if("translator")
if(href_list["toggle"]) if(href_list["toggle"]) //This is permanent.
grant_all_languages(TRUE) grant_all_languages(TRUE, TRUE, TRUE, LANGUAGE_SOFTWARE)
// this is PERMAMENT.
if("doorjack") if("doorjack")
if(href_list["jack"]) if(href_list["jack"])

View File

@@ -913,7 +913,6 @@ Pass a positive integer as an argument to override a bot's default speed.
bot_name = name bot_name = name
name = paicard.pai.name name = paicard.pai.name
faction = user.faction.Copy() faction = user.faction.Copy()
language_holder = paicard.pai.language_holder.copy(src)
log_combat(user, paicard.pai, "uploaded to [bot_name],") log_combat(user, paicard.pai, "uploaded to [bot_name],")
return TRUE return TRUE
else else

View File

@@ -458,6 +458,7 @@
new_xeno.a_intent = INTENT_HARM new_xeno.a_intent = INTENT_HARM
new_xeno.key = key new_xeno.key = key
update_atom_languages()
to_chat(new_xeno, "<B>You are now an alien.</B>") to_chat(new_xeno, "<B>You are now an alien.</B>")
. = new_xeno . = new_xeno

View File

@@ -259,7 +259,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
add_overlay(causality_field, TRUE) add_overlay(causality_field, TRUE)
var/speaking = "[emergency_alert] The supermatter has reached critical integrity failure. Emergency causality destabilization field has been activated." var/speaking = "[emergency_alert] The supermatter has reached critical integrity failure. Emergency causality destabilization field has been activated."
radio.talk_into(src, speaking, common_channel, language = get_default_language()) radio.talk_into(src, speaking, common_channel, language = get_selected_language())
for(var/i in SUPERMATTER_COUNTDOWN_TIME to 0 step -10) for(var/i in SUPERMATTER_COUNTDOWN_TIME to 0 step -10)
if(damage < explosion_point) // Cutting it a bit close there engineers if(damage < explosion_point) // Cutting it a bit close there engineers
radio.talk_into(src, "[safe_alert] Failsafe has been disengaged.", common_channel) radio.talk_into(src, "[safe_alert] Failsafe has been disengaged.", common_channel)

View File

@@ -276,7 +276,6 @@
if(!new_mob) if(!new_mob)
return return
new_mob.grant_language(/datum/language/common)
// Some forms can still wear some items // Some forms can still wear some items
for(var/obj/item/W in contents) for(var/obj/item/W in contents)

View File

@@ -929,9 +929,10 @@ datum/status_effect/stabilized/blue/on_remove()
familiar = new linked.mob_type(get_turf(owner.loc)) familiar = new linked.mob_type(get_turf(owner.loc))
familiar.name = linked.mob_name familiar.name = linked.mob_name
familiar.del_on_death = TRUE familiar.del_on_death = TRUE
familiar.copy_known_languages_from(owner, FALSE) familiar.copy_languages(owner, LANGUAGE_MASTER)
if(linked.saved_mind) if(linked.saved_mind)
linked.saved_mind.transfer_to(familiar) linked.saved_mind.transfer_to(familiar)
familiar.update_atom_languages()
familiar.ckey = linked.saved_mind.key familiar.ckey = linked.saved_mind.key
else else
if(familiar.mind) if(familiar.mind)

View File

@@ -686,7 +686,7 @@
if(SM.flags_1 & HOLOGRAM_1) //Check to see if it's a holodeck creature if(SM.flags_1 & HOLOGRAM_1) //Check to see if it's a holodeck creature
to_chat(SM, "<span class='userdanger'>You also become depressingly aware that you are not a real creature, but instead a holoform. Your existence is limited to the parameters of the holodeck.</span>") to_chat(SM, "<span class='userdanger'>You also become depressingly aware that you are not a real creature, but instead a holoform. Your existence is limited to the parameters of the holodeck.</span>")
to_chat(user, "<span class='notice'>[SM] accepts [src] and suddenly becomes attentive and aware. It worked!</span>") to_chat(user, "<span class='notice'>[SM] accepts [src] and suddenly becomes attentive and aware. It worked!</span>")
SM.copy_known_languages_from(user, FALSE) SM.copy_languages(user)
after_success(user, SM) after_success(user, SM)
qdel(src) qdel(src)
else else

View File

@@ -122,7 +122,7 @@
assignedrole = "Lavaland Syndicate" assignedrole = "Lavaland Syndicate"
/obj/effect/mob_spawn/human/lavaland_syndicate/special(mob/living/new_spawn) /obj/effect/mob_spawn/human/lavaland_syndicate/special(mob/living/new_spawn)
new_spawn.grant_language(/datum/language/codespeak) new_spawn.grant_language(/datum/language/codespeak, TRUE, TRUE, LANGUAGE_MIND)
/datum/outfit/lavaland_syndicate /datum/outfit/lavaland_syndicate
name = "Lavaland Syndicate Agent" name = "Lavaland Syndicate Agent"

View File

@@ -183,7 +183,7 @@
to_chat(user, "<span class='boldannounce'>You start skimming through [src], but you already know dronespeak.</span>") to_chat(user, "<span class='boldannounce'>You start skimming through [src], but you already know dronespeak.</span>")
else else
to_chat(user, "<span class='boldannounce'>You start skimming through [src], and suddenly the drone chittering makes sense.</span>") to_chat(user, "<span class='boldannounce'>You start skimming through [src], and suddenly the drone chittering makes sense.</span>")
user.grant_language(/datum/language/drone) user.grant_language(/datum/language/drone, TRUE, TRUE, LANGUAGE_MIND)
return return
if(user.has_language(/datum/language/drone)) if(user.has_language(/datum/language/drone))
@@ -197,14 +197,14 @@
if(M == user) if(M == user)
attack_self(user) attack_self(user)
return return
playsound(loc, "punch", 25, TRUE, -1) playsound(loc, "punch", 25, TRUE, -1)
if(isdrone(M) || issilicon(M)) if(isdrone(M) || issilicon(M))
if(M.has_language(/datum/language/drone)) if(M.has_language(/datum/language/drone))
M.visible_message("<span class='danger'>[user] beats [M] over the head with [src]!</span>", "<span class='userdanger'>[user] beats you over the head with [src]!</span>", "<span class='hear'>You hear smacking.</span>") M.visible_message("<span class='danger'>[user] beats [M] over the head with [src]!</span>", "<span class='userdanger'>[user] beats you over the head with [src]!</span>", "<span class='hear'>You hear smacking.</span>")
else else
M.visible_message("<span class='notice'>[user] teaches [M] by beating [M.p_them()] over the head with [src]!</span>", "<span class='boldnotice'>As [user] hits you with [src], chitters resonate in your mind.</span>", "<span class='hear'>You hear smacking.</span>") M.visible_message("<span class='notice'>[user] teaches [M] by beating [M.p_them()] over the head with [src]!</span>", "<span class='boldnotice'>As [user] hits you with [src], chitters resonate in your mind.</span>", "<span class='hear'>You hear smacking.</span>")
M.grant_language(/datum/language/drone) M.grant_language(/datum/language/drone, TRUE, TRUE, LANGUAGE_MIND)
return return
/obj/structure/fluff/oldturret /obj/structure/fluff/oldturret

View File

@@ -41,8 +41,8 @@
UnregisterSignal(M, COMSIG_MOB_SAY, .proc/handle_speech) UnregisterSignal(M, COMSIG_MOB_SAY, .proc/handle_speech)
M.RegisterSignal(M, COMSIG_MOB_SAY, /mob/living/carbon/.proc/handle_tongueless_speech) M.RegisterSignal(M, COMSIG_MOB_SAY, /mob/living/carbon/.proc/handle_tongueless_speech)
/obj/item/organ/tongue/could_speak_in_language(datum/language/dt) /obj/item/organ/tongue/could_speak_language(language)
return is_type_in_typecache(dt, languages_possible) return is_type_in_typecache(language, languages_possible)
/obj/item/organ/tongue/lizard /obj/item/organ/tongue/lizard
name = "forked tongue" name = "forked tongue"
@@ -215,7 +215,7 @@
modifies_speech = TRUE modifies_speech = TRUE
taste_sensitivity = 25 // not as good as an organic tongue taste_sensitivity = 25 // not as good as an organic tongue
/obj/item/organ/tongue/robot/can_speak_in_language(datum/language/dt) /obj/item/organ/tongue/robot/can_speak_language(language)
return TRUE // THE MAGIC OF ELECTRONICS return TRUE // THE MAGIC OF ELECTRONICS
/obj/item/organ/tongue/robot/handle_speech(datum/source, list/speech_args) /obj/item/organ/tongue/robot/handle_speech(datum/source, list/speech_args)

View File

@@ -52,7 +52,9 @@ export const LanguageMenu = props => {
{' '} {' '}
Key: ,{language.key} Key: ,{language.key}
{' '} {' '}
{!!language.shadow && '(gained from mob)'} {language.can_understand
? 'Can understand.'
: 'Cannot understand.'}
{' '} {' '}
{language.can_speak ? 'Can speak.' : 'Cannot speak.'} {language.can_speak ? 'Can speak.' : 'Cannot speak.'}
</LabeledList.Item> </LabeledList.Item>

File diff suppressed because one or more lines are too long