Files
PkmnLib.NET/Plugins/PkmnLib.Plugin.Gen7.Tests/Scripts/Moves/HiddenPowerTests.cs

147 lines
6.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using PkmnLib.Dynamic.Libraries;
using PkmnLib.Dynamic.Models;
using PkmnLib.Dynamic.ScriptHandling;
using PkmnLib.Plugin.Gen7.Scripts.Moves;
using PkmnLib.Static;
using PkmnLib.Static.Libraries;
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
/// <summary>
/// Tests for the <see cref="HiddenPower"/> move script.
/// Gen VII Bulbapedia behavior: "Hidden Power can be any type, other than Normal and Fairy, based on its user's
/// IVs." and "From Generation VI onward, its power is fixed at 60."
/// </summary>
public class HiddenPowerTests
{
public record TestCaseData(IndividualValueStatisticSet Ivs, StringKey ExpectedType)
{
/// <inheritdoc />
public override string ToString() =>
$"Hidden Power type is {ExpectedType} " +
$"with IVs: HP {Ivs.Hp}, Atk {Ivs.Attack}, Def {Ivs.Defense}, SpA {Ivs.SpecialAttack}, SpD {Ivs.SpecialDefense}, Spe {Ivs.Speed}";
}
/// <summary>
/// Rows of the Bulbapedia type-determination formula: the type index is
/// (a + 2b + 4c + 8d + 16e + 32f) × 15 / 63 rounded down, where af are the least significant bits of the
/// HP, Attack, Defense, Speed, Special Attack, and Special Defense IVs, and index 0 is Fighting through
/// index 15 being Dark.
/// </summary>
public static IEnumerable<Func<TestCaseData>> HiddenPowerTestData()
{
// All-even IVs: formula value 0 -> the lowest possible type, Fighting.
yield return () => new TestCaseData(new IndividualValueStatisticSet(0, 0, 0, 0, 0, 0), "fighting");
// Only the Speed IV is odd: formula value 8 -> 8 * 15 / 63 = 1, Flying.
yield return () => new TestCaseData(new IndividualValueStatisticSet(0, 0, 0, 0, 0, 1), "flying");
// All-odd IVs: formula value 63 -> the highest possible type, Dark.
yield return () => new TestCaseData(new IndividualValueStatisticSet(31, 31, 31, 31, 31, 31), "dark");
yield return () => new TestCaseData(new IndividualValueStatisticSet(25, 2, 12, 5, 8, 17), "bug");
yield return () => new TestCaseData(new IndividualValueStatisticSet(29, 19, 18, 22, 15, 28), "fire");
}
/// <summary>
/// Creates a type library holding all 18 Gen VII types, registered in the National Pokédex type order.
/// </summary>
private static TypeLibrary CreateTypeLibrary()
{
var typeLibrary = new TypeLibrary();
typeLibrary.RegisterType("normal");
typeLibrary.RegisterType("fighting");
typeLibrary.RegisterType("flying");
typeLibrary.RegisterType("poison");
typeLibrary.RegisterType("ground");
typeLibrary.RegisterType("rock");
typeLibrary.RegisterType("bug");
typeLibrary.RegisterType("ghost");
typeLibrary.RegisterType("steel");
typeLibrary.RegisterType("fire");
typeLibrary.RegisterType("water");
typeLibrary.RegisterType("grass");
typeLibrary.RegisterType("electric");
typeLibrary.RegisterType("psychic");
typeLibrary.RegisterType("ice");
typeLibrary.RegisterType("dragon");
typeLibrary.RegisterType("dark");
typeLibrary.RegisterType("fairy");
return typeLibrary;
}
/// <summary>
/// Creates a mocked executing move whose user has the given IVs and a library containing all 18 types.
/// </summary>
private static (IExecutingMove executingMove, IBattlePokemon target) CreateTestSetup(
IndividualValueStatisticSet ivs)
{
var executingMove = Substitute.For<IExecutingMove>();
var user = Substitute.For<IBattlePokemon>();
var target = Substitute.For<IBattlePokemon>();
var dynamicLibrary = Substitute.For<IDynamicLibrary>();
var staticLibrary = Substitute.For<IStaticLibrary>();
executingMove.User.Returns(user);
user.IndividualValues.Returns(ivs);
user.Library.Returns(dynamicLibrary);
staticLibrary.Types.Returns(CreateTypeLibrary());
dynamicLibrary.StaticLibrary.Returns(staticLibrary);
return (executingMove, target);
}
/// <summary>
/// Bulbapedia: "Hidden Power can be any type, other than Normal and Fairy, based on its user's IVs."
/// The type index is (a + 2b + 4c + 8d + 16e + 32f) × 15 / 63 rounded down, where af are the least
/// significant bits of the HP, Attack, Defense, Speed, Special Attack, and Special Defense IVs.
/// </summary>
[Test, MethodDataSource(nameof(HiddenPowerTestData))]
public async Task HiddenPower_ChangesType(TestCaseData test)
{
var (executingMove, target) = CreateTestSetup(test.Ivs);
TypeIdentifier? moveType = new TypeIdentifier(1, "normal");
var hiddenPower = new HiddenPower();
hiddenPower.ChangeMoveType(executingMove, target, 0, ref moveType);
await Assert.That(moveType!.Value.Name).IsEqualTo(test.ExpectedType);
}
/// <summary>
/// Bulbapedia: "Hidden Power can be any type, other than Normal and Fairy, based on its user's IVs."
/// The type only depends on the least significant bit of each of the six IVs, so checking all 64 parity
/// combinations exhaustively proves the move can never be Normal or Fairy.
/// </summary>
[Test]
public async Task ChangeMoveType_AllIvParityCombinations_TypeIsNeverNormalOrFairy()
{
for (byte combination = 0; combination < 64; combination++)
{
// Arrange - each bit of the combination becomes the least significant bit of one IV.
var ivs = new IndividualValueStatisticSet((byte)(combination & 0x01), (byte)((combination >> 1) & 0x01),
(byte)((combination >> 2) & 0x01), (byte)((combination >> 4) & 0x01), (byte)((combination >> 5) & 0x01),
(byte)((combination >> 3) & 0x01));
var (executingMove, target) = CreateTestSetup(ivs);
TypeIdentifier? moveType = new TypeIdentifier(1, "normal");
// Act
var hiddenPower = new HiddenPower();
hiddenPower.ChangeMoveType(executingMove, target, 0, ref moveType);
// Assert
await Assert.That(moveType!.Value.Name).IsNotEqualTo(new StringKey("normal"));
await Assert.That(moveType!.Value.Name).IsNotEqualTo(new StringKey("fairy"));
}
}
/// <summary>
/// Bulbapedia: "From Generation VI onward, its power is fixed at 60." The pre-Gen-VI variable power formula
/// no longer applies, so the script must leave the base power of 60 from the move data untouched, regardless
/// of the user's IVs.
/// </summary>
[Test, MethodDataSource(nameof(HiddenPowerTestData))]
public async Task ChangeBasePower_AnyIvs_PowerRemainsFixedAtSixty(TestCaseData test)
{
var hiddenPower = new HiddenPower();
await Assert.That(hiddenPower).IsNotAssignableTo<IScriptChangeBasePower>();
}
}