Implement basic AI check for whether a move would fail

This commit is contained in:
2025-07-11 17:13:11 +02:00
parent a3a4993407
commit 364d4b9080
3 changed files with 56 additions and 8 deletions

View File

@@ -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
{
}

View File

@@ -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<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 failureMethod = type.GetMethods(BindingFlags.Public | BindingFlags.Static).FirstOrDefault(m =>
m.GetCustomAttribute<AIMoveFailureFunctionAttribute>() != 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<AIBoolHandler>(
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<AIMoveScoreFunctionAttribute>() != 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<AIScoreMoveHandler>(
Expression.Call(null, method, optionParam, scoreParam), optionParam, scoreParam).Compile();
Expression.Call(null, scoreMethod, optionParam, scoreParam), optionParam, scoreParam).Compile();
handlers.MoveEffectScore.Add(attribute.Name, functionExpression);
}
}