219 lines
8.7 KiB
C#
219 lines
8.7 KiB
C#
using PkmnLib.Dynamic.Models;
|
|
using PkmnLib.Static;
|
|
using PkmnLib.Static.Species;
|
|
using PkmnLib.Tests.Integration;
|
|
|
|
namespace PkmnLib.Tests.Dynamic;
|
|
|
|
/// <summary>
|
|
/// Tests for the ephemeral <see cref="IBattlePokemon"/> wrapper. Battle-only state must live on the wrapper
|
|
/// and never leak into the underlying <see cref="IPokemon"/>; dropping the wrapper is all the cleanup a
|
|
/// battle needs.
|
|
/// </summary>
|
|
public class BattlePokemonTests
|
|
{
|
|
private static (IBattle battle, IBattlePokemon wrapper, IPokemon inner) CreateBattleWithWrapper(
|
|
string heldItem = "oran_berry")
|
|
{
|
|
var library = LibraryHelpers.LoadLibrary();
|
|
if (!library.StaticLibrary.Species.TryGet("bulbasaur", out var bulbasaur))
|
|
throw new InvalidOperationException("Failed to load bulbasaur species.");
|
|
if (!library.StaticLibrary.Species.TryGet("charmander", out var charmander))
|
|
throw new InvalidOperationException("Failed to load charmander species.");
|
|
if (!library.StaticLibrary.Items.TryGet(heldItem, out var item))
|
|
throw new InvalidOperationException($"Failed to load item {heldItem}.");
|
|
|
|
var pokemon = new PokemonImpl(library, bulbasaur, bulbasaur.GetDefaultForm(), new AbilityIndex
|
|
{
|
|
Index = 0,
|
|
IsHidden = false,
|
|
}, 50, 0, Gender.Male, 0, "hardy");
|
|
pokemon.LearnMove("tackle", MoveLearnMethod.LevelUp, 0);
|
|
_ = pokemon.ForceSetHeldItem(item);
|
|
|
|
var opponent = new PokemonImpl(library, charmander, charmander.GetDefaultForm(), new AbilityIndex
|
|
{
|
|
Index = 0,
|
|
IsHidden = false,
|
|
}, 50, 0, Gender.Male, 0, "hardy");
|
|
|
|
var party1 = new PokemonPartyImpl(6);
|
|
party1.SwapInto(pokemon, 0);
|
|
var party2 = new PokemonPartyImpl(6);
|
|
party2.SwapInto(opponent, 0);
|
|
var parties = new[]
|
|
{
|
|
new BattlePartyImpl(party1, [new ResponsibleIndex(0, 0)]),
|
|
new BattlePartyImpl(party2, [new ResponsibleIndex(1, 0)]),
|
|
};
|
|
var battle = new BattleImpl(library, parties, false, 2, 1, false, "grass", 0);
|
|
var wrapper = parties[0].GetBattlePokemon(pokemon) ??
|
|
throw new InvalidOperationException("Wrapper not created.");
|
|
return (battle, wrapper, pokemon);
|
|
}
|
|
|
|
[Test]
|
|
public async Task PersistentMembersAreProxiedToUnderlyingPokemon()
|
|
{
|
|
var (_, wrapper, inner) = CreateBattleWithWrapper();
|
|
|
|
await Assert.That(wrapper.UnderlyingPokemon).IsSameReferenceAs(inner);
|
|
await Assert.That(wrapper.Species).IsSameReferenceAs(inner.Species);
|
|
await Assert.That(wrapper.Form).IsSameReferenceAs(inner.Form);
|
|
await Assert.That(wrapper.Level).IsEqualTo(inner.Level);
|
|
await Assert.That(wrapper.CurrentHealth).IsEqualTo(inner.CurrentHealth);
|
|
await Assert.That(wrapper.Nature).IsSameReferenceAs(inner.Nature);
|
|
await Assert.That(wrapper.OriginalSpecies).IsSameReferenceAs(inner.Species);
|
|
await Assert.That(wrapper.OriginalForm).IsSameReferenceAs(inner.Form);
|
|
}
|
|
|
|
[Test]
|
|
public async Task TypeOverlayDoesNotTouchUnderlyingPokemon()
|
|
{
|
|
var (_, wrapper, inner) = CreateBattleWithWrapper();
|
|
var originalTypes = inner.Types.ToList();
|
|
|
|
wrapper.SetTypes([new TypeIdentifier(18, "water")]);
|
|
|
|
await Assert.That(wrapper.Types.Count).IsEqualTo(1);
|
|
await Assert.That(inner.Types.SequenceEqual(originalTypes)).IsTrue();
|
|
|
|
wrapper.OnSwitchedOut();
|
|
await Assert.That(wrapper.Types.SequenceEqual(inner.Form.Types)).IsTrue();
|
|
}
|
|
|
|
[Test]
|
|
public async Task TemporaryMoveOverlayDoesNotTouchUnderlyingPokemonAndResetsOnSwitchOut()
|
|
{
|
|
var (_, wrapper, inner) = CreateBattleWithWrapper();
|
|
|
|
wrapper.LearnTemporaryMove("swords_dance", MoveLearnMethod.Mimic, 0);
|
|
|
|
await Assert.That(wrapper.Moves[0]!.MoveData.Name.ToString()).IsEqualTo("swords_dance");
|
|
await Assert.That(wrapper.BaseMoves[0]!.MoveData.Name.ToString()).IsEqualTo("tackle");
|
|
await Assert.That(inner.Moves[0]!.MoveData.Name.ToString()).IsEqualTo("tackle");
|
|
|
|
wrapper.OnSwitchedOut();
|
|
await Assert.That(wrapper.Moves[0]!.MoveData.Name.ToString()).IsEqualTo("tackle");
|
|
}
|
|
|
|
[Test]
|
|
public async Task StatBoostLivesOnWrapperAndResetsOnSwitchOut()
|
|
{
|
|
var (_, wrapper, inner) = CreateBattleWithWrapper();
|
|
var innerFlatAttack = inner.FlatStats.Attack;
|
|
|
|
var changed = wrapper.ChangeStatBoost(Statistic.Attack, 2, true, false);
|
|
|
|
await Assert.That(changed).IsTrue();
|
|
await Assert.That(wrapper.StatBoost.Attack).IsEqualTo((sbyte)2);
|
|
await Assert.That(wrapper.BoostedStats.Attack > wrapper.FlatStats.Attack).IsTrue();
|
|
await Assert.That(inner.FlatStats.Attack).IsEqualTo(innerFlatAttack);
|
|
|
|
wrapper.OnSwitchedOut();
|
|
await Assert.That(wrapper.StatBoost.Attack).IsEqualTo((sbyte)0);
|
|
await Assert.That(wrapper.BoostedStats.Attack).IsEqualTo(wrapper.FlatStats.Attack);
|
|
}
|
|
|
|
[Test]
|
|
public async Task HeldItemOverlayDoesNotTouchUnderlyingPokemon()
|
|
{
|
|
var (_, wrapper, inner) = CreateBattleWithWrapper();
|
|
var innerItem = inner.HeldItem;
|
|
await Assert.That(innerItem).IsNotNull();
|
|
|
|
var removed = wrapper.RemoveHeldItemForBattle();
|
|
|
|
await Assert.That(removed).IsSameReferenceAs(innerItem);
|
|
await Assert.That(wrapper.HeldItem).IsNull();
|
|
await Assert.That(wrapper.HasItemBeenRemovedForBattle).IsTrue();
|
|
await Assert.That(inner.HeldItem).IsSameReferenceAs(innerItem);
|
|
|
|
wrapper.RestoreRemovedHeldItem();
|
|
await Assert.That(wrapper.HeldItem).IsSameReferenceAs(innerItem);
|
|
await Assert.That(wrapper.HasItemBeenRemovedForBattle).IsFalse();
|
|
}
|
|
|
|
[Test]
|
|
public async Task StealingHeldItemDoesNotTouchUnderlyingPokemon()
|
|
{
|
|
var (_, wrapper, inner) = CreateBattleWithWrapper();
|
|
var innerItem = inner.HeldItem;
|
|
|
|
var stolen = wrapper.TryStealHeldItem(out var item);
|
|
|
|
await Assert.That(stolen).IsTrue();
|
|
await Assert.That(item).IsSameReferenceAs(innerItem);
|
|
await Assert.That(wrapper.HeldItem).IsNull();
|
|
await Assert.That(inner.HeldItem).IsSameReferenceAs(innerItem);
|
|
}
|
|
|
|
[Test]
|
|
public async Task MarkAsCaughtOnlyAffectsWrapper()
|
|
{
|
|
var (_, wrapper, inner) = CreateBattleWithWrapper();
|
|
|
|
wrapper.MarkAsCaught();
|
|
|
|
await Assert.That(wrapper.IsCaught).IsTrue();
|
|
await Assert.That(wrapper.IsUsable).IsFalse();
|
|
await Assert.That(inner.IsUsable).IsTrue();
|
|
}
|
|
|
|
[Test]
|
|
public async Task AbilityOverrideAndSuppressionLiveOnWrapper()
|
|
{
|
|
var (_, wrapper, inner) = CreateBattleWithWrapper();
|
|
var naturalAbility = inner.Ability;
|
|
await Assert.That(naturalAbility).IsNotNull();
|
|
|
|
wrapper.SuppressAbility();
|
|
await Assert.That(wrapper.AbilitySuppressed).IsTrue();
|
|
await Assert.That(wrapper.ActiveAbility).IsNull();
|
|
await Assert.That(inner.Ability).IsSameReferenceAs(naturalAbility);
|
|
|
|
wrapper.OnSwitchedOut();
|
|
await Assert.That(wrapper.AbilitySuppressed).IsFalse();
|
|
await Assert.That(wrapper.ActiveAbility).IsSameReferenceAs(naturalAbility);
|
|
}
|
|
|
|
[Test]
|
|
public async Task GetOwnScriptsUsesUnderlyingStatusScript()
|
|
{
|
|
var (_, wrapper, inner) = CreateBattleWithWrapper();
|
|
|
|
var scripts = new List<IEnumerable<PkmnLib.Dynamic.ScriptHandling.ScriptContainer>>();
|
|
wrapper.GetOwnScripts(scripts);
|
|
|
|
await Assert.That(scripts.Count).IsEqualTo(4);
|
|
await Assert.That(scripts[0]).IsSameReferenceAs(wrapper.HeldItemTriggerScript);
|
|
await Assert.That(scripts[1]).IsSameReferenceAs(wrapper.AbilityScript);
|
|
await Assert.That(scripts[2]).IsSameReferenceAs(inner.StatusScript);
|
|
await Assert.That(scripts[3]).IsSameReferenceAs(wrapper.Volatile);
|
|
}
|
|
|
|
[Test]
|
|
public async Task GetBattlePokemonFindsWrapperByInnerAndByWrapper()
|
|
{
|
|
var (battle, wrapper, inner) = CreateBattleWithWrapper();
|
|
var party = battle.Parties[0];
|
|
|
|
await Assert.That(party.GetBattlePokemon(inner)).IsSameReferenceAs(wrapper);
|
|
await Assert.That(party.GetBattlePokemon(wrapper)).IsSameReferenceAs(wrapper);
|
|
await Assert.That(battle.Parties[1].GetBattlePokemon(inner)).IsNull();
|
|
}
|
|
|
|
[Test]
|
|
public async Task OnSwitchedInTracksTurnAndPosition()
|
|
{
|
|
var (_, wrapper, _) = CreateBattleWithWrapper();
|
|
await Assert.That(wrapper.IsOnBattlefield).IsFalse();
|
|
|
|
wrapper.OnSwitchedIn(0);
|
|
|
|
await Assert.That(wrapper.IsOnBattlefield).IsTrue();
|
|
await Assert.That(wrapper.Position).IsEqualTo((byte)0);
|
|
// Bulbasaur's ability (Overgrow) has no script in the Gen7 plugin, so the ability script stays empty.
|
|
await Assert.That(wrapper.AbilityScript.IsEmpty).IsTrue();
|
|
}
|
|
} |