Reworks block chance into Parrying. (#19334)

* parry component

* converts block chance to parry components

* armour pen, katana fix, pickup fix

* melee parry fix

* removes perfect parries, tweaks armour pen calc

* SIGNAL_HANDLER

* fix

* resist fix

* reduces parry time out time, increases cooldown

* Apply suggestions from code review

Co-authored-by: Farie82 <farie82@users.noreply.github.com>

* fix

* cooldown rebalance

Co-authored-by: Farie82 <farie82@users.noreply.github.com>
This commit is contained in:
Charlie
2022-11-12 08:49:44 +01:00
committed by GitHub
co-authored by Farie82
parent 8679d130bb
commit 421777b317
20 changed files with 195 additions and 66 deletions
+3 -5
View File
@@ -81,7 +81,6 @@ GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons
var/breakouttime = 0
var/flags_cover = 0 //for flags such as GLASSESCOVERSEYES
var/block_chance = 0
var/hit_reaction_chance = 0 //If you want to have something unrelated to blocking/armour piercing etc. Maybe not needed, but trying to think ahead/allow more freedom
// Needs to be in /obj/item because corgis can wear a lot of
@@ -399,11 +398,10 @@ GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons
return ..()
/obj/item/proc/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
SEND_SIGNAL(src, COMSIG_ITEM_HIT_REACT, args)
if(prob(final_block_chance))
if((SEND_SIGNAL(src, COMSIG_ITEM_HIT_REACT, owner, hitby, damage, attack_type) & COMPONENT_BLOCK_SUCCESSFUL) || prob(final_block_chance))
owner.visible_message("<span class='danger'>[owner] blocks [attack_text] with [src]!</span>")
return 1
return 0
return TRUE
return FALSE
// Generic use proc. Depending on the item, it uses up fuel, charges, sheets, etc.
// Returns TRUE on success, FALSE on failure.
@@ -130,7 +130,10 @@
w_class = WEIGHT_CLASS_HUGE
force = 5
slot_flags = SLOT_BACK
block_chance = 50
/obj/item/nullrod/staff/Initialize(mapload)
. = ..()
AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.5, _parryable_attack_types = ALL_ATTACK_TYPES)
/obj/item/nullrod/staff/blue
name = "blue holy staff"
@@ -144,11 +147,14 @@
desc = "A weapon fit for a crusade!"
w_class = WEIGHT_CLASS_BULKY
slot_flags = SLOT_BACK|SLOT_BELT
block_chance = 30
sharp = TRUE
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
/obj/item/nullrod/claymore/Initialize(mapload)
. = ..()
AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.7, _parryable_attack_types = ALL_ATTACK_TYPES, _parry_cooldown = (7 / 3) SECONDS) // 2.3333 seconds of cooldown for 30% uptime
/obj/item/nullrod/claymore/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(attack_type == PROJECTILE_ATTACK)
final_block_chance = 0 //Don't bring a sword to a gunfight
@@ -381,7 +387,6 @@
desc = "A long, tall staff made of polished wood. Traditionally used in ancient old-Earth martial arts, now used to harass the clown."
w_class = WEIGHT_CLASS_BULKY
force = 13
block_chance = 40
slot_flags = SLOT_BACK
sharp = FALSE
hitsound = "swing_hit"
@@ -389,6 +394,10 @@
icon_state = "bostaff0"
item_state = "bostaff0"
/obj/item/nullrod/claymore/bostaff/Initialize(mapload)
. = ..()
AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.4, _parryable_attack_types = ALL_ATTACK_TYPES, _parry_cooldown = (2 / 3) SECONDS ) // will remove the other component, 0.666667 seconds for 60% uptime.
/obj/item/nullrod/tribal_knife
name = "arrhythmic knife"
icon_state = "crysknife"
@@ -531,7 +540,6 @@
w_class = WEIGHT_CLASS_HUGE
force = 5
slot_flags = SLOT_BACK
block_chance = 50
var/team_color = "red"
var/obj/item/clothing/suit/hooded/chaplain_hoodie/missionary_robe/robes = null //the robes linked with this staff
@@ -547,6 +555,7 @@
icon_state = "godstaff-[team_color]"
item_state = "godstaff-[team_color]"
name = "[team_color] holy staff"
AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.5, _parryable_attack_types = ALL_ATTACK_TYPES)
/obj/item/nullrod/missionary_staff/Destroy()
if(robes) //delink on destruction
@@ -124,7 +124,6 @@
armour_penetration_percentage = 50
armour_penetration_flat = 10
origin_tech = "combat=3;magnets=4;syndicate=4"
block_chance = 50
sharp = TRUE
var/hacked = FALSE
@@ -132,6 +131,7 @@
..()
if(item_color == null)
item_color = pick("red", "blue", "green", "purple")
AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.5, _parryable_attack_types = ALL_ATTACK_TYPES)
/obj/item/melee/energy/sword/detailed_examine()
return "The energy sword is a very strong melee weapon, capable of severing limbs easily, if they are targeted. It can also has a chance \
@@ -29,7 +29,6 @@
force = 15
throwforce = 10
w_class = WEIGHT_CLASS_BULKY
block_chance = 50
armour_penetration_percentage = 75
sharp = TRUE
origin_tech = "combat=5"
@@ -38,10 +37,9 @@
materials = list(MAT_METAL = 1000)
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF // Theft targets should be hard to destroy
/obj/item/melee/rapier/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(attack_type == PROJECTILE_ATTACK)
final_block_chance = 0 //Don't bring a sword to a gunfight
return ..()
/obj/item/melee/rapier/Initialize(mapload)
. = ..()
AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.5, _parryable_attack_types = NON_PROJECTILE_ATTACKS)
/obj/item/melee/icepick
name = "ice pick"
@@ -108,13 +106,17 @@
w_class = WEIGHT_CLASS_BULKY
force = 25
armour_penetration_flat = 50
block_chance = 50
sharp = TRUE
///enchantment holder, gives it unique on hit effects.
var/datum/enchantment/enchant = null
///the cooldown and power of enchantments are multiplied by this var when its applied
var/power = 1
/obj/item/melee/spellblade/Initialize(mapload)
. = ..()
AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.5, _parryable_attack_types = ALL_ATTACK_TYPES)
/obj/item/melee/spellblade/Destroy()
QDEL_NULL(enchant)
return ..()
+21 -8
View File
@@ -1,11 +1,15 @@
/obj/item/shield
name = "shield"
block_chance = 50
armor = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 0, BOMB = 30, BIO = 0, RAD = 0, FIRE = 80, ACID = 70)
/obj/item/shield/proc/add_parry_component()
AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.5, _parryable_attack_types = ALL_ATTACK_TYPES)
/obj/item/shield/Initialize(mapload)
. = ..()
add_parry_component()
/obj/item/shield/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(attack_type == THROWN_PROJECTILE_ATTACK)
final_block_chance += 30
if(attack_type == LEAP_ATTACK)
final_block_chance = 100
return ..()
@@ -25,9 +29,9 @@
attack_verb = list("shoved", "bashed")
var/cooldown = 0 //shield bash cooldown. based on world.time
/obj/item/shield/riot/attackby(obj/item/W as obj, mob/user as mob, params)
/obj/item/shield/riot/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/melee/baton))
if(cooldown < world.time - 25)
if(cooldown < world.time - 2.5 SECONDS)
user.visible_message("<span class='warning'>[user] bashes [src] with [W]!</span>")
playsound(user.loc, 'sound/effects/shieldbash.ogg', 50, 1)
cooldown = world.time
@@ -43,9 +47,11 @@
/obj/item/shield/riot/roman/fake
desc = "Bears an inscription on the inside: <i>\"Romanes venio domus\"</i>. It appears to be a bit flimsy."
block_chance = 0
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0)
/obj/item/shield/riot/roman/fake/add_parry_component()
return
/obj/item/shield/riot/buckler
name = "wooden buckler"
desc = "A medieval wooden buckler."
@@ -54,7 +60,10 @@
materials = list()
origin_tech = "materials=1;combat=3;biotech=2"
resistance_flags = FLAMMABLE
block_chance = 30
/obj/item/shield/riot/buckler/add_parry_component()
AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.7, _parryable_attack_types = ALL_ATTACK_TYPES, _parry_cooldown = (7 / 3) SECONDS) // 2.3333 seconds of cooldown for 30% uptime
/obj/item/shield/energy
name = "energy combat shield"
@@ -69,6 +78,9 @@
attack_verb = list("shoved", "bashed")
var/active = FALSE
/obj/item/shield/energy/add_parry_component()
return
/obj/item/shield/energy/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(istype(hitby, /obj/item/projectile))
var/obj/item/projectile/P = hitby
@@ -111,6 +123,7 @@
if(!forced)
add_fingerprint(user)
return
/obj/item/shield/riot/tele
name = "telescopic shield"
desc = "An advanced riot shield made of lightweight materials that collapses for easy storage."
@@ -127,7 +140,7 @@
/obj/item/shield/riot/tele/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
return FALSE // by not calling the parent the hit_reaction signal is never sent
/obj/item/shield/riot/tele/attack_self(mob/living/user)
active = !active
+2 -2
View File
@@ -285,7 +285,6 @@
armour_penetration_flat = 10
origin_tech = "magnets=4;syndicate=5"
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
block_chance = 75
sharp_when_wielded = TRUE // only sharp when wielded
max_integrity = 200
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 70)
@@ -299,6 +298,7 @@
..()
if(!blade_color)
blade_color = pick("red", "blue", "green", "purple")
AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.25, _parryable_attack_types = ALL_ATTACK_TYPES, _parry_cooldown = (1 / 3) SECONDS) // 0.3333 seconds of cooldown for 75% uptime
/obj/item/twohanded/dualsaber/update_icon_state()
if(wielded)
@@ -838,7 +838,6 @@
force_wielded = 22
damtype = BURN
armour_penetration_percentage = 50
block_chance = 50
sharp = TRUE
attack_effect_override = ATTACK_EFFECT_CLAW
hitsound = 'sound/weapons/bladeslice.ogg'
@@ -850,6 +849,7 @@
/obj/item/twohanded/required/pyro_claws/Initialize(mapload)
. = ..()
START_PROCESSING(SSobj, src)
AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.5, _parryable_attack_types = ALL_ATTACK_TYPES)
/obj/item/twohanded/required/pyro_claws/Destroy()
STOP_PROCESSING(SSobj, src)
+8 -2
View File
@@ -55,11 +55,14 @@
sharp = TRUE
w_class = WEIGHT_CLASS_NORMAL
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
block_chance = 50
max_integrity = 200
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 50)
resistance_flags = FIRE_PROOF
/obj/item/claymore/Initialize(mapload)
. = ..()
AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.5, _parryable_attack_types = ALL_ATTACK_TYPES)
/obj/item/claymore/suicide_act(mob/user)
user.visible_message("<span class='suicide'>[user] is falling on [src]! It looks like [user.p_theyre()] trying to commit suicide.</span>")
return BRUTELOSS
@@ -82,12 +85,15 @@
w_class = WEIGHT_CLASS_BULKY
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
block_chance = 50
max_integrity = 200
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 50)
resistance_flags = FIRE_PROOF
needs_permit = TRUE
/obj/item/katana/Initialize(mapload)
. = ..()
AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.5, _parryable_attack_types = ALL_ATTACK_TYPES)
/obj/item/katana/suicide_act(mob/user)
user.visible_message("<span class='suicide'>[user] is slitting [user.p_their()] stomach open with [src]! It looks like [user.p_theyre()] trying to commit seppuku.</span>")