Files
tiny_tackle_heroes/Assets/_Project/Tests/EditMode/PlayerStatsTests.cs
T

268 lines
9.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using BumpCombat.Core;
using BumpCombat.Combat;
using BumpCombat.Player;
using NUnit.Framework;
using UnityEngine;
namespace BumpCombat.Tests
{
public sealed class PlayerStatsTests
{
private GameObject owner;
private PlayerStats stats;
[SetUp]
public void SetUp()
{
owner = new GameObject("PlayerStats Tests");
stats = owner.AddComponent<PlayerStats>();
}
[TearDown]
public void TearDown()
{
Object.DestroyImmediate(owner);
}
[Test]
public void Evaluate_AppliesFlatThenSummedIncreasedThenEachMore()
{
stats.AddModifier(new StatModifier(
"flat",
CharacterStat.CollisionDamage,
ModifierOperation.Flat,
10f));
stats.AddModifier(new StatModifier(
"increased-a",
CharacterStat.CollisionDamage,
ModifierOperation.Increased,
0.1f));
stats.AddModifier(new StatModifier(
"increased-b",
CharacterStat.CollisionDamage,
ModifierOperation.Increased,
0.2f));
stats.AddModifier(new StatModifier(
"more-a",
CharacterStat.CollisionDamage,
ModifierOperation.More,
0.1f));
stats.AddModifier(new StatModifier(
"more-b",
CharacterStat.CollisionDamage,
ModifierOperation.More,
0.2f));
Assert.That(
stats.Evaluate(CharacterStat.CollisionDamage, 100f),
Is.EqualTo(188.76f).Within(0.001f));
}
[Test]
public void CalculateDamage_CollisionModifierDoesNotAffectSpell()
{
stats.AddModifier(new StatModifier(
"collision-increased",
CharacterStat.CollisionDamage,
ModifierOperation.Increased,
0.5f));
Assert.That(
stats.CalculateDamage(10f, DamageTag.Collision),
Is.EqualTo(15f).Within(0.001f));
Assert.That(
stats.CalculateDamage(10f, DamageTag.Spell),
Is.EqualTo(10f).Within(0.001f));
}
[Test]
public void CalculateDamage_AppliesSharedAttackDamageBeforeCollisionDamage()
{
stats.AddModifier(new StatModifier(
"shared-attack-increased",
CharacterStat.AttackDamage,
ModifierOperation.Increased,
0.1f));
stats.AddModifier(new StatModifier(
"collision-increased",
CharacterStat.CollisionDamage,
ModifierOperation.Increased,
0.5f));
Assert.That(
stats.CalculateDamage(10f, DamageTag.Collision),
Is.EqualTo(16.5f).Within(0.001f));
Assert.That(
stats.CalculateDamage(10f, DamageTag.Spell),
Is.EqualTo(11f).Within(0.001f));
}
[Test]
public void CalculateDamage_PreservesFractionsUntilTheFinalHit()
{
stats.AddModifier(new StatModifier(
"damage-flat",
CharacterStat.CollisionDamage,
ModifierOperation.Flat,
0.8f));
stats.AddModifier(new StatModifier(
"damage-increased",
CharacterStat.CollisionDamage,
ModifierOperation.Increased,
0.25f));
stats.AddModifier(new StatModifier(
"damage-more",
CharacterStat.CollisionDamage,
ModifierOperation.More,
0.2f));
float calculatedDamage = stats.CalculateDamage(10f, DamageTag.Collision);
Assert.That(calculatedDamage, Is.EqualTo(16.2f).Within(0.001f));
Assert.That(
stats.Evaluate(CharacterStat.CollisionDamage, 10f),
Is.EqualTo(calculatedDamage).Within(0.001f),
"Damage stat evaluation and the public damage API must share the same calculation.");
Assert.That(DamageCalculator.FinalizeDamage(calculatedDamage), Is.EqualTo(16f));
Assert.That(
stats.CalculateDamage(10.9f, DamageTag.Spell),
Is.EqualTo(10.9f).Within(0.001f),
"Spell damage has no collision modifiers and keeps its intermediate fraction.");
}
[Test]
public void CalculateIncomingDamage_PreservesFractionsUntilThePlayerHit()
{
stats.AddModifier(new StatModifier(
"incoming-flat",
CharacterStat.IncomingDamage,
ModifierOperation.Flat,
0.8f));
stats.AddModifier(new StatModifier(
"incoming-increased",
CharacterStat.IncomingDamage,
ModifierOperation.Increased,
0.25f));
stats.AddModifier(new StatModifier(
"incoming-more",
CharacterStat.IncomingDamage,
ModifierOperation.More,
0.2f));
float incomingDamage = stats.CalculateIncomingDamage(10f);
Assert.That(incomingDamage, Is.EqualTo(16.2f).Within(0.001f));
Assert.That(
stats.Evaluate(CharacterStat.IncomingDamage, 10f),
Is.EqualTo(incomingDamage).Within(0.001f));
Assert.That(DamageCalculator.FinalizeDamage(incomingDamage), Is.EqualTo(16f));
}
[Test]
public void CalculateDamage_PreservesFractionsAcrossMoreStacks()
{
StatModifier more = new(
"damage-more-stacked",
CharacterStat.CollisionDamage,
ModifierOperation.More,
0.2f,
3);
stats.AddModifier(more);
stats.AddModifier(more);
stats.AddModifier(more);
float calculatedDamage = stats.CalculateDamage(10f, DamageTag.Collision);
Assert.That(calculatedDamage, Is.EqualTo(17.28f).Within(0.001f));
Assert.That(
DamageCalculator.FinalizeDamage(calculatedDamage),
Is.EqualTo(17),
"10 × 1.2 × 1.2 × 1.2 stays fractional until the final hit.");
}
[Test]
public void Evaluate_IncomingDamageMoreModifierReducesReceivedDamage()
{
stats.AddModifier(new StatModifier(
"artifact.pulse.damage-reduction",
CharacterStat.IncomingDamage,
ModifierOperation.More,
-0.35f));
Assert.That(
stats.Evaluate(CharacterStat.IncomingDamage, 20f),
Is.EqualTo(13f).Within(0.001f));
}
[Test]
public void AddModifier_StopsAtMaxStacksAndReportsCurrentStacks()
{
StatModifier modifier = new(
"level-up.move-speed",
CharacterStat.MoveSpeed,
ModifierOperation.Increased,
0.05f,
2);
Assert.That(stats.AddModifier(modifier), Is.True);
Assert.That(stats.AddModifier(modifier), Is.True);
Assert.That(stats.AddModifier(modifier), Is.False);
Assert.That(
stats.GetStackCount("level-up.move-speed", CharacterStat.MoveSpeed),
Is.EqualTo(2));
AppliedStatModifier applied = stats.GetAppliedModifiers()[0];
Assert.That(applied.CurrentStacks, Is.EqualTo(2));
Assert.That(applied.MaxStacks, Is.EqualTo(2));
}
[Test]
public void RemoveModifiersFromSource_RemovesEveryStackFromThatSource()
{
StatModifier modifier = new(
"temporary-buff",
CharacterStat.ArtifactGaugeGain,
ModifierOperation.Increased,
0.1f,
3);
stats.AddModifier(modifier);
stats.AddModifier(modifier);
Assert.That(
stats.RemoveModifiersFromSource("temporary-buff"),
Is.EqualTo(2));
Assert.That(
stats.GetStackCount(
"temporary-buff",
CharacterStat.ArtifactGaugeGain),
Is.Zero);
Assert.That(
stats.Evaluate(CharacterStat.ArtifactGaugeGain, 5f),
Is.EqualTo(5f).Within(0.001f));
}
[Test]
public void BaseProperties_UseConfiguredDefaultsAndModifiers()
{
stats.AddModifier(new StatModifier(
"level-up.max-health",
CharacterStat.MaxHealth,
ModifierOperation.Flat,
10f));
stats.AddModifier(new StatModifier(
"level-up.move-speed",
CharacterStat.MoveSpeed,
ModifierOperation.Increased,
0.05f));
Assert.That(stats.MaxHealth, Is.EqualTo(110f).Within(0.001f));
Assert.That(stats.MoveSpeed, Is.EqualTo(3.15f).Within(0.001f));
}
[Test]
public void CharacterStat_KeepsExistingSerializedValuesAndAppendsAttackDamage()
{
Assert.That((int)CharacterStat.CollisionDamage, Is.EqualTo(0));
Assert.That((int)CharacterStat.IncomingDamage, Is.EqualTo(8));
Assert.That((int)CharacterStat.AttackDamage, Is.EqualTo(9));
}
}
}