From f83ef617e97107c02d778bebdbbd28df02b9b07e Mon Sep 17 00:00:00 2001 From: Luc <89928798+lewcc@users.noreply.github.com> Date: Sun, 21 Apr 2024 11:59:23 -0400 Subject: [PATCH] Expands "genderless" to all species, adds body-type option, removes some gender checks (#23910) * adds most body type support, removes some gender checks * remove gender from species, accessories * restore pick_list * re-adds limitations on accessories * Universal access to body hair * remove unused var * Update example config, some preference saving code * updates tgui bundle * oops * Remove formatting * hopefully undoes formatting changes * dammit * been meaning to fix this one for a while * dgamer reviews * move body_type into human_defines * sql file changes * update tgui * Update db code * bump versions --------- Co-authored-by: S34N <12197162+S34NW@users.noreply.github.com> Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> --- SQL/paradise_schema.sql | 1 + SQL/updates/54-55.sql | 9 +++ code/__DEFINES/dna.dm | 23 +++--- code/__DEFINES/misc_defines.dm | 2 +- code/__HELPERS/mob_helpers.dm | 15 ++-- code/__HELPERS/sanitize_values.dm | 14 ++-- code/game/dna/dna2.dm | 6 ++ code/game/dna/dna2_helpers.dm | 6 ++ .../login_processing/20-load_characters.dm | 3 +- code/modules/client/preference/character.dm | 43 +++++++---- .../client/preference/link_processing.dm | 73 +++++++++---------- code/modules/client/preference/preferences.dm | 5 +- .../mob/living/carbon/human/appearance.dm | 27 +++---- .../mob/living/carbon/human/human_defines.dm | 2 + .../mob/living/carbon/human/human_mob.dm | 3 - .../living/carbon/human/species/_species.dm | 1 - .../carbon/human/species/diona_species.dm | 1 - .../mob/living/carbon/human/species/drask.dm | 1 - .../mob/living/carbon/human/species/grey.dm | 1 - .../living/carbon/human/species/machine.dm | 1 - .../mob/living/carbon/human/species/vox.dm | 1 - .../human/human_facial_hair.dm | 1 - .../sprite_accessories/human/human_hair.dm | 1 - .../sprite_accessories/skrell/skrell_face.dm | 16 ---- .../sprite_accessories/sprite_accessories.dm | 42 ++++++----- .../unathi/unathi_facial_hair.dm | 1 - .../sprite_accessories/vox/vox_facial_hair.dm | 1 - .../vulpkanin/vulpkanin_facial_hair.dm | 1 - .../vulpkanin/vulpkanin_hair.dm | 1 - code/modules/surgery/organs/organ_icon.dm | 13 ++-- .../tgui/modules/appearance_changer.dm | 1 - config/example/config.toml | 2 +- .../tgui/interfaces/AppearanceChanger.js | 5 +- tgui/public/tgui.bundle.js | 18 ++--- 34 files changed, 171 insertions(+), 170 deletions(-) create mode 100644 SQL/updates/54-55.sql diff --git a/SQL/paradise_schema.sql b/SQL/paradise_schema.sql index 60c0dc25dc0..c472e55eb21 100644 --- a/SQL/paradise_schema.sql +++ b/SQL/paradise_schema.sql @@ -27,6 +27,7 @@ CREATE TABLE `characters` ( `real_name` varchar(55) COLLATE utf8mb4_unicode_ci NOT NULL, `name_is_always_random` tinyint(1) NOT NULL, `gender` varchar(11) COLLATE utf8mb4_unicode_ci NOT NULL, + `body_type` varchar(11) COLLATE utf8mb4_unicode_ci NOT NULL, `age` smallint(4) NOT NULL, `species` varchar(45) COLLATE utf8mb4_unicode_ci NOT NULL, `language` varchar(45) COLLATE utf8mb4_unicode_ci NOT NULL, diff --git a/SQL/updates/54-55.sql b/SQL/updates/54-55.sql new file mode 100644 index 00000000000..8b388b65f0c --- /dev/null +++ b/SQL/updates/54-55.sql @@ -0,0 +1,9 @@ +# Updating DB from 54-55 - lewc +# Adds a new `body_type` (gender sprite) column to the `characters` table + +# Add the new column next to the existing `gender` one +ALTER TABLE `characters` + ADD COLUMN `body_type` varchar(11) COLLATE utf8mb4_unicode_ci NOT NULL AFTER `gender`; + +# Set the `body_type` column to whatever's already in `gender`, so that it doesn't change existing characters +UPDATE `characters` SET `body_type` = `gender` WHERE `gender` IS NOT NULL diff --git a/code/__DEFINES/dna.dm b/code/__DEFINES/dna.dm index c3cdf346f92..6f6b03b29ad 100644 --- a/code/__DEFINES/dna.dm +++ b/code/__DEFINES/dna.dm @@ -50,17 +50,18 @@ #define DNA_UI_EYES_G 35 #define DNA_UI_EYES_B 36 #define DNA_UI_GENDER 37 -#define DNA_UI_BEARD_STYLE 38 -#define DNA_UI_HAIR_STYLE 39 -#define DNA_UI_HACC_STYLE 40 -#define DNA_UI_BACC_STYLE 41 -#define DNA_UI_HAIR_GRADIENT_STYLE 42 -#define DNA_UI_HEAD_MARK_STYLE 43 -#define DNA_UI_BODY_MARK_STYLE 44 -#define DNA_UI_TAIL_MARK_STYLE 45 -#define DNA_UI_PHYSIQUE 46 -#define DNA_UI_HEIGHT 47 -#define DNA_UI_LENGTH 48 // Update this when you add something, or you WILL break shit. +#define DNA_UI_BODY_TYPE 38 +#define DNA_UI_BEARD_STYLE 39 +#define DNA_UI_HAIR_STYLE 40 +#define DNA_UI_HACC_STYLE 41 +#define DNA_UI_BACC_STYLE 42 +#define DNA_UI_HAIR_GRADIENT_STYLE 43 +#define DNA_UI_HEAD_MARK_STYLE 44 +#define DNA_UI_BODY_MARK_STYLE 45 +#define DNA_UI_TAIL_MARK_STYLE 46 +#define DNA_UI_PHYSIQUE 47 +#define DNA_UI_HEIGHT 48 +#define DNA_UI_LENGTH 49 // Update this when you add something, or you WILL break shit. #define DNA_SE_LENGTH 55 // Was STRUCDNASIZE, size 27. 15 new blocks added = 42, plus room to grow. diff --git a/code/__DEFINES/misc_defines.dm b/code/__DEFINES/misc_defines.dm index c1ab48c1f79..17beb518b37 100644 --- a/code/__DEFINES/misc_defines.dm +++ b/code/__DEFINES/misc_defines.dm @@ -398,7 +398,7 @@ #define INVESTIGATE_BOMB "bombs" // The SQL version required by this version of the code -#define SQL_VERSION 54 +#define SQL_VERSION 55 // Vending machine stuff #define CAT_NORMAL (1<<0) diff --git a/code/__HELPERS/mob_helpers.dm b/code/__HELPERS/mob_helpers.dm index bebb8213919..42a2c024560 100644 --- a/code/__HELPERS/mob_helpers.dm +++ b/code/__HELPERS/mob_helpers.dm @@ -43,8 +43,6 @@ if(hairstyle == "Bald") //Just in case. valid_hairstyles += hairstyle continue - if((gender == MALE && S.gender == FEMALE) || (gender == FEMALE && S.gender == MALE)) - continue if(species == "Machine") //If the user is a species who can have a robotic head... if(!robohead) robohead = GLOB.all_robolimbs["Morpheus Cyberkinetics"] @@ -72,8 +70,6 @@ if(facialhairstyle == "Shaved") //Just in case. valid_facial_hairstyles += facialhairstyle continue - if((gender == MALE && S.gender == FEMALE) || (gender == FEMALE && S.gender == MALE)) - continue if(species == "Machine") //If the user is a species who can have a robotic head... if(!robohead) robohead = GLOB.all_robolimbs["Morpheus Cyberkinetics"] @@ -171,10 +167,13 @@ current_species = GLOB.all_species[species] if(!current_species || current_species.name == "Human") - if(gender==FEMALE) - return capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names)) - else - return capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names)) + switch(gender) + if(FEMALE) + return capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names)) + if(MALE) + return capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names)) + else + return capitalize(pick(GLOB.first_names_male + GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names)) else return current_species.get_random_name(gender) diff --git a/code/__HELPERS/sanitize_values.dm b/code/__HELPERS/sanitize_values.dm index 2ba09743571..8c7f9714d4b 100644 --- a/code/__HELPERS/sanitize_values.dm +++ b/code/__HELPERS/sanitize_values.dm @@ -23,15 +23,15 @@ //more specialised stuff -/proc/sanitize_gender(gender,neuter=0,plural=0, default="male") +/proc/sanitize_gender(gender, neuter = FALSE, default = "male") switch(gender) - if(MALE, FEMALE)return gender + if(MALE, FEMALE, PLURAL) + return gender if(NEUTER) - if(neuter) return gender - else return default - if(PLURAL) - if(plural) return gender - else return default + if(neuter) + return gender + else + return default return default /proc/sanitize_hexcolor(color, default="#000000") diff --git a/code/game/dna/dna2.dm b/code/game/dna/dna2.dm index 86d0448bbac..cb5cd14435c 100644 --- a/code/game/dna/dna2.dm +++ b/code/game/dna/dna2.dm @@ -136,6 +136,12 @@ GLOBAL_LIST_EMPTY(bad_blocks) var/list/bodyacc = GLOB.body_accessory_by_name.Find(character.body_accessory?.name || "None") SetUIValueRange(DNA_UI_BACC_STYLE, bodyacc, length(GLOB.body_accessory_by_name), 1) + switch(character.body_type) + if(FEMALE) + SetUIState(DNA_UI_BODY_TYPE, DNA_GENDER_FEMALE, TRUE) + if(MALE) + SetUIState(DNA_UI_BODY_TYPE, DNA_GENDER_MALE, TRUE) + //Set the Gender switch(character.gender) if(FEMALE) diff --git a/code/game/dna/dna2_helpers.dm b/code/game/dna/dna2_helpers.dm index b3de3a92f38..c387b34e5c3 100644 --- a/code/game/dna/dna2_helpers.dm +++ b/code/game/dna/dna2_helpers.dm @@ -154,6 +154,12 @@ H.s_tone = 35 - dna.GetUIValueRange(DNA_UI_SKIN_TONE, 220) // Value can be negative. + switch(dna.GetUIState(DNA_UI_BODY_TYPE)) + if(DNA_GENDER_FEMALE) + H.change_body_type(FEMALE, FALSE) + if(DNA_GENDER_MALE) + H.change_body_type(MALE, FALSE) + switch(dna.GetUITriState(DNA_UI_GENDER)) if(DNA_GENDER_FEMALE) H.change_gender(FEMALE, FALSE) diff --git a/code/modules/client/login_processing/20-load_characters.dm b/code/modules/client/login_processing/20-load_characters.dm index 40be0ffc0cd..22d72472264 100644 --- a/code/modules/client/login_processing/20-load_characters.dm +++ b/code/modules/client/login_processing/20-load_characters.dm @@ -61,7 +61,8 @@ custom_emotes, physique, height, - cyborg_brain_type + cyborg_brain_type, + body_type FROM characters WHERE ckey=:ckey"}, list( "ckey" = C.ckey )) diff --git a/code/modules/client/preference/character.dm b/code/modules/client/preference/character.dm index 1179c524ea1..9bfd23e7846 100644 --- a/code/modules/client/preference/character.dm +++ b/code/modules/client/preference/character.dm @@ -6,6 +6,7 @@ var/real_name //our character's name var/be_random_name = FALSE //whether we are a random name every round var/gender = MALE //gender of character (well duh) + var/body_type = MALE //body sprite variant var/age = 30 //age of character var/b_type = "A+" //blood type (not-chooseable) var/underwear = "Nude" //underwear type @@ -118,13 +119,13 @@ var/markingcolourslist = list2params(m_colours) var/markingstyleslist = list2params(m_styles) - if(!isemptylist(organ_data)) + if(length(organ_data)) organ_list = list2params(organ_data) - if(!isemptylist(rlimb_data)) + if(length(rlimb_data)) rlimb_list = list2params(rlimb_data) - if(!isemptylist(player_alt_titles)) + if(length(player_alt_titles)) playertitlelist = list2params(player_alt_titles) - if(!isemptylist(loadout_gear)) + if(length(loadout_gear)) gearlist = json_encode(loadout_gear) var/datum/db_query/firstquery = SSdbcore.NewQuery("SELECT slot FROM characters WHERE ckey=:ckey ORDER BY slot", list( @@ -141,6 +142,7 @@ real_name=:real_name, name_is_always_random=:be_random_name, gender=:gender, + body_type=:body_type, age=:age, species=:species, language=:language, @@ -193,7 +195,8 @@ hair_gradient_colour=:h_grad_colour, hair_gradient_alpha=:h_grad_alpha, custom_emotes=:custom_emotes, - cyborg_brain_type=:cyborg_brain_type + cyborg_brain_type=:cyborg_brain_type, + body_type=:body_type WHERE ckey=:ckey AND slot=:slot"}, list( // OH GOD SO MANY PARAMETERS @@ -201,6 +204,7 @@ "real_name" = real_name, "be_random_name" = be_random_name, "gender" = gender, + "body_type" = body_type, "age" = age, "species" = species, "language" = language, @@ -294,7 +298,7 @@ player_alt_titles, disabilities, organ_data, rlimb_data, nanotrasen_relation, physique, height, speciesprefs, socks, body_accessory, gear, autohiss, - hair_gradient, hair_gradient_offset, hair_gradient_colour, hair_gradient_alpha, custom_emotes, cyborg_brain_type) + hair_gradient, hair_gradient_offset, hair_gradient_colour, hair_gradient_alpha, custom_emotes, cyborg_brain_type, body_type) VALUES (:ckey, :slot, :metadata, :name, :be_random_name, :gender, :age, :species, :language, @@ -321,7 +325,7 @@ :playertitlelist, :disabilities, :organ_list, :rlimb_list, :nanotrasen_relation, :physique, :height, :speciesprefs, :socks, :body_accessory, :gearlist, :autohiss_mode, - :h_grad_style, :h_grad_offset, :h_grad_colour, :h_grad_alpha, :custom_emotes, :cyborg_brain_type) + :h_grad_style, :h_grad_offset, :h_grad_colour, :h_grad_alpha, :custom_emotes, :cyborg_brain_type, :body_type) "}, list( // This has too many params for anyone to look at this without going insae "ckey" = C.ckey, @@ -330,6 +334,7 @@ "name" = real_name, "be_random_name" = be_random_name, "gender" = gender, + "body_type" = body_type, "age" = age, "species" = species, "language" = language, @@ -394,6 +399,10 @@ return 1 +/** + * Load in and process the database's information on the player's character save. + * The order of indices here is the relative order from get_query() in 20-load-characters.dm. + */ /datum/character_save/proc/load(datum/db_query/query) //Character metadata = query.item[1] @@ -471,6 +480,7 @@ physique = query.item[56] height = query.item[57] cyborg_brain_type = query.item[58] + body_type = query.item[59] //Sanitize var/datum/species/SP = GLOB.all_species[species] @@ -504,7 +514,7 @@ real_name = random_name(gender, species) be_random_name = sanitize_integer(be_random_name, 0, 1, initial(be_random_name)) - gender = sanitize_gender(gender, FALSE, !SP.has_gender) + gender = sanitize_gender(gender, FALSE) age = sanitize_integer(age, SP.min_age, SP.max_age, initial(age)) h_colour = sanitize_hexcolor(h_colour) h_sec_colour = sanitize_hexcolor(h_sec_colour) @@ -590,9 +600,10 @@ gender = gender_override else gender = pick(MALE, FEMALE) - underwear = random_underwear(gender, species) - undershirt = random_undershirt(gender, species) - socks = random_socks(gender, species) + body_type = pick(MALE, FEMALE) + underwear = random_underwear(body_type, species) + undershirt = random_undershirt(body_type, species) + socks = random_socks(body_type, species) if(length(GLOB.body_accessory_by_species[species])) body_accessory = random_body_accessory(species, S.optional_body_accessory) if(S.bodyflags & (HAS_SKIN_TONE|HAS_ICON_SKIN_TONE)) @@ -794,7 +805,8 @@ qdel(preview_icon) var/g = "m" - if(gender == FEMALE) g = "f" + if(body_type == FEMALE) + g = "f" var/icon/icobase var/datum/species/current_species = GLOB.all_species[species] @@ -1808,6 +1820,7 @@ character.gen_record = gen_record character.change_gender(gender) + character.body_type = body_type // TODO does this update the character properly or do we need a setter here character.age = age //Head-specific @@ -1885,10 +1898,10 @@ character.backbag = backbag //Debugging report to track down a bug, which randomly assigned the plural gender to people. - if(character.dna.species.has_gender && (character.gender in list(PLURAL, NEUTER))) + if(character.gender == NEUTER) if(isliving(src)) //Ghosts get neuter by default - message_admins("[key_name_admin(character)] has spawned with their gender as plural or neuter. Please notify coders.") - character.change_gender(MALE) + message_admins("[key_name_admin(character)] has spawned with their gender as neuter. Please notify coders.") + character.change_gender(PLURAL) character.change_eye_color(e_colour, skip_icons = TRUE) character.original_eye_color = e_colour diff --git a/code/modules/client/preference/link_processing.dm b/code/modules/client/preference/link_processing.dm index b7c832a9952..76c8ac966f1 100644 --- a/code/modules/client/preference/link_processing.dm +++ b/code/modules/client/preference/link_processing.dm @@ -168,13 +168,13 @@ if(S.bodyflags & HAS_TAIL_MARKINGS) //Species with tail markings. active_character.m_colours["tail"] = rand_hex_color() if("underwear") - active_character.underwear = random_underwear(active_character.gender, active_character.species) + active_character.underwear = random_underwear(active_character.body_type, active_character.species) ShowChoices(user) if("undershirt") - active_character.undershirt = random_undershirt(active_character.gender, active_character.species) + active_character.undershirt = random_undershirt(active_character.body_type, active_character.species) ShowChoices(user) if("socks") - active_character.socks = random_socks(active_character.gender, active_character.species) + active_character.socks = random_socks(active_character.body_type, active_character.species) ShowChoices(user) if("eyes") active_character.e_colour = rand_hex_color() @@ -226,8 +226,6 @@ return if(prev_species != active_character.species) active_character.age = clamp(active_character.age, NS.min_age, NS.max_age) - if(NS.has_gender && active_character.gender == PLURAL) - active_character.gender = pick(MALE,FEMALE) var/datum/robolimb/robohead if(NS.bodyflags & ALL_RPARTS) var/head_model = "[!active_character.rlimb_data["head"] ? "Morpheus Cyberkinetics" : active_character.rlimb_data["head"]]" @@ -265,15 +263,15 @@ // Don't wear another species' underwear! var/datum/sprite_accessory/SA = GLOB.underwear_list[active_character.underwear] if(!SA || !(active_character.species in SA.species_allowed)) - active_character.underwear = random_underwear(active_character.gender, active_character.species) + active_character.underwear = random_underwear(active_character.body_type, active_character.species) SA = GLOB.undershirt_list[active_character.undershirt] if(!SA || !(active_character.species in SA.species_allowed)) - active_character.undershirt = random_undershirt(active_character.gender, active_character.species) + active_character.undershirt = random_undershirt(active_character.body_type, active_character.species) SA = GLOB.socks_list[active_character.socks] if(!SA || !(active_character.species in SA.species_allowed)) - active_character.socks = random_socks(active_character.gender, active_character.species) + active_character.socks = random_socks(active_character.body_type, active_character.species) //reset skin tone and colour if(NS.bodyflags & (HAS_SKIN_TONE|HAS_ICON_SKIN_TONE)) @@ -579,10 +577,6 @@ if(facialhairstyle == "Shaved") //Just in case. valid_facial_hairstyles += facialhairstyle continue - if(active_character.gender == MALE && SA.gender == FEMALE) - continue - if(active_character.gender == FEMALE && SA.gender == MALE) - continue if(S.bodyflags & ALL_RPARTS) //Species that can use prosthetic heads. var/head_model if(!active_character.rlimb_data["head"]) //Handle situations where the head is default. @@ -608,9 +602,10 @@ var/list/valid_underwear = list() for(var/underwear in GLOB.underwear_list) var/datum/sprite_accessory/SA = GLOB.underwear_list[underwear] - if(active_character.gender == MALE && SA.gender == FEMALE) + // soon... + if(active_character.body_type == MALE && SA.body_type == FEMALE) continue - if(active_character.gender == FEMALE && SA.gender == MALE) + if(active_character.body_type == FEMALE && SA.body_type == MALE) continue if(!(active_character.species in SA.species_allowed)) continue @@ -624,12 +619,12 @@ var/list/valid_undershirts = list() for(var/undershirt in GLOB.undershirt_list) var/datum/sprite_accessory/SA = GLOB.undershirt_list[undershirt] - if(active_character.gender == MALE && SA.gender == FEMALE) - continue - if(active_character.gender == FEMALE && SA.gender == MALE) - continue if(!(active_character.species in SA.species_allowed)) continue + if(active_character.body_type == MALE && SA.body_type == FEMALE) + continue + if(active_character.body_type == FEMALE && SA.body_type == MALE) + continue valid_undershirts[undershirt] = GLOB.undershirt_list[undershirt] sortTim(valid_undershirts, GLOBAL_PROC_REF(cmp_text_asc)) var/new_undershirt = tgui_input_list(user, "Choose your character's undershirt", "Character Preference", valid_undershirts) @@ -641,12 +636,12 @@ var/list/valid_sockstyles = list() for(var/sockstyle in GLOB.socks_list) var/datum/sprite_accessory/SA = GLOB.socks_list[sockstyle] - if(active_character.gender == MALE && SA.gender == FEMALE) - continue - if(active_character.gender == FEMALE && SA.gender == MALE) - continue if(!(active_character.species in SA.species_allowed)) continue + if(active_character.body_type == MALE && SA.body_type == FEMALE) + continue + if(active_character.body_type == FEMALE && SA.body_type == MALE) + continue valid_sockstyles[sockstyle] = GLOB.socks_list[sockstyle] sortTim(valid_sockstyles, GLOBAL_PROC_REF(cmp_text_asc)) var/new_socks = tgui_input_list(user, "Choose your character's socks", "Character Preference", valid_sockstyles) @@ -896,23 +891,25 @@ toggles ^= PREFTOGGLE_DONATOR_PUBLIC if("gender") - if(!S.has_gender) - var/newgender = tgui_input_list(user, "Who are you?", "Choose Gender", list("Male", "Female", "Genderless")) - if(!newgender) - return - switch(newgender) - if("Male") - active_character.gender = MALE - if("Female") - active_character.gender = FEMALE - if("Genderless") - active_character.gender = PLURAL - else - if(active_character.gender == MALE) - active_character.gender = FEMALE - else + var/newgender = tgui_input_list(user, "Who are you?", "Choose Gender", list("Male", "Female", "Genderless")) + if(!newgender) + return + switch(newgender) + if("Male") + active_character.gender = MALE - active_character.underwear = random_underwear(active_character.gender) + if("Female") + active_character.gender = FEMALE + if("Genderless") + active_character.gender = PLURAL + + if("body_type") + if(active_character.body_type == MALE) + active_character.body_type = FEMALE + else + active_character.body_type = MALE + + active_character.underwear = random_underwear(active_character.body_type) if("hear_adminhelps") sound ^= SOUND_ADMINHELP diff --git a/code/modules/client/preference/preferences.dm b/code/modules/client/preference/preferences.dm index eb36655a4f0..ad75383205c 100644 --- a/code/modules/client/preference/preferences.dm +++ b/code/modules/client/preference/preferences.dm @@ -195,11 +195,12 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts dat += "" dat += "
" dat += "

Identity

" - dat += "Gender: [active_character.gender == MALE ? "Male" : (active_character.gender == FEMALE ? "Female" : "Genderless")]" - dat += "
" dat += "Age: [active_character.age]
" dat += "Body: (®)
" dat += "Species: [active_character.species]
" + dat += "Gender: [active_character.gender == MALE ? "Male" : (active_character.gender == FEMALE ? "Female" : "Genderless")]
" + dat += "Body Type: [active_character.body_type == MALE ? "Masculine" : "Feminine"]" + dat += "
" if(active_character.species == "Vox") // Purge these bastards dat += "N2 Tank: [active_character.speciesprefs ? "Large N2 Tank" : "Specialized N2 Tank"]
" if(active_character.species == "Plasmaman") diff --git a/code/modules/mob/living/carbon/human/appearance.dm b/code/modules/mob/living/carbon/human/appearance.dm index e9e304b4a4b..0d27033de48 100644 --- a/code/modules/mob/living/carbon/human/appearance.dm +++ b/code/modules/mob/living/carbon/human/appearance.dm @@ -4,27 +4,28 @@ AC.ui_interact(user) /mob/living/carbon/human/proc/change_gender(new_gender, update_dna = TRUE) - var/obj/item/organ/external/head/H = bodyparts_by_name["head"] - if(gender == new_gender || (gender == PLURAL && !dna.species.has_gender)) + if(gender == new_gender) return gender = new_gender - if(istype(H)) - var/datum/sprite_accessory/hair/current_hair = GLOB.hair_styles_full_list[H.h_style] - if(current_hair.gender != NEUTER && current_hair.gender != gender) - reset_head_hair() - - var/datum/sprite_accessory/hair/current_fhair = GLOB.facial_hair_styles_list[H.f_style] - if(current_fhair.gender != NEUTER && current_fhair.gender != gender) - reset_facial_hair() - if(update_dna) update_dna() sync_organ_dna(assimilate = FALSE) update_body() return TRUE +/mob/living/carbon/human/proc/change_body_type(new_body, update_dna = TRUE) + if(!new_body || new_body == body_type) + return + + body_type = new_body + + if(update_dna) + update_dna() + sync_organ_dna(FALSE) + update_body(TRUE) + /mob/living/carbon/human/proc/change_hair(hair_style, fluff) var/obj/item/organ/external/head/H = get_organ("head") @@ -373,8 +374,6 @@ if(hairstyle == "Bald") //Just in case. valid_hairstyles += hairstyle continue - if((H.gender == MALE && S.gender == FEMALE) || (H.gender == FEMALE && S.gender == MALE)) - continue if(H.dna.species.bodyflags & ALL_RPARTS) //If the user is a species who can have a robotic head... var/datum/robolimb/robohead = GLOB.all_robolimbs[H.model] if((H.dna.species.name in S.species_allowed) && robohead.is_monitor && ((S.models_allowed && (robohead.company in S.models_allowed)) || !S.models_allowed)) //If this is a hair style native to the user's species, check to see if they have a head with an ipc-style screen and that the head's company is in the screen style's allowed models list. @@ -401,8 +400,6 @@ if(facialhairstyle == "Shaved") //Just in case. valid_facial_hairstyles += facialhairstyle continue - if((H.gender == MALE && S.gender == FEMALE) || (H.gender == FEMALE && S.gender == MALE)) - continue if(H.dna.species.bodyflags & ALL_RPARTS) //If the user is a species who can have a robotic head... var/datum/robolimb/robohead = GLOB.all_robolimbs[H.model] if(H.dna.species.name in S.species_allowed) //If this is a facial hair style native to the user's species... diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 56c1af2531b..5cf1b5218fc 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -32,6 +32,8 @@ var/height = "average height" /// Players physique (even MORE fluff) var/physique = "average" + /// The body type associated with the body + var/body_type = MALE var/underwear = "Nude" //Which underwear the player wants var/undershirt = "Nude" //Which undershirt the player wants diff --git a/code/modules/mob/living/carbon/human/human_mob.dm b/code/modules/mob/living/carbon/human/human_mob.dm index 7296e27c278..6938a3e3451 100644 --- a/code/modules/mob/living/carbon/human/human_mob.dm +++ b/code/modules/mob/living/carbon/human/human_mob.dm @@ -1087,9 +1087,6 @@ if(oldspecies.default_language) remove_language(oldspecies.default_language) - if(gender == PLURAL && oldspecies.has_gender) - change_gender(pick(MALE, FEMALE)) - oldspecies.handle_dna(src, TRUE) // Remove any mutations that belong to the old species oldspecies.on_species_loss(src) diff --git a/code/modules/mob/living/carbon/human/species/_species.dm b/code/modules/mob/living/carbon/human/species/_species.dm index 483c58b8ae8..4a9fcf2b651 100644 --- a/code/modules/mob/living/carbon/human/species/_species.dm +++ b/code/modules/mob/living/carbon/human/species/_species.dm @@ -118,7 +118,6 @@ var/forced_heartattack = FALSE //Some species have blood, but we still want them to have heart attacks var/dies_at_threshold = FALSE // Do they die or get knocked out at specific thresholds, or do they go through complex crit? var/can_revive_by_healing // Determines whether or not this species can be revived by simply healing them - var/has_gender = TRUE var/blacklisted = FALSE var/dangerous_existence = FALSE diff --git a/code/modules/mob/living/carbon/human/species/diona_species.dm b/code/modules/mob/living/carbon/human/species/diona_species.dm index 65ad87eadda..8fd6d96e22d 100644 --- a/code/modules/mob/living/carbon/human/species/diona_species.dm +++ b/code/modules/mob/living/carbon/human/species/diona_species.dm @@ -22,7 +22,6 @@ inherent_biotypes = MOB_ORGANIC | MOB_HUMANOID | MOB_PLANT clothing_flags = HAS_SOCKS default_hair_colour = "#000000" - has_gender = FALSE bodyflags = SHAVED dietflags = DIET_HERB //Diona regenerate nutrition in light and water, no diet necessary, but if they must, they eat other plants *scream taste_sensitivity = TASTE_SENSITIVITY_DULL diff --git a/code/modules/mob/living/carbon/human/species/drask.dm b/code/modules/mob/living/carbon/human/species/drask.dm index a5586270a6a..6d612d98e99 100644 --- a/code/modules/mob/living/carbon/human/species/drask.dm +++ b/code/modules/mob/living/carbon/human/species/drask.dm @@ -32,7 +32,6 @@ species_traits = list(LIPS, NO_HAIR) clothing_flags = HAS_UNDERWEAR | HAS_UNDERSHIRT bodyflags = HAS_SKIN_TONE | HAS_BODY_MARKINGS | BALD | SHAVED - has_gender = FALSE dietflags = DIET_OMNI cold_level_1 = -1 //Default 260 - Lower is better diff --git a/code/modules/mob/living/carbon/human/species/grey.dm b/code/modules/mob/living/carbon/human/species/grey.dm index 21de51a0324..498b739e631 100644 --- a/code/modules/mob/living/carbon/human/species/grey.dm +++ b/code/modules/mob/living/carbon/human/species/grey.dm @@ -26,7 +26,6 @@ clothing_flags = HAS_UNDERWEAR | HAS_UNDERSHIRT | HAS_SOCKS bodyflags = HAS_BODY_MARKINGS | HAS_BODYACC_COLOR | SHAVED | BALD dietflags = DIET_HERB - has_gender = FALSE reagent_tag = PROCESS_ORG flesh_color = "#a598ad" blood_color = "#A200FF" diff --git a/code/modules/mob/living/carbon/human/species/machine.dm b/code/modules/mob/living/carbon/human/species/machine.dm index 924ca49d876..fadcdf582df 100644 --- a/code/modules/mob/living/carbon/human/species/machine.dm +++ b/code/modules/mob/living/carbon/human/species/machine.dm @@ -34,7 +34,6 @@ default_hair = "Blue IPC Screen" dies_at_threshold = TRUE can_revive_by_healing = 1 - has_gender = FALSE reagent_tag = PROCESS_SYN male_scream_sound = 'sound/goonstation/voice/robot_scream.ogg' female_scream_sound = 'sound/goonstation/voice/robot_scream.ogg' diff --git a/code/modules/mob/living/carbon/human/species/vox.dm b/code/modules/mob/living/carbon/human/species/vox.dm index 853819c6bcd..c300570b0dd 100644 --- a/code/modules/mob/living/carbon/human/species/vox.dm +++ b/code/modules/mob/living/carbon/human/species/vox.dm @@ -30,7 +30,6 @@ flesh_color = "#808D11" //Default styles for created mobs. default_hair = "Short Vox Quills" - has_gender = FALSE default_hair_colour = "#614f19" //R: 97, G: 79, B: 25 butt_sprite = "vox" diff --git a/code/modules/mob/new_player/sprite_accessories/human/human_facial_hair.dm b/code/modules/mob/new_player/sprite_accessories/human/human_facial_hair.dm index f70bf5d5b42..2d4aea1d857 100644 --- a/code/modules/mob/new_player/sprite_accessories/human/human_facial_hair.dm +++ b/code/modules/mob/new_player/sprite_accessories/human/human_facial_hair.dm @@ -10,7 +10,6 @@ icon = 'icons/mob/human_face.dmi' // Special case, use the bald icon in human face name = "Shaved" icon_state = "bald" - gender = NEUTER species_allowed = list("Human", "Unathi", "Tajaran", "Skrell", "Vox", "Diona", "Kidan", "Greys", "Vulpkanin", "Slime People") /datum/sprite_accessory/facial_hair/watson diff --git a/code/modules/mob/new_player/sprite_accessories/human/human_hair.dm b/code/modules/mob/new_player/sprite_accessories/human/human_hair.dm index 9cdfb017e9b..c62273ffdb1 100644 --- a/code/modules/mob/new_player/sprite_accessories/human/human_hair.dm +++ b/code/modules/mob/new_player/sprite_accessories/human/human_hair.dm @@ -563,7 +563,6 @@ /datum/sprite_accessory/hair/joestar name = "Joestar" icon_state = "joestar" - gender = MALE species_allowed = list("Human", "Slime People", "Unathi", "Tajaran", "Vulpkanin") /datum/sprite_accessory/hair/nitori diff --git a/code/modules/mob/new_player/sprite_accessories/skrell/skrell_face.dm b/code/modules/mob/new_player/sprite_accessories/skrell/skrell_face.dm index 76cbbc7284c..cdb4c487806 100644 --- a/code/modules/mob/new_player/sprite_accessories/skrell/skrell_face.dm +++ b/code/modules/mob/new_player/sprite_accessories/skrell/skrell_face.dm @@ -5,12 +5,10 @@ /datum/sprite_accessory/hair/skrell/skr_tentacle_m name = "Skrell Male Tentacles" icon_state = "male" - gender = MALE /datum/sprite_accessory/hair/skrell/skr_tentacle_f name = "Skrell Female Tentacles" icon_state = "female" - gender = FEMALE /datum/sprite_accessory/hair/skrell/skr_tentacleslong name = "Long Skrell Tentacles" @@ -23,39 +21,33 @@ /datum/sprite_accessory/hair/skrell/skr_gold_m name = "Gold plated Skrell Male Tentacles" icon_state = "male" - gender = MALE secondary_theme = "gold" no_sec_colour = 1 /datum/sprite_accessory/hair/skrell/skr_gold_f name = "Gold chained Skrell Female Tentacles" icon_state = "female" - gender = FEMALE secondary_theme = "gold" no_sec_colour = 1 /datum/sprite_accessory/hair/skrell/skr_clothtentacle_m name = "Cloth draped Skrell Male Tentacles" icon_state = "male" - gender = MALE secondary_theme = "cloth" /datum/sprite_accessory/hair/skrell/skr_clothtentacle_f name = "Cloth draped Skrell Female Tentacles" icon_state = "female" - gender = FEMALE secondary_theme = "cloth" /datum/sprite_accessory/hair/skrell/skr_gclothtentacle_m name = "Ombre Dye, Skrell Male Tentacles" icon_state = "male" - gender = MALE secondary_theme = "gradient" /datum/sprite_accessory/hair/skrell/skr_gclothtentacle_f name = "Ombre Dye, Skrell Female Tentacles" icon_state = "female" - gender = FEMALE secondary_theme = "gradient" /datum/sprite_accessory/hair/skrell/skr_gclothtentacleslong @@ -71,14 +63,12 @@ /datum/sprite_accessory/hair/skrell/skr_diablacktentacle_m name = "Black headress Skrell Male Tentacles" icon_state = "male" - gender = MALE secondary_theme = "blackdia" no_sec_colour = 1 /datum/sprite_accessory/hair/skrell/skr_diablacktentacle_f name = "Black headress Skrell Female Tentacles" icon_state = "female" - gender = FEMALE secondary_theme = "blackdia" no_sec_colour = 1 @@ -92,14 +82,12 @@ /datum/sprite_accessory/hair/skrell/skr_diagoldtentacle_m name = "Gold headress Skrell Male Tentacles" icon_state = "male" - gender = MALE secondary_theme = "golddia" no_sec_colour = 1 /datum/sprite_accessory/hair/skrell/skr_diagoldtentacle_f name = "Gold headress Skrell Female Tentacles" icon_state = "female" - gender = FEMALE secondary_theme = "golddia" no_sec_colour = 1 @@ -112,14 +100,12 @@ /datum/sprite_accessory/hair/skrell/skr_diasilvertentacle_m name = "Silver headress Skrell Male Tentacles" icon_state = "male" - gender = MALE secondary_theme = "silvdia" no_sec_colour = 1 /datum/sprite_accessory/hair/skrell/skr_diasilvertentacle_f name = "Silver headress Skrell Female Tentacles" icon_state = "female" - gender = FEMALE secondary_theme = "silvdia" no_sec_colour = 1 @@ -132,14 +118,12 @@ /datum/sprite_accessory/hair/skrell/skr_festivetentacle_m name = "Festive headress Skrell Male Tentacles" icon_state = "male" - gender = MALE secondary_theme = "fest" no_sec_colour = 1 /datum/sprite_accessory/hair/skrell/skr_festivetentacle_f name = "Festive headress Skrell Female Tentacles" icon_state = "female" - gender = FEMALE secondary_theme = "fest" no_sec_colour = 1 diff --git a/code/modules/mob/new_player/sprite_accessories/sprite_accessories.dm b/code/modules/mob/new_player/sprite_accessories/sprite_accessories.dm index 2610cd828c5..41895d77952 100644 --- a/code/modules/mob/new_player/sprite_accessories/sprite_accessories.dm +++ b/code/modules/mob/new_player/sprite_accessories/sprite_accessories.dm @@ -18,10 +18,14 @@ */ /proc/init_sprite_accessory_subtypes(prototype, list/L, list/male, list/female, list/full_list) - if(!istype(L)) L = list() - if(!istype(male)) male = list() - if(!istype(female)) female = list() - if(!istype(full_list)) full_list = list() + if(!istype(L)) + L = list() + if(!istype(male)) + male = list() + if(!istype(female)) + female = list() + if(!istype(full_list)) + full_list = list() for(var/path in subtypesof(prototype)) var/datum/sprite_accessory/D = new path() @@ -33,9 +37,11 @@ L[D.name] = D full_list[D.name] = D - switch(D.gender) - if(MALE) male[D.name] = D - if(FEMALE) female[D.name] = D + switch(D.body_type) + if(MALE) + male[D.name] = D + if(FEMALE) + female[D.name] = D else male[D.name] = D female[D.name] = D @@ -45,7 +51,7 @@ var/icon //the icon file the accessory is located in var/icon_state //the icon_state of the accessory var/name //the preview name of the accessory - var/gender = NEUTER //Determines if the accessory will be skipped or included in random hair generations + var/body_type = NEUTER //Determines if the accessory will be skipped or included in random hair generations // Restrict some styles to specific species var/list/species_allowed = list("Human", "Slime People") @@ -74,7 +80,6 @@ glasses_over = 1 /datum/sprite_accessory/facial_hair - gender = MALE // barf (unless you're a dorf, dorfs dig chix /w beards :P) icon = 'icons/mob/sprite_accessories/human/human_facial_hair.dmi' var/over_hair @@ -174,7 +179,6 @@ "Grey" = 'icons/mob/clothing/species/grey/underwear.dmi', "Kidan" = 'icons/mob/clothing/species/kidan/underwear.dmi' ) - gender = NEUTER /datum/sprite_accessory/underwear/nude name = "Nude" @@ -182,7 +186,7 @@ species_allowed = list("Human", "Unathi", "Diona", "Vulpkanin", "Tajaran", "Kidan", "Grey", "Plasmaman", "Machine", "Skrell", "Slime People", "Skeleton", "Drask", "Vox", "Nian") /datum/sprite_accessory/underwear/male - gender = MALE + body_type = MALE /datum/sprite_accessory/underwear/male/male_white name = "Mens White" @@ -233,7 +237,7 @@ icon_state = "male_mankini" /datum/sprite_accessory/underwear/female - gender = FEMALE + body_type = FEMALE /datum/sprite_accessory/underwear/female/female_red name = "Ladies Red" @@ -305,7 +309,6 @@ "Grey" = 'icons/mob/clothing/species/grey/underwear.dmi', "Kidan" = 'icons/mob/clothing/species/kidan/underwear.dmi' ) - gender = NEUTER /datum/sprite_accessory/undershirt/nude name = "Nude" @@ -494,17 +497,17 @@ /datum/sprite_accessory/undershirt/tank_redtop name = "Red Crop-Top" icon_state = "tank_redtop" - gender = FEMALE + body_type = FEMALE /datum/sprite_accessory/undershirt/tank_whitetop name = "White Crop-Top" icon_state = "tank_whitetop" - gender = FEMALE + body_type = FEMALE /datum/sprite_accessory/undershirt/tank_midriff name = "White Mid Tank-Top" icon_state = "tank_midriff" - gender = FEMALE + body_type = FEMALE /datum/sprite_accessory/undershirt/tank_white name = "White Tank-Top" @@ -547,7 +550,6 @@ "Nian" = 'icons/mob/clothing/species/nian/underwear.dmi' ) - gender = NEUTER /datum/sprite_accessory/socks/nude name = "Nude" @@ -581,7 +583,7 @@ /datum/sprite_accessory/socks/thin_knee name = "Knee-high Thin" icon_state = "thin_knee" - gender = FEMALE + body_type = FEMALE /datum/sprite_accessory/socks/striped_norm name = "Normal Striped" @@ -606,7 +608,7 @@ /datum/sprite_accessory/socks/thin_thigh name = "Thigh-high Thin" icon_state = "thin_thigh" - gender = FEMALE + body_type = FEMALE /datum/sprite_accessory/socks/striped_thigh name = "Thigh-high Striped" @@ -619,7 +621,7 @@ /datum/sprite_accessory/socks/pantyhose name = "Pantyhose" icon_state = "pantyhose" - gender = FEMALE + body_type = FEMALE /datum/sprite_accessory/socks/black_fishnet name = "Black Fishnet" diff --git a/code/modules/mob/new_player/sprite_accessories/unathi/unathi_facial_hair.dm b/code/modules/mob/new_player/sprite_accessories/unathi/unathi_facial_hair.dm index 5fcf93aa770..c43ea89f204 100644 --- a/code/modules/mob/new_player/sprite_accessories/unathi/unathi_facial_hair.dm +++ b/code/modules/mob/new_player/sprite_accessories/unathi/unathi_facial_hair.dm @@ -1,7 +1,6 @@ /datum/sprite_accessory/facial_hair/unathi icon = 'icons/mob/sprite_accessories/unathi/unathi_facial_hair.dmi' species_allowed = list("Unathi") - gender = NEUTER over_hair = 1 /datum/sprite_accessory/facial_hair/unathi/una_spines_long diff --git a/code/modules/mob/new_player/sprite_accessories/vox/vox_facial_hair.dm b/code/modules/mob/new_player/sprite_accessories/vox/vox_facial_hair.dm index 2f292e443e3..56381bbbf6c 100644 --- a/code/modules/mob/new_player/sprite_accessories/vox/vox_facial_hair.dm +++ b/code/modules/mob/new_player/sprite_accessories/vox/vox_facial_hair.dm @@ -1,7 +1,6 @@ /datum/sprite_accessory/facial_hair/vox icon = 'icons/mob/sprite_accessories/vox/vox_facial_hair.dmi' species_allowed = list("Vox") - gender = NEUTER /datum/sprite_accessory/facial_hair/vox/vox_colonel name = "Vox Colonel Beard" diff --git a/code/modules/mob/new_player/sprite_accessories/vulpkanin/vulpkanin_facial_hair.dm b/code/modules/mob/new_player/sprite_accessories/vulpkanin/vulpkanin_facial_hair.dm index fca910b401a..419aa7c2e76 100644 --- a/code/modules/mob/new_player/sprite_accessories/vulpkanin/vulpkanin_facial_hair.dm +++ b/code/modules/mob/new_player/sprite_accessories/vulpkanin/vulpkanin_facial_hair.dm @@ -1,7 +1,6 @@ /datum/sprite_accessory/facial_hair/vulpkanin icon = 'icons/mob/sprite_accessories/vulpkanin/vulpkanin_facial_hair.dmi' species_allowed = list("Vulpkanin") - gender = NEUTER /datum/sprite_accessory/facial_hair/vulpkanin/vulp_earfluff name = "Vulpkanin Earfluff" diff --git a/code/modules/mob/new_player/sprite_accessories/vulpkanin/vulpkanin_hair.dm b/code/modules/mob/new_player/sprite_accessories/vulpkanin/vulpkanin_hair.dm index b32f2b4153a..27ca4286943 100644 --- a/code/modules/mob/new_player/sprite_accessories/vulpkanin/vulpkanin_hair.dm +++ b/code/modules/mob/new_player/sprite_accessories/vulpkanin/vulpkanin_hair.dm @@ -84,7 +84,6 @@ /datum/sprite_accessory/hair/vulpkanin/vulp_hair_raine name = "Raine" icon_state = "raine" - gender = FEMALE /datum/sprite_accessory/hair/vulpkanin/vulp_hair_jeremy name = "Jeremy" diff --git a/code/modules/surgery/organs/organ_icon.dm b/code/modules/surgery/organs/organ_icon.dm index 6d4c69f1fec..58a50911591 100644 --- a/code/modules/surgery/organs/organ_icon.dm +++ b/code/modules/surgery/organs/organ_icon.dm @@ -151,7 +151,7 @@ return mob_icon //Don't need to blend the above into this as it's handled in human/update_icons(). The overlays are for rendering stuff on disembodied heads. /obj/item/organ/external/proc/get_icon_state(skeletal) - var/gender + var/body var/icon_file var/new_icon_state if(!dna) @@ -159,18 +159,17 @@ new_icon_state = "[icon_name][gendered_icon ? "_f" : ""]" else if(gendered_icon) - switch(dna.GetUITriState(DNA_UI_GENDER)) + switch(dna.GetUITriState(DNA_UI_BODY_TYPE)) if(DNA_GENDER_FEMALE) - gender = "f" - if(DNA_GENDER_MALE) - gender = "m" + body = "f" else - gender = "f" //Default to "f" (per line 162). Using a pick("m", "f") will make different body parts different genders for the same character. + body = "m" + if(limb_name == "head") var/obj/item/organ/external/head/head_organ = src head_organ.handle_alt_icon() - new_icon_state = "[icon_name][gender ? "_[gender]" : ""]" + new_icon_state = "[icon_name][body ? "_[body]" : ""]" if(skeletal) icon_file = 'icons/mob/human_races/r_skeleton.dmi' diff --git a/code/modules/tgui/modules/appearance_changer.dm b/code/modules/tgui/modules/appearance_changer.dm index 49791db04e8..afc7edd4396 100644 --- a/code/modules/tgui/modules/appearance_changer.dm +++ b/code/modules/tgui/modules/appearance_changer.dm @@ -214,7 +214,6 @@ data["specimen"] = owner.dna.species.name data["gender"] = owner.gender - data["has_gender"] = owner.dna.species.has_gender data["change_race"] = can_change(APPEARANCE_RACE) if(data["change_race"]) var/list/species = list() diff --git a/config/example/config.toml b/config/example/config.toml index 0502825cb37..fedba7ae4a3 100644 --- a/config/example/config.toml +++ b/config/example/config.toml @@ -145,7 +145,7 @@ ipc_screens = [ # Enable/disable the database on a whole sql_enabled = false # SQL version. If this is a mismatch, round start will be delayed -sql_version = 54 +sql_version = 55 # SQL server address. Can be an IP or DNS name sql_address = "127.0.0.1" # SQL server port diff --git a/tgui/packages/tgui/interfaces/AppearanceChanger.js b/tgui/packages/tgui/interfaces/AppearanceChanger.js index fedcce5f540..3d1805ce543 100644 --- a/tgui/packages/tgui/interfaces/AppearanceChanger.js +++ b/tgui/packages/tgui/interfaces/AppearanceChanger.js @@ -10,7 +10,6 @@ export const AppearanceChanger = (props, context) => { specimen, change_gender, gender, - has_gender, change_eye_color, change_skin_tone, change_skin_color, @@ -95,13 +94,13 @@ export const AppearanceChanger = (props, context) => { selected={gender === 'female'} onClick={() => act('gender', { gender: 'female' })} /> - {!has_gender && ( + {