diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm
index e3eab3a8d8..5fe0f40bd1 100644
--- a/code/__DEFINES/combat.dm
+++ b/code/__DEFINES/combat.dm
@@ -233,10 +233,13 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
/// For keys in associative list/block_return as we don't want to saturate our (somewhat) limited flags.
#define BLOCK_RETURN_REDIRECT_METHOD "REDIRECT_METHOD"
/// Pass through victim
- #define REDIRECT_MODE_PASSTHROUGH "passthrough"
+ #define REDIRECT_METHOD_PASSTHROUGH "passthrough"
/// Reflect using normal angular/mirrorlike reflection
- #define REDIRECT_MODE_REFLECT "reflect"
+ #define REDIRECT_METHOD_REFLECT "reflect"
/// Deflect at randomish angle
- #define REDIRECT_MODE_DEFLECT "deflect"
+ #define REDIRECT_METHOD_DEFLECT "deflect"
/// do not taser the bad man with the desword
- #define REDIRECT_MODE_RETURN_TO_SENDER "no_you"
+ #define REDIRECT_METHOD_RETURN_TO_SENDER "no_you"
+
+/// Default if the above isn't set in the list.
+#define DEFAULT_REDIRECT_METHOD_PROJECTILE REDIRECT_METHOD_REFLECT
diff --git a/code/datums/martial/sleeping_carp.dm b/code/datums/martial/sleeping_carp.dm
index 2b7d9e0a09..e837277fce 100644
--- a/code/datums/martial/sleeping_carp.dm
+++ b/code/datums/martial/sleeping_carp.dm
@@ -237,7 +237,7 @@
else
return ..()
-/obj/item/twohanded/bostaff/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
- if(wielded)
- return ..()
- return FALSE
+/obj/item/twohanded/bostaff/run_block(mob/living/owner, real_attack, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
+ if(!wielded)
+ return BLOCK_NONE
+ return ..()
diff --git a/code/game/objects/items/melee/energy.dm b/code/game/objects/items/melee/energy.dm
index 3dc11e74b3..ac29c62d74 100644
--- a/code/game/objects/items/melee/energy.dm
+++ b/code/game/objects/items/melee/energy.dm
@@ -113,10 +113,10 @@
else
RemoveElement(/datum/element/sword_point)
-/obj/item/melee/transforming/energy/sword/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
- if(active)
- return ..()
- return 0
+/obj/item/melee/transforming/energy/sword/run_block(mob/living/owner, real_attack, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
+ if(!active)
+ return NONE
+ return ..()
/obj/item/melee/transforming/energy/sword/cyborg
item_color = "red"
diff --git a/code/game/objects/items/twohanded.dm b/code/game/objects/items/twohanded.dm
index 1fa09555a9..1400339a35 100644
--- a/code/game/objects/items/twohanded.dm
+++ b/code/game/objects/items/twohanded.dm
@@ -904,7 +904,8 @@
if(attack_type == ATTACK_TYPE_PROJECTILE)
owner.visible_message("[owner] deflects [attack_text] with [src]!")
playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, 1)
- return BLOCK_SUCCESS | BLOCK_SHOULD_DEFLECT | BLOCK_PHYSICAL_EXTERNAL
+ block_return[BLOCK_RETURN_REDIRECT_METHOD] = REDIRECT_METHOD_DEFLECT
+ return BLOCK_SUCCESS | BLOCK_REDIRECT | BLOCK_SHOULD_REDIRECT | BLOCK_PHYSICAL_EXTERNAL
else
owner.visible_message("[owner] parries [attack_text] with [src]!")
return BLOCK_SUCCESS | BLOCK_PARRY
@@ -1177,7 +1178,7 @@
if(iscyborg(target))
..()
return
- if(target.run_block(src, 0, "[user]'s [name]", BLOCK_TYPE_MELEE, 0, user) & BLOCK_SUCCESS) //No message; check_shields() handles that
+ if(target.run_block(src, 0, "[user]'s [name]", ATTACK_TYPE_MELEE, 0, user) & BLOCK_SUCCESS) //No message; check_shields() handles that
playsound(target, 'sound/weapons/genhit.ogg', 50, 1)
return FALSE
if(user.a_intent != INTENT_HARM)
diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm
index bc9c3255a6..7a95f0daff 100644
--- a/code/game/objects/items/weaponry.dm
+++ b/code/game/objects/items/weaponry.dm
@@ -155,8 +155,10 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
return
to_chat(user, "[src] thrums and points to the [dir2text(get_dir(user, closest_victim))].")
-/obj/item/claymore/highlander/IsReflect()
- return 1 //YOU THINK YOUR PUNY LASERS CAN STOP ME?
+/obj/item/claymore/highlander/run_block(mob/living/owner, real_attack, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
+ if((attack_type == ATTACK_TYPE_PROJECTILE) && is_energy_reflectable_projectile(object))
+ return BLOCK_SUCCESS | BLOCK_SHOULD_REDIRECT | BLOCK_PHYSICAL_EXTERNAL | BLOCK_REDIRECT
+ return ..()
/obj/item/claymore/highlander/proc/add_notch(mob/living/user) //DYNAMIC CLAYMORE PROGRESSION SYSTEM - THIS IS THE FUTURE
notches++
diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm
index 49c34f4d1f..b95e9a90f4 100644
--- a/code/modules/antagonists/changeling/powers/mutations.dm
+++ b/code/modules/antagonists/changeling/powers/mutations.dm
@@ -441,23 +441,20 @@
var/remaining_uses //Set by the changeling ability.
-/obj/item/shield/changeling/Initialize()
+/obj/item/shield/changeling/Initialize(mapload)
. = ..()
ADD_TRAIT(src, TRAIT_NODROP, CHANGELING_TRAIT)
if(ismob(loc))
loc.visible_message("The end of [loc.name]\'s hand inflates rapidly, forming a huge shield-like mass!", "We inflate our hand into a strong shield.", "You hear organic matter ripping and tearing!")
-/obj/item/shield/changeling/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
- if(remaining_uses < 1)
- if(ishuman(loc))
- var/mob/living/carbon/human/H = loc
- H.visible_message("With a sickening crunch, [H] reforms [H.p_their()] shield into an arm!", "We assimilate our shield into our body", "With a sickening crunch, [H] reforms [H.p_their()] shield into an arm!", "We assimilate our shield into our body", "The reactive teleport system is still recharging! It fails to teleport [H]!")
return
owner.visible_message("The reactive teleport system flings [H] clear of [attack_text], shutting itself off in the process!")
- playsound(get_turf(owner),'sound/magic/blink.ogg', 100, 1)
- var/list/turfs = new/list()
+ playsound(get_turf(owner), 'sound/magic/blink.ogg', 100, 1)
+ var/list/turfs = new
var/turf/old = get_turf(src)
for(var/turf/T in orange(tele_range, H))
if(T.density)
@@ -101,7 +106,9 @@
radiation_pulse(old, rad_amount_before)
radiation_pulse(src, rad_amount)
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
- return TRUE
+ block_return[BLOCK_RETURN_REDIRECT_METHOD] = REDIRECT_METHOD_PASSTHROUGH
+ return BLOCK_SUCCESS | BLOCK_REDIRECT | BLOCK_SHOULD_REDIRECT | BLOCK_TARGET_DODGED
+ return BLOCK_NONE
//Fire
@@ -109,9 +116,7 @@
name = "reactive incendiary armor"
desc = "An experimental suit of armor with a reactive sensor array rigged to a flame emitter. For the stylish pyromaniac."
-/obj/item/clothing/suit/armor/reactive/fire/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
- if(!active)
- return 0
+/obj/item/clothing/suit/armor/reactive/fire/block_action(mob/living/owner, real_attack, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(prob(hit_reaction_chance))
if(world.time < reactivearmor_cooldown)
owner.visible_message("The reactive incendiary armor on [owner] activates, but fails to send out flames as it is still recharging its flame jets!")
@@ -124,8 +129,8 @@
C.IgniteMob()
owner.fire_stacks = -20
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
- return 1
- return 0
+ return BLOCK_SUCCESS | BLOCK_PHYSICAL_INTERNAL
+ return BLOCK_NONE
//Stealth
@@ -134,9 +139,7 @@
reactivearmor_cooldown_duration = 65
desc = "An experimental suit of armor that renders the wearer invisible on detection of imminent harm, and creates a decoy that runs away from the owner. You can't fight what you can't see."
-/obj/item/clothing/suit/armor/reactive/stealth/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
- if(!active)
- return 0
+/obj/item/clothing/suit/armor/reactive/stealth/block_action(mob/living/owner, real_attack, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(prob(hit_reaction_chance))
if(world.time < reactivearmor_cooldown)
owner.visible_message("The reactive stealth system on [owner] activates, but is still recharging its holographic emitters!")
@@ -150,7 +153,8 @@
spawn(40)
owner.alpha = initial(owner.alpha)
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
- return 1
+ return BLOCK_SUCCESS | BLOCK_PHYSICAL_INTERNAL
+ return BLOCK_NONE
//Tesla
@@ -175,9 +179,7 @@
if(slot_flags & slotdefine2slotbit(slot)) //Was equipped to a valid slot for this item?
user.flags_1 |= TESLA_IGNORE_1
-/obj/item/clothing/suit/armor/reactive/tesla/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
- if(!active)
- return FALSE
+/obj/item/clothing/suit/armor/reactive/tesla/block_action(mob/living/owner, real_attack, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(prob(hit_reaction_chance))
if(world.time < reactivearmor_cooldown)
var/datum/effect_system/spark_spread/sparks = new /datum/effect_system/spark_spread
@@ -196,7 +198,8 @@
M.adjustFireLoss(legacy_dmg)
playsound(M, 'sound/machines/defib_zap.ogg', 50, 1, -1)
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
- return TRUE
+ return BLOCK_SUCCESS | BLOCK_PHYSICAL_INTERNAL
+ return NONE
//Repulse
@@ -205,9 +208,7 @@
reactivearmor_cooldown_duration = 20
desc = "An experimental suit of armor that violently throws back attackers."
-/obj/item/clothing/suit/armor/reactive/repulse/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
- if(!active)
- return 0
+/obj/item/clothing/suit/armor/reactive/repulse/block_action(mob/living/owner, real_attack, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(prob(hit_reaction_chance))
if(world.time < reactivearmor_cooldown)
owner.visible_message("The repulse generator is still recharging!")
@@ -234,7 +235,8 @@
AM.throw_at(throwtarget,10,1)
safety--
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
- return 1
+ return BLOCK_SUCCESS | BLOCK_PHYSICAL_INTERNAL
+ return BLOCK_NONE
/obj/item/clothing/suit/armor/reactive/table
name = "reactive table armor"
@@ -242,9 +244,7 @@
desc = "If you can't beat the memes, embrace them."
var/tele_range = 10
-/obj/item/clothing/suit/armor/reactive/table/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
- if(!active)
- return 0
+/obj/item/clothing/suit/armor/reactive/table/block_action(mob/living/owner, real_attack, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(prob(hit_reaction_chance))
var/mob/living/carbon/human/H = owner
if(world.time < reactivearmor_cooldown)
@@ -270,8 +270,8 @@
H.forceMove(picked)
new /obj/structure/table(get_turf(owner))
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
- return 1
- return 0
+ return BLOCK_SUCCESS | BLOCK_PHYSICAL_INTERNAL
+ return BLOCK_NONE
/obj/item/clothing/suit/armor/reactive/table/emp_act()
return
diff --git a/code/modules/clothing/under/color.dm b/code/modules/clothing/under/color.dm
index a18b7e5817..c02f78cb8f 100644
--- a/code/modules/clothing/under/color.dm
+++ b/code/modules/clothing/under/color.dm
@@ -79,9 +79,10 @@
name = "ancient jumpsuit"
desc = "A terribly ragged and frayed grey jumpsuit. It looks like it hasn't been washed in over a decade."
-/obj/item/clothing/under/color/grey/glorf/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
- owner.forcesay(GLOB.hit_appends)
- return 0
+/obj/item/clothing/under/color/grey/glorf/run_block(mob/living/owner, real_attack, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
+ . = ..()
+ if(real_attack)
+ owner.forcesay(GLOB.hit_appends)
/obj/item/clothing/under/color/blue
name = "blue jumpsuit"
diff --git a/code/modules/mob/living/carbon/carbon_block.dm b/code/modules/mob/living/carbon/carbon_block.dm
new file mode 100644
index 0000000000..14d68f6ea7
--- /dev/null
+++ b/code/modules/mob/living/carbon/carbon_block.dm
@@ -0,0 +1,4 @@
+/mob/living/carbon/get_blocking_items()
+ . = ..()
+ if(wear_suit)
+ . += wear_suit
diff --git a/code/modules/mob/living/carbon/human/human_block.dm b/code/modules/mob/living/carbon/human/human_block.dm
new file mode 100644
index 0000000000..946f21df07
--- /dev/null
+++ b/code/modules/mob/living/carbon/human/human_block.dm
@@ -0,0 +1,6 @@
+/mob/living/carbon/human/get_blocking_items()
+ . = ..()
+ if(w_uniform)
+ . += w_uniform
+ if(wear_neck)
+ . += wear_neck
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 7c1123dbad..9e72c80305 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -1786,7 +1786,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
return TRUE
if(M.mind)
attacker_style = M.mind.martial_art
- if((M != H) && M.a_intent != INTENT_HELP && (H.run_block(M, 0, "[M]", UNARMED_ATTACK, 0, M, M.zone_selected) & BLOCK_SUCCESS))
+ if((M != H) && M.a_intent != INTENT_HELP && (H.run_block(M, 0, "[M]", ATTACK_TYPE_UNARMED, 0, M, M.zone_selected) & BLOCK_SUCCESS))
log_combat(M, H, "attempted to touch")
H.visible_message("[M] attempted to touch [H]!")
return TRUE
diff --git a/code/modules/mob/living/living_block.dm b/code/modules/mob/living/living_block.dm
index 2ca63c3eb0..5267226d0d 100644
--- a/code/modules/mob/living/living_block.dm
+++ b/code/modules/mob/living/living_block.dm
@@ -46,29 +46,28 @@
*/
/mob/living/proc/do_run_block(real_attack = TRUE, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list = list())
// Component signal block runs have highest priority.. for now.
- . = SEND_SIGNAL(src, COMSIG_MOB_RUN_BLOCK, real_attack, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list)
+ . = SEND_SIGNAL(src, COMSIG_LIVING_RUN_BLOCK, real_attack, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list)
if(. & BLOCK_INTERRUPT_CHAIN)
return
- for(var/obj/item/I in held_items)
- if(istype(I, /obj/item/clothing)) //yeah usually this shouldn't.. uh, work. This is a bad check and should be removed though.
- continue
-
-
-
-/mob/living/proc/_check_shields()
+ var/list/obj/item/tocheck = get_blocking_items()
+ // i don't like this
var/block_chance_modifier = round(damage / -3)
- for(var/obj/item/I in held_items)
- if(!istype(I, /obj/item/clothing))
- var/final_block_chance = I.block_chance - (CLAMP((armour_penetration-I.armour_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
- return FALSE
+ for(var/obj/item/I in tocheck)
+ // i don't like this too
+ var/final_block_chance = I.block_chance - (CLAMP((armour_penetration-I.armour_penetration)/2,0,100)) + block_chance_modifier //So armour piercing blades can still be parried by other blades, for example
+ var/results = I.run_block(src, real_attack, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, return_list)
+ . |= results
+ if(results & BLOCK_INTERRUPT_CHAIN)
+ break
-/mob/living/proc/_check_reflect(def_zone) //Reflection checks for anything in your hands, based on the reflection chance of the object(s)
+/// Gets an unsortedlist of objects to run block checks on.
+/mob/living/proc/get_blocking_items()
+ . = list()
for(var/obj/item/I in held_items)
- if(I.IsReflect(def_zone))
- return TRUE
- return FALSE
+ // this is a bad check but i am not removing it until a better catchall is made
+ if(istype(I, /obj/item/clothing))
+ continue
+ . |= I
/obj/item
/// The 0% to 100% chance for the default implementation of random block rolls.
@@ -87,6 +86,7 @@
return 0
+
/mob/living/carbon/human/check_reflect(def_zone)
if(wear_suit?.IsReflect(def_zone))
return TRUE
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index d0d1ccce5d..0794fcefac 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -302,7 +302,7 @@
var/damage = rand(5, 35)
if(M.is_adult)
damage = rand(20, 40)
- if(run_block(M, damage, "the [M.name]", ATTACK_TYPE_MELEE, null, M, check_zone(user.zone_selected)) & BLOCK_SUCCESS)
+ if(run_block(M, damage, "the [M.name]", ATTACK_TYPE_MELEE, null, M, check_zone(M.zone_selected)) & BLOCK_SUCCESS)
return FALSE
if (stat != DEAD)