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 Flare inflicts damage. The base power of Fusion Flare will double /// if any Pokémon has successfully used Fusion Bolt previously in the same turn, with no intervening moves /// in between, except perhaps for failed moves." /// public class FusionFlareTests { /// /// 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 (FusionFlare script, IExecutingMove move, IPokemon target) CreateTestSetup( IMoveChoice executingChoice, params ITurnChoice[] currentTurnChoices) { var script = new FusionFlare(); 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 Flare will double if any Pokémon has successfully used Fusion /// Bolt previously in the same turn". /// [Test] public async Task ChangeDamageModifier_FusionBoltUsedEarlierInTurn_ModifierDoubles() { // Arrange var flareChoice = CreateMoveChoice("fusion_flare"); var boltChoice = CreateMoveChoice("fusion_bolt"); var (script, move, target) = CreateTestSetup(flareChoice, boltChoice, flareChoice); 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 Bolt previously in /// the same turn" — with no Fusion Bolt used this turn, the modifier stays unchanged. /// [Test] public async Task ChangeDamageModifier_NoFusionBoltInTurn_ModifierUnchanged() { // Arrange var flareChoice = CreateMoveChoice("fusion_flare"); var tackleChoice = CreateMoveChoice("tackle"); var (script, move, target) = CreateTestSetup(flareChoice, tackleChoice, flareChoice); var modifier = 1f; // Act script.ChangeDamageModifier(move, target, 0, ref modifier); // Assert await Assert.That(modifier).IsEqualTo(1f); } /// /// Bulbapedia: Fusion Bolt must have been used "previously in the same turn" — a Fusion Bolt that /// executes after this Fusion Flare does not boost it. /// [Test] public async Task ChangeDamageModifier_FusionBoltLaterInTurn_ModifierUnchanged() { // Arrange var flareChoice = CreateMoveChoice("fusion_flare"); var boltChoice = CreateMoveChoice("fusion_bolt"); var (script, move, target) = CreateTestSetup(flareChoice, flareChoice, boltChoice); 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 Bolt used on the previous turn does /// not double this turn's Fusion Flare. /// [Test] public async Task ChangeDamageModifier_FusionBoltOnPreviousTurn_ModifierUnchanged() { // Arrange var flareChoice = CreateMoveChoice("fusion_flare"); var boltChoice = CreateMoveChoice("fusion_bolt"); var script = new FusionFlare(); var move = Substitute.For(); move.MoveChoice.Returns(flareChoice); var battle = Substitute.For(); battle.PreviousTurnChoices.Returns(new List> { new ITurnChoice[] { boltChoice }, new ITurnChoice[] { flareChoice }, }); 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 Bolt "with no intervening moves in between" — another /// successful move executed between Fusion Bolt and Fusion Flare breaks the combination. /// [Test] public async Task ChangeDamageModifier_SuccessfulMoveBetweenBoltAndFlare_ModifierUnchanged() { // Arrange var flareChoice = CreateMoveChoice("fusion_flare"); var boltChoice = CreateMoveChoice("fusion_bolt"); var tackleChoice = CreateMoveChoice("tackle"); var (script, move, target) = CreateTestSetup(flareChoice, boltChoice, tackleChoice, flareChoice); 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 Bolt and Fusion Flare does not break the combination. /// [Test] public async Task ChangeDamageModifier_FailedMoveBetweenBoltAndFlare_ModifierStillDoubles() { // Arrange var flareChoice = CreateMoveChoice("fusion_flare"); var boltChoice = CreateMoveChoice("fusion_bolt"); var failedTackleChoice = CreateMoveChoice("tackle", true); var (script, move, target) = CreateTestSetup(flareChoice, boltChoice, failedTackleChoice, flareChoice); 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 Bolt" — a Fusion Bolt /// that failed does not double the power. /// [Test] public async Task ChangeDamageModifier_FusionBoltFailed_ModifierUnchanged() { // Arrange var flareChoice = CreateMoveChoice("fusion_flare"); var failedBoltChoice = CreateMoveChoice("fusion_bolt", true); var (script, move, target) = CreateTestSetup(flareChoice, failedBoltChoice, flareChoice); var modifier = 1f; // Act script.ChangeDamageModifier(move, target, 0, ref modifier); // Assert await Assert.That(modifier).IsEqualTo(1f); } /// /// Bulbapedia: only Fusion Bolt boosts Fusion Flare — another Fusion Flare used earlier in the turn /// does not double the power. /// [Test] public async Task ChangeDamageModifier_AnotherFusionFlareUsedEarlier_ModifierUnchanged() { // Arrange var flareChoice = CreateMoveChoice("fusion_flare"); var earlierFlareChoice = CreateMoveChoice("fusion_flare"); var (script, move, target) = CreateTestSetup(flareChoice, earlierFlareChoice, flareChoice); 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 FusionFlare(); 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); } }