diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index b1e131dd87..ff7cecf169 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -409,7 +409,12 @@ var/list/global/slot_flags_enumeration = list(
/obj/item/proc/ui_action_click()
attack_self(usr)
-/obj/item/proc/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/attack_text = "the attack")
+//RETURN VALUES
+//handle_shield should return a positive value to indicate that the attack is blocked and should be prevented.
+//If a negative value is returned, it should be treated as a special return value for bullet_act() and handled appropriately.
+//For non-projectile attacks this usually means the attack is blocked.
+//Otherwise should return 0 to indicate that the attack is not affected in any way.
+/obj/item/proc/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
return 0
/obj/item/proc/get_loc_turf()
diff --git a/code/game/objects/items/weapons/material/swords.dm b/code/game/objects/items/weapons/material/swords.dm
index a907e2abdf..38ef718c8d 100644
--- a/code/game/objects/items/weapons/material/swords.dm
+++ b/code/game/objects/items/weapons/material/swords.dm
@@ -11,7 +11,7 @@
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
hitsound = 'sound/weapons/bladeslice.ogg'
-/obj/item/weapon/material/sword/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/attack_text = "the attack")
+/obj/item/weapon/material/sword/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
//parry only melee attacks
if(istype(damage_source, /obj/item/projectile) || (attacker && get_dist(user, attacker) > 1))
diff --git a/code/game/objects/items/weapons/material/twohanded.dm b/code/game/objects/items/weapons/material/twohanded.dm
index e944ab743a..d11f798b8e 100644
--- a/code/game/objects/items/weapons/material/twohanded.dm
+++ b/code/game/objects/items/weapons/material/twohanded.dm
@@ -72,7 +72,7 @@
return unwield()
//Allow a small chance of parrying melee attacks when wielded - maybe generalize this to other weapons someday
-/obj/item/weapon/material/twohanded/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/attack_text = "the attack")
+/obj/item/weapon/material/twohanded/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
if(!wielded)
return 0
diff --git a/code/game/objects/items/weapons/melee/energy.dm b/code/game/objects/items/weapons/melee/energy.dm
index d1dee719e1..0936a1ad00 100644
--- a/code/game/objects/items/weapons/melee/energy.dm
+++ b/code/game/objects/items/weapons/melee/energy.dm
@@ -151,7 +151,7 @@
attack_verb = list()
icon_state = initial(icon_state)
-/obj/item/weapon/melee/energy/sword/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/attack_text = "the attack")
+/obj/item/weapon/melee/energy/sword/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
if(!active)
return 0
diff --git a/code/game/objects/items/weapons/shields.dm b/code/game/objects/items/weapons/shields.dm
index 15a1eaf96b..d0e990b6de 100644
--- a/code/game/objects/items/weapons/shields.dm
+++ b/code/game/objects/items/weapons/shields.dm
@@ -2,7 +2,7 @@
name = "shield"
var/base_block_chance = 50
-/obj/item/weapon/shield/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/attack_text = "the attack")
+/obj/item/weapon/shield/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
//block as long as they are not directly behind us
var/bad_arc = reverse_direction(user.dir) //arc of directions from which we cannot block
if(check_shield_arc(user, bad_arc, damage_source, attacker))
diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm
index 7a9d6f3f20..300422bc73 100644
--- a/code/modules/clothing/suits/armor.dm
+++ b/code/modules/clothing/suits/armor.dm
@@ -63,6 +63,26 @@
armor = list(melee = 10, bullet = 10, laser = 80, energy = 50, bomb = 0, bio = 0, rad = 0)
siemens_coefficient = 0
+/obj/item/clothing/suit/armor/laserproof/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
+ if(istype(damage_source, /obj/item/projectile/energy) || istype(damage_source, /obj/item/projectile/beam))
+ var/obj/item/projectile/P = damage_source
+
+ var/reflectchance = 40 - round(damage/3)
+ if(!(def_zone in list("chest", "groin")))
+ reflectchance /= 2
+ if(P.starting && prob(reflectchance))
+ visible_message("\The [user]'s [src.name] reflects [attack_text]!")
+
+ // Find a turf near or on the original location to bounce to
+ var/new_x = P.starting.x + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
+ var/new_y = P.starting.y + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
+ var/turf/curloc = get_turf(user)
+
+ // redirect the projectile
+ P.redirect(new_x, new_y, curloc, user)
+
+ return PROJECTILE_CONTINUE // complete projectile permutation
+
/obj/item/clothing/suit/armor/swat
name = "swat suit"
desc = "A heavily armored suit that protects against moderate damage. Used in special operations."
@@ -113,7 +133,7 @@
slowdown = 1
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0)
-/obj/item/clothing/suit/armor/reactive/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/attack_text = "the attack")
+/obj/item/clothing/suit/armor/reactive/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
if(prob(50))
user.visible_message("The reactive teleport system flings [user] clear of the attack!")
var/list/turfs = new/list()
@@ -133,7 +153,7 @@
playsound(user.loc, "sparks", 50, 1)
user.loc = picked
- return 1
+ return PROJECTILE_FORCE_MISS
return 0
/obj/item/clothing/suit/armor/reactive/attack_self(mob/user as mob)
diff --git a/code/modules/holodeck/HolodeckObjects.dm b/code/modules/holodeck/HolodeckObjects.dm
index fbd998fc52..fbd3f7b41c 100644
--- a/code/modules/holodeck/HolodeckObjects.dm
+++ b/code/modules/holodeck/HolodeckObjects.dm
@@ -252,7 +252,7 @@
New()
item_color = "red"
-/obj/item/weapon/holo/esword/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/attack_text = "the attack")
+/obj/item/weapon/holo/esword/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
if(!active)
return 0
diff --git a/code/modules/mob/living/carbon/human/human_attackhand.dm b/code/modules/mob/living/carbon/human/human_attackhand.dm
index e15f9a554d..68680a432c 100644
--- a/code/modules/mob/living/carbon/human/human_attackhand.dm
+++ b/code/modules/mob/living/carbon/human/human_attackhand.dm
@@ -19,7 +19,7 @@
// Should this all be in Touch()?
if(istype(H))
- if(H != src && check_shields(0, null, H, H.name))
+ if(H != src && check_shields(0, null, H, H.zone_sel.selecting, H.name))
H.do_attack_animation(src)
return 0
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index b66a610368..284515a222 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -16,30 +16,14 @@ emp_act
var/obj/item/organ/external/organ = get_organ()
- //Shields
- if(check_shields(P.damage, P, null, "the [P.name]"))
- P.on_hit(src, 2, def_zone)
- return 2
-
- //Laserproof armour
- if(wear_suit && istype(wear_suit, /obj/item/clothing/suit/armor/laserproof))
- if(istype(P, /obj/item/projectile/energy) || istype(P, /obj/item/projectile/beam))
- var/reflectchance = 40 - round(P.damage/3)
- if(!(def_zone in list("chest", "groin")))
- reflectchance /= 2
- if(prob(reflectchance))
- visible_message("\red \The [P] gets reflected by \the [src]'s [wear_suit.name]!")
-
- // Find a turf near or on the original location to bounce to
- if(P.starting)
- var/new_x = P.starting.x + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
- var/new_y = P.starting.y + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
- var/turf/curloc = get_turf(src)
-
- // redirect the projectile
- P.redirect(new_x, new_y, curloc, src)
-
- return PROJECTILE_CONTINUE // complete projectile permutation
+ //Shields
+ var/shield_check = check_shields(P.damage, P, null, def_zone, "the [P.name]")
+ if(shield_check)
+ if(shield_check < 0)
+ return shield_check
+ else
+ P.on_hit(src, 2, def_zone)
+ return 2
//Shrapnel
if(P.can_embed())
@@ -148,10 +132,13 @@ emp_act
return gear
return null
-/mob/living/carbon/human/proc/check_shields(var/damage = 0, var/atom/damage_source = null, var/mob/attacker = null, var/attack_text = "the attack")
+/mob/living/carbon/human/proc/check_shields(var/damage = 0, var/atom/damage_source = null, var/mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
for(var/obj/item/shield in list(l_hand, r_hand, wear_suit))
- if(shield && shield.handle_shield(src, damage, damage_source, attacker, attack_text))
- return 1
+ if(!shield)
+ continue
+ var/result = shield.handle_shield(src, damage, damage_source, attacker, def_zone, attack_text)
+ if(result)
+ return result
return 0
/mob/living/carbon/human/emp_act(severity)
@@ -183,7 +170,7 @@ emp_act
if(user.a_intent == "disarm") effective_force = round(I.force/2)
var/hit_area = affecting.name
- if((user != src) && check_shields(effective_force, I, user, "the [I.name]"))
+ if((user != src) && check_shields(effective_force, I, user, target_zone, "the [I.name]"))
return 0
if(istype(I,/obj/item/weapon/card/emag))
@@ -312,7 +299,7 @@ emp_act
O.throwing = 0 //it hit, so stop moving
- if ((O.thrower != src) && check_shields(throw_damage, O, thrower, "[O]"))
+ if ((O.thrower != src) && check_shields(throw_damage, O, thrower, zone, "[O]"))
return
var/obj/item/organ/external/affecting = get_organ(zone)