Move all battle state from IPokemon to an ephemeral IBattlePokemon wrapper

This commit is contained in:
2026-08-28 15:20:26 +02:00
parent 942be8eaeb
commit 8a2733a0a9
859 changed files with 4408 additions and 5331 deletions

View File

@@ -20,12 +20,12 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
/// </summary>
public class FlyTests
{
private static (Fly script, IExecutingMove move, IPokemon user, ScriptSet userVolatile, IMoveChoice moveChoice,
EventHook eventHook) CreateTestSetup()
private static (Fly script, IExecutingMove move, IBattlePokemon user, ScriptSet userVolatile, IMoveChoice moveChoice
, EventHook eventHook) CreateTestSetup()
{
var script = new Fly();
var move = Substitute.For<IExecutingMove>();
var user = Substitute.For<IPokemon>();
var user = Substitute.For<IBattlePokemon>();
// Use a real script set so the charge volatile added by Fly can be inspected afterwards.
var userVolatile = new ScriptSet(user);
user.Volatile.Returns(userVolatile);
@@ -38,9 +38,7 @@ public class FlyTests
var eventHook = new EventHook();
var battle = Substitute.For<IBattle>();
battle.EventHook.Returns(eventHook);
var battleData = Substitute.For<IPokemonBattleData>();
battleData.Battle.Returns(battle);
user.BattleData.Returns(battleData);
user.Battle.Returns(battle);
return (script, move, user, userVolatile, moveChoice, eventHook);
}
@@ -146,33 +144,6 @@ public class FlyTests
await Assert.That(prevent).IsFalse();
}
/// <summary>
/// Technical test: a user that is not in a battle (no <see cref="IPokemon.BattleData"/>) still starts
/// the charge turn without throwing; only the dialog event is skipped.
/// </summary>
[Test]
public async Task PreventMove_NoBattleData_StillPreventsMove()
{
// Arrange
var script = new Fly();
var move = Substitute.For<IExecutingMove>();
var user = Substitute.For<IPokemon>();
var userVolatile = new ScriptSet(user);
user.Volatile.Returns(userVolatile);
user.GetScripts().Returns(_ => new ScriptIterator(new List<IEnumerable<ScriptContainer>>()));
user.BattleData.Returns((IPokemonBattleData?)null);
move.User.Returns(user);
move.MoveChoice.Returns(Substitute.For<IMoveChoice>());
var prevent = false;
// Act
script.PreventMove(move, ref prevent);
// Assert
await Assert.That(prevent).IsTrue();
await Assert.That(userVolatile.Contains(ScriptUtils.ResolveName<ChargeFlyEffect>())).IsTrue();
}
/// <summary>
/// Bulbapedia: the attack executes on the second turn, ending the semi-invulnerable state. Once the
/// attack executes, the <see cref="ChargeFlyEffect"/> is removed from the user.
@@ -309,7 +280,7 @@ public class FlyTests
public async Task OnAfterMoveChoice_ChoiceIsNotFlyCharge_RemovesChargeFlyEffect()
{
// Arrange
var user = Substitute.For<IPokemon>();
var user = Substitute.For<IBattlePokemon>();
var userVolatile = new ScriptSet(user);
user.GetScripts().Returns(_ => new ScriptIterator(new List<IEnumerable<ScriptContainer>>()));
var effect = new ChargeFlyEffect(user);
@@ -332,7 +303,7 @@ public class FlyTests
public async Task OnAfterMoveChoice_ChoiceIsFlyCharge_KeepsChargeFlyEffect()
{
// Arrange
var user = Substitute.For<IPokemon>();
var user = Substitute.For<IBattlePokemon>();
var userVolatile = new ScriptSet(user);
user.GetScripts().Returns(_ => new ScriptIterator(new List<IEnumerable<ScriptContainer>>()));
var effect = new ChargeFlyEffect(user);