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)