diff --git a/Content.Shared/Contests/ContestsSystem.Utilities.cs b/Content.Shared/Contests/ContestsSystem.Utilities.cs
index 42a69bff478..0278d75e943 100644
--- a/Content.Shared/Contests/ContestsSystem.Utilities.cs
+++ b/Content.Shared/Contests/ContestsSystem.Utilities.cs
@@ -1,4 +1,5 @@
using Content.Shared.CCVar;
+using Robust.Shared.Serialization;
namespace Content.Shared.Contests;
public sealed partial class ContestsSystem
@@ -18,4 +19,265 @@ private bool ContestClampOverride(bool bypassClamp)
{
return _cfg.GetCVar(CCVars.AllowClampOverride) && bypassClamp;
}
+
+ ///
+ /// Constructor for feeding options from a given set of ContestArgs into the ContestsSystem.
+ /// Just multiply by this and give it a user EntityUid and a ContestArgs variable. That's all you need to know.
+ ///
+ public float ContestConstructor(EntityUid user, ContestArgs args)
+ {
+ if (!_cfg.GetCVar(CCVars.DoContestsSystem))
+ return 1;
+
+ if (!args.DoEveryInteraction)
+ return args.DoMassInteraction ? ((!args.MassDisadvantage
+ ? MassContest(user, args.MassBypassClamp, args.MassRangeModifier)
+ : 1 / MassContest(user, args.MassBypassClamp, args.MassRangeModifier))
+ + args.MassOffset)
+ : 1
+ * (args.DoStaminaInteraction ? ((!args.StaminaDisadvantage
+ ? StaminaContest(user, args.StaminaBypassClamp, args.StaminaRangeModifier)
+ : 1 / StaminaContest(user, args.StaminaBypassClamp, args.StaminaRangeModifier))
+ + args.StaminaOffset)
+ : 1)
+ * (args.DoHealthInteraction ? ((!args.HealthDisadvantage
+ ? HealthContest(user, args.HealthBypassClamp, args.HealthRangeModifier)
+ : 1 / HealthContest(user, args.HealthBypassClamp, args.HealthRangeModifier))
+ + args.HealthOffset)
+ : 1)
+ * (args.DoMindInteraction ? ((!args.MindDisadvantage
+ ? MindContest(user, args.MindBypassClamp, args.MindRangeModifier)
+ : 1 / MindContest(user, args.MindBypassClamp, args.MindRangeModifier))
+ + args.MindOffset)
+ : 1)
+ * (args.DoMoodInteraction ? ((!args.MoodDisadvantage
+ ? MoodContest(user, args.MoodBypassClamp, args.MoodRangeModifier)
+ : 1 / MoodContest(user, args.MoodBypassClamp, args.MoodRangeModifier))
+ + args.MoodOffset)
+ : 1);
+
+ var everyContest = EveryContest(user,
+ args.MassBypassClamp,
+ args.StaminaBypassClamp,
+ args.HealthBypassClamp,
+ args.MindBypassClamp,
+ args.MoodBypassClamp,
+ args.MassRangeModifier,
+ args.StaminaRangeModifier,
+ args.HealthRangeModifier,
+ args.MindRangeModifier,
+ args.MoodRangeModifier,
+ args.EveryMassWeight,
+ args.EveryStaminaWeight,
+ args.EveryHealthWeight,
+ args.EveryMindWeight,
+ args.EveryMoodWeight,
+ args.EveryInteractionSumOrMultiply);
+
+ return !args.EveryDisadvantage ? everyContest : 1 / everyContest;
+ }
}
+
+[Serializable, NetSerializable, DataDefinition]
+public sealed partial class ContestArgs
+{
+ ///
+ /// Controls whether this melee weapon allows for mass to factor into damage.
+ ///
+ [DataField]
+ public bool DoMassInteraction;
+
+ ///
+ /// When true, mass provides a disadvantage.
+ ///
+ [DataField]
+ public bool MassDisadvantage;
+
+ ///
+ /// When true, mass contests ignore clamp limitations for a melee weapon.
+ ///
+ [DataField]
+ public bool MassBypassClamp;
+
+ ///
+ /// Multiplies the acceptable range of outputs provided by mass contests for melee.
+ ///
+ [DataField]
+ public float MassRangeModifier = 1;
+
+ ///
+ /// The output of a mass contest is increased by this amount.
+ ///
+ [DataField]
+ public float MassOffset;
+
+ ///
+ /// Controls whether this melee weapon allows for stamina to factor into damage.
+ ///
+ [DataField]
+ public bool DoStaminaInteraction;
+
+ ///
+ /// When true, stamina provides a disadvantage.
+ ///
+ [DataField]
+ public bool StaminaDisadvantage;
+
+ ///
+ /// When true, stamina contests ignore clamp limitations for a melee weapon.
+ ///
+ [DataField]
+ public bool StaminaBypassClamp;
+
+ ///
+ /// Multiplies the acceptable range of outputs provided by mass contests for melee.
+ ///
+ [DataField]
+ public float StaminaRangeModifier = 1;
+
+ ///
+ /// The output of a stamina contest is increased by this amount.
+ ///
+ [DataField]
+ public float StaminaOffset;
+
+ ///
+ /// Controls whether this melee weapon allows for health to factor into damage.
+ ///
+ [DataField]
+ public bool DoHealthInteraction;
+
+ ///
+ /// When true, health contests provide a disadvantage.
+ ///
+ [DataField]
+ public bool HealthDisadvantage;
+
+ ///
+ /// When true, health contests ignore clamp limitations for a melee weapon.
+ ///
+ [DataField]
+ public bool HealthBypassClamp;
+
+ ///
+ /// Multiplies the acceptable range of outputs provided by mass contests for melee.
+ ///
+ [DataField]
+ public float HealthRangeModifier = 1;
+
+ ///
+ /// The output of health contests is increased by this amount.
+ ///
+ [DataField]
+ public float HealthOffset;
+
+ ///
+ /// Controls whether this melee weapon allows for psychic casting stats to factor into damage.
+ ///
+ [DataField]
+ public bool DoMindInteraction;
+
+ ///
+ /// When true, high psychic casting stats provide a disadvantage.
+ ///
+ [DataField]
+ public bool MindDisadvantage;
+
+ ///
+ /// When true, mind contests ignore clamp limitations for a melee weapon.
+ ///
+ [DataField]
+ public bool MindBypassClamp;
+
+ ///
+ /// Multiplies the acceptable range of outputs provided by mind contests for melee.
+ ///
+ [DataField]
+ public float MindRangeModifier = 1;
+
+ ///
+ /// The output of a mind contest is increased by this amount.
+ ///
+ [DataField]
+ public float MindOffset;
+
+ ///
+ /// Controls whether this melee weapon allows mood to factor into damage.
+ ///
+ [DataField]
+ public bool DoMoodInteraction;
+
+ ///
+ /// When true, mood provides a disadvantage.
+ ///
+ [DataField]
+ public bool MoodDisadvantage;
+
+ ///
+ /// When true, mood contests ignore clamp limitations for a melee weapon.
+ ///
+ [DataField]
+ public bool MoodBypassClamp;
+
+ ///
+ /// Multiplies the acceptable range of outputs provided by mood contests for melee.
+ ///
+ [DataField]
+ public float MoodRangeModifier = 1;
+
+ ///
+ /// The output of mood contests is increased by this amount.
+ ///
+ [DataField]
+ public float MoodOffset;
+
+ ///
+ /// Enables the EveryContest interaction for a melee weapon.
+ /// IF YOU PUT THIS ON ANY WEAPON OTHER THAN AN ADMEME, I WILL COME TO YOUR HOUSE AND SEND YOU TO MEET YOUR CREATOR WHEN THE PLAYERS COMPLAIN.
+ ///
+ [DataField]
+ public bool DoEveryInteraction;
+
+ ///
+ /// When true, EveryContest provides a disadvantage.
+ ///
+ [DataField]
+ public bool EveryDisadvantage;
+
+ ///
+ /// How much Mass is considered for an EveryContest.
+ ///
+ [DataField]
+ public float EveryMassWeight = 1;
+
+ ///
+ /// How much Stamina is considered for an EveryContest.
+ ///
+ [DataField]
+ public float EveryStaminaWeight = 1;
+
+ ///
+ /// How much Health is considered for an EveryContest.
+ ///
+ [DataField]
+ public float EveryHealthWeight = 1;
+
+ ///
+ /// How much psychic casting stats are considered for an EveryContest.
+ ///
+ [DataField]
+ public float EveryMindWeight = 1;
+
+ ///
+ /// How much mood is considered for an EveryContest.
+ ///
+ [DataField]
+ public float EveryMoodWeight = 1;
+
+ ///
+ /// When true, the EveryContest sums the results of all contests rather than multiplying them,
+ /// probably giving you a very, very, very large multiplier...
+ ///
+ [DataField]
+ public bool EveryInteractionSumOrMultiply;
+}
\ No newline at end of file
diff --git a/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs b/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs
index c242d448f27..43e3096d158 100644
--- a/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs
+++ b/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs
@@ -1,3 +1,4 @@
+using Content.Shared.Contests;
using Content.Shared.Damage;
using Content.Shared.FixedPoint;
using Robust.Shared.Audio;
@@ -156,6 +157,20 @@ public sealed partial class MeleeWeaponComponent : Component
///
[DataField, AutoNetworkedField]
public SoundSpecifier SoundNoDamage { get; set; } = new SoundCollectionSpecifier("WeakHit");
+
+ ///
+ /// Arguments for the MeleeContestInteractions constructor
+ ///
+ [DataField]
+ public ContestArgs ContestArgs = new ContestArgs
+ {
+ DoStaminaInteraction = true,
+ StaminaDisadvantage = true,
+ StaminaRangeModifier = 2,
+ StaminaOffset = 0.25f,
+ DoHealthInteraction = true,
+ HealthRangeModifier = 1.5f,
+ };
}
///
diff --git a/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs b/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs
index b5a537b7e15..fd77ad31a45 100644
--- a/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs
+++ b/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs
@@ -32,7 +32,7 @@
namespace Content.Shared.Weapons.Melee;
-public abstract class SharedMeleeWeaponSystem : EntitySystem
+public abstract partial class SharedMeleeWeaponSystem : EntitySystem
{
[Dependency] protected readonly ISharedAdminLogManager AdminLogger = default!;
[Dependency] protected readonly ActionBlockerSystem Blocker = default!;
@@ -225,6 +225,9 @@ public DamageSpecifier GetDamage(EntityUid uid, EntityUid user, MeleeWeaponCompo
var ev = new GetMeleeDamageEvent(uid, new (component.Damage), new(), user);
RaiseLocalEvent(uid, ref ev);
+ if (component.ContestArgs is not null)
+ ev.Damage *= _contests.ContestConstructor(user, component.ContestArgs);
+
return DamageSpecifier.ApplyModifierSets(ev.Damage, ev.Modifiers);
}
@@ -249,9 +252,7 @@ public FixedPoint2 GetHeavyDamageModifier(EntityUid uid, EntityUid user, MeleeWe
return ev.DamageModifier
* ev.Multipliers
- * component.HeavyDamageBaseModifier
- * _contests.StaminaContest(user, false, 2f) //Taking stamina damage reduces wide swing damage by up to 50%
- / _contests.HealthContest(user, false, 0.8f); //Being injured grants up to 20% more wide swing damage
+ * component.HeavyDamageBaseModifier;
}
public bool TryGetWeapon(EntityUid entity, out EntityUid weaponUid, [NotNullWhen(true)] out MeleeWeaponComponent? melee)
@@ -440,9 +441,7 @@ private bool AttemptAttack(EntityUid user, EntityUid weaponUid, MeleeWeaponCompo
protected virtual void DoLightAttack(EntityUid user, LightAttackEvent ev, EntityUid meleeUid, MeleeWeaponComponent component, ICommonSession? session)
{
- var damage = GetDamage(meleeUid, user, component)
- * _contests.StaminaContest(user) //Taking stamina damage reduces light attack damage by up to 25%
- / _contests.HealthContest(user, false, 0.8f); //Being injured grants up to 20% more damage;
+ var damage = GetDamage(meleeUid, user, component);
var target = GetEntity(ev.Target);
// For consistency with wide attacks stuff needs damageable.