diff --git a/code/__DEFINES/clothing.dm b/code/__DEFINES/clothing.dm
index 46b776f7ef7..4c99ff20ee1 100644
--- a/code/__DEFINES/clothing.dm
+++ b/code/__DEFINES/clothing.dm
@@ -7,3 +7,8 @@
#define AC_LIGHT 1
#define AC_MEDIUM 2
#define AC_HEAVY 3
+
+//Armor material categories
+#define ARMOR_MAT_PLATE 1
+#define ARMOR_MAT_FABRIC 2
+#define ARMOR_MAT_CHAINMAIL 3
diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm
index b5def483ec9..8f41221c38d 100644
--- a/code/__DEFINES/layers.dm
+++ b/code/__DEFINES/layers.dm
@@ -196,7 +196,7 @@
//-------------------- HUD ---------------------
//HUD layer defines
#define HUD_PLANE 1000
-#define HUD_RENDER_TARGET "HUD_RENDER_TARGETE"
+#define HUD_RENDER_TARGET "HUD_RENDER_TARGET"
#define ABOVE_HUD_PLANE 1100
#define ABOVE_HUD_RENDER_TARGET "ABOVE_HUD_RENDER_TARGET"
diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm
index d4bf081c269..ea83badafd3 100644
--- a/code/__DEFINES/preferences.dm
+++ b/code/__DEFINES/preferences.dm
@@ -47,6 +47,8 @@
#define DISABLE_RUNECHAT (1<<0)
#define DISABLE_HOVER_TEXT (1<<1)
#define DISABLE_BALLOON_ALERTS (1<<3)
+#define DISABLE_BALLOON_COMBAT (1<<4)
+#define DISABLE_BALLOON_EXP (1<<5)
#define PARALLAX_INSANE -1 //for show offs
#define PARALLAX_HIGH 0 //default.
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index b652a48abfd..ced7b22b9ef 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -1528,3 +1528,12 @@ GLOBAL_DATUM_INIT(fire_overlay, /mutable_appearance, mutable_appearance('icons/e
if(1 to 4)
if(alch_skill >= SKILL_LEVEL_EXPERT)
. += span_notice(" Smells faintly of [smell].")
+
+/obj/item/atom_break(damage_flag, silent)
+ . = ..()
+
+ if(!ismob(loc))
+ return
+
+ if(!silent)
+ balloon_alert_to_viewers(span_warning("[name]
breaks!"))
diff --git a/code/modules/antagonists/villain/neu_vampires/covens/coven_powers/fae_trickery.dm b/code/modules/antagonists/villain/neu_vampires/covens/coven_powers/fae_trickery.dm
index 2a4a7c4a91a..fbd0422382c 100644
--- a/code/modules/antagonists/villain/neu_vampires/covens/coven_powers/fae_trickery.dm
+++ b/code/modules/antagonists/villain/neu_vampires/covens/coven_powers/fae_trickery.dm
@@ -93,7 +93,7 @@
var/strength = 5
var/attached = 0
-/obj/item/clothing/face/goblin_mask/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
+/obj/item/clothing/face/goblin_mask/take_damage(damage_amount, damage_type, damage_flag, sound_effect, attack_dir, armor_penetration)
..()
if(atom_integrity < 90)
Die()
diff --git a/code/modules/balloon_alert/balloon_alert.dm b/code/modules/balloon_alert/balloon_alert.dm
index cc763515518..f1578907b9f 100644
--- a/code/modules/balloon_alert/balloon_alert.dm
+++ b/code/modules/balloon_alert/balloon_alert.dm
@@ -15,14 +15,14 @@
* * mob/viewer: The mob the text will be shown to. Nullable (But only in the form of it won't runtime).
* * text: The text to be shown to viewer. Must not be null.
*/
-/atom/proc/balloon_alert(mob/viewer, text)
+/atom/proc/balloon_alert(mob/viewer, text, balloon_flag)
SHOULD_NOT_SLEEP(TRUE)
- INVOKE_ASYNC(src, PROC_REF(balloon_alert_perform), viewer, text)
+ INVOKE_ASYNC(src, PROC_REF(balloon_alert_perform), viewer, text, balloon_flag)
/// Create balloon alerts (text that floats up) to everything within range.
/// Will only display to people who can see.
-/atom/proc/balloon_alert_to_viewers(message, self_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs)
+/atom/proc/balloon_alert_to_viewers(message, self_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, balloon_flag)
SHOULD_NOT_SLEEP(TRUE)
var/list/hearers = get_hearers_in_view(vision_distance, src, RECURSIVE_CONTENTS_CLIENT_MOBS)
@@ -38,12 +38,15 @@
// MeasureText blocks. I have no idea for how long.
// I would've made the maptext_height update on its own, but I don't know
// if this would look bad on laggy clients.
-/atom/proc/balloon_alert_perform(mob/viewer, text)
+/atom/proc/balloon_alert_perform(mob/viewer, text, balloon_flag)
var/client/viewer_client = viewer?.client
if(isnull(viewer_client))
return
- if(viewer.client?.prefs.toggles_maptext & DISABLE_BALLOON_ALERTS)
+ var/balloon_disabled = viewer_client.prefs.toggles_maptext & DISABLE_BALLOON_ALERTS
+ var/flag_disabled = viewer_client.prefs.toggles_maptext & balloon_flag
+
+ if(balloon_disabled || flag_disabled)
to_chat(viewer, span_emote("[name]: [text]"))
return
diff --git a/code/modules/clothing/armor/_armor.dm b/code/modules/clothing/armor/_armor.dm
index 9370e0708d3..43bb42eeca7 100644
--- a/code/modules/clothing/armor/_armor.dm
+++ b/code/modules/clothing/armor/_armor.dm
@@ -40,6 +40,8 @@
var/togglename = null
abstract_type = /obj/item/clothing/armor
+ material_category = ARMOR_MAT_PLATE
+
/obj/item/clothing/armor/worn_overlays(mutable_appearance/standing, isinhands = FALSE, icon_file, dummy_block = FALSE)
. = ..()
if(!isinhands)
diff --git a/code/modules/clothing/armor/chainmail.dm b/code/modules/clothing/armor/chainmail.dm
index 86529b4894c..fc19836d87c 100644
--- a/code/modules/clothing/armor/chainmail.dm
+++ b/code/modules/clothing/armor/chainmail.dm
@@ -19,6 +19,8 @@
max_integrity = INTEGRITY_STRONG
item_weight = 6 * STEEL_MULTIPLIER
+ material_category = ARMOR_MAT_CHAINMAIL
+
/obj/item/clothing/armor/chainmail/iron
name = "iron haubergeon"
desc = "Made out of interlocked iron rings. Offers good resistance against arrows, stabs and cuts. \nUsually worn as padding for proper armor."
diff --git a/code/modules/clothing/armor/gambesson.dm b/code/modules/clothing/armor/gambesson.dm
index 81338725bde..5e7fe543f92 100644
--- a/code/modules/clothing/armor/gambesson.dm
+++ b/code/modules/clothing/armor/gambesson.dm
@@ -21,6 +21,8 @@
body_parts_covered = COVERAGE_FULL
prevent_crits = ALL_EXCEPT_CHOP_AND_STAB
+ material_category = ARMOR_MAT_FABRIC
+
/obj/item/clothing/armor/gambeson/light
name = "light gambeson"
desc = "Thin and the maker skimped on the padding, typically worn by the peasantry to give some protection against cold for the whole body."
diff --git a/code/modules/clothing/armor/leather.dm b/code/modules/clothing/armor/leather.dm
index b3780c982e1..f8336bc63e2 100644
--- a/code/modules/clothing/armor/leather.dm
+++ b/code/modules/clothing/armor/leather.dm
@@ -21,6 +21,8 @@
salvage_result = /obj/item/natural/hide/cured
item_weight = 3.2
+ material_category = ARMOR_MAT_FABRIC
+
//THE ARMOUR VALUES OF ADVANCED AND MASTERWORK ARMOUR ARE INTENDED
//KEEP THIS IN MIND
diff --git a/code/modules/clothing/armor/misc.dm b/code/modules/clothing/armor/misc.dm
index 781915f84de..f13b4aeaec5 100644
--- a/code/modules/clothing/armor/misc.dm
+++ b/code/modules/clothing/armor/misc.dm
@@ -36,6 +36,8 @@
item_weight = 7 * IRON_MULTIPLIER
min_cold_protection_temperature = 5 //this is like fur but also its a fucking bikini like???
+ material_category = ARMOR_MAT_CHAINMAIL
+
//................ Brigandine ............... //
/obj/item/clothing/armor/brigandine
name = "brigandine"
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index 07c5661ba55..1d20688f26f 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -79,6 +79,9 @@
var/proper_drying = FALSE
COOLDOWN_DECLARE(wet_stress_cd)
+ /// Defines for damage sounds, see [_DEFINES/clothing] and [pick_damage_sound]
+ var/material_category = ARMOR_MAT_FABRIC
+
/obj/item/clothing/Initialize()
. = ..()
if(ispath(pocket_storage_component_path))
@@ -585,3 +588,64 @@ BLIND // can't see anything
if(COOLDOWN_FINISHED(src, wet_stress_cd))
COOLDOWN_START(src, wet_stress_cd, 60 SECONDS)
C.add_stress(/datum/stress_event/wet_cloth)
+
+/obj/item/clothing/take_damage(damage_amount, damage_type, damage_flag, sound_effect, attack_dir, armor_penetration)
+ . = ..()
+ if(!. || !ismob(loc))
+ return
+
+ var/damage_dealt = .
+
+ var/max_int = max_integrity - (max_integrity * integrity_failure)
+ var/cur_int = max(atom_integrity - (max_integrity * integrity_failure), 0)
+ var/old_int = min(damage_dealt + cur_int, max_integrity)
+
+ var/ratio = cur_int / max_int
+ var/ratio_old = old_int / max_int
+
+ var/text
+ var/sound
+
+ if(ratio <= 0.75 && ratio_old > 0.75)
+ text = "Armor
marred"
+ sound = pick_damage_sound(1)
+ if(ratio <= 0.5 && ratio_old > 0.5)
+ text = "Armor
damaged"
+ sound = pick_damage_sound(2)
+ if(ratio <= 0.25 && ratio_old > 0.25)
+ text = "Armor
sundered"
+ sound = pick_damage_sound(3)
+
+ if(sound)
+ playsound(src, sound, 100, TRUE)
+
+ if(text)
+ balloon_alert_to_viewers(text, balloon_flag = DISABLE_BALLOON_COMBAT)
+
+/obj/item/clothing/proc/pick_damage_sound(tier)
+ var/picked_sound
+ switch(material_category)
+ if(ARMOR_MAT_PLATE)
+ switch(tier)
+ if(1)
+ return 'sound/combat/armor_degrade_plate1.ogg'
+ if(2)
+ return 'sound/combat/armor_degrade_plate2.ogg'
+ if(3)
+ return 'sound/combat/armor_degrade_plate3.ogg'
+ if(ARMOR_MAT_CHAINMAIL)
+ switch(tier)
+ if(1)
+ return 'sound/combat/armor_degrade_chain1.ogg'
+ if(2)
+ return 'sound/combat/armor_degrade_chain2.ogg'
+ if(3)
+ return 'sound/combat/armor_degrade_chain3.ogg'
+ if(ARMOR_MAT_FABRIC)
+ switch(tier)
+ if(1)
+ return 'sound/combat/armor_degrade_leather1.ogg'
+ if(2)
+ return 'sound/combat/armor_degrade_leather2.ogg'
+ if(3)
+ return 'sound/combat/armor_degrade_leather3.ogg'
diff --git a/code/modules/clothing/face/masks.dm b/code/modules/clothing/face/masks.dm
index d98aa51d99d..10d48304b24 100644
--- a/code/modules/clothing/face/masks.dm
+++ b/code/modules/clothing/face/masks.dm
@@ -44,6 +44,8 @@
melting_material = /datum/material/iron
melt_amount = 50
+ material_category = ARMOR_MAT_PLATE
+
/obj/item/clothing/face/facemask/goldnosechain
name = "gold nosechain"
icon_state = "nosechain_g"
diff --git a/code/modules/clothing/gloves/chain.dm b/code/modules/clothing/gloves/chain.dm
index be6e287e9b7..2e2cafd7f12 100644
--- a/code/modules/clothing/gloves/chain.dm
+++ b/code/modules/clothing/gloves/chain.dm
@@ -24,6 +24,8 @@
melting_material = /datum/material/steel
melt_amount = 50
+ material_category = ARMOR_MAT_CHAINMAIL
+
/obj/item/clothing/gloves/chain/psydon
name = "grenzelhoftian chain gauntlets"
icon_state = "psydongloveschain"
diff --git a/code/modules/clothing/gloves/plate.dm b/code/modules/clothing/gloves/plate.dm
index aa3979f3e15..d34863ba325 100644
--- a/code/modules/clothing/gloves/plate.dm
+++ b/code/modules/clothing/gloves/plate.dm
@@ -25,6 +25,8 @@
grid_height = 32
item_weight = 7 * IRON_MULTIPLIER
+ material_category = ARMOR_MAT_PLATE
+
/obj/item/clothing/gloves/plate/ancient
name = "ancient gauntlets"
desc = "Ancient plated gauntlets made out of steel."
diff --git a/code/modules/clothing/gloves/rare.dm b/code/modules/clothing/gloves/rare.dm
index a9790e4e156..3427718debd 100644
--- a/code/modules/clothing/gloves/rare.dm
+++ b/code/modules/clothing/gloves/rare.dm
@@ -21,6 +21,8 @@
prevent_crits = ALL_CRITICAL_HITS
abstract_type = /obj/item/clothing/gloves/rare
+ material_category = ARMOR_MAT_PLATE
+
/obj/item/clothing/gloves/rare/elfplate
name = "dark elf plate gauntlets"
desc = "Plate gauntlets of mystic dark elven alloy, lightweight yet incredibly protective. Typically worn by elite bladesingers."
diff --git a/code/modules/clothing/head/helmets/_helmet.dm b/code/modules/clothing/head/helmets/_helmet.dm
index 4ee1f0d631d..bc9b45028bd 100644
--- a/code/modules/clothing/head/helmets/_helmet.dm
+++ b/code/modules/clothing/head/helmets/_helmet.dm
@@ -19,3 +19,5 @@
grid_height = 64
grid_width = 64
abstract_type = /obj/item/clothing/head/helmet
+
+ material_category = ARMOR_MAT_PLATE
diff --git a/code/modules/clothing/head/helmets/leather.dm b/code/modules/clothing/head/helmets/leather.dm
index 2b7048c8b3f..7475eced227 100644
--- a/code/modules/clothing/head/helmets/leather.dm
+++ b/code/modules/clothing/head/helmets/leather.dm
@@ -21,6 +21,8 @@
salvage_result = /obj/item/natural/hide/cured
item_weight = 1.6
+ material_category = ARMOR_MAT_FABRIC
+
//THE ARMOUR VALUES OF ADVANCED AND MASTERWORK HELMETS ARE INTENDED
//KEEP THIS IN MIND
diff --git a/code/modules/clothing/neck/misc.dm b/code/modules/clothing/neck/misc.dm
index c3924ff4c45..ea9ed8e7a83 100644
--- a/code/modules/clothing/neck/misc.dm
+++ b/code/modules/clothing/neck/misc.dm
@@ -253,6 +253,7 @@
max_integrity = INTEGRITY_STRONGEST
prevent_crits = ALL_EXCEPT_BLUNT
+ material_category = ARMOR_MAT_CHAINMAIL
/obj/item/clothing/neck/chaincoif/AdjustClothes(mob/user)
if(loc == user)
@@ -333,6 +334,8 @@
max_integrity = INTEGRITY_STRONGEST
prevent_crits = ALL_EXCEPT_STAB
+ material_category = ARMOR_MAT_PLATE
+
/obj/item/clothing/neck/bevor/Initialize()
. = ..()
ADD_TRAIT(src, TRAIT_HARD_TO_STEAL, TRAIT_GENERIC)
@@ -369,6 +372,8 @@
max_integrity = INTEGRITY_STRONG
prevent_crits = ALL_EXCEPT_STAB
+ material_category = ARMOR_MAT_PLATE
+
/obj/item/clothing/neck/gorget/Initialize()
. = ..()
ADD_TRAIT(src, TRAIT_HARD_TO_STEAL, TRAIT_GENERIC)
@@ -530,6 +535,8 @@
max_integrity = INTEGRITY_STRONGEST
prevent_crits = ALL_EXCEPT_BLUNT
+ material_category = ARMOR_MAT_CHAINMAIL
+
/obj/item/clothing/neck/highcollier/AdjustClothes(mob/user)
if(loc == user)
if(adjustable == CAN_CADJUST)
diff --git a/code/modules/clothing/pants/chain_legs.dm b/code/modules/clothing/pants/chain_legs.dm
index caa2381a7b5..a6febda44ec 100644
--- a/code/modules/clothing/pants/chain_legs.dm
+++ b/code/modules/clothing/pants/chain_legs.dm
@@ -27,6 +27,8 @@
prevent_crits = ALL_EXCEPT_BLUNT
item_weight = 6 * STEEL_MULTIPLIER
+ material_category = ARMOR_MAT_CHAINMAIL
+
/obj/item/clothing/pants/chainlegs/Initialize()
. = ..()
AddComponent(/datum/component/item_equipped_movement_rustle)
diff --git a/code/modules/clothing/pants/plate_legs.dm b/code/modules/clothing/pants/plate_legs.dm
index d4c4141d814..ee615963ed4 100644
--- a/code/modules/clothing/pants/plate_legs.dm
+++ b/code/modules/clothing/pants/plate_legs.dm
@@ -28,6 +28,8 @@
prevent_crits = ALL_EXCEPT_BLUNT
item_weight = 9 * STEEL_MULTIPLIER
+ material_category = ARMOR_MAT_PLATE
+
/obj/item/clothing/pants/platelegs/Initialize()
. = ..()
AddComponent(/datum/component/item_equipped_movement_rustle, custom_sounds = SFX_PLATE_STEP)
diff --git a/code/modules/clothing/shoes/boots.dm b/code/modules/clothing/shoes/boots.dm
index 945276cb12c..af73c328189 100644
--- a/code/modules/clothing/shoes/boots.dm
+++ b/code/modules/clothing/shoes/boots.dm
@@ -34,6 +34,8 @@
sellprice = 25
item_weight = 7 * STEEL_MULTIPLIER
+ material_category = ARMOR_MAT_PLATE
+
/obj/item/clothing/shoes/boots/armor/light
name = "light plate boots"
icon_state = "soldierboots"
diff --git a/code/modules/clothing/shoes/rare.dm b/code/modules/clothing/shoes/rare.dm
index 3d9b06b4bf0..91927afe95a 100644
--- a/code/modules/clothing/shoes/rare.dm
+++ b/code/modules/clothing/shoes/rare.dm
@@ -19,6 +19,8 @@
max_integrity = INTEGRITY_STRONGEST
abstract_type = /obj/item/clothing/shoes/boots/rare
+ material_category = ARMOR_MAT_PLATE
+
/obj/item/clothing/shoes/boots/rare/elfplate
name = "dark elvish plated boots"
desc = "Bizarrely shaped boots of exquisite dark elven craftsmanship, forged from steel alloyed in ways unbeknownst to every other species."
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 620ae5571c6..80516d0fe07 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -1822,8 +1822,12 @@ GLOBAL_LIST_EMPTY(roundstart_species)
if(!selzone)
selzone = user.zone_selected
+
if(!accurate)
selzone = accuracy_check(selzone, user, H, I.associated_skill, user.used_intent, I)
+ if(selzone != user.zone_selected)
+ H.balloon_alert(user, "miss! [selzone]!", DISABLE_BALLOON_COMBAT)
+
affecting = H.get_bodypart(check_zone(selzone))
if(!affecting)
diff --git a/sound/combat/armor_degrade_chain1.ogg b/sound/combat/armor_degrade_chain1.ogg
new file mode 100644
index 00000000000..4abb188a22f
Binary files /dev/null and b/sound/combat/armor_degrade_chain1.ogg differ
diff --git a/sound/combat/armor_degrade_chain2.ogg b/sound/combat/armor_degrade_chain2.ogg
new file mode 100644
index 00000000000..45068c5ebed
Binary files /dev/null and b/sound/combat/armor_degrade_chain2.ogg differ
diff --git a/sound/combat/armor_degrade_chain3.ogg b/sound/combat/armor_degrade_chain3.ogg
new file mode 100644
index 00000000000..2ebb74c0db8
Binary files /dev/null and b/sound/combat/armor_degrade_chain3.ogg differ
diff --git a/sound/combat/armor_degrade_leather1.ogg b/sound/combat/armor_degrade_leather1.ogg
new file mode 100644
index 00000000000..98b9e3f712a
Binary files /dev/null and b/sound/combat/armor_degrade_leather1.ogg differ
diff --git a/sound/combat/armor_degrade_leather2.ogg b/sound/combat/armor_degrade_leather2.ogg
new file mode 100644
index 00000000000..df83c43f173
Binary files /dev/null and b/sound/combat/armor_degrade_leather2.ogg differ
diff --git a/sound/combat/armor_degrade_leather3.ogg b/sound/combat/armor_degrade_leather3.ogg
new file mode 100644
index 00000000000..6339567e61e
Binary files /dev/null and b/sound/combat/armor_degrade_leather3.ogg differ
diff --git a/sound/combat/armor_degrade_plate1.ogg b/sound/combat/armor_degrade_plate1.ogg
new file mode 100644
index 00000000000..1416711a1b6
Binary files /dev/null and b/sound/combat/armor_degrade_plate1.ogg differ
diff --git a/sound/combat/armor_degrade_plate2.ogg b/sound/combat/armor_degrade_plate2.ogg
new file mode 100644
index 00000000000..0405e8a0bb1
Binary files /dev/null and b/sound/combat/armor_degrade_plate2.ogg differ
diff --git a/sound/combat/armor_degrade_plate3.ogg b/sound/combat/armor_degrade_plate3.ogg
new file mode 100644
index 00000000000..dfd8089f893
Binary files /dev/null and b/sound/combat/armor_degrade_plate3.ogg differ