70 lines
2.9 KiB
C#
70 lines
2.9 KiB
C#
using System.Linq.Expressions;
|
|
using System.Reflection;
|
|
using PkmnLib.Dynamic.AI.Explicit;
|
|
using PkmnLib.Plugin.Gen7.Scripts.Moves;
|
|
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
|
using PkmnLib.Static.Moves;
|
|
|
|
namespace PkmnLib.Plugin.Gen7.AI;
|
|
|
|
public static class ExplicitAIFunctions
|
|
{
|
|
public static void RegisterAIFunctions(ExplicitAIHandlers handlers)
|
|
{
|
|
var baseType = typeof(Script);
|
|
foreach (var type in typeof(ExplicitAIFunctions).Assembly.GetTypes().Where(t => baseType.IsAssignableFrom(t)))
|
|
{
|
|
var attribute = type.GetCustomAttribute<ScriptAttribute>();
|
|
if (attribute == null)
|
|
continue;
|
|
|
|
if (attribute.Category == ScriptCategory.Move)
|
|
{
|
|
// Check if the move type has a static function in the following format:
|
|
// public static void AIMoveEffectScore(MoveOption option, ref int score);
|
|
var method = type.GetMethods(BindingFlags.Public | BindingFlags.Static).FirstOrDefault(m =>
|
|
m.GetCustomAttribute<AIMoveScoreFunctionAttribute>() != null && m.ReturnType == typeof(void) &&
|
|
m.GetParameters().Length == 2 && m.GetParameters()[0].ParameterType == typeof(MoveOption) &&
|
|
m.GetParameters()[1].ParameterType == typeof(int).MakeByRefType());
|
|
if (method != null)
|
|
{
|
|
var optionParam = Expression.Parameter(typeof(MoveOption), "option");
|
|
var scoreParam = Expression.Parameter(typeof(int).MakeByRefType(), "score");
|
|
var functionExpression = Expression.Lambda<AIScoreMoveHandler>(
|
|
Expression.Call(null, method, optionParam, scoreParam), optionParam, scoreParam).Compile();
|
|
handlers.MoveEffectScore.Add(attribute.Name, functionExpression);
|
|
}
|
|
}
|
|
}
|
|
|
|
handlers.GeneralMoveAgainstTargetScore.Add("predicated_damage", PredictedDamageScore);
|
|
}
|
|
|
|
private static void PredictedDamageScore(MoveOption option, ref int score)
|
|
{
|
|
var target = option.Target;
|
|
if (target == null)
|
|
return;
|
|
if (option.Move.Move.Category == MoveCategory.Status)
|
|
return;
|
|
var damage = option.EstimatedDamage;
|
|
if (target.Volatile.TryGet<SubstituteEffect>(out var substitute))
|
|
{
|
|
var health = substitute.Health;
|
|
score += (int)Math.Min(15.0f * damage / health, 20);
|
|
return;
|
|
}
|
|
|
|
score += (int)Math.Min(15.0f * damage / target.CurrentHealth, 30);
|
|
|
|
if (damage > target.CurrentHealth * 1.1f)
|
|
{
|
|
score += 10;
|
|
if ((option.Move.Move.HasFlag("multi_hit") && target.CurrentHealth == target.MaxHealth &&
|
|
target.ActiveAbility?.Name == "sturdy") || target.HasHeldItem("focus_sash"))
|
|
{
|
|
score += 8;
|
|
}
|
|
}
|
|
}
|
|
} |