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

157 lines
6.5 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.Events;
using PkmnLib.Dynamic.Models;
using PkmnLib.Plugin.Gen7.Scripts.Moves;
namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
/// <summary>
/// Tests for the <see cref="Magnitude"/> move script.
/// Gen VII Bulbapedia behavior: "Magnitude's power varies based on a randomly selected 'magnitude' value
/// ranging from 4 to 10, with 4 having the least power and 10 having the greatest."
/// The doubling of damage against a Pokémon in the semi-invulnerable turn of Dig and the halving under
/// Grassy Terrain are handled outside this script and are not tested here.
/// </summary>
public class MagnitudeTests
{
private static (Magnitude script, IExecutingMove move, IBattlePokemon target, IBattlePokemon user, EventHook
eventHook) CreateTestSetup(int randomValue)
{
var script = new Magnitude();
var random = Substitute.For<IBattleRandom>();
random.GetInt(0, 100).Returns(randomValue);
var eventHook = new EventHook();
var battle = Substitute.For<IBattle>();
battle.Random.Returns(random);
battle.EventHook.Returns(eventHook);
var user = Substitute.For<IBattlePokemon>();
var move = Substitute.For<IExecutingMove>();
user.Battle.Returns(battle);
move.User.Returns(user);
var target = Substitute.For<IBattlePokemon>();
return (script, move, target, user, eventHook);
}
/// <summary>
/// Bulbapedia magnitude→power table: 4→10, 5→30, 6→50, 7→70, 8→90, 9→110, 10→150.
/// Each row exercises a boundary of a random-percentage bracket, verifying both edges of every
/// magnitude's probability range (5%, 10%, 20%, 30%, 20%, 10%, 5%).
/// </summary>
[Test, Arguments(0, 10), Arguments(4, 10), Arguments(5, 30), Arguments(14, 30), Arguments(15, 50),
Arguments(34, 50), Arguments(35, 70), Arguments(64, 70), Arguments(65, 90), Arguments(84, 90), Arguments(85, 110),
Arguments(94, 110), Arguments(95, 150), Arguments(99, 150)]
// magnitude 4 bracket start
// magnitude 4 bracket end
// magnitude 5 bracket start
// magnitude 5 bracket end
// magnitude 6 bracket start
// magnitude 6 bracket end
// magnitude 7 bracket start
// magnitude 7 bracket end
// magnitude 8 bracket start
// magnitude 8 bracket end
// magnitude 9 bracket start
// magnitude 9 bracket end
// magnitude 10 bracket start
// magnitude 10 bracket end
public async Task ChangeBasePower_RandomRoll_MapsToExpectedBasePower(int randomValue, int expectedPower)
{
// Arrange
var (script, move, target, _, _) = CreateTestSetup(randomValue);
ushort basePower = 1;
// Act
script.ChangeBasePower(move, target, 0, ref basePower);
// Assert
await Assert.That(basePower).IsEqualTo((ushort)expectedPower);
}
/// <summary>
/// Bulbapedia probability table: magnitude 4 has 5% probability, 5 has 10%, 6 has 20%, 7 has 30%,
/// 8 has 20%, 9 has 10% and 10 has 5%. Rolling every possible random percentage (099) exactly once
/// must produce each power in exactly that proportion.
/// </summary>
[Test]
public async Task ChangeBasePower_AllRandomRolls_MatchBulbapediaProbabilities()
{
// Arrange
var powerCounts = new Dictionary<ushort, int>();
// Act - roll every possible random percentage once
for (var roll = 0; roll < 100; roll++)
{
var (script, move, target, _, _) = CreateTestSetup(roll);
ushort basePower = 1;
script.ChangeBasePower(move, target, 0, ref basePower);
powerCounts[basePower] = powerCounts.GetValueOrDefault(basePower) + 1;
}
// Assert - counts out of 100 equal the Bulbapedia percentages
await Assert.That(powerCounts.GetValueOrDefault((ushort)10)).IsEqualTo(5);
await Assert.That(powerCounts.GetValueOrDefault((ushort)30)).IsEqualTo(10);
await Assert.That(powerCounts.GetValueOrDefault((ushort)50)).IsEqualTo(20);
await Assert.That(powerCounts.GetValueOrDefault((ushort)70)).IsEqualTo(30);
await Assert.That(powerCounts.GetValueOrDefault((ushort)90)).IsEqualTo(20);
await Assert.That(powerCounts.GetValueOrDefault((ushort)110)).IsEqualTo(10);
await Assert.That(powerCounts.GetValueOrDefault((ushort)150)).IsEqualTo(5);
}
/// <summary>
/// Bulbapedia: the power is based on "a randomly selected 'magnitude' value ranging from 4 to 10" —
/// the selected magnitude is announced through a <see cref="DialogEvent"/> so the front-end can show
/// it (in the games: "Magnitude &lt;value&gt;!").
/// </summary>
[Test, Arguments(0, 4), Arguments(5, 5), Arguments(15, 6), Arguments(35, 7), Arguments(65, 8), Arguments(85, 9),
Arguments(95, 10)]
public async Task ChangeBasePower_RandomRoll_FiresDialogEventWithSelectedMagnitude(int randomValue,
int expectedMagnitude)
{
// Arrange
var (script, move, target, _, eventHook) = CreateTestSetup(randomValue);
DialogEvent? capturedEvent = null;
eventHook.Handler += (_, args) =>
{
if (args is DialogEvent dialogEvent)
capturedEvent = dialogEvent;
};
ushort basePower = 1;
// Act
script.ChangeBasePower(move, target, 0, ref basePower);
// Assert
await Assert.That(capturedEvent).IsNotNull();
await Assert.That(capturedEvent!.Message).IsEqualTo("magnitude");
await Assert.That((int)capturedEvent.Parameters!["magnitude"]).IsEqualTo(expectedMagnitude);
}
/// <summary>
/// Bulbapedia: the magnitude announcement concerns the move's user and target — the fired
/// <see cref="DialogEvent"/> carries both so the front-end can format its message.
/// </summary>
[Test]
public async Task ChangeBasePower_RandomRoll_DialogEventContainsUserAndTarget()
{
// Arrange
var (script, move, target, user, eventHook) = CreateTestSetup(50);
DialogEvent? capturedEvent = null;
eventHook.Handler += (_, args) =>
{
if (args is DialogEvent dialogEvent)
capturedEvent = dialogEvent;
};
ushort basePower = 1;
// Act
script.ChangeBasePower(move, target, 0, ref basePower);
// Assert
await Assert.That(capturedEvent).IsNotNull();
await Assert.That((IBattlePokemon)capturedEvent!.Parameters!["user"]).IsEqualTo(user);
await Assert.That((IBattlePokemon)capturedEvent.Parameters!["target"]).IsEqualTo(target);
}
}