mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-27 23:27:34 +01:00
State based digi and snout bodyshape (#96030)
## About The Pull Request Digi and snout bodyshape are added and removed if digi or snout is hidden There now also exists a digitigrade bodytype which is not removed if the bodyshape his Bodyshape is solely used for determining how the body is shaped for rendering Bodytype is used for checking stuff like "can digis wear shoes" This lets us clean up rendering code a bit, allowing us to pass around bodyshape rather than needing to check our wearer for digi and whatnot Digi itself is now a component for legs that tracks - on item equip or unequip - if said items squish the legs. ## Why It's Good For The Game Right now we do some super jank stuff like updating body every time we update our jumpsuit which is obviously a bit wasteful This should make things easier to manage and work with (and maybe more performant?) ## Changelog 🆑 Melbert refactor: Refactored how digitigrade and snouts render, report any oddities with that /🆑
This commit is contained in:
@@ -60,6 +60,11 @@
|
||||
/// Called from bodypart being removed /obj/item/bodypart/proc/drop_limb(mob/living/carbon/old_owner, special, dismembered)
|
||||
#define COMSIG_BODYPART_REMOVED "bodypart_removed"
|
||||
|
||||
/// From /obj/item/bodypart/proc/update_limb(): (dropping_limb, is_creating)
|
||||
#define COMSIG_BODYPART_UPDATED "bodypart_updated"
|
||||
/// From /datum/component/butchering/create_replacement_limb(): (replacement limb)
|
||||
#define COMSIG_BODYPART_BUTCHERED "bodypart_butchered"
|
||||
|
||||
/// Sent to a limb when something *attempts* to change its surgery state (old_state, new_state, changed_states)
|
||||
#define COMSIG_BODYPART_UPDATING_SURGERY_STATE "bodypart_updating_surgery_state"
|
||||
|
||||
@@ -212,3 +217,5 @@
|
||||
#define COMSIG_START_DREAMING "start_dreaming"
|
||||
/// A mob has finished dreaming: (datum/dream/finished_dream)
|
||||
#define COMSIG_END_DREAMING "end_dreaming"
|
||||
/// From /mob/living/carbon/item_coverage_changed: (added_slots, removed_slots)
|
||||
#define COMSIG_CARBON_ITEM_COVERAGE_CHANGED "carbon_item_coverage_changed"
|
||||
|
||||
@@ -172,6 +172,8 @@
|
||||
#define BODYTYPE_SHADOW (1<<7)
|
||||
//This limb is a ghost limb and can phase through walls.
|
||||
#define BODYTYPE_GHOST (1<<8)
|
||||
/// Analagous to BODYSHAPE_DIGITIGRADE, though this one is not removed if the mob's shape changed
|
||||
#define BODYTYPE_DIGITIGRADE (1<<9)
|
||||
|
||||
// Bodyshape defines for how things can be worn, i.e., what "shape" the mob sprite is
|
||||
///The limb fits the human mold. This is not meant to be literal, if the sprite "fits" on a human, it is "humanoid", regardless of origin.
|
||||
|
||||
@@ -318,6 +318,7 @@
|
||||
wound.remove_wound()
|
||||
wound.apply_wound(replacement, silent = TRUE)
|
||||
|
||||
SEND_SIGNAL(target, COMSIG_BODYPART_BUTCHERED, replacement)
|
||||
return replacement
|
||||
|
||||
/datum/component/butchering/proc/start_butcher(obj/item/source, mob/living/target, mob/living/user)
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
/// Updates the limb id of a bodypart if the mob is wearing digitigrade squishing clothing
|
||||
/datum/component/digitigrade_limb
|
||||
/// Id when wearing digitigrade squishing clothing
|
||||
var/squashed_id
|
||||
/// Id when not wearing digitigrade squishing clothing
|
||||
var/free_id
|
||||
|
||||
/// Lazylist of refs that are squishing this limb
|
||||
VAR_PRIVATE/list/squashing_us
|
||||
|
||||
/datum/component/digitigrade_limb/Initialize(squashed_id, free_id)
|
||||
if(!istype(parent, /obj/item/bodypart/leg))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
var/obj/item/bodypart/limb = parent
|
||||
limb.bodytype |= BODYTYPE_DIGITIGRADE
|
||||
|
||||
src.squashed_id = squashed_id
|
||||
src.free_id = free_id || initial(limb.limb_id)
|
||||
|
||||
RegisterSignal(parent, COMSIG_BODYPART_UPDATED, PROC_REF(update_limb_id_comsig))
|
||||
RegisterSignal(parent, COMSIG_BODYPART_ATTACHED, PROC_REF(on_attach))
|
||||
RegisterSignal(parent, COMSIG_BODYPART_REMOVED, PROC_REF(on_remove))
|
||||
RegisterSignal(parent, COMSIG_BODYPART_BUTCHERED, PROC_REF(on_butchered))
|
||||
|
||||
if(ishuman(limb.owner))
|
||||
on_attach(limb, limb.owner)
|
||||
|
||||
/datum/component/digitigrade_limb/Destroy()
|
||||
UnregisterSignal(parent, COMSIG_BODYPART_UPDATED)
|
||||
UnregisterSignal(parent, COMSIG_BODYPART_ATTACHED)
|
||||
UnregisterSignal(parent, COMSIG_BODYPART_REMOVED)
|
||||
|
||||
UnregisterSignal(parent, COMSIG_BODYPART_BUTCHERED)
|
||||
var/obj/item/bodypart/limb = parent
|
||||
if(!QDELING(parent) && ishuman(limb.owner))
|
||||
on_remove(limb, limb.owner)
|
||||
limb.bodytype &= ~BODYTYPE_DIGITIGRADE
|
||||
return ..()
|
||||
|
||||
/datum/component/digitigrade_limb/proc/on_attach(obj/item/bodypart/limb, mob/living/carbon/new_limb_owner)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
RegisterSignal(new_limb_owner, COMSIG_MOB_EQUIPPED_ITEM, PROC_REF(equipped_item))
|
||||
RegisterSignal(new_limb_owner, COMSIG_MOB_DROPPED_ITEM, PROC_REF(unequipped_item))
|
||||
RegisterSignal(new_limb_owner, COMSIG_CARBON_ITEM_COVERAGE_CHANGED, PROC_REF(coverage_changed))
|
||||
for(var/obj/item/equipped as anything in new_limb_owner.get_equipped_items())
|
||||
if(equipped_item(new_limb_owner, equipped, new_limb_owner.get_slot_by_item(equipped)))
|
||||
LAZYOR(squashing_us, REF(equipped))
|
||||
|
||||
/datum/component/digitigrade_limb/proc/on_remove(obj/item/bodypart/limb, mob/living/carbon/old_limb_owner)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
UnregisterSignal(old_limb_owner, COMSIG_MOB_EQUIPPED_ITEM)
|
||||
UnregisterSignal(old_limb_owner, COMSIG_MOB_DROPPED_ITEM)
|
||||
UnregisterSignal(old_limb_owner, COMSIG_CARBON_ITEM_COVERAGE_CHANGED)
|
||||
LAZYNULL(squashing_us)
|
||||
update_limb_id()
|
||||
|
||||
/datum/component/digitigrade_limb/proc/equipped_item(mob/living/carbon/equipper, obj/item/equipped_item, slot)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if((slot & equipped_item.slot_flags) && item_squishes_limb(equipped_item, equipper))
|
||||
LAZYOR(squashing_us, REF(equipped_item))
|
||||
update_limb_id()
|
||||
|
||||
/datum/component/digitigrade_limb/proc/unequipped_item(mob/living/carbon/equipper, obj/item/equipped_item)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
LAZYREMOVE(squashing_us, REF(equipped_item))
|
||||
update_limb_id()
|
||||
|
||||
// Snowflake case for updating whether our jumpsuit should squish us
|
||||
/datum/component/digitigrade_limb/proc/coverage_changed(mob/living/carbon/equipper, added_slots, removed_slots)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!((added_slots|removed_slots) & HIDEJUMPSUIT))
|
||||
return
|
||||
|
||||
var/obj/item/clothing/uniform = equipper.get_item_by_slot(ITEM_SLOT_ICLOTHING)
|
||||
if(isnull(uniform))
|
||||
return
|
||||
|
||||
var/uniform_ref = REF(uniform)
|
||||
if(uniform_ref in squashing_us)
|
||||
if(added_slots & HIDEJUMPSUIT)
|
||||
LAZYREMOVE(squashing_us, uniform_ref)
|
||||
update_limb_id()
|
||||
|
||||
else
|
||||
if((removed_slots & HIDEJUMPSUIT) && item_squishes_limb(uniform, equipper))
|
||||
LAZYOR(squashing_us, uniform_ref)
|
||||
update_limb_id()
|
||||
|
||||
/datum/component/digitigrade_limb/proc/item_squishes_limb(obj/item/equipped_item, mob/living/carbon/equipper)
|
||||
if(!(equipped_item.body_parts_covered & (LEGS|FEET)))
|
||||
return FALSE
|
||||
|
||||
switch(equipper.get_slot_by_item(equipped_item))
|
||||
if(ITEM_SLOT_FEET, ITEM_SLOT_OCLOTHING)
|
||||
return !(equipped_item.supports_variations_flags & DIGITIGRADE_VARIATIONS)
|
||||
if(ITEM_SLOT_ICLOTHING) // If the jumpsuit is obscured, it shouldn't contribute to squishing
|
||||
return !(equipped_item.supports_variations_flags & DIGITIGRADE_VARIATIONS) && !(equipper.obscured_slots & HIDEJUMPSUIT)
|
||||
|
||||
return FALSE
|
||||
|
||||
/// This is just ran on update_limb() to ensure we always have the correct ID
|
||||
/datum/component/digitigrade_limb/proc/update_limb_id_comsig()
|
||||
SIGNAL_HANDLER
|
||||
update_limb_id(sprite_update = FALSE)
|
||||
|
||||
/// Digitigrade limbs that are butchered add the component to the replacement limb
|
||||
/datum/component/digitigrade_limb/proc/on_butchered(datum/source, obj/item/bodypart/replacement)
|
||||
SIGNAL_HANDLER
|
||||
squashed_id = "[initial(replacement.limb_id)]_[BODYPART_ID_DIGITIGRADE]"
|
||||
free_id = initial(replacement.limb_id)
|
||||
replacement.TakeComponent(src)
|
||||
|
||||
/datum/component/digitigrade_limb/proc/update_limb_id(sprite_update = TRUE)
|
||||
var/obj/item/bodypart/limb = parent
|
||||
var/old_id = limb.limb_id
|
||||
if(LAZYLEN(squashing_us))
|
||||
limb.limb_id = squashed_id
|
||||
limb.remove_bodyshape(BODYSHAPE_DIGITIGRADE)
|
||||
|
||||
else
|
||||
limb.limb_id = free_id
|
||||
limb.add_bodyshape(BODYSHAPE_DIGITIGRADE)
|
||||
|
||||
if(!sprite_update || old_id == limb.limb_id)
|
||||
return
|
||||
|
||||
if(isnull(limb.owner))
|
||||
limb.update_icon_dropped()
|
||||
return
|
||||
|
||||
// Ensures any items that with a variation are updated
|
||||
for(var/obj/item/thing as anything in limb.owner.get_equipped_items(INCLUDE_PROSTHETICS|INCLUDE_ABSTRACT))
|
||||
if(thing.supports_variations_flags & DIGITIGRADE_VARIATIONS)
|
||||
thing.update_slot_icon()
|
||||
// Updates underwear and mob sprites
|
||||
limb.owner.update_body()
|
||||
@@ -270,7 +270,7 @@
|
||||
if(IS_RIGHT_INDEX(get_held_index_of_item(I)))
|
||||
icon_file = I.righthand_file
|
||||
|
||||
hands += I.build_worn_icon(default_layer = HANDS_LAYER, default_icon_file = icon_file, isinhands = TRUE)
|
||||
hands += I.build_worn_icon(default_layer = HANDS_LAYER, default_icon_file = icon_file, isinhands = TRUE, bodyshape = bodyshape)
|
||||
return hands
|
||||
|
||||
/mob/living/carbon/get_fire_overlay(stacks, on_fire)
|
||||
@@ -344,7 +344,7 @@
|
||||
|
||||
if(wear_mask)
|
||||
if(!(obscured_slots & HIDEMASK))
|
||||
overlays_standing[FACEMASK_LAYER] = wear_mask.build_worn_icon(default_layer = FACEMASK_LAYER, default_icon_file = 'icons/mob/clothing/mask.dmi')
|
||||
overlays_standing[FACEMASK_LAYER] = wear_mask.build_worn_icon(default_layer = FACEMASK_LAYER, default_icon_file = 'icons/mob/clothing/mask.dmi', bodyshape = bodyshape)
|
||||
update_hud_wear_mask(wear_mask)
|
||||
|
||||
apply_overlay(FACEMASK_LAYER)
|
||||
@@ -358,7 +358,7 @@
|
||||
|
||||
if(wear_neck)
|
||||
if(!(obscured_slots & HIDENECK))
|
||||
overlays_standing[NECK_LAYER] = wear_neck.build_worn_icon(default_layer = NECK_LAYER, default_icon_file = 'icons/mob/clothing/neck.dmi')
|
||||
overlays_standing[NECK_LAYER] = wear_neck.build_worn_icon(default_layer = NECK_LAYER, default_icon_file = 'icons/mob/clothing/neck.dmi', bodyshape = bodyshape)
|
||||
update_hud_neck(wear_neck)
|
||||
|
||||
apply_overlay(NECK_LAYER)
|
||||
@@ -371,7 +371,7 @@
|
||||
inv.update_appearance()
|
||||
|
||||
if(back)
|
||||
overlays_standing[BACK_LAYER] = back.build_worn_icon(default_layer = BACK_LAYER, default_icon_file = 'icons/mob/clothing/back.dmi')
|
||||
overlays_standing[BACK_LAYER] = back.build_worn_icon(default_layer = BACK_LAYER, default_icon_file = 'icons/mob/clothing/back.dmi', bodyshape = bodyshape)
|
||||
update_hud_back(back)
|
||||
|
||||
apply_overlay(BACK_LAYER)
|
||||
@@ -399,7 +399,7 @@
|
||||
|
||||
if(head)
|
||||
if(!(obscured_slots & HIDEHEADGEAR))
|
||||
overlays_standing[HEAD_LAYER] = head.build_worn_icon(default_layer = HEAD_LAYER, default_icon_file = 'icons/mob/clothing/head/default.dmi')
|
||||
overlays_standing[HEAD_LAYER] = head.build_worn_icon(default_layer = HEAD_LAYER, default_icon_file = 'icons/mob/clothing/head/default.dmi', bodyshape = bodyshape)
|
||||
update_hud_head(head)
|
||||
|
||||
apply_overlay(HEAD_LAYER)
|
||||
|
||||
@@ -593,7 +593,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
|
||||
if(ITEM_SLOT_FEET)
|
||||
if(H.num_legs < 2)
|
||||
return FALSE
|
||||
if((H.bodyshape & BODYSHAPE_DIGITIGRADE) && !(I.item_flags & IGNORE_DIGITIGRADE))
|
||||
if((H.bodytype & BODYTYPE_DIGITIGRADE) && !(I.item_flags & IGNORE_DIGITIGRADE))
|
||||
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!"))
|
||||
|
||||
@@ -120,6 +120,7 @@ There are several things that need to be remembered:
|
||||
female_uniform = woman ? uniform.female_sprite_flags : null,
|
||||
override_state = target_overlay,
|
||||
override_file = handled_by_bodyshape ? icon_file : null,
|
||||
bodyshape = bodyshape,
|
||||
)
|
||||
|
||||
var/obj/item/bodypart/chest/my_chest = get_bodypart(BODY_ZONE_CHEST)
|
||||
@@ -127,7 +128,6 @@ There are several things that need to be remembered:
|
||||
overlays_standing[UNIFORM_LAYER] = uniform_overlay
|
||||
|
||||
apply_overlay(UNIFORM_LAYER)
|
||||
check_body_shape(BODYSHAPE_DIGITIGRADE, ITEM_SLOT_ICLOTHING)
|
||||
|
||||
/mob/living/carbon/human/update_worn_id()
|
||||
remove_overlay(ID_LAYER)
|
||||
@@ -147,7 +147,7 @@ There are several things that need to be remembered:
|
||||
|
||||
var/icon_file = 'icons/mob/clothing/id.dmi'
|
||||
|
||||
id_overlay = wear_id.build_worn_icon(default_layer = ID_LAYER, default_icon_file = icon_file)
|
||||
id_overlay = wear_id.build_worn_icon(default_layer = ID_LAYER, default_icon_file = icon_file, bodyshape = bodyshape)
|
||||
|
||||
if(!id_overlay)
|
||||
return
|
||||
@@ -193,7 +193,7 @@ There are several things that need to be remembered:
|
||||
|
||||
var/icon_file = 'icons/mob/clothing/hands.dmi'
|
||||
|
||||
var/mutable_appearance/gloves_overlay = gloves.build_worn_icon(default_layer = GLOVES_LAYER, default_icon_file = icon_file)
|
||||
var/mutable_appearance/gloves_overlay = gloves.build_worn_icon(default_layer = GLOVES_LAYER, default_icon_file = icon_file, bodyshape = bodyshape)
|
||||
|
||||
var/feature_y_offset = 0
|
||||
//needs to be typed, hand_bodyparts can have nulls
|
||||
@@ -240,7 +240,7 @@ There are several things that need to be remembered:
|
||||
|
||||
var/icon_file = 'icons/mob/clothing/eyes.dmi'
|
||||
|
||||
var/mutable_appearance/glasses_overlay = glasses.build_worn_icon(default_layer = GLASSES_LAYER, default_icon_file = icon_file)
|
||||
var/mutable_appearance/glasses_overlay = glasses.build_worn_icon(default_layer = GLASSES_LAYER, default_icon_file = icon_file, bodyshape = bodyshape)
|
||||
my_head.worn_glasses_offset?.apply_offset(glasses_overlay)
|
||||
overlays_standing[GLASSES_LAYER] = glasses_overlay
|
||||
apply_overlay(GLASSES_LAYER)
|
||||
@@ -266,7 +266,7 @@ There are several things that need to be remembered:
|
||||
|
||||
var/icon_file = 'icons/mob/clothing/ears.dmi'
|
||||
|
||||
var/mutable_appearance/ears_overlay = ears.build_worn_icon(default_layer = EARS_LAYER, default_icon_file = icon_file)
|
||||
var/mutable_appearance/ears_overlay = ears.build_worn_icon(default_layer = EARS_LAYER, default_icon_file = icon_file, bodyshape = bodyshape)
|
||||
my_head.worn_ears_offset?.apply_offset(ears_overlay)
|
||||
overlays_standing[EARS_LAYER] = ears_overlay
|
||||
apply_overlay(EARS_LAYER)
|
||||
@@ -287,7 +287,7 @@ There are several things that need to be remembered:
|
||||
|
||||
var/icon_file = 'icons/mob/clothing/neck.dmi'
|
||||
|
||||
var/mutable_appearance/neck_overlay = worn_item.build_worn_icon(default_layer = NECK_LAYER, default_icon_file = icon_file)
|
||||
var/mutable_appearance/neck_overlay = worn_item.build_worn_icon(default_layer = NECK_LAYER, default_icon_file = icon_file, bodyshape = bodyshape)
|
||||
var/obj/item/bodypart/chest/my_chest = get_bodypart(BODY_ZONE_CHEST)
|
||||
my_chest?.worn_neck_offset?.apply_offset(neck_overlay)
|
||||
overlays_standing[NECK_LAYER] = neck_overlay
|
||||
@@ -313,7 +313,7 @@ There are several things that need to be remembered:
|
||||
|
||||
var/icon_file = DEFAULT_SHOES_FILE
|
||||
|
||||
var/mutable_appearance/shoes_overlay = shoes.build_worn_icon(default_layer = SHOES_LAYER, default_icon_file = icon_file)
|
||||
var/mutable_appearance/shoes_overlay = shoes.build_worn_icon(default_layer = SHOES_LAYER, default_icon_file = icon_file, bodyshape = bodyshape)
|
||||
if(!shoes_overlay)
|
||||
return
|
||||
|
||||
@@ -330,7 +330,6 @@ There are several things that need to be remembered:
|
||||
overlays_standing[SHOES_LAYER] = shoes_overlay
|
||||
|
||||
apply_overlay(SHOES_LAYER)
|
||||
check_body_shape(BODYSHAPE_DIGITIGRADE, ITEM_SLOT_FEET)
|
||||
|
||||
/mob/living/carbon/human/update_suit_storage()
|
||||
remove_overlay(SUIT_STORE_LAYER)
|
||||
@@ -367,13 +366,12 @@ There are several things that need to be remembered:
|
||||
|
||||
var/icon_file = 'icons/mob/clothing/head/default.dmi'
|
||||
|
||||
var/mutable_appearance/head_overlay = head.build_worn_icon(default_layer = HEAD_LAYER, default_icon_file = icon_file)
|
||||
var/mutable_appearance/head_overlay = head.build_worn_icon(default_layer = HEAD_LAYER, default_icon_file = icon_file, bodyshape = bodyshape)
|
||||
var/obj/item/bodypart/head/my_head = get_bodypart(BODY_ZONE_HEAD)
|
||||
my_head?.worn_head_offset?.apply_offset(head_overlay)
|
||||
overlays_standing[HEAD_LAYER] = head_overlay
|
||||
|
||||
apply_overlay(HEAD_LAYER)
|
||||
check_body_shape(BODYSHAPE_SNOUTED, ITEM_SLOT_HEAD)
|
||||
|
||||
/mob/living/carbon/human/update_worn_belt()
|
||||
remove_overlay(BELT_LAYER)
|
||||
@@ -391,7 +389,7 @@ There are several things that need to be remembered:
|
||||
|
||||
var/icon_file = 'icons/mob/clothing/belt.dmi'
|
||||
|
||||
var/mutable_appearance/belt_overlay = belt.build_worn_icon(default_layer = BELT_LAYER, default_icon_file = icon_file)
|
||||
var/mutable_appearance/belt_overlay = belt.build_worn_icon(default_layer = BELT_LAYER, default_icon_file = icon_file, bodyshape = bodyshape)
|
||||
var/obj/item/bodypart/chest/my_chest = get_bodypart(BODY_ZONE_CHEST)
|
||||
my_chest?.worn_belt_offset?.apply_offset(belt_overlay)
|
||||
overlays_standing[BELT_LAYER] = belt_overlay
|
||||
@@ -414,13 +412,12 @@ There are several things that need to be remembered:
|
||||
|
||||
var/icon_file = DEFAULT_SUIT_FILE
|
||||
|
||||
var/mutable_appearance/suit_overlay = wear_suit.build_worn_icon(default_layer = SUIT_LAYER, default_icon_file = icon_file)
|
||||
var/mutable_appearance/suit_overlay = wear_suit.build_worn_icon(default_layer = SUIT_LAYER, default_icon_file = icon_file, bodyshape = bodyshape)
|
||||
var/obj/item/bodypart/chest/my_chest = get_bodypart(BODY_ZONE_CHEST)
|
||||
my_chest?.worn_suit_offset?.apply_offset(suit_overlay)
|
||||
overlays_standing[SUIT_LAYER] = suit_overlay
|
||||
|
||||
apply_overlay(SUIT_LAYER)
|
||||
check_body_shape(BODYSHAPE_DIGITIGRADE, ITEM_SLOT_OCLOTHING)
|
||||
|
||||
/mob/living/carbon/human/update_pockets()
|
||||
if(client && hud_used)
|
||||
@@ -463,12 +460,11 @@ There are several things that need to be remembered:
|
||||
|
||||
var/icon_file = 'icons/mob/clothing/mask.dmi'
|
||||
|
||||
var/mutable_appearance/mask_overlay = wear_mask.build_worn_icon(default_layer = FACEMASK_LAYER, default_icon_file = icon_file)
|
||||
var/mutable_appearance/mask_overlay = wear_mask.build_worn_icon(default_layer = FACEMASK_LAYER, default_icon_file = icon_file, bodyshape = bodyshape)
|
||||
my_head.worn_mask_offset?.apply_offset(mask_overlay)
|
||||
overlays_standing[FACEMASK_LAYER] = mask_overlay
|
||||
|
||||
apply_overlay(FACEMASK_LAYER)
|
||||
check_body_shape(BODYSHAPE_SNOUTED, ITEM_SLOT_MASK)
|
||||
|
||||
/mob/living/carbon/human/update_worn_back()
|
||||
remove_overlay(BACK_LAYER)
|
||||
@@ -487,7 +483,7 @@ There are several things that need to be remembered:
|
||||
|
||||
var/icon_file = 'icons/mob/clothing/back.dmi'
|
||||
|
||||
back_overlay = back.build_worn_icon(default_layer = BACK_LAYER, default_icon_file = icon_file)
|
||||
back_overlay = back.build_worn_icon(default_layer = BACK_LAYER, default_icon_file = icon_file, bodyshape = bodyshape)
|
||||
|
||||
if(!back_overlay)
|
||||
return
|
||||
@@ -520,7 +516,7 @@ There are several things that need to be remembered:
|
||||
|
||||
var/mutable_appearance/hand_overlay
|
||||
var/icon_file = IS_RIGHT_INDEX(held_index) ? worn_item.righthand_file : worn_item.lefthand_file
|
||||
hand_overlay = worn_item.build_worn_icon(default_layer = HANDS_LAYER, default_icon_file = icon_file, isinhands = TRUE)
|
||||
hand_overlay = worn_item.build_worn_icon(default_layer = HANDS_LAYER, default_icon_file = icon_file, isinhands = TRUE, bodyshape = bodyshape)
|
||||
var/obj/item/bodypart/arm/held_in_hand = hand_bodyparts[held_index]
|
||||
held_in_hand?.held_hand_offset?.apply_offset(hand_overlay)
|
||||
|
||||
@@ -758,6 +754,7 @@ generate/load female uniform sprites matching all previously decided variables
|
||||
female_uniform = NO_FEMALE_UNIFORM,
|
||||
override_state = null,
|
||||
override_file = null,
|
||||
bodyshape = NONE,
|
||||
)
|
||||
|
||||
//Find a valid icon_state from variables+arguments
|
||||
@@ -767,9 +764,6 @@ 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/mob/living/carbon/wearer = loc
|
||||
var/is_digi = istype(wearer) && (wearer.bodyshape & BODYSHAPE_DIGITIGRADE) && !wearer.is_digitigrade_squished()
|
||||
|
||||
var/mutable_appearance/draw_target // MA of the item itself, not the final result
|
||||
var/icon/building_icon // used to construct an icon across multiple procs before converting it to MA
|
||||
if(female_uniform)
|
||||
@@ -779,7 +773,7 @@ generate/load female uniform sprites matching all previously decided variables
|
||||
type = female_uniform,
|
||||
greyscale_colors = greyscale_colors,
|
||||
)
|
||||
if(!isinhands && is_digi && (supports_variations_flags & CLOTHING_DIGITIGRADE_MASK))
|
||||
if(!isinhands && (bodyshape & BODYSHAPE_DIGITIGRADE) && (supports_variations_flags & CLOTHING_DIGITIGRADE_MASK))
|
||||
building_icon = wear_digi_version(
|
||||
base_icon = building_icon || icon(file2use, t_state),
|
||||
item = src,
|
||||
@@ -879,22 +873,21 @@ generate/load female uniform sprites matching all previously decided variables
|
||||
return .
|
||||
|
||||
// Underwear, Undershirts & Socks
|
||||
var/active_bodyshapes = get_active_bodyshapes()
|
||||
if(underwear)
|
||||
var/datum/sprite_accessory/clothing/underwear/undie_accessory = SSaccessories.underwear_list[underwear]
|
||||
var/mutable_appearance/underwear_overlay = undie_accessory?.make_appearance(underwear_color, physique, active_bodyshapes)
|
||||
var/mutable_appearance/underwear_overlay = undie_accessory?.make_appearance(underwear_color, physique, bodyshape)
|
||||
if(underwear_overlay)
|
||||
. += underwear_overlay
|
||||
|
||||
if(undershirt)
|
||||
var/datum/sprite_accessory/clothing/undershirt/shirt_accessory = SSaccessories.undershirt_list[undershirt]
|
||||
var/mutable_appearance/shirt_overlay = shirt_accessory?.make_appearance(null, physique, active_bodyshapes)
|
||||
var/mutable_appearance/shirt_overlay = shirt_accessory?.make_appearance(null, physique, bodyshape)
|
||||
if(shirt_overlay)
|
||||
. += shirt_overlay
|
||||
|
||||
if(socks && num_legs >= 2 && !(bodyshape & BODYSHAPE_DIGITIGRADE))
|
||||
var/datum/sprite_accessory/clothing/socks/sock_accessory = SSaccessories.socks_list[socks]
|
||||
var/mutable_appearance/socks_overlay = sock_accessory?.make_appearance(null, physique, active_bodyshapes)
|
||||
var/mutable_appearance/socks_overlay = sock_accessory?.make_appearance(null, physique, bodyshape)
|
||||
if(socks_overlay)
|
||||
. += socks_overlay
|
||||
|
||||
@@ -970,44 +963,6 @@ generate/load female uniform sprites matching all previously decided variables
|
||||
update_eyes()
|
||||
update_hair()
|
||||
|
||||
/**
|
||||
* Used to perform regular updates to the limbs of humans with special bodyshapes
|
||||
*
|
||||
* * check_shapes: The bodyshapes to check for.
|
||||
* Any limbs or organs which share this shape, will be updated.
|
||||
* * ignore_slots: The slots to ignore when updating the limbs.
|
||||
* This is useful for things like digitigrade legs, where we can skip some slots that we're already updating.
|
||||
*
|
||||
* return an integer, the number of limbs updated
|
||||
*/
|
||||
/mob/living/carbon/human/proc/check_body_shape(check_shapes = BODYSHAPE_DIGITIGRADE|BODYSHAPE_SNOUTED, ignore_slots = NONE)
|
||||
. = 0
|
||||
if(!(bodyshape & check_shapes))
|
||||
// optimization - none of our limbs or organs have the desired shape
|
||||
return .
|
||||
|
||||
for(var/obj/item/bodypart/limb as anything in get_bodyparts())
|
||||
var/checked_bodyshape = limb.bodyshape
|
||||
// accounts for stuff like snouts
|
||||
for(var/obj/item/organ/organ in limb)
|
||||
checked_bodyshape |= organ.external_bodyshapes
|
||||
|
||||
// any limb needs to be updated, so stop here and do it
|
||||
if(checked_bodyshape & check_shapes)
|
||||
. = update_body_parts()
|
||||
break
|
||||
|
||||
if(!.)
|
||||
return
|
||||
// hardcoding this here until bodypart updating is more sane
|
||||
// we need to update clothing items that may have been affected by bodyshape updates
|
||||
if(check_shapes & BODYSHAPE_DIGITIGRADE)
|
||||
for(var/obj/item/thing as anything in get_equipped_items(INCLUDE_PROSTHETICS|INCLUDE_ABSTRACT))
|
||||
if(thing.slot_flags & ignore_slots)
|
||||
continue
|
||||
if(thing.supports_variations_flags & DIGITIGRADE_VARIATIONS)
|
||||
thing.update_slot_icon()
|
||||
|
||||
// Hooks into human apply overlay so that we can modify all overlays applied through standing overlays to our height system.
|
||||
// Some of our overlays will be passed through a displacement filter to make our mob look taller or shorter.
|
||||
// Some overlays can't be displaced as they're too close to the edge of the sprite or cross the middle point in a weird way.
|
||||
|
||||
@@ -260,7 +260,10 @@
|
||||
* * removed_slots - slots that were removed from obscured_slots
|
||||
*/
|
||||
/mob/living/carbon/proc/item_coverage_changed(added_slots, removed_slots)
|
||||
SEND_SIGNAL(src, COMSIG_CARBON_ITEM_COVERAGE_CHANGED, added_slots, removed_slots)
|
||||
update_clothing(hidden_slots_to_inventory_slots(added_slots|removed_slots))
|
||||
if((added_slots|removed_slots) & HIDESNOUT)
|
||||
synchronize_bodyshapes()
|
||||
if((added_slots|removed_slots) & (HIDEHAIR|HIDEFACIALHAIR))
|
||||
update_hair()
|
||||
if((added_slots|removed_slots) & HIDEEYES)
|
||||
|
||||
@@ -1146,6 +1146,8 @@
|
||||
/obj/item/bodypart/proc/update_limb(dropping_limb = FALSE, is_creating = FALSE)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
|
||||
SEND_SIGNAL(src, COMSIG_BODYPART_UPDATED, dropping_limb, is_creating)
|
||||
|
||||
if(IS_ORGANIC_LIMB(src))
|
||||
// Try to add a cached blood type data, we must do it in here because for some reason DNA gets initialized AFTER the mob's limbs are created.
|
||||
// Should be fine as this gets called before all the important stuff happens
|
||||
@@ -1783,6 +1785,22 @@
|
||||
return
|
||||
REMOVE_TRAIT(owner, old_trait, bodypart_trait_source)
|
||||
|
||||
/// Add a bodyshape to the bodypart, then synchronize with the owner if necessary
|
||||
/obj/item/bodypart/proc/add_bodyshape(new_shape)
|
||||
if(bodyshape & new_shape)
|
||||
return
|
||||
|
||||
bodyshape |= new_shape
|
||||
owner?.synchronize_bodyshapes()
|
||||
|
||||
/// Remove a bodyshape from the bodypart, then synchronize with the owner if necessary
|
||||
/obj/item/bodypart/proc/remove_bodyshape(old_shape)
|
||||
if(!(bodyshape & old_shape))
|
||||
return
|
||||
|
||||
bodyshape &= ~old_shape
|
||||
owner?.synchronize_bodyshapes()
|
||||
|
||||
/// Add one or multiple surgical states to the bodypart
|
||||
/obj/item/bodypart/proc/add_surgical_state(new_states)
|
||||
if(!new_states)
|
||||
|
||||
@@ -284,17 +284,10 @@
|
||||
all_limb_flags |= organ.external_bodyshapes
|
||||
all_limb_flags |= limb.bodyshape
|
||||
|
||||
bodyshape = all_limb_flags
|
||||
if(obscured_slots & HIDESNOUT)
|
||||
all_limb_flags &= ~BODYSHAPE_SNOUTED
|
||||
|
||||
/// Get all bodyshapes but filter out bodyshapes that are currently being hidden
|
||||
/mob/living/carbon/proc/get_active_bodyshapes()
|
||||
var/active_shapes = bodyshape
|
||||
// future todo: both of these are state based, maybe we can just remove relevant bodyshapes directly. would remove the need for this proc
|
||||
if((active_shapes & BODYSHAPE_DIGITIGRADE) && is_digitigrade_squished())
|
||||
active_shapes &= ~BODYSHAPE_DIGITIGRADE
|
||||
if((active_shapes & BODYSHAPE_SNOUTED) && (obscured_slots & HIDESNOUT))
|
||||
active_shapes &= ~BODYSHAPE_SNOUTED
|
||||
return active_shapes
|
||||
bodyshape = all_limb_flags
|
||||
|
||||
/proc/skintone2hex(skin_tone)
|
||||
. = 0
|
||||
|
||||
@@ -51,50 +51,26 @@
|
||||
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) \
|
||||
|| (obscured_slots & 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
|
||||
species_id = SPECIES_LIZARD
|
||||
bodyshape = BODYSHAPE_HUMANOID | BODYSHAPE_DIGITIGRADE
|
||||
bodyshape = BODYSHAPE_HUMANOID
|
||||
footprint_sprite = FOOTPRINT_SPRITE_CLAWS
|
||||
footstep_type = FOOTSTEP_MOB_CLAW
|
||||
|
||||
/obj/item/bodypart/leg/left/digitigrade/update_limb(dropping_limb = FALSE, is_creating = FALSE)
|
||||
/obj/item/bodypart/leg/left/digitigrade/Initialize(mapload)
|
||||
. = ..()
|
||||
limb_id = owner?.is_digitigrade_squished() ? SPECIES_LIZARD : BODYPART_ID_DIGITIGRADE
|
||||
AddComponent(/datum/component/digitigrade_limb, SPECIES_LIZARD, initial(limb_id))
|
||||
|
||||
/obj/item/bodypart/leg/right/digitigrade
|
||||
icon_greyscale = 'icons/mob/human/species/lizard/bodyparts.dmi'
|
||||
limb_id = BODYPART_ID_DIGITIGRADE
|
||||
species_id = SPECIES_LIZARD
|
||||
bodyshape = BODYSHAPE_HUMANOID | BODYSHAPE_DIGITIGRADE
|
||||
bodyshape = BODYSHAPE_HUMANOID
|
||||
footprint_sprite = FOOTPRINT_SPRITE_CLAWS
|
||||
footstep_type = FOOTSTEP_MOB_CLAW
|
||||
|
||||
/obj/item/bodypart/leg/right/digitigrade/update_limb(dropping_limb = FALSE, is_creating = FALSE)
|
||||
/obj/item/bodypart/leg/right/digitigrade/Initialize(mapload)
|
||||
. = ..()
|
||||
limb_id = owner?.is_digitigrade_squished() ? SPECIES_LIZARD : BODYPART_ID_DIGITIGRADE
|
||||
AddComponent(/datum/component/digitigrade_limb, SPECIES_LIZARD, initial(limb_id))
|
||||
|
||||
@@ -481,10 +481,6 @@
|
||||
. = ..()
|
||||
AddElement(/datum/element/blood_limb_overlay)
|
||||
|
||||
/obj/item/bodypart/leg/left/skeleton/nonfunctional/update_limb(dropping_limb = FALSE, is_creating = FALSE)
|
||||
. = ..()
|
||||
limb_id = ((bodyshape & BODYSHAPE_DIGITIGRADE) && owner?.is_digitigrade_squished()) ? initial(limb_id) : "[initial(limb_id)]_[BODYPART_ID_DIGITIGRADE]"
|
||||
|
||||
/obj/item/bodypart/leg/right/skeleton/nonfunctional
|
||||
limb_id = BODYPART_ID_BONE
|
||||
disabling_threshold_percentage = 0
|
||||
@@ -493,10 +489,6 @@
|
||||
. = ..()
|
||||
AddElement(/datum/element/blood_limb_overlay)
|
||||
|
||||
/obj/item/bodypart/leg/right/skeleton/nonfunctional/update_limb(dropping_limb = FALSE, is_creating = FALSE)
|
||||
. = ..()
|
||||
limb_id = ((bodyshape & BODYSHAPE_DIGITIGRADE) && owner?.is_digitigrade_squished()) ? initial(limb_id) : "[initial(limb_id)]_[BODYPART_ID_DIGITIGRADE]"
|
||||
|
||||
///MUSHROOM
|
||||
/obj/item/bodypart/head/mushroom
|
||||
limb_id = SPECIES_MUSHROOM
|
||||
|
||||
@@ -1187,6 +1187,7 @@
|
||||
#include "code\datums\components\defaceable.dm"
|
||||
#include "code\datums\components\dejavu.dm"
|
||||
#include "code\datums\components\deployable.dm"
|
||||
#include "code\datums\components\digitigrade_linb.dm"
|
||||
#include "code\datums\components\direct_explosive_trap.dm"
|
||||
#include "code\datums\components\earprotection.dm"
|
||||
#include "code\datums\components\echolocation.dm"
|
||||
|
||||
Reference in New Issue
Block a user