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(); 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() != 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( 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(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; } } } }