From 0a751322e3fc6f7812d85f64e2592e0586713a0c Mon Sep 17 00:00:00 2001 From: mwerezak Date: Sat, 11 Jul 2015 18:14:16 -0400 Subject: [PATCH 1/6] Rewrites shield handling Rewrites shield handling to be less hardcoded. Shields now take into account the damage source and direction when blocking. Riot shields no longer block most bullets, but are better at blocking melee and thrown items than they were previously. Energy shields block projectiles with a similar probability as they did before, and block melee and thrown as well as riot shields do. Shields no longer block from directly behind the player. Weapons now only block melee attacks. Cool effects when blocking with an energy shield or energy sword (including holoswords). --- code/game/objects/items.dm | 2 +- .../objects/items/weapons/material/swords.dm | 18 +++- .../items/weapons/material/twohanded.dm | 66 +++++--------- .../objects/items/weapons/melee/energy.dm | 22 ++++- code/game/objects/items/weapons/shields.dm | 90 +++++++++++++++---- code/modules/clothing/suits/armor.dm | 22 ++++- code/modules/holodeck/HolodeckObjects.dm | 22 ++++- .../living/carbon/human/human_attackhand.dm | 3 +- .../mob/living/carbon/human/human_defense.dm | 35 ++------ .../reagents/reagent_containers/syringes.dm | 2 +- 10 files changed, 180 insertions(+), 102 deletions(-) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 8f36b1d007b..b1e131dd87b 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -409,7 +409,7 @@ var/list/global/slot_flags_enumeration = list( /obj/item/proc/ui_action_click() attack_self(usr) -/obj/item/proc/IsShield() +/obj/item/proc/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = 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 8a93d59fe58..a907e2abdf6 100644 --- a/code/game/objects/items/weapons/material/swords.dm +++ b/code/game/objects/items/weapons/material/swords.dm @@ -11,8 +11,22 @@ attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") hitsound = 'sound/weapons/bladeslice.ogg' -/obj/item/weapon/material/sword/IsShield() - return 1 +/obj/item/weapon/material/sword/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/attack_text = "the attack") + + //parry only melee attacks + if(istype(damage_source, /obj/item/projectile) || (attacker && get_dist(user, attacker) > 1)) + return 0 + + //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)) + return 0 + + if(prob(50)) + user.visible_message("\The [user] parries [attack_text] with \the [src]!") + playsound(user.loc, 'sound/weapons/punchmiss.ogg', 50, 1) + return 1 + return 0 /obj/item/weapon/material/sword/suicide_act(mob/user) viewers(user) << "[user] is falling on the [src.name]! It looks like \he's trying to commit suicide." diff --git a/code/game/objects/items/weapons/material/twohanded.dm b/code/game/objects/items/weapons/material/twohanded.dm index b41a4175a79..e944ab743a2 100644 --- a/code/game/objects/items/weapons/material/twohanded.dm +++ b/code/game/objects/items/weapons/material/twohanded.dm @@ -71,6 +71,26 @@ O.unwield() 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") + if(!wielded) + return 0 + + //parry only melee attacks + if(istype(damage_source, /obj/item/projectile) || (attacker && get_dist(user, attacker) > 1)) + return 0 + + //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)) + return 0 + + if(prob(15)) + user.visible_message("\The [user] parries [attack_text] with \the [src]!") + playsound(user.loc, 'sound/weapons/punchmiss.ogg', 50, 1) + return 1 + return 0 + /obj/item/weapon/material/twohanded/update_icon() icon_state = "[base_icon][wielded]" item_state = icon_state @@ -167,51 +187,7 @@ else if(istype(A,/obj/effect/plant)) var/obj/effect/plant/P = A P.die_off() - -/* -/* - * Double-Bladed Energy Swords - Cheridan - */ - // Not sure what to do with this one, it won't work nicely with the material system, - // but I don't want to copypaste all the twohanded procs.. -/obj/item/weapon/material/twohanded/dualsaber - icon_state = "dualsaber0" - base_icon = "dualsaber" - name = "double-bladed energy sword" - desc = "Handle with care." - force = 3 - throwforce = 5.0 - throw_speed = 1 - throw_range = 5 - w_class = 2.0 - force_wielded = 30 - wieldsound = 'sound/weapons/saberon.ogg' - unwieldsound = 'sound/weapons/saberoff.ogg' - origin_tech = list(TECH_MAGNET = 3, TECH_ILLEGAL = 4) - attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") - sharp = 1 - edge = 1 - applies_material_colour = 0 - -/obj/item/weapon/material/twohanded/dualsaber/attack(target as mob, mob/living/user as mob) - ..() - if((CLUMSY in user.mutations) && (wielded) &&prob(40)) - user << "You twirl around a bit before losing your balance and impaling yourself on \the [src]." - user.take_organ_damage(20,25) - return - if((wielded) && prob(50)) - spawn(0) - for(var/i in list(1,2,4,8,4,2,1,2,4,8,4,2)) - user.set_dir(i) - sleep(1) - -/obj/item/weapon/material/twohanded/dualsaber/IsShield() - if(wielded) - return 1 - else - return 0 -*/ - + //spears, bay edition /obj/item/weapon/material/twohanded/spear icon_state = "spearglass0" diff --git a/code/game/objects/items/weapons/melee/energy.dm b/code/game/objects/items/weapons/melee/energy.dm index 43acc06908e..d1dee719e1e 100644 --- a/code/game/objects/items/weapons/melee/energy.dm +++ b/code/game/objects/items/weapons/melee/energy.dm @@ -151,8 +151,26 @@ attack_verb = list() icon_state = initial(icon_state) -/obj/item/weapon/melee/energy/sword/IsShield() - if(active) +/obj/item/weapon/melee/energy/sword/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/attack_text = "the attack") + if(!active) + return 0 + + //parry only melee attacks + if(istype(damage_source, /obj/item/projectile) || (attacker && get_dist(user, attacker) > 1)) + return 0 + + //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)) + return 0 + + if(prob(50)) + user.visible_message("\The [user] parries [attack_text] with \the [src]!") + + var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() + spark_system.set_up(5, 0, user.loc) + spark_system.start() + playsound(user.loc, 'sound/weapons/blade1.ogg', 50, 1) return 1 return 0 diff --git a/code/game/objects/items/weapons/shields.dm b/code/game/objects/items/weapons/shields.dm index 02b412232de..15a1eaf96be 100644 --- a/code/game/objects/items/weapons/shields.dm +++ b/code/game/objects/items/weapons/shields.dm @@ -1,5 +1,18 @@ /obj/item/weapon/shield 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") + //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)) + if(prob(get_block_chance(user, damage, damage_source, attacker))) + user.visible_message("\The [user] blocks [attack_text] with \the [src]!") + return 1 + return 0 + +/obj/item/weapon/shield/proc/get_block_chance(mob/user, var/damage, atom/damage_source = null, mob/attacker = null) + return base_block_chance /obj/item/weapon/shield/riot name = "riot shield" @@ -18,17 +31,26 @@ attack_verb = list("shoved", "bashed") var/cooldown = 0 //shield bash cooldown. based on world.time - IsShield() - return 1 +/obj/item/weapon/shield/riot/handle_shield(mob/user) + . = ..() + if(.) playsound(user.loc, 'sound/weapons/Genhit.ogg', 50, 1) - attackby(obj/item/weapon/W as obj, mob/user as mob) - if(istype(W, /obj/item/weapon/melee/baton)) - if(cooldown < world.time - 25) - user.visible_message("[user] bashes [src] with [W]!") - playsound(user.loc, 'sound/effects/shieldbash.ogg', 50, 1) - cooldown = world.time - else - ..() +/obj/item/weapon/shield/riot/get_block_chance(mob/user, var/damage, atom/damage_source = null, mob/attacker = null) + if(istype(damage_source, /obj/item/projectile)) + var/obj/item/projectile/P = damage_source + //plastic shields do not stop bullets or lasers, even in space. Will block beanbags, rubber bullets, and stunshots just fine though. + if((is_sharp(P) && damage > 10) || istype(P, /obj/item/projectile/beam)) + return 0 + return base_block_chance + +/obj/item/weapon/shield/riot/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/melee/baton)) + if(cooldown < world.time - 25) + user.visible_message("[user] bashes [src] with [W]!") + playsound(user.loc, 'sound/effects/shieldbash.ogg', 50, 1) + cooldown = world.time + else + ..() /* * Energy Shield @@ -49,11 +71,23 @@ attack_verb = list("shoved", "bashed") var/active = 0 -/obj/item/weapon/shield/energy/IsShield() - if(active) - return 1 - else - return 0 +/obj/item/weapon/shield/energy/handle_shield(mob/user) + if(!active) + return 0 //turn it on first! + . = ..() + + if(.) + var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() + spark_system.set_up(5, 0, user.loc) + spark_system.start() + playsound(user.loc, 'sound/weapons/blade1.ogg', 50, 1) + +/obj/item/weapon/shield/energy/get_block_chance(mob/user, var/damage, atom/damage_source = null, mob/attacker = null) + if(istype(damage_source, /obj/item/projectile)) + var/obj/item/projectile/P = damage_source + if((is_sharp(P) && damage > 10) || istype(P, /obj/item/projectile/beam)) + return (base_block_chance - round(damage / 3)) //block bullets and beams using the old block chance + return base_block_chance /obj/item/weapon/shield/energy/attack_self(mob/living/user as mob) if ((CLUMSY in user.mutations) && prob(50)) @@ -82,9 +116,32 @@ add_fingerprint(user) return +//** Shield Helpers +//This is here in case it is useful for things like energy swords that want to pretend they are shields + +//bad_arc is the ABSOLUTE arc of directions from which we cannot block +/obj/item/proc/check_shield_arc(mob/user, var/bad_arc, atom/damage_source = null, mob/attacker = null) + //check attack direction + var/attack_dir = 0 //direction from the user to the source of the attack + if(istype(damage_source, /obj/item/projectile)) + var/obj/item/projectile/P = damage_source + attack_dir = get_dir(get_turf(user), P.starting) + else if(attacker) + attack_dir = get_dir(get_turf(user), get_turf(attacker)) + else if(damage_source) + attack_dir = get_dir(get_turf(user), get_turf(damage_source)) + + world << "attack_dir: [print_dir(attack_dir)]" + + if(!(attack_dir && (attack_dir & bad_arc))) + return 1 + return 0 + + + /obj/item/weapon/cloaking_device name = "cloaking device" - desc = "Use this to become invisible to the human eyesocket." + desc = "Use this to become invisible to the human eye." icon = 'icons/obj/device.dmi' icon_state = "shield0" var/active = 0.0 @@ -114,3 +171,4 @@ if(ismob(loc)) loc:update_icons() ..() + diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index 4bcefa5c153..7a9d6f3f207 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -113,8 +113,26 @@ slowdown = 1 armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0) -/obj/item/clothing/suit/armor/reactive/IsShield() - if(active) +/obj/item/clothing/suit/armor/reactive/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = 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() + for(var/turf/T in orange(6, user)) + if(istype(T,/turf/space)) continue + if(T.density) continue + if(T.x>world.maxx-6 || T.x<6) continue + if(T.y>world.maxy-6 || T.y<6) continue + turfs += T + if(!turfs.len) turfs += pick(/turf in orange(6)) + var/turf/picked = pick(turfs) + if(!isturf(picked)) return + + var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() + spark_system.set_up(5, 0, user.loc) + spark_system.start() + playsound(user.loc, "sparks", 50, 1) + + user.loc = picked return 1 return 0 diff --git a/code/modules/holodeck/HolodeckObjects.dm b/code/modules/holodeck/HolodeckObjects.dm index ce9ac0f225b..fbd998fc52f 100644 --- a/code/modules/holodeck/HolodeckObjects.dm +++ b/code/modules/holodeck/HolodeckObjects.dm @@ -252,8 +252,26 @@ New() item_color = "red" -/obj/item/weapon/holo/esword/IsShield() - if(active) +/obj/item/weapon/holo/esword/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/attack_text = "the attack") + if(!active) + return 0 + + //parry only melee holo attacks + if(!istype(damage_source, /obj/item/weapon/holo) || (attacker && get_dist(user, attacker) > 1)) + return 0 + + //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)) + return 0 + + if(prob(50)) + user.visible_message("\The [user] parries [attack_text] with \the [src]!") + + var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() + spark_system.set_up(5, 0, user.loc) + spark_system.start() + playsound(user.loc, 'sound/weapons/blade1.ogg', 50, 1) return 1 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 d9535b106c4..e15f9a554db 100644 --- a/code/modules/mob/living/carbon/human/human_attackhand.dm +++ b/code/modules/mob/living/carbon/human/human_attackhand.dm @@ -19,8 +19,7 @@ // Should this all be in Touch()? if(istype(H)) - if((H != src) && check_shields(0, H.name)) - visible_message("\red [H] attempted to touch [src]!") + if(H != src && check_shields(0, null, H, 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 5ecfa1807c8..b66a610368b 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -17,7 +17,7 @@ emp_act var/obj/item/organ/external/organ = get_organ() //Shields - if(check_shields(P.damage, "the [P.name]")) + if(check_shields(P.damage, P, null, "the [P.name]")) P.on_hit(src, 2, def_zone) return 2 @@ -148,32 +148,9 @@ emp_act return gear return null -/mob/living/carbon/human/proc/check_shields(var/damage = 0, var/attack_text = "the attack") - if(l_hand && istype(l_hand, /obj/item/weapon))//Current base is the prob(50-d/3) - var/obj/item/weapon/I = l_hand - if(I.IsShield() && (prob(50 - round(damage / 3)))) - visible_message("\red [src] blocks [attack_text] with the [l_hand.name]!") - return 1 - if(r_hand && istype(r_hand, /obj/item/weapon)) - var/obj/item/weapon/I = r_hand - if(I.IsShield() && (prob(50 - round(damage / 3)))) - visible_message("\red [src] blocks [attack_text] with the [r_hand.name]!") - return 1 - if(wear_suit && istype(wear_suit, /obj/item/)) - var/obj/item/I = wear_suit - if(I.IsShield() && (prob(35))) - visible_message("\red The reactive teleport system flings [src] clear of [attack_text]!") - var/list/turfs = new/list() - for(var/turf/T in orange(6)) - if(istype(T,/turf/space)) continue - if(T.density) continue - if(T.x>world.maxx-6 || T.x<6) continue - if(T.y>world.maxy-6 || T.y<6) continue - turfs += T - if(!turfs.len) turfs += pick(/turf in orange(6)) - var/turf/picked = pick(turfs) - if(!isturf(picked)) return - src.loc = picked +/mob/living/carbon/human/proc/check_shields(var/damage = 0, var/atom/damage_source = null, var/mob/attacker = 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 return 0 @@ -206,7 +183,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, "the [I.name]")) + if((user != src) && check_shields(effective_force, I, user, "the [I.name]")) return 0 if(istype(I,/obj/item/weapon/card/emag)) @@ -335,7 +312,7 @@ emp_act O.throwing = 0 //it hit, so stop moving - if ((O.thrower != src) && check_shields(throw_damage, "[O]")) + if ((O.thrower != src) && check_shields(throw_damage, O, thrower, "[O]")) return var/obj/item/organ/external/affecting = get_organ(zone) diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm index c06b57d54c8..19ac8c62fbc 100644 --- a/code/modules/reagents/reagent_containers/syringes.dm +++ b/code/modules/reagents/reagent_containers/syringes.dm @@ -237,7 +237,7 @@ var/hit_area = affecting.name - if((user != target) && H.check_shields(7, "the [src.name]")) + if((user != target) && H.check_shields(7, src, user, "\the [src]")) return if (target != user && H.getarmor(target_zone, "melee") > 5 && prob(50)) From fb6b94de8773e6855b362faf84ef8e0f427e608f Mon Sep 17 00:00:00 2001 From: mwerezak Date: Mon, 13 Jul 2015 01:33:50 -0400 Subject: [PATCH 2/6] Incorporates laser reflection into the shield system --- code/game/objects/items.dm | 7 ++- .../objects/items/weapons/material/swords.dm | 2 +- .../items/weapons/material/twohanded.dm | 2 +- .../objects/items/weapons/melee/energy.dm | 2 +- code/game/objects/items/weapons/shields.dm | 2 +- code/modules/clothing/suits/armor.dm | 24 +++++++++- code/modules/holodeck/HolodeckObjects.dm | 2 +- .../living/carbon/human/human_attackhand.dm | 2 +- .../mob/living/carbon/human/human_defense.dm | 45 +++++++------------ 9 files changed, 50 insertions(+), 38 deletions(-) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index b1e131dd87b..ff7cecf169c 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 a907e2abdf6..38ef718c8d6 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 e944ab743a2..d11f798b8e2 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 d1dee719e1e..0936a1ad00a 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 15a1eaf96be..d0e990b6de4 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 7a9d6f3f207..300422bc731 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 fbd998fc52f..fbd3f7b41c7 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 e15f9a554db..68680a432cf 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 b66a610368b..284515a222c 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) From c5889928b2cae6d9ace6e169347972067462a30b Mon Sep 17 00:00:00 2001 From: mwerezak Date: Mon, 13 Jul 2015 01:41:06 -0400 Subject: [PATCH 3/6] Updates changelog --- html/changelogs/HarpyEagle-dev.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 html/changelogs/HarpyEagle-dev.yml diff --git a/html/changelogs/HarpyEagle-dev.yml b/html/changelogs/HarpyEagle-dev.yml new file mode 100644 index 00000000000..a2aab0fd972 --- /dev/null +++ b/html/changelogs/HarpyEagle-dev.yml @@ -0,0 +1,22 @@ +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment + +author: HarpyEagle +changes: + - rscadd: "Shields no longer block attacks from directly behind the player." + - rscadd: "Riot shields no longer stop bullets or beams (except for beanbags and rubber bullets), however they are now more effective at blocking melee attacks and thrown objects." + - rscadd: "Energy shields block melee attacks as effectively as riot shields do. Their ability to block projectiles is largely unchanged." + - rscadd: "Melee weapons (just energy swords, really) now only block melee attacks." + - experiment: "Two handed weapons have a small chance of blocking melee attacks when wielded in two hands." + - rscadd: "Sound and visual effects when blocking attacks with an energy shield or energy sword." +delete-after: false From e152ebcd142a4e54e1d8dc1debba273d499d98ea Mon Sep 17 00:00:00 2001 From: HarpyEagle Date: Thu, 13 Aug 2015 17:23:54 -0400 Subject: [PATCH 4/6] Thrown objects continue flying if reactive teleport armour is triggered. --- .../mob/living/carbon/human/human_defense.dm | 20 ++++++++++--------- code/modules/mob/living/damage_procs.dm | 1 + code/modules/mob/living/living_defense.dm | 1 - 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 284515a222c..e1cfa6f7ff7 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -134,11 +134,9 @@ emp_act /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) - continue - var/result = shield.handle_shield(src, damage, damage_source, attacker, def_zone, attack_text) - if(result) - return result + if(!shield) continue + . = shield.handle_shield(src, damage, damage_source, attacker, def_zone, attack_text) + if(.) return return 0 /mob/living/carbon/human/emp_act(severity) @@ -293,15 +291,19 @@ emp_act miss_chance = max(15*(distance-2), 0) zone = get_zone_with_miss_chance(zone, src, miss_chance, ranged_attack=1) + if(zone && O.thrower != src) + var/shield_check = check_shields(throw_damage, O, thrower, zone, "[O]") + if(shield_check == PROJECTILE_FORCE_MISS) + zone = null + else if(shield_check) + return + if(!zone) - visible_message("\blue \The [O] misses [src] narrowly!") + visible_message("\The [O] misses [src] narrowly!") return O.throwing = 0 //it hit, so stop moving - if ((O.thrower != src) && check_shields(throw_damage, O, thrower, zone, "[O]")) - return - var/obj/item/organ/external/affecting = get_organ(zone) var/hit_area = affecting.name diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm index cc76d40c654..2f0d30ce2cc 100644 --- a/code/modules/mob/living/damage_procs.dm +++ b/code/modules/mob/living/damage_procs.dm @@ -24,6 +24,7 @@ adjustCloneLoss(damage/(blocked+1)) if(HALLOSS) adjustHalLoss(damage/(blocked+1)) + flash_weak_pain() updatehealth() return 1 diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 871e95c8b40..0d4a5d77b48 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -50,7 +50,6 @@ /mob/living/bullet_act(var/obj/item/projectile/P, var/def_zone) - flash_weak_pain() //Being hit while using a cloaking device var/obj/item/weapon/cloaking_device/C = locate((/obj/item/weapon/cloaking_device) in src) From df3eeb891e0c1debd42e792b1686db399a887a50 Mon Sep 17 00:00:00 2001 From: HarpyEagle Date: Thu, 13 Aug 2015 17:52:28 -0400 Subject: [PATCH 5/6] Fixes dead people blocking stuff with shields. --- code/game/objects/items/weapons/material/swords.dm | 2 +- code/game/objects/items/weapons/material/twohanded.dm | 2 +- code/game/objects/items/weapons/melee/energy.dm | 2 +- code/game/objects/items/weapons/shields.dm | 3 +++ code/modules/holodeck/HolodeckObjects.dm | 2 +- html/changelogs/HarpyEagle-dev.yml | 3 ++- 6 files changed, 9 insertions(+), 5 deletions(-) diff --git a/code/game/objects/items/weapons/material/swords.dm b/code/game/objects/items/weapons/material/swords.dm index 38ef718c8d6..62111196f47 100644 --- a/code/game/objects/items/weapons/material/swords.dm +++ b/code/game/objects/items/weapons/material/swords.dm @@ -14,7 +14,7 @@ /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)) + if(istype(damage_source, /obj/item/projectile) || (attacker && get_dist(user, attacker) > 1) || user.incapacitated()) return 0 //block as long as they are not directly behind us diff --git a/code/game/objects/items/weapons/material/twohanded.dm b/code/game/objects/items/weapons/material/twohanded.dm index d11f798b8e2..177957bd91a 100644 --- a/code/game/objects/items/weapons/material/twohanded.dm +++ b/code/game/objects/items/weapons/material/twohanded.dm @@ -77,7 +77,7 @@ return 0 //parry only melee attacks - if(istype(damage_source, /obj/item/projectile) || (attacker && get_dist(user, attacker) > 1)) + if(istype(damage_source, /obj/item/projectile) || (attacker && get_dist(user, attacker) > 1) || user.incapacitated()) return 0 //block as long as they are not directly behind us diff --git a/code/game/objects/items/weapons/melee/energy.dm b/code/game/objects/items/weapons/melee/energy.dm index 0936a1ad00a..71b43d85641 100644 --- a/code/game/objects/items/weapons/melee/energy.dm +++ b/code/game/objects/items/weapons/melee/energy.dm @@ -156,7 +156,7 @@ return 0 //parry only melee attacks - if(istype(damage_source, /obj/item/projectile) || (attacker && get_dist(user, attacker) > 1)) + if(istype(damage_source, /obj/item/projectile) || (attacker && get_dist(user, attacker) > 1) || user.incapacitated()) return 0 //block as long as they are not directly behind us diff --git a/code/game/objects/items/weapons/shields.dm b/code/game/objects/items/weapons/shields.dm index d0e990b6de4..020af234d20 100644 --- a/code/game/objects/items/weapons/shields.dm +++ b/code/game/objects/items/weapons/shields.dm @@ -3,6 +3,9 @@ var/base_block_chance = 50 /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") + if(user.incapacitated()) + return 0 + //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/holodeck/HolodeckObjects.dm b/code/modules/holodeck/HolodeckObjects.dm index fbd3f7b41c7..b2841c4cf08 100644 --- a/code/modules/holodeck/HolodeckObjects.dm +++ b/code/modules/holodeck/HolodeckObjects.dm @@ -257,7 +257,7 @@ return 0 //parry only melee holo attacks - if(!istype(damage_source, /obj/item/weapon/holo) || (attacker && get_dist(user, attacker) > 1)) + if(!istype(damage_source, /obj/item/weapon/holo) || (attacker && get_dist(user, attacker) > 1) || user.incapacitated()) return 0 //block as long as they are not directly behind us diff --git a/html/changelogs/HarpyEagle-dev.yml b/html/changelogs/HarpyEagle-dev.yml index a2aab0fd972..08a2ca3b46f 100644 --- a/html/changelogs/HarpyEagle-dev.yml +++ b/html/changelogs/HarpyEagle-dev.yml @@ -16,7 +16,8 @@ changes: - rscadd: "Shields no longer block attacks from directly behind the player." - rscadd: "Riot shields no longer stop bullets or beams (except for beanbags and rubber bullets), however they are now more effective at blocking melee attacks and thrown objects." - rscadd: "Energy shields block melee attacks as effectively as riot shields do. Their ability to block projectiles is largely unchanged." - - rscadd: "Melee weapons (just energy swords, really) now only block melee attacks." + - tweak: "Melee weapons now only block melee attacks." - experiment: "Two handed weapons have a small chance of blocking melee attacks when wielded in two hands." - rscadd: "Sound and visual effects when blocking attacks with an energy shield or energy sword." + - bugfix: "Fixed dead or unconscious people blocking stuff with shields." delete-after: false From db8aefb121bf574727068540e558e0581f366ef1 Mon Sep 17 00:00:00 2001 From: mwerezak Date: Fri, 28 Aug 2015 14:39:28 -0400 Subject: [PATCH 6/6] Refactors duplicate parry code --- .../objects/items/weapons/material/swords.dm | 11 +--- .../items/weapons/material/twohanded.dm | 14 +---- .../objects/items/weapons/melee/energy.dm | 14 +---- code/game/objects/items/weapons/shields.dm | 53 +++++++++++-------- code/modules/holodeck/HolodeckObjects.dm | 14 +---- 5 files changed, 35 insertions(+), 71 deletions(-) diff --git a/code/game/objects/items/weapons/material/swords.dm b/code/game/objects/items/weapons/material/swords.dm index 62111196f47..a8b0ea19a3b 100644 --- a/code/game/objects/items/weapons/material/swords.dm +++ b/code/game/objects/items/weapons/material/swords.dm @@ -13,16 +13,7 @@ /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) || user.incapacitated()) - return 0 - - //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)) - return 0 - - if(prob(50)) + if(default_parry_check(user, attacker, damage_source) && prob(50)) user.visible_message("\The [user] parries [attack_text] with \the [src]!") playsound(user.loc, 'sound/weapons/punchmiss.ogg', 50, 1) return 1 diff --git a/code/game/objects/items/weapons/material/twohanded.dm b/code/game/objects/items/weapons/material/twohanded.dm index 177957bd91a..6102c760260 100644 --- a/code/game/objects/items/weapons/material/twohanded.dm +++ b/code/game/objects/items/weapons/material/twohanded.dm @@ -73,19 +73,7 @@ //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/def_zone = null, var/attack_text = "the attack") - if(!wielded) - return 0 - - //parry only melee attacks - if(istype(damage_source, /obj/item/projectile) || (attacker && get_dist(user, attacker) > 1) || user.incapacitated()) - return 0 - - //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)) - return 0 - - if(prob(15)) + if(wielded && default_parry_check(user, attacker, damage_source) && prob(15)) user.visible_message("\The [user] parries [attack_text] with \the [src]!") playsound(user.loc, 'sound/weapons/punchmiss.ogg', 50, 1) return 1 diff --git a/code/game/objects/items/weapons/melee/energy.dm b/code/game/objects/items/weapons/melee/energy.dm index 71b43d85641..6a236e1b8f7 100644 --- a/code/game/objects/items/weapons/melee/energy.dm +++ b/code/game/objects/items/weapons/melee/energy.dm @@ -152,19 +152,7 @@ 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/def_zone = null, var/attack_text = "the attack") - if(!active) - return 0 - - //parry only melee attacks - if(istype(damage_source, /obj/item/projectile) || (attacker && get_dist(user, attacker) > 1) || user.incapacitated()) - return 0 - - //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)) - return 0 - - if(prob(50)) + if(active && default_parry_check(user, attacker, damage_source) && prob(50)) user.visible_message("\The [user] parries [attack_text] with \the [src]!") var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() diff --git a/code/game/objects/items/weapons/shields.dm b/code/game/objects/items/weapons/shields.dm index 020af234d20..8b807e803fe 100644 --- a/code/game/objects/items/weapons/shields.dm +++ b/code/game/objects/items/weapons/shields.dm @@ -1,3 +1,34 @@ +//** Shield Helpers +//These are shared by various items that have shield-like behaviour + +//bad_arc is the ABSOLUTE arc of directions from which we cannot block. If you want to fix it to e.g. the user's facing you will need to rotate the dirs yourself. +/proc/check_shield_arc(mob/user, var/bad_arc, atom/damage_source = null, mob/attacker = null) + //check attack direction + var/attack_dir = 0 //direction from the user to the source of the attack + if(istype(damage_source, /obj/item/projectile)) + var/obj/item/projectile/P = damage_source + attack_dir = get_dir(get_turf(user), P.starting) + else if(attacker) + attack_dir = get_dir(get_turf(user), get_turf(attacker)) + else if(damage_source) + attack_dir = get_dir(get_turf(user), get_turf(damage_source)) + + if(!(attack_dir && (attack_dir & bad_arc))) + return 1 + return 0 + +/proc/default_parry_check(mob/user, mob/attacker, atom/damage_source) + //parry only melee attacks + if(istype(damage_source, /obj/item/projectile) || (attacker && get_dist(user, attacker) > 1) || user.incapacitated()) + return 0 + + //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)) + return 0 + + return 1 + /obj/item/weapon/shield name = "shield" var/base_block_chance = 50 @@ -119,28 +150,6 @@ add_fingerprint(user) return -//** Shield Helpers -//This is here in case it is useful for things like energy swords that want to pretend they are shields - -//bad_arc is the ABSOLUTE arc of directions from which we cannot block -/obj/item/proc/check_shield_arc(mob/user, var/bad_arc, atom/damage_source = null, mob/attacker = null) - //check attack direction - var/attack_dir = 0 //direction from the user to the source of the attack - if(istype(damage_source, /obj/item/projectile)) - var/obj/item/projectile/P = damage_source - attack_dir = get_dir(get_turf(user), P.starting) - else if(attacker) - attack_dir = get_dir(get_turf(user), get_turf(attacker)) - else if(damage_source) - attack_dir = get_dir(get_turf(user), get_turf(damage_source)) - - world << "attack_dir: [print_dir(attack_dir)]" - - if(!(attack_dir && (attack_dir & bad_arc))) - return 1 - return 0 - - /obj/item/weapon/cloaking_device name = "cloaking device" diff --git a/code/modules/holodeck/HolodeckObjects.dm b/code/modules/holodeck/HolodeckObjects.dm index b2841c4cf08..bc0f1a376c9 100644 --- a/code/modules/holodeck/HolodeckObjects.dm +++ b/code/modules/holodeck/HolodeckObjects.dm @@ -253,19 +253,7 @@ item_color = "red" /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 - - //parry only melee holo attacks - if(!istype(damage_source, /obj/item/weapon/holo) || (attacker && get_dist(user, attacker) > 1) || user.incapacitated()) - return 0 - - //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)) - return 0 - - if(prob(50)) + if(active && default_parry_check(user, attacker, damage_source) && prob(50)) user.visible_message("\The [user] parries [attack_text] with \the [src]!") var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread()