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

@@ -16,27 +16,18 @@ public class FocusPunchTests
/// <summary>
/// Creates a fully mocked test setup for the turn start (charging) phase of Focus Punch.
/// </summary>
private static (FocusPunch focusPunch, ITurnChoice choice, IPokemon user, IScriptSet volatileSet, EventHook
eventHook) CreateChargeSetup(bool hasBattleData = true)
private static (FocusPunch focusPunch, ITurnChoice choice, IBattlePokemon user, IScriptSet volatileSet, EventHook
eventHook) CreateChargeSetup()
{
var focusPunch = new FocusPunch();
var user = Substitute.For<IPokemon>();
var user = Substitute.For<IBattlePokemon>();
var volatileSet = Substitute.For<IScriptSet>();
user.Volatile.Returns(volatileSet);
var eventHook = new EventHook();
if (hasBattleData)
{
var battle = Substitute.For<IBattle>();
battle.EventHook.Returns(eventHook);
var battleData = Substitute.For<IPokemonBattleData>();
battleData.Battle.Returns(battle);
user.BattleData.Returns(battleData);
}
else
{
user.BattleData.Returns((IPokemonBattleData?)null);
}
var battle = Substitute.For<IBattle>();
battle.EventHook.Returns(eventHook);
user.Battle.Returns(battle);
var choice = Substitute.For<ITurnChoice>();
choice.User.Returns(user);
@@ -50,7 +41,7 @@ public class FocusPunchTests
{
var focusPunch = new FocusPunch();
var move = Substitute.For<IExecutingMove>();
var user = Substitute.For<IPokemon>();
var user = Substitute.For<IBattlePokemon>();
var volatileSet = Substitute.For<IScriptSet>();
user.Volatile.Returns(volatileSet);
move.User.Returns(user);
@@ -64,8 +55,8 @@ public class FocusPunchTests
private static FocusPunchEffect CreateHitEffect()
{
var effect = new FocusPunchEffect();
var hitReceiver = Substitute.For<IPokemon>();
hitReceiver.BattleData.Returns((IPokemonBattleData?)null);
var hitReceiver = Substitute.For<IBattlePokemon>();
hitReceiver.Battle.EventHook.Returns(new EventHook());
effect.OnIncomingHit(Substitute.For<IExecutingMove>(), hitReceiver, 0);
return effect;
}
@@ -118,26 +109,6 @@ public class FocusPunchTests
await Assert.That(ReferenceEquals(capturedEvent.Parameters["pokemon"], user)).IsTrue();
}
/// <summary>
/// Bulbapedia: "The user of Focus Punch will start focusing at the beginning of the turn the move is used".
/// Technical test: if the user has no <see cref="IPokemon.BattleData"/>, no dialog can be shown, but the
/// charging effect is still applied without throwing.
/// </summary>
[Test]
public async Task OnBeforeTurnStart_UserWithoutBattleData_StillAddsFocusPunchEffect()
{
// Arrange
var (focusPunch, choice, _, volatileSet, _) = CreateChargeSetup(false);
// Act
focusPunch.OnBeforeTurnStart(choice);
// Assert
var addCall = volatileSet.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "Add");
await Assert.That(addCall).IsNotNull();
await Assert.That(addCall!.GetArguments()[0] is FocusPunchEffect).IsTrue();
}
/// <summary>
/// Bulbapedia: "then execute the move Focus Punch at a decreased priority, unless it was hit by another
/// Pokémon's damaging move before executing Focus Punch".
@@ -217,8 +188,7 @@ public class FocusPunchTests
var effect = new FocusPunchEffect();
var move = Substitute.For<IExecutingMove>();
move.UseMove.Returns(fissure!);
var target = Substitute.For<IPokemon>();
target.BattleData.Returns((IPokemonBattleData?)null);
var target = Substitute.For<IBattlePokemon>();
// Act
effect.OnIncomingHit(move, target, 0);