using PkmnLib.Dynamic.Models; using PkmnLib.Dynamic.Models.Choices; using PkmnLib.Plugin.Gen7.Scripts.Moves; using PkmnLib.Static.Moves; using PkmnLib.Static.Utils; namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves; /// /// Tests for the move script. /// Gen VII Bulbapedia behavior: "Fusion Bolt inflicts damage. The base power of Fusion Bolt will double if /// any Pokémon has successfully used Fusion Flare previously in the same turn, with no intervening moves in /// between, except perhaps for failed moves." /// public class FusionBoltTests { /// /// Creates a concrete whose chosen move has the given name. Concrete choices /// are required because the script filters the turn's choices by the type. /// private static MoveChoice CreateMoveChoice(string moveName, bool failed = false) { var moveData = Substitute.For(); moveData.Name.Returns(new StringKey(moveName)); moveData.SecondaryEffect.Returns((ISecondaryEffect?)null); var learnedMove = Substitute.For(); learnedMove.MoveData.Returns(moveData); var user = Substitute.For(); var choice = new MoveChoice(user, learnedMove, 0, 0); if (failed) choice.Fail(); return choice; } /// /// Creates a fully mocked test setup where the current turn consists of the given choices, executed in /// order, and the script is evaluating the given executing choice. /// private static (FusionBolt script, IExecutingMove move, IPokemon target) CreateTestSetup( IMoveChoice executingChoice, params ITurnChoice[] currentTurnChoices) { var script = new FusionBolt(); var move = Substitute.For(); move.MoveChoice.Returns(executingChoice); var battle = Substitute.For(); battle.PreviousTurnChoices.Returns(new List> { currentTurnChoices }); var battleData = Substitute.For(); battleData.Battle.Returns(battle); var target = Substitute.For(); target.BattleData.Returns(battleData); return (script, move, target); } /// /// Bulbapedia: "The base power of Fusion Bolt will double if any Pokémon has successfully used Fusion /// Flare previously in the same turn". /// [Test] public async Task ChangeDamageModifier_FusionFlareUsedEarlierInTurn_ModifierDoubles() { // Arrange var boltChoice = CreateMoveChoice("fusion_bolt"); var flareChoice = CreateMoveChoice("fusion_flare"); var (script, move, target) = CreateTestSetup(boltChoice, flareChoice, boltChoice); var modifier = 1f; // Act script.ChangeDamageModifier(move, target, 0, ref modifier); // Assert await Assert.That(modifier).IsEqualTo(2f); } /// /// Bulbapedia: the power only doubles "if any Pokémon has successfully used Fusion Flare previously in /// the same turn" — with no Fusion Flare used this turn, the modifier stays unchanged. /// [Test] public async Task ChangeDamageModifier_NoFusionFlareInTurn_ModifierUnchanged() { // Arrange var boltChoice = CreateMoveChoice("fusion_bolt"); var tackleChoice = CreateMoveChoice("tackle"); var (script, move, target) = CreateTestSetup(boltChoice, tackleChoice, boltChoice); var modifier = 1f; // Act script.ChangeDamageModifier(move, target, 0, ref modifier); // Assert await Assert.That(modifier).IsEqualTo(1f); } /// /// Bulbapedia: Fusion Flare must have been used "previously in the same turn" — a Fusion Flare that /// executes after this Fusion Bolt does not boost it. /// [Test] public async Task ChangeDamageModifier_FusionFlareLaterInTurn_ModifierUnchanged() { // Arrange var boltChoice = CreateMoveChoice("fusion_bolt"); var flareChoice = CreateMoveChoice("fusion_flare"); var (script, move, target) = CreateTestSetup(boltChoice, boltChoice, flareChoice); var modifier = 1f; // Act script.ChangeDamageModifier(move, target, 0, ref modifier); // Assert await Assert.That(modifier).IsEqualTo(1f); } /// /// Bulbapedia: the boost only applies "in the same turn" — a Fusion Flare used on the previous turn does /// not double this turn's Fusion Bolt. /// [Test] public async Task ChangeDamageModifier_FusionFlareOnPreviousTurn_ModifierUnchanged() { // Arrange var boltChoice = CreateMoveChoice("fusion_bolt"); var flareChoice = CreateMoveChoice("fusion_flare"); var script = new FusionBolt(); var move = Substitute.For(); move.MoveChoice.Returns(boltChoice); var battle = Substitute.For(); battle.PreviousTurnChoices.Returns(new List> { new ITurnChoice[] { flareChoice }, new ITurnChoice[] { boltChoice }, }); var battleData = Substitute.For(); battleData.Battle.Returns(battle); var target = Substitute.For(); target.BattleData.Returns(battleData); var modifier = 1f; // Act script.ChangeDamageModifier(move, target, 0, ref modifier); // Assert await Assert.That(modifier).IsEqualTo(1f); } /// /// Bulbapedia: the boost requires Fusion Flare "with no intervening moves in between" — another /// successful move executed between Fusion Flare and Fusion Bolt breaks the combination. /// [Test] public async Task ChangeDamageModifier_SuccessfulMoveBetweenFlareAndBolt_ModifierUnchanged() { // Arrange var boltChoice = CreateMoveChoice("fusion_bolt"); var flareChoice = CreateMoveChoice("fusion_flare"); var tackleChoice = CreateMoveChoice("tackle"); var (script, move, target) = CreateTestSetup(boltChoice, flareChoice, tackleChoice, boltChoice); var modifier = 1f; // Act script.ChangeDamageModifier(move, target, 0, ref modifier); // Assert await Assert.That(modifier).IsEqualTo(1f); } /// /// Bulbapedia: "with no intervening moves in between, except perhaps for failed moves" — a failed move /// between Fusion Flare and Fusion Bolt does not break the combination. /// [Test] public async Task ChangeDamageModifier_FailedMoveBetweenFlareAndBolt_ModifierStillDoubles() { // Arrange var boltChoice = CreateMoveChoice("fusion_bolt"); var flareChoice = CreateMoveChoice("fusion_flare"); var failedTackleChoice = CreateMoveChoice("tackle", true); var (script, move, target) = CreateTestSetup(boltChoice, flareChoice, failedTackleChoice, boltChoice); var modifier = 1f; // Act script.ChangeDamageModifier(move, target, 0, ref modifier); // Assert await Assert.That(modifier).IsEqualTo(2f); } /// /// Bulbapedia: the boost requires that a Pokémon "has successfully used Fusion Flare" — a Fusion Flare /// that failed does not double the power. /// [Test] public async Task ChangeDamageModifier_FusionFlareFailed_ModifierUnchanged() { // Arrange var boltChoice = CreateMoveChoice("fusion_bolt"); var failedFlareChoice = CreateMoveChoice("fusion_flare", true); var (script, move, target) = CreateTestSetup(boltChoice, failedFlareChoice, boltChoice); var modifier = 1f; // Act script.ChangeDamageModifier(move, target, 0, ref modifier); // Assert await Assert.That(modifier).IsEqualTo(1f); } /// /// Bulbapedia: only Fusion Flare boosts Fusion Bolt — another Fusion Bolt used earlier in the turn does /// not double the power. /// [Test] public async Task ChangeDamageModifier_AnotherFusionBoltUsedEarlier_ModifierUnchanged() { // Arrange var boltChoice = CreateMoveChoice("fusion_bolt"); var earlierBoltChoice = CreateMoveChoice("fusion_bolt"); var (script, move, target) = CreateTestSetup(boltChoice, earlierBoltChoice, boltChoice); var modifier = 1f; // Act script.ChangeDamageModifier(move, target, 0, ref modifier); // Assert await Assert.That(modifier).IsEqualTo(1f); } /// /// Technical test: outside of battle (no battle data on the target) the modifier is left unchanged and /// the hook does not throw. /// [Test] public async Task ChangeDamageModifier_TargetHasNoBattleData_ModifierUnchanged() { // Arrange var script = new FusionBolt(); var move = Substitute.For(); var target = Substitute.For(); target.BattleData.Returns((IPokemonBattleData?)null); var modifier = 1f; // Act script.ChangeDamageModifier(move, target, 0, ref modifier); // Assert await Assert.That(modifier).IsEqualTo(1f); } }