using Content.Shared.CCVar;
using Content.Shared.Damage;
using Content.Shared.Damage.Components;
using Content.Shared.Mobs.Systems;
using Robust.Shared.Configuration;
using Robust.Shared.Physics.Components;
namespace Content.Shared.Contests
{
public sealed partial class ContestsSystem : EntitySystem
{
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly MobThresholdSystem _mobThreshold = default!;
///
/// The presumed average mass of a player entity
/// Defaulted to the average mass of an adult human
///
private const float AverageMass = 71f;
#region Mass Contests
///
/// Outputs the ratio of mass between a performer and the average human mass
///
/// Uid of Performer
public float MassContest(EntityUid performerUid, bool bypassClamp = false, float rangeFactor = 1f, float otherMass = AverageMass)
{
if (!_cfg.GetCVar(CCVars.DoContestsSystem)
|| !_cfg.GetCVar(CCVars.DoMassContests)
|| !TryComp(performerUid, out var performerPhysics)
|| performerPhysics.Mass == 0)
return 1f;
return _cfg.GetCVar(CCVars.AllowClampOverride) && bypassClamp
? performerPhysics.Mass / otherMass
: Math.Clamp(performerPhysics.Mass / otherMass,
1 - _cfg.GetCVar(CCVars.MassContestsMaxPercentage) * rangeFactor,
1 + _cfg.GetCVar(CCVars.MassContestsMaxPercentage) * rangeFactor);
}
///
///
/// MaybeMassContest, in case your entity doesn't exist
///
public float MassContest(EntityUid? performerUid, bool bypassClamp = false, float rangeFactor = 1f, float otherMass = AverageMass)
{
if (!_cfg.GetCVar(CCVars.DoContestsSystem)
|| !_cfg.GetCVar(CCVars.DoMassContests)
|| performerUid is null)
return 1f;
return MassContest(performerUid.Value, bypassClamp, rangeFactor, otherMass);
}
///
/// Outputs the ratio of mass between a performer and the average human mass
/// If a function already has the performer's physics component, this is faster
///
///
public float MassContest(PhysicsComponent performerPhysics, bool bypassClamp = false, float rangeFactor = 1f, float otherMass = AverageMass)
{
if (!_cfg.GetCVar(CCVars.DoContestsSystem)
|| !_cfg.GetCVar(CCVars.DoMassContests)
|| performerPhysics.Mass == 0)
return 1f;
return _cfg.GetCVar(CCVars.AllowClampOverride) && bypassClamp
? performerPhysics.Mass / otherMass
: Math.Clamp(performerPhysics.Mass / otherMass,
1 - _cfg.GetCVar(CCVars.MassContestsMaxPercentage) * rangeFactor,
1 + _cfg.GetCVar(CCVars.MassContestsMaxPercentage) * rangeFactor);
}
///
/// Outputs the ratio of mass between a performer and a target, accepts either EntityUids or PhysicsComponents in any combination
/// If you have physics components already in your function, use instead
///
///
///
public float MassContest(EntityUid performerUid, EntityUid targetUid, bool bypassClamp = false, float rangeFactor = 1f)
{
if (!_cfg.GetCVar(CCVars.DoContestsSystem)
|| !_cfg.GetCVar(CCVars.DoMassContests)
|| !TryComp(performerUid, out var performerPhysics)
|| !TryComp(targetUid, out var targetPhysics)
|| performerPhysics.Mass == 0
|| targetPhysics.InvMass == 0)
return 1f;
return _cfg.GetCVar(CCVars.AllowClampOverride) && bypassClamp
? performerPhysics.Mass * targetPhysics.InvMass
: Math.Clamp(performerPhysics.Mass * targetPhysics.InvMass,
1 - _cfg.GetCVar(CCVars.MassContestsMaxPercentage) * rangeFactor,
1 + _cfg.GetCVar(CCVars.MassContestsMaxPercentage) * rangeFactor);
}
///
public float MassContest(EntityUid performerUid, PhysicsComponent targetPhysics, bool bypassClamp = false, float rangeFactor = 1f)
{
if (!_cfg.GetCVar(CCVars.DoContestsSystem)
|| !_cfg.GetCVar(CCVars.DoMassContests)
|| !TryComp(performerUid, out var performerPhysics)
|| performerPhysics.Mass == 0
|| targetPhysics.InvMass == 0)
return 1f;
return _cfg.GetCVar(CCVars.AllowClampOverride) && bypassClamp
? performerPhysics.Mass * targetPhysics.InvMass
: Math.Clamp(performerPhysics.Mass * targetPhysics.InvMass,
1 - _cfg.GetCVar(CCVars.MassContestsMaxPercentage) * rangeFactor,
1 + _cfg.GetCVar(CCVars.MassContestsMaxPercentage) * rangeFactor);
}
///
public float MassContest(PhysicsComponent performerPhysics, EntityUid targetUid, bool bypassClamp = false, float rangeFactor = 1f)
{
if (!_cfg.GetCVar(CCVars.DoContestsSystem)
|| !_cfg.GetCVar(CCVars.DoMassContests)
|| !TryComp(targetUid, out var targetPhysics)
|| performerPhysics.Mass == 0
|| targetPhysics.InvMass == 0)
return 1f;
return _cfg.GetCVar(CCVars.AllowClampOverride) && bypassClamp
? performerPhysics.Mass * targetPhysics.InvMass
: Math.Clamp(performerPhysics.Mass * targetPhysics.InvMass,
1 - _cfg.GetCVar(CCVars.MassContestsMaxPercentage) * rangeFactor,
1 + _cfg.GetCVar(CCVars.MassContestsMaxPercentage) * rangeFactor);
}
///
public float MassContest(PhysicsComponent performerPhysics, PhysicsComponent targetPhysics, bool bypassClamp = false, float rangeFactor = 1f)
{
if (!_cfg.GetCVar(CCVars.DoContestsSystem)
|| !_cfg.GetCVar(CCVars.DoMassContests)
|| performerPhysics.Mass == 0
|| targetPhysics.InvMass == 0)
return 1f;
return _cfg.GetCVar(CCVars.AllowClampOverride) && bypassClamp
? performerPhysics.Mass * targetPhysics.InvMass
: Math.Clamp(performerPhysics.Mass * targetPhysics.InvMass,
1 - _cfg.GetCVar(CCVars.MassContestsMaxPercentage) * rangeFactor,
1 + _cfg.GetCVar(CCVars.MassContestsMaxPercentage) * rangeFactor);
}
#endregion
#region Stamina Contests
public float StaminaContest(EntityUid performer, bool bypassClamp = false, float rangeFactor = 1f)
{
if (!_cfg.GetCVar(CCVars.DoContestsSystem)
|| !_cfg.GetCVar(CCVars.DoStaminaContests)
|| !TryComp(performer, out var perfStamina)
|| perfStamina.StaminaDamage == 0)
return 1f;
return _cfg.GetCVar(CCVars.AllowClampOverride) && bypassClamp
? 1 - perfStamina.StaminaDamage / perfStamina.CritThreshold
: 1 - Math.Clamp(perfStamina.StaminaDamage / perfStamina.CritThreshold, 0, 0.25f * rangeFactor);
}
public float StaminaContest(StaminaComponent perfStamina, bool bypassClamp = false, float rangeFactor = 1f)
{
if (!_cfg.GetCVar(CCVars.DoContestsSystem)
|| !_cfg.GetCVar(CCVars.DoStaminaContests))
return 1f;
return _cfg.GetCVar(CCVars.AllowClampOverride) && bypassClamp
? 1 - perfStamina.StaminaDamage / perfStamina.CritThreshold
: 1 - Math.Clamp(perfStamina.StaminaDamage / perfStamina.CritThreshold, 0, 0.25f * rangeFactor);
}
public float StaminaContest(EntityUid performer, EntityUid target, bool bypassClamp = false, float rangeFactor = 1f)
{
if (!_cfg.GetCVar(CCVars.DoContestsSystem)
|| !_cfg.GetCVar(CCVars.DoStaminaContests)
|| !TryComp(performer, out var perfStamina)
|| !TryComp(target, out var targetStamina))
return 1f;
return _cfg.GetCVar(CCVars.AllowClampOverride) && bypassClamp
? (1 - perfStamina.StaminaDamage / perfStamina.CritThreshold)
/ (1 - targetStamina.StaminaDamage / targetStamina.CritThreshold)
: (1 - Math.Clamp(perfStamina.StaminaDamage / perfStamina.CritThreshold, 0, 0.25f * rangeFactor))
/ (1 - Math.Clamp(targetStamina.StaminaDamage / targetStamina.CritThreshold, 0, 0.25f * rangeFactor));
}
#endregion
#region Health Contests
public float HealthContest(EntityUid performer, bool bypassClamp = false, float rangeFactor = 1f)
{
if (!_cfg.GetCVar(CCVars.DoContestsSystem)
|| !_cfg.GetCVar(CCVars.DoHealthContests)
|| !TryComp(performer, out var damage)
|| !_mobThreshold.TryGetThresholdForState(performer, Mobs.MobState.Critical, out var threshold))
return 1f;
return _cfg.GetCVar(CCVars.AllowClampOverride) && bypassClamp
? 1 - damage.TotalDamage.Float() / threshold.Value.Float()
: 1 - Math.Clamp(damage.TotalDamage.Float() / threshold.Value.Float(), 0, 0.25f * rangeFactor);
}
public float HealthContest(EntityUid performer, EntityUid target, bool bypassClamp = false, float rangeFactor = 1f)
{
if (!_cfg.GetCVar(CCVars.DoContestsSystem)
|| !_cfg.GetCVar(CCVars.DoHealthContests)
|| !TryComp(performer, out var perfDamage)
|| !TryComp(target, out var targetDamage)
|| !_mobThreshold.TryGetThresholdForState(performer, Mobs.MobState.Critical, out var perfThreshold)
|| !_mobThreshold.TryGetThresholdForState(target, Mobs.MobState.Critical, out var targetThreshold))
return 1f;
return _cfg.GetCVar(CCVars.AllowClampOverride) && bypassClamp
? (1 - perfDamage.TotalDamage.Float() / perfThreshold.Value.Float())
/ (1 - targetDamage.TotalDamage.Float() / targetThreshold.Value.Float())
: (1 - Math.Clamp(perfDamage.TotalDamage.Float() / perfThreshold.Value.Float(), 0, 0.25f * rangeFactor))
/ (1 - Math.Clamp(targetDamage.TotalDamage.Float() / targetThreshold.Value.Float(), 0, 0.25f * rangeFactor));
}
#endregion
#region Mind Contests
///
/// These cannot be implemented until AFTER the psychic refactor, but can still be factored into other systems before that point.
/// Same rule here as other Contest functions, simply multiply or divide by the function.
///
///
///
///
///
public float MindContest(EntityUid performer, bool bypassClamp = false, float rangeFactor = 1f)
{
if (!_cfg.GetCVar(CCVars.DoContestsSystem)
|| !_cfg.GetCVar(CCVars.DoMindContests))
return 1f;
return 1f;
}
public float MindContest(EntityUid performer, EntityUid target, bool bypassClamp = false, float rangeFactor = 1f)
{
if (!_cfg.GetCVar(CCVars.DoContestsSystem)
|| !_cfg.GetCVar(CCVars.DoMindContests))
return 1f;
return 1f;
}
#endregion
#region EVERY CONTESTS
public float EveryContest(
EntityUid performer,
bool bypassClampMass = false,
bool bypassClampStamina = false,
bool bypassClampHealth = false,
bool bypassClampMind = false,
float rangeFactorMass = 1f,
float rangeFactorStamina = 1f,
float rangeFactorHealth = 1f,
float rangeFactorMind = 1f,
float weightMass = 1f,
float weightStamina = 1f,
float weightHealth = 1f,
float weightMind = 1f,
bool sumOrMultiply = false)
{
if (!_cfg.GetCVar(CCVars.DoContestsSystem))
return 1f;
var weightTotal = weightMass + weightStamina + weightHealth + weightMind;
var massMultiplier = weightMass / weightTotal;
var staminaMultiplier = weightStamina / weightTotal;
var healthMultiplier = weightHealth / weightTotal;
var mindMultiplier = weightMind / weightTotal;
return sumOrMultiply
? MassContest(performer, bypassClampMass, rangeFactorMass) * massMultiplier
+ StaminaContest(performer, bypassClampStamina, rangeFactorStamina) * staminaMultiplier
+ HealthContest(performer, bypassClampHealth, rangeFactorHealth) * healthMultiplier
+ MindContest(performer, bypassClampMind, rangeFactorMind) * mindMultiplier
: MassContest(performer, bypassClampMass, rangeFactorMass) * massMultiplier
* StaminaContest(performer, bypassClampStamina, rangeFactorStamina) * staminaMultiplier
* HealthContest(performer, bypassClampHealth, rangeFactorHealth) * healthMultiplier
* MindContest(performer, bypassClampMind, rangeFactorMind) * mindMultiplier;
}
public float EveryContest(
EntityUid performer,
EntityUid target,
bool bypassClampMass = false,
bool bypassClampStamina = false,
bool bypassClampHealth = false,
bool bypassClampMind = false,
float rangeFactorMass = 1f,
float rangeFactorStamina = 1f,
float rangeFactorHealth = 1f,
float rangeFactorMind = 1f,
float weightMass = 1f,
float weightStamina = 1f,
float weightHealth = 1f,
float weightMind = 1f,
bool sumOrMultiply = false)
{
if (!_cfg.GetCVar(CCVars.DoContestsSystem))
return 1f;
var weightTotal = weightMass + weightStamina + weightHealth + weightMind;
var massMultiplier = weightMass / weightTotal;
var staminaMultiplier = weightStamina / weightTotal;
var healthMultiplier = weightHealth / weightTotal;
var mindMultiplier = weightMind / weightTotal;
return sumOrMultiply
? MassContest(performer, target, bypassClampMass, rangeFactorMass) * massMultiplier
+ StaminaContest(performer, target, bypassClampStamina, rangeFactorStamina) * staminaMultiplier
+ HealthContest(performer, target, bypassClampHealth, rangeFactorHealth) * healthMultiplier
+ MindContest(performer, target, bypassClampMind, rangeFactorMind) * mindMultiplier
: MassContest(performer, target, bypassClampMass, rangeFactorMass) * massMultiplier
* StaminaContest(performer, target, bypassClampStamina, rangeFactorStamina) * staminaMultiplier
* HealthContest(performer, target, bypassClampHealth, rangeFactorHealth) * healthMultiplier
* MindContest(performer, target, bypassClampMind, rangeFactorMind) * mindMultiplier;
}
#endregion
}
}