diff --git a/code/__DEFINES/combat/block.dm b/code/__DEFINES/combat/block.dm index 19c541826e..bc85947d71 100644 --- a/code/__DEFINES/combat/block.dm +++ b/code/__DEFINES/combat/block.dm @@ -63,6 +63,8 @@ #define BLOCK_RETURN_MITIGATION_PERCENT "partial_mitigation" /// Used internally by run_parry proc, use on an on_active_parry() proc to override parrying efficiency. #define BLOCK_RETURN_OVERRIDE_PARRY_EFFICIENCY "override_parry_efficiency" +/// Always set to 100 by run_block() if BLOCK_SUCCESS is in return value. Otherwise, defaults to mitigation percent if not set. Used by projectile/proc/on_hit(). +#define BLOCK_RETURN_PROJECTILE_BLOCK_PERCENTAGE "projectile_block_percentage" /// Default if the above isn't set in the list. #define DEFAULT_REDIRECT_METHOD_PROJECTILE REDIRECT_METHOD_DEFLECT diff --git a/code/game/objects/items/shields.dm b/code/game/objects/items/shields.dm index a2660b1bfb..12a1b57364 100644 --- a/code/game/objects/items/shields.dm +++ b/code/game/objects/items/shields.dm @@ -29,6 +29,7 @@ block_start_delay = 3 block_damage_absorption = 0 block_resting_stamina_penalty_multiplier = 2 + block_projectile_mitigation = 50 /obj/item/shield/examine(mob/user) . = ..() diff --git a/code/game/objects/items/stunbaton.dm b/code/game/objects/items/stunbaton.dm index 60fc761bfe..fa0c9ba693 100644 --- a/code/game/objects/items/stunbaton.dm +++ b/code/game/objects/items/stunbaton.dm @@ -170,10 +170,12 @@ return disarming || (user.a_intent != INTENT_HARM) /obj/item/melee/baton/proc/baton_stun(mob/living/L, mob/user, disarming = FALSE) - if(L.mob_run_block(src, 0, "[user]'s [name]", ATTACK_TYPE_MELEE, 0, user, null, null) & BLOCK_SUCCESS) //No message; check_shields() handles that + var/list/return_list = list() + if(L.mob_run_block(src, 0, "[user]'s [name]", ATTACK_TYPE_MELEE, 0, user, null, return_list) & BLOCK_SUCCESS) //No message; check_shields() handles that playsound(L, 'sound/weapons/genhit.ogg', 50, 1) return FALSE var/stunpwr = stamforce + stunpwr = block_calculate_resultant_damage(stunpwr, return_list) var/obj/item/stock_parts/cell/our_cell = get_cell() if(!our_cell) switch_status(FALSE) diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index f3c35b0495..cd630a2c82 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -446,6 +446,7 @@ throw_range = 5 force_unwielded = 0 force_wielded = 0 + block_parry_data = null attack_verb = list("attacked", "struck", "hit") total_mass_on = TOTAL_MASS_TOY_SWORD sharpness = IS_BLUNT diff --git a/code/game/objects/items/twohanded.dm b/code/game/objects/items/twohanded.dm index f7e43e6d01..128621dff3 100644 --- a/code/game/objects/items/twohanded.dm +++ b/code/game/objects/items/twohanded.dm @@ -318,6 +318,7 @@ block_slowdown = 1 // no attacking while blocking block_lock_attacking = TRUE + block_projectile_mitigation = 75 parry_time_windup = 0 parry_time_active = 8 diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm index 3257b0e3bf..87d5abb89e 100644 --- a/code/modules/mob/living/damage_procs.dm +++ b/code/modules/mob/living/damage_procs.dm @@ -78,8 +78,6 @@ apply_damage(brain, BRAIN, def_zone, blocked) return 1 - - /mob/living/proc/apply_effect(effect = 0,effecttype = EFFECT_STUN, blocked = FALSE, knockdown_stamoverride, knockdown_stammax) var/hit_percent = (100-blocked)/100 if(!effect || (hit_percent <= 0)) @@ -108,7 +106,7 @@ return 1 -/mob/living/proc/apply_effects(stun = 0, knockdown = 0, unconscious = 0, irradiate = 0, slur = 0, stutter = 0, eyeblur = 0, drowsy = 0, blocked = FALSE, stamina = 0, jitter = 0, kd_stamoverride, kd_stammax) +/mob/living/proc/apply_effects(stun = 0, knockdown = 0, unconscious = 0, irradiate = 0, slur = 0, stutter = 0, eyeblur = 0, drowsy = 0, blocked = 0, stamina = 0, jitter = 0, kd_stamoverride, kd_stammax) if(blocked >= 100) return BULLET_ACT_BLOCK if(stun) diff --git a/code/modules/mob/living/living_active_block.dm b/code/modules/mob/living/living_active_block.dm index dacdc0c1c5..64f9a8f6e7 100644 --- a/code/modules/mob/living/living_active_block.dm +++ b/code/modules/mob/living/living_active_block.dm @@ -200,11 +200,12 @@ block_return[BLOCK_RETURN_ACTIVE_BLOCK_DAMAGE_MITIGATED] = damage - final_damage block_return[BLOCK_RETURN_SET_DAMAGE_TO] = final_damage . = BLOCK_SHOULD_CHANGE_DAMAGE - if(final_damage <= 0) + if((final_damage <= 0) || (damage <= 0)) . |= BLOCK_SUCCESS //full block owner.visible_message("[owner] blocks \the [attack_text] with [src]!") else owner.visible_message("[owner] dampens \the [attack_text] with [src]!") + block_return[BLOCK_RETURN_PROJECTILE_BLOCK_PERCENTAGE] = data.block_projectile_mitigation if(length(data.block_sounds)) playsound(loc, pickweight(data.block_sounds), 75, TRUE) on_active_block(owner, object, damage, damage_blocked, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, block_return, override_direction) diff --git a/code/modules/mob/living/living_active_parry.dm b/code/modules/mob/living/living_active_parry.dm index 9b4d022960..f281399960 100644 --- a/code/modules/mob/living/living_active_parry.dm +++ b/code/modules/mob/living/living_active_parry.dm @@ -204,6 +204,8 @@ . |= BLOCK_SHOULD_PARTIAL_MITIGATE if(isnull(return_list[BLOCK_RETURN_MITIGATION_PERCENT])) // if one of the on_active_parry procs overrode. We don't have to worry about interference since parries are the first thing checked in the [do_run_block()] sequence. return_list[BLOCK_RETURN_MITIGATION_PERCENT] = clamp(efficiency, 0, 100) // do not allow > 100% or < 0% for now. + if((return_list[BLOCK_RETURN_MITIGATION_PERCENT] >= 100) || (damage <= 0)) + . |= BLOCK_SUCCESS var/list/effect_text if(efficiency >= data.parry_efficiency_to_counterattack) run_parry_countereffects(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency) diff --git a/code/modules/mob/living/living_block.dm b/code/modules/mob/living/living_block.dm index 2cef06c9f4..d32265e478 100644 --- a/code/modules/mob/living/living_block.dm +++ b/code/modules/mob/living/living_block.dm @@ -24,6 +24,7 @@ // Component signal block runs have highest priority.. for now. . = SEND_SIGNAL(src, COMSIG_LIVING_RUN_BLOCK, real_attack, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, attack_direction) if((. & BLOCK_SUCCESS) && !(. & BLOCK_CONTINUE_CHAIN)) + return_list[BLOCK_RETURN_PROJECTILE_BLOCK_PERCENTAGE] = 100 return var/list/obj/item/tocheck = get_blocking_items() sortTim(tocheck, /proc/cmp_numeric_dsc, TRUE) @@ -49,6 +50,10 @@ I.check_active_block(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, return_list, attack_direction) else I.check_block(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, return_list) + if(. & BLOCK_SUCCESS) + return_list[BLOCK_RETURN_PROJECTILE_BLOCK_PERCENTAGE] = 100 + else if(isnull(return_list[BLOCK_RETURN_PROJECTILE_BLOCK_PERCENTAGE])) + return_list[BLOCK_RETURN_PROJECTILE_BLOCK_PERCENTAGE] = return_list[BLOCK_RETURN_MITIGATION_PERCENT] /// Gets an unsortedlist of objects to run block checks on. List must have associative values for priorities! /mob/living/proc/get_blocking_items() diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm index 424c91e845..67d90a37f3 100644 --- a/code/modules/mob/living/living_blocking_parrying.dm +++ b/code/modules/mob/living/living_blocking_parrying.dm @@ -53,6 +53,9 @@ GLOBAL_LIST_EMPTY(block_parry_data) /// Override upper bound of damage block, list("[ATTACK_TYPE_DEFINE]" = absorption), see [block_damage_limit] var/list/block_damage_limit_override + /// The blocked variable of on_hit() on projectiles is impacted by this. Higher is better, 0 to 100, percentage. + var/block_projectile_mitigation = 50 + /* * NOTE: Overrides for attack types for most the block_stamina variables were removed, * because at the time of writing nothing needed to use it. Add them if you need it, diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index e8faa7b3ec..2ca1b63b14 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -67,15 +67,17 @@ /mob/living/bullet_act(obj/item/projectile/P, def_zone) var/totaldamage = P.damage + var/final_percent = 0 if(P.original != src || P.firer != src) //try to block or reflect the bullet, can't do so when shooting oneself var/list/returnlist = list() var/returned = mob_run_block(P, P.damage, "the [P.name]", ATTACK_TYPE_PROJECTILE, P.armour_penetration, P.firer, def_zone, returnlist) + final_percent = returnlist[BLOCK_RETURN_PROJECTILE_BLOCK_PERCENTAGE] if(returned & BLOCK_SHOULD_REDIRECT) handle_projectile_attack_redirection(P, returnlist[BLOCK_RETURN_REDIRECT_METHOD]) if(returned & BLOCK_REDIRECTED) return BULLET_ACT_FORCE_PIERCE if(returned & BLOCK_SUCCESS) - P.on_hit(src, 100, def_zone) + P.on_hit(src, final_percent, def_zone) return BULLET_ACT_BLOCK totaldamage = block_calculate_resultant_damage(totaldamage, returnlist) var/armor = run_armor_check(def_zone, P.flag, null, null, P.armour_penetration, null) @@ -83,7 +85,11 @@ apply_damage(totaldamage, P.damage_type, def_zone, armor) if(P.dismemberment) check_projectile_dismemberment(P, def_zone) - return P.on_hit(src, armor) ? BULLET_ACT_HIT : BULLET_ACT_BLOCK + var/missing = 100 - final_percent + var/armor_ratio = armor * 0.01 + if(missing > 0) + final_percent += missing * armor_ratio + return P.on_hit(src, final_percent, def_zone) ? BULLET_ACT_HIT : BULLET_ACT_BLOCK /mob/living/proc/check_projectile_dismemberment(obj/item/projectile/P, def_zone) return 0 diff --git a/code/modules/mob/living/silicon/silicon_defense.dm b/code/modules/mob/living/silicon/silicon_defense.dm index e5b487d510..0850f0f886 100644 --- a/code/modules/mob/living/silicon/silicon_defense.dm +++ b/code/modules/mob/living/silicon/silicon_defense.dm @@ -129,7 +129,7 @@ if(returned & BLOCK_REDIRECTED) return BULLET_ACT_FORCE_PIERCE if(returned & BLOCK_SUCCESS) - P.on_hit(src, 100, def_zone) + P.on_hit(src, returnlist[BLOCK_RETURN_PROJECTILE_BLOCK_PERCENTAGE], def_zone) return BULLET_ACT_BLOCK totaldamage = block_calculate_resultant_damage(totaldamage, returnlist) if((P.damage_type == BRUTE || P.damage_type == BURN)) @@ -140,7 +140,7 @@ "You are knocked off of [src] by the [P]!") unbuckle_mob(M) M.DefaultCombatKnockdown(40) - P.on_hit(src) + P.on_hit(src, 0, def_zone) return BULLET_ACT_HIT /mob/living/silicon/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /obj/screen/fullscreen/flash/static) diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index a5938c2758..3705f7902c 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -162,7 +162,15 @@ /obj/item/projectile/proc/prehit(atom/target) return TRUE -/obj/item/projectile/proc/on_hit(atom/target, blocked = FALSE) +/** + * Called when we hit something. + * + * @params + * * target - what we hit + * * blocked - 0 to 100 percentage mitigation/block + * * def zone - where we hit if we hit a mob. + */ +/obj/item/projectile/proc/on_hit(atom/target, blocked = 0, def_zone) if(fired_from) SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_ON_HIT, firer, target, Angle) var/turf/target_loca = get_turf(target)