From 95c6c7345c62bd0b27fac0708193549a7659f628 Mon Sep 17 00:00:00 2001 From: kevinz000 <2003111+kevinz000@users.noreply.github.com> Date: Sun, 24 May 2020 14:56:01 -0700 Subject: [PATCH] implementations --- code/__DEFINES/combat/block.dm | 2 ++ code/_onclick/item_attack.dm | 4 ++- code/game/objects/items/melee/misc.dm | 2 +- code/game/objects/items/shields.dm | 2 ++ .../mob/living/carbon/carbon_defense.dm | 4 ++- .../mob/living/carbon/human/species.dm | 25 +++++++------ code/modules/mob/living/living_block.dm | 12 +++++++ .../mob/living/living_blocking_parrying.dm | 35 ++++++++++--------- code/modules/mob/living/living_defense.dm | 15 +++++--- .../mob/living/silicon/silicon_defense.dm | 14 ++++---- 10 files changed, 73 insertions(+), 42 deletions(-) diff --git a/code/__DEFINES/combat/block.dm b/code/__DEFINES/combat/block.dm index b489662078..84b739a1c7 100644 --- a/code/__DEFINES/combat/block.dm +++ b/code/__DEFINES/combat/block.dm @@ -51,6 +51,8 @@ #define BLOCK_RETURN_SET_DAMAGE_TO "set_damage_to" /// For [BLOCK_SHOULD_PARTIAL_MITIGATE]. Percentage mitigation. #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" /// Default if the above isn't set in the list. #define DEFAULT_REDIRECT_METHOD_PROJECTILE REDIRECT_METHOD_DEFLECT diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 98db89a100..f0e4a0ea08 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -125,8 +125,10 @@ if(!CHECK_MOBILITY(user, MOBILITY_STAND)) totitemdamage *= 0.5 //CIT CHANGES END HERE - if((user != src) && run_block(I, totitemdamage, "the [I.name]", ATTACK_TYPE_MELEE, I.armour_penetration, user) & BLOCK_SUCCESS) + var/list/block_return = list() + if((user != src) && run_block(I, totitemdamage, "the [I.name]", ATTACK_TYPE_MELEE, I.armour_penetration, user, return_list = block_return) & BLOCK_SUCCESS) return FALSE + totitemdamage = block_calculate_resultant_damage(totitemdamage, block_return) send_item_attack_message(I, user) I.do_stagger_action(src, user) if(I.force) diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm index c2db529675..2923e35bf7 100644 --- a/code/game/objects/items/melee/misc.dm +++ b/code/game/objects/items/melee/misc.dm @@ -664,4 +664,4 @@ . = ..() overlay = mutable_appearance(icon, overlay_state) overlay.appearance_flags = RESET_COLOR - add_overlay(overlay) \ No newline at end of file + add_overlay(overlay) diff --git a/code/game/objects/items/shields.dm b/code/game/objects/items/shields.dm index 593aa599c0..30e1460f8a 100644 --- a/code/game/objects/items/shields.dm +++ b/code/game/objects/items/shields.dm @@ -25,6 +25,8 @@ var/shieldbash_push_distance = 1 /datum/block_parry_data/shield + block_stamina_efficiency = 1 + block_stamina_cost_per_second = 3 /obj/item/shield/examine(mob/user) . = ..() diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 9c4f0316b7..0b0edc5742 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -87,8 +87,10 @@ totitemdamage *= 1.5 //CIT CHANGES END HERE var/impacting_zone = (user == src)? check_zone(user.zone_selected) : ran_zone(user.zone_selected) - if((user != src) && (run_block(I, totitemdamage, "the [I]", ATTACK_TYPE_MELEE, I.armour_penetration, user, impacting_zone) & BLOCK_SUCCESS)) + var/list/block_return = list() + if((user != src) && (run_block(I, totitemdamage, "the [I]", ATTACK_TYPE_MELEE, I.armour_penetration, user, impacting_zone, return_list = block_return) & BLOCK_SUCCESS)) return FALSE + totitemdamage = block_calculate_resultant_damage(totitemdamage, block_return) var/obj/item/bodypart/affecting = get_bodypart(impacting_zone) if(!affecting) //missing limb? we select the first bodypart (you can never have zero, because of chest) affecting = bodyparts[1] diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index aeab0042ac..7205a4bf59 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1668,10 +1668,22 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) disarm(M, H, attacker_style) /datum/species/proc/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H) + //CIT CHANGES START HERE - combatmode and resting checks + var/totitemdamage = I.force + if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE)) + totitemdamage *= 0.5 + if(!CHECK_MOBILITY(user, MOBILITY_STAND)) + totitemdamage *= 0.5 + if(istype(H)) + if(!(H.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE)) + totitemdamage *= 1.5 + //CIT CHANGES END HERE // Allows you to put in item-specific reactions based on species if(user != H) - if(H.run_block(I, I.force, "the [I.name]", ATTACK_TYPE_MELEE, I.armour_penetration, user, affecting.body_zone) & BLOCK_SUCCESS) + var/list/block_return = list() + if(H.run_block(I, I.force, "the [I.name]", ATTACK_TYPE_MELEE, I.armour_penetration, user, affecting.body_zone, return_list = block_return) & BLOCK_SUCCESS) return 0 + totitemdamage = block_calculate_resultant_damage(totitemdamage, block_return) if(H.check_martial_melee_block()) H.visible_message("[H] blocks [I]!") return 0 @@ -1686,16 +1698,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) var/armor_block = H.run_armor_check(affecting, "melee", "Your armor has protected your [hit_area].", "Your armor has softened a hit to your [hit_area].",I.armour_penetration) armor_block = min(90,armor_block) //cap damage reduction at 90% var/Iforce = I.force //to avoid runtimes on the forcesay checks at the bottom. Some items might delete themselves if you drop them. (stunning yourself, ninja swords) - //CIT CHANGES START HERE - combatmode and resting checks - var/totitemdamage = I.force - if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE)) - totitemdamage *= 0.5 - if(!CHECK_MOBILITY(user, MOBILITY_STAND)) - totitemdamage *= 0.5 - if(istype(H)) - if(!(H.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE)) - totitemdamage *= 1.5 - //CIT CHANGES END HERE + var/weakness = H.check_weakness(I, user) apply_damage(totitemdamage * weakness, I.damtype, def_zone, armor_block, H) //CIT CHANGE - replaces I.force with totitemdamage diff --git a/code/modules/mob/living/living_block.dm b/code/modules/mob/living/living_block.dm index c0f2bc809d..1efc487f60 100644 --- a/code/modules/mob/living/living_block.dm +++ b/code/modules/mob/living/living_block.dm @@ -93,3 +93,15 @@ SEND_SIGNAL(src, COMSIG_ITEM_CHECK_BLOCK, owner, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, block_return) var/existing = block_return[BLOCK_RETURN_NORMAL_BLOCK_CHANCE] block_return[BLOCK_RETURN_NORMAL_BLOCK_CHANCE] = max(existing || 0, final_block_chance) + +// HELPER PROCS + +/** + * Considers a block return_list and calculates damage to use from that. + */ +/proc/block_calculate_resultant_damage(damage, list/block_return) + if(!isnull(block_return[BLOCK_RETURN_SET_DAMAGE_TO)) // higher priority + return block_return[BLOCK_RETURN_SET_DAMAGE_TO] + else if(!isnull(block_return[BLOCK_RETURN_MITIGATION_PERCENT])) + return damage * ((100 - block_return[BLOCK_RETURN_MITIGATION_PERCENT]) * 0.01) + return damage diff --git a/code/modules/mob/living/living_blocking_parrying.dm b/code/modules/mob/living/living_blocking_parrying.dm index b721cb4a1a..ac867b7a75 100644 --- a/code/modules/mob/living/living_blocking_parrying.dm +++ b/code/modules/mob/living/living_blocking_parrying.dm @@ -108,7 +108,6 @@ GLOBAL_LIST_EMPTY(block_parry_data) var/parry_stamina_cost = 5 #warn implement - /// Parry windup duration in deciseconds. 0 to this is windup, afterwards is main stage. var/parry_time_windup = 2 /// Parry spindown duration in deciseconds. main stage end to this is the spindown stage, afterwards the parry fully ends. @@ -170,17 +169,17 @@ GLOBAL_LIST_EMPTY(block_parry_data) //Stubs. -/obj/item/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, parry_efficiency) +/obj/item/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, parry_efficiency, parry_time) -/mob/living/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, parry_efficiency) +/mob/living/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, parry_efficiency, parry_time) -/datum/martial_art/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, parry_efficiency) +/datum/martial_art/proc/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, parry_efficiency, parry_time) -/obj/item/proc/active_parry_reflex_counter(atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list) +/obj/item/proc/active_parry_reflex_counter(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list, parry_efficiency) -/mob/living/proc/active_parry_reflex_counter(atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list) +/mob/living/proc/active_parry_reflex_counter(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list, parry_efficiency) -/datum/martial_art/proc/active_parry_reflex_counter(atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list) +/datum/martial_art/proc/active_parry_reflex_counter(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list, parry_efficiency) /** * Gets the stage of our parry sequence we're currently in. @@ -203,6 +202,8 @@ GLOBAL_LIST_EMPTY(block_parry_data) /** * Gets the percentage efficiency of our parry. + * + * Returns a percentage in normal 0 to 100 scale, but not clamped to just 0 to 100. */ /mob/living/proc/get_parry_efficiency(attack_type) var/datum/block_parry_data/data = get_parry_data() @@ -236,16 +237,18 @@ GLOBAL_LIST_EMPTY(block_parry_data) var/efficiency = get_parry_efficiency(attack_type) switch(parrying) if(ITEM_PARRY) - . = active_parry_item.on_active_parry(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency) + . = active_parry_item.on_active_parry(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency, get_parry_time()) if(UNARMED_PARRY) - . = on_active_parry(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency) + . = on_active_parry(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency, get_parry_time()) if(MARTIAL_PARRY) - . = mind.martial_art.on_active_parry(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency) - if(efficiency <= 0) + . = mind.martial_art.on_active_parry(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency, get_parry_time()) + if(!isnull(return_list[BLOCK_RETURN_OVERRIDE_PARRY_EFFICIENCY])) // one of our procs overrode + efficiency = return_list[BLOCK_RETURN_OVERRIDE_PARRY_EFFICIENCY] + if(efficiency <= 0) // Do not allow automatically handled/standardized parries that increase damage for now. return . |= BLOCK_SHOULD_PARTIAL_MITIGATE - var/current = return_list[BLOCK_RETURN_MITIGATION_PERCENT] || 0 - return_list[BLOCK_RETURN_MITIGATION_PERCENT] = 100 - (clamp(100 - current, 0, 100) * clamp(1 - (efficiency / 100), 0, 1)) + 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. var/list/effect_text = run_parry_countereffects(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency) if(data.parry_default_handle_feedback) handle_parry_feedback(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency, effect_text) @@ -269,11 +272,11 @@ GLOBAL_LIST_EMPTY(block_parry_data) if(PARRY_COUNTERATTACK_PROC) switch(parrying) if(ITEM_PARRY) - active_parry_item.active_parry_reflex_counter(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list) + active_parry_item.active_parry_reflex_counter(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, parry_efficiency) if(UNARMED_PARRY) - active_parry_reflex_counter(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list) + active_parry_reflex_counter(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, parry_efficiency) if(MARTIAL_PARRY) - mind.martial_art.active_parry_reflex_counter(object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list) + mind.martial_art.active_parry_reflex_counter(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, parry_efficiency) if(PARRY_COUNTERATTACK_MELEE_ATTACK_CHAIN) switch(parrying) if(ITEM_PARRY) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 3e4fbd9625..1335c8c2dc 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -66,6 +66,7 @@ CRASH("Invalid rediretion mode [redirection_mode]") /mob/living/bullet_act(obj/item/projectile/P, def_zone) + var/totaldamage = P.damage 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 = run_block(P, P.damage, "the [P.name]", ATTACK_TYPE_PROJECTILE, P.armour_penetration, P.firer, def_zone, returnlist) @@ -76,9 +77,10 @@ if(returned & BLOCK_SUCCESS) P.on_hit(src, 100, 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) if(!P.nodamage) - apply_damage(P.damage, P.damage_type, def_zone, armor) + 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 @@ -111,10 +113,13 @@ I = AM throwpower = I.throwforce var/impacting_zone = ran_zone(BODY_ZONE_CHEST, 65)//Hits a random part of the body, geared towards the chest - if(run_block(AM, throwpower, "\the [AM.name]", ATTACK_TYPE_THROWN, 0, throwingdatum?.thrower, impacting_zone) & BLOCK_SUCCESS) + var/list/block_return = list() + var/total_damage = I.throwforce + if(run_block(AM, throwpower, "\the [AM.name]", ATTACK_TYPE_THROWN, 0, throwingdatum?.thrower, impacting_zone, return_list = block_return) & BLOCK_SUCCESS) hitpush = FALSE skipcatch = TRUE blocked = TRUE + total_damage = block_calculate_resultant_damage(total_damage, block_return) else if(I && I.throw_speed >= EMBED_THROWSPEED_THRESHOLD && can_embed(I, src) && prob(I.embedding.embed_chance) && !HAS_TRAIT(src, TRAIT_PIERCEIMMUNE) && (!HAS_TRAIT(src, TRAIT_AUTO_CATCH_ITEM) || incapacitated() || get_active_held_item())) embed_item(I) hitpush = FALSE @@ -143,7 +148,7 @@ visible_message("[src] has been hit by [I].", \ "[src] has been hit by [I].") var/armor = run_armor_check(impacting_zone, "melee", "Your armor has protected your [parse_zone(impacting_zone)].", "Your armor has softened hit to your [parse_zone(impacting_zone)].",I.armour_penetration) - apply_damage(I.throwforce, dtype, impacting_zone, armor) + apply_damage(total_damage, dtype, impacting_zone, armor) if(I.thrownby) log_combat(I.thrownby, src, "threw and hit", I) else @@ -303,8 +308,10 @@ 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(M.zone_selected)) & BLOCK_SUCCESS) + var/list/block_return = list() + if(run_block(M, damage, "the [M.name]", ATTACK_TYPE_MELEE, null, M, check_zone(M.zone_selected), return_list = block_return) & BLOCK_SUCCESS) return FALSE + damage = block_calculate_resultant_damage(damage, block_return) if (stat != DEAD) log_combat(M, src, "attacked") diff --git a/code/modules/mob/living/silicon/silicon_defense.dm b/code/modules/mob/living/silicon/silicon_defense.dm index dced5ae869..d03785f71c 100644 --- a/code/modules/mob/living/silicon/silicon_defense.dm +++ b/code/modules/mob/living/silicon/silicon_defense.dm @@ -113,6 +113,7 @@ flash_act(affect_silicon = 1) /mob/living/silicon/bullet_act(obj/item/projectile/P, def_zone) + var/totaldamage = P.damage 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 = run_block(P, P.damage, "the [P.name]", ATTACK_TYPE_PROJECTILE, P.armour_penetration, P.firer, def_zone, returnlist) @@ -123,17 +124,14 @@ if(returned & BLOCK_SUCCESS) P.on_hit(src, 100, def_zone) return BULLET_ACT_BLOCK + totaldamage = block_calculate_resultant_damage(totaldamage, returnlist) if((P.damage_type == BRUTE || P.damage_type == BURN)) - adjustBruteLoss(P.damage) - if(prob(P.damage*1.5)) - for(var/mob/living/M in buckled_mobs) - M.visible_message("[M] is knocked off of [src]!") - unbuckle_mob(M) - M.DefaultCombatKnockdown(40) - if(P.stun || P.knockdown) + adjustBruteLoss(totaldamage) + if((P.damage >= 10) || P.stun || P.knockdown || (P.stamina >= 20)) for(var/mob/living/M in buckled_mobs) + M.visible_message("[M] is knocked off of [src]!") unbuckle_mob(M) - M.visible_message("[M] is knocked off of [src] by the [P]!") + M.DefaultCombatKnockdown(40) P.on_hit(src) return BULLET_ACT_HIT