From d647a567f47cb9c2d6f1bbb0b4b00d38a5978eaa Mon Sep 17 00:00:00 2001 From: Geeves Date: Wed, 15 Jul 2020 20:16:50 +0200 Subject: [PATCH] Back-mounted Shields (#9301) A shield worn on your back will now properly defend you from penetration in the rear. --- code/game/objects/items.dm | 5 ++++- .../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 | 19 +++++++++++++++---- code/modules/clothing/clothing.dm | 2 +- code/modules/clothing/suits/armor.dm | 4 ++-- code/modules/holodeck/HolodeckObjects.dm | 2 +- .../mob/living/carbon/human/human_defense.dm | 15 +++++++++++---- html/changelogs/geeves-back_shield.yml | 6 ++++++ 10 files changed, 43 insertions(+), 16 deletions(-) create mode 100644 html/changelogs/geeves-back_shield.yml diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index d9fd71f5fca..ea5a48f4366 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -524,9 +524,12 @@ var/list/global/slot_flags_enumeration = list( //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") +/obj/item/proc/handle_shield(mob/user, var/on_back, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") return 0 +/obj/item/proc/can_shield_back() + return + /obj/item/proc/get_loc_turf() var/atom/L = loc while(L && !istype(L, /turf/)) diff --git a/code/game/objects/items/weapons/material/swords.dm b/code/game/objects/items/weapons/material/swords.dm index 48c5ddb9890..5fd76f533c2 100644 --- a/code/game/objects/items/weapons/material/swords.dm +++ b/code/game/objects/items/weapons/material/swords.dm @@ -19,7 +19,7 @@ drop_sound = 'sound/items/drop/sword.ogg' pickup_sound = 'sound/items/pickup/sword.ogg' -/obj/item/material/sword/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") +/obj/item/material/sword/handle_shield(mob/user, var/on_back, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") var/parry_bonus = 1 if(ishuman(user)) diff --git a/code/game/objects/items/weapons/material/twohanded.dm b/code/game/objects/items/weapons/material/twohanded.dm index a271adb6dc9..3d006eae207 100644 --- a/code/game/objects/items/weapons/material/twohanded.dm +++ b/code/game/objects/items/weapons/material/twohanded.dm @@ -80,7 +80,7 @@ return unwield() //Allow a small chance of parrying melee attacks when wielded - maybe generalize this to other weapons someday -/obj/item/material/twohanded/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") +/obj/item/material/twohanded/handle_shield(mob/user, var/on_back, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") if(wielded && default_parry_check(user, attacker, damage_source) && prob(parry_chance)) user.visible_message("\The [user] parries [attack_text] with \the [src]!") playsound(user.loc, 'sound/weapons/punchmiss.ogg', 50, 1) diff --git a/code/game/objects/items/weapons/melee/energy.dm b/code/game/objects/items/weapons/melee/energy.dm index 563b7a7ae8d..831a214dee3 100644 --- a/code/game/objects/items/weapons/melee/energy.dm +++ b/code/game/objects/items/weapons/melee/energy.dm @@ -62,7 +62,7 @@ add_fingerprint(user) return -/obj/item/melee/energy/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") +/obj/item/melee/energy/handle_shield(mob/user, var/on_back, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") if(active && default_parry_check(user, attacker, damage_source) && prob(50)) user.visible_message("\The [user] parries [attack_text] with \the [src]!") diff --git a/code/game/objects/items/weapons/shields.dm b/code/game/objects/items/weapons/shields.dm index dfb098eba24..758deb33e06 100644 --- a/code/game/objects/items/weapons/shields.dm +++ b/code/game/objects/items/weapons/shields.dm @@ -39,18 +39,25 @@ ) var/base_block_chance = 50 -/obj/item/shield/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") +/obj/item/shield/handle_shield(mob/user, var/on_back, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") if(user.incapacitated()) return 0 + var/shield_dir = reverse_dir[user.dir] + if(on_back) + shield_dir = user.dir + //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 + var/bad_arc = shield_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/shield/can_shield_back() + return TRUE + /obj/item/shield/proc/get_block_chance(mob/user, var/damage, atom/damage_source = null, mob/attacker = null) return base_block_chance @@ -139,7 +146,7 @@ var/shield_power = 150 var/active = 0 -/obj/item/shield/energy/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") +/obj/item/shield/energy/handle_shield(mob/user, var/on_back, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") if(!active) return 0 //turn it on first! @@ -150,8 +157,12 @@ spark(user.loc, 5) playsound(user.loc, 'sound/weapons/blade.ogg', 50, 1) + var/shield_dir = reverse_dir[user.dir] + if(on_back) + shield_dir = user.dir + //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 + var/bad_arc = shield_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))) diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index a413769e820..a3358aac98c 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -200,7 +200,7 @@ playsound(src.loc, "shatter", 70, 1) qdel(src) -/obj/item/clothing/suit/armor/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") +/obj/item/clothing/suit/armor/handle_shield(mob/user, var/on_back, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") if(!material) // No point checking for reflection. return ..() diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index 58e5f30013c..f4c10a9461e 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -130,7 +130,7 @@ siemens_coefficient = 0 pocket_slots = 4 -/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") +/obj/item/clothing/suit/armor/laserproof/handle_shield(mob/user, var/on_back, 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 @@ -200,7 +200,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/def_zone = null, var/attack_text = "the attack") +/obj/item/clothing/suit/armor/reactive/handle_shield(mob/user, var/on_back, 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() diff --git a/code/modules/holodeck/HolodeckObjects.dm b/code/modules/holodeck/HolodeckObjects.dm index da507ae92c2..55bbf9a4694 100644 --- a/code/modules/holodeck/HolodeckObjects.dm +++ b/code/modules/holodeck/HolodeckObjects.dm @@ -263,7 +263,7 @@ New() item_color = "red" -/obj/item/holo/esword/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") +/obj/item/holo/esword/handle_shield(mob/user, var/on_back, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") if(active && default_parry_check(user, attacker, damage_source) && prob(50)) user.visible_message("\The [user] parries [attack_text] with \the [src]!") diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 18878cdba97..f7b63e645bc 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -168,10 +168,17 @@ emp_act return null /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 - . = shield.handle_shield(src, damage, damage_source, attacker, def_zone, attack_text) - if(.) return + for(var/obj/item/shield in list(l_hand, r_hand, wear_suit, back)) + if(!shield) + continue + if(!shield.can_shield_back()) + continue + var/is_on_back = FALSE + if(back && back == shield) + is_on_back = TRUE + . = shield.handle_shield(src, is_on_back, damage, damage_source, attacker, def_zone, attack_text) + if(.) + return return 0 /mob/living/carbon/human/emp_act(severity) diff --git a/html/changelogs/geeves-back_shield.yml b/html/changelogs/geeves-back_shield.yml new file mode 100644 index 00000000000..3006ad2622d --- /dev/null +++ b/html/changelogs/geeves-back_shield.yml @@ -0,0 +1,6 @@ +author: Geeves + +delete-after: True + +changes: + - rscadd: "A shield worn on your back will now properly defend you from penetration in the rear." \ No newline at end of file