Cyberbrawlening 2: Electric Boogaloo: Strongarm implants now ACTUALLY improve arm strength (#93442)

## About The Pull Request

Strongarm implants now directly improve your arm's unarmed stats,
improving the upper damage (+2), accuracy (+10) and stamina damage
inflicted while a grabbed target fails to escape a grab (+10).

As a result, strongarm implants do not tack on an extra +5 to the damage
inflicted by its super slam attack. However, this attack now uses
similar math to your standard punches; improved by athletics and the
Strength mutation, [as explained in this
PR](https://github.com/tgstation/tgstation/pull/93125).

Strongarms do not get their damage bonus against Beast mob biotypes, but
retain Mining and Special biotype effectiveness.

Strongarms do not go on cooldown, nor consider the cooldown for the
super slam except when punching human targets. When not punching a human
target, strongarms will always use the super slam.

Adds support for limbs to alter grab states, grab escape chances and
grab punishment damage. This is only actually able to be used by arms as
of the moment. (Maybe one day we'll get tail constrictions if someone is
insane enough to add lamia-like creatures/limbs or something)

## Why It's Good For The Game

The strongarms worked like a pseudo-punch and this often threw players
for a loop as to what they actually do. Many people assumed they
improved the actual power of the arm itself, rather than just being a
vehicle for a special attack.

This basically affirms player assumptions about the implant. Yes, it
does improve the arm strength. Yes, most of the generic improvements to
unarmed attacks improve this one's special attack. They're now closer in
functionality.

This is also my less than thrilling workaround for enabling the borg
punching that [lucy has been
craving](https://github.com/Monkestation/Monkestation2.0/pull/6748) :U

## Changelog
🆑
balance: The strongarm implants now directly improves the unarmed power
of the arm it is implanted into.
balance: The strongarm implant's super slam now uses similar
calculations to normal unarmed attacks, including improvements from
mutations and athletics.
balance: The strongarm always uses the super slam against nonhuman
opponents. It will only go on cooldown, and care about that cooldown,
when used against humans.
/🆑
This commit is contained in:
necromanceranne
2025-10-21 12:25:53 +11:00
committed by GitHub
parent f13e1564b9
commit cbbcd71d78
3 changed files with 90 additions and 41 deletions
@@ -438,25 +438,31 @@
)
aug_overlay = "strongarm"
///The amount of damage the implant adds to our unarmed attacks.
var/punch_damage = 5
///Biotypes we apply an additional amount of damage too
var/biotype_bonus_targets = MOB_BEAST | MOB_SPECIAL | MOB_MINING
///Extra damage dealt to our targeted mobs
/// The amount of damage the implant adds to the lower punching force of our arm.
var/lower_punch_damage = 0
/// The amount of damage the implant adds to the upper punching force of our arm.
var/upper_punch_damage = 2
/// The amount of punch effectiveness (AKA accuracy and crit potential) the implant adds to our arm
var/punch_effectiveness_added = 10
/// How much extra damage does our implant allow the implanted while grabbing someone and they are unable to break the grapple?
var/bonus_grab_damage = 20
/// Biotypes we apply an additional amount of damage too
var/biotype_bonus_targets = MOB_SPECIAL | MOB_MINING
/// Extra damage dealt to our targeted mobs
var/biotype_bonus_damage = 20
///IF true, the throw attack will not smash people into walls
/// IF true, the throw attack will not smash people into walls
var/non_harmful_throw = TRUE
///How far away your attack will throw your oponent
/// How far away your attack will throw your oponent
var/attack_throw_range = 1
///Minimum throw power of the attack
/// Minimum throw power of the attack
var/throw_power_min = 1
///Maximum throw power of the attack
/// Maximum throw power of the attack
var/throw_power_max = 4
///How long will the implant malfunction if it is EMP'd
/// How long will the implant malfunction if it is EMP'd
var/emp_base_duration = 9 SECONDS
///How long before we get another slam punch; consider that these usually come in pairs of two
/// How long before we get another slam punch against a human; consider that these usually come in pairs
var/slam_cooldown_duration = 5 SECONDS
///Tracks how soon we can perform another slam attack
/// Tracks how soon we can perform another slam attack
COOLDOWN_DECLARE(slam_cooldown)
/obj/item/organ/cyberimp/arm/strongarm/Initialize(mapload)
@@ -472,6 +478,20 @@
. = ..()
UnregisterSignal(arm_owner, COMSIG_LIVING_EARLY_UNARMED_ATTACK)
/obj/item/organ/cyberimp/arm/strongarm/on_bodypart_insert(obj/item/bodypart/arm)
. = ..()
arm.unarmed_damage_low += lower_punch_damage
arm.unarmed_damage_high += upper_punch_damage
arm.unarmed_effectiveness += punch_effectiveness_added
arm.unarmed_grab_damage_bonus += bonus_grab_damage
/obj/item/organ/cyberimp/arm/strongarm/on_bodypart_remove(obj/item/bodypart/arm)
. = ..()
arm.unarmed_damage_low += lower_punch_damage
arm.unarmed_damage_high += upper_punch_damage
arm.unarmed_effectiveness += punch_effectiveness_added
arm.unarmed_grab_damage_bonus += bonus_grab_damage
/obj/item/organ/cyberimp/arm/strongarm/emp_act(severity)
. = ..()
if((organ_flags & ORGAN_FAILING) || . & EMP_PROTECT_SELF)
@@ -495,13 +515,12 @@
return NONE
if(HAS_TRAIT(source, TRAIT_HULK)) //NO HULK
return NONE
if(!COOLDOWN_FINISHED(src, slam_cooldown))
if(!COOLDOWN_FINISHED(src, slam_cooldown) && ishuman(target))
return NONE
if(!source.can_unarmed_attack())
return COMPONENT_SKIP_ATTACK
var/mob/living/living_target = target
source.changeNext_move(CLICK_CD_MELEE)
var/picked_hit_type = pick("punch", "smash", "pummel", "bash", "slam")
if(organ_flags & ORGAN_FAILING)
@@ -514,22 +533,28 @@
source.Paralyze(1 SECONDS)
return COMPONENT_CANCEL_ATTACK_CHAIN
if(ishuman(target))
var/mob/living/carbon/human/human_target = target
if(human_target.check_block(source, punch_damage, "[source]'s' [picked_hit_type]"))
source.do_attack_animation(target)
playsound(living_target.loc, 'sound/items/weapons/punchmiss.ogg', 25, TRUE, -1)
log_combat(source, target, "attempted to [picked_hit_type]", "muscle implant")
return COMPONENT_CANCEL_ATTACK_CHAIN
var/ground_bounce = FALSE // funny flavor. if you hit someone who's floored you slam them into the ground, breaking tiles
var/turf/target_turf = get_turf(living_target)
/* Damage calculations operate on the same math used in /datum/species/proc/harm():
* Unarmed damage is randomized between an upper and lower value.
* The lower value is determined by taking the damage value from the limb, and then increasing that value based on athletics level (min upper value)
* The upper value is determiend by taking the damage value from the limb, and then seeing if we have the strength trait, providing extra damage.
* The end result is that the more investment into athletics, the more precise the damage is, without necessarily increasing the potential damage.
*/
// Our attacking limb
var/obj/item/bodypart/attacking_bodypart = hand
var/potential_damage = punch_damage
// The upper damage, calculated first as it will be used to cap our potential lower damage.
var/potential_upper_damage = attacking_bodypart.unarmed_damage_high + (HAS_TRAIT(source, TRAIT_STRENGTH) ? 2 : 0)
// The lower damage, which is capped by potential_upper_damage
var/potential_lower_damage = min(attacking_bodypart.unarmed_damage_low + (source.mind?.get_skill_level(/datum/skill/athletics) || 0), potential_upper_damage)
// Finally, we determine the actual damage roll.
var/potential_damage = rand(potential_lower_damage, potential_upper_damage)
// This value is used to determine armour penetration.
var/potential_effectiveness = attacking_bodypart.unarmed_effectiveness
// This is a damage and penetration multiplier if our target is grabbed when we deliver our punch.
var/potential_pummel_bonus = attacking_bodypart.unarmed_pummeling_bonus
potential_damage += rand(attacking_bodypart.unarmed_damage_low, attacking_bodypart.unarmed_damage_high)
if(living_target.pulledby && living_target.pulledby.grab_state >= GRAB_AGGRESSIVE) // get pummeled idiot
potential_damage *= potential_pummel_bonus
@@ -541,21 +566,18 @@
if(biotype_bonus_targets && is_correct_biotype) //If we are punching one of our special biotype targets, increase the damage floor by a factor of two.
potential_damage += biotype_bonus_damage
if(ishuman(target))
var/mob/living/carbon/human/human_target = target
if(human_target.check_block(source, potential_damage, "[source]'s' [picked_hit_type]"))
source.do_attack_animation(target)
playsound(living_target.loc, 'sound/items/weapons/punchmiss.ogg', 25, TRUE, -1)
log_combat(source, target, "attempted to [picked_hit_type]", "muscle implant")
return COMPONENT_CANCEL_ATTACK_CHAIN
source.do_attack_animation(target, ATTACK_EFFECT_SMASH)
playsound(living_target.loc, 'sound/items/weapons/punch1.ogg', 25, TRUE, -1)
var/target_zone = living_target.get_random_valid_zone(source.zone_selected)
var/armor_block = living_target.run_armor_check(target_zone, MELEE, armour_penetration = potential_effectiveness)
living_target.apply_damage(potential_damage * 2, attacking_bodypart.attack_type, target_zone, armor_block)
if(source.body_position != LYING_DOWN) //Throw them if we are standing
var/atom/throw_target = get_edge_target_turf(living_target, source.dir)
living_target.throw_at(throw_target, attack_throw_range, rand(throw_power_min,throw_power_max), source, gentle = non_harmful_throw)
if(ground_bounce)
if(isfloorturf(target_turf))
var/turf/open/floor/crunched = target_turf
crunched.crush() // crunch
// Some mobs gib when killed, so we're logging early. At this point, we're definitely hitting, so...
living_target.visible_message(
span_danger("[source] [picked_hit_type]ed [living_target][ground_bounce ? " into [target_turf]" : ""]!"),
span_userdanger("You're [picked_hit_type]ed by [source][ground_bounce ? " into [target_turf]" : ""]!"),
@@ -568,7 +590,24 @@
log_combat(source, target, "[picked_hit_type]ed", "muscle implant")
COOLDOWN_START(src, slam_cooldown, slam_cooldown_duration)
if(ishuman(target))
COOLDOWN_START(src, slam_cooldown, slam_cooldown_duration)
var/target_zone = living_target.get_random_valid_zone(source.zone_selected)
var/armor_block = living_target.run_armor_check(target_zone, MELEE, armour_penetration = potential_effectiveness)
living_target.apply_damage(potential_damage * 2, attacking_bodypart.attack_type, target_zone, armor_block)
if(source.body_position != LYING_DOWN && !QDELETED(living_target)) //Throw them if we are standing and we didn't somehow just completely obliterate the target
var/atom/throw_target = get_edge_target_turf(living_target, source.dir)
living_target.throw_at(throw_target, attack_throw_range, rand(throw_power_min,throw_power_max), source, gentle = non_harmful_throw)
if(ground_bounce)
if(isfloorturf(target_turf))
var/turf/open/floor/crunched = target_turf
crunched.crush() // crunch
else if (ground_bounce) // Just in case our target mob somehow evaporated during this process, we still leave an obliterated tile in their wake
if(isfloorturf(target_turf))
var/turf/open/floor/crunched = target_turf
crunched.crush() // again, crunch
return COMPONENT_CANCEL_ATTACK_CHAIN