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 =