From b44ec9554af3a4fb26d4a5908e4b80f58db09a57 Mon Sep 17 00:00:00 2001 From: Rane <60792108+Elijahrane@users.noreply.github.com> Date: Fri, 17 Jun 2022 01:37:07 -0400 Subject: [PATCH] Disarm 1984 (#8872) --- Content.Server/CombatMode/CombatModeSystem.cs | 52 +++++++++++++++++-- .../CombatMode/Disarm/DisarmMalusComponent.cs | 16 ++++++ .../Components/EnergySwordComponent.cs | 3 ++ .../Melee/EnergySword/EnergySwordSystem.cs | 11 ++++ .../CombatMode/SharedCombatModeComponent.cs | 4 +- .../en-US/actions/actions/disarm-action.ftl | 2 + .../Objects/Weapons/Melee/e_sword.yml | 6 +++ .../Entities/Objects/Weapons/Melee/knife.yml | 2 + .../Entities/Objects/Weapons/Melee/sword.yml | 4 ++ .../Entities/Objects/Weapons/security.yml | 2 + 10 files changed, 96 insertions(+), 6 deletions(-) create mode 100644 Content.Server/CombatMode/Disarm/DisarmMalusComponent.cs diff --git a/Content.Server/CombatMode/CombatModeSystem.cs b/Content.Server/CombatMode/CombatModeSystem.cs index f4398bdbdc..23533ea431 100644 --- a/Content.Server/CombatMode/CombatModeSystem.cs +++ b/Content.Server/CombatMode/CombatModeSystem.cs @@ -1,16 +1,20 @@ using Content.Server.Actions.Events; using Content.Server.Administration.Logs; +using Content.Server.CombatMode.Disarm; using Content.Server.Hands.Components; using Content.Server.Popups; using Content.Server.Weapon.Melee; using Content.Shared.ActionBlocker; using Content.Shared.Audio; using Content.Shared.CombatMode; +using Content.Shared.Damage; using Content.Shared.Database; +using Content.Shared.Stunnable; using JetBrains.Annotations; using Robust.Shared.Audio; using Robust.Shared.Player; using Robust.Shared.Random; +using Robust.Shared.Physics; namespace Content.Server.CombatMode { @@ -38,9 +42,17 @@ namespace Content.Server.CombatMode if (!_actionBlockerSystem.CanAttack(args.Performer)) return; + if (TryComp(args.Performer, out var hands) + && hands.ActiveHand != null + && !hands.ActiveHand.IsEmpty) + { + _popupSystem.PopupEntity(Loc.GetString("disarm-action-free-hand"), args.Performer, Filter.Entities(args.Performer)); + return; + } + EntityUid? inTargetHand = null; - if (EntityManager.TryGetComponent(args.Target, out HandsComponent? targetHandsComponent) + if (TryComp(args.Target, out HandsComponent? targetHandsComponent) && targetHandsComponent.ActiveHand != null && !targetHandsComponent.ActiveHand.IsEmpty) { @@ -64,8 +76,8 @@ namespace Content.Server.CombatMode var filterOther = filterAll.RemoveWhereAttachedEntity(e => e == args.Performer); args.Handled = true; - - if (_random.Prob(component.DisarmFailChance)) + var chance = CalculateDisarmChance(args.Performer, args.Target, inTargetHand, component); + if (_random.Prob(chance)) { SoundSystem.Play(component.DisarmFailSound.GetSound(), Filter.Pvs(args.Performer), args.Performer, AudioHelpers.WithVariation(0.025f)); @@ -89,8 +101,40 @@ namespace Content.Server.CombatMode SoundSystem.Play(component.DisarmSuccessSound.GetSound(), filterAll, args.Performer, AudioHelpers.WithVariation(0.025f)); _adminLogger.Add(LogType.DisarmedAction, $"{ToPrettyString(args.Performer):user} used disarm on {ToPrettyString(args.Target):target}"); - var eventArgs = new DisarmedEvent() { Target = args.Target, Source = args.Performer, PushProbability = component.DisarmPushChance }; + var eventArgs = new DisarmedEvent() { Target = args.Target, Source = args.Performer, PushProbability = chance }; RaiseLocalEvent(args.Target, eventArgs); } + + + private float CalculateDisarmChance(EntityUid disarmer, EntityUid disarmed, EntityUid? inTargetHand, SharedCombatModeComponent disarmerComp) + { + float healthMod = 0; + if (TryComp(disarmer, out var disarmerDamage) && TryComp(disarmed, out var disarmedDamage)) + { + // I wanted this to consider their mob state thresholds too but I'm not touching that shitcode after having a go at this. + healthMod = (((float) disarmedDamage.TotalDamage - (float) disarmerDamage.TotalDamage) / 200); // Ex. You have 0 damage, they have 90, you get a 45% chance increase + } + + float massMod = 0; + + if (TryComp(disarmer, out var disarmerPhysics) && TryComp(disarmed, out var disarmedPhysics)) + { + if (disarmerPhysics.FixturesMass != 0) // yeah this will never happen but let's not kill the server if it does + massMod = (((disarmedPhysics.FixturesMass / disarmerPhysics.FixturesMass - 1 ) / 2)); // Ex, you weigh 120, they weigh 70, you get a 29% bonus + } + + float chance = (disarmerComp.BaseDisarmFailChance - healthMod - massMod); + if (HasComp(disarmer)) // might need to revisit this part after stamina damage, right now this is basically "pre-stun" + chance += 0.35f; + if (HasComp(disarmed)) + chance -= 0.35f; + + if (inTargetHand != null && TryComp(inTargetHand, out var malus)) + { + chance += malus.Malus; + } + + return Math.Clamp(chance, 0f, 1f); + } } } diff --git a/Content.Server/CombatMode/Disarm/DisarmMalusComponent.cs b/Content.Server/CombatMode/Disarm/DisarmMalusComponent.cs new file mode 100644 index 0000000000..9e5b454ae7 --- /dev/null +++ b/Content.Server/CombatMode/Disarm/DisarmMalusComponent.cs @@ -0,0 +1,16 @@ +namespace Content.Server.CombatMode.Disarm +{ + /// + /// Applies a malus to disarm attempts against this item. + /// + [RegisterComponent] + public sealed class DisarmMalusComponent : Component + { + /// + /// So, disarm chances are a % chance represented as a value between 0 and 1. + /// This default would be a 30% penalty to that. + /// + [DataField("malus")] + public float Malus = 0.3f; + } +} diff --git a/Content.Server/Weapon/Melee/EnergySword/Components/EnergySwordComponent.cs b/Content.Server/Weapon/Melee/EnergySword/Components/EnergySwordComponent.cs index 442f979faf..2f11c73661 100644 --- a/Content.Server/Weapon/Melee/EnergySword/Components/EnergySwordComponent.cs +++ b/Content.Server/Weapon/Melee/EnergySword/Components/EnergySwordComponent.cs @@ -36,5 +36,8 @@ namespace Content.Server.Weapon.Melee.EnergySword [DataField("litDamageBonus", required: true)] public DamageSpecifier LitDamageBonus = default!; + + [DataField("litDisarmMalus", required: true)] + public float litDisarmMalus = 0.6f; } } diff --git a/Content.Server/Weapon/Melee/EnergySword/EnergySwordSystem.cs b/Content.Server/Weapon/Melee/EnergySword/EnergySwordSystem.cs index ba165e8b49..aa675681a1 100644 --- a/Content.Server/Weapon/Melee/EnergySword/EnergySwordSystem.cs +++ b/Content.Server/Weapon/Melee/EnergySword/EnergySwordSystem.cs @@ -5,6 +5,7 @@ using Content.Shared.Light; using Content.Shared.Light.Component; using Content.Shared.Toggleable; using Content.Shared.Tools.Components; +using Content.Server.CombatMode.Disarm; using Robust.Shared.Audio; using Robust.Shared.Player; using Robust.Shared.Random; @@ -68,6 +69,11 @@ namespace Content.Server.Weapon.Melee.EnergySword item.Size = 5; } + if (TryComp(comp.Owner, out var malus)) + { + malus.Malus -= comp.litDisarmMalus; + } + SoundSystem.Play(comp.DeActivateSound.GetSound(), Filter.Pvs(comp.Owner, entityManager: EntityManager), comp.Owner); comp.Activated = false; @@ -85,6 +91,11 @@ namespace Content.Server.Weapon.Melee.EnergySword SoundSystem.Play(comp.ActivateSound.GetSound(), Filter.Pvs(comp.Owner, entityManager: EntityManager), comp.Owner); + if (TryComp(comp.Owner, out var malus)) + { + malus.Malus += comp.litDisarmMalus; + } + comp.Activated = true; } diff --git a/Content.Shared/CombatMode/SharedCombatModeComponent.cs b/Content.Shared/CombatMode/SharedCombatModeComponent.cs index 790a2724bd..8a958f6f59 100644 --- a/Content.Shared/CombatMode/SharedCombatModeComponent.cs +++ b/Content.Shared/CombatMode/SharedCombatModeComponent.cs @@ -15,10 +15,10 @@ namespace Content.Shared.CombatMode private TargetingZone _activeZone; [DataField("disarmFailChance")] - public readonly float DisarmFailChance = 0.4f; + public readonly float BaseDisarmFailChance = 0.4f; [DataField("pushChance")] - public readonly float DisarmPushChance = 0.4f; + public readonly float BasePushFailChance = 0.4f; [DataField("disarmFailSound")] public readonly SoundSpecifier DisarmFailSound = new SoundPathSpecifier("/Audio/Weapons/punchmiss.ogg"); diff --git a/Resources/Locale/en-US/actions/actions/disarm-action.ftl b/Resources/Locale/en-US/actions/actions/disarm-action.ftl index 2625ec336e..4f97b4f766 100644 --- a/Resources/Locale/en-US/actions/actions/disarm-action.ftl +++ b/Resources/Locale/en-US/actions/actions/disarm-action.ftl @@ -1,3 +1,5 @@ +disarm-action-free-hand = You need to use a free hand to disarm! + disarm-action-popup-message-other-clients = {$performerName} fails to disarm {$targetName}! disarm-action-popup-message-cursor = You fail to disarm {$targetName}! diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml index b31075c040..848b95003a 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml @@ -10,6 +10,7 @@ Slash: 12.5 Heat: 12.5 Blunt: -7 + litDisarmMalus: 0.6 - type: Sharp - type: Sprite sprite: Objects/Weapons/Melee/e_sword.rsi @@ -47,6 +48,8 @@ right: - state: inhand-right-blade shader: unshaded + - type: DisarmMalus + malus: 0 - type: entity name: pen @@ -61,6 +64,7 @@ Slash: 7.5 Heat: 7.5 Blunt: -1 + litDisarmMalus: 0.4 - type: Sprite sprite: Objects/Weapons/Melee/e_dagger.rsi layers: @@ -98,3 +102,5 @@ - type: Tag tags: - Write + - type: DisarmMalus + malus: 0 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml index 476ece58d7..ea6799758e 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml @@ -89,6 +89,8 @@ size: 10 sprite: Objects/Weapons/Melee/combat_knife.rsi prefix: inhand + - type: DisarmMalus + malus: 0.225 - type: entity name: survival knife diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml index ef734865a3..f44fda2571 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml @@ -18,6 +18,7 @@ - type: Tag tags: - CaptainSabre + - type: DisarmMalus - type: entity name: katana @@ -39,6 +40,7 @@ - type: Item size: 15 sprite: Objects/Weapons/Melee/katana.rsi + - type: DisarmMalus - type: entity name: machete @@ -60,6 +62,7 @@ - type: Item size: 15 sprite: Objects/Weapons/Melee/machete.rsi + - type: DisarmMalus - type: entity name: claymore @@ -80,3 +83,4 @@ sprite: Objects/Weapons/Melee/claymore.rsi Slots: - back + - type: DisarmMalus diff --git a/Resources/Prototypes/Entities/Objects/Weapons/security.yml b/Resources/Prototypes/Entities/Objects/Weapons/security.yml index 1bac5df766..3db6c2463d 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/security.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/security.yml @@ -27,6 +27,8 @@ size: 20 Slots: - Belt + - type: DisarmMalus + malus: 0.225 - type: entity name: flash