diff --git a/Plugins/PkmnLib.Plugin.Gen7/AI/AIMoveScoreFunctionAttribute.cs b/Plugins/PkmnLib.Plugin.Gen7/AI/AIMoveScoreFunctionAttribute.cs index ff73d4d..18d9aaa 100644 --- a/Plugins/PkmnLib.Plugin.Gen7/AI/AIMoveScoreFunctionAttribute.cs +++ b/Plugins/PkmnLib.Plugin.Gen7/AI/AIMoveScoreFunctionAttribute.cs @@ -5,4 +5,9 @@ namespace PkmnLib.Plugin.Gen7.AI; [AttributeUsage(AttributeTargets.Method), MeansImplicitUse] public class AIMoveScoreFunctionAttribute : Attribute { +} + +[AttributeUsage(AttributeTargets.Method), MeansImplicitUse] +public class AIMoveFailureFunctionAttribute : Attribute +{ } \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/AI/ExplicitAIFunctions.cs b/Plugins/PkmnLib.Plugin.Gen7/AI/ExplicitAIFunctions.cs index 82c1c5b..bd76dd9 100644 --- a/Plugins/PkmnLib.Plugin.Gen7/AI/ExplicitAIFunctions.cs +++ b/Plugins/PkmnLib.Plugin.Gen7/AI/ExplicitAIFunctions.cs @@ -20,18 +20,37 @@ public static class ExplicitAIFunctions 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 failureMethod = type.GetMethods(BindingFlags.Public | BindingFlags.Static).FirstOrDefault(m => + m.GetCustomAttribute() != null); + if (failureMethod != null) { + if (failureMethod.ReturnType != typeof(bool) || failureMethod.GetParameters().Length != 1 || + failureMethod.GetParameters()[0].ParameterType != typeof(MoveOption)) + { + throw new InvalidOperationException( + $"Method {failureMethod.Name} in {type.Name} must return bool and take a single MoveOption parameter."); + } + var optionParam = Expression.Parameter(typeof(MoveOption), "option"); + var functionExpression = Expression.Lambda( + Expression.Call(null, failureMethod, optionParam), optionParam).Compile(); + handlers.MoveFailureCheck.Add(attribute.Name, functionExpression); + } + + var scoreMethod = type.GetMethods(BindingFlags.Public | BindingFlags.Static).FirstOrDefault(m => + m.GetCustomAttribute() != null); + if (scoreMethod != null) + { + if (scoreMethod.ReturnType != typeof(void) || scoreMethod.GetParameters().Length != 2 || + scoreMethod.GetParameters()[0].ParameterType != typeof(MoveOption) || + scoreMethod.GetParameters()[1].ParameterType != typeof(int).MakeByRefType()) + { + throw new InvalidOperationException( + $"Method {scoreMethod.Name} in {type.Name} must return void and take a MoveOption and an int by reference parameter."); + } 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(); + Expression.Call(null, scoreMethod, optionParam, scoreParam), optionParam, scoreParam).Compile(); handlers.MoveEffectScore.Add(attribute.Name, functionExpression); } } diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ChangeUserStats.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ChangeUserStats.cs index bbcb771..e057822 100644 --- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ChangeUserStats.cs +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ChangeUserStats.cs @@ -35,6 +35,9 @@ public abstract class ChangeUserStats : Script, IScriptOnInitialize, IScriptOnSe move.User.ChangeStatBoost(_stat, _amount, true, false); } + protected static bool WouldMoveFail(MoveOption option, Statistic stat) => + option.Move.User.StatBoost.GetStatistic(stat) == StatBoostStatisticSet.MaxStatBoost; + protected static void GetMoveEffectScore(MoveOption option, Statistic stat, ref int score) { if (option.Move.Move.SecondaryEffect == null || @@ -56,6 +59,9 @@ public class ChangeUserAttack : ChangeUserStats { } + [AIMoveFailureFunction] + public static bool AIMoveWillFail(MoveOption option) => WouldMoveFail(option, Statistic.Attack); + [AIMoveScoreFunction] public static void AIMoveEffectScore(MoveOption option, ref int score) => GetMoveEffectScore(option, Statistic.Attack, ref score); @@ -68,6 +74,9 @@ public class ChangeUserDefense : ChangeUserStats { } + [AIMoveFailureFunction] + public static bool AIMoveWillFail(MoveOption option) => WouldMoveFail(option, Statistic.Defense); + [AIMoveScoreFunction] public static void AIMoveEffectScore(MoveOption option, ref int score) => GetMoveEffectScore(option, Statistic.Defense, ref score); @@ -80,6 +89,9 @@ public class ChangeUserSpecialAttack : ChangeUserStats { } + [AIMoveFailureFunction] + public static bool AIMoveWillFail(MoveOption option) => WouldMoveFail(option, Statistic.SpecialAttack); + [AIMoveScoreFunction] public static void AIMoveEffectScore(MoveOption option, ref int score) => GetMoveEffectScore(option, Statistic.SpecialAttack, ref score); @@ -92,6 +104,9 @@ public class ChangeUserSpecialDefense : ChangeUserStats { } + [AIMoveFailureFunction] + public static bool AIMoveWillFail(MoveOption option) => WouldMoveFail(option, Statistic.SpecialDefense); + [AIMoveScoreFunction] public static void AIMoveEffectScore(MoveOption option, ref int score) => GetMoveEffectScore(option, Statistic.SpecialDefense, ref score); @@ -104,6 +119,9 @@ public class ChangeUserSpeed : ChangeUserStats { } + [AIMoveFailureFunction] + public static bool AIMoveWillFail(MoveOption option) => WouldMoveFail(option, Statistic.Speed); + [AIMoveScoreFunction] public static void AIMoveEffectScore(MoveOption option, ref int score) => GetMoveEffectScore(option, Statistic.Speed, ref score); @@ -116,6 +134,9 @@ public class ChangeUserAccuracy : ChangeUserStats { } + [AIMoveFailureFunction] + public static bool AIMoveWillFail(MoveOption option) => WouldMoveFail(option, Statistic.Accuracy); + [AIMoveScoreFunction] public static void AIMoveEffectScore(MoveOption option, ref int score) => GetMoveEffectScore(option, Statistic.Accuracy, ref score); @@ -128,6 +149,9 @@ public class ChangeUserEvasion : ChangeUserStats { } + [AIMoveFailureFunction] + public static bool AIMoveWillFail(MoveOption option) => WouldMoveFail(option, Statistic.Evasion); + [AIMoveScoreFunction] public static void AIMoveEffectScore(MoveOption option, ref int score) => GetMoveEffectScore(option, Statistic.Evasion, ref score);