using Content.Shared.Abilities.Psionics;
using Content.Shared.CCVar;
using Content.Shared.Damage;
using Content.Shared.Damage.Components;
using Content.Shared.Mobs.Systems;
using Content.Shared.Mood;
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;
///
/// The presumed average sum of a Psionic's Baseline Amplification and Baseline Dampening.
/// Since Baseline casting stats are a random value between 0.4 and 1.2, this is defaulted to 0.8 + 0.8.
///
private const float AveragePsionicPotential = 1.6f;
#region Mass Contests
///
/// Outputs the ratio of mass between a performer and the average human mass
///
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
///
/// Returns the ratio of casting stats between a performer and the presumed average latent psionic.
/// Uniquely among Contests, not being Psionic is not a failure condition, and is instead a variable.
/// If you do not have a PsionicComponent, your combined casting stats are assumed to be 0.1f
///
///
/// This can produce some truly astounding modifiers, so be ready to meet god if you bypass the clamp.
///
public float MindContest(EntityUid performer, bool bypassClamp = false, float rangeFactor = 1f, float otherPsion = AveragePsionicPotential)
{
if (!_cfg.GetCVar(CCVars.DoContestsSystem)
|| !_cfg.GetCVar(CCVars.DoMindContests))
return 1f;
var performerPotential = TryComp(performer, out var performerPsionic)
? performerPsionic.CurrentAmplification + performerPsionic.CurrentDampening
: 0.1f;
if (performerPotential == otherPsion)
return 1f;
return _cfg.GetCVar(CCVars.AllowClampOverride) && bypassClamp
? performerPotential / otherPsion
: Math.Clamp(performerPotential / otherPsion,
1 - _cfg.GetCVar(CCVars.MassContestsMaxPercentage) * rangeFactor,
1 + _cfg.GetCVar(CCVars.MassContestsMaxPercentage) * rangeFactor);
}
///
/// Returns the ratio of casting stats between a performer and a target.
/// Like with single-Uid MindContests, if an entity does not possess a PsionicComponent, its casting stats are assumed to be 0.1f.
///
///
/// This can produce some truly astounding modifiers, so be ready to meet god if you bypass the clamp.
///
public float MindContest(EntityUid performer, EntityUid target, bool bypassClamp = false, float rangeFactor = 1f)
{
if (!_cfg.GetCVar(CCVars.DoContestsSystem)
|| !_cfg.GetCVar(CCVars.DoMindContests))
return 1f;
var performerPotential = TryComp(performer, out var performerPsionic)
? performerPsionic.CurrentAmplification + performerPsionic.CurrentDampening
: 0.1f;
var targetPotential = TryComp(target, out var targetPsionic)
? targetPsionic.CurrentAmplification + targetPsionic.CurrentDampening
: 0.1f;
if (performerPotential == targetPotential)
return 1f;
return _cfg.GetCVar(CCVars.AllowClampOverride) && bypassClamp
? performerPotential / targetPotential
: Math.Clamp(performerPotential / targetPotential,
1 - _cfg.GetCVar(CCVars.MassContestsMaxPercentage) * rangeFactor,
1 + _cfg.GetCVar(CCVars.MassContestsMaxPercentage) * rangeFactor);
}
#endregion
#region Mood Contests
///
/// Outputs the ratio of an Entity's mood level and its Neutral Mood threshold.
///
public float MoodContest(EntityUid performer, bool bypassClamp = false, float rangeFactor = 1f)
{
if (!_cfg.GetCVar(CCVars.DoContestsSystem)
|| !_cfg.GetCVar(CCVars.DoMoodContests)
|| !TryComp(performer, out var mood))
return 1f;
return _cfg.GetCVar(CCVars.AllowClampOverride) && bypassClamp
? mood.CurrentMoodLevel / mood.NeutralMoodThreshold
: Math.Clamp(mood.CurrentMoodLevel / mood.NeutralMoodThreshold,
1 - _cfg.GetCVar(CCVars.MassContestsMaxPercentage) * rangeFactor,
1 + _cfg.GetCVar(CCVars.MassContestsMaxPercentage) * rangeFactor);
}
///
/// Outputs the ratio of mood level between two Entities.
///
public float MoodContest(EntityUid performer, EntityUid target, bool bypassClamp = false, float rangeFactor = 1f)
{
if (!_cfg.GetCVar(CCVars.DoContestsSystem)
|| !_cfg.GetCVar(CCVars.DoMoodContests)
|| !TryComp(performer, out var performerMood)
|| !TryComp(target, out var targetMood))
return 1f;
return _cfg.GetCVar(CCVars.AllowClampOverride) && bypassClamp
? performerMood.CurrentMoodLevel / targetMood.CurrentMoodLevel
: Math.Clamp(performerMood.CurrentMoodLevel / targetMood.CurrentMoodLevel,
1 - _cfg.GetCVar(CCVars.MassContestsMaxPercentage) * rangeFactor,
1 + _cfg.GetCVar(CCVars.MassContestsMaxPercentage) * rangeFactor);
}
#endregion
#region EVERY CONTESTS
public float EveryContest(
EntityUid performer,
bool bypassClampMass = false,
bool bypassClampStamina = false,
bool bypassClampHealth = false,
bool bypassClampMind = false,
bool bypassClampMood = false,
float rangeFactorMass = 1f,
float rangeFactorStamina = 1f,
float rangeFactorHealth = 1f,
float rangeFactorMind = 1f,
float rangeFactorMood = 1f,
float weightMass = 1f,
float weightStamina = 1f,
float weightHealth = 1f,
float weightMind = 1f,
float weightMood = 1f,
bool sumOrMultiply = false)
{
if (!_cfg.GetCVar(CCVars.DoContestsSystem))
return 1f;
var weightTotal = weightMass + weightStamina + weightHealth + weightMind + weightMood;
var massMultiplier = weightMass / weightTotal;
var staminaMultiplier = weightStamina / weightTotal;
var healthMultiplier = weightHealth / weightTotal;
var mindMultiplier = weightMind / weightTotal;
var moodMultiplier = weightMood / weightTotal;
return sumOrMultiply
? MassContest(performer, bypassClampMass, rangeFactorMass) * massMultiplier
+ StaminaContest(performer, bypassClampStamina, rangeFactorStamina) * staminaMultiplier
+ HealthContest(performer, bypassClampHealth, rangeFactorHealth) * healthMultiplier
+ MindContest(performer, bypassClampMind, rangeFactorMind) * mindMultiplier
+ MoodContest(performer, bypassClampMood, rangeFactorMood) * moodMultiplier
: MassContest(performer, bypassClampMass, rangeFactorMass) * massMultiplier
* StaminaContest(performer, bypassClampStamina, rangeFactorStamina) * staminaMultiplier
* HealthContest(performer, bypassClampHealth, rangeFactorHealth) * healthMultiplier
* MindContest(performer, bypassClampMind, rangeFactorMind) * mindMultiplier
* MoodContest(performer, bypassClampMood, rangeFactorMood) * moodMultiplier;
}
public float EveryContest(
EntityUid performer,
EntityUid target,
bool bypassClampMass = false,
bool bypassClampStamina = false,
bool bypassClampHealth = false,
bool bypassClampMind = false,
bool bypassClampMood = false,
float rangeFactorMass = 1f,
float rangeFactorStamina = 1f,
float rangeFactorHealth = 1f,
float rangeFactorMind = 1f,
float rangeFactorMood = 1f,
float weightMass = 1f,
float weightStamina = 1f,
float weightHealth = 1f,
float weightMind = 1f,
float weightMood = 1f,
bool sumOrMultiply = false)
{
if (!_cfg.GetCVar(CCVars.DoContestsSystem))
return 1f;
var weightTotal = weightMass + weightStamina + weightHealth + weightMind + weightMood;
var massMultiplier = weightMass / weightTotal;
var staminaMultiplier = weightStamina / weightTotal;
var healthMultiplier = weightHealth / weightTotal;
var mindMultiplier = weightMind / weightTotal;
var moodMultiplier = weightMood / 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
+ MoodContest(performer, target, bypassClampMood, rangeFactorMood) * moodMultiplier
: MassContest(performer, target, bypassClampMass, rangeFactorMass) * massMultiplier
* StaminaContest(performer, target, bypassClampStamina, rangeFactorStamina) * staminaMultiplier
* HealthContest(performer, target, bypassClampHealth, rangeFactorHealth) * healthMultiplier
* MindContest(performer, target, bypassClampMind, rangeFactorMind) * mindMultiplier
* MoodContest(performer, target, bypassClampMood, rangeFactorMood) * moodMultiplier;
}
#endregion
}
}