Skip to content

Commit

Permalink
Condenses language holders, unit tests them (#11971)
Browse files Browse the repository at this point in the history
* tongue language privatization

* alright looks done

tgstation/tgstation#76612 tgstation/tgstation#72080

* oops

* sorry, but its runtiming

tgstation/tgstation#56047

* our parent handles this

ill include testing evidence tho
  • Loading branch information
Tsar-Salat authored Dec 24, 2024
1 parent cac7ec5 commit 78cc231
Show file tree
Hide file tree
Showing 47 changed files with 615 additions and 474 deletions.
22 changes: 21 additions & 1 deletion code/__DEFINES/language.dm
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,22 @@


// LANGUAGE SOURCE DEFINES
#define LANGUAGE_ALL "all" // For use in full removal only.
/// For use in full removal only.
#define LANGUAGE_ALL "all"

// Generic language sources.
/// Language is linked to the movable directly.
#define LANGUAGE_ATOM "atom"
/// Language is linked to the mob's mind.
/// If a mind transfer happens, language follows.
#define LANGUAGE_MIND "mind"
/// Language is linked to the mob's species.
/// If a species change happens, language goes away.
/// If applied to a non-human (no species) atom, this is effectively the same as [LANGUAGE_ATOM].
#define LANGUAGE_SPECIES "species"

// More specific language sources.
// Only ever goes away when dismissed directly.
#define LANGUAGE_FRIEND "friend"
#define LANGUAGE_ABSORB "absorb"
#define LANGUAGE_APHASIA "aphasia"
Expand All @@ -46,6 +59,13 @@
#define LANGUAGE_MULTILINGUAL "multilingual"
#define LANGUAGE_EMP "emp"
#define LANGUAGE_HOLOPARA "holoparasite"
#define LANGUAGE_BABEL "babel"

// Language flags. Used in granting and removing languages.
/// This language can be spoken.
#define SPOKEN_LANGUAGE (1<<0)
/// This language can be understood.
#define UNDERSTOOD_LANGUAGE (1<<1)

// Languages available from Multilingual
GLOBAL_LIST_INIT(multilingual_language_list, typecacheof(list(
Expand Down
4 changes: 1 addition & 3 deletions code/_onclick/hud/screen_objects.dm
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,7 @@
screen_loc = ui_language_menu

/atom/movable/screen/language_menu/Click()
var/mob/M = usr
var/datum/language_holder/H = M.get_language_holder()
H.open_language_menu(usr)
usr.get_language_holder().open_language_menu(usr)

/atom/movable/screen/inventory
var/slot_id
Expand Down
5 changes: 5 additions & 0 deletions code/controllers/configuration/configuration.dm
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@

var/motd

/// If the configuration is loaded
var/loaded = FALSE

var/static/regex/ic_filter_regex
var/static/regex/ooc_filter_regex

Expand Down Expand Up @@ -60,6 +63,8 @@
LoadProtectedIDs()
LoadChatFilter()

loaded = TRUE

if (Master)
Master.OnConfigLoad()

Expand Down
14 changes: 0 additions & 14 deletions code/datums/action.dm
Original file line number Diff line number Diff line change
Expand Up @@ -718,20 +718,6 @@
icon_icon = 'icons/hud/actions/actions_items.dmi'
button_icon_state = "jetboot"

/datum/action/language_menu
name = "Language Menu"
desc = "Open the language menu to review your languages, their keys, and select your default language."
button_icon_state = "language_menu"
check_flags = NONE

/datum/action/language_menu/Trigger()
if(!..())
return FALSE
if(ismob(owner))
var/mob/M = owner
var/datum/language_holder/H = M.get_language_holder()
H.open_language_menu(usr)

/datum/action/item_action/wheelys
name = "Toggle Wheely-Heel's Wheels"
desc = "Pops out or in your wheely-heel's wheels."
Expand Down
2 changes: 1 addition & 1 deletion code/datums/brain_damage/mrat.dm
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/mob/camera/imaginary_friend/mrat)
leave = new
leave.Grant(src)

grant_all_languages(spoken=FALSE) // they understand all language, but doesn't have to speak that
grant_all_languages(UNDERSTOOD_LANGUAGE) // they understand all language, but doesn't have to speak that
// mentor rats default language is set to metalanguage from imaginary friend init
// everything mrat says will be understandable to all people

Expand Down
10 changes: 6 additions & 4 deletions code/datums/brain_damage/severe.dm
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@
lose_text = "<span class='notice'>You suddenly remember how languages work.</span>"

/datum/brain_trauma/severe/aphasia/on_gain()
owner.add_blocked_language(subtypesof(/datum/language/) - /datum/language/aphasia, LANGUAGE_APHASIA)
owner.grant_language(/datum/language/aphasia, TRUE, TRUE, LANGUAGE_APHASIA)
owner.add_blocked_language(subtypesof(/datum/language) - /datum/language/aphasia, LANGUAGE_APHASIA)
owner.grant_language(/datum/language/aphasia, source = LANGUAGE_APHASIA)
..()

/datum/brain_trauma/severe/aphasia/on_lose()
owner.remove_blocked_language(subtypesof(/datum/language/), LANGUAGE_APHASIA)
owner.remove_language(/datum/language/aphasia, TRUE, TRUE, LANGUAGE_APHASIA)
if(!QDELING(owner))
owner.remove_blocked_language(subtypesof(/datum/language), LANGUAGE_APHASIA)
owner.remove_language(/datum/language/aphasia, LANGUAGE_APHASIA)

..()

/datum/brain_trauma/severe/blindness
Expand Down
2 changes: 1 addition & 1 deletion code/datums/diseases/advance/symptoms/voice_change.dm
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ Bonus
if(scramble_language && !current_language) // Last part prevents rerolling language with small amounts of cure.
current_language = pick(subtypesof(/datum/language) - /datum/language/common)
H.add_blocked_language(subtypesof(/datum/language) - current_language, LANGUAGE_VOICECHANGE)
H.grant_language(current_language, TRUE, TRUE, LANGUAGE_VOICECHANGE)
H.grant_language(current_language, source = LANGUAGE_VOICECHANGE)

/datum/symptom/voice_change/End(datum/disease/advance/A)
..()
Expand Down
5 changes: 0 additions & 5 deletions code/datums/dna.dm
Original file line number Diff line number Diff line change
Expand Up @@ -344,11 +344,6 @@
dna.species = new_race
dna.species.on_species_gain(src, old_species, pref_load)
SEND_SIGNAL(src, COMSIG_CARBON_SPECIESCHANGE, new_race)
if(ishuman(src))
qdel(language_holder)
var/species_holder = initial(mrace.species_language_holder)
language_holder = new species_holder(src)
update_atom_languages()
if(icon_update)
update_mutations_overlay()// no lizard with human hulk overlay please.

Expand Down
60 changes: 36 additions & 24 deletions code/datums/mind.dm
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
/* Note from Carnie:
/* Note from Carnie:
The way datum/mind stuff works has been changed a lot.
Minds now represent IC characters rather than following a client around constantly.
Guidelines for using minds properly:
- Never mind.transfer_to(ghost). The var/current and var/original of a mind must always be of type mob/living!
- Never mind.transfer_to(ghost). The var/current and var/original of a mind must always be of type mob/living!
ghost.mind is however used as a reference to the ghost's corpse
- When creating a new mob for an existing IC character (e.g. cloning a dead guy or borging a brain of a human)
the existing mind of the old mob should be transfered to the new mob like so:
- When creating a new mob for an existing IC character (e.g. cloning a dead guy or borging a brain of a human)
the existing mind of the old mob should be transferred to the new mob like so:
mind.transfer_to(new_mob)
- You must not assign key= or ckey= after transfer_to() since the transfer_to transfers the client for you.
- You must not assign key= or ckey= after transfer_to() since the transfer_to transfers the client for you.
By setting key or ckey explicitly after transferring the mind with transfer_to you will cause bugs like DCing
the player.
- IMPORTANT NOTE 2, if you want a player to become a ghost, use mob.ghostize() It does all the hard work for you.
- IMPORTANT NOTE 2, if you want a player to become a ghost, use mob.ghostize() It does all the hard work for you.
- When creating a new mob which will be a new IC character (e.g. putting a shade in a construct or randomly selecting
- When creating a new mob which will be a new IC character (e.g. putting a shade in a construct or randomly selecting
a ghost to become a xeno during an event). Simply assign the key or ckey like you've always done.
new_mob.key = key
Expand All @@ -30,22 +30,28 @@
*/

/datum/mind
/// Key of the mob
var/key
var/name //replaces mob/var/original_name
var/ghostname //replaces name for observers name if set
/// The last living mob this mind occupied - if the player is dead, this is their body.
/// The name linked to this mind
var/name
/// replaces name for observers name if set
var/ghostname
/// Current mob this mind datum is attached to
var/mob/living/current
var/active = 0
/// Is this mind active?
var/active = FALSE

var/memory
var/list/quirks = list()

var/assigned_role
/// Job datum indicating the mind's role. This should always exist after initialization, as a reference to a singleton.
var/datum/job/assigned_role
var/special_role
var/list/restricted_roles = list()
var/list/spell_list = list() // Wizard mode & "Give Spell" badmin button.

var/linglink
/// Martial art on this mind
var/datum/martial_art/martial_art
var/static/default_martial_art = new/datum/martial_art
var/miming = 0 // Mime's vow of silence
Expand All @@ -61,7 +67,6 @@
var/no_cloning_at_all = FALSE

var/datum/mind/enslaved_to //If this mind's master is another mob (i.e. adamantine golems)
var/datum/language_holder/language_holder
var/unconvertable = FALSE
var/late_joiner = FALSE

Expand Down Expand Up @@ -97,7 +102,6 @@
/datum/mind/Destroy()
SSticker.minds -= src
QDEL_LIST(antag_datums)
QDEL_NULL(language_holder)
soulOwner = null
set_current(null)
return ..()
Expand All @@ -115,11 +119,6 @@
SIGNAL_HANDLER
set_current(null)

/datum/mind/proc/get_language_holder()
if(!language_holder)
language_holder = new (src)
return language_holder

/datum/mind/proc/transfer_to(mob/new_character, var/force_key_move = 0)
if(current) // remove ourself from our old body's mind variable
current.mind = null
Expand All @@ -137,9 +136,22 @@

var/datum/atom_hud/antag/hud_to_transfer = antag_hud//we need this because leave_hud() will clear this list
var/mob/living/old_current = current
if(current)
current.transfer_observers_to(new_character, TRUE) //transfer anyone observing the old character to the new one
set_current(new_character) //associate ourself with our new body
if(old_current)
//transfer anyone observing the old character to the new one
old_current.transfer_observers_to(new_character)

// Offload all mind languages from the old holder to a temp one
var/datum/language_holder/empty/temp_holder = new()
var/datum/language_holder/old_holder = old_current.get_language_holder()
var/datum/language_holder/new_holder = new_character.get_language_holder()
// Off load mind languages to the temp holder momentarily
new_holder.transfer_mind_languages(temp_holder)
// Transfer the old holder's mind languages to the new holder
old_holder.transfer_mind_languages(new_holder)
// And finally transfer the temp holder's mind languages back to the old holder
temp_holder.transfer_mind_languages(old_holder)

set_current(new_character) //associate ourself with our new body
new_character.mind = src //and associate our new body with ourself

for(var/datum/quirk/T as() in quirks) //Retarget all traits this mind has
Expand All @@ -151,13 +163,13 @@
if(iscarbon(new_character))
var/mob/living/carbon/C = new_character
C.last_mind = src
transfer_antag_huds(hud_to_transfer) //inherit the antag HUD
transfer_antag_huds(hud_to_transfer) //inherit the antag HUD
transfer_actions(new_character)
transfer_martial_arts(new_character)
RegisterSignal(new_character, COMSIG_MOB_DEATH, PROC_REF(set_death_time))
if(active || force_key_move)
new_character.key = key //now transfer the key to link the client to our new body
current.update_atom_languages()

SEND_SIGNAL(src, COMSIG_MIND_TRANSFER_TO, old_current, new_character)
// Update SSD indicators
if(isliving(old_current))
Expand Down
4 changes: 2 additions & 2 deletions code/datums/mutations/speech.dm
Original file line number Diff line number Diff line change
Expand Up @@ -237,12 +237,12 @@

/datum/mutation/stoner/on_acquiring(mob/living/carbon/owner)
..()
owner.grant_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_STONER)
owner.grant_language(/datum/language/beachbum, source = LANGUAGE_STONER)
owner.add_blocked_language(subtypesof(/datum/language) - /datum/language/beachbum, LANGUAGE_STONER)

/datum/mutation/stoner/on_losing(mob/living/carbon/owner)
..()
owner.remove_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_STONER)
owner.remove_language(/datum/language/beachbum, source = LANGUAGE_STONER)
owner.remove_blocked_language(subtypesof(/datum/language) - /datum/language/beachbum, LANGUAGE_STONER)

/datum/mutation/medieval
Expand Down
4 changes: 2 additions & 2 deletions code/datums/status_effects/debuffs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -1048,11 +1048,11 @@
. = ..()
to_chat(owner, "<span class='warning'>Alert: Vocal cords are malfunctioning.</span>")
owner.add_blocked_language(subtypesof(/datum/language/) - /datum/language/uncommon, LANGUAGE_EMP)
owner.grant_language(/datum/language/uncommon, FALSE, TRUE, LANGUAGE_EMP)
owner.grant_language(/datum/language/uncommon, SPOKEN_LANGUAGE, source = LANGUAGE_EMP)

/datum/status_effect/spanish/on_remove()
owner.remove_blocked_language(subtypesof(/datum/language/), LANGUAGE_EMP)
owner.remove_language(/datum/language/uncommon, TRUE, TRUE, LANGUAGE_EMP)
owner.remove_language(/datum/language/uncommon, source = LANGUAGE_EMP)
to_chat(owner, "<span class='warning'>Alert: Vocal cords restored to normal function.</span>")
return ..()

Expand Down
12 changes: 6 additions & 6 deletions code/datums/traits/positive_quirk.dm
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,11 @@
var/datum/language/known_language

/datum/quirk/multilingual/proc/set_up_language()
var/datum/language_holder/LH = quirk_holder.get_language_holder()
var/datum/language_holder/LH = quirk_target.get_language_holder()
if(quirk_holder.assigned_role == JOB_NAME_CURATOR)
return
var/obj/item/organ/tongue/T = quirk_target.getorganslot(ORGAN_SLOT_TONGUE)
var/list/languages_possible = T.languages_possible
var/list/languages_possible = T.get_possible_languages()
languages_possible = languages_possible - typecacheof(/datum/language/codespeak) - typecacheof(/datum/language/narsie) - typecacheof(/datum/language/ratvar)
languages_possible = languages_possible - LH.understood_languages
languages_possible = languages_possible - LH.spoken_languages
Expand All @@ -142,14 +142,14 @@
known_language = read_choice_preference(/datum/preference/choiced/quirk/multilingual_language)
if(!known_language) // default to random
set_up_language()
var/datum/language_holder/LH = quirk_holder.get_language_holder()
LH.grant_language(known_language, TRUE, TRUE, LANGUAGE_MULTILINGUAL)
var/datum/language_holder/LH = quirk_target.get_language_holder()
LH.grant_language(known_language, source = LANGUAGE_MULTILINGUAL)

/datum/quirk/multilingual/remove()
if(!known_language)
return
var/datum/language_holder/LH = quirk_holder.get_language_holder()
LH.remove_language(known_language, TRUE, TRUE, LANGUAGE_MULTILINGUAL)
var/datum/language_holder/LH = quirk_target.get_language_holder()
LH.remove_language(known_language, source = LANGUAGE_MULTILINGUAL)

/datum/quirk/night_vision
name = "Night Vision"
Expand Down
Loading

0 comments on commit 78cc231

Please sign in to comment.