From ddb6f3c316d51851bf829e76cab3905eec3d80a4 Mon Sep 17 00:00:00 2001
From: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com>
Date: Sun, 11 Aug 2024 18:54:46 -0400
Subject: [PATCH] Wounds Atomization: repairing clothes (#10782)
* finished, basically
* 515
* fix broken overlays
---
code/__DEFINES/obj_flags.dm | 8 +-
code/__HELPERS/type2type.dm | 16 ++
code/_onclick/item_attack.dm | 41 +--
code/datums/traits/negative_quirk.dm | 2 +-
code/game/objects/obj_defense.dm | 1 +
code/modules/clothing/clothing.dm | 241 ++++++++++++++----
code/modules/clothing/glasses/_glasses.dm | 2 +-
code/modules/clothing/gloves/_gloves.dm | 12 +-
code/modules/clothing/head/_head.dm | 2 +-
code/modules/clothing/masks/_masks.dm | 2 +-
code/modules/clothing/shoes/_shoes.dm | 2 +-
.../clothing/spacesuits/_spacesuits.dm | 5 +-
code/modules/clothing/suits/_suits.dm | 2 +-
code/modules/clothing/under/_under.dm | 8 +-
.../mob/living/carbon/human/human_defense.dm | 13 +
code/modules/ninja/suit/gloves.dm | 2 +-
16 files changed, 274 insertions(+), 85 deletions(-)
diff --git a/code/__DEFINES/obj_flags.dm b/code/__DEFINES/obj_flags.dm
index c5d69146da015..ccb1c97b78797 100644
--- a/code/__DEFINES/obj_flags.dm
+++ b/code/__DEFINES/obj_flags.dm
@@ -50,7 +50,13 @@
#define SCAN_BOOZEPOWER (1<<12) //! Allows helmets and glasses to scan reagents.
#define MASKEXTENDRANGE (1<<13) //! For masks, allows you to breathe from internals on adjecent tiles
#define NOTCONSUMABLE (1<<14) //! Moths cannot eat clothing with that flag
-#define HEADINTERNALS (1<<15) //! Headgear/helmet allows internals
+/// Headgear/helmet allows internals
+#define HEADINTERNALS (1<<18)
+
+/// Integrity defines for clothing (not flags but close enough)
+#define CLOTHING_PRISTINE 0 // We have no damage on the clothing
+#define CLOTHING_DAMAGED 1 // There's some damage on the clothing but it still has at least one functioning bodypart and can be equipped
+#define CLOTHING_SHREDDED 2 // The clothing is useless and cannot be equipped unless repaired first
/// Flags for the organ_flags var on /obj/item/organ
diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm
index 17d0f18859353..9e97d2b6c031e 100644
--- a/code/__HELPERS/type2type.dm
+++ b/code/__HELPERS/type2type.dm
@@ -175,6 +175,22 @@
. = "NONE"
return .
+/// For finding out what body parts a body zone covers, the inverse of the below basically
+/proc/body_zone2cover_flags(def_zone)
+ switch(def_zone)
+ if(BODY_ZONE_CHEST)
+ return CHEST|GROIN
+ if(BODY_ZONE_HEAD)
+ return HEAD
+ if(BODY_ZONE_L_ARM)
+ return ARM_LEFT|HAND_LEFT
+ if(BODY_ZONE_R_ARM)
+ return ARM_RIGHT|HAND_RIGHT
+ if(BODY_ZONE_L_LEG)
+ return LEG_LEFT|FOOT_LEFT
+ if(BODY_ZONE_R_LEG)
+ return LEG_RIGHT|FOOT_RIGHT
+
/// Converts an RGB color to an HSL color
/proc/rgb2hsl(red, green, blue)
red /= 255;green /= 255;blue /= 255;
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index bebe1933939a6..86011abca63a6 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -81,20 +81,21 @@
return I.attack(src, user)
/**
- * Called from [/mob/living/attackby]
- *
- * Arguments:
- * * mob/living/M - The mob being hit by this item
- * * mob/living/user - The mob hitting with this item
- */
-/obj/item/proc/attack(mob/living/M, mob/living/user)
- var/signal_return = SEND_SIGNAL(src, COMSIG_ITEM_ATTACK, M, user)
+ * Called from [/mob/living/proc/attackby]
+ *
+ * Arguments:
+ * * mob/living/target_mob - The mob being hit by this item
+ * * mob/living/user - The mob hitting with this item
+ * * params - Click params of this attack
+ */
+/obj/item/proc/attack(mob/living/M, mob/living/user, params)
+ var/signal_return = SEND_SIGNAL(src, COMSIG_ITEM_ATTACK, M, user, params)
if(signal_return & COMPONENT_CANCEL_ATTACK_CHAIN)
return TRUE
if(signal_return & COMPONENT_SKIP_ATTACK)
return
- SEND_SIGNAL(user, COMSIG_MOB_ITEM_ATTACK, M, user)
+ SEND_SIGNAL(user, COMSIG_MOB_ITEM_ATTACK, M, user, params)
SEND_SIGNAL(M, COMSIG_MOB_ITEM_ATTACKBY, user, src)
var/nonharmfulhit = FALSE
@@ -165,17 +166,17 @@
/mob/living/attacked_by(obj/item/I, mob/living/user)
send_item_attack_message(I, user)
- if(I.force)
- var/armour_block = run_armor_check(null, MELEE, armour_penetration = I.armour_penetration)
- apply_damage(I.force, I.damtype, blocked = armour_block)
- if(I.damtype == BRUTE)
- if(prob(33))
- I.add_mob_blood(src)
- var/turf/location = get_turf(src)
- add_splatter_floor(location)
- if(get_dist(user, src) <= 1) //people with TK won't get smeared with blood
- user.add_mob_blood(src)
- return TRUE //successful attack
+ if(!I.force)
+ return FALSE
+ var/armour_block = run_armor_check(null, MELEE, armour_penetration = I.armour_penetration)
+ apply_damage(I.force, I.damtype, blocked = armour_block)
+ if(I.damtype == BRUTE && prob(33))
+ I.add_mob_blood(src)
+ var/turf/location = get_turf(src)
+ add_splatter_floor(location)
+ if(get_dist(user, src) <= 1) //people with TK won't get smeared with blood
+ user.add_mob_blood(src)
+ return TRUE //successful attack
/mob/living/simple_animal/attacked_by(obj/item/I, mob/living/user, nonharmfulhit = FALSE)
if(I.force < force_threshold || I.damtype == STAMINA || nonharmfulhit)
diff --git a/code/datums/traits/negative_quirk.dm b/code/datums/traits/negative_quirk.dm
index d20380451137a..561f23594f8cf 100644
--- a/code/datums/traits/negative_quirk.dm
+++ b/code/datums/traits/negative_quirk.dm
@@ -141,7 +141,7 @@
var/mob/living/carbon/human/H = quirk_target
var/obj/item/heirloom_type
- if(is_species(H, /datum/species/moth) && prob(50))
+ if((ismoth(H)) && prob(50))
heirloom_type = /obj/item/flashlight/lantern/heirloom_moth
else
switch(quirk_holder.assigned_role)
diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm
index 0aef759471a2a..3aeaa50a71511 100644
--- a/code/game/objects/obj_defense.dm
+++ b/code/game/objects/obj_defense.dm
@@ -296,6 +296,7 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e
//what happens when the obj's integrity reaches zero.
/obj/proc/obj_destruction(damage_flag)
+
if(damage_flag == ACID)
acid_melt()
else if(damage_flag == FIRE)
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index 747308300863a..723509ef40772 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -11,7 +11,7 @@
resistance_flags = FLAMMABLE
max_integrity = 200
integrity_failure = 0.4
- var/damaged_clothes = 0 //similar to machine's BROKEN stat and structure's broken var
+ var/damaged_clothes = CLOTHING_PRISTINE //similar to machine's BROKEN stat and structure's broken var
var/flash_protect = 0 //What level of bright light protection item has. 1 = Flashers, Flashes, & Flashbangs | 2 = Welding | -1 = OH GOD WELDING BURNT OUT MY RETINAS
var/bang_protect = 0 //what level of sound protection the item has. 1 is the level of a normal bowman.
var/tint = 0 //Sets the item's level of visual impairment tint, normally set to the same as flash_protect
@@ -31,6 +31,9 @@
var/clothing_flags = NONE
+ /// What items can be consumed to repair this clothing (must by an /obj/item/stack)
+ var/repairable_by = /obj/item/stack/sheet/cotton/cloth
+
var/can_be_bloody = TRUE
//Var modification - PLEASE be careful with this I know who you are and where you live
@@ -51,6 +54,13 @@
var/high_pressure_multiplier = 1
var/static/list/high_pressure_multiplier_types = list(MELEE, BULLET, LASER, ENERGY, BOMB)
+ /// How much clothing damage has been dealt to each of the limbs of the clothing, assuming it covers more than one limb
+ var/list/damage_by_parts
+ /// How much integrity is in a specific limb before that limb is disabled (for use in [/obj/item/clothing/proc/take_damage_zone], and only if we cover multiple zones.) Set to 0 to disable shredding.
+ var/limb_integrity = 0
+ /// How many zones (body parts, not precise) we have disabled so far, for naming purposes
+ var/zones_disabled
+
/// A lazily initiated "food" version of the clothing for moths
var/obj/item/food/clothing/moth_snack
@@ -113,26 +123,127 @@
else
qdel(src)
-/obj/item/clothing/attack(mob/attacker, mob/user, def_zone)
- if(user.a_intent != INTENT_HARM && (ismoth(attacker) || ispsyphoza(attacker)) && !(clothing_flags & NOTCONSUMABLE) && !(resistance_flags & INDESTRUCTIBLE) && (armor.getRating(MELEE) == 0))
- if (isnull(moth_snack))
- moth_snack = new
- moth_snack.name = name
- moth_snack.clothing = WEAKREF(src)
- moth_snack.attack(attacker, user, def_zone)
- else
- return ..()
+/obj/item/clothing/attack(mob/attacker, mob/user, params)
+ if(user.a_intent == INTENT_HARM)
+ return //Harm intent does not eat
+ //if(!ismoth(attacker) || !ispsyphoza(attacker))
+ // return ..() //Not a clotheater species? No Clotheating!
+ //if((clothing_flags & NOTCONSUMABLE) && (resistance_flags & INDESTRUCTIBLE) && (armor.getRating(MELEE) != 0))
+ // return ..() //Any remaining flags that make eating it impossible?
+
+ if (isnull(moth_snack))
+ moth_snack = new
+ moth_snack.name = name
+ moth_snack.clothing = WEAKREF(src)
+ moth_snack.attack(attacker, user, params)
/obj/item/clothing/attackby(obj/item/W, mob/user, params)
- if(damaged_clothes && istype(W, /obj/item/stack/sheet/cotton/cloth))
- var/obj/item/stack/sheet/cotton/cloth/C = W
- C.use(1)
- update_clothes_damaged_state(FALSE)
- obj_integrity = max_integrity
- to_chat(user, "You fix the damage on [src] with [C].")
- return 1
+ if(!istype(W, repairable_by))
+ return ..()
+
+ switch(damaged_clothes)
+ if(CLOTHING_PRISTINE)
+ return..()
+ if(CLOTHING_DAMAGED)
+ var/obj/item/stack/cloth_repair = W
+ cloth_repair.use(1)
+ repair(user, params)
+ return TRUE
+ if(CLOTHING_SHREDDED)
+ var/obj/item/stack/cloth_repair = W
+ if(cloth_repair.amount < 3)
+ to_chat(user, "You require 3 [cloth_repair.name] to repair [src].")
+ return TRUE
+ to_chat(user, "You begin fixing the damage to [src] with [cloth_repair]...")
+ if(!do_after(user, 6 SECONDS, src) || !cloth_repair.use(3))
+ return TRUE
+ repair(user, params)
+ return TRUE
+
return ..()
+/// Set the clothing's integrity back to 100%, remove all damage to bodyparts, and generally fix it up
+/obj/item/clothing/proc/repair(mob/user, params)
+ update_clothes_damaged_state(CLOTHING_PRISTINE)
+ obj_integrity = max_integrity
+ name = initial(name) // remove "tattered" or "shredded" if there's a prefix
+ body_parts_covered = initial(body_parts_covered)
+ slot_flags = initial(slot_flags)
+ damage_by_parts = null
+ if(user)
+ UnregisterSignal(user, COMSIG_MOVABLE_MOVED)
+ to_chat(user, "You fix the damage on [src].")
+ update_appearance()
+
+/**
+ * take_damage_zone() is used for dealing damage to specific bodyparts on a worn piece of clothing, meant to be called from [/obj/item/bodypart/proc/check_woundings_mods()]
+ *
+ * This proc only matters when a bodypart that this clothing is covering is harmed by a direct attack (being on fire or in space need not apply), and only if this clothing covers
+ * more than one bodypart to begin with. No point in tracking damage by zone for a hat, and I'm not cruel enough to let you fully break them in a few shots.
+ * Also if limb_integrity is 0, then this clothing doesn't have bodypart damage enabled so skip it.
+ *
+ * Arguments:
+ * * def_zone: The bodypart zone in question
+ * * damage_amount: Incoming damage
+ * * damage_type: BRUTE or BURN
+ * * armour_penetration: If the attack had armour_penetration
+ */
+/obj/item/clothing/proc/take_damage_zone(def_zone, damage_amount, damage_type, armour_penetration)
+ if(!def_zone || !limb_integrity || (initial(body_parts_covered) in GLOB.bitflags)) // the second check sees if we only cover one bodypart anyway and don't need to bother with this
+ return
+ var/list/covered_limbs = body_parts_covered2organ_names(body_parts_covered) // what do we actually cover?
+ if(!(def_zone in covered_limbs))
+ return
+
+ var/damage_dealt = take_damage(damage_amount * 0.1, damage_type, armour_penetration, FALSE) * 10 // only deal 10% of the damage to the general integrity damage, then multiply it by 10 so we know how much to deal to limb
+ LAZYINITLIST(damage_by_parts)
+ damage_by_parts[def_zone] += damage_dealt
+ if(damage_by_parts[def_zone] > limb_integrity)
+ disable_zone(def_zone, damage_type)
+
+/**
+ * disable_zone() is used to disable a given bodypart's protection on our clothing item, mainly from [/obj/item/clothing/proc/take_damage_zone()]
+ *
+ * This proc disables all protection on the specified bodypart for this piece of clothing: it'll be as if it doesn't cover it at all anymore (because it won't!)
+ * If every possible bodypart has been disabled on the clothing, we put it out of commission entirely and mark it as shredded, whereby it will have to be repaired in
+ * order to equip it again. Also note we only consider it damaged if there's more than one bodypart disabled.
+ *
+ * Arguments:
+ * * def_zone: The bodypart zone we're disabling
+ * * damage_type: Only really relevant for the verb for describing the breaking, and maybe obj_destruction()
+ */
+/obj/item/clothing/proc/disable_zone(def_zone, damage_type)
+ var/list/covered_limbs = body_parts_covered2organ_names(body_parts_covered)
+ if(!(def_zone in covered_limbs))
+ return
+
+ var/zone_name = parse_zone(def_zone)
+ var/break_verb = ((damage_type == BRUTE) ? "torn" : "burned")
+
+ if(iscarbon(loc))
+ var/mob/living/carbon/C = loc
+ C.visible_message("The [zone_name] on [C]'s [src.name] is [break_verb] away!", "The [zone_name] on your [src.name] is [break_verb] away!", vision_distance = COMBAT_MESSAGE_RANGE)
+ RegisterSignal(C, COMSIG_MOVABLE_MOVED, PROC_REF(bristle))
+
+ zones_disabled++
+ for(var/i in body_zone2cover_flags(def_zone))
+ body_parts_covered &= ~i
+
+ if(body_parts_covered == NONE) // if there are no more parts to break then the whole thing is kaput
+ obj_destruction((damage_type == BRUTE ? "melee" : "laser")) // melee/laser is good enough since this only procs from direct attacks anyway and not from fire/bombs
+ return
+
+ switch(zones_disabled)
+ if(1)
+ name = "damaged [initial(name)]"
+ if(2)
+ name = "mangy [initial(name)]"
+ if(3 to INFINITY) // take better care of your shit, dude
+ name = "tattered [initial(name)]"
+
+ update_clothes_damaged_state(CLOTHING_DAMAGED)
+ update_appearance()
+
/obj/item/clothing/Destroy()
user_vars_remembered = null //Oh god somebody put REFERENCES in here? not to worry, we'll clean it up
QDEL_NULL(moth_snack)
@@ -142,6 +253,8 @@
..()
if(!istype(user))
return
+ UnregisterSignal(user, COMSIG_MOVABLE_MOVED)
+
if(LAZYLEN(user_vars_remembered))
for(var/variable in user_vars_remembered)
if(variable in user.vars)
@@ -154,7 +267,10 @@
if (!istype(user))
return
if(slot_flags & slot) //Was equipped to a valid slot for this item?
- if (LAZYLEN(user_vars_to_edit))
+ if(iscarbon(user) && LAZYLEN(zones_disabled))
+ RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(bristle))
+
+ if(LAZYLEN(user_vars_to_edit))
for(var/variable in user_vars_to_edit)
if(variable in user.vars)
LAZYSET(user_vars_remembered, variable, user.vars[variable])
@@ -162,6 +278,10 @@
/obj/item/clothing/examine(mob/user)
. = ..()
+ if(damaged_clothes == CLOTHING_SHREDDED)
+ . += "[p_theyre(TRUE)] completely shredded and require[p_s()] mending before [p_they()] can be worn again!"
+ return
+
switch (max_heat_protection_temperature)
if (400 to 1000)
. += "[src] offers the wearer limited protection from fire."
@@ -169,22 +289,17 @@
. += "[src] offers the wearer some protection from fire."
if (1601 to 35000)
. += "[src] offers the wearer robust protection from fire."
- if(damaged_clothes)
- . += "It looks damaged!"
- /* Bodypart wounds-related shit for when we eventually port https://github.com/tgstation/tgstation/pull/50558
- *
for(var/zone in damage_by_parts)
var/pct_damage_part = damage_by_parts[zone] / limb_integrity * 100
var/zone_name = parse_zone(zone)
switch(pct_damage_part)
if(100 to INFINITY)
- . += span_warning("The [zone_name] is useless and requires mending!")
+ . += "The [zone_name] is useless and requires mending!"
if(60 to 99)
- . += span_warning("The [zone_name] is heavily shredded!")
+ . += "The [zone_name] is heavily shredded!"
if(30 to 59)
- . += span_danger("The [zone_name] is partially shredded.")
- */
+ . += "The [zone_name] is partially shredded."
var/datum/component/storage/pockets = GetComponent(/datum/component/storage)
if(pockets)
@@ -276,32 +391,31 @@
/obj/item/clothing/obj_break(damage_flag)
. = ..()
- if(!damaged_clothes)
- update_clothes_damaged_state(TRUE)
- if(ismob(loc)) //It's not important enough to warrant a message if nobody's wearing it
- var/mob/M = loc
- to_chat(M, "Your [name] starts to fall apart!")
+ update_clothes_damaged_state(CLOTHING_DAMAGED)
+
+ if(isliving(loc)) //It's not important enough to warrant a message if it's not on someone
+ var/mob/living/M = loc
+ if(src in M.get_equipped_items(FALSE))
+ to_chat(M, "Your [name] start[p_s()] to fall apart!")
+ else
+ to_chat(M, "[src] start[p_s()] to fall apart!")
//This mostly exists so subtypes can call appriopriate update icon calls on the wearer.
-/obj/item/clothing/proc/update_clothes_damaged_state(damaging = TRUE)
- if(damaging)
- damaged_clothes = 1
- else
- damaged_clothes = 0
+/obj/item/clothing/proc/update_clothes_damaged_state(damaged_state = CLOTHING_DAMAGED)
+ damaged_clothes = damaged_state
/obj/item/clothing/update_overlays()
. = ..()
if(!damaged_clothes)
return
- var/initial_icon = initial(icon)
- var/index = "[REF(initial_icon)]-[initial(icon_state)]"
+ var/index = "[REF(icon)]-[icon_state]"
var/static/list/damaged_clothes_icons = list()
var/icon/damaged_clothes_icon = damaged_clothes_icons[index]
if(!damaged_clothes_icon)
- damaged_clothes_icon = icon(icon, icon_state, null, 1)
- damaged_clothes_icon.Blend("#fff", ICON_ADD) //fills the icon_state with white (except where it's transparent)
+ damaged_clothes_icon = icon(icon, icon_state, , 1)
+ damaged_clothes_icon.Blend("#fff", ICON_ADD) //fills the icon_state with white (except where it's transparent)
damaged_clothes_icon.Blend(icon('icons/effects/item_damage.dmi', "itemdamaged"), ICON_MULTIPLY) //adds damage effect and the remaining white areas become transparant
damaged_clothes_icon = fcopy_rsc(damaged_clothes_icon)
damaged_clothes_icons[index] = damaged_clothes_icon
@@ -314,15 +428,15 @@ SEE_MOBS // can see all mobs, no matter what
SEE_OBJS // can see all objs, no matter what
SEE_TURFS // can see all turfs (and areas), no matter what
SEE_PIXELS// if an object is located on an unlit area, but some of its pixels are
- // in a lit area (via pixel_x,y or smooth movement), can see those pixels
+ // in a lit area (via pixel_x,y or smooth movement), can see those pixels
BLIND // can't see anything
*/
/proc/generate_female_clothing(index,t_color,icon,type)
- var/icon/female_clothing_icon = icon("icon"=icon, "icon_state"=t_color)
+ var/icon/female_clothing_icon = icon("icon"=icon, "icon_state"=t_color)
var/icon/female_s = icon("icon"='icons/mob/clothing/under/masking_helpers.dmi', "icon_state"="[(type == FEMALE_UNIFORM_FULL) ? "female_full" : "female_top"]")
female_clothing_icon.Blend(female_s, ICON_MULTIPLY)
- female_clothing_icon = fcopy_rsc(female_clothing_icon)
+ female_clothing_icon = fcopy_rsc(female_clothing_icon)
GLOB.female_clothing_icons[index] = female_clothing_icon
/obj/item/clothing/under/proc/set_sensors(mob/user)
@@ -436,11 +550,19 @@ BLIND // can't see anything
fitted = NO_FEMALE_UNIFORM
if(!alt_covers_chest) // for the special snowflake suits that expose the chest when adjusted
body_parts_covered &= ~CHEST
+ body_parts_covered &= ~ARMS
else
fitted = initial(fitted)
envirosealed = initial(envirosealed)
if(!alt_covers_chest)
body_parts_covered |= CHEST
+ body_parts_covered |= ARMS
+ if(!LAZYLEN(damage_by_parts))
+ return adjusted
+ for(var/zone in list(BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)) // ugly check to make sure we don't reenable protection on a disabled part
+ if(damage_by_parts[zone] > limb_integrity)
+ for(var/part in body_zone2cover_flags(zone))
+ body_parts_covered &= part
return adjusted
/obj/item/clothing/proc/weldingvisortoggle(mob/user) //proc to toggle welding visors on helmets, masks, goggles, etc.
@@ -484,12 +606,13 @@ BLIND // can't see anything
return 1
return 0
+/obj/item/clothing/proc/_spawn_shreds()
+ new /obj/effect/decal/cleanable/shreds(get_turf(src), name)
+
/obj/item/clothing/obj_destruction(damage_flag)
- if(damage_flag == BOMB || damage_flag == MELEE)
- var/turf/T = get_turf(src)
- spawn(1) //so the shred survives potential turf change from the explosion.
- var/obj/effect/decal/cleanable/shreds/Shreds = new(T)
- Shreds.desc = "The sad remains of what used to be [name]."
+ if(damage_flag == BOMB)
+ //so the shred survives potential turf change from the explosion.
+ addtimer(CALLBACK(src, PROC_REF(_spawn_shreds)), 1)
deconstruct(FALSE)
if(damage_flag == CONSUME) //This allows for moths to fully consume clothing, rather than damaging it like other sources like brute
var/turf/current_position = get_turf(src)
@@ -498,9 +621,31 @@ BLIND // can't see anything
var/mob/living/possessing_mob = loc
possessing_mob.visible_message("[src] is consumed until naught but shreds remains!", "[src] falls apart into little bits!")
deconstruct(FALSE)
+ else if(!(damage_flag in list(ACID, FIRE)))
+ body_parts_covered = NONE
+ slot_flags = NONE
+ update_clothes_damaged_state(CLOTHING_SHREDDED)
+ if(isliving(loc))
+ var/mob/living/M = loc
+ if(src in M.get_equipped_items(FALSE)) //make sure they were wearing it and not attacking the item in their hands
+ M.visible_message("[M]'s [src.name] fall[p_s()] off, [p_theyre()] completely shredded!", "Your [src.name] fall[p_s()] off, [p_theyre()] completely shredded!", vision_distance = COMBAT_MESSAGE_RANGE)
+ M.dropItemToGround(src)
+ else
+ M.visible_message("[src] fall[p_s()] apart, completely shredded!", vision_distance = COMBAT_MESSAGE_RANGE)
+ name = "shredded [initial(name)]" // change the name -after- the message, not before.
+ update_appearance()
else
..()
+/// If we're a clothing with at least 1 shredded/disabled zone, give the wearer a periodic heads up letting them know their clothes are damaged
+/obj/item/clothing/proc/bristle(mob/living/L)
+ SIGNAL_HANDLER
+
+ if(!istype(L))
+ return
+ if(prob(0.2))
+ to_chat(L, "The damaged threads on your [src.name] chafe!")
+
/obj/item/clothing/get_armor_rating(d_type, mob/wearer)
. = ..()
if(high_pressure_multiplier == 1)
diff --git a/code/modules/clothing/glasses/_glasses.dm b/code/modules/clothing/glasses/_glasses.dm
index 1c81e72e5dffe..7eb20bdca3c0c 100644
--- a/code/modules/clothing/glasses/_glasses.dm
+++ b/code/modules/clothing/glasses/_glasses.dm
@@ -31,7 +31,7 @@
/obj/item/clothing/glasses/examine(mob/user)
. = ..()
if(glass_colour_type && ishuman(user))
- . += "Alt-click to toggle its colors."
+ . += "Alt-click to toggle [p_their()] colors."
/obj/item/clothing/glasses/update_overlays()
. = ..()
diff --git a/code/modules/clothing/gloves/_gloves.dm b/code/modules/clothing/gloves/_gloves.dm
index 1dbe7fdaab4e1..7c601c0c419f4 100644
--- a/code/modules/clothing/gloves/_gloves.dm
+++ b/code/modules/clothing/gloves/_gloves.dm
@@ -31,12 +31,14 @@
/obj/item/clothing/gloves/worn_overlays(mutable_appearance/standing, isinhands = FALSE, icon_file, item_layer, atom/origin)
. = list()
if(!isinhands)
- if(damaged_clothes)
- . += mutable_appearance('icons/effects/item_damage.dmi', "damagedgloves", item_layer)
- if(HAS_BLOOD_DNA(src))
- . += mutable_appearance('icons/effects/blood.dmi', "bloodyhands", item_layer)
+ return
+
+ if(damaged_clothes)
+ . += mutable_appearance('icons/effects/item_damage.dmi', "damagedgloves", item_layer)
+ if(HAS_BLOOD_DNA(src))
+ . += mutable_appearance('icons/effects/blood.dmi', "bloodyhands", item_layer)
-/obj/item/clothing/gloves/update_clothes_damaged_state(damaging = TRUE)
+/obj/item/clothing/gloves/update_clothes_damaged_state(damaged_state = CLOTHING_DAMAGED)
..()
if(ismob(loc))
var/mob/M = loc
diff --git a/code/modules/clothing/head/_head.dm b/code/modules/clothing/head/_head.dm
index 464766aff8062..48d68753eecb8 100644
--- a/code/modules/clothing/head/_head.dm
+++ b/code/modules/clothing/head/_head.dm
@@ -143,7 +143,7 @@
if(HAS_BLOOD_DNA(src))
. += mutable_appearance('icons/effects/blood.dmi', "helmetblood", item_layer)
-/obj/item/clothing/head/update_clothes_damaged_state(damaging = TRUE)
+/obj/item/clothing/head/update_clothes_damaged_state(damaged_state = CLOTHING_DAMAGED)
..()
if(ismob(loc))
var/mob/M = loc
diff --git a/code/modules/clothing/masks/_masks.dm b/code/modules/clothing/masks/_masks.dm
index 9540fed92cca0..e25003b96afd4 100644
--- a/code/modules/clothing/masks/_masks.dm
+++ b/code/modules/clothing/masks/_masks.dm
@@ -47,7 +47,7 @@
if(HAS_BLOOD_DNA(src))
. += mutable_appearance('icons/effects/blood.dmi', "maskblood", item_layer)
-/obj/item/clothing/mask/update_clothes_damaged_state(damaging = TRUE)
+/obj/item/clothing/mask/update_clothes_damaged_state(damaged_state = CLOTHING_DAMAGED)
..()
if(ismob(loc))
var/mob/M = loc
diff --git a/code/modules/clothing/shoes/_shoes.dm b/code/modules/clothing/shoes/_shoes.dm
index 6c5e6d1a16b43..7470dc01e32df 100644
--- a/code/modules/clothing/shoes/_shoes.dm
+++ b/code/modules/clothing/shoes/_shoes.dm
@@ -61,7 +61,7 @@
if(offset && equipped_before_drop)
restore_offsets(user)
-/obj/item/clothing/shoes/update_clothes_damaged_state(damaging = TRUE)
+/obj/item/clothing/shoes/update_clothes_damaged_state(damaged_state = CLOTHING_DAMAGED)
..()
if(ismob(loc))
var/mob/M = loc
diff --git a/code/modules/clothing/spacesuits/_spacesuits.dm b/code/modules/clothing/spacesuits/_spacesuits.dm
index f753d1e455d3e..10f1173c51507 100644
--- a/code/modules/clothing/spacesuits/_spacesuits.dm
+++ b/code/modules/clothing/spacesuits/_spacesuits.dm
@@ -38,7 +38,10 @@
permeability_coefficient = 0.02
clothing_flags = NOTCONSUMABLE | STOPSPRESSUREDAMAGE | THICKMATERIAL
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
- allowed = list(/obj/item/flashlight, /obj/item/tank/internals)
+ allowed = list(
+ /obj/item/flashlight,
+ /obj/item/tank/internals,
+ )
slowdown = 1
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 50, FIRE = 80, ACID = 70, STAMINA = 10, BLEED = 50)
flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
diff --git a/code/modules/clothing/suits/_suits.dm b/code/modules/clothing/suits/_suits.dm
index 3ddbb1945e747..a2411a769ca29 100644
--- a/code/modules/clothing/suits/_suits.dm
+++ b/code/modules/clothing/suits/_suits.dm
@@ -37,7 +37,7 @@
if(A.above_suit)
. += U.accessory_overlay
-/obj/item/clothing/suit/update_clothes_damaged_state(damaging = TRUE)
+/obj/item/clothing/suit/update_clothes_damaged_state(damaged_state = CLOTHING_DAMAGED)
..()
if(ismob(loc))
var/mob/M = loc
diff --git a/code/modules/clothing/under/_under.dm b/code/modules/clothing/under/_under.dm
index 2b1d78cfd6b5f..fbbe7af58d8dd 100644
--- a/code/modules/clothing/under/_under.dm
+++ b/code/modules/clothing/under/_under.dm
@@ -42,14 +42,16 @@
if(!attach_accessory(I, user))
return ..()
-/obj/item/clothing/under/update_clothes_damaged_state(damaging = TRUE)
+/obj/item/clothing/under/update_clothes_damaged_state(damaged_state = CLOTHING_DAMAGED)
..()
if(ismob(loc))
var/mob/M = loc
M.update_inv_w_uniform()
- if(has_sensor > NO_SENSORS)
+ if(damaged_state == CLOTHING_SHREDDED && has_sensor > NO_SENSORS)
has_sensor = BROKEN_SENSORS
- update_sensors(NO_SENSORS)
+ else if(damaged_state == CLOTHING_PRISTINE && has_sensor == BROKEN_SENSORS)
+ has_sensor = HAS_SENSORS
+ update_sensors(NO_SENSORS)
/obj/item/clothing/under/Initialize(mapload)
. = ..()
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 701172cac1662..ff02f8efca6fb 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -47,6 +47,19 @@
protection *= 1 - CLAMP01(physiology.armor.getRating(d_type) / 100)
return (1 - protection) * 100
+///Get all the clothing on a specific body part
+/mob/living/carbon/human/proc/clothingonpart(obj/item/bodypart/def_zone)
+ var/list/covering_part = list()
+ var/list/body_parts = list(head, wear_mask, wear_suit, w_uniform, back, gloves, shoes, belt, s_store, glasses, ears, wear_id, wear_neck) //Everything but pockets. Pockets are l_store and r_store. (if pockets were allowed, putting something armored, gloves or hats for example, would double up on the armor)
+ for(var/bp in body_parts)
+ if(!bp)
+ continue
+ if(bp && istype(bp , /obj/item/clothing))
+ var/obj/item/clothing/C = bp
+ if(C.body_parts_covered & def_zone.body_part)
+ covering_part += C
+ return covering_part
+
/mob/living/carbon/human/on_hit(obj/projectile/P)
if(dna?.species)
dna.species.on_hit(P, src)
diff --git a/code/modules/ninja/suit/gloves.dm b/code/modules/ninja/suit/gloves.dm
index 4f5669b3dcfe6..4925002d6a842 100644
--- a/code/modules/ninja/suit/gloves.dm
+++ b/code/modules/ninja/suit/gloves.dm
@@ -78,4 +78,4 @@
/obj/item/clothing/gloves/space_ninja/examine(mob/user)
. = ..()
if(HAS_TRAIT_FROM(src, TRAIT_NODROP, NINJA_SUIT_TRAIT))
- . += "The energy drain mechanism is [candrain?"active":"inactive"]."
+ . += "[p_their(TRUE)] energy drain mechanism is [candrain?"active":"inactive"]."