157 lines
6.5 KiB
C#
157 lines
6.5 KiB
C#
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 (0–99) 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 <value>!").
|
||
/// </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);
|
||
}
|
||
} |