Fixes tackles rarely applying permanent slowdowns, improves min_distance tackle targeting (#73550)

## About The Pull Request

Fixes: #61449
Monster tackles (the top tackle result that automatically applies an
aggro-grab) now checks if the user is getting stamcrit from the stamina
damage that comes from launching the tackle. If not, it proceeds as
normal and applies the aggro-grab, but if it does stamcrit, the tackler
instead extra stamina damage/paralyze/knockdown in lieu of the autograb.
This resolves the issue with the aggro-grab slowdown applying
permanently, since that grab shouldn't have been possible to land in the
first place.

Fixes: #50888
I was lazy when I first implemented tackles, so if you tackled a target
with a range less than the gloves' min_distance (dolphin and rocket
gloves), it would simply launch you the min_distance range in the
nearest cardinal/diagonal direction. It now uses the angle you're
launching towards, which means you'll leap closer to where you actually
clicked on, and hopefully make rocket gloves slightly less suicidal.

Also I raised the amount of objects you can knock off a table with a
tackle from 12 to 18 because it's funny.
## Why It's Good For The Game
Tackles are more consistent and less buggy. Also you can shotgun more
shards of glass stacked on a table at people at once with rocket gloves.
## Changelog
🆑 Ryll/Shaps
fix: Landing a monster tackle that applies an auto aggro-grab while
stamcrit will no longer try applying an aggro-grab that leads to a
permanent slowdown to the user, and will instead just knock the target
down a bit harder.
fix: Launching dolphin and rocket glove tackles on targets at ranges
shorter than their minimum distance will be more accurate at targeting
where you clicked at, rather than locking you into the nearest
cardinal/diagonal direction.
balance: You can now knock more things off a table full of stuff by
tackling it than you could before.
/🆑
This commit is contained in:
Ryll Ryll
2023-02-21 16:43:03 +13:00
committed by GitHub
parent 1570d9694d
commit 40fa6e43a0
+54 -43
View File
@@ -1,5 +1,5 @@
/// how many things can we knock off a table at once by diving into it?
#define MAX_TABLE_MESSES 12
#define MAX_TABLE_MESSES 18
/**
* For when you want to throw a person at something and have fun stuff happen
@@ -68,7 +68,7 @@
tackle.thrower = user
///See if we can tackle or not. If we can, leap!
/datum/component/tackler/proc/checkTackle(mob/living/carbon/user, atom/A, list/modifiers)
/datum/component/tackler/proc/checkTackle(mob/living/carbon/user, atom/clicked_atom, list/modifiers)
SIGNAL_HANDLER
if(modifiers[ALT_CLICK] || modifiers[SHIFT_CLICK] || modifiers[CTRL_CLICK] || modifiers[MIDDLE_CLICK])
@@ -77,7 +77,7 @@
if(!user.throw_mode || user.get_active_held_item() || user.pulling || user.buckled || user.incapacitated())
return
if(!A || !(isturf(A) || isturf(A.loc)))
if(!clicked_atom || !(isturf(clicked_atom) || isturf(clicked_atom.loc)))
return
if(HAS_TRAIT(user, TRAIT_HULK))
@@ -100,25 +100,25 @@
to_chat(user, span_warning("You're too off balance to tackle!"))
return
user.face_atom(A)
user.face_atom(clicked_atom)
tackling = TRUE
RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(checkObstacle))
playsound(user, 'sound/weapons/thudswoosh.ogg', 40, TRUE, -1)
var/leap_word = isfelinid(user) ? "pounce" : "leap" //If cat, "pounce" instead of "leap".
if(can_see(user, A, 7))
user.visible_message(span_warning("[user] [leap_word]s at [A]!"), span_danger("You [leap_word] at [A]!"))
if(can_see(user, clicked_atom, 7))
user.visible_message(span_warning("[user] [leap_word]s at [clicked_atom]!"), span_danger("You [leap_word] at [clicked_atom]!"))
else
user.visible_message(span_warning("[user] [leap_word]s!"), span_danger("You [leap_word]!"))
if(get_dist(user, A) < min_distance)
A = get_ranged_target_turf(user, get_dir(user, A), min_distance) //TODO: this only works in cardinals/diagonals, make it work with in-betweens too!
if(get_dist(user, clicked_atom) < min_distance)
var/tackle_angle = get_angle(user, clicked_atom)
clicked_atom = get_turf_in_angle(tackle_angle, get_turf(user), min_distance)
user.Knockdown(base_knockdown, ignore_canstun = TRUE)
user.adjustStaminaLoss(stamina_cost)
user.throw_at(A, range, speed, user, FALSE)
user.throw_at(clicked_atom, range, speed, user, FALSE)
addtimer(CALLBACK(src, PROC_REF(resetTackle)), base_knockdown, TIMER_STOPPABLE)
return(COMSIG_MOB_CANCEL_CLICKON)
@@ -168,10 +168,10 @@
user.visible_message(span_danger("[user] botches [user.p_their()] [tackle_word] and slams [user.p_their()] head into [target], knocking [user.p_them()]self silly!"), span_userdanger("You botch your [tackle_word] and slam your head into [target], knocking yourself silly!"), ignored_mobs = target)
to_chat(target, span_userdanger("[user] botches [user.p_their()] [tackle_word] and slams [user.p_their()] head into you, knocking [user.p_them()]self silly!"))
user.Paralyze(30)
user.Paralyze(3 SECONDS)
var/obj/item/bodypart/head/hed = user.get_bodypart(BODY_ZONE_HEAD)
if(hed)
hed.receive_damage(brute=15, updating_health=TRUE, wound_bonus = CANT_WOUND)
hed.receive_damage(brute = 15, updating_health = TRUE, wound_bonus = CANT_WOUND)
user.gain_trauma(/datum/brain_trauma/mild/concussion)
if(-4 to -2) // glancing blow at best
@@ -188,18 +188,18 @@
to_chat(target, span_userdanger("[user] lands a passable [tackle_word] on you, sending you both tumbling!"))
target.adjustStaminaLoss(stamina_cost)
target.Paralyze(5)
user.Knockdown(20)
target.Knockdown(25)
target.Paralyze(0.5 SECONDS)
user.Knockdown(2 SECONDS)
target.Knockdown(2.5 SECONDS)
if(1 to 2) // solid hit, tackler has a slight advantage
user.visible_message(span_warning("[user] lands a solid [tackle_word] on [target], knocking them both down hard!"), span_userdanger("You land a solid [tackle_word] on [target], knocking you both down hard!"), ignored_mobs = target)
to_chat(target, span_userdanger("[user] lands a solid [tackle_word] on you, knocking you both down hard!"))
target.adjustStaminaLoss(30)
target.Paralyze(5)
user.Knockdown(10)
target.Knockdown(20)
target.Paralyze(0.5 SECONDS)
user.Knockdown(1 SECONDS)
target.Knockdown(2 SECONDS)
if(3 to 4) // really good hit, the target is definitely worse off here. Without positive modifiers, this is as good a tackle as you can land
user.visible_message(span_warning("[user] lands an expert [tackle_word] on [target], knocking [target.p_them()] down hard while landing on [user.p_their()] feet with a passive grip!"), span_userdanger("You land an expert [tackle_word] on [target], knocking [target.p_them()] down hard while landing on your feet with a passive grip!"), ignored_mobs = target)
@@ -209,25 +209,34 @@
user.get_up(TRUE)
user.forceMove(get_turf(target))
target.adjustStaminaLoss(40)
target.Paralyze(5)
target.Knockdown(30)
target.Paralyze(0.5 SECONDS)
target.Knockdown(3 SECONDS)
if(ishuman(target) && ishuman(user))
INVOKE_ASYNC(S.dna.species, TYPE_PROC_REF(/datum/species, grab), S, T)
S.setGrabState(GRAB_PASSIVE)
if(5 to INFINITY) // absolutely BODIED
user.visible_message(span_warning("[user] lands a monster [tackle_word] on [target], knocking [target.p_them()] senseless and applying an aggressive pin!"), span_userdanger("You land a monster [tackle_word] on [target], knocking [target.p_them()] senseless and applying an aggressive pin!"), ignored_mobs = target)
to_chat(target, span_userdanger("[user] lands a monster [tackle_word] on you, knocking you senseless and aggressively pinning you!"))
var/stamcritted_user = HAS_TRAIT_FROM(user, TRAIT_INCAPACITATED, STAMINA)
if(stamcritted_user) // in case the user went into stamcrit from the tackle itself and cannot actually aggro grab (since they will be crit) we make the tackle a bit more effective on the target
user.visible_message(span_warning("[user] lands a monsterly reckless [tackle_word] on [target], knocking both of them senseless!"), span_userdanger("You land a monsterly reckless [tackle_word] on [target], knocking both of you senseless!"), ignored_mobs = target)
to_chat(target, span_userdanger("[user] lands a monsterly reckless [tackle_word] on you, knocking the both of you senseless!"))
user.forceMove(get_turf(target))
target.adjustStaminaLoss(60)
target.Paralyze(1 SECONDS)
target.Knockdown(5 SECONDS)
else
user.visible_message(span_warning("[user] lands a monster [tackle_word] on [target], knocking [target.p_them()] senseless and applying an aggressive pin!"), span_userdanger("You land a monster [tackle_word] on [target], knocking [target.p_them()] senseless and applying an aggressive pin!"), ignored_mobs = target)
to_chat(target, span_userdanger("[user] lands a monster [tackle_word] on you, knocking you senseless and aggressively pinning you!"))
user.SetKnockdown(0)
user.get_up(TRUE)
user.forceMove(get_turf(target))
target.adjustStaminaLoss(40)
target.Paralyze(5)
target.Knockdown(30)
if(ishuman(target) && ishuman(user))
INVOKE_ASYNC(S.dna.species, TYPE_PROC_REF(/datum/species, grab), S, T)
S.setGrabState(GRAB_AGGRESSIVE)
user.SetKnockdown(0)
user.get_up(TRUE)
user.forceMove(get_turf(target))
target.adjustStaminaLoss(40)
target.Paralyze(0.5 SECONDS)
target.Knockdown(3 SECONDS)
if(ishuman(target) && ishuman(user))
INVOKE_ASYNC(S.dna.species, TYPE_PROC_REF(/datum/species, grab), S, T)
S.setGrabState(GRAB_AGGRESSIVE)
return COMPONENT_MOVABLE_IMPACT_FLIP_HITPUSH
@@ -411,9 +420,9 @@
user.visible_message(span_danger("[user] slams skull-first into [hit] with a sound like crumpled paper, revealing a horrifying breakage in [user.p_their()] cranium! Holy shit!"), span_userdanger("You slam skull-first into [hit] and your senses are filled with warm goo flooding across your face! Your skull is open!"))
var/obj/item/bodypart/head/hed = user.get_bodypart(BODY_ZONE_HEAD)
if(hed)
hed.receive_damage(brute=30, updating_health=FALSE, wound_bonus = 25)
hed.receive_damage(brute = 30, updating_health = FALSE, wound_bonus = 25)
else
user.adjustBruteLoss(40, updating_health=FALSE)
user.adjustBruteLoss(40, updating_health = FALSE)
user.adjustStaminaLoss(30)
user.gain_trauma_type(BRAIN_TRAUMA_MILD)
playsound(user, 'sound/effects/blobattack.ogg', 60, TRUE)
@@ -426,7 +435,7 @@
user.visible_message(span_danger("[user] slams face-first into [hit] with a concerning squish, immediately going limp!"), span_userdanger("You slam face-first into [hit], and immediately lose consciousness!"))
user.adjustStaminaLoss(30)
user.adjustBruteLoss(30)
user.Unconscious(100)
user.Unconscious(10 SECONDS)
user.gain_trauma_type(BRAIN_TRAUMA_MILD)
user.playsound_local(get_turf(user), 'sound/weapons/flashbang.ogg', 100, TRUE, 8)
shake_camera(user, 6, 6)
@@ -440,7 +449,7 @@
if(prob(80))
user.gain_trauma(/datum/brain_trauma/mild/concussion)
user.playsound_local(get_turf(user), 'sound/weapons/flashbang.ogg', 100, TRUE, 8)
user.Knockdown(40)
user.Knockdown(4 SECONDS)
shake_camera(user, 5, 5)
user.flash_act(1, TRUE, TRUE, length = 2.5)
@@ -449,14 +458,14 @@
user.adjustStaminaLoss(30, updating_stamina=FALSE)
user.adjustBruteLoss(10)
user.adjust_confusion(10 SECONDS)
user.Knockdown(30)
user.Knockdown(3 SECONDS)
shake_camera(user, 3, 4)
if(1 to 67)
user.visible_message(span_danger("[user] slams into [hit]!"), span_userdanger("You slam into [hit]!"))
user.adjustStaminaLoss(20, updating_stamina=FALSE)
user.adjustBruteLoss(10)
user.Knockdown(20)
user.Knockdown(2 SECONDS)
shake_camera(user, 2, 2)
playsound(user, 'sound/weapons/smash.ogg', 70, TRUE)
@@ -481,13 +490,13 @@
shard.updateEmbedding()
W.atom_destruction()
user.adjustStaminaLoss(10 * speed)
user.Paralyze(30)
user.Paralyze(3 SECONDS)
user.visible_message(span_danger("[user] smacks into [W] and shatters it, shredding [user.p_them()]self with glass!"), span_userdanger("You smacks into [W] and shatter it, shredding yourself with glass!"))
else
user.visible_message(span_danger("[user] smacks into [W] like a bug!"), span_userdanger("You smacks into [W] like a bug!"))
user.Paralyze(10)
user.Knockdown(30)
user.Paralyze(1 SECONDS)
user.Knockdown(3 SECONDS)
W.take_damage(30 * speed)
user.adjustStaminaLoss(10 * speed, updating_stamina=FALSE)
user.adjustBruteLoss(5 * speed)
@@ -522,12 +531,14 @@
// for telling HOW big of a mess we just made
var/HOW_big_of_a_miss_did_we_just_make = ""
if(messes.len)
if(messes.len < MAX_TABLE_MESSES / 4)
if(messes.len < MAX_TABLE_MESSES * 0.125)
HOW_big_of_a_miss_did_we_just_make = ", making a mess"
else if(messes.len < MAX_TABLE_MESSES / 2)
else if(messes.len < MAX_TABLE_MESSES * 0.25)
HOW_big_of_a_miss_did_we_just_make = ", making a big mess"
else if(messes.len < MAX_TABLE_MESSES)
else if(messes.len < MAX_TABLE_MESSES * 0.5)
HOW_big_of_a_miss_did_we_just_make = ", making a giant mess"
else if(messes.len < MAX_TABLE_MESSES)
HOW_big_of_a_miss_did_we_just_make = ", making a gnarly mess"
else
HOW_big_of_a_miss_did_we_just_make = ", making a ginormous mess!" // an extra exclamation point!! for emphasis!!!