using PkmnLib.Dynamic.Models; using PkmnLib.Dynamic.ScriptHandling; using PkmnLib.Dynamic.ScriptHandling.Registry; using PkmnLib.Plugin.Gen7.Scripts.Moves; using PkmnLib.Plugin.Gen7.Scripts.Pokemon; using PkmnLib.Static.Moves; using PkmnLib.Static.Utils; namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves; /// /// Tests for the move script and its volatile. /// Gen VII Bulbapedia behavior: "Every time Fury Cutter hits the power will double", and (Generation VI /// onwards) "Fury Cutter's base power increased even further from 20 to 40, meaning that it takes three /// consecutive turns to reach the maximum power of 160." /// public class FuryCutterTests { /// /// Creates a fully mocked test setup where the user's volatile scripts are a real /// , so the added by the move can be inspected. /// private static (FuryCutter script, IExecutingMove move, IBattlePokemon target, IBattlePokemon user, ScriptSet userVolatile) CreateTestSetup() { var script = new FuryCutter(); var move = Substitute.For(); var target = Substitute.For(); var user = Substitute.For(); var userVolatile = new ScriptSet(user); user.Volatile.Returns(userVolatile); user.GetScripts().Returns(_ => new ScriptIterator(Array.Empty>())); move.User.Returns(user); return (script, move, target, user, userVolatile); } /// /// Simulates the given number of consecutive uses of Fury Cutter, feeding the Gen VII base power of 40 /// into each use, and returns the base power of the final use. /// private static ushort SimulateConsecutiveUses(FuryCutter script, IExecutingMove move, IBattlePokemon target, int uses) { ushort basePower = 40; for (var i = 0; i < uses; i++) { basePower = 40; script.ChangeBasePower(move, target, 0, ref basePower); } return basePower; } /// /// Bulbapedia (Generation VI onwards): "Fury Cutter's base power increased even further from 20 to 40" — /// on the first use there is no previous hit, so the base power is not modified. /// [Test] public async Task ChangeBasePower_FirstUse_BasePowerUnchanged() { // Arrange var (script, move, target, _, _) = CreateTestSetup(); // Act var basePower = SimulateConsecutiveUses(script, move, target, 1); // Assert await Assert.That(basePower).IsEqualTo((ushort)40); } /// /// Bulbapedia: the power doubles on consecutive hits — the first use attaches the /// volatile to the user so the next use is recognized as consecutive. /// [Test] public async Task ChangeBasePower_FirstUse_AddsFuryCutterEffectToUser() { // Arrange var (script, move, target, _, userVolatile) = CreateTestSetup(); // Act SimulateConsecutiveUses(script, move, target, 1); // Assert await Assert.That(userVolatile.Contains(ScriptUtils.ResolveName())).IsTrue(); } /// /// Bulbapedia: "Every time Fury Cutter hits the power will double" — the second consecutive use has /// power 80 and the third consecutive use reaches the maximum of 160. /// [Test, Arguments(2, (ushort)80), Arguments(3, (ushort)160)] public async Task ChangeBasePower_ConsecutiveUses_PowerDoublesEachTurn(int uses, ushort expectedPower) { // Arrange var (script, move, target, _, _) = CreateTestSetup(); // Act var basePower = SimulateConsecutiveUses(script, move, target, uses); // Assert await Assert.That(basePower).IsEqualTo(expectedPower); } /// /// Bulbapedia (Generation VI onwards): "it takes three consecutive turns to reach the maximum power of /// 160" — uses beyond the third consecutive turn stay capped at 160 and do not keep doubling. /// [Test, Arguments(4), Arguments(5), Arguments(6)] public async Task ChangeBasePower_BeyondThirdConsecutiveUse_PowerCappedAt160(int uses) { // Arrange var (script, move, target, _, _) = CreateTestSetup(); // Act var basePower = SimulateConsecutiveUses(script, move, target, uses); // Assert await Assert.That(basePower).IsEqualTo((ushort)160); } /// /// Bulbapedia (Generation V onwards): "If another move is selected, its power resets to normal." — when /// the user executes a different move, the removes itself, resetting the /// doubling progression. /// [Test] public async Task OnBeforeMove_DifferentMoveUsed_EffectRemovesItself() { // Arrange var user = Substitute.For(); user.GetScripts().Returns(_ => new ScriptIterator(Array.Empty>())); var userVolatile = new ScriptSet(user); var effect = new FuryCutterEffect(); userVolatile.Add(effect); var otherMove = Substitute.For(); var otherMoveData = Substitute.For(); otherMoveData.Name.Returns(new StringKey("tackle")); otherMove.UseMove.Returns(otherMoveData); // Act effect.OnBeforeMove(otherMove); // Assert await Assert.That(userVolatile.Contains(ScriptUtils.ResolveName())).IsFalse(); } /// /// Bulbapedia: the doubling continues on "consecutive turns" — when Fury Cutter is used again, the /// stays on the user so the progression continues. /// [Test] public async Task OnBeforeMove_FuryCutterUsedAgain_EffectPersists() { // Arrange var user = Substitute.For(); user.GetScripts().Returns(_ => new ScriptIterator(Array.Empty>())); var userVolatile = new ScriptSet(user); var effect = new FuryCutterEffect(); userVolatile.Add(effect); var furyCutterMove = Substitute.For(); var furyCutterMoveData = Substitute.For(); furyCutterMoveData.Name.Returns(new StringKey("fury_cutter")); furyCutterMove.UseMove.Returns(furyCutterMoveData); // Act effect.OnBeforeMove(furyCutterMove); // Assert await Assert.That(userVolatile.Contains(ScriptUtils.ResolveName())).IsTrue(); } }