mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-23 13:10:02 +01:00
[MIRROR] Limits the methods through which you can be stunned by a shove. Shoves disarm people who are knocked down. (#28667)
* Limits the methods through which you can be stunned by a shove. Shoves disarm people who are knocked down. (#84640) ## About The Pull Request For the sake of this PR's language, we'll be defining two different stuns; First: **wall stuns** are any stuns related to the shoving mechanic where you are pushing people into objects and other people to cause a knockdown. And, while they are in that specific knockdown, you shove them again to stun them. Second, a **shove stun** is any instance where you would be currently able to apply this stun from a shove even if the conditions above have not been met. This PR limits down the potential stuns from a shove to; **wall stuns**, and **shove stuns** following a telescoping baton knockdown or being touched by the Mansus Grasp. To know when you can stun someone with a shove, they will have this animated visual cue.  Successfully stunning, paralyzing or immobilizing the victim will remove the opportunity for a stun. You cannot apply another stun from a shove on someone for at least 3.5 seconds after the last stun was applied. The stun lasts for 3 seconds, so there is a 0.5 gap after the stun expires before another stun from a shove can be applied. This does not prevent further knockdowns or staggers. This part was added mostly to help clarify better when someone is or is not vulnerable, as well as cut down on chain stuns without some additional attacks. To make up for the loss of this advantage, shoving someone while they are in any kind of knockdown forces them to drop their held items. ## Why It's Good For The Game You may have remembered the removal of shove stuns testmerge a bit ago. [You can read a bit about it here, but I'll link specifically to my conclusions about that testmerge.](https://tgstation13.org/phpBB/viewtopic.php?p=726119#p726119) At the moment, shove stuns are very oppressive. Generally, it makes a few engagements against a variety of tools too dangerous to be worth attempting, and can often mean that a fight has already been won not from the intelligent employment of a tool, but the mere existence of one taking advantage of a very specific combination of actions. The most egregious part is that it enables an individual who knows the patterns to chain these stuns together to deny someone a chance at fighting back. Wall stunning, however, is a good equalizer that punishes people for not considering their environment, and rewards players who are. It allows the clever player to maneuver themselves just right to score a powerful reversal against even better equipped opponents, or a strong opener to allow them a chance at a successful attack. And it is a strong example of our environmental combat mechanics. Something that shove stuns in isolation is not necessarily (though it can be in some cases). Shove stuns are not exclusive to these scenarios, however. They exist as a ubiquitous means of turning any given knockdown effect into a chain of stun effects. Better equipped opponents, particularly ones with gear able to apply knockdowns, often find themselves able to readily match any opponent without having to worry about the aforementioned environmental aspect of shoving. It is all the advantages with none of the effort put in, and does play into any kind of struggle once the chain effects start to take place. We want to enable players to be able to have their big win moments against the odds. But we also don't want to be rewarding players for already being in an advantage position beyond what their gear affords them. Edit: With the new visual cue, I've allowed in a few shove stuns for equipment that somewhat needs it in order to function well. Heads of staff utilizing their telebatons are meant to be reasonably intimidating opponents, contractors absolutely need the advantage in order to successfully kidnap, and Heretics were one of the biggest sufferers during the testmerge and clearly also hinge quite a bit on the effect. ## Changelog 🆑 balance: You can only stun someone with a shove if they have been shoved into objects or people, or have been hit by telescopic batons, contractor batons or the Mansus Grasp. balance: If someone is knocked to the floor, however, you can still disarm them of any object with a shove. /🆑 --------- Co-authored-by: Mothblocks <35135081+Mothblocks@ users.noreply.github.com> * Limits the methods through which you can be stunned by a shove. Shoves disarm people who are knocked down. --------- Co-authored-by: necromanceranne <40847847+necromanceranne@users.noreply.github.com> Co-authored-by: Mothblocks <35135081+Mothblocks@ users.noreply.github.com>
This commit is contained in:
co-authored by
Mothblocks
necromanceranne
parent
41c8765ff7
commit
68fcd1842f
@@ -163,13 +163,13 @@ DEFINE_BITFIELD(status_flags, list(
|
||||
#define DEFAULT_MESSAGE_RANGE 7
|
||||
|
||||
//Shove knockdown lengths (deciseconds)
|
||||
#define SHOVE_KNOCKDOWN_SOLID 20
|
||||
#define SHOVE_KNOCKDOWN_HUMAN 20
|
||||
#define SHOVE_KNOCKDOWN_TABLE 20
|
||||
#define SHOVE_KNOCKDOWN_SOLID 2 SECONDS
|
||||
#define SHOVE_KNOCKDOWN_HUMAN 2 SECONDS
|
||||
#define SHOVE_KNOCKDOWN_TABLE 2 SECONDS
|
||||
#define SHOVE_KNOCKDOWN_COLLATERAL 1
|
||||
#define SHOVE_CHAIN_PARALYZE 30
|
||||
#define SHOVE_CHAIN_PARALYZE 3 SECONDS
|
||||
//Staggered slowdown, an effect caused by shoving and a few other features, such as tackling
|
||||
#define STAGGERED_SLOWDOWN_LENGTH 30
|
||||
#define STAGGERED_SLOWDOWN_LENGTH 3 SECONDS
|
||||
#define STAGGERED_SLOWDOWN_STRENGTH 0.85 //multiplier
|
||||
//Shove disarming item list
|
||||
GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
|
||||
|
||||
@@ -563,6 +563,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
|
||||
///Makes the player appear as their respective job in Binary Talk rather than being a 'Default Cyborg'.
|
||||
#define TRAIT_DISPLAY_JOB_IN_BINARY "display job in binary"
|
||||
|
||||
/// Trait that determines vulnerability to being stunned from a shove
|
||||
#define TRAIT_STUN_ON_NEXT_SHOVE "stun on next shove"
|
||||
|
||||
// METABOLISMS
|
||||
// Various jobs on the station have historically had better reactions
|
||||
// to various drinks and foodstuffs. Security liking donuts is a classic
|
||||
|
||||
@@ -470,6 +470,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
|
||||
"TRAIT_STRONG_STOMACH" = TRAIT_STRONG_STOMACH,
|
||||
"TRAIT_STUBBY_BODY" = TRAIT_STUBBY_BODY,
|
||||
"TRAIT_STUNIMMUNE" = TRAIT_STUNIMMUNE,
|
||||
"TRAIT_STUN_ON_NEXT_SHOVE" = TRAIT_STUN_ON_NEXT_SHOVE,
|
||||
"TRAIT_STURDY_FRAME" = TRAIT_STURDY_FRAME,
|
||||
"TRAIT_SUCCUMB_OVERRIDE" = TRAIT_SUCCUMB_OVERRIDE,
|
||||
"TRAIT_SUICIDED" = TRAIT_SUICIDED,
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/// Staggered, Next Shove Stuns, No Side Kick
|
||||
/// Status effects related to shoving effects and collisions due to shoving
|
||||
|
||||
/// Staggered can occur most often via shoving, but can also occur in other places too.
|
||||
/datum/status_effect/staggered
|
||||
id = "staggered"
|
||||
tick_interval = 0.5 SECONDS
|
||||
@@ -43,3 +47,88 @@
|
||||
/mob/living/proc/do_stagger_animation()
|
||||
animate(src, pixel_x = 4, time = 0.2 SECONDS, loop = 6, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL)
|
||||
animate(pixel_x = -4, time = 0.2 SECONDS, flags = ANIMATION_RELATIVE)
|
||||
|
||||
/// Status effect specifically for instances where someone is vulnerable to being stunned when shoved.
|
||||
/datum/status_effect/next_shove_stuns
|
||||
id = "next shove stuns"
|
||||
duration = 3 SECONDS
|
||||
status_type = STATUS_EFFECT_UNIQUE
|
||||
tick_interval = 0.5 SECONDS
|
||||
alert_type = null
|
||||
remove_on_fullheal = TRUE
|
||||
/// Our visual cue for the vulnerable state this status effect puts us in.
|
||||
var/mutable_appearance/vulnverability_overlay
|
||||
|
||||
/datum/status_effect/next_shove_stuns/on_apply()
|
||||
//Let's just clear this if they're dead or we can't stun them on a shove
|
||||
if(owner.stat == DEAD || HAS_TRAIT(owner, TRAIT_NO_SIDE_KICK) || HAS_TRAIT(owner, TRAIT_IMMOBILIZED))
|
||||
return FALSE
|
||||
RegisterSignal(owner, COMSIG_LIVING_DEATH, PROC_REF(clear_stun_vulnverability_on_death))
|
||||
RegisterSignals(owner, list(
|
||||
COMSIG_LIVING_STATUS_PARALYZE,
|
||||
COMSIG_LIVING_STATUS_STUN,
|
||||
COMSIG_LIVING_STATUS_IMMOBILIZE), PROC_REF(clear_stun_vulnverability)
|
||||
)
|
||||
ADD_TRAIT(owner, TRAIT_STUN_ON_NEXT_SHOVE, STATUS_EFFECT_TRAIT)
|
||||
vulnverability_overlay = mutable_appearance(icon = 'icons/effects/effects.dmi', icon_state = "dazed")
|
||||
owner.add_overlay(vulnverability_overlay)
|
||||
return TRUE
|
||||
|
||||
/datum/status_effect/next_shove_stuns/on_remove()
|
||||
UnregisterSignal(owner, list(
|
||||
COMSIG_LIVING_STATUS_PARALYZE,
|
||||
COMSIG_LIVING_STATUS_STUN,
|
||||
COMSIG_LIVING_STATUS_IMMOBILIZE,
|
||||
COMSIG_LIVING_DEATH,
|
||||
))
|
||||
REMOVE_TRAIT(owner, TRAIT_STUN_ON_NEXT_SHOVE, STATUS_EFFECT_TRAIT)
|
||||
if(vulnverability_overlay)
|
||||
clear_stun_vulnverability_overlay()
|
||||
|
||||
/// If our owner is either stunned, paralzyed or immobilized, we remove the status effect.
|
||||
/// This is both an anti-chainstun measure and a sanity check.
|
||||
/datum/status_effect/next_shove_stuns/proc/clear_stun_vulnverability(mob/living/source, amount = 0, ignore_canstun = FALSE)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(amount > 0)
|
||||
// Making absolutely sure we're removing this overlay
|
||||
clear_stun_vulnverability_overlay()
|
||||
qdel(src)
|
||||
|
||||
/datum/status_effect/next_shove_stuns/proc/clear_stun_vulnverability_on_death(mob/living/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
clear_stun_vulnverability_overlay()
|
||||
qdel(src)
|
||||
|
||||
/// Clears our overlay where needed.
|
||||
/datum/status_effect/next_shove_stuns/proc/clear_stun_vulnverability_overlay()
|
||||
owner.cut_overlay(vulnverability_overlay)
|
||||
vulnverability_overlay = null
|
||||
|
||||
/// Status effect to prevent stuns from a shove
|
||||
/// Only applied by shoving someone to paralyze them
|
||||
/datum/status_effect/no_side_kick
|
||||
id = "no side kick"
|
||||
duration = 3.5 SECONDS
|
||||
status_type = STATUS_EFFECT_UNIQUE
|
||||
tick_interval = 0.5 SECONDS
|
||||
alert_type = null
|
||||
remove_on_fullheal = TRUE
|
||||
|
||||
/datum/status_effect/no_side_kick/on_apply()
|
||||
// Once again, clear if dead
|
||||
if(owner.stat == DEAD)
|
||||
return FALSE
|
||||
RegisterSignal(owner, COMSIG_LIVING_DEATH, PROC_REF(clear_on_death))
|
||||
ADD_TRAIT(owner, TRAIT_NO_SIDE_KICK, STATUS_EFFECT_TRAIT)
|
||||
return TRUE
|
||||
|
||||
/datum/status_effect/no_side_kick/on_remove()
|
||||
UnregisterSignal(owner, list(COMSIG_LIVING_DEATH))
|
||||
REMOVE_TRAIT(owner, TRAIT_NO_SIDE_KICK, STATUS_EFFECT_TRAIT)
|
||||
|
||||
/datum/status_effect/no_side_kick/proc/clear_on_death(mob/living/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
qdel(src)
|
||||
|
||||
@@ -339,6 +339,9 @@
|
||||
)
|
||||
RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform))
|
||||
|
||||
/obj/item/melee/baton/telescopic/additional_effects_non_cyborg(mob/living/target, mob/living/user)
|
||||
target.apply_status_effect(/datum/status_effect/next_shove_stuns)
|
||||
|
||||
/obj/item/melee/baton/telescopic/suicide_act(mob/living/user)
|
||||
var/mob/living/carbon/human/human_user = user
|
||||
var/obj/item/organ/internal/brain/our_brain = human_user.get_organ_by_type(/obj/item/organ/internal/brain)
|
||||
@@ -401,6 +404,7 @@
|
||||
return span_danger("The baton is still charging!")
|
||||
|
||||
/obj/item/melee/baton/telescopic/contractor_baton/additional_effects_non_cyborg(mob/living/target, mob/living/user)
|
||||
. = ..()
|
||||
target.set_jitter_if_lower(40 SECONDS)
|
||||
target.set_stutter_if_lower(40 SECONDS)
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@
|
||||
carbon_hit.adjust_timed_status_effect(4 SECONDS, /datum/status_effect/speech/slurring/heretic)
|
||||
carbon_hit.AdjustKnockdown(5 SECONDS)
|
||||
carbon_hit.adjustStaminaLoss(80)
|
||||
carbon_hit.apply_status_effect(/datum/status_effect/next_shove_stuns)
|
||||
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -742,7 +742,7 @@
|
||||
/mob/living/carbon/get_shove_flags(mob/living/shover, obj/item/weapon)
|
||||
. = ..()
|
||||
. |= SHOVE_CAN_STAGGER
|
||||
if(IsKnockdown() && !IsParalyzed())
|
||||
if(IsKnockdown() && !IsParalyzed() && HAS_TRAIT(src, TRAIT_STUN_ON_NEXT_SHOVE))
|
||||
. |= SHOVE_CAN_KICK_SIDE
|
||||
if(HAS_TRAIT(src, TRAIT_NO_SIDE_KICK)) // added as an extra check, just in case
|
||||
. &= ~SHOVE_CAN_KICK_SIDE
|
||||
|
||||
@@ -146,8 +146,10 @@
|
||||
return
|
||||
if(!(shove_flags & SHOVE_KNOCKDOWN_BLOCKED))
|
||||
target.Knockdown(SHOVE_KNOCKDOWN_HUMAN)
|
||||
target.apply_status_effect(/datum/status_effect/next_shove_stuns)
|
||||
if(!HAS_TRAIT(src, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED))
|
||||
Knockdown(SHOVE_KNOCKDOWN_COLLATERAL)
|
||||
apply_status_effect(/datum/status_effect/next_shove_stuns)
|
||||
target.visible_message(span_danger("[shover] shoves [target.name] into [name]!"),
|
||||
span_userdanger("You're shoved into [name] by [shover]!"), span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, src)
|
||||
to_chat(src, span_danger("You shove [target.name] into [name]!"))
|
||||
|
||||
@@ -712,6 +712,7 @@
|
||||
return
|
||||
if((shove_flags & SHOVE_BLOCKED) && !(shove_flags & (SHOVE_KNOCKDOWN_BLOCKED|SHOVE_CAN_KICK_SIDE)))
|
||||
target.Knockdown(SHOVE_KNOCKDOWN_SOLID)
|
||||
target.apply_status_effect(/datum/status_effect/next_shove_stuns)
|
||||
target.visible_message(span_danger("[name] shoves [target.name], knocking [target.p_them()] down!"),
|
||||
span_userdanger("You're knocked down from a shove by [name]!"), span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, src)
|
||||
to_chat(src, span_danger("You shove [target.name], knocking [target.p_them()] down!"))
|
||||
@@ -720,6 +721,7 @@
|
||||
|
||||
if(shove_flags & SHOVE_CAN_KICK_SIDE) //KICK HIM IN THE NUTS
|
||||
target.Paralyze(SHOVE_CHAIN_PARALYZE)
|
||||
target.apply_status_effect(/datum/status_effect/no_side_kick)
|
||||
target.visible_message(span_danger("[name] kicks [target.name] onto [target.p_their()] side!"),
|
||||
span_userdanger("You're kicked onto your side by [name]!"), span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, src)
|
||||
to_chat(src, span_danger("You kick [target.name] onto [target.p_their()] side!"))
|
||||
@@ -732,10 +734,8 @@
|
||||
//Take their lunch money
|
||||
var/target_held_item = target.get_active_held_item()
|
||||
var/append_message = weapon ? " with [weapon]" : ""
|
||||
if(!is_type_in_typecache(target_held_item, GLOB.shove_disarming_types)) //It's too expensive we'll get caught
|
||||
target_held_item = null
|
||||
|
||||
if(target_held_item && target.get_timed_status_effect_duration(/datum/status_effect/staggered))
|
||||
// If it's in our typecache, they're staggered and it exists, disarm. If they're knocked down, disarm too.
|
||||
if(target_held_item && target.get_timed_status_effect_duration(/datum/status_effect/staggered) && is_type_in_typecache(target_held_item, GLOB.shove_disarming_types) || target_held_item && target.body_position == LYING_DOWN)
|
||||
target.dropItemToGround(target_held_item)
|
||||
append_message = "causing [target.p_them()] to drop [target_held_item]"
|
||||
target.visible_message(span_danger("[target.name] drops \the [target_held_item]!"),
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 905 KiB After Width: | Height: | Size: 905 KiB |
Reference in New Issue
Block a user