mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-24 04:27:35 +01:00
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:
@@ -70,6 +70,11 @@
|
||||
#define PROJECTILE_ATTACK 3
|
||||
#define THROWN_PROJECTILE_ATTACK 4
|
||||
#define LEAP_ATTACK 5
|
||||
#define ALL_ATTACK_TYPES list(MELEE_ATTACK, UNARMED_ATTACK, PROJECTILE_ATTACK, THROWN_PROJECTILE_ATTACK, LEAP_ATTACK)
|
||||
#define NON_PROJECTILE_ATTACKS list(MELEE_ATTACK, UNARMED_ATTACK, LEAP_ATTACK)
|
||||
|
||||
// the standard parry time out time
|
||||
#define PARRY_DEFAULT_TIMEOUT 1 SECONDS
|
||||
|
||||
//attack visual effects
|
||||
#define ATTACK_EFFECT_PUNCH "punch"
|
||||
|
||||
@@ -529,6 +529,7 @@
|
||||
#define COMPONENT_BLOCK_MARK_RETRIEVAL (1<<0)
|
||||
///from base of obj/item/hit_reaction(): (list/args)
|
||||
#define COMSIG_ITEM_HIT_REACT "item_hit_react"
|
||||
#define COMPONENT_BLOCK_SUCCESSFUL (1 << 0)
|
||||
///called on item when crossed by something (): (/atom/movable, mob/living/crossed)
|
||||
#define COMSIG_ITEM_WEARERCROSSED "wearer_crossed"
|
||||
///called on item when microwaved (): (obj/machinery/microwave/M)
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#define CLICK_CD_HANDCUFFED 10
|
||||
#define CLICK_CD_TKSTRANGLE 10
|
||||
#define CLICK_CD_POINT 10
|
||||
#define CLICK_CD_RESIST 20
|
||||
#define CLICK_CD_RESIST 8
|
||||
#define CLICK_CD_CLICK_ABILITY 6
|
||||
#define CLICK_CD_RAPID 2
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/datum/component/parry
|
||||
/// the world.time we last parried at
|
||||
var/time_parried
|
||||
/// the max time since `time_parried` that the shield is still considered "active"
|
||||
var/parry_time_out_time
|
||||
|
||||
/// the flat amount of damage the shield user takes per non-perfect parry
|
||||
var/stamina_constant
|
||||
/// stamina_coefficient * damage * time_since_time_parried = stamina damage taken per non perfect parry
|
||||
var/stamina_coefficient
|
||||
/// the attack types that are considered for parrying
|
||||
var/parryable_attack_types
|
||||
/// the time between parry attempts
|
||||
var/parry_cooldown
|
||||
|
||||
/datum/component/parry/RegisterWithParent()
|
||||
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(equipped))
|
||||
RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(dropped))
|
||||
RegisterSignal(parent, COMSIG_ITEM_HIT_REACT, PROC_REF(attempt_parry))
|
||||
|
||||
/datum/component/parry/UnregisterFromParent()
|
||||
UnregisterSignal(parent, COMSIG_ITEM_EQUIPPED)
|
||||
UnregisterSignal(parent, COMSIG_ITEM_DROPPED)
|
||||
UnregisterSignal(parent, COMSIG_ITEM_HIT_REACT)
|
||||
var/obj/item/I = parent
|
||||
if(ismob(I.loc))
|
||||
UnregisterSignal(I.loc, COMSIG_LIVING_RESIST)
|
||||
|
||||
/datum/component/parry/Initialize(_stamina_constant = 0, _stamina_coefficient = 0, _parry_time_out_time = PARRY_DEFAULT_TIMEOUT, _parryable_attack_types = ALL_ATTACK_TYPES, _parry_cooldown = 2 SECONDS)
|
||||
if(!isitem(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
parry_time_out_time = _parry_time_out_time
|
||||
stamina_constant = _stamina_constant
|
||||
stamina_coefficient = _stamina_coefficient
|
||||
parry_cooldown = _parry_cooldown
|
||||
if(islist(_parryable_attack_types))
|
||||
parryable_attack_types = _parryable_attack_types
|
||||
else
|
||||
parryable_attack_types = list(_parryable_attack_types)
|
||||
|
||||
/datum/component/parry/proc/equipped(datum/source, mob/user, slot)
|
||||
SIGNAL_HANDLER
|
||||
if(slot in list(slot_l_hand, slot_r_hand))
|
||||
RegisterSignal(user, COMSIG_LIVING_RESIST, PROC_REF(start_parry))
|
||||
else
|
||||
UnregisterSignal(user, COMSIG_LIVING_RESIST)
|
||||
|
||||
/datum/component/parry/proc/dropped(datum/source, mob/user)
|
||||
SIGNAL_HANDLER
|
||||
UnregisterSignal(user, COMSIG_LIVING_RESIST)
|
||||
|
||||
/datum/component/parry/proc/start_parry(mob/living/L)
|
||||
SIGNAL_HANDLER
|
||||
var/time_since_parry = world.time - time_parried
|
||||
if(time_since_parry < parry_cooldown) // stops spam
|
||||
return
|
||||
|
||||
time_parried = world.time
|
||||
L.do_attack_animation(L, used_item = parent)
|
||||
|
||||
/datum/component/parry/proc/attempt_parry(datum/source, mob/living/carbon/human/owner, atom/movable/hitby, damage = 0, attack_type = MELEE_ATTACK)
|
||||
SIGNAL_HANDLER
|
||||
if(!(attack_type in parryable_attack_types))
|
||||
return
|
||||
var/time_since_parry = world.time - time_parried
|
||||
if(time_since_parry > parry_time_out_time)
|
||||
return
|
||||
|
||||
var/armour_penetration_percentage = 0
|
||||
var/armour_penetration_flat = 0
|
||||
|
||||
if(isitem(hitby))
|
||||
var/obj/item/I = hitby
|
||||
armour_penetration_percentage = I.armour_penetration_percentage
|
||||
armour_penetration_flat = I.armour_penetration_flat
|
||||
|
||||
if(armour_penetration_flat + armour_penetration_percentage >= 100)
|
||||
return
|
||||
|
||||
var/stamina_damage = stamina_coefficient * (((time_since_parry / parry_time_out_time) + armour_penetration_percentage / 100) * (damage + armour_penetration_flat)) + stamina_constant
|
||||
|
||||
var/sound_to_play
|
||||
if(attack_type == PROJECTILE_ATTACK)
|
||||
sound_to_play = pick('sound/weapons/effects/ric1.ogg', 'sound/weapons/effects/ric2.ogg', 'sound/weapons/effects/ric3.ogg', 'sound/weapons/effects/ric4.ogg', 'sound/weapons/effects/ric5.ogg')
|
||||
else
|
||||
sound_to_play = 'sound/weapons/parry.ogg'
|
||||
|
||||
playsound(owner, sound_to_play, clamp(stamina_damage, 40, 120))
|
||||
|
||||
owner.adjustStaminaLoss(stamina_damage)
|
||||
if(owner.getStaminaLoss() < 100)
|
||||
return COMPONENT_BLOCK_SUCCESSFUL
|
||||
|
||||
|
||||
|
||||
@@ -505,7 +505,7 @@
|
||||
|
||||
// Hit by a melee weapon or blocked a projectile
|
||||
. = ..()
|
||||
if(.) // 50|50 chance
|
||||
if(.) // they did parry the attack
|
||||
playsound(src, 'sound/weapons/parry.ogg', 100, TRUE)
|
||||
if(illusions > 0)
|
||||
illusions--
|
||||
@@ -568,7 +568,6 @@
|
||||
throwforce = 30
|
||||
throw_speed = 2
|
||||
armour_penetration_percentage = 50
|
||||
block_chance = 30
|
||||
attack_verb = list("attacked", "impaled", "stabbed", "torn", "gored")
|
||||
sharp = TRUE
|
||||
no_spin_thrown = TRUE
|
||||
@@ -576,6 +575,10 @@
|
||||
needs_permit = TRUE
|
||||
var/datum/action/innate/cult/spear/spear_act
|
||||
|
||||
/obj/item/twohanded/cult_spear/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.4, _parryable_attack_types = ALL_ATTACK_TYPES, _parry_cooldown = (2 / 3) SECONDS ) // 0.666667 seconds for 60% uptime.
|
||||
|
||||
/obj/item/twohanded/cult_spear/Destroy()
|
||||
if(spear_act)
|
||||
qdel(spear_act)
|
||||
@@ -626,20 +629,6 @@
|
||||
playsound(T, 'sound/effects/glassbr3.ogg', 100)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/twohanded/cult_spear/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)
|
||||
final_block_chance *= 2
|
||||
if(prob(final_block_chance))
|
||||
if(attack_type == PROJECTILE_ATTACK)
|
||||
owner.visible_message("<span class='danger'>[owner] deflects [attack_text] with [src]!</span>")
|
||||
playsound(src, pick('sound/weapons/effects/ric1.ogg', 'sound/weapons/effects/ric2.ogg', 'sound/weapons/effects/ric3.ogg', 'sound/weapons/effects/ric4.ogg', 'sound/weapons/effects/ric5.ogg'), 100, TRUE)
|
||||
return TRUE
|
||||
else
|
||||
playsound(src, 'sound/weapons/parry.ogg', 100, TRUE)
|
||||
owner.visible_message("<span class='danger'>[owner] parries [attack_text] with [src]!</span>")
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/twohanded/cult_spear/attack(mob/living/M, mob/living/user, def_zone)
|
||||
. = ..()
|
||||
var/datum/status_effect/cult_stun_mark/S = M.has_status_effect(STATUS_EFFECT_CULT_STUN)
|
||||
|
||||
@@ -440,7 +440,10 @@
|
||||
throwforce = 10
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
|
||||
block_chance = 50
|
||||
|
||||
/obj/item/holo/claymore/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.5, _parryable_attack_types = NON_PROJECTILE_ATTACKS)
|
||||
|
||||
|
||||
/obj/item/holo/claymore/blue
|
||||
@@ -462,9 +465,12 @@
|
||||
throwforce = 0
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
armour_penetration_percentage = 50
|
||||
block_chance = 50
|
||||
var/active = FALSE
|
||||
|
||||
/obj/item/holo/esword/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.5, _parryable_attack_types = NON_PROJECTILE_ATTACKS)
|
||||
|
||||
/obj/item/holo/esword/green/New()
|
||||
..()
|
||||
item_color = "green"
|
||||
|
||||
@@ -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 ..()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>")
|
||||
|
||||
@@ -360,12 +360,12 @@
|
||||
desc = "A mass of tough, boney tissue. You can still see the fingers as a twisted pattern in the shield."
|
||||
flags = NODROP | DROPDEL
|
||||
icon_state = "ling_shield"
|
||||
block_chance = 50
|
||||
|
||||
var/remaining_uses //Set by the changeling ability.
|
||||
|
||||
/obj/item/shield/changeling/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.5, _parryable_attack_types = ALL_ATTACK_TYPES)
|
||||
if(ismob(loc))
|
||||
loc.visible_message("<span class='warning'>The end of [loc.name]\'s hand inflates rapidly, forming a huge shield-like mass!</span>", "<span class='warning'>We inflate our hand into a strong shield.</span>", "<span class='warning'>You hear organic matter ripping and tearing!</span>")
|
||||
|
||||
|
||||
@@ -323,7 +323,10 @@
|
||||
throw_speed = 2
|
||||
attack_verb = list("smashed", "slammed", "whacked", "thwacked")
|
||||
icon_state = "bostaff0"
|
||||
block_chance = 50
|
||||
|
||||
/obj/item/twohanded/bostaff/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.5, _parryable_attack_types = ALL_ATTACK_TYPES)
|
||||
|
||||
/obj/item/twohanded/bostaff/update_icon_state()
|
||||
icon_state = "bostaff[wielded]"
|
||||
|
||||
@@ -503,7 +503,6 @@
|
||||
force = 15
|
||||
armour_penetration_percentage = 40
|
||||
armour_penetration_flat = 10
|
||||
block_chance = 50
|
||||
sharp = TRUE
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
attack_verb = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut")
|
||||
@@ -524,6 +523,7 @@
|
||||
|
||||
/obj/item/cursed_katana/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.5, _parryable_attack_types = NON_PROJECTILE_ATTACKS)
|
||||
for(var/combo in combo_list)
|
||||
var/list/combo_specifics = combo_list[combo]
|
||||
var/step_string = english_list(combo_specifics[COMBO_STEPS])
|
||||
|
||||
@@ -215,21 +215,11 @@ emp_act
|
||||
|
||||
//End Here
|
||||
|
||||
#define BLOCK_CHANCE_CALCULATION(hand_block_chance, armour_penetration_flat, armour_penetration_percentage, block_chance_modifier) clamp((hand_block_chance * ((100-armour_penetration_percentage) / 100)) - max(armour_penetration_flat, 0) + block_chance_modifier, 0, 100)
|
||||
|
||||
/mob/living/carbon/human/proc/check_shields(atom/AM, damage, attack_text = "the attack", attack_type = MELEE_ATTACK, armour_penetration_flat = 0, armour_penetration_percentage = 0)
|
||||
var/block_chance_modifier = round(damage / -3)
|
||||
var/l_block_chance = 0
|
||||
var/r_block_chance = 0
|
||||
var/obj/item/shield = get_best_shield()
|
||||
|
||||
if(l_hand)
|
||||
l_block_chance = BLOCK_CHANCE_CALCULATION(l_hand.block_chance, armour_penetration_flat, armour_penetration_percentage, block_chance_modifier)
|
||||
if(r_hand)
|
||||
r_block_chance = BLOCK_CHANCE_CALCULATION(r_hand.block_chance, armour_penetration_flat, armour_penetration_percentage, block_chance_modifier)
|
||||
|
||||
if(l_block_chance > r_block_chance && l_hand.hit_reaction(src, AM, attack_text, l_block_chance, damage, attack_type))
|
||||
return TRUE
|
||||
else if(r_block_chance > 0 && r_hand.hit_reaction(src, AM, attack_text, r_block_chance, damage, attack_type))
|
||||
if(shield?.hit_reaction(src, AM, attack_text, 0, damage, attack_type))
|
||||
return TRUE
|
||||
|
||||
if(wear_suit && wear_suit.hit_reaction(src, AM, attack_text, 0, damage, attack_type))
|
||||
@@ -243,7 +233,18 @@ emp_act
|
||||
|
||||
return FALSE
|
||||
|
||||
#undef BLOCK_CHANCE_CALCULATION
|
||||
/mob/living/carbon/human/proc/get_best_shield()
|
||||
var/datum/component/parry/left_hand_parry = l_hand?.GetComponent(/datum/component/parry)
|
||||
var/datum/component/parry/right_hand_parry = r_hand?.GetComponent(/datum/component/parry)
|
||||
if(!right_hand_parry && !left_hand_parry)
|
||||
return null // no parry component
|
||||
|
||||
if(right_hand_parry && left_hand_parry)
|
||||
if(right_hand_parry.stamina_coefficient > left_hand_parry.stamina_coefficient) // try and parry with your best item
|
||||
return left_hand_parry.parent
|
||||
else
|
||||
return right_hand_parry.parent
|
||||
return right_hand_parry?.parent || left_hand_parry?.parent // parry with whichever hand has an item that can parry
|
||||
|
||||
/mob/living/carbon/human/proc/check_block()
|
||||
if(mind && mind.martial_art && prob(mind.martial_art.block_chance) && mind.martial_art.can_use(src) && in_throw_mode && !incapacitated(FALSE, TRUE))
|
||||
|
||||
@@ -148,9 +148,7 @@
|
||||
if(!(M.status_flags & CANPUSH))
|
||||
return TRUE
|
||||
//anti-riot equipment is also anti-push
|
||||
if(M.r_hand && (prob(M.r_hand.block_chance * 2)) && !isclothing(M.r_hand))
|
||||
return TRUE
|
||||
if(M.l_hand && (prob(M.l_hand.block_chance * 2)) && !isclothing(M.l_hand))
|
||||
if(M.r_hand?.GetComponent(/datum/component/parry) || M.l_hand?.GetComponent(/datum/component/parry))
|
||||
return TRUE
|
||||
|
||||
//Called when we bump into an obj
|
||||
|
||||
@@ -141,6 +141,7 @@
|
||||
name = "instagib laser"
|
||||
icon_state = "purple_laser"
|
||||
damage = 200
|
||||
armour_penetration_percentage = 100
|
||||
damage_type = BURN
|
||||
impact_effect_type = /obj/effect/temp_visual/impact_effect/purple_laser
|
||||
light_color = LIGHT_COLOR_PURPLE
|
||||
|
||||
@@ -360,6 +360,7 @@
|
||||
#include "code\datums\components\material_container.dm"
|
||||
#include "code\datums\components\orbiter.dm"
|
||||
#include "code\datums\components\paintable.dm"
|
||||
#include "code\datums\components\parry.dm"
|
||||
#include "code\datums\components\persistent_overlay.dm"
|
||||
#include "code\datums\components\proximity_monitor.dm"
|
||||
#include "code\datums\components\radioactive.dm"
|
||||
|
||||
Reference in New Issue
Block a user