Files
PkmnLib.NET/Plugins/PkmnLib.Plugin.Gen7.Tests/Scripts/Moves/FusionBoltTests.cs
Deukhoofd d2a82b5fe3
All checks were successful
Build / Build (push) Successful in 3m12s
Many more tests and fixes
2026-08-27 17:11:12 +02:00

253 lines
9.3 KiB
C#

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;
/// <summary>
/// Tests for the <see cref="FusionBolt"/> 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."
/// </summary>
public class FusionBoltTests
{
/// <summary>
/// Creates a concrete <see cref="MoveChoice"/> whose chosen move has the given name. Concrete choices
/// are required because the script filters the turn's choices by the <see cref="MoveChoice"/> type.
/// </summary>
private static MoveChoice CreateMoveChoice(string moveName, bool failed = false)
{
var moveData = Substitute.For<IMoveData>();
moveData.Name.Returns(new StringKey(moveName));
moveData.SecondaryEffect.Returns((ISecondaryEffect?)null);
var learnedMove = Substitute.For<ILearnedMove>();
learnedMove.MoveData.Returns(moveData);
var user = Substitute.For<IPokemon>();
var choice = new MoveChoice(user, learnedMove, 0, 0);
if (failed)
choice.Fail();
return choice;
}
/// <summary>
/// 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.
/// </summary>
private static (FusionBolt script, IExecutingMove move, IPokemon target) CreateTestSetup(
IMoveChoice executingChoice, params ITurnChoice[] currentTurnChoices)
{
var script = new FusionBolt();
var move = Substitute.For<IExecutingMove>();
move.MoveChoice.Returns(executingChoice);
var battle = Substitute.For<IBattle>();
battle.PreviousTurnChoices.Returns(new List<IReadOnlyList<ITurnChoice>> { currentTurnChoices });
var battleData = Substitute.For<IPokemonBattleData>();
battleData.Battle.Returns(battle);
var target = Substitute.For<IPokemon>();
target.BattleData.Returns(battleData);
return (script, move, target);
}
/// <summary>
/// Bulbapedia: "The base power of Fusion Bolt will double if any Pokémon has successfully used Fusion
/// Flare previously in the same turn".
/// </summary>
[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);
}
/// <summary>
/// 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.
/// </summary>
[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);
}
/// <summary>
/// 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.
/// </summary>
[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);
}
/// <summary>
/// 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.
/// </summary>
[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<IExecutingMove>();
move.MoveChoice.Returns(boltChoice);
var battle = Substitute.For<IBattle>();
battle.PreviousTurnChoices.Returns(new List<IReadOnlyList<ITurnChoice>>
{
new ITurnChoice[] { flareChoice },
new ITurnChoice[] { boltChoice },
});
var battleData = Substitute.For<IPokemonBattleData>();
battleData.Battle.Returns(battle);
var target = Substitute.For<IPokemon>();
target.BattleData.Returns(battleData);
var modifier = 1f;
// Act
script.ChangeDamageModifier(move, target, 0, ref modifier);
// Assert
await Assert.That(modifier).IsEqualTo(1f);
}
/// <summary>
/// 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.
/// </summary>
[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);
}
/// <summary>
/// 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.
/// </summary>
[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);
}
/// <summary>
/// Bulbapedia: the boost requires that a Pokémon "has successfully used Fusion Flare" — a Fusion Flare
/// that failed does not double the power.
/// </summary>
[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);
}
/// <summary>
/// Bulbapedia: only Fusion Flare boosts Fusion Bolt — another Fusion Bolt used earlier in the turn does
/// not double the power.
/// </summary>
[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);
}
/// <summary>
/// Technical test: outside of battle (no battle data on the target) the modifier is left unchanged and
/// the hook does not throw.
/// </summary>
[Test]
public async Task ChangeDamageModifier_TargetHasNoBattleData_ModifierUnchanged()
{
// Arrange
var script = new FusionBolt();
var move = Substitute.For<IExecutingMove>();
var target = Substitute.For<IPokemon>();
target.BattleData.Returns((IPokemonBattleData?)null);
var modifier = 1f;
// Act
script.ChangeDamageModifier(move, target, 0, ref modifier);
// Assert
await Assert.That(modifier).IsEqualTo(1f);
}
}