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

@@ -24,7 +24,7 @@ public interface IBattleSide : IScriptSource, IDeepCloneable
/// <summary>
/// A list of Pokémon currently on the battlefield.
/// </summary>
IReadOnlyList<IPokemon?> Pokemon { get; }
IReadOnlyList<IBattlePokemon?> Pokemon { get; }
/// <summary>
/// The currently set choices for all Pokémon on the battlefield. Cleared when the turn starts.
@@ -84,7 +84,14 @@ public interface IBattleSide : IScriptSource, IDeepCloneable
/// Switches out a spot on the field for a different Pokémon. If null is passed, the spot is
/// cleared. Returns the Pokémon that was previously in the spot.
/// </summary>
IPokemon? SwapPokemon(byte position, IPokemon? pokemon);
IBattlePokemon? SwapPokemon(byte position, IBattlePokemon? pokemon);
/// <summary>
/// Sends out a Pokémon by its persistent representation. This resolves the battle-scoped wrapper for
/// the Pokémon from the parties in the battle, and swaps it into the given position. This is the
/// convenient entry point for hosts, which generally hold the persistent party Pokémon.
/// </summary>
IBattlePokemon? SendOut(byte position, IPokemon pokemon);
/// <summary>
/// Swaps two Pokémon on the side.
@@ -94,7 +101,7 @@ public interface IBattleSide : IScriptSource, IDeepCloneable
/// <summary>
/// Checks whether a Pokemon is on the field in this side.
/// </summary>
bool IsPokemonOnSide(IPokemon pokemon);
bool IsPokemonOnSide(IBattlePokemon pokemon);
/// <summary>
/// Marks a slot as unfillable. This happens when no parties are able to fill the slot anymore.
@@ -166,7 +173,7 @@ public class BattleSideImpl : ScriptSource, IBattleSide
{
Index = index;
NumberOfPositions = numberOfPositions;
_pokemon = new IPokemon?[numberOfPositions];
_pokemon = new IBattlePokemon?[numberOfPositions];
_setChoices = new ITurnChoice?[numberOfPositions];
_fillablePositions = new bool[numberOfPositions];
for (byte i = 0; i < numberOfPositions; i++)
@@ -183,10 +190,10 @@ public class BattleSideImpl : ScriptSource, IBattleSide
/// <inheritdoc />
public byte NumberOfPositions { get; }
private readonly IPokemon?[] _pokemon;
private readonly IBattlePokemon?[] _pokemon;
/// <inheritdoc />
public IReadOnlyList<IPokemon?> Pokemon => _pokemon;
public IReadOnlyList<IBattlePokemon?> Pokemon => _pokemon;
private readonly ITurnChoice?[] _setChoices;
@@ -249,28 +256,31 @@ public class BattleSideImpl : ScriptSource, IBattleSide
if (pokemon is not null)
{
pokemon.RunScriptHook<IScriptOnRemove>(script => script.OnRemove());
pokemon.SetOnBattlefield(false);
pokemon.OnSwitchedOut();
}
_pokemon[index] = null;
}
/// <inheritdoc />
public IPokemon? SwapPokemon(byte position, IPokemon? pokemon)
public IBattlePokemon? SwapPokemon(byte position, IBattlePokemon? pokemon)
{
var oldPokemon = _pokemon[position];
if (oldPokemon is not null)
{
oldPokemon.RunScriptHook<IScriptOnSwitchOut>(script => script.OnSwitchOut(oldPokemon, position));
oldPokemon.RunScriptHook<IScriptOnRemove>(script => script.OnRemove());
oldPokemon.SetOnBattlefield(false);
oldPokemon.OnSwitchedOut();
}
_pokemon[position] = pokemon;
if (pokemon is not null)
{
pokemon.SetBattleData(Battle, Index);
pokemon.SetOnBattlefield(true);
pokemon.SetBattleSidePosition(position);
if (pokemon.SideIndex != Index)
{
throw new InvalidOperationException(
"A battle Pokémon can only be sent out on the side its party is responsible for.");
}
pokemon.OnSwitchedIn(position);
Battle.EventHook.Invoke(new SwitchEvent(Index, position, pokemon));
pokemon.RunScriptHook<IScriptOnSwitchIn>(script => script.OnSwitchIn(pokemon, position));
@@ -300,6 +310,14 @@ public class BattleSideImpl : ScriptSource, IBattleSide
return oldPokemon;
}
/// <inheritdoc />
public IBattlePokemon? SendOut(byte position, IPokemon pokemon)
{
var wrapper = Battle.Parties.Select(p => p.GetBattlePokemon(pokemon)).FirstOrDefault(x => x != null) ??
throw new InvalidOperationException("The Pokémon does not belong to any party in this battle.");
return SwapPokemon(position, wrapper);
}
/// <inheritdoc />
public void SwapPokemon(byte position1, byte position2)
{
@@ -307,7 +325,7 @@ public class BattleSideImpl : ScriptSource, IBattleSide
}
/// <inheritdoc />
public bool IsPokemonOnSide(IPokemon pokemon) => _pokemon.Contains(pokemon);
public bool IsPokemonOnSide(IBattlePokemon pokemon) => _pokemon.Contains(pokemon);
/// <inheritdoc />
public void MarkPositionAsUnfillable(byte position) => _fillablePositions[position] = false;