Makes the mech clamp attack do only brute damage, checks for block and armor, and gives it an attack animation and sound. (#91563)

## About The Pull Request

If you use the mech clamp offensively, it actually performs an attack
animation and sound, and properly checks armor and block. It only deals
brute damage.

As a consequence of these changes, it actually logs attacks made against
mobs that die when gibbed.

Also, xenos take x3 damage from the clamp.

## Why It's Good For The Game

This is a pretty sinister kind of attack, as it is completely silent
except for throwing a warning into chat, and can be done even in a large
crowd of people. Someone who isn't aware that the clamp can be used this
way may not even understand what is happening before it is too late.

> block check

While mech melee doesn't normally check block, this is an improvised
attack on a non-combat mech. I think it should stay a bit weak compared
to a proper mech melee in most ways and have some additional
limitations.

> Xenos

I thought this was already a thing. It's thematically on point, no?

## Changelog
🆑
balance: Mech hydraulic clamps perform an attack animation and sound
when attacking mobs.
balance: Mech hydraulic clamps can be blocked and respect armor.
balance: Mech hydraulic clamps do triple damage to xenomorphs.
/🆑

(cherry picked from commit fb9824a401)
This commit is contained in:
necromanceranne
2025-06-28 20:38:35 -04:00
committed by Roxy
parent e04863ad39
commit a8fe50f4f4
10 changed files with 52 additions and 29 deletions
+2
View File
@@ -139,6 +139,8 @@ DEFINE_BITFIELD(status_flags, list(
#define THROWN_PROJECTILE_ATTACK 4
/// We're being tackled or leaped at.
#define LEAP_ATTACK 5
/// We're being attacked with an oversized object, perhaps a road roller. Not that anyone use such a thing as a waepon. So only relevant for certain mech based attacks.
#define OVERWHELMING_ATTACK 6
/// Used in check block to get what mob is attacking the blocker.
#define GET_ASSAILANT(weapon) (get(weapon, /mob/living))
+3
View File
@@ -170,6 +170,9 @@
if(attack_type == LEAP_ATTACK)
final_block_chance -= 50 //We are particularly bad at blocking someone JUMPING at us..
if(attack_type == OVERWHELMING_ATTACK)
final_block_chance = 0 //Far too small to block these kinds of attacks.
return ..()
/obj/item/dualsaber/process()
+8 -8
View File
@@ -119,8 +119,8 @@
INVOKE_ASYNC(baned_target, TYPE_PROC_REF(/mob/living/carbon/human, emote), "scream")
/obj/item/melee/sabre/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE)
if(attack_type == PROJECTILE_ATTACK || attack_type == LEAP_ATTACK)
final_block_chance = 0 //Don't bring a sword to a gunfight, and also you aren't going to really block someone full body tackling you with a sword
if(attack_type == (PROJECTILE_ATTACK || LEAP_ATTACK || OVERWHELMING_ATTACK))
final_block_chance = 0 //Don't bring a sword to a gunfight, and also you aren't going to really block someone full body tackling you with a sword. Or a road roller, if one happened to hit you.
return ..()
/obj/item/melee/sabre/on_exit_storage(datum/storage/container)
@@ -201,8 +201,8 @@
AddComponent(/datum/component/jousting)
/obj/item/melee/parsnip_sabre/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE)
if(attack_type == PROJECTILE_ATTACK || attack_type == LEAP_ATTACK)
final_block_chance = 0 //Don't bring a sword to a gunfight, and also you aren't going to really block someone full body tackling you with a sword
if(attack_type == (PROJECTILE_ATTACK || LEAP_ATTACK || OVERWHELMING_ATTACK))
final_block_chance = 0 //Don't bring a sword to a gunfight, and also you aren't going to really block someone full body tackling you with a sword. Or a road roller, if one happened to hit you.
return ..()
/obj/item/melee/parsnip_sabre/on_exit_storage(datum/storage/container)
@@ -237,8 +237,8 @@
block_sound = 'sound/items/weapons/parry.ogg'
/obj/item/melee/beesword/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE)
if(attack_type == PROJECTILE_ATTACK || attack_type == LEAP_ATTACK)
final_block_chance = 0 //Don't bring a sword to a gunfight, and also you aren't going to really block someone full body tackling you with a sword
if(attack_type == (PROJECTILE_ATTACK || LEAP_ATTACK || OVERWHELMING_ATTACK))
final_block_chance = 0 //Don't bring a sword to a gunfight, and also you aren't going to really block someone full body tackling you with a sword. Or a road roller, if one happened to hit you.
return ..()
/obj/item/melee/beesword/afterattack(atom/target, mob/user, list/modifiers, list/attack_modifiers)
@@ -566,6 +566,6 @@
desc = "[initial(desc)] Its handle is made of [material.name]."
/obj/item/melee/cleric_mace/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE)
if(attack_type == PROJECTILE_ATTACK || attack_type == LEAP_ATTACK)
final_block_chance = 0 //Don't bring a...mace to a gunfight, and also you aren't going to really block someone full body tackling you with a mace
if(attack_type == (PROJECTILE_ATTACK || LEAP_ATTACK || OVERWHELMING_ATTACK))
final_block_chance = 0 //Don't bring a...mace to a gunfight, and also you aren't going to really block someone full body tackling you with a mace. Or a road roller, if one happened to hit you.
return ..()
+12 -4
View File
@@ -44,12 +44,16 @@
AddElement(/datum/element/disarm_attack)
/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, damage_type = BRUTE)
var/effective_block_chance = final_block_chance
if(transparent && (hitby.pass_flags & PASSGLASS))
return FALSE
if(attack_type == THROWN_PROJECTILE_ATTACK)
final_block_chance += 30
effective_block_chance += 30
if(attack_type == LEAP_ATTACK)
final_block_chance = 100
effective_block_chance = 100
if(attack_type == OVERWHELMING_ATTACK)
effective_block_chance -= 25
final_block_chance = clamp(effective_block_chance, 0, 100)
. = ..()
if(.)
on_shield_block(owner, hitby, attack_text, damage, attack_type, damage_type)
@@ -336,12 +340,16 @@
if(!HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE))
return FALSE
var/effective_block_chance = final_block_chance
if(attack_type == OVERWHELMING_ATTACK)
effective_block_chance -= 25
if(attack_type == PROJECTILE_ATTACK)
var/obj/projectile/our_projectile = hitby
if(our_projectile.reflectable) //We handle this via IsReflect() instead.
final_block_chance = 0
effective_block_chance = 0
final_block_chance = clamp(effective_block_chance, 0, 100)
return ..()
/obj/item/shield/energy/IsReflect()
+2 -2
View File
@@ -155,8 +155,8 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
return BRUTELOSS
/obj/item/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, damage_type = BRUTE)
if(attack_type == PROJECTILE_ATTACK || attack_type == LEAP_ATTACK)
final_block_chance = 0 //Don't bring a sword to a gunfight, and also you aren't going to really block someone full body tackling you with a sword
if(attack_type == (PROJECTILE_ATTACK || LEAP_ATTACK || OVERWHELMING_ATTACK))
final_block_chance = 0 //Don't bring a sword to a gunfight, and also you aren't going to really block someone full body tackling you with a sword. Or a road roller, if one happened to hit you.
return ..()
//statistically similar to e-cutlasses
+6 -1
View File
@@ -55,7 +55,7 @@ Striking a noncultist, however, will tear their flesh."}
if(owner.get_active_held_item() != src)
block_message = "[owner] parries [attack_text] with [src] in their offhand"
if(IS_CULTIST(owner) && prob(final_block_chance) && attack_type != PROJECTILE_ATTACK)
if(IS_CULTIST(owner) && prob(final_block_chance) && attack_type != (PROJECTILE_ATTACK || OVERWHELMING_ATTACK))
new /obj/effect/temp_visual/cult/sparks(get_turf(owner))
owner.visible_message(span_danger("[block_message]"))
return TRUE
@@ -123,6 +123,9 @@ Striking a noncultist, however, will tear their flesh."}
ADD_TRAIT(src, TRAIT_CONTRABAND, INNATE_TRAIT)
/obj/item/melee/cultblade/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE)
if(attack_type == OVERWHELMING_ATTACK)
return FALSE
if(IS_CULTIST(owner) && prob(final_block_chance))
new /obj/effect/temp_visual/cult/sparks(get_turf(owner))
owner.visible_message(span_danger("[owner] parries [attack_text] with [src]!"))
@@ -940,6 +943,8 @@ Striking a noncultist, however, will tear their flesh."}
qdel(src)
/obj/item/melee/cultblade/halberd/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE)
if(attack_type == OVERWHELMING_ATTACK)
return FALSE
if(HAS_TRAIT(src, TRAIT_WIELDED))
final_block_chance *= 2
if(IS_CULTIST(owner) && prob(final_block_chance))
@@ -142,8 +142,8 @@ means that you'll be forced to move carefully while it's on. Fits in pockets, an
AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple, -3)
/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, damage_type = BRUTE)
if(attack_type == PROJECTILE_ATTACK || attack_type == LEAP_ATTACK)
final_block_chance = 0 //Don't bring a sword to a gunfight, and also you aren't going to really block someone full body tackling you with a sword
if(attack_type == (PROJECTILE_ATTACK || LEAP_ATTACK || OVERWHELMING_ATTACK))
final_block_chance = 0 //Don't bring a sword to a gunfight, and also you aren't going to really block someone full body tackling you with a sword. Or a road roller, if one happened to hit you.
return ..()
/obj/item/nullrod/claymore/darkblade
@@ -661,8 +661,8 @@ means that you'll be forced to move carefully while it's on. Fits in pockets, an
return ..()
/obj/item/nullrod/bostaff/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE)
if(attack_type == PROJECTILE_ATTACK)
final_block_chance = 0 //Don't bring a sword to a gunfight
if(attack_type == (PROJECTILE_ATTACK || LEAP_ATTACK || OVERWHELMING_ATTACK))
final_block_chance = 0 //Don't bring a stick to a gunfight, and also you aren't going to really block someone full body tackling you with a stick. Or a road roller, if one happened to hit you.
return ..()
// Arrhythmic Knife - Lets your walk without rhythm by varying your walk speed. Can't be put away.
@@ -107,8 +107,8 @@
return ..()
/obj/item/cursed_katana/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE)
if(attack_type == PROJECTILE_ATTACK || attack_type == LEAP_ATTACK)
final_block_chance = 0 //Don't bring a sword to a gunfight, and also you aren't going to really block someone full body tackling you with a sword
if(attack_type == (PROJECTILE_ATTACK || LEAP_ATTACK || OVERWHELMING_ATTACK))
final_block_chance = 0 //Don't bring a sword to a gunfight, and also you aren't going to really block someone full body tackling you with a sword. Or a road roller, if one happened to hit you.
return ..()
/obj/item/cursed_katana/proc/can_combo_attack(mob/user, mob/living/target)
+2 -2
View File
@@ -264,8 +264,8 @@
)
/obj/item/gun/magic/staff/spellblade/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE)
if(attack_type == PROJECTILE_ATTACK || attack_type == LEAP_ATTACK)
final_block_chance = 0 //Don't bring a sword to a gunfight, and also you aren't going to really block someone full body tackling you with a sword
if(attack_type == (PROJECTILE_ATTACK || LEAP_ATTACK || OVERWHELMING_ATTACK))
final_block_chance = 0 //Don't bring a sword to a gunfight, and also you aren't going to really block someone full body tackling you with a sword. Or a road roller, if one happened to hit you.
return ..()
/obj/item/gun/magic/staff/locker
@@ -94,7 +94,7 @@
var/mob/living/victim = target
if(victim.stat == DEAD)
return
return ..()
if(!source.combat_mode)
step_away(victim, chassis)
@@ -107,6 +107,11 @@
span_notice("[chassis] pushes you aside."))
return ..()
if(victim.check_block(chassis, clamp_damage, name, attack_type = OVERWHELMING_ATTACK))
source.visible_message(span_danger("[chassis] attempts to squeeze [victim] with [src], but the [name] is blocked!"), span_userdanger("You attempt to squeeze [victim] with [src], but [victim.p_They()] managed to block the attempt!"), ignored_mobs = victim)
to_chat(victim, span_userdanger("You block [chassis]'s attempt to squeeze you with [src]!"))
return ..()
if(iscarbon(victim) && killer_clamp)//meme clamp here
var/mob/living/carbon/carbon_victim = target
var/torn_off = FALSE
@@ -124,15 +129,15 @@
span_userdanger("[chassis] rips your arms off!"))
log_combat(source, carbon_victim, "removed both arms with a real clamp,", "[name]", "(COMBAT MODE: [uppertext(source.combat_mode)] (DAMTYPE: [uppertext(damtype)])")
return ..()
victim.take_overall_damage(clamp_damage)
if(isnull(victim)) //get gibbed stoopid
return ..()
victim.adjustOxyLoss(round(clamp_damage/2))
var/armor_check = clamp(victim.run_armor_check(null, MELEE) / 3, 0, 100) //our target only benefits from a third of their armor. Because it's a huge ass clamp
victim.visible_message(span_danger("[chassis] squeezes [victim]!"), \
span_userdanger("[chassis] squeezes you!"),\
span_hear("You hear something crack."))
log_combat(source, victim, "attacked", "[name]", "(Combat mode: [source.combat_mode ? "On" : "Off"]) (DAMTYPE: [uppertext(damtype)])")
var/final_damage = isalien(victim) ? clamp_damage * 3 : clamp_damage
chassis.do_attack_animation(victim)
playsound(chassis, clampsound, 30, FALSE, -6)
victim.apply_damage(final_damage, BRUTE, blocked = armor_check, spread_damage = TRUE)
return ..()
//This is pretty much just for the death-ripley