From ed2f017923eefacba18d2a6f83324e93ed117dfc Mon Sep 17 00:00:00 2001 From: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Date: Thu, 15 Aug 2024 16:28:02 -0500 Subject: [PATCH] Digitigrade clothing sprites (feat. GAGS and 0 sprite bloat) (#85406) ## About The Pull Request Use GAGS to auto-generate digitgrade leg sprites based off of 1 basic template + color sampling. Icons are cached relatively aggressively, like female sprite variations. So no need to worry about that. The result: All of these sprites with only **3** icons added (the base template, and the masks) Obviously it's not perfect - some of the sprites (like the engineer's jumpsuit) lose some "luster", but it does the job if I do say so myself. ![image](https://github.com/user-attachments/assets/5c23dc97-8716-490c-898c-58b1e01a8a02) Only applied to undersuits, for now. ## Why It's Good For The Game - Allows Lizards to show off their handicap, rather than hiding it or necessitating they use skirts. - (Ideally) leads to an uptick in Digitigrade abuse (due to being easier to identify), which is also a net positive. - Implemented without any common issues revolving alt bodytype clothing sprites (those being maintainability and sprite bloat) ## Changelog :cl: Melbert add: Auto-generated digitigrade clothing sprites for most jumpsuits /:cl: --------- Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com> --- code/__DEFINES/inventory.dm | 12 ++- code/_globalvars/bitfields.dm | 1 + .../greyscale_configs/greyscale_clothes.dm | 5 + .../json_configs/jumpsuit_worn_digilegs.json | 10 ++ code/game/objects/items.dm | 6 ++ code/game/objects/structures/mannequin.dm | 8 +- code/modules/clothing/under/_under.dm | 2 + code/modules/clothing/under/color.dm | 1 + .../under/jobs/civilian/clown_mime.dm | 1 + code/modules/clothing/under/miscellaneous.dm | 1 + .../mob/living/carbon/human/_species.dm | 8 +- .../living/carbon/human/human_update_icons.dm | 99 ++++++++++++++++-- .../species_parts/lizard_bodyparts.dm | 74 ++++++------- ...anoids__datum_species_lizard_ashwalker.png | Bin 2700 -> 2961 bytes icons/mob/clothing/under/digi_template.dmi | Bin 0 -> 586 bytes icons/mob/clothing/under/masking_helpers.dmi | Bin 316 -> 454 bytes 16 files changed, 171 insertions(+), 57 deletions(-) create mode 100644 code/datums/greyscale/json_configs/jumpsuit_worn_digilegs.json create mode 100644 icons/mob/clothing/under/digi_template.dmi diff --git a/code/__DEFINES/inventory.dm b/code/__DEFINES/inventory.dm index 63054e533b1..054a08743ac 100644 --- a/code/__DEFINES/inventory.dm +++ b/code/__DEFINES/inventory.dm @@ -148,12 +148,18 @@ DEFINE_BITFIELD(no_equip_flags, list( #define DIGITIGRADE_STYLE 2 //Flags (actual flags, fucker ^) for /obj/item/var/supports_variations_flags -///No alternative sprites based on bodytype +/// No alternative sprites or handling based on bodytype #define CLOTHING_NO_VARIATION (1<<0) -///Has a sprite for digitigrade legs specifically. +/// Has a sprite for digitigrade legs specifically. #define CLOTHING_DIGITIGRADE_VARIATION (1<<1) -///The sprite works fine for digitigrade legs as-is. +/// The sprite works fine for digitigrade legs as-is. #define CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON (1<<2) +/// Auto-generates the leg portion of the sprite with GAGS +/// Suggested that you set [/obj/item/var/digitigrade_greyscale_config_worn] when using this flag +#define CLOTHING_DIGITIGRADE_MASK (1<<3) + +/// All variation flags which render "correctly" on a digitigrade leg setup +#define DIGITIGRADE_VARIATIONS (CLOTHING_DIGITIGRADE_VARIATION|CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON|CLOTHING_DIGITIGRADE_MASK) //flags for covering body parts #define GLASSESCOVERSEYES (1<<0) diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 27c0d27ec2e..8db59bccc35 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -442,6 +442,7 @@ DEFINE_BITFIELD(supports_variations_flags, list( "CLOTHING_NO_VARIATION" = CLOTHING_NO_VARIATION, "CLOTHING_DIGITIGRADE_VARIATION" = CLOTHING_DIGITIGRADE_VARIATION, "CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON" = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON, + "CLOTHING_DIGITIGRADE_MASK" = CLOTHING_DIGITIGRADE_MASK, )) DEFINE_BITFIELD(flora_flags, list( diff --git a/code/datums/greyscale/config_types/greyscale_configs/greyscale_clothes.dm b/code/datums/greyscale/config_types/greyscale_configs/greyscale_clothes.dm index 377a2fa1693..bdc2a7d2928 100644 --- a/code/datums/greyscale/config_types/greyscale_configs/greyscale_clothes.dm +++ b/code/datums/greyscale/config_types/greyscale_configs/greyscale_clothes.dm @@ -276,6 +276,11 @@ icon_file = 'icons/mob/inhands/clothing/suits_righthand.dmi' json_config = 'code/datums/greyscale/json_configs/jumpsuit_prison_inhand.json' +/datum/greyscale_config/jumpsuit/worn_digi + name = "Jumpsuit Worn (Digitigrate)" + icon_file = 'icons/mob/clothing/under/digi_template.dmi' + json_config = 'code/datums/greyscale/json_configs/jumpsuit_worn_digilegs.json' + /datum/greyscale_config/eth_tunic name = "Ethereal Tunic" icon_file = 'icons/obj/clothing/under/ethereal.dmi' diff --git a/code/datums/greyscale/json_configs/jumpsuit_worn_digilegs.json b/code/datums/greyscale/json_configs/jumpsuit_worn_digilegs.json new file mode 100644 index 00000000000..9aa201cece3 --- /dev/null +++ b/code/datums/greyscale/json_configs/jumpsuit_worn_digilegs.json @@ -0,0 +1,10 @@ +{ + "": [ + { + "type": "icon_state", + "icon_state": "jumpsuit", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ] +} diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 41d86c9eba9..67fa375a46d 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -39,6 +39,12 @@ ///The config type to use for greyscaled belt overlays. Both this and greyscale_colors must be assigned to work. var/greyscale_config_belt + /// Greyscale config used when generating digitigrade versions of the sprite. + var/digitigrade_greyscale_config_worn + /// Greyscale colors used when generating digitigrade versions of the sprite. + /// Optional - If not set it will default to normal greyscale colors, or approximate them if those are unset as well + var/digitigrade_greyscale_colors + /* !!!!!!!!!!!!!!! IMPORTANT !!!!!!!!!!!!!! IF YOU ADD MORE ICON CRAP TO THIS diff --git a/code/game/objects/structures/mannequin.dm b/code/game/objects/structures/mannequin.dm index b64fca106ae..b53de86d5ee 100644 --- a/code/game/objects/structures/mannequin.dm +++ b/code/game/objects/structures/mannequin.dm @@ -97,15 +97,15 @@ var/datum/sprite_accessory/underwear/underwear = SSaccessories.underwear_list[underwear_name] if(underwear) if(body_type == FEMALE && underwear.gender == MALE) - . += wear_female_version(underwear.icon_state, underwear.icon, BODY_LAYER, FEMALE_UNIFORM_FULL) + . += mutable_appearance(wear_female_version(underwear.icon_state, underwear.icon, FEMALE_UNIFORM_FULL), layer = -BODY_LAYER) else - . += mutable_appearance(underwear.icon, underwear.icon_state, -BODY_LAYER) + . += mutable_appearance(underwear.icon, underwear.icon_state, layer = -BODY_LAYER) var/datum/sprite_accessory/undershirt/undershirt = SSaccessories.undershirt_list[undershirt_name] if(undershirt) if(body_type == FEMALE) - . += wear_female_version(undershirt.icon_state, undershirt.icon, BODY_LAYER) + . += mutable_appearance(wear_female_version(undershirt.icon_state, undershirt.icon), layer = -BODY_LAYER) else - . += mutable_appearance(undershirt.icon, undershirt.icon_state, -BODY_LAYER) + . += mutable_appearance(undershirt.icon, undershirt.icon_state, layer = -BODY_LAYER) var/datum/sprite_accessory/socks/socks = SSaccessories.socks_list[socks_name] if(socks) . += mutable_appearance(socks.icon, socks.icon_state, -BODY_LAYER) diff --git a/code/modules/clothing/under/_under.dm b/code/modules/clothing/under/_under.dm index 2168177abcb..6c6f9608e4b 100644 --- a/code/modules/clothing/under/_under.dm +++ b/code/modules/clothing/under/_under.dm @@ -8,6 +8,8 @@ slot_flags = ITEM_SLOT_ICLOTHING interaction_flags_click = NEED_DEXTERITY armor_type = /datum/armor/clothing_under + supports_variations_flags = CLOTHING_DIGITIGRADE_MASK + digitigrade_greyscale_config_worn = /datum/greyscale_config/jumpsuit/worn_digi equip_sound = 'sound/items/equip/jumpsuit_equip.ogg' drop_sound = 'sound/items/handling/cloth_drop.ogg' pickup_sound = 'sound/items/handling/cloth_pickup.ogg' diff --git a/code/modules/clothing/under/color.dm b/code/modules/clothing/under/color.dm index 748e697415c..9ae1c7d63e3 100644 --- a/code/modules/clothing/under/color.dm +++ b/code/modules/clothing/under/color.dm @@ -224,6 +224,7 @@ greyscale_config_inhand_left = null greyscale_config_inhand_right = null greyscale_config_worn = null + digitigrade_greyscale_colors = "#3f3f3f" can_adjust = FALSE flags_1 = NONE diff --git a/code/modules/clothing/under/jobs/civilian/clown_mime.dm b/code/modules/clothing/under/jobs/civilian/clown_mime.dm index 98571182f29..55f0da88918 100644 --- a/code/modules/clothing/under/jobs/civilian/clown_mime.dm +++ b/code/modules/clothing/under/jobs/civilian/clown_mime.dm @@ -31,6 +31,7 @@ inhand_icon_state = "clown" female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY can_adjust = FALSE + supports_variations_flags = CLOTHING_NO_VARIATION /obj/item/clothing/under/rank/civilian/clown/Initialize(mapload) . = ..() diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm index 8f1263fa3e2..81002bd8a9e 100644 --- a/code/modules/clothing/under/miscellaneous.dm +++ b/code/modules/clothing/under/miscellaneous.dm @@ -33,6 +33,7 @@ desc = "Groovy!" icon_state = "psyche" inhand_icon_state = "p_suit" + digitigrade_greyscale_colors = "#3f3f3f" /obj/item/clothing/under/misc/vice_officer name = "vice officer's jumpsuit" diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index 5e1bdf42826..9c8d615f94d 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -572,7 +572,7 @@ GLOBAL_LIST_EMPTY(features_by_species) var/mutable_appearance/underwear_overlay if(underwear) if(species_human.dna.species.sexes && species_human.physique == FEMALE && (underwear.gender == MALE)) - underwear_overlay = wear_female_version(underwear.icon_state, underwear.icon, BODY_LAYER, FEMALE_UNIFORM_FULL) + underwear_overlay = mutable_appearance(wear_female_version(underwear.icon_state, underwear.icon, FEMALE_UNIFORM_FULL), layer = -BODY_LAYER) else underwear_overlay = mutable_appearance(underwear.icon, underwear.icon_state, -BODY_LAYER) if(!underwear.use_static) @@ -584,9 +584,9 @@ GLOBAL_LIST_EMPTY(features_by_species) if(undershirt) var/mutable_appearance/working_shirt if(species_human.dna.species.sexes && species_human.physique == FEMALE) - working_shirt = wear_female_version(undershirt.icon_state, undershirt.icon, BODY_LAYER) + working_shirt = mutable_appearance(wear_female_version(undershirt.icon_state, undershirt.icon), layer = -BODY_LAYER) else - working_shirt = mutable_appearance(undershirt.icon, undershirt.icon_state, -BODY_LAYER) + working_shirt = mutable_appearance(undershirt.icon, undershirt.icon_state, layer = -BODY_LAYER) standing += working_shirt if(species_human.socks && species_human.num_legs >= 2 && !(species_human.bodyshape & BODYSHAPE_DIGITIGRADE)) @@ -800,7 +800,7 @@ GLOBAL_LIST_EMPTY(features_by_species) if(H.num_legs < 2) return FALSE if((H.bodyshape & BODYSHAPE_DIGITIGRADE) && !(I.item_flags & IGNORE_DIGITIGRADE)) - if(!(I.supports_variations_flags & (CLOTHING_DIGITIGRADE_VARIATION|CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON))) + if(!(I.supports_variations_flags & DIGITIGRADE_VARIATIONS)) if(!disable_warning) to_chat(H, span_warning("The footwear around here isn't compatible with your feet!")) return FALSE diff --git a/code/modules/mob/living/carbon/human/human_update_icons.dm b/code/modules/mob/living/carbon/human/human_update_icons.dm index fe5817eab27..3fa50fe9c67 100644 --- a/code/modules/mob/living/carbon/human/human_update_icons.dm +++ b/code/modules/mob/living/carbon/human/human_update_icons.dm @@ -548,12 +548,72 @@ There are several things that need to be remembered: hands += hand_overlay return hands -/proc/wear_female_version(t_color, icon, layer, type, greyscale_colors) - var/index = "[t_color]-[greyscale_colors]" - var/icon/female_clothing_icon = GLOB.female_clothing_icons[index] - if(!female_clothing_icon) //Create standing/laying icons if they don't exist - generate_female_clothing(index, t_color, icon, type) - return mutable_appearance(GLOB.female_clothing_icons[index], layer = -layer) +/// Modifies a sprite slightly to conform to female body shapes +/proc/wear_female_version(icon_state, icon, type, greyscale_colors) + var/index = "[icon_state]-[greyscale_colors]" + var/static/list/female_clothing_icons = list() + var/icon/female_clothing_icon = female_clothing_icons[index] + if(!female_clothing_icon) //Create standing/laying icons if they don't exist + var/female_icon_state = "female[type == FEMALE_UNIFORM_FULL ? "_full" : ((!type || type & FEMALE_UNIFORM_TOP_ONLY) ? "_top" : "")][type & FEMALE_UNIFORM_NO_BREASTS ? "_no_breasts" : ""]" + var/icon/female_cropping_mask = icon('icons/mob/clothing/under/masking_helpers.dmi', female_icon_state) + female_clothing_icon = icon(icon, icon_state) + female_clothing_icon.Blend(female_cropping_mask, ICON_MULTIPLY) + female_clothing_icon = fcopy_rsc(female_clothing_icon) + female_clothing_icons[index] = female_clothing_icon + + return icon(female_clothing_icon) + +// These coordonates point to roughly somewhere in the middle of the left leg +// Used in approximating what color the pants of clothing should be +#define LEG_SAMPLE_X_LOWER 13 +#define LEG_SAMPLE_X_UPPER 14 + +#define LEG_SAMPLE_Y_LOWER 8 +#define LEG_SAMPLE_Y_UPPER 9 + +/// Modifies a sprite to conform to digitigrade body shapes +/proc/wear_digi_version(icon/base_icon, key, greyscale_config = /datum/greyscale_config/jumpsuit/worn_digi, greyscale_colors) + ASSERT(key, "wear_digi_version: no key passed") + ASSERT(ispath(greyscale_config, /datum/greyscale_config), "wear_digi_version: greyscale_config is not a valid path (got: [greyscale_config])") + // items with greyscale colors containing multiple colors are invalid + if(isnull(greyscale_colors) || length(SSgreyscale.ParseColorString(greyscale_colors)) > 1) + var/pant_color + // approximates the color of the pants by sampling a few pixels in the middle of the left leg + for(var/x in LEG_SAMPLE_X_LOWER to LEG_SAMPLE_X_UPPER) + for(var/y in LEG_SAMPLE_Y_LOWER to LEG_SAMPLE_Y_UPPER) + var/xy_color = base_icon.GetPixel(x, y) + pant_color = pant_color ? BlendRGB(pant_color, xy_color, 0.5) : xy_color + + greyscale_colors = pant_color || "#1d1d1d" // black pants always look good + + var/index = "[key]-[greyscale_config]-[greyscale_colors]" + var/static/list/digitigrade_clothing_icons = list() + var/icon/digitigrade_clothing_icon = digitigrade_clothing_icons[index] + if(!digitigrade_clothing_icon) + var/static/icon/torso_mask + if(!torso_mask) + torso_mask = icon('icons/mob/clothing/under/masking_helpers.dmi', "digi_torso_mask") + var/static/icon/leg_mask + if(!leg_mask) + leg_mask = icon('icons/mob/clothing/under/masking_helpers.dmi', "digi_leg_mask") + + base_icon.Blend(leg_mask, ICON_SUBTRACT) // cuts the legs off + + var/icon/leg_icon = SSgreyscale.GetColoredIconByType(greyscale_config, greyscale_colors) + leg_icon.Blend(torso_mask, ICON_SUBTRACT) // cuts the torso off + + base_icon.Blend(leg_icon, ICON_OVERLAY) // puts the new legs on + + digitigrade_clothing_icon = fcopy_rsc(base_icon) + digitigrade_clothing_icons[index] = digitigrade_clothing_icon + + return icon(digitigrade_clothing_icon) + +#undef LEG_SAMPLE_X_LOWER +#undef LEG_SAMPLE_X_UPPER + +#undef LEG_SAMPLE_Y_LOWER +#undef LEG_SAMPLE_Y_UPPER /mob/living/carbon/human/proc/get_overlays_copy(list/unwantedLayers) var/list/out = new @@ -689,11 +749,30 @@ generate/load female uniform sprites matching all previously decided variables //Find a valid layer from variables+arguments var/layer2use = alternate_worn_layer || default_layer - var/mutable_appearance/standing + var/mob/living/carbon/wearer = loc + var/is_digi = istype(wearer) && (wearer.bodyshape & BODYSHAPE_DIGITIGRADE) && !wearer.is_digitigrade_squished() + + var/mutable_appearance/standing // this is the actual resulting MA + var/icon/building_icon // used to construct an icon across multiple procs before converting it to MA if(female_uniform) - standing = wear_female_version(t_state, file2use, layer2use, female_uniform, greyscale_colors) //should layer2use be in sync with the adjusted value below? needs testing - shiz - if(!standing) - standing = mutable_appearance(file2use, t_state, -layer2use) + building_icon = wear_female_version( + icon_state = t_state, + icon = file2use, + type = female_uniform, + greyscale_colors = greyscale_colors, + ) + if(!isinhands && is_digi && (supports_variations_flags & CLOTHING_DIGITIGRADE_MASK)) + building_icon = wear_digi_version( + base_icon = building_icon || icon(file2use, t_state), + key = "[t_state]-[file2use]-[female_uniform]", + greyscale_config = digitigrade_greyscale_config_worn || greyscale_config_worn, + greyscale_colors = digitigrade_greyscale_colors || greyscale_colors || color, + ) + if(building_icon) + standing = mutable_appearance(building_icon, layer = -layer2use) + + // no special handling done, default it + standing ||= mutable_appearance(file2use, t_state, layer = -layer2use) //Get the overlays for this item when it's being worn //eg: ammo counters, primed grenade flashes, etc. diff --git a/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm index 350e2f32883..03c0dd86b85 100644 --- a/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm @@ -47,6 +47,30 @@ icon_greyscale = 'icons/mob/human/species/lizard/bodyparts.dmi' limb_id = SPECIES_LIZARD +/// Checks if this mob is wearing anything that does not have a valid sprite set for digitigrade legs +/// (In other words, is the mob's digitigrade body squished by its clothing?) +/mob/living/carbon/proc/is_digitigrade_squished() + return FALSE + +/mob/living/carbon/human/is_digitigrade_squished() + var/obj/item/clothing/shoes/worn_shoes = shoes + var/obj/item/clothing/under/worn_suit = wear_suit + var/obj/item/clothing/under/worn_uniform = w_uniform + + var/uniform_compatible = isnull(worn_uniform) \ + || (worn_uniform.supports_variations_flags & DIGITIGRADE_VARIATIONS) \ + || !(worn_uniform.body_parts_covered & LEGS) \ + || (worn_suit?.flags_inv & HIDEJUMPSUIT) // If suit hides our jumpsuit, it doesn't matter if it squishes + + var/suit_compatible = isnull(worn_suit) \ + || (worn_suit.supports_variations_flags & DIGITIGRADE_VARIATIONS) \ + || !(worn_suit.body_parts_covered & LEGS) + + var/shoes_compatible = isnull(worn_shoes) \ + || (worn_shoes.supports_variations_flags & DIGITIGRADE_VARIATIONS) + + return !uniform_compatible || !suit_compatible || !shoes_compatible + /obj/item/bodypart/leg/left/digitigrade icon_greyscale = 'icons/mob/human/species/lizard/bodyparts.dmi' limb_id = BODYPART_ID_DIGITIGRADE @@ -54,24 +78,13 @@ /obj/item/bodypart/leg/left/digitigrade/update_limb(dropping_limb = FALSE, is_creating = FALSE) . = ..() - if(ishuman(owner)) - var/mob/living/carbon/human/human_owner = owner - var/obj/item/clothing/shoes/worn_shoes = human_owner.get_item_by_slot(ITEM_SLOT_FEET) - var/uniform_compatible = FALSE - var/suit_compatible = FALSE - var/shoes_compatible = FALSE - if(!(human_owner.w_uniform) || (human_owner.w_uniform.supports_variations_flags & (CLOTHING_DIGITIGRADE_VARIATION|CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON))) //Checks uniform compatibility - uniform_compatible = TRUE - if((!human_owner.wear_suit) || (human_owner.wear_suit.supports_variations_flags & (CLOTHING_DIGITIGRADE_VARIATION|CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON)) || !(human_owner.wear_suit.body_parts_covered & LEGS)) //Checks suit compatability - suit_compatible = TRUE - if((worn_shoes == null) || (worn_shoes.supports_variations_flags & (CLOTHING_DIGITIGRADE_VARIATION|CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON))) - shoes_compatible = TRUE - - if((uniform_compatible && suit_compatible && shoes_compatible) || (suit_compatible && shoes_compatible && human_owner.wear_suit?.flags_inv & HIDEJUMPSUIT)) //If the uniform is hidden, it doesnt matter if its compatible - limb_id = BODYPART_ID_DIGITIGRADE - - else - limb_id = SPECIES_LIZARD + var/old_id = limb_id + limb_id = owner?.is_digitigrade_squished() ? SPECIES_LIZARD : BODYPART_ID_DIGITIGRADE + if(old_id != limb_id) + // Something unsquished / squished us so we need to go through and update everything that is affected + for(var/obj/item/thing as anything in owner?.get_equipped_items()) + if(thing.supports_variations_flags & DIGITIGRADE_VARIATIONS) + thing.update_slot_icon() /obj/item/bodypart/leg/right/digitigrade icon_greyscale = 'icons/mob/human/species/lizard/bodyparts.dmi' @@ -80,21 +93,10 @@ /obj/item/bodypart/leg/right/digitigrade/update_limb(dropping_limb = FALSE, is_creating = FALSE) . = ..() - if(ishuman(owner)) - var/mob/living/carbon/human/human_owner = owner - var/obj/item/clothing/shoes/worn_shoes = human_owner.get_item_by_slot(ITEM_SLOT_FEET) - var/uniform_compatible = FALSE - var/suit_compatible = FALSE - var/shoes_compatible = FALSE - if(!(human_owner.w_uniform) || (human_owner.w_uniform.supports_variations_flags & (CLOTHING_DIGITIGRADE_VARIATION|CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON))) //Checks uniform compatibility - uniform_compatible = TRUE - if((!human_owner.wear_suit) || (human_owner.wear_suit.supports_variations_flags & (CLOTHING_DIGITIGRADE_VARIATION|CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON)) || !(human_owner.wear_suit.body_parts_covered & LEGS)) //Checks suit compatability - suit_compatible = TRUE - if((worn_shoes == null) || (worn_shoes.supports_variations_flags & (CLOTHING_DIGITIGRADE_VARIATION|CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON))) - shoes_compatible = TRUE - - if((uniform_compatible && suit_compatible && shoes_compatible) || (suit_compatible && shoes_compatible && human_owner.wear_suit?.flags_inv & HIDEJUMPSUIT)) //If the uniform is hidden, it doesnt matter if its compatible - limb_id = BODYPART_ID_DIGITIGRADE - - else - limb_id = SPECIES_LIZARD + var/old_id = limb_id + limb_id = owner?.is_digitigrade_squished() ? SPECIES_LIZARD : BODYPART_ID_DIGITIGRADE + if(old_id != limb_id) + // Something unsquished / squished us so we need to go through and update everything that is affected + for(var/obj/item/thing as anything in owner?.get_equipped_items()) + if(thing.supports_variations_flags & DIGITIGRADE_VARIATIONS) + thing.update_slot_icon() diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_lizard_ashwalker.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_lizard_ashwalker.png index e157cb5631d55a622acf70eca404b3d10e3ab8af..c4c48d3fdb83918c565d051d82f99d5a890e26d6 100644 GIT binary patch delta 2836 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 literal 316 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?O3?zSk_}l@c*aCb)T>mpL{Qv*oQPxBdD8g70 zeukTAW;zSx}OhpU1#ZF(){zps4iwm*9erU!Q1s>uQ}lb3S-O zsKG_!2aj~l`)HnIDC+6mVPPC(eA(DbVa}sTM<#_R1Z(P=nj5N{+O0KFckk>rR^7Zp zV#(BQ