using PkmnLib.Dynamic.Models;
using PkmnLib.Static.Utils;
namespace PkmnLib.Dynamic.AI.Explicit;
///
/// An option where a move is used against a target
///
public record struct MoveOption(AIMoveState Move, IBattle Battle, IPokemon? Target, uint EstimatedDamage = 0);
///
/// A function that takes an explicit AI and a move option and returns a boolean value.
///
public delegate bool AIBoolHandler(IExplicitAI ai, MoveOption option);
///
/// A function for returning whether a Pokemon should switch.
///
public delegate bool AISwitchBoolHandler(IExplicitAI ai, IPokemon pokemon, IBattle battle,
IReadOnlyList reserves);
///
/// A function for returning the base power of a move.
///
public delegate void AIMoveBasePowerHandler(IExplicitAI ai, MoveOption option, ref int score);
///
/// A function for returning a score
///
public delegate void AIScoreMoveHandler(IExplicitAI ai, MoveOption option, ref int score);
///
/// Explicit AI Handlers are a library that allow plugins to explicitly indicate AI preferences.
///
public interface IReadOnlyExplicitAIHandlers
{
///
/// A list of checks to determine if a move will fail.
///
IReadOnlyDictionary MoveFailureCheck { get; }
///
/// Checks if a move will fail based on the provided function code and options.
///
bool MoveWillFail(IExplicitAI ai, StringKey functionCode, MoveOption option);
///
/// A list of checks to determine if a move will fail against a target.
///
IReadOnlyDictionary MoveFailureAgainstTargetCheck { get; }
///
/// Checks if a move will fail against a target based on the provided function code and options.
///
bool MoveWillFailAgainstTarget(IExplicitAI ai, StringKey functionCode, MoveOption option);
///
/// A list of handlers to apply scores for move effects.
///
IReadOnlyDictionary MoveEffectScore { get; }
///
/// Applies the score for a move effect based on the provided name and options.
///
void ApplyMoveEffectScore(IExplicitAI ai, StringKey name, MoveOption option, ref int score);
///
/// A list of handlers to apply scores for move effects against a target.
///
IReadOnlyDictionary MoveEffectAgainstTargetScore { get; }
///
/// Applies the score for a move effect against a target based on the provided name and options.
///
void ApplyMoveEffectAgainstTargetScore(IExplicitAI ai, StringKey name, MoveOption option, ref int score);
///
/// A list of handlers to determine the base power of a move.
///
IReadOnlyDictionary MoveBasePower { get; }
///
/// Applies the base power for a move based on the provided name and options.
///
void GetBasePower(IExplicitAI ai, StringKey name, MoveOption option, ref int power);
///
/// A list of handlers to apply scores for general move effectiveness.
///
IReadOnlyDictionary GeneralMoveScore { get; }
///
/// Applies the score for a general move based on the provided option.
///
void ApplyGenerateMoveScoreModifiers(IExplicitAI ai, MoveOption option, ref int score);
///
/// A list of handlers to apply scores for general move effectiveness against a target.
///
IReadOnlyDictionary GeneralMoveAgainstTargetScore { get; }
///
/// Applies the score for a general move against a target based on the provided option.
///
void ApplyGenerateMoveAgainstTargetScoreModifiers(IExplicitAI ai, MoveOption option, ref int score);
///
/// Functions that indicate whether a Pokemon should switch
///
IReadOnlyDictionary ShouldSwitchFunctions { get; }
///
/// Indicates whether a Pokemon should switch into another Pokemon
///
bool ShouldSwitch(IExplicitAI ai, IPokemon pokemon, IBattle battle, IReadOnlyList reserves);
///
/// Functions that indicate whether a Pokemon should NOT switch
///
IReadOnlyDictionary ShouldNotSwitchFunctions { get; }
///
/// Indicates whether a Pokemon should NOT switch into another Pokemon
///
bool ShouldNotSwitch(IExplicitAI ai, IPokemon pokemon, IBattle battle, IReadOnlyList reserves);
///
/// Scores abilities
///
IReadOnlyDictionary AbilityRanking { get; }
}
///
public class ExplicitAIHandlers : IReadOnlyExplicitAIHandlers
{
///
IReadOnlyDictionary IReadOnlyExplicitAIHandlers.MoveFailureCheck => MoveFailureCheck;
///
/// Checks whether a move will fail
///
public FunctionHandlerDictionary MoveFailureCheck { get; } = new();
///
public bool MoveWillFail(IExplicitAI ai, StringKey functionCode, MoveOption option) =>
MoveFailureCheck.TryGetValue(functionCode, out var handler) && handler(ai, option);
///
/// Checks whether a move will fail against a target
///
public FunctionHandlerDictionary MoveFailureAgainstTargetCheck { get; } = new();
///
IReadOnlyDictionary IReadOnlyExplicitAIHandlers.MoveFailureAgainstTargetCheck =>
MoveFailureAgainstTargetCheck;
///
public bool MoveWillFailAgainstTarget(IExplicitAI ai, StringKey functionCode, MoveOption option) =>
MoveFailureAgainstTargetCheck.TryGetValue(functionCode, out var handler) && handler(ai, option);
///
/// Functions to score a move
///
public FunctionHandlerDictionary MoveEffectScore { get; } = [];
///
IReadOnlyDictionary IReadOnlyExplicitAIHandlers.MoveEffectScore =>
MoveEffectScore;
///
/// Functions to score a move against a target
///
public FunctionHandlerDictionary MoveEffectAgainstTargetScore = [];
///
public void ApplyMoveEffectScore(IExplicitAI ai, StringKey name, MoveOption option, ref int score)
{
if (MoveEffectScore.TryGetValue(name, out var handler))
handler(ai, option, ref score);
}
///
IReadOnlyDictionary IReadOnlyExplicitAIHandlers.MoveEffectAgainstTargetScore =>
MoveEffectAgainstTargetScore;
///
/// Functions that indicate a moves base power
///
public FunctionHandlerDictionary MoveBasePower = [];
///
public void ApplyMoveEffectAgainstTargetScore(IExplicitAI ai, StringKey name, MoveOption option, ref int score)
{
if (MoveEffectAgainstTargetScore.TryGetValue(name, out var handler))
handler(ai, option, ref score);
}
///
IReadOnlyDictionary IReadOnlyExplicitAIHandlers.MoveBasePower =>
MoveBasePower;
///
/// Functions that indicate a moves score
///
public FunctionHandlerDictionary GeneralMoveScore = [];
///
public void GetBasePower(IExplicitAI ai, StringKey name, MoveOption option, ref int power)
{
if (MoveBasePower.TryGetValue(name, out var handler))
handler(ai, option, ref power);
}
///
IReadOnlyDictionary IReadOnlyExplicitAIHandlers.GeneralMoveScore =>
GeneralMoveScore;
public FunctionHandlerDictionary GeneralMoveAgainstTargetScore = [];
///
public void ApplyGenerateMoveScoreModifiers(IExplicitAI ai, MoveOption option, ref int score)
{
foreach (var (_, handler) in GeneralMoveScore)
{
handler(ai, option, ref score);
}
}
///
IReadOnlyDictionary IReadOnlyExplicitAIHandlers.GeneralMoveAgainstTargetScore =>
GeneralMoveAgainstTargetScore;
///
public void ApplyGenerateMoveAgainstTargetScoreModifiers(IExplicitAI ai, MoveOption option, ref int score)
{
foreach (var (_, handler) in GeneralMoveAgainstTargetScore)
{
handler(ai, option, ref score);
}
}
public FunctionHandlerDictionary ShouldSwitchFunctions = [];
///
IReadOnlyDictionary IReadOnlyExplicitAIHandlers.ShouldSwitchFunctions =>
ShouldSwitchFunctions;
///
public bool ShouldSwitch(IExplicitAI ai, IPokemon pokemon, IBattle battle, IReadOnlyList reserves)
{
var shouldSwitch = false;
foreach (var (_, handler) in ShouldSwitchFunctions)
{
shouldSwitch |= handler(ai, pokemon, battle, reserves);
}
return shouldSwitch;
}
///
/// Functions that indicate whether we should not switch
///
public FunctionHandlerDictionary ShouldNotSwitchFunctions = [];
///
///
IReadOnlyDictionary IReadOnlyExplicitAIHandlers.ShouldNotSwitchFunctions =>
ShouldNotSwitchFunctions;
///
/// Functions to rank an ability
///
public FunctionHandlerDictionary AbilityRanking = [];
///
public bool ShouldNotSwitch(IExplicitAI ai, IPokemon pokemon, IBattle battle, IReadOnlyList reserves)
{
var shouldNotSwitch = false;
foreach (var (_, handler) in ShouldNotSwitchFunctions)
{
shouldNotSwitch |= handler(ai, pokemon, battle, reserves);
}
return shouldNotSwitch;
}
///
IReadOnlyDictionary IReadOnlyExplicitAIHandlers.AbilityRanking =>
AbilityRanking;
}