From 0964962220fdca45f11f728a90b330804fc8e5fc Mon Sep 17 00:00:00 2001 From: Aura Dusklight <46622484+NovaDusklight@users.noreply.github.com> Date: Wed, 25 Feb 2026 01:00:04 +0200 Subject: [PATCH] Convert gender and pronoun from bay to TG (#19170) * Convert gender and pronoun from pay to TG * Remove HERM from biological gender init_possible_values because it won't work * fix runtime error --------- Co-authored-by: ShadowLarkens Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com> --- code/game/sound.dm | 5 +- .../preference_setup/general/01_basic.dm | 29 +++----- .../preference_setup/general/03_body.dm | 6 +- .../preference_setup/loadout/01_equipment.dm | 3 +- code/modules/client/preferences.dm | 10 +-- .../preferences/types/character/gender.dm | 73 +++++++++++++++++++ .../preferences/types/character/names.dm | 4 +- code/modules/mob/living/voice/voice.dm | 2 +- code/modules/mob/new_player/lobby_browser.dm | 2 +- code/modules/mob/new_player/new_player.dm | 2 +- .../mob/new_player/preferences_setup.dm | 5 +- .../nifsoft/software/13_soulcatcher.dm | 2 +- vorestation.dme | 1 + 13 files changed, 107 insertions(+), 37 deletions(-) create mode 100644 code/modules/client/preferences/types/character/gender.dm diff --git a/code/game/sound.dm b/code/game/sound.dm index 6cf20f9d39..5e5bf9643c 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -420,10 +420,11 @@ GLOBAL_LIST_INIT(species_sound_map, list( if(valid.selects_bodytype == (SELECTS_BODYTYPE_CUSTOM || SELECTS_BODYTYPE_SHAPESHIFTER)) // Custom species or xenochimera handling here valid = coalesce(GLOB.all_species[pref.custom_base], GLOB.all_species[pref.species]) // Now we start getting our sounds. + var/id_gender = pref.read_preference(/datum/preference/choiced/gender/identifying) if(valid.gender_specific_species_sounds) // Do we have gender-specific sounds? - if(pref.identifying_gender == FEMALE && valid.species_sounds_female) + if(id_gender == FEMALE && valid.species_sounds_female) return valid.species_sounds_female - else if(pref.identifying_gender == MALE && valid.species_sounds_male) + else if(id_gender == MALE && valid.species_sounds_male) return valid.species_sounds_male else // Failsafe. Update if there's ever gendered sounds for HERM/Neuter/etc return valid.species_sounds diff --git a/code/modules/client/preference_setup/general/01_basic.dm b/code/modules/client/preference_setup/general/01_basic.dm index 66253cf0c0..31ae74381c 100644 --- a/code/modules/client/preference_setup/general/01_basic.dm +++ b/code/modules/client/preference_setup/general/01_basic.dm @@ -3,46 +3,39 @@ #define AUTOHISS_FULL 2 /datum/preferences - var/biological_gender = MALE - var/identifying_gender = MALE - var/vore_egg_type = "Egg" //The egg type they have. var/autohiss = "Full" // VOREStation Add: Whether we have Autohiss on. I'm hijacking the egg panel bc this one has a shitton of unused space. /datum/preferences/proc/set_biological_gender(var/gender) - biological_gender = gender - identifying_gender = gender + update_preference_by_type(/datum/preference/choiced/gender/biological, gender) + update_preference_by_type(/datum/preference/choiced/gender/identifying, gender) /datum/category_item/player_setup_item/general/basic name = "Basic" sort_order = 1 /datum/category_item/player_setup_item/general/basic/load_character(list/save_data) - pref.biological_gender = save_data["gender"] - pref.identifying_gender = save_data["id_gender"] pref.vore_egg_type = save_data["vore_egg_type"] pref.autohiss = save_data["autohiss"] /datum/category_item/player_setup_item/general/basic/save_character(list/save_data) - save_data["gender"] = pref.biological_gender - save_data["id_gender"] = pref.identifying_gender save_data["vore_egg_type"] = pref.vore_egg_type save_data["autohiss"] = pref.autohiss /datum/category_item/player_setup_item/general/basic/sanitize_character() - pref.biological_gender = sanitize_inlist(pref.biological_gender, get_genders(), pick(get_genders())) - pref.identifying_gender = (pref.identifying_gender in all_genders_define_list) ? pref.identifying_gender : pref.biological_gender pref.vore_egg_type = sanitize_inlist(pref.vore_egg_type, GLOB.global_vore_egg_types, initial(pref.vore_egg_type)) pref.autohiss = sanitize_inlist(pref.autohiss, list("Off", "Basic", "Full"), initial(pref.autohiss)) // Moved from /datum/preferences/proc/copy_to() /datum/category_item/player_setup_item/general/basic/copy_to_mob(var/mob/living/carbon/human/character) var/char_real_name = pref.read_preference(/datum/preference/name/real_name) + var/char_bio_gender = pref.read_preference(/datum/preference/choiced/gender/biological) + var/char_id_gender = pref.read_preference(/datum/preference/choiced/gender/identifying) // Re-sanitize name on join. // Fixes being able to swap from FBP to organic before round join to be organic with numbers in name. char_real_name = sanitize_name(char_real_name, pref.species, is_FBP()) if(!char_real_name) - char_real_name = random_name(pref.identifying_gender, pref.species) + char_real_name = random_name(char_id_gender, pref.species) if(CONFIG_GET(flag/humans_need_surnames)) var/firstspace = findtext(char_real_name, " ") var/name_length = length(char_real_name) @@ -58,8 +51,8 @@ character.nickname = pref.read_preference(/datum/preference/name/nickname) - character.gender = pref.biological_gender - character.identifying_gender = pref.identifying_gender + character.gender = char_bio_gender + character.identifying_gender = char_id_gender character.vore_egg_type = pref.vore_egg_type // VOREStation Add @@ -81,8 +74,8 @@ data["real_name"] = pref.read_preference(/datum/preference/name/real_name) data["be_random_name"] = pref.read_preference(/datum/preference/toggle/human/name_is_always_random) data["nickname"] = pref.read_preference(/datum/preference/name/nickname) - data["biological_sex"] = gender2text(pref.biological_gender) - data["identifying_gender"] = gender2text(pref.identifying_gender) + data["biological_sex"] = gender2text(pref.read_preference(/datum/preference/choiced/gender/biological)) + data["identifying_gender"] = gender2text(pref.read_preference(/datum/preference/choiced/gender/identifying)) data["age"] = pref.read_preference(/datum/preference/numeric/human/age) data["bday_month"] = pref.read_preference(/datum/preference/numeric/human/bday_month) data["bday_day"] = pref.read_preference(/datum/preference/numeric/human/bday_day) @@ -211,7 +204,7 @@ return TOPIC_NOACTION if("random_name") - pref.update_preference_by_type(/datum/preference/name/real_name, random_name(pref.identifying_gender, pref.species)) + pref.update_preference_by_type(/datum/preference/name/real_name, random_name(pref.read_preference(/datum/preference/choiced/gender/identifying), pref.species)) return TOPIC_REFRESH if("always_random_name") @@ -245,7 +238,7 @@ if("id_gender") var/new_gender = lowertext(params["gender"]) if(new_gender in all_genders_define_list) - pref.identifying_gender = new_gender + pref.update_preference_by_type(/datum/preference/choiced/gender/identifying, new_gender) return TOPIC_REFRESH if("age") diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm index 2c668d746d..2e063513a1 100644 --- a/code/modules/client/preference_setup/general/03_body.dm +++ b/code/modules/client/preference_setup/general/03_body.dm @@ -196,7 +196,7 @@ var/list/wing_styles = pref.get_available_styles(GLOB.wing_styles_list) character.wing_style = wing_styles[pref.wing_style] - character.set_gender(pref.biological_gender) + character.set_gender(pref.read_preference(/datum/preference/choiced/gender/biological)) character.synthetic = pref.species == "Protean" ? GLOB.all_robolimbs["protean"] : null //Clear the existing var. (unless protean, then switch it to the normal protean limb) var/list/organs_to_edit = list() @@ -271,7 +271,7 @@ var/current_name = pref.read_preference(/datum/preference/name/real_name) current_name = sanitize_name(current_name, pref.species) if(!current_name) - current_name = random_name(pref.identifying_gender, pref.species) + current_name = random_name(pref.read_preference(/datum/preference/choiced/gender/identifying), pref.species) pref.update_preference_by_type(/datum/preference/name/real_name, current_name) /datum/category_item/player_setup_item/general/body/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) @@ -756,7 +756,7 @@ var/prev_species = pref.species pref.species = params["species"] if(prev_species != pref.species) - if(!(pref.biological_gender in mob_species.genders)) + if(!(pref.read_preference(/datum/preference/choiced/gender/biological) in mob_species.genders)) pref.set_biological_gender(mob_species.genders[1]) pref.custom_species = null //grab one of the valid hair styles for the newly chosen species diff --git a/code/modules/client/preference_setup/loadout/01_equipment.dm b/code/modules/client/preference_setup/loadout/01_equipment.dm index cc7d37b9e7..923e213413 100644 --- a/code/modules/client/preference_setup/loadout/01_equipment.dm +++ b/code/modules/client/preference_setup/loadout/01_equipment.dm @@ -67,7 +67,8 @@ for(var/datum/category_group/underwear/WRC in GLOB.global_underwear.categories) for(var/datum/category_item/underwear/WRI in WRC.items) - if(WRI.is_default(pref.identifying_gender ? pref.identifying_gender : MALE)) + var/id_gender = pref.read_preference(/datum/preference/choiced/gender/identifying) + if(WRI.is_default(id_gender ? id_gender : MALE)) pref.all_underwear[WRC.name] = WRI.name break diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index ba1bd51f80..97a083cec0 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -158,7 +158,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) // Didn't load a character, so let's randomize set_biological_gender(pick(MALE, FEMALE)) - update_preference_by_type(/datum/preference/name/real_name, random_name(identifying_gender, species)) + update_preference_by_type(/datum/preference/name/real_name, random_name(read_preference(/datum/preference/choiced/gender/identifying), species)) b_type = RANDOM_BLOOD_TYPE if(client) @@ -300,7 +300,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) character.set_species(species) // Special Case: This references variables owned by two different datums, so do it here. if(read_preference(/datum/preference/toggle/human/name_is_always_random)) - update_preference_by_type(/datum/preference/name/real_name, random_name(identifying_gender, species)) + update_preference_by_type(/datum/preference/name/real_name, random_name(read_preference(/datum/preference/choiced/gender/identifying), species)) // Ask the preferences datums to apply their own settings to the new mob player_setup.copy_to_mob(character) @@ -436,8 +436,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(character.dna) character.dna.real_name = character.real_name character.nickname = read_preference(/datum/preference/name/nickname) - character.gender = biological_gender - character.identifying_gender = identifying_gender + character.gender = read_preference(/datum/preference/choiced/gender/biological) + character.identifying_gender = read_preference(/datum/preference/choiced/gender/identifying) character.h_style = h_style @@ -507,7 +507,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/datum/preference/numeric/skin_color = GLOB.preference_entries[/datum/preference/color/human/skin_color] skin_color.apply_pref_to(character,read_preference(/datum/preference/color/human/skin_color)) - character.set_gender(biological_gender) + character.set_gender(read_preference(/datum/preference/choiced/gender/biological)) // Destroy/cyborgize organs and limbs. if (convert_to_prosthetics) //should only really be run for proteans diff --git a/code/modules/client/preferences/types/character/gender.dm b/code/modules/client/preferences/types/character/gender.dm new file mode 100644 index 0000000000..42d2657335 --- /dev/null +++ b/code/modules/client/preferences/types/character/gender.dm @@ -0,0 +1,73 @@ +// Gender/Pronoun preferences for character creation +// Handles biological sex and identifying gender (pronouns) + +/// Abstract gender preference type that provides species-aware validation +/datum/preference/choiced/gender + abstract_type = /datum/preference/choiced/gender + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + can_randomize = FALSE + var/default_species = SPECIES_HUMAN + +/// FBP check +/datum/preference/choiced/gender/proc/is_fbp(datum/preferences/preferences) + if(!preferences?.organ_data) + return FALSE + return preferences.organ_data[BP_TORSO] == "cyborg" + +/// Get the list of valid bio genders for the species +/datum/preference/choiced/gender/proc/get_valid_biological_genders(datum/preferences/preferences) + var/datum/species/S + if(preferences?.species) + S = GLOB.all_species[preferences.species] + if(!S) + S = GLOB.all_species[SPECIES_HUMAN] + var/list/possible_genders = S.genders + if(!is_fbp(preferences)) + return possible_genders + possible_genders = possible_genders.Copy() + possible_genders |= NEUTER + return possible_genders + +/datum/preference/choiced/gender/apply_to_human(mob/living/carbon/human/target, value) + return + +/datum/preference/choiced/gender/apply_to_living(mob/living/target, value) + return + +/datum/preference/choiced/gender/apply_to_silicon(mob/living/silicon/target, value) + return + +/datum/preference/choiced/gender/apply_to_animal(mob/living/simple_mob/target, value) + return + +/datum/preference/choiced/gender/biological + savefile_key = "gender" + +/datum/preference/choiced/gender/biological/init_possible_values() + // Actual validation happens in pref_deserialize + return list(MALE, FEMALE, PLURAL, NEUTER) + +/datum/preference/choiced/gender/biological/create_default_value() + return MALE + +/datum/preference/choiced/gender/biological/pref_deserialize(input, datum/preferences/preferences) + var/list/valid_genders = get_valid_biological_genders(preferences) + return sanitize_inlist(input, valid_genders, pick(valid_genders)) + +/datum/preference/choiced/gender/identifying + savefile_key = "id_gender" + +/datum/preference/choiced/gender/identifying/init_possible_values() + return list(MALE, FEMALE, PLURAL, NEUTER, HERM) + +/datum/preference/choiced/gender/identifying/create_default_value() + return MALE + +/datum/preference/choiced/gender/identifying/pref_deserialize(input, datum/preferences/preferences) + if(input in all_genders_define_list) + return input + var/bio_gender = preferences?.read_preference(/datum/preference/choiced/gender/biological) + if(bio_gender) + return bio_gender + return MALE diff --git a/code/modules/client/preferences/types/character/names.dm b/code/modules/client/preferences/types/character/names.dm index ba4711bab9..5093917849 100644 --- a/code/modules/client/preferences/types/character/names.dm +++ b/code/modules/client/preferences/types/character/names.dm @@ -62,12 +62,12 @@ return "Character" /datum/preference/name/real_name/create_informed_default_value(datum/preferences/preferences) - var/gender = preferences?.identifying_gender || MALE + var/gender = preferences?.read_preference(/datum/preference/choiced/gender/identifying) || MALE var/species = preferences?.species || SPECIES_HUMAN return random_name(gender, species) /datum/preference/name/real_name/create_random_value(datum/preferences/preferences, datum/species/current_species) - var/gender = preferences?.identifying_gender || MALE + var/gender = preferences?.read_preference(/datum/preference/choiced/gender/identifying) || MALE var/species_name = current_species?.name || SPECIES_HUMAN return random_name(gender, species_name) diff --git a/code/modules/mob/living/voice/voice.dm b/code/modules/mob/living/voice/voice.dm index 5e1f5fd437..00ac204b3c 100644 --- a/code/modules/mob/living/voice/voice.dm +++ b/code/modules/mob/living/voice/voice.dm @@ -31,7 +31,7 @@ var/datum/preferences/p = speaker.client.prefs name = p.read_preference(/datum/preference/name/real_name) real_name = name - gender = p.identifying_gender + gender = p.read_preference(/datum/preference/choiced/gender/identifying) for(var/language in p.alternate_languages) add_language(language) diff --git a/code/modules/mob/new_player/lobby_browser.dm b/code/modules/mob/new_player/lobby_browser.dm index b4b0ce81df..9d1391b5b1 100644 --- a/code/modules/mob/new_player/lobby_browser.dm +++ b/code/modules/mob/new_player/lobby_browser.dm @@ -128,7 +128,7 @@ announce_ghost_joinleave(src) if(client.prefs.read_preference(/datum/preference/toggle/human/name_is_always_random)) - client.prefs.update_preference_by_type(/datum/preference/name/real_name, random_name(client.prefs.identifying_gender)) + client.prefs.update_preference_by_type(/datum/preference/name/real_name, random_name(client.prefs.read_preference(/datum/preference/choiced/gender/identifying))) observer.real_name = client.prefs.read_preference(/datum/preference/name/real_name) observer.name = observer.real_name if(!check_rights_for(client, R_HOLDER) && !CONFIG_GET(flag/antag_hud_allowed)) // For new ghosts we remove the verb from even showing up if it's not allowed. diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 2f10decd07..39018b58ce 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -478,7 +478,7 @@ /mob/new_player/get_gender() if(!client || !client.prefs) ..() - return client.prefs.biological_gender + return client.prefs.read_preference(/datum/preference/choiced/gender/biological) /mob/new_player/is_ready() return ready && ..() diff --git a/code/modules/mob/new_player/preferences_setup.dm b/code/modules/mob/new_player/preferences_setup.dm index 7e8b761eb4..2698dc1b63 100644 --- a/code/modules/mob/new_player/preferences_setup.dm +++ b/code/modules/mob/new_player/preferences_setup.dm @@ -292,13 +292,14 @@ /datum/preferences/proc/get_valid_facialhairstyles() var/list/valid_facialhairstyles = list() + var/bio_gender = read_preference(/datum/preference/choiced/gender/biological) for(var/facialhairstyle in GLOB.facial_hair_styles_list) var/datum/sprite_accessory/S = GLOB.facial_hair_styles_list[facialhairstyle] if(S.name == DEVELOPER_WARNING_NAME) continue - if(biological_gender == MALE && S.gender == FEMALE) + if(bio_gender == MALE && S.gender == FEMALE) continue - if(biological_gender == FEMALE && S.gender == MALE) + if(bio_gender == FEMALE && S.gender == MALE) continue if(!(species in S.species_allowed) && (!custom_base || !(custom_base in S.species_allowed))) continue diff --git a/code/modules/nifsoft/software/13_soulcatcher.dm b/code/modules/nifsoft/software/13_soulcatcher.dm index f126f2906d..f7c0095b78 100644 --- a/code/modules/nifsoft/software/13_soulcatcher.dm +++ b/code/modules/nifsoft/software/13_soulcatcher.dm @@ -306,7 +306,7 @@ ..() plane_holder.set_vis(VIS_AUGMENTED, TRUE) plane_holder.set_vis(VIS_SOULCATCHER, TRUE) - identifying_gender = client.prefs.identifying_gender + identifying_gender = client.prefs.read_preference(/datum/preference/choiced/gender/identifying) /mob/living/carbon/brain/caught_soul/Destroy() if(soulcatcher) diff --git a/vorestation.dme b/vorestation.dme index 5822fc139d..e7ae627bc5 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -2479,6 +2479,7 @@ #include "code\modules\client\preferences\migrations\16_colors.dm" #include "code\modules\client\preferences\migrations\17_tails.dm" #include "code\modules\client\preferences\migrations\18_jukebox.dm" +#include "code\modules\client\preferences\types\character\gender.dm" #include "code\modules\client\preferences\types\character\names.dm" #include "code\modules\client\preferences\types\character\antagonism\01_basic.dm" #include "code\modules\client\preferences\types\character\general\01_basic.dm"