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

@@ -40,23 +40,22 @@ public class FollowMeTests
/// <summary>
/// Creates a mocked Pokémon standing on the given side of the given <see cref="Arena"/>.
/// </summary>
private static IPokemon CreatePokemon(Arena arena, byte sideIndex)
private static IBattlePokemon CreatePokemon(Arena arena, byte sideIndex)
{
var pokemon = Substitute.For<IPokemon>();
var pokemon = Substitute.For<IBattlePokemon>();
pokemon.Volatile.Returns(Substitute.For<IScriptSet>());
var battleData = Substitute.For<IPokemonBattleData>();
battleData.SideIndex.Returns(sideIndex);
battleData.BattleSide.Returns(arena.Sides[sideIndex]);
battleData.Battle.Returns(arena.Battle);
pokemon.BattleData.Returns(battleData);
pokemon.SideIndex.Returns(sideIndex);
pokemon.BattleSide.Returns(arena.Sides[sideIndex]);
pokemon.Battle.Returns(arena.Battle);
return pokemon;
}
/// <summary>
/// Creates a mocked move choice made by the given Pokémon, using the named move.
/// </summary>
private static IMoveChoice CreateMoveChoice(IPokemon user, string moveName = "tackle", bool noRedirection = false)
private static IMoveChoice CreateMoveChoice(IBattlePokemon user, string moveName = "tackle",
bool noRedirection = false)
{
var moveData = Substitute.For<IMoveData>();
moveData.Name.Returns(new StringKey(moveName));
@@ -94,7 +93,7 @@ public class FollowMeTests
/// Executes <see cref="FollowMe"/> for the given user and returns the center-of-attention effect it
/// registered, regardless of which script set it chose to register it on.
/// </summary>
private static Script? MakeCenterOfAttention(IPokemon user)
private static Script? MakeCenterOfAttention(IBattlePokemon user)
{
var followMe = new FollowMe();
var move = Substitute.For<IExecutingMove>();
@@ -102,14 +101,14 @@ public class FollowMeTests
followMe.OnSecondaryEffect(move, user, 0);
return RegisteredScript(user.Volatile) ?? RegisteredScript(user.BattleData!.BattleSide.VolatileScripts);
return RegisteredScript(user.Volatile) ?? RegisteredScript(user.BattleSide.VolatileScripts);
}
/// <summary>
/// Drives the registered effect through whichever target-redirection hook it implements, mirroring the two
/// hooks the engine runs while resolving a move's targets.
/// </summary>
private static void Redirect(Script effect, IMoveChoice moveChoice, ref IReadOnlyList<IPokemon?> targets)
private static void Redirect(Script effect, IMoveChoice moveChoice, ref IReadOnlyList<IBattlePokemon?> targets)
{
switch (effect)
{
@@ -146,7 +145,7 @@ public class FollowMeTests
/// The engine resolves a move's targets by running <see cref="IScriptChangeTargets"/> over the attacker's
/// own script scope, and <see cref="IScriptChangeIncomingTargets"/> over each intended target's scope —
/// which covers that target's own scripts and its <see cref="IBattleSide.VolatileScripts"/>. A redirection
/// effect stored on the center of attention's <see cref="IPokemon.Volatile"/> therefore sits in neither
/// effect stored on the center of attention's <see cref="IBattlePokemon.Volatile"/> therefore sits in neither
/// scope when an opponent attacks the center's ally. It must live on the center's side, the way
/// <see cref="PkmnLib.Plugin.Gen7.Scripts.Side.RagePowderEffect"/> does.
/// </summary>
@@ -200,7 +199,7 @@ public class FollowMeTests
var opponent = CreatePokemon(arena, OpposingSide);
var effect = MakeCenterOfAttention(center)!;
var moveChoice = CreateMoveChoice(opponent);
IReadOnlyList<IPokemon?> targets = [ally];
IReadOnlyList<IBattlePokemon?> targets = [ally];
// Act
Redirect(effect, moveChoice, ref targets);
@@ -223,7 +222,7 @@ public class FollowMeTests
var opponent = CreatePokemon(arena, OpposingSide);
var effect = MakeCenterOfAttention(center)!;
var moveChoice = CreateMoveChoice(opponent);
IReadOnlyList<IPokemon?> targets = [center, ally];
IReadOnlyList<IBattlePokemon?> targets = [center, ally];
// Act
Redirect(effect, moveChoice, ref targets);
@@ -248,7 +247,7 @@ public class FollowMeTests
var targetedAlly = CreatePokemon(arena, CenterSide);
var effect = MakeCenterOfAttention(center)!;
var moveChoice = CreateMoveChoice(attackingAlly);
IReadOnlyList<IPokemon?> targets = [targetedAlly];
IReadOnlyList<IBattlePokemon?> targets = [targetedAlly];
// Act
Redirect(effect, moveChoice, ref targets);
@@ -271,7 +270,7 @@ public class FollowMeTests
var opponent = CreatePokemon(arena, OpposingSide);
var effect = MakeCenterOfAttention(center)!;
var moveChoice = CreateMoveChoice(opponent);
IReadOnlyList<IPokemon?> targets = [center];
IReadOnlyList<IBattlePokemon?> targets = [center];
// Act
Redirect(effect, moveChoice, ref targets);
@@ -287,7 +286,7 @@ public class FollowMeTests
/// </summary>
private static IScriptSet CreateHostedSet(Script effect)
{
var owner = Substitute.For<IPokemon>();
var owner = Substitute.For<IBattlePokemon>();
owner.GetScripts().Returns(_ => new ScriptIterator(Array.Empty<IEnumerable<ScriptContainer>>()));
IScriptSet set = new ScriptSet(owner);
set.Add(effect);
@@ -369,7 +368,7 @@ public class FollowMeTests
var opponent = CreatePokemon(arena, OpposingSide);
var effect = MakeCenterOfAttention(center)!;
var moveChoice = CreateMoveChoice(opponent, moveName, true);
IReadOnlyList<IPokemon?> targets = [ally];
IReadOnlyList<IBattlePokemon?> targets = [ally];
// Act
Redirect(effect, moveChoice, ref targets);
@@ -391,7 +390,7 @@ public class FollowMeTests
var opponent = CreatePokemon(arena, OpposingSide);
var effect = MakeCenterOfAttention(center)!;
var moveChoice = CreateMoveChoice(opponent);
IReadOnlyList<IPokemon?> targets = [];
IReadOnlyList<IBattlePokemon?> targets = [];
// Act
Redirect(effect, moveChoice, ref targets);