using NUnit.Framework; using UnityEngine; using YachtDice.Categories; using YachtDice.Modifiers.Core; using YachtDice.Modifiers.Definition; using YachtDice.Modifiers.Effects; using YachtDice.Modifiers.Runtime; using YachtDice.Scoring; namespace YachtDice.Tests { public class ModifierEffectTests { private CategoryDefinition testCategory; [SetUp] public void SetUp() { testCategory = SumAllCategory.CreateForTest("chance", "Шанс"); } [TearDown] public void TearDown() { Object.DestroyImmediate(testCategory); } private ModifierInstance CreateInstance(string id = "test") { var def = ModifierDefinition.CreateForTest(id, null); return new ModifierInstance(def); } private ModifierContext CreateContext(int baseScore, int[] dice) { return new ModifierContext { BaseScore = baseScore, DiceValues = dice, Category = testCategory, }; } // ── AddPerDiceEffect ───────────────────────────────────────── [Test] public void AddPerDiceEffect_CountsMatchingDice() { var effect = AddPerDiceEffect.CreateForTest(10, targetDiceValue: 1); var ctx = CreateContext(5, new[] { 1, 1, 3, 4, 1 }); var inst = CreateInstance(); effect.Apply(ctx, inst).GetAwaiter().GetResult(); Assert.AreEqual(30, ctx.FlatBonus); // 10 * 3 matching dice } [Test] public void AddPerDiceEffect_ZeroTarget_CountsAllDice() { var effect = AddPerDiceEffect.CreateForTest(2, targetDiceValue: 0); var ctx = CreateContext(10, new[] { 1, 2, 3, 4, 5 }); var inst = CreateInstance(); effect.Apply(ctx, inst).GetAwaiter().GetResult(); Assert.AreEqual(10, ctx.FlatBonus); // 2 * 5 dice } [Test] public void AddPerDiceEffect_NoMatches_ZeroBonus() { var effect = AddPerDiceEffect.CreateForTest(10, targetDiceValue: 6); var ctx = CreateContext(5, new[] { 1, 2, 3, 4, 5 }); var inst = CreateInstance(); effect.Apply(ctx, inst).GetAwaiter().GetResult(); Assert.AreEqual(0, ctx.FlatBonus); } [Test] public void AddPerDiceEffect_ScalesWithStacks() { var effect = AddPerDiceEffect.CreateForTest(10, targetDiceValue: 1); var ctx = CreateContext(5, new[] { 1, 1, 3, 4, 1 }); var inst = CreateInstance(); inst.Stacks = 2; effect.Apply(ctx, inst).GetAwaiter().GetResult(); Assert.AreEqual(60, ctx.FlatBonus); // 10 * 3 * 2 stacks } // ── AddFlatScoreEffect ────────────────────────────────────── [Test] public void AddFlatScoreEffect_AddsFlat() { var effect = AddFlatScoreEffect.CreateForTest(15); var ctx = CreateContext(25, new[] { 3, 3, 2, 2, 2 }); var inst = CreateInstance(); effect.Apply(ctx, inst).GetAwaiter().GetResult(); Assert.AreEqual(15, ctx.FlatBonus); } [Test] public void AddFlatScoreEffect_ScalesWithStacks() { var effect = AddFlatScoreEffect.CreateForTest(15); var ctx = CreateContext(25, new[] { 3, 3, 2, 2, 2 }); var inst = CreateInstance(); inst.Stacks = 3; effect.Apply(ctx, inst).GetAwaiter().GetResult(); Assert.AreEqual(45, ctx.FlatBonus); // 15 * 3 stacks } // ── MultiplyPerDiceEffect ──────────────────────────────────── [Test] public void MultiplyPerDiceEffect_MultipliesPerMatch() { var effect = MultiplyPerDiceEffect.CreateForTest(2f, targetDiceValue: 6); var ctx = CreateContext(18, new[] { 6, 6, 6, 1, 2 }); var inst = CreateInstance(); effect.Apply(ctx, inst).GetAwaiter().GetResult(); Assert.AreEqual(8f, ctx.Multiplier, 0.001f); // 1 * 2 * 2 * 2 = 8 } [Test] public void MultiplyPerDiceEffect_NoMatches_MultiplierUnchanged() { var effect = MultiplyPerDiceEffect.CreateForTest(3f, targetDiceValue: 6); var ctx = CreateContext(10, new[] { 1, 2, 3, 4, 5 }); var inst = CreateInstance(); effect.Apply(ctx, inst).GetAwaiter().GetResult(); Assert.AreEqual(1f, ctx.Multiplier); } // ── MultiplyScoreEffect ───────────────────────────────────── [Test] public void MultiplyScoreEffect_MultipliesOnce() { var effect = MultiplyScoreEffect.CreateForTest(1.5f); var ctx = CreateContext(50, new[] { 6, 6, 6, 6, 6 }); var inst = CreateInstance(); effect.Apply(ctx, inst).GetAwaiter().GetResult(); Assert.AreEqual(1.5f, ctx.Multiplier, 0.001f); } [Test] public void MultiplyScoreEffect_ScalesWithStacks() { var effect = MultiplyScoreEffect.CreateForTest(2f); var ctx = CreateContext(10, new[] { 1, 2, 3, 4, 5 }); var inst = CreateInstance(); inst.Stacks = 3; effect.Apply(ctx, inst).GetAwaiter().GetResult(); // Pow(2, 3) = 8 Assert.AreEqual(8f, ctx.Multiplier, 0.001f); } // ── PostMultiplyEffect ────────────────────────────────────── [Test] public void PostMultiplyEffect_MultipliesPostMultiplier() { var effect = PostMultiplyEffect.CreateForTest(2f); var ctx = CreateContext(10, new[] { 1, 2, 3, 4, 5 }); var inst = CreateInstance(); effect.Apply(ctx, inst).GetAwaiter().GetResult(); Assert.AreEqual(2f, ctx.PostMultiplier, 0.001f); } // ── AddCurrencyEffect ─────────────────────────────────────── [Test] public void AddCurrencyEffect_AddsToCurrencyDelta() { var effect = AddCurrencyEffect.CreateForTest(25); var ctx = CreateContext(10, new[] { 1, 2, 3, 4, 5 }); var inst = CreateInstance(); effect.Apply(ctx, inst).GetAwaiter().GetResult(); Assert.AreEqual(25, ctx.CurrencyDelta); } [Test] public void AddCurrencyEffect_ScalesWithStacks() { var effect = AddCurrencyEffect.CreateForTest(25); var ctx = CreateContext(10, new[] { 1, 2, 3, 4, 5 }); var inst = CreateInstance(); inst.Stacks = 2; effect.Apply(ctx, inst).GetAwaiter().GetResult(); Assert.AreEqual(50, ctx.CurrencyDelta); // 25 * 2 stacks } // ── ConsumeChargeEffect ───────────────────────────────────── [Test] public void ConsumeChargeEffect_DecrementsRemainingUses() { var effect = ConsumeChargeEffect.CreateForTest(1); var ctx = CreateContext(10, new[] { 1, 2, 3, 4, 5 }); var def = ModifierDefinition.CreateForTest("limited", null, hasLimitedUses: true, maxUses: 3); var inst = new ModifierInstance(def); effect.Apply(ctx, inst).GetAwaiter().GetResult(); Assert.AreEqual(2, inst.RemainingUses); } [Test] public void ConsumeChargeEffect_IgnoresPermanent() { var effect = ConsumeChargeEffect.CreateForTest(1); var ctx = CreateContext(10, new[] { 1, 2, 3, 4, 5 }); var inst = CreateInstance(); // permanent (no limited uses) effect.Apply(ctx, inst).GetAwaiter().GetResult(); Assert.AreEqual(-1, inst.RemainingUses); // unchanged } // ── FinalScore Integration ────────────────────────────────── [Test] public void FinalScore_CombinesBaseAndFlatAndMultiplier() { var ctx = CreateContext(10, new[] { 1, 2, 3, 4, 5 }); ctx.FlatBonus = 5; ctx.Multiplier = 2f; ctx.PostMultiplier = 1.5f; // FinalScore = floor((10 + 5) * 2 * 1.5) = floor(45) = 45 Assert.AreEqual(45, ctx.FinalScore); } } }