This commit is contained in:
@@ -60,7 +60,7 @@ public partial class ExplicitAI
|
||||
private IPokemon? ChooseBestReplacementPokemon(byte position, bool terribleMoves,
|
||||
IReadOnlyList<IPokemon> usablePokemon, IBattleSide battleSide)
|
||||
{
|
||||
var options = usablePokemon.Where((pokemon, index) =>
|
||||
var options = usablePokemon.Where((_, index) =>
|
||||
{
|
||||
if (_skillFlags.ReserveLastPokemon && index == usablePokemon.Count - 1 && usablePokemon.Count > 1)
|
||||
return false; // Don't switch to the last Pokemon if there are others available.
|
||||
@@ -132,6 +132,9 @@ public partial class ExplicitAI
|
||||
return score;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the expected entry hazard damage for a given Pokémon on a given battle side.
|
||||
/// </summary>
|
||||
public static uint CalculateEntryHazardDamage(IPokemon pokemon, IBattleSide side)
|
||||
{
|
||||
var damage = 0u;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using PkmnLib.Dynamic.BattleFlow;
|
||||
using PkmnLib.Dynamic.Libraries;
|
||||
using PkmnLib.Dynamic.Models;
|
||||
@@ -9,52 +8,111 @@ using PkmnLib.Static.Utils;
|
||||
|
||||
namespace PkmnLib.Dynamic.AI.Explicit;
|
||||
|
||||
public interface IExplicitAI
|
||||
{
|
||||
public bool TrainerHighSkill { get; }
|
||||
public bool TrainerMediumSkill { get; }
|
||||
public IRandom Random { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An explicit AI that has explicitly written logic for each Pokémon and move.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is heavily based on the AI used in <a href="https://github.com/Maruno17/pokemon-essentials">Pokémon Essentials</a>
|
||||
/// </remarks>
|
||||
public interface IExplicitAI
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether the trainer is of high skill level.
|
||||
/// </summary>
|
||||
bool TrainerHighSkill { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the trainer is of medium skill level.
|
||||
/// </summary>
|
||||
bool TrainerMediumSkill { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The random number generator used by the AI.
|
||||
/// </summary>
|
||||
IRandom Random { get; }
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IExplicitAI"/>
|
||||
public partial class ExplicitAI : PokemonAI, IExplicitAI
|
||||
{
|
||||
/// <summary>
|
||||
/// The score assigned to a move that is predicted to fail.
|
||||
/// </summary>
|
||||
public const int MoveFailScore = 20;
|
||||
|
||||
/// <summary>
|
||||
/// The score assigned to a move that is considered useless.
|
||||
/// </summary>
|
||||
public const int MoveUselessScore = 60;
|
||||
|
||||
/// <summary>
|
||||
/// The base score assigned to a move before modifiers.
|
||||
/// </summary>
|
||||
public const int MoveBaseScore = 100;
|
||||
|
||||
private const float TrainerSkill = 100; // TODO: This should be configurable
|
||||
private SkillFlags _skillFlags = new();
|
||||
private readonly float _trainerSkill = 100;
|
||||
private readonly SkillFlags _skillFlags = new();
|
||||
|
||||
private float MoveScoreThreshold => (float)(0.6f + 0.35f * Math.Sqrt(Math.Min(TrainerSkill, 100) / 100f));
|
||||
private float MoveScoreThreshold => (float)(0.6f + 0.35f * Math.Sqrt(Math.Min(_trainerSkill, 100) / 100f));
|
||||
|
||||
private readonly IReadOnlyExplicitAIHandlers _handlers;
|
||||
|
||||
private readonly IRandom _random = new RandomImpl();
|
||||
|
||||
/// <summary>
|
||||
/// Flags that control the skill of the AI.
|
||||
/// </summary>
|
||||
public class SkillFlags
|
||||
{
|
||||
// TODO: Make these configurable
|
||||
public bool CanPredictMoveFailure { get; set; } = true;
|
||||
public bool ScoreMoves { get; set; } = true;
|
||||
public bool ConsiderSwitching { get; set; } = true;
|
||||
public bool ReserveLastPokemon { get; set; } = true;
|
||||
public bool UsePokemonInOrder { get; set; } = true;
|
||||
/// <summary>
|
||||
/// Whether the AI can predict if a move will fail.
|
||||
/// </summary>
|
||||
public bool CanPredictMoveFailure { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the AI will score moves to determine their usefulness.
|
||||
/// </summary>
|
||||
public bool ScoreMoves { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the AI will consider switching out Pokémon.
|
||||
/// </summary>
|
||||
public bool ConsiderSwitching { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the AI will reserve the last Pokémon in its party (ace).
|
||||
/// </summary>
|
||||
public bool ReserveLastPokemon { get; init; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the AI will use Pokémon in the order they are in the party, or choose freely.
|
||||
/// </summary>
|
||||
public bool UsePokemonInOrder { get; init; } = false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <inheritdoc cref="ExplicitAI"/>
|
||||
/// <param name="library">The library for Pokémon data.</param>
|
||||
public ExplicitAI(IDynamicLibrary library) : base("explicit")
|
||||
{
|
||||
_handlers = library.ExplicitAIHandlers;
|
||||
}
|
||||
|
||||
public bool TrainerHighSkill => TrainerSkill >= 45;
|
||||
public bool TrainerMediumSkill => TrainerSkill >= 32;
|
||||
/// <inheritdoc cref="ExplicitAI(IDynamicLibrary)"/>
|
||||
/// <param name="library">The library for Pokémon data.</param>
|
||||
/// <param name="trainerSkill">The skill level of the trainer (0-100).</param>
|
||||
/// <param name="skillFlags">The skill flags that control the AI's behavior.</param>
|
||||
public ExplicitAI(IDynamicLibrary library, float trainerSkill, SkillFlags skillFlags) : base("explicit")
|
||||
{
|
||||
_handlers = library.ExplicitAIHandlers;
|
||||
_trainerSkill = trainerSkill;
|
||||
_skillFlags = skillFlags;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool TrainerHighSkill => _trainerSkill >= 45;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool TrainerMediumSkill => _trainerSkill >= 32;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IRandom Random => _random;
|
||||
|
||||
Reference in New Issue
Block a user