diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm
index 14068b818ef..f6c361f01c7 100644
--- a/code/__DEFINES/combat.dm
+++ b/code/__DEFINES/combat.dm
@@ -467,3 +467,9 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
#define DODGING_PENALTY 1
/// A define so the cooldown on the baited status and the duration of the baitcd status are the same
#define BAIT_COOLDOWN_TIME 15 SECONDS
+
+// try_crit keys for modifiers
+/// Chance modifier
+#define CRIT_MOD_CHANCE "crit_mod"
+/// Specifically knockout modifier for head crits
+#define CRIT_MOD_KNOCKOUT_CHANCE "knockout_mod"
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index 47dbc1b461f..5781231c251 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -436,8 +436,10 @@
var/dullfactor = 1
if(!I?.force)
return 0
+
// newforce starts here and is the default amount of damage the item does.
var/newforce = I.force
+
// If this weapon has no user and is somehow attacking you just return default.
if(!istype(user))
return newforce
@@ -445,33 +447,31 @@
var/dullness_ratio
if(I.max_blade_int && I.sharpness != IS_BLUNT)
dullness_ratio = I.blade_int / I.max_blade_int
- var/cont = FALSE
+
var/used_str = GET_MOB_ATTRIBUTE_VALUE(user, STAT_STRENGTH)
if(iscarbon(user))
var/mob/living/carbon/C = user
- /*
- * If you have a dominant hand which is assigned at
- * character creation. You suffer a -1 Str if your
- * no using the item in your dominant hand.
- * Check living/carbon/carbon.dm for more info.
- */
if(C.domhand)
used_str = C.get_str_arms(C.used_hand)
- //STR is +1 from STRONG stance and -1 from SWIFT stance
+
+ // Apply rmb intent modifiers
if(istype(user.rmb_intent, /datum/rmb_intent/strong))
used_str++
- if(istype(user.rmb_intent, /datum/rmb_intent/swift))
+ else if(istype(user.rmb_intent, /datum/rmb_intent/swift))
used_str--
- if(istype(user.rmb_intent, /datum/rmb_intent/weak))
+ else if(istype(user.rmb_intent, /datum/rmb_intent/weak))
used_str /= 2
+
//Your max STR is 20.
- used_str = CLAMP(used_str, 1, 20)
+ used_str = clamp(used_str, 1, 20)
+
//Vampire checks for Potence
if(ishuman(user))
var/mob/living/carbon/human/user_human = user
if(user_human.clan)
used_str += floor(0.5 * user_human.potence_weapon_buff)
// For each level of potence user gains 0.5 STR, at 5 Potence their STR buff is 2.5
+
if(used_str >= 11)
newforce = newforce + (newforce * ((used_str - 10) * 0.1))
if(dullness_ratio && (user.used_intent.blade_class in list(BCLASS_CHOP, BCLASS_CUT, BCLASS_STAB)))
@@ -488,8 +488,8 @@
if(HAS_TRAIT(I, TRAIT_WIELDED))
effective *= 0.75
//Strength influence is reduced to 30%
- if(effective > GET_MOB_ATTRIBUTE_VALUE(user, STAT_STRENGTH))
- newforce = max(newforce*0.3, 1)
+ if(effective > used_str)
+ newforce = max(newforce * 0.3, 1)
//Blade Dulling Starts here.
switch(blade_dulling)
@@ -503,7 +503,6 @@
else
dullfactor = 0.45 + (lumberskill * 0.15)
lumberjacker.mind.add_sleep_experience(/datum/attribute/skill/labor/lumberjacking, (GET_MOB_ATTRIBUTE_VALUE(lumberjacker, STAT_INTELLIGENCE)*0.2))
- cont = TRUE
if(BCLASS_CHOP)
//Additional damage for axes against trees.
if(istype(I, /obj/item/weapon))
@@ -515,51 +514,42 @@
dullfactor = 0.2
else
dullfactor = 1.5
- cont = TRUE
- if(!cont)
- return 0
+ else
+ return 0
if(DULLING_BASH) //stone/metal, can't be attacked by cutting
switch(user.used_intent.blade_class)
if(BCLASS_BLUNT)
- cont = TRUE
+ EMPTY_BLOCK_GUARD
if(BCLASS_SMASH)
dullfactor = 1.5
- cont = TRUE
if(BCLASS_DRILL)
dullfactor = 10
- cont = TRUE
if(BCLASS_PICK)
dullfactor = 1.5
- cont = TRUE
- if(!cont)
- return 0
+ else
+ return 0
if(DULLING_BASHCHOP) //structures that can be attacked by clubs also (doors fences etc)
switch(user.used_intent.blade_class)
if(BCLASS_CUT)
if(!I.remove_bintegrity(1, user))
dullfactor = 0.8
- cont = TRUE
if(BCLASS_CHOP)
if(!I.remove_bintegrity(1, user))
dullfactor = 0.8
else
dullfactor = 1.5
- cont = TRUE
if(BCLASS_SMASH)
dullfactor = 1.5
- cont = TRUE
if(BCLASS_DRILL)
dullfactor = 10
- cont = TRUE
if(BCLASS_BLUNT)
- cont = TRUE
+ EMPTY_BLOCK_GUARD
if(BCLASS_PICK)
var/mob/living/miner = user
var/mineskill = GET_MOB_SKILL_VALUE_OLD(miner, /datum/attribute/skill/labor/mining)
dullfactor = 1.6 - (mineskill * 0.1)
- cont = TRUE
- if(!cont)
- return 0
+ else
+ return 0
if(DULLING_PICK) //cannot deal damage if not a pick item. aka rock walls
if(user.body_position == LYING_DOWN)
to_chat(user, span_warning("I need to stand up to get a proper swing."))
@@ -595,23 +585,25 @@
var/damflerp = (dullness_ratio - SHARPNESS_TIER2_THRESHOLD) / (SHARPNESS_TIER1_THRESHOLD - SHARPNESS_TIER2_THRESHOLD)
newforce *= damflerp
newforce = round(newforce)
+
if(user.used_intent.get_chargetime() && user.client?.chargedprog < 100)
newforce = newforce * round(user.client?.chargedprog / 100, 0.1)
- // newforce = round(newforce, 1)
+
if(user.body_position == LYING_DOWN)
newforce *= 0.5
+
if(user.has_status_effect(/datum/status_effect/divine_strike))
newforce += 5
- // newforce is rounded upto the nearest intiger.
- newforce = round(newforce,1)
- //This is returning the maximum of the arguments meaning this is to prevent negative values.
- newforce = max(newforce, 1)
+
if(dullness_ratio)
if(dullness_ratio < SHARPNESS_TIER2_THRESHOLD && (user.used_intent.blade_class in list(BCLASS_CHOP, BCLASS_CUT, BCLASS_STAB)))
var/lerpratio = LERP(0, SHARPNESS_TIER2_THRESHOLD, (dullness_ratio / SHARPNESS_TIER2_THRESHOLD))
if(prob(33))
to_chat(user, span_info("The blade is dull..."))
newforce *= (lerpratio * 2)
+
+ newforce = max(1, round(newforce, DAMAGE_PRECISION))
+
return newforce
/mob/living/proc/simple_limb_hit(zone)
@@ -637,43 +629,54 @@
return "foreleg"
return zone
-/obj/item/proc/funny_attack_effects(mob/living/target, mob/living/user, nodmg)
+/obj/item/proc/funny_attack_effects(mob/living/target, mob/living/user)
return
/mob/living/attacked_by(obj/item/I, mob/living/user)
var/hitlim = simple_limb_hit(user.zone_selected)
I.funny_attack_effects(src, user)
- if(I.force)
- var/newforce = get_complex_damage(I, user)
- apply_damage(newforce, I.damtype, def_zone = hitlim)
- if(I.damtype == BRUTE)
- next_attack_msg.Cut()
- if(HAS_TRAIT(src, TRAIT_SIMPLE_WOUNDS))
- var/datum/wound/crit_wound = simple_woundcritroll(user.used_intent.blade_class, newforce, user, hitlim)
- if(crit_wound?.should_embed(I))
- // throw_alert("embeddedobject", /atom/movable/screen/alert/embeddedobject)
- simple_add_embedded_object(I, silent = FALSE, crit_message = TRUE)
- src.grabbedby(user, 1, item_override = I)
- var/haha = user.used_intent.blade_class
- if(newforce > 5)
- if(haha != BCLASS_BLUNT)
- 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)
- user.adjust_hygiene(-10)
- if(newforce > 15)
- if(haha == BCLASS_BLUNT)
- 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)
- user.adjust_hygiene(-10)
+ if(!I.force)
+ return FALSE
+
+ var/newforce = get_complex_damage(I, user)
+
+ apply_damage(newforce, I.damtype, def_zone = hitlim)
+
+ if(!cmode && !stat && user.m_intent == MOVE_INTENT_SNEAK && (dir == REVERSE_DIR(get_dir(src, user))))
+ var/blunt = (user.used_intent.blade_class == BCLASS_BLUNT)
+ var/attacker_sneaking = GET_MOB_SKILL_VALUE(user, /datum/attribute/skill/misc/sneaking)
+ if((blunt || I.wbalance >= HARD_TO_DODGE) && attacker_sneaking >= 10)
+ next_attack_msg += " [span_userdanger("SNEAK ATTACK!")]"
+ // Get extra damage as a percent of 50% extra based on skill
+ var/percentage = attacker_sneaking / (SKILL_LEVEL_LEGENDARY * 10)
+ newforce += (newforce * 0.5) * percentage
+
+ if(I.damtype == BRUTE)
+ if(HAS_TRAIT(src, TRAIT_SIMPLE_WOUNDS))
+ var/datum/wound/crit_wound = simple_woundcritroll(user.used_intent.blade_class, newforce, user, hitlim)
+ if(crit_wound?.should_embed(I))
+ // throw_alert("embeddedobject", /atom/movable/screen/alert/embeddedobject)
+ simple_add_embedded_object(I, silent = FALSE, crit_message = TRUE)
+ grabbedby(user, 1, item_override = I)
+ if(newforce > 5)
+ if(user.used_intent.blade_class != BCLASS_BLUNT)
+ 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)
+ user.adjust_hygiene(-10)
+ else if(newforce > 15)
+ if(user.used_intent.blade_class == BCLASS_BLUNT)
+ 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)
+ user.adjust_hygiene(-10)
+
send_item_attack_message(I, user, hitlim)
- if(I.force)
- return TRUE
+ return TRUE
/mob/living/simple_animal/attacked_by(obj/item/I, mob/living/user)
var/hitlim = simple_limb_hit(user.zone_selected)
@@ -820,17 +823,24 @@
return CLAMP(w_class * 6, 10, 100) // Multiply the item's weight class by 6, then clamp the value between 10 and 100
/mob/living/proc/send_item_attack_message(obj/item/I, mob/living/user, hit_area)
+ if(!I.force)
+ return
+
var/message_verb = "attacked"
if(user.used_intent)
message_verb = "[pick(user.used_intent.attack_verb)]"
- else if(!I.force)
- return
+
var/message_hit_area = ""
if(hit_area)
message_hit_area = " in the [hit_area]"
+
var/attack_message = "[user] [message_verb] [src][message_hit_area] with [I]!"
var/attack_message_local = "[user] [message_verb] me[message_hit_area] with [I]!"
- visible_message("[attack_message][next_attack_msg.Join()]",\
- "[attack_message_local][next_attack_msg.Join()]", null, COMBAT_MESSAGE_RANGE)
+ visible_message(
+ span_danger("[attack_message][next_attack_msg.Join()]"),
+ span_danger("[attack_message_local][next_attack_msg.Join()]"),
+ null,
+ COMBAT_MESSAGE_RANGE
+ )
next_attack_msg.Cut()
return 1
diff --git a/code/game/objects/items/weapons/melee/special.dm b/code/game/objects/items/weapons/melee/special.dm
index fdc9e8a8a24..4b46dc6787e 100644
--- a/code/game/objects/items/weapons/melee/special.dm
+++ b/code/game/objects/items/weapons/melee/special.dm
@@ -247,7 +247,7 @@
STOP_PROCESSING(SSobj, src)
. = ..()
-/obj/item/weapon/mace/stunmace/funny_attack_effects(mob/living/target, mob/living/user, nodmg)
+/obj/item/weapon/mace/stunmace/funny_attack_effects(mob/living/target, mob/living/user)
. = ..()
if(on)
target.electrocute_act(5, src)
diff --git a/code/modules/combat/_special_intent.dm b/code/modules/combat/_special_intent.dm
index b1c1fa76ff1..3175851f858 100644
--- a/code/modules/combat/_special_intent.dm
+++ b/code/modules/combat/_special_intent.dm
@@ -293,7 +293,7 @@
var/obj/item/bodypart/affecting = human_victim.get_bodypart(damage_zone)
var/armor_block = human_victim.run_armor_check(damage_zone, damage_type, damage = damage)
if(human_victim.apply_damage(damage, damage_type, affecting, armor_block))
- affecting?.bodypart_attacked_by(damage_class, damage, user, crit_message = TRUE, reduce_crit = 100)
+ affecting?.bodypart_attacked_by(damage_class, damage, user, crit_message = TRUE, modifiers = list(CRIT_MOD_CHANCE = -100))
message += " It pierces through to their flesh!"
playsound(human_victim, weapon.hitsound, 80, TRUE)
diff --git a/code/modules/crafting/alchemy/reagents.dm b/code/modules/crafting/alchemy/reagents.dm
index d13156db93a..2de225e49fb 100644
--- a/code/modules/crafting/alchemy/reagents.dm
+++ b/code/modules/crafting/alchemy/reagents.dm
@@ -394,7 +394,7 @@ If you want to expand on poisons theres tons of fun effects TG chemistry has tha
to_chat(graggar_lover, span_bloody("More... More..."))
var/obj/item/bodypart/bp = graggar_lover.get_bodypart()
bp?.lingering_pain += 10
- bp?.bodypart_attacked_by(BCLASS_BLUNT, 12, null, BODY_ZONE_CHEST, crit_message = FALSE, reduce_crit = 10)
+ bp?.bodypart_attacked_by(BCLASS_BLUNT, 12, null, BODY_ZONE_CHEST, crit_message = FALSE, modifiers = list(CRIT_MOD_CHANCE = -10))
M.do_jitter_animation(100)
if(60)
M.do_jitter_animation(150)
diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index b44852f1546..f2556ed7591 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -84,7 +84,7 @@
var/obj/item/bodypart/BP = get_bodypart(check_zone(def_zone))
if(BP)
var/newdam = P.damage * (100-blocked)/100
- BP.bodypart_attacked_by(P.woundclass, newdam, zone_precise = def_zone, crit_message = TRUE, reduce_crit = P.reduce_crit_chance)
+ BP.bodypart_attacked_by(P.woundclass, newdam, zone_precise = def_zone, crit_message = TRUE, modifiers = list(CRIT_MOD_CHANCE = -P.reduce_crit_chance))
return TRUE
/mob/living/carbon/check_projectile_embed(obj/projectile/P, def_zone, blocked)
@@ -202,55 +202,64 @@
/mob/living/carbon/attacked_by(obj/item/I, mob/living/user)
- var/obj/item/bodypart/affecting
var/useder = user.zone_selected
+
if(user.tempatarget)
useder = user.tempatarget
user.tempatarget = null
+
if(!lying_attack_check(user, I))
return
- affecting = get_bodypart(check_zone(useder)) //precise attacks, on yourself or someone you are grabbing
+
+ var/obj/item/bodypart/affecting = get_bodypart(check_zone(useder)) //precise attacks, on yourself or someone you are grabbing
if(!affecting) //missing limb
to_chat(user, span_warning("Unfortunately, there's nothing there."))
return FALSE
+
SEND_SIGNAL(I, COMSIG_ITEM_ATTACK_ZONE, src, user, affecting)
+
I.funny_attack_effects(src, user)
+
var/statforce = get_complex_damage(I, user)
- if(statforce)
- next_attack_msg.Cut()
- affecting.bodypart_attacked_by(user.used_intent.blade_class, statforce, crit_message = TRUE)
- apply_damage(statforce, I.damtype, affecting)
- if(I.damtype == BRUTE && affecting.status == BODYPART_ORGANIC)
- if(prob(statforce))
- I.add_mob_blood(src)
- user.update_inv_hands()
- 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)
- var/splatter_dir = get_dir(user, src)
- new /obj/effect/temp_visual/dir_setting/bloodsplatter(loc, splatter_dir, get_blood_type())
- if(affecting.body_zone == BODY_ZONE_HEAD)
- if(wear_mask)
- wear_mask.add_mob_blood(src)
- update_inv_wear_mask()
- if(wear_neck)
- wear_neck.add_mob_blood(src)
- update_inv_neck()
- if(head)
- head.add_mob_blood(src)
- update_inv_head()
if(user == src || pulledby == user)
send_item_attack_message(I, user, precise_attack_check(useder, affecting))
else
send_item_attack_message(I, user, affecting.name)
- if(statforce)
- var/probability = I.get_dismemberment_chance(affecting, user)
- if(prob(probability) && affecting.dismember(I.damtype, user.used_intent?.blade_class, user, user.zone_selected))
+ if(!statforce)
+ return TRUE
+
+ affecting.bodypart_attacked_by(user.used_intent.blade_class, statforce, crit_message = TRUE)
+
+ apply_damage(statforce, I.damtype, affecting)
+
+ if(I.damtype == BRUTE && affecting.status == BODYPART_ORGANIC)
+ if(prob(statforce))
I.add_mob_blood(src)
- return TRUE //successful attack
+ user.update_inv_hands()
+ 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)
+ var/splatter_dir = get_dir(user, src)
+ new /obj/effect/temp_visual/dir_setting/bloodsplatter(loc, splatter_dir, get_blood_type())
+ if(affecting.body_zone == BODY_ZONE_HEAD)
+ if(wear_mask)
+ wear_mask.add_mob_blood(src)
+ update_inv_wear_mask()
+ if(wear_neck)
+ wear_neck.add_mob_blood(src)
+ update_inv_neck()
+ if(head)
+ head.add_mob_blood(src)
+ update_inv_head()
+
+ var/probability = I.get_dismemberment_chance(affecting, user)
+ if(prob(probability) && affecting.dismember(I.damtype, user.used_intent?.blade_class, user, user.zone_selected))
+ I.add_mob_blood(src)
+
+ return TRUE //successful attack
/mob/living/carbon/attack_hand(mob/living/carbon/human/user)
. = ..()
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 84186abd7a5..7a781a2841d 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -173,22 +173,27 @@
var/final_block_chance = I.block_chance - (CLAMP((armor_penetration-I.armor_penetration)/2,0,100)) + block_chance_modifier //So armour piercing blades can still be parried by other blades, for example
if(I.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
return TRUE
+
if(head)
var/final_block_chance = head.block_chance - (CLAMP((armor_penetration-head.armor_penetration)/2,0,100)) + block_chance_modifier
if(head.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
return TRUE
+
if(wear_armor)
var/final_block_chance = wear_armor.block_chance - (CLAMP((armor_penetration-wear_armor.armor_penetration)/2,0,100)) + block_chance_modifier
if(wear_armor.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
return TRUE
+
if(wear_pants)
var/final_block_chance = wear_pants.block_chance - (CLAMP((armor_penetration-wear_pants.armor_penetration)/2,0,100)) + block_chance_modifier
if(wear_pants.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
return TRUE
+
if(wear_neck)
var/final_block_chance = wear_neck.block_chance - (CLAMP((armor_penetration-wear_neck.armor_penetration)/2,0,100)) + block_chance_modifier
if(wear_neck.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
return TRUE
+
return FALSE
/mob/living/carbon/human/proc/check_block()
@@ -238,19 +243,19 @@
if(!I || !user)
return 0
- var/obj/item/bodypart/affecting
var/useder = user.zone_selected
- if(!lying_attack_check(user,I))
+ if(!lying_attack_check(user, I))
return 0
+
var/accurate = FALSE
if(user.tempatarget)
useder = user.tempatarget
user.tempatarget = null
accurate = TRUE
- affecting = get_bodypart(check_zone(useder)) //precise attacks, on yourself or someone you are grabbing
-// else
-// affecting = get_bodypart_complex(user.used_intent.height2limb(user.aimheight)) //this proc picks a bodypart at random as long as it's in the height list
- if(!affecting) //missing limb
+
+ var/obj/item/bodypart/affecting = get_bodypart(check_zone(useder)) //precise attacks, on yourself or someone you are grabbing
+
+ if(!affecting)
to_chat(user, "Unfortunately, there's nothing there.")
return 0
@@ -340,8 +345,9 @@
next_attack_msg += " Armor stops the damage."
else
affecting.bodypart_attacked_by(M.a_intent.blade_class, damage - armor, M, dam_zone, crit_message = TRUE)
- visible_message("\The [M] [pick(M.a_intent.attack_verb)] [src]![next_attack_msg.Join()]", \
- "\The [M] [pick(M.a_intent.attack_verb)] me![next_attack_msg.Join()]", null, COMBAT_MESSAGE_RANGE)
+ visible_message(
+ "\The [M] [pick(M.a_intent.attack_verb)] [src]![next_attack_msg.Join()]", \
+ "\The [M] [pick(M.a_intent.attack_verb)] me![next_attack_msg.Join()]", null, COMBAT_MESSAGE_RANGE)
next_attack_msg.Cut()
if(nodmg)
return FALSE
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 7c5da50601c..5ebce1558cd 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -1469,7 +1469,7 @@ GLOBAL_LIST_EMPTY(roundstart_species)
if(affecting.body_zone == BODY_ZONE_HEAD)
SEND_SIGNAL(user, COMSIG_HEAD_PUNCHED, target)
log_combat(user, target, "punched")
- knockback(attacker_style, target, user, nodmg, actual_damage)
+ knockback(attacker_style, target, user, actual_damage)
if(!nodmg)
if(user.limb_destroyer)
@@ -1831,18 +1831,21 @@ GLOBAL_LIST_EMPTY(roundstart_species)
if(istype(M.used_intent, /datum/intent/unarmed))
harm(M, H, attacker_style)
+// We need to remove this
/datum/species/proc/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H, selzone, accurate = FALSE)
- // Allows you to put in item-specific reactions based on species
- if(user != H)
- if(H.can_see_cone(user))
- if(H.check_shields(I, I.force, "\the [I]", MELEE_ATTACK, I.armor_penetration))
- return 0
- if(H.check_block())
- H.visible_message("[H] blocks [I]!", \
- "I block [I]!")
- return 0
+ if(!I || !affecting)
+ return FALSE
- var/hit_area
+ if(user != H && H.can_see_cone(user))
+ if(H.check_shields(I, I.force, "\the [I]", MELEE_ATTACK, I.armor_penetration))
+ return FALSE
+
+ if(H.check_block())
+ H.visible_message(
+ "[H] blocks [I]!",
+ "I block [I]!"
+ )
+ return FALSE
if(!selzone)
selzone = user.zone_selected
@@ -1852,85 +1855,90 @@ GLOBAL_LIST_EMPTY(roundstart_species)
if(selzone != user.zone_selected)
H.balloon_alert(user, "miss! [selzone]!", DISABLE_BALLOON_COMBAT)
- affecting = H.get_bodypart(check_zone(selzone))
+ var/item_force = get_complex_damage(I, user) //to avoid runtimes on the forcesay checks at the bottom. Some items might delete themselves if you drop them. (stunning yourself, ninja swords)
- if(!affecting)
- return
+ // Only batons (Unused, will be refactored out at some point)
+ I.funny_attack_effects(H, user)
- hit_area = affecting.name
- var/def_zone = affecting.body_zone
+ if(!item_force)
+ SEND_SIGNAL(I, COMSIG_ITEM_SPEC_ATTACKEDBY, H, user, affecting, 0)
+ return
var/pen = I.armor_penetration
if(user.used_intent?.penfactor)
pen = I.armor_penetration + user.used_intent.penfactor
-// var/armor_block = H.run_armor_check(affecting, "melee", "My armor has protected my [hit_area]!", "My armor has softened a hit to my [hit_area]!",pen)
+ var/knockout_modifier = 0
+ if(!H.cmode && !H.stat && H.body_position != LYING_DOWN && user.m_intent == MOVE_INTENT_SNEAK && (H.dir == REVERSE_DIR(get_dir(H, user))))
+ var/blunt = (user.used_intent.blade_class == BCLASS_BLUNT)
+ var/attacker_sneaking = GET_MOB_SKILL_VALUE(user, /datum/attribute/skill/misc/sneaking)
+ if((blunt || I.wbalance >= HARD_TO_DODGE) && attacker_sneaking >= 10)
+ H.next_attack_msg += " [span_userdanger("SNEAK ATTACK!")]"
+ // Get extra damage as a percent of 50% extra based on skill
+ var/percentage = attacker_sneaking / (SKILL_LEVEL_LEGENDARY * 10)
+ if(blunt)
+ knockout_modifier = FLOOR(15 * percentage, 1)
+ item_force += (item_force * 0.5) * percentage
+ pen = 100
- var/Iforce = get_complex_damage(I, user) //to avoid runtimes on the forcesay checks at the bottom. Some items might delete themselves if you drop them. (stunning yourself, ninja swords)
- var/armor_block = H.run_armor_check(selzone, I.damage_type, "", "",pen, damage = Iforce, blade_dulling=user.used_intent.blade_class)
+ var/def_zone = affecting.body_zone
- var/nodmg = FALSE
+ var/armor_block = H.run_armor_check(selzone, I.damage_type, "", "", pen, damage = item_force, blade_dulling = user.used_intent.blade_class)
+ var/weakness = H.check_weakness(I, user)
+ var/actual_damage = apply_damage(item_force * weakness, I.damtype, def_zone, armor_block, H)
- var/actual_damage = Iforce
- if(Iforce)
+ if(!actual_damage)
+ H.next_attack_msg += " [span_danger(span_big("Armor stops the damage!"))]"
+ H.send_item_attack_message(I, user, parse_zone(selzone))
+ if(!QDELETED(I))
+ I.take_damage(1, BRUTE, I.damage_type)
+ return TRUE
- var/weakness = H.check_weakness(I, user)
- actual_damage = apply_damage(Iforce * weakness, I.damtype, def_zone, armor_block, H)
- H.next_attack_msg.Cut()
- if(!actual_damage)
- nodmg = TRUE
- H.next_attack_msg += " Armor stops the damage."
- if(!QDELETED(I))
- I.take_damage(1, BRUTE, I.damage_type)
- if(!nodmg)
- var/datum/wound/crit_wound = affecting.bodypart_attacked_by(user.used_intent.blade_class, (Iforce * weakness) * ((100-(armor_block))/100), user, selzone, crit_message = TRUE)
- if(crit_wound?.should_embed(I))
- var/can_impale = TRUE
- if(!affecting)
- can_impale = FALSE
- else if(I.wlength > WLENGTH_SHORT && !(affecting.body_zone in list(BODY_ZONE_CHEST, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)))
- can_impale = FALSE
- if(can_impale && user.Adjacent(H))
- affecting.add_embedded_object(I, silent = FALSE, crit_message = TRUE)
- H.emote("embed")
- affecting.receive_damage(I.embedding.embedded_unsafe_removal_pain_multiplier*I.w_class)//It hurts to rip it out, get surgery you dingus.
- user.put_in_hands(I)
- H.emote("pain", TRUE)
- playsound(H, 'sound/foley/flesh_rem.ogg', 100, TRUE, -2)
- I.do_special_attack_effect(user, affecting, intent, H, selzone)
- if(istype(user.used_intent, /datum/intent/effect) && selzone)
- var/datum/intent/effect/effect_intent = user.used_intent
- if(LAZYLEN(effect_intent.target_parts))
- if(selzone in effect_intent.target_parts)
- H.apply_status_effect(effect_intent.intent_effect)
- else
- H.apply_status_effect(effect_intent.intent_effect)
-// if(H.used_intent.blade_class == BCLASS_BLUNT && I.force >= 15 && affecting.body_zone == "chest")
-// var/turf/target_shove_turf = get_step(H.loc, get_dir(user.loc,H.loc))
-// H.throw_at(target_shove_turf, 1, 1, H, spin = FALSE)
+ var/datum/wound/bodypart_wound = affecting.bodypart_attacked_by(user.used_intent.blade_class, actual_damage, user, selzone, crit_message = TRUE, modifiers = list(CRIT_MOD_KNOCKOUT_CHANCE = knockout_modifier))
+ H.send_item_attack_message(I, user, parse_zone(selzone))
- I.funny_attack_effects(H, user, nodmg)
- knockback(I, H, user, nodmg, actual_damage)
+ if(bodypart_wound?.should_embed(I))
+ var/can_impale = TRUE
+ if(!affecting)
+ can_impale = FALSE
+ else if(I.wlength > WLENGTH_SHORT && !(affecting.body_zone in list(BODY_ZONE_CHEST, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)))
+ can_impale = FALSE
+ if(can_impale && user.Adjacent(H))
+ affecting.add_embedded_object(I, silent = FALSE, crit_message = TRUE)
+ H.emote("embed")
+ affecting.receive_damage(I.embedding.embedded_unsafe_removal_pain_multiplier * I.w_class)//It hurts to rip it out, get surgery you dingus.
+ user.put_in_hands(I)
+ H.emote("pain", TRUE)
+ playsound(H, 'sound/foley/flesh_rem.ogg', 100, TRUE, -2)
+
+ I.do_special_attack_effect(user, affecting, intent, H, selzone)
+
+ if(istype(user.used_intent, /datum/intent/effect) && selzone)
+ var/datum/intent/effect/effect_intent = user.used_intent
+ if(LAZYLEN(effect_intent.target_parts))
+ if(selzone in effect_intent.target_parts)
+ H.apply_status_effect(effect_intent.intent_effect)
+ else
+ H.apply_status_effect(effect_intent.intent_effect)
- H.send_item_attack_message(I, user, parse_zone(selzone))
- SEND_SIGNAL(I, COMSIG_ITEM_SPEC_ATTACKEDBY, H, user, affecting, actual_damage)
- if(nodmg)
- return FALSE //dont play a sound
+ knockback(I, H, user, actual_damage)
//dismemberment
- var/bloody = 0
+ var/bloody = FALSE
var/probability = I.get_dismemberment_chance(affecting, user)
if(affecting.brute_dam && prob(probability) && affecting.dismember(I.damtype, user.used_intent?.blade_class, user, selzone))
- bloody = 1
+ bloody = TRUE
I.add_mob_blood(H)
user.update_inv_hands()
- if(((I.damtype == BRUTE) && I.force && prob(25 + (I.force * 2))))
+ var/hit_area = affecting.name
+
+ if(((I.damtype == BRUTE) && actual_damage && prob(25 + (actual_damage * 2))))
if(affecting.status == BODYPART_ORGANIC)
I.add_mob_blood(H) //Make the weapon bloody, not the person.
user.update_inv_hands()
- if(prob(I.force * 2) || bloody) //blood spatter!
- bloody = 1
+ if(prob(actual_damage * 2) || bloody) //blood spatter!
+ bloody = TRUE
var/turf/location = H.loc
var/splatter_dir = get_dir(H, user)
new /obj/effect/temp_visual/dir_setting/bloodsplatter(H.loc, splatter_dir, H.get_blood_type())
@@ -1961,8 +1969,9 @@ GLOBAL_LIST_EMPTY(roundstart_species)
H.wear_pants.add_mob_blood(H)
H.update_inv_pants()
- if(Iforce > 10 || Iforce >= 5 && prob(Iforce))
+ if(actual_damage > 10 || actual_damage >= 5 && prob(actual_damage))
H.forcesay(GLOB.hit_appends) //forcesay checks stat already.
+
return TRUE
/datum/species/proc/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H, forced = FALSE, spread_damage = FALSE, flashes = TRUE)
@@ -2016,6 +2025,7 @@ GLOBAL_LIST_EMPTY(roundstart_species)
H.update_damage_overlays()
else//no bodypart, we deal damage with a more general method.
H.adjustBruteLoss(damage_amount)
+
if(BURN)
H.damageoverlaytemp = 20
damage_amount = forced ? damage : damage * hit_percent * H.physiology.burn_mod
@@ -2036,15 +2046,19 @@ GLOBAL_LIST_EMPTY(roundstart_species)
if(TOX)
damage_amount = forced ? damage : damage * hit_percent * H.physiology.tox_mod
H.adjustToxLoss(damage_amount)
+
if(OXY)
damage_amount = forced ? damage : damage * hit_percent * H.physiology.oxy_mod
H.adjustOxyLoss(damage_amount)
+
if(CLONE)
damage_amount = forced ? damage : damage * hit_percent * H.physiology.clone_mod
H.adjustCloneLoss(damage_amount)
+
if(BRAIN)
damage_amount = forced ? damage : damage * hit_percent * H.physiology.brain_mod
H.adjustOrganLoss(ORGAN_SLOT_BRAIN, damage_amount)
+
return damage_amount
/datum/species/proc/on_hit(obj/projectile/P, mob/living/carbon/human/H)
@@ -2468,48 +2482,58 @@ GLOBAL_LIST_EMPTY(roundstart_species)
T.wagging = FALSE
H.update_body_parts(TRUE)
-/datum/species/proc/knockback(obj/item/I, mob/living/target, mob/living/user, nodmg, actual_damage)
- if(!istype(I))
- if(!target.resting)
- var/chungus_str = GET_MOB_ATTRIBUTE_VALUE(target, STAT_STRENGTH)
- var/knockback_tiles = 0
- var/damage = actual_damage
- if(chungus_str >= 3)
- knockback_tiles = FLOOR(damage/((chungus_str - 2) * 4), 1)
- else
- knockback_tiles = FLOOR(damage/2, 1)
- if(knockback_tiles >= 1)
- var/turf/edge_target_turf = get_edge_target_turf(target, get_dir(user, target))
- if(istype(edge_target_turf))
- target.safe_throw_at(edge_target_turf, \
- knockback_tiles, \
- knockback_tiles, \
- user, \
- spin = FALSE, \
- force = target.move_force, \
- callback = CALLBACK(target, TYPE_PROC_REF(/mob/living, handle_knockback), get_turf(target)))
- else
- if(!I.force)
+/datum/species/proc/knockback(obj/item/I, mob/living/target, mob/living/user, actual_damage)
+ if(!actual_damage || target.resting)
+ return
+
+ if(istype(I) && I.force)
+ if(!user.used_intent.knockback)
return
- if(user.used_intent.knockback)
- if(!target.resting)
- var/endurance = GET_MOB_ATTRIBUTE_VALUE(target, STAT_ENDURANCE)
- var/knockback_tiles = 0
- var/newforce = actual_damage
- if(endurance >= 3)
- knockback_tiles = FLOOR(newforce/((endurance - 2) * 4), 1)
- else
- knockback_tiles = FLOOR(newforce/2, 1)
- if(knockback_tiles >= 1)
- var/turf/edge_target_turf = get_edge_target_turf(target, get_dir(user, target))
- if(istype(edge_target_turf))
- target.safe_throw_at(edge_target_turf, \
- knockback_tiles, \
- knockback_tiles, \
- user, \
- spin = FALSE, \
- force = target.move_force, \
- callback = CALLBACK(target, TYPE_PROC_REF(/mob/living, handle_knockback), get_turf(target)))
+ var/endurance = GET_MOB_ATTRIBUTE_VALUE(target, STAT_ENDURANCE)
+ var/knockback_tiles = 0
+ if(endurance >= 3)
+ knockback_tiles = FLOOR(actual_damage / ((endurance - 2) * 4), 1)
+ else
+ knockback_tiles = FLOOR(actual_damage / 2, 1)
+
+ if(knockback_tiles < 1)
+ return
+ var/turf/edge_target_turf = get_edge_target_turf(target, get_dir(user, target))
+ if(!istype(edge_target_turf))
+ return
+ target.safe_throw_at(
+ edge_target_turf,
+ knockback_tiles,
+ knockback_tiles,
+ user,
+ spin = FALSE,
+ force = target.move_force,
+ callback = CALLBACK(target, TYPE_PROC_REF(/mob/living, handle_knockback), get_turf(target)
+ ))
+ return
+
+ var/chungus_str = GET_MOB_ATTRIBUTE_VALUE(target, STAT_STRENGTH)
+ var/knockback_tiles = 0
+ if(chungus_str >= 3)
+ knockback_tiles = FLOOR(actual_damage / ((chungus_str - 2) * 4), 1)
+ else
+ knockback_tiles = FLOOR(actual_damage / 2, 1)
+
+ if(knockback_tiles < 1)
+ return
+
+ var/turf/edge_target_turf = get_edge_target_turf(target, get_dir(user, target))
+ if(!istype(edge_target_turf))
+ return
+ target.safe_throw_at(
+ edge_target_turf,
+ knockback_tiles,
+ knockback_tiles,
+ user,
+ spin = FALSE,
+ force = target.move_force,
+ callback = CALLBACK(target, TYPE_PROC_REF(/mob/living, handle_knockback), get_turf(target))
+ )
/mob/living/proc/handle_knockback(turf/starting_turf)
var/distance = 0
diff --git a/code/modules/surgery/bodyparts/bodypart_wounds.dm b/code/modules/surgery/bodyparts/bodypart_wounds.dm
index 21eaf008600..174cdeff412 100644
--- a/code/modules/surgery/bodyparts/bodypart_wounds.dm
+++ b/code/modules/surgery/bodyparts/bodypart_wounds.dm
@@ -137,16 +137,16 @@
return bleed_rate
/// Called after a bodypart is attacked so that wounds and critical effects can be applied
-/obj/item/bodypart/proc/bodypart_attacked_by(bclass, dam, mob/living/user, zone_precise, silent = FALSE, crit_message = FALSE, reduce_crit = 0)
+/obj/item/bodypart/proc/bodypart_attacked_by(bclass, dam, mob/living/user, zone_precise, silent = FALSE, crit_message = FALSE, list/modifiers = list())
if(!bclass || !dam || !owner || (owner.status_flags & GODMODE))
return FALSE
if(dam < 5)
return
- var/do_crit = (reduce_crit >= 100) ? FALSE : TRUE
+ var/do_crit = (modifiers[CRIT_MOD_CHANCE] <= -100) ? FALSE : TRUE
- if(ishuman(owner))
+ if(do_crit && ishuman(owner))
var/mob/living/carbon/human/human_owner = owner
if(human_owner.check_crit_armor(zone_precise, bclass))
do_crit = FALSE
@@ -158,7 +158,7 @@
do_crit = FALSE
if(do_crit)
- var/crit_attempt = try_crit(bclass, dam, user, zone_precise, silent, crit_message, reduce_crit)
+ var/crit_attempt = try_crit(bclass, dam, user, zone_precise, silent, crit_message, modifiers)
if(crit_attempt)
return crit_attempt
@@ -197,7 +197,7 @@
return changed_wound
/// Behemoth of a proc used to apply a wound after a bodypart is damaged in an attack
-/obj/item/bodypart/proc/try_crit(bclass, dam, mob/living/user, zone_precise, silent = FALSE, crit_message = FALSE, reduce_crit = 0)
+/obj/item/bodypart/proc/try_crit(bclass, dam, mob/living/user, zone_precise, silent = FALSE, crit_message = FALSE, list/modifiers = list())
if(!bclass || !dam || (owner.status_flags & GODMODE))
return FALSE
@@ -220,8 +220,7 @@
if(user?.stat_roll(STAT_FORTUNE, 2, 10))
dam += 10
- var/used
- used -= reduce_crit
+ var/used = modifiers[CRIT_MOD_CHANCE]
var/damage_dividend = (get_damage() / max_damage)
var/list/attempted_wounds
switch(pick(crit_classes))
@@ -230,7 +229,7 @@
return
if(user && istype(user.rmb_intent, /datum/rmb_intent/strong))
dam += 10
- used = round(damage_dividend * 20 + (dam / 6), 1)
+ used += round(damage_dividend * 20 + (dam / 6), 1)
if(HAS_TRAIT(src, TRAIT_CRITICAL_RESISTANCE))
used -= 10
if(prob(used))
@@ -245,7 +244,7 @@
dam += 10
if(HAS_TRAIT(src, TRAIT_BRITTLE))
dam += 10
- used = round(damage_dividend * 20 + (dam / 6), 1)
+ used += round(damage_dividend * 20 + (dam / 6), 1)
if(HAS_TRAIT(src, TRAIT_CRITICAL_RESISTANCE))
used -= 10
if(prob(used))
@@ -259,7 +258,7 @@
dam += 10
else if(istype(user.rmb_intent, /datum/rmb_intent/aimed))
dam += 10
- used = round(damage_dividend * 20 + (dam / 6), 1)
+ used += round(damage_dividend * 20 + (dam / 6), 1)
if(HAS_TRAIT(src, TRAIT_CRITICAL_RESISTANCE))
used -= 10
if(prob(used))
@@ -282,9 +281,10 @@
if(user?.client)
record_round_statistic(STATS_CRITS_MADE)
return applied
+
return FALSE
-/obj/item/bodypart/chest/try_crit(bclass, dam, mob/living/user, zone_precise, silent = FALSE, crit_message = FALSE, reduce_crit = 0)
+/obj/item/bodypart/chest/try_crit(bclass, dam, mob/living/user, zone_precise, silent = FALSE, crit_message = FALSE, list/modifiers = list())
if(!bclass || !dam || (owner.status_flags & GODMODE))
return FALSE
@@ -307,8 +307,7 @@
if(user?.stat_roll(STAT_FORTUNE,2,10))
dam += 10
- var/used
- used -= reduce_crit
+ var/used = modifiers[CRIT_MOD_CHANCE]
var/damage_dividend = (get_damage() / max_damage)
var/resistance = HAS_TRAIT(owner, TRAIT_CRITICAL_RESISTANCE)
var/list/attempted_wounds
@@ -331,7 +330,7 @@
dam += 10
if(HAS_TRAIT(src, TRAIT_BRITTLE))
dam += 10
- used = round(damage_dividend * 20 + (dam / 6), 1)
+ used += round(damage_dividend * 20 + (dam / 6), 1)
if(HAS_TRAIT(src, TRAIT_CRITICAL_RESISTANCE))
used -= 10
var/fracture_type = /datum/wound/fracture/chest
@@ -345,7 +344,7 @@
dam += 10
else if(user && istype(user.rmb_intent, /datum/rmb_intent/aimed))
dam += 10
- used = round(damage_dividend * 20 + (dam / 6), 1)
+ used += round(damage_dividend * 20 + (dam / 6), 1)
if(HAS_TRAIT(src, TRAIT_CRITICAL_RESISTANCE))
used -= 10
if(prob(used))
@@ -358,7 +357,7 @@
if("scarring")
if(user && istype(user.rmb_intent, /datum/rmb_intent/strong))
dam += 10
- used = round(damage_dividend * 20 + (dam / 6), 1)
+ used += round(damage_dividend * 20 + (dam / 6), 1)
if(HAS_TRAIT(src, TRAIT_CRITICAL_RESISTANCE))
used -= 10
if(prob(used))
@@ -373,9 +372,10 @@
if(user?.client)
record_round_statistic(STATS_CRITS_MADE)
return applied
+
return FALSE
-/obj/item/bodypart/head/try_crit(bclass, dam, mob/living/user, zone_precise, silent = FALSE, crit_message = FALSE, reduce_crit = 0)
+/obj/item/bodypart/head/try_crit(bclass, dam, mob/living/user, zone_precise, silent = FALSE, crit_message = FALSE, list/modifiers = list())
var/static/list/eyestab_zones = list(BODY_ZONE_PRECISE_R_EYE, BODY_ZONE_PRECISE_L_EYE)
var/static/list/tonguestab_zones = list(BODY_ZONE_PRECISE_MOUTH)
var/static/list/nosestab_zones = list(BODY_ZONE_PRECISE_NOSE)
@@ -404,15 +404,14 @@
if((owner.dir == REVERSE_DIR(get_dir(owner, user))))
from_behind = TRUE
- var/used
- used -= reduce_crit
+ var/used = modifiers[CRIT_MOD_CHANCE]
var/damage_dividend = (get_damage() / max_damage)
var/resistance = HAS_TRAIT(owner, TRAIT_CRITICAL_RESISTANCE)
var/list/attempted_wounds
switch(pick(crit_classes))
if("dislocation")
if(damage_dividend >= 1)
- used = round(damage_dividend * 20 + (dam / 6), 1)
+ used += round(damage_dividend * 20 + (dam / 6), 1)
if(HAS_TRAIT(src, TRAIT_CRITICAL_RESISTANCE))
used -= 10
if(prob(used))
@@ -425,17 +424,19 @@
dam += 20
if(user && istype(user.rmb_intent, /datum/rmb_intent/strong))
dam += 10
- used = round(damage_dividend * 20 + (dam / 6), 1)
+ used += round(damage_dividend * 20 + (dam / 6), 1)
if(HAS_TRAIT(src, TRAIT_CRITICAL_RESISTANCE))
used -= 10
- if(!owner.stat && (zone_precise in knockout_zones) && !(bclass in GLOB.no_knockout_bclasses) && prob(used))
- owner.next_attack_msg += " [span_crit("Critical hit! [owner] is knocked out[from_behind ? " FROM BEHIND" : ""]!")]"
- owner.flash_fullscreen("whiteflash3")
- owner.Unconscious(15 SECONDS + (from_behind * 15 SECONDS))
- if(owner.client)
- winset(owner.client, "outputwindow.output", "max-lines=1")
- winset(owner.client, "outputwindow.output", "max-lines=100")
- return
+ if(!owner.stat && (zone_precise in knockout_zones) && !(bclass in GLOB.no_knockout_bclasses))
+ var/knockout_chance = used + modifiers[CRIT_MOD_KNOCKOUT_CHANCE]
+ if(prob(knockout_chance))
+ owner.next_attack_msg += " [span_crit("Critical hit! [owner] is knocked out[from_behind ? " FROM BEHIND" : ""]!")]"
+ owner.flash_fullscreen("whiteflash3")
+ owner.Unconscious(15 SECONDS + (from_behind * 15 SECONDS))
+ if(owner.client)
+ winset(owner.client, "outputwindow.output", "max-lines=1")
+ winset(owner.client, "outputwindow.output", "max-lines=100")
+ return
var/dislocation_type
var/fracture_type = /datum/wound/fracture/head
var/necessary_damage = 0.95
@@ -468,7 +469,7 @@
else
if(istype(user.rmb_intent, /datum/rmb_intent/aimed))
dam += 10
- used = round(damage_dividend * 20 + (dam / 6), 1)
+ used += round(damage_dividend * 20 + (dam / 6), 1)
if(HAS_TRAIT(src, TRAIT_CRITICAL_RESISTANCE))
used -= 10
if(prob(used))
@@ -515,6 +516,7 @@
if(user?.client)
record_round_statistic(STATS_CRITS_MADE)
return applied
+
return FALSE
/// Embeds an object in this bodypart