Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Language Menu + Yangyu -> Konjin #120

Merged
merged 6 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions code/__DEFINES/~doppler_defines/declarations.dm
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@
#define TRAIT_EXCITABLE "wagwag"
/// Trait for hemophages particularly!
#define TRAIT_OXYIMMUNE "oxyimmune" // Immune to oxygen damage, ideally give this to all non-breathing species or bad stuff will happen
// Trait for extra language point.
#define TRAIT_LINGUIST "Linguist"
5 changes: 5 additions & 0 deletions code/__DEFINES/~doppler_defines/language.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#define LANGUAGE_UNDERSTOOD 1
#define LANGUAGE_SPOKEN 2
// LANGUAGE SOURCE DEFINES
/// Use this when granting languages in special() for spawner roles, to prevent prefs from removing them
#define LANGUAGE_SPAWNER "spawner"
1 change: 1 addition & 0 deletions code/_globalvars/traits/_traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_EXCITABLE" = TRAIT_EXCITABLE,
"TRAIT_TWITCH_ADAPTED" = TRAIT_TWITCH_ADAPTED,
"TRAIT_GOLEM_LIMBATTACHMENT" = TRAIT_GOLEM_LIMBATTACHMENT,
"TRAIT_LINGUIST" = TRAIT_LINGUIST,
),
// DOPPLER EDIT ADDITION END
))
Expand Down
1 change: 1 addition & 0 deletions code/_globalvars/traits/admin_tooling.dm
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list(
"TRAIT_DETECTIVE" = TRAIT_DETECTIVE,
"TRAIT_EXCITABLE" = TRAIT_EXCITABLE,
"TRAIT_TWITCH_ADAPTED" = TRAIT_TWITCH_ADAPTED,
"TRAIT_LINGUIST" = TRAIT_LINGUIST
),
// DOPPLER EDIT ADDITION END
))
Expand Down
12 changes: 12 additions & 0 deletions code/modules/client/preferences/middleware/_middleware.dm
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,15 @@
/// Called when a character is changed.
/datum/preference_middleware/proc/on_new_character(mob/user)
return

//DOPPLER EDIT
/// Called after every update_preference, returns TRUE if this handled it.
/datum/preference_middleware/proc/post_set_preference(mob/user, preference, value)
return FALSE

/// Called when applying preferences to the mob.
/datum/preference_middleware/proc/apply_to_human(mob/living/carbon/human/target, datum/preferences/preferences, visuals_only = FALSE) //NOVA EDIT CHANGE
SHOULD_NOT_SLEEP(TRUE)
SHOULD_CALL_PARENT(FALSE)
return
//DOPPLER EDIT END
1 change: 0 additions & 1 deletion code/modules/surgery/organs/internal/tongue/_tongue.dm
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@
/datum/language/shadowtongue,
/datum/language/terrum,
/datum/language/nekomimetic,
/datum/language/yangyu, //DOPPLER ADDITION
)

/obj/item/organ/internal/tongue/proc/handle_speech(datum/source, list/speech_args)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@
icon_state = "omgkittyhiii"
icon = 'modular_doppler/hearthkin/primitive_genemod/icons/language_icon.dmi'
default_priority = 94
// secret = TRUE //this needs a dedicated module for language
secret = TRUE
22 changes: 22 additions & 0 deletions modular_doppler/languages/code/language menu/_language.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/datum/language/
/// Should this be hidden on the language buy menu?
var/secret = FALSE


/datum/language/aphasia
secret = TRUE

/datum/language/codespeak
secret = TRUE

/datum/language/drone
secret = TRUE

/datum/language/narsie
secret = TRUE

/datum/language/piratespeak
secret = TRUE

/datum/language/xenocommon
secret = TRUE
169 changes: 169 additions & 0 deletions modular_doppler/languages/code/language menu/client_languages.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
#define MAX_LANGUAGES_NORMAL 3
#define MAX_LANGUAGES_LINGUIST 4

/datum/asset/spritesheet/languages
name = "languages"
early = TRUE
cross_round_cachable = TRUE

/datum/asset/spritesheet/languages/create_spritesheets()
var/list/to_insert = list()

if(!GLOB.all_languages.len)
stack_trace("Warning: Language spritesheets could not be created because language subsystem has not been loaded yet. This should not happen--adjust the init_order in master_files/code/controllers/subsystem/language.dm.")
return

for (var/language_name in GLOB.all_languages)
var/datum/language/language = GLOB.language_datum_instances[language_name]
var/icon/language_icon = icon(language.icon, icon_state = language.icon_state)
to_insert[sanitize_css_class_name(language.name)] = language_icon

for (var/spritesheet_key in to_insert)
Insert(spritesheet_key, to_insert[spritesheet_key])

/// Middleware to handle languages
/datum/preference_middleware/languages
/// A associative list of language names to their typepath
var/static/list/name_to_language = list()
action_delegations = list(
"give_language" = PROC_REF(give_language),
"remove_language" = PROC_REF(remove_language),
)

/datum/preference_middleware/languages/apply_to_human(mob/living/carbon/human/target, datum/preferences/preferences, visuals_only = FALSE)
var/datum/language_holder/language_holder = target.get_language_holder()
language_holder.adjust_languages_to_prefs(preferences)

/datum/preference_middleware/languages/get_ui_assets()
return list(
get_asset_datum(/datum/asset/spritesheet/languages),
)

/datum/preference_middleware/languages/post_set_preference(mob/user, preference, value)
if(preference != "species")
return
preferences.languages = list()
var/species_type = preferences.read_preference(/datum/preference/choiced/species)
var/datum/species/species = new species_type()
var/datum/language_holder/lang_holder = new species.species_language_holder()
for(var/language in preferences.get_adjusted_language_holder())
preferences.languages[language] = LANGUAGE_SPOKEN
qdel(lang_holder)
qdel(species)

for(var/language in lang_holder.spoken_languages)
preferences.languages[language] = LANGUAGE_SPOKEN

qdel(lang_holder)
qdel(species)

return ..()

/datum/preference_middleware/languages/get_ui_data(mob/user)
if(length(name_to_language) != length(GLOB.all_languages))
initialize_name_to_language()

var/list/data = list()

var/max_languages = preferences.all_quirks.Find(TRAIT_LINGUIST) ? MAX_LANGUAGES_LINGUIST : MAX_LANGUAGES_NORMAL
var/species_type = preferences.read_preference(/datum/preference/choiced/species)
var/datum/species/species = new species_type()
var/datum/language_holder/lang_holder = preferences.get_adjusted_language_holder()
if(!preferences.languages || !preferences.languages.len || (preferences.languages && preferences.languages.len > max_languages)) // Too many languages, or no languages.
preferences.languages = list()
for(var/language in lang_holder.spoken_languages)
preferences.languages[language] = LANGUAGE_SPOKEN

var/list/selected_languages = list()
var/list/unselected_languages = list()

for (var/language_name in GLOB.all_languages)
var/datum/language/language = GLOB.language_datum_instances[language_name]

if(language.secret && !(language.type in species.language_prefs_whitelist)) // For ghostrole species who are able to speak a secret language, e.g. ashwalkers, display it.
continue

if(species.always_customizable && !(language.type in lang_holder.spoken_languages)) // For the ghostrole species. We don't want ashwalkers speaking beachtongue now.
continue
if(preferences.languages[language.type])
selected_languages += list(list(
"description" = language.desc,
"name" = language.name,
"icon" = sanitize_css_class_name(language.name)
))
else
unselected_languages += list(list(
"description" = language.desc,
"name" = language.name,
"icon" = sanitize_css_class_name(language.name)
))

qdel(lang_holder)
qdel(species)

data["total_language_points"] = max_languages
data["selected_languages"] = selected_languages
data["unselected_languages"] = unselected_languages
return data

/// (Re-)Initializes the `name_to_language` associative list, to ensure that it's properly populated.
/datum/preference_middleware/languages/proc/initialize_name_to_language()
name_to_language = list()
for(var/language_name in GLOB.all_languages)
var/datum/language/language = GLOB.language_datum_instances[language_name]
name_to_language[language.name] = language_name

/**
* Proc that gives a language to a character, granted that they don't already have too many
* of them, based on their maximum amount of languages.
*
* Arguments:
* * params - List of parameters, given to us by the `act()` method from TGUI. Needs to
* contain a value under `"language_name"`.
*
* Returns TRUE all the time, to ensure that the UI is updated.
*/
/datum/preference_middleware/languages/proc/give_language(list/params)
var/language_name = params["language_name"]
var/max_languages = preferences.all_quirks.Find(TRAIT_LINGUIST) ? MAX_LANGUAGES_LINGUIST : MAX_LANGUAGES_NORMAL

if(preferences.languages && preferences.languages.len == max_languages) // too many languages
return TRUE

preferences.languages[name_to_language[language_name]] = LANGUAGE_SPOKEN
return TRUE

/**
* Proc that removes a language from a character.
*
* Arguments:
* * params - List of parameters, given to us by the `act()` method from TGUI. Needs to
* contain a value under `"language_name"`.
*
* Returns TRUE all the time, to ensure that the UI is updated.
*/
/datum/preference_middleware/languages/proc/remove_language(list/params)
var/language_name = params["language_name"]
preferences.languages -= name_to_language[language_name]
return TRUE

/// Cleans up any invalid languages. Typically happens on language renames and codedels.
/datum/preferences/proc/sanitize_languages()
var/languages_edited = FALSE
for(var/lang_path as anything in languages)
if(!lang_path)
languages.Remove(lang_path)
languages_edited = TRUE
continue

var/datum/language/language = new lang_path()
// Yes, checking subtypes is VERY necessary, because byond doesn't check to see if a path is valid at runtime!
// If you delete /datum/language/meme, it will still load as /datum/language/meme, and will instantiate with /datum/language's defaults!
var/species_type = read_preference(/datum/preference/choiced/species)
var/datum/species/species = new species_type()
if(!(language.type in subtypesof(/datum/language)) || (language.secret && !(language.type in species.language_prefs_whitelist)))
languages.Remove(lang_path)
languages_edited = TRUE
qdel(species)
qdel(language)
return languages_edited
111 changes: 111 additions & 0 deletions modular_doppler/languages/code/language menu/language_holder.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
GLOBAL_DATUM_INIT(language_holder_adjustor, /datum/language_holder_adjustor, new)

/// Language code needs to be purged. Make sure, once and for all, that we get the correct languages on spawn.
/// Every time a crew member joins the adjustor will personally fix their language, because there is too much coupling between mind and language code to do it reliably otherwise.
/// It has already needed to be fixed like 3 times. This will (hopefully) be the final time.
/datum/language_holder_adjustor/New()
RegisterSignal(SSdcs, COMSIG_GLOB_CREWMEMBER_JOINED, PROC_REF(handle_new_player))

/datum/language_holder_adjustor/proc/handle_new_player(datum/source, mob/living/carbon/human/new_crewmember, rank)
SIGNAL_HANDLER

// sanity checking because we really do not want to be causing any runtimes
if(!istype(new_crewmember))
return
if(isnull(new_crewmember.mind))
return

var/datum/language_holder/language_holder = new_crewmember.get_language_holder()

if(isnull(language_holder))
return

language_holder.adjust_languages_to_prefs(new_crewmember.client?.prefs)

/datum/language_holder_adjustor/Destroy()
..()
UnregisterSignal(SSdcs, COMSIG_GLOB_CREWMEMBER_JOINED)

/datum/language_holder/proc/adjust_languages_to_prefs(datum/preferences/preferences)
// no prefs? then don't remove any languages
if(!preferences)
return

// remove the innate languages (like common, and other species languages) and instead use the language prefs
// do not remove any languages granted by spawners, which are denoted by source = LANGUAGE_SPAWNER
remove_languages_by_source(list(LANGUAGE_MIND, LANGUAGE_ATOM, LANGUAGE_SPECIES))

for(var/lang_path in preferences.languages)
grant_language(lang_path)

get_selected_language()

/// Removes every language whose source(s) match the provided source list arg
/datum/language_holder/proc/remove_languages_by_source(list/sources)
if(!length(sources))
return
for(var/language in understood_languages)
for(var/source in sources)
remove_language(language, ALL, source)
// in most cases spoken_languages should be empty by now, but just in case we should remove what's left
for(var/language in spoken_languages)
for(var/source in sources)
remove_language(language, ALL, source)

//************************************************
//* Specific language holders *
//* Use atom language sources only. *
//************************************************/

/datum/language_holder/machine // SYNTHETIC LIZARD & CO LANGUAGE
understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM),
/datum/language/machine = list(LANGUAGE_ATOM))
spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM),
/datum/language/machine = list(LANGUAGE_ATOM))

/// Modularized the Cyborg and AI language_holder, add here the languages that you want them to be able to speak and understand.
/datum/language_holder/synthetic
understood_languages = list(
/datum/language/common = list(LANGUAGE_ATOM),
/datum/language/uncommon = list(LANGUAGE_ATOM),
/datum/language/machine = list(LANGUAGE_ATOM),
/datum/language/draconic = list(LANGUAGE_ATOM),
/datum/language/moffic = list(LANGUAGE_ATOM),
/datum/language/calcic = list(LANGUAGE_ATOM),
/datum/language/voltaic = list(LANGUAGE_ATOM),
/datum/language/nekomimetic = list(LANGUAGE_ATOM),
/datum/language/gutter = list(LANGUAGE_ATOM),
/datum/language/konjin = list(LANGUAGE_ATOM),
/datum/language/monkey = list(LANGUAGE_ATOM),
/datum/language/slime = list(LANGUAGE_ATOM),
/datum/language/beachbum = list(LANGUAGE_ATOM),
/datum/language/mushroom = list(LANGUAGE_ATOM),
/datum/language/shadowtongue = list(LANGUAGE_ATOM),
/datum/language/buzzwords = list(LANGUAGE_ATOM),
/datum/language/terrum = list(LANGUAGE_ATOM),
/datum/language/sylvan = list(LANGUAGE_ATOM),
)
spoken_languages = list(
/datum/language/common = list(LANGUAGE_ATOM),
/datum/language/uncommon = list(LANGUAGE_ATOM),
/datum/language/machine = list(LANGUAGE_ATOM),
/datum/language/draconic = list(LANGUAGE_ATOM),
/datum/language/moffic = list(LANGUAGE_ATOM),
/datum/language/calcic = list(LANGUAGE_ATOM),
/datum/language/voltaic = list(LANGUAGE_ATOM),
/datum/language/nekomimetic = list(LANGUAGE_ATOM),
/datum/language/gutter = list(LANGUAGE_ATOM),
/datum/language/konjin = list(LANGUAGE_ATOM),
/datum/language/monkey = list(LANGUAGE_ATOM),
/datum/language/slime = list(LANGUAGE_ATOM),
/datum/language/beachbum = list(LANGUAGE_ATOM),
/datum/language/mushroom = list(LANGUAGE_ATOM),
/datum/language/shadowtongue = list(LANGUAGE_ATOM),
/datum/language/buzzwords = list(LANGUAGE_ATOM),
/datum/language/terrum = list(LANGUAGE_ATOM),
/datum/language/sylvan = list(LANGUAGE_ATOM),
)

/datum/language_holder/drone_nova
understood_languages = list(/datum/language/drone = list(LANGUAGE_ATOM), /datum/language/common = list(LANGUAGE_ATOM))
spoken_languages = list(/datum/language/drone = list(LANGUAGE_ATOM))
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#define MAX_MUTANT_ROWS 4

/datum/preferences
/// Associative list, keyed by language typepath, pointing to LANGUAGE_UNDERSTOOD, or LANGUAGE_SPOKEN, for whether we understand or speak the language
var/list/languages = list()

/datum/preferences/proc/species_updated(species_type)
all_quirks = list()
// Reset cultural stuff
languages[try_get_common_language()] = LANGUAGE_SPOKEN
save_character()

/// This helper proc gets the current species language holder and does any post-processing that's required in one easy to track place.
/// This proc should *always* be edited or used when modifying or getting the default languages of a player controlled, unrestricted species, to prevent any errant conflicts.
/datum/preferences/proc/get_adjusted_language_holder()
var/datum/species/species = read_preference(/datum/preference/choiced/species)
species = new species()
var/datum/language_holder/language_holder = new species.species_language_holder()

// Do language post procesing here. Used to house our foreigner functionality.
// I saw little reason to remove this proc, considering it makes code using this a little easier to read.

return language_holder

/// Tries to get the topmost language of the language holder. Should be the species' native language, and if it isn't, you should pester a coder.
/datum/preferences/proc/try_get_common_language()
var/datum/language_holder/language_holder = get_adjusted_language_holder()
var/language = language_holder.spoken_languages[1]
return language
Loading
Loading