From 6d2bab909c26c3734e1c5e235bd809da0b894c55 Mon Sep 17 00:00:00 2001 From: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Date: Tue, 11 Mar 2025 13:32:59 -0500 Subject: [PATCH] Fixes the prefs dummy not updating for species features / Bald quirk prefs QoL (#89833) ## About The Pull Request ![image](https://github.com/user-attachments/assets/b03901a2-1c2d-4793-9591-abe824a90fd5) Fixes #89768 Fixes #89769 - Fixes the prefs menu not updating mobs Organs are imprinted on insert, and SSwardrobe didn't reset this imprinting status when taking out items. Weirdly in the past (testing old commits) items withdrawn DID reset imprinting status - or maybe they never set it in the first place? - Lots of prefs now respect features `is_accessible` is used when checking many features rather than the prefs menu checking itself in the UI - Bald quirk QOL Just handy stuff like showing the wig in the prefs preview, pre-starting with your hat attached ## Changelog :cl: Melbert fix: Preference dummy now properly updates when changing some species features qol: If you have the bald quirk selected, the wig shows up on the preference dummy qol: If you have the bald quirk selected, and your role starts with a hat, the hat will start attached to your wig /:cl: --- code/datums/quirks/neutral_quirks/bald.dm | 41 +++++++++++++++++-- .../modules/client/preferences/_preference.dm | 26 +++++++----- .../preferences/species_features/basic.dm | 6 +++ .../preferences/species_features/ethereal.dm | 4 ++ .../preferences/species_features/lizard.dm | 3 ++ .../preferences/species_features/moth.dm | 2 + .../preferences/species_features/pod.dm | 1 + code/modules/surgery/organs/_organ.dm | 1 + .../CharacterPreferences/MainPage.tsx | 10 +---- 9 files changed, 71 insertions(+), 23 deletions(-) diff --git a/code/datums/quirks/neutral_quirks/bald.dm b/code/datums/quirks/neutral_quirks/bald.dm index 2844b790ddf..f08f2e8cc13 100644 --- a/code/datums/quirks/neutral_quirks/bald.dm +++ b/code/datums/quirks/neutral_quirks/bald.dm @@ -4,6 +4,7 @@ icon = FA_ICON_EGG value = 0 mob_trait = TRAIT_BALD + quirk_flags = QUIRK_HUMAN_ONLY | QUIRK_CHANGES_APPEARANCE gain_text = span_notice("Your head is as smooth as can be, it's terrible.") lose_text = span_notice("Your head itches, could it be... growing hair?!") medical_record_text = "Patient starkly refused to take off headwear during examination." @@ -27,13 +28,47 @@ baldie_wig.update_appearance() - give_item_to_holder(baldie_wig, list(LOCATION_HEAD = ITEM_SLOT_HEAD, LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) + give_item_to_holder(baldie_wig, list(LOCATION_HEAD = ITEM_SLOT_HEAD, LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS), notify_player = FALSE) + +/datum/quirk/item_quirk/bald/give_item_to_holder(obj/item/quirk_item, list/valid_slots, flavour_text = null, default_location = "at your feet", notify_player = TRUE) + var/any_head = FALSE + for(var/place_loc in valid_slots) + if(valid_slots[place_loc] & ITEM_SLOT_HEAD) + any_head = TRUE + break + + // guess we don't care + if(!any_head) + return ..() + + if(ispath(quirk_item, /obj/item)) + quirk_item = new quirk_item(get_turf(quirk_holder)) + + // check if their job / loadout has a hat + var/obj/item/clothing/existing = quirk_holder.get_item_by_slot(ITEM_SLOT_HEAD) + // no hat -> try equipping like normal (via parent) + if(!istype(existing) || (existing.clothing_flags & STACKABLE_HELMET_EXEMPT)) + return ..() + // try removing the existing hat. if fail -> try equipping like normal + if(!quirk_holder.temporarilyRemoveItemFromInventory(existing)) + return ..() + // try to place the wig. if fail -> try equipping like normal + if(!quirk_holder.equip_to_slot_if_possible(quirk_item, ITEM_SLOT_HEAD, qdel_on_fail = FALSE, indirect_action = TRUE)) + return ..() + + // now that the wig is properly equipped, try attaching the old job / loadout hat via the component + var/datum/component/hat_stabilizer/comp = quirk_item.GetComponent(/datum/component/hat_stabilizer) + // nvm i guess someone removed that feature (futureproofed comment) + if(isnull(comp)) + return ..() + + comp.attach_hat(existing) /datum/quirk/item_quirk/bald/remove() . = ..() var/mob/living/carbon/human/human_holder = quirk_holder - human_holder.hairstyle = old_hair - human_holder.update_body_parts() + if(human_holder.hairstyle == "Bald" && old_hair != "Bald") + human_holder.set_hairstyle(old_hair, update = TRUE) UnregisterSignal(human_holder, list(COMSIG_CARBON_EQUIP_HAT, COMSIG_CARBON_UNEQUIP_HAT)) human_holder.clear_mood_event("bad_hair_day") diff --git a/code/modules/client/preferences/_preference.dm b/code/modules/client/preferences/_preference.dm index 3b4a688ebf3..1d06060d91f 100644 --- a/code/modules/client/preferences/_preference.dm +++ b/code/modules/client/preferences/_preference.dm @@ -325,23 +325,27 @@ GLOBAL_LIST_INIT(preference_entries_by_key, init_preference_entries_by_key()) return null +/// Checks the species currently selected by the passed preferences object to see if it has this preference's key as a feature. +/datum/preference/proc/current_species_has_savekey(datum/preferences/preferences) + var/species_type = preferences.read_preference(/datum/preference/choiced/species) + var/datum/species/species = GLOB.species_prototypes[species_type] + return (savefile_key in species.get_features()) + +/// Checks if this preference is relevant and thus visible to the passed preferences object. +/datum/preference/proc/has_relevant_feature(datum/preferences/preferences) + if(isnull(relevant_inherent_trait) && isnull(relevant_external_organ) && isnull(relevant_head_flag) && isnull(relevant_body_markings)) + return TRUE + + return current_species_has_savekey(preferences) + /// Returns whether or not this preference is accessible. /// If FALSE, will not show in the UI and will not be editable (by update_preference). /datum/preference/proc/is_accessible(datum/preferences/preferences) SHOULD_CALL_PARENT(TRUE) SHOULD_NOT_SLEEP(TRUE) - if ( \ - !isnull(relevant_inherent_trait) \ - || !isnull(relevant_external_organ) \ - || !isnull(relevant_head_flag) \ - || !isnull(relevant_body_markings) \ - ) - var/species_type = preferences.read_preference(/datum/preference/choiced/species) - - var/datum/species/species = GLOB.species_prototypes[species_type] - if (!(savefile_key in species.get_features())) - return FALSE + if (!has_relevant_feature(preferences)) + return FALSE if (!should_show_on_page(preferences.current_window)) return FALSE diff --git a/code/modules/client/preferences/species_features/basic.dm b/code/modules/client/preferences/species_features/basic.dm index 260848d8511..876d3a3c45d 100644 --- a/code/modules/client/preferences/species_features/basic.dm +++ b/code/modules/client/preferences/species_features/basic.dm @@ -143,6 +143,9 @@ category = PREFERENCE_CATEGORY_SUPPLEMENTAL_FEATURES relevant_head_flag = HEAD_HAIR +/datum/preference/color/hair_color/has_relevant_feature(datum/preferences/preferences) + return ..() || (/datum/quirk/item_quirk/bald::name in preferences.all_quirks) + /datum/preference/color/hair_color/apply_to_human(mob/living/carbon/human/target, value) target.set_haircolor(value, update = FALSE) @@ -158,6 +161,9 @@ should_generate_icons = TRUE relevant_head_flag = HEAD_HAIR +/datum/preference/choiced/hairstyle/has_relevant_feature(datum/preferences/preferences) + return ..() || (/datum/quirk/item_quirk/bald::name in preferences.all_quirks) + /datum/preference/choiced/hairstyle/init_possible_values() return assoc_to_keys_features(SSaccessories.hairstyles_list) diff --git a/code/modules/client/preferences/species_features/ethereal.dm b/code/modules/client/preferences/species_features/ethereal.dm index 60117d3cd98..244068bc8a9 100644 --- a/code/modules/client/preferences/species_features/ethereal.dm +++ b/code/modules/client/preferences/species_features/ethereal.dm @@ -5,6 +5,10 @@ main_feature_name = "Ethereal color" should_generate_icons = TRUE +/datum/preference/choiced/ethereal_color/has_relevant_feature(datum/preferences/preferences) + // Skips checks for relevant_organ, relevant trait etc. because ethereal color is tied directly to species (atm) + return current_species_has_savekey(preferences) + /datum/preference/choiced/ethereal_color/init_possible_values() return assoc_to_keys(GLOB.color_list_ethereal) diff --git a/code/modules/client/preferences/species_features/lizard.dm b/code/modules/client/preferences/species_features/lizard.dm index f1e3e43660a..18f580ac6e8 100644 --- a/code/modules/client/preferences/species_features/lizard.dm +++ b/code/modules/client/preferences/species_features/lizard.dm @@ -63,6 +63,7 @@ category = PREFERENCE_CATEGORY_FEATURES main_feature_name = "Frills" should_generate_icons = TRUE + relevant_external_organ = /obj/item/organ/frills /datum/preference/choiced/lizard_frills/init_possible_values() return assoc_to_keys_features(SSaccessories.frills_list) @@ -79,6 +80,7 @@ category = PREFERENCE_CATEGORY_FEATURES main_feature_name = "Horns" should_generate_icons = TRUE + relevant_external_organ = /obj/item/organ/horns /datum/preference/choiced/lizard_horns/init_possible_values() return assoc_to_keys_features(SSaccessories.horns_list) @@ -134,6 +136,7 @@ category = PREFERENCE_CATEGORY_FEATURES main_feature_name = "Snout" should_generate_icons = TRUE + relevant_external_organ = /obj/item/organ/snout /datum/preference/choiced/lizard_snout/init_possible_values() return assoc_to_keys_features(SSaccessories.snouts_list) diff --git a/code/modules/client/preferences/species_features/moth.dm b/code/modules/client/preferences/species_features/moth.dm index 7a9031b98ba..a1340539ed6 100644 --- a/code/modules/client/preferences/species_features/moth.dm +++ b/code/modules/client/preferences/species_features/moth.dm @@ -4,6 +4,7 @@ category = PREFERENCE_CATEGORY_FEATURES main_feature_name = "Antennae" should_generate_icons = TRUE + relevant_external_organ = /obj/item/organ/antennae /datum/preference/choiced/moth_antennae/init_possible_values() return assoc_to_keys_features(SSaccessories.moth_antennae_list) @@ -84,6 +85,7 @@ category = PREFERENCE_CATEGORY_FEATURES main_feature_name = "Moth wings" should_generate_icons = TRUE + relevant_external_organ = /obj/item/organ/wings/moth /datum/preference/choiced/moth_wings/init_possible_values() return assoc_to_keys_features(SSaccessories.moth_wings_list) diff --git a/code/modules/client/preferences/species_features/pod.dm b/code/modules/client/preferences/species_features/pod.dm index 733cfb568f2..2515d610cd7 100644 --- a/code/modules/client/preferences/species_features/pod.dm +++ b/code/modules/client/preferences/species_features/pod.dm @@ -4,6 +4,7 @@ category = PREFERENCE_CATEGORY_FEATURES main_feature_name = "Hairstyle" should_generate_icons = TRUE + relevant_external_organ = /obj/item/organ/pod_hair /datum/preference/choiced/pod_hair/init_possible_values() return assoc_to_keys_features(SSaccessories.pod_hair_list) diff --git a/code/modules/surgery/organs/_organ.dm b/code/modules/surgery/organs/_organ.dm index 66c84a8776f..edd46d33ed5 100644 --- a/code/modules/surgery/organs/_organ.dm +++ b/code/modules/surgery/organs/_organ.dm @@ -203,6 +203,7 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) ///Used as callbacks by object pooling /obj/item/organ/proc/exit_wardrobe() START_PROCESSING(SSobj, src) + bodypart_overlay?.imprint_on_next_insertion = TRUE //See above /obj/item/organ/proc/enter_wardrobe() diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/MainPage.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/MainPage.tsx index 250e90839fc..14d21a352c2 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/MainPage.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferences/MainPage.tsx @@ -512,15 +512,7 @@ export function MainPage(props: MainPageProps) { const mainFeatures = [ ...Object.entries(data.character_preferences.clothing), - ...Object.entries(data.character_preferences.features).filter( - ([featureName]) => { - if (!currentSpeciesData) { - return false; - } - - return currentSpeciesData.enabled_features.indexOf(featureName) !== -1; - }, - ), + ...Object.entries(data.character_preferences.features), ]; const randomBodyEnabled =