using PkmnLib.Dynamic.Models; using PkmnLib.Dynamic.Models.Choices; using PkmnLib.Static.Moves; using PkmnLib.Static.Utils; namespace PkmnLib.Dynamic.AI; /// /// The base class for implementing an AI for Pokémon. /// public abstract class PokemonAI { /// /// The name of the AI. /// public StringKey Name { get; set; } /// protected PokemonAI(StringKey name) { Name = name; } /// /// Gets the choice for the Pokémon. /// public abstract ITurnChoice GetChoice(IBattle battle, IPokemon pokemon); public IEnumerable<(byte side, byte position)> GetValidTargetsForMove(IPokemon user, ILearnedMove move) { byte GetOppositeSide(byte side) => side == 0 ? (byte)1 : (byte)0; var userBattleData = user.BattleData!; switch (move.MoveData.Target) { case MoveTarget.Adjacent: yield return (GetOppositeSide(userBattleData.SideIndex), userBattleData.Position); break; case MoveTarget.AdjacentAlly: if (userBattleData.Position > 0) yield return (userBattleData.SideIndex, (byte)(userBattleData.Position - 1)); if (userBattleData.Battle.PositionsPerSide > userBattleData.Position + 1) yield return (userBattleData.SideIndex, (byte)(userBattleData.Position + 1)); break; case MoveTarget.AdjacentAllySelf: if (userBattleData.Position > 0) yield return (userBattleData.SideIndex, (byte)(userBattleData.Position - 1)); if (userBattleData.Battle.PositionsPerSide > userBattleData.Position + 1) yield return (userBattleData.SideIndex, (byte)(userBattleData.Position + 1)); yield return (userBattleData.SideIndex, userBattleData.Position); break; case MoveTarget.AdjacentOpponent: yield return (GetOppositeSide(userBattleData.SideIndex), userBattleData.Position); if (userBattleData.Position > 0) yield return (GetOppositeSide(userBattleData.SideIndex), (byte)(userBattleData.Position - 1)); if (userBattleData.Battle.PositionsPerSide > userBattleData.Position + 1) yield return (GetOppositeSide(userBattleData.SideIndex), (byte)(userBattleData.Position + 1)); break; case MoveTarget.All: yield return (userBattleData.SideIndex, userBattleData.Position); break; case MoveTarget.AllAdjacent: yield return (userBattleData.SideIndex, userBattleData.Position); break; case MoveTarget.AllAdjacentOpponent: yield return (GetOppositeSide(userBattleData.SideIndex), userBattleData.Position); break; case MoveTarget.AllAlly: yield return (userBattleData.SideIndex, userBattleData.Position); break; case MoveTarget.AllOpponent: yield return (GetOppositeSide(userBattleData.SideIndex), userBattleData.Position); break; case MoveTarget.Any: foreach (var side in userBattleData.Battle.Sides) { foreach (var pokemon in side.Pokemon) { if (pokemon?.BattleData == null) continue; yield return (side.Index, pokemon.BattleData!.Position); } } break; case MoveTarget.RandomOpponent: yield return (GetOppositeSide(userBattleData.SideIndex), userBattleData.Position); break; case MoveTarget.SelfUse: yield return (userBattleData.SideIndex, userBattleData.Position); break; default: throw new ArgumentOutOfRangeException(); } } }