77 lines
3.7 KiB
C#
77 lines
3.7 KiB
C#
using System.Linq.Expressions;
|
|
using System.Reflection;
|
|
using PkmnLib.Dynamic.AI.Explicit;
|
|
|
|
namespace PkmnLib.Plugin.Gen7.AI;
|
|
|
|
public static class ExplicitAIFunctionRegistration
|
|
{
|
|
public static void RegisterAIFunctions(ExplicitAIHandlers handlers)
|
|
{
|
|
var baseType = typeof(Script);
|
|
foreach (var type in typeof(ExplicitAIFunctionRegistration).Assembly.GetTypes()
|
|
.Where(t => baseType.IsAssignableFrom(t)))
|
|
{
|
|
var attribute = type.GetCustomAttribute<ScriptAttribute>();
|
|
if (attribute == null)
|
|
continue;
|
|
|
|
if (attribute.Category == ScriptCategory.Move)
|
|
{
|
|
InitializeMoveFailFunction(handlers, type, attribute);
|
|
InitializeMoveScoreFunction(handlers, type, attribute);
|
|
}
|
|
}
|
|
|
|
handlers.GeneralMoveAgainstTargetScore.Add("predicted_damage", AIDamageFunctions.PredictedDamageScore);
|
|
|
|
AISwitchFunctions.RegisterAISwitchFunctions(handlers);
|
|
}
|
|
|
|
#region Reflection based function initialization
|
|
|
|
private static void InitializeMoveFailFunction(ExplicitAIHandlers handlers, Type type, ScriptAttribute attribute)
|
|
{
|
|
var failureMethod = type.GetMethods(BindingFlags.Public | BindingFlags.Static).FirstOrDefault(m =>
|
|
m.GetCustomAttribute<AIMoveFailureFunctionAttribute>() != null);
|
|
if (failureMethod == null)
|
|
return;
|
|
if (failureMethod.ReturnType != typeof(bool) || failureMethod.GetParameters().Length != 2 ||
|
|
failureMethod.GetParameters()[0].ParameterType != typeof(IExplicitAI) ||
|
|
failureMethod.GetParameters()[1].ParameterType != typeof(MoveOption))
|
|
{
|
|
throw new InvalidOperationException(
|
|
$"Method {failureMethod.Name} in {type.Name} must return bool and take an IExplicitAI and a MoveOption as parameters.");
|
|
}
|
|
var aiParam = Expression.Parameter(typeof(IExplicitAI), "ai");
|
|
var optionParam = Expression.Parameter(typeof(MoveOption), "option");
|
|
var functionExpression = Expression.Lambda<AIBoolHandler>(
|
|
Expression.Call(null, failureMethod, aiParam, optionParam), aiParam, optionParam).Compile();
|
|
handlers.MoveFailureCheck.Add(attribute.Name, functionExpression);
|
|
}
|
|
|
|
private static void InitializeMoveScoreFunction(ExplicitAIHandlers handlers, Type type, ScriptAttribute attribute)
|
|
{
|
|
var scoreMethod = type.GetMethods(BindingFlags.Public | BindingFlags.Static).FirstOrDefault(m =>
|
|
m.GetCustomAttribute<AIMoveScoreFunctionAttribute>() != null);
|
|
if (scoreMethod == null)
|
|
return;
|
|
if (scoreMethod.ReturnType != typeof(void) || scoreMethod.GetParameters().Length != 3 ||
|
|
scoreMethod.GetParameters()[0].ParameterType != typeof(IExplicitAI) ||
|
|
scoreMethod.GetParameters()[1].ParameterType != typeof(MoveOption) ||
|
|
scoreMethod.GetParameters()[2].ParameterType != typeof(int).MakeByRefType())
|
|
{
|
|
throw new InvalidOperationException(
|
|
$"Method {scoreMethod.Name} in {type.Name} must return void and take an IExplicitAI, a MoveOption, and a ref int as parameters.");
|
|
}
|
|
var aiParam = Expression.Parameter(typeof(IExplicitAI), "ai");
|
|
var optionParam = Expression.Parameter(typeof(MoveOption), "option");
|
|
var scoreParam = Expression.Parameter(typeof(int).MakeByRefType(), "score");
|
|
var functionExpression = Expression.Lambda<AIScoreMoveHandler>(
|
|
Expression.Call(null, scoreMethod, aiParam, optionParam, scoreParam), aiParam, optionParam, scoreParam)
|
|
.Compile();
|
|
handlers.MoveEffectScore.Add(attribute.Name, functionExpression);
|
|
}
|
|
|
|
#endregion
|
|
} |