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(); 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() != 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( 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() != 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( Expression.Call(null, scoreMethod, aiParam, optionParam, scoreParam), aiParam, optionParam, scoreParam) .Compile(); handlers.MoveEffectScore.Add(attribute.Name, functionExpression); } #endregion }