Bunch more moves, changes in how additional information for items works.

This commit is contained in:
2025-04-14 15:29:26 +02:00
parent 2adbb12367
commit 7c2845502d
60 changed files with 4275 additions and 963 deletions

View File

@@ -8,26 +8,46 @@ namespace PkmnLib.Dynamic.ScriptHandling.Registry;
/// </summary>
public static class ScriptUtils
{
private static readonly Dictionary<Type, StringKey> NameCache = new();
private static readonly Dictionary<Type, (ScriptCategory category, StringKey name)> Cache = new();
/// <summary>
/// Resolve name from the <see cref="ScriptAttribute"/> of the given script.
/// </summary>
public static StringKey ResolveName(this Script script) => ResolveName(script.GetType());
/// <summary>
/// Resolve name from the <see cref="ScriptAttribute"/> of the given type.
/// </summary>
public static StringKey ResolveName<T>() where T : Script => ResolveName(typeof(T));
/// <summary>
/// Resolve name from the <see cref="ScriptAttribute"/> of the given type.
/// </summary>
public static StringKey ResolveName(Type type)
public static StringKey ResolveName(Type type) => GetFromCacheOrAdd(type).name;
/// <summary>
/// Resolve category from the <see cref="ScriptAttribute"/> of the given script.
/// </summary>
public static ScriptCategory ResolveCategory(this Script script) => ResolveCategory(script.GetType());
/// <summary>
/// Resolve category from the <see cref="ScriptAttribute"/> of the given script.
/// </summary>
public static ScriptCategory ResolveCategory<T>() where T : Script => ResolveCategory(typeof(T));
/// <summary>
/// Resolve category from the <see cref="ScriptAttribute"/> of the given type.
/// </summary>
public static ScriptCategory ResolveCategory(Type type) => GetFromCacheOrAdd(type).category;
private static (ScriptCategory category, StringKey name) GetFromCacheOrAdd(Type type)
{
if (NameCache.TryGetValue(type, out var name))
return name;
if (Cache.TryGetValue(type, out var key))
return key;
var scriptAttr = type.GetCustomAttribute<ScriptAttribute>();
if (scriptAttr == null)
throw new InvalidOperationException($"Type {type} does not have a {nameof(ScriptAttribute)}.");
return NameCache[type] = scriptAttr.Name;
return Cache[type] = (scriptAttr.Category, scriptAttr.Name);
}
}

View File

@@ -29,6 +29,12 @@ public abstract class Script : IDeepCloneable
/// </summary>
public virtual StringKey Name => this.ResolveName();
/// <summary>
/// The category of a script is used to determine what kind of script it is. This is used to
/// determine what kind of script it is, and what kind of events it can handle.
/// </summary>
public virtual ScriptCategory Category => this.ResolveCategory();
/// <summary>
/// A script can be suppressed by other scripts. If a script is suppressed by at least one script
/// we will not execute its methods. This should return the number of suppressions on the script.
@@ -55,6 +61,10 @@ public abstract class Script : IDeepCloneable
/// </summary>
public void Unsuppress() => _suppressCount--;
public virtual void OnBeforeAnyHookInvoked(ref List<ScriptCategory>? suppressedCategories)
{
}
/// <summary>
/// This function is ran when a volatile effect is added while that volatile effect already is
/// in place. Instead of adding the volatile effect twice, it will execute this function instead.
@@ -206,6 +216,11 @@ public abstract class Script : IDeepCloneable
{
}
public virtual void ChangeIncomingEffectiveness(IExecutingMove executingMove, IPokemon target, byte hitIndex,
ref float effectiveness)
{
}
/// <summary>
/// This function allows a script to block an outgoing move from being critical.
/// </summary>
@@ -473,6 +488,10 @@ public abstract class Script : IDeepCloneable
{
}
public virtual void OnSwitchOut(IPokemon oldPokemon, byte position)
{
}
/// <summary>
/// This function is triggered on a Pokemon and its parents when the given Pokemon is switched into
/// the battlefield.
@@ -567,4 +586,14 @@ public abstract class Script : IDeepCloneable
public virtual void PreventHeal(IPokemon pokemon, uint heal, bool allowRevive, ref bool prevented)
{
}
public virtual void ChangeTypesForMove(IExecutingMove executingMove, IPokemon target, byte hitIndex,
IList<TypeIdentifier> types)
{
}
public virtual void ChangeTypesForIncomingMove(IExecutingMove executingMove, IPokemon target, byte hitIndex,
IList<TypeIdentifier> types)
{
}
}

View File

@@ -16,6 +16,14 @@ public static class ScriptExecution
public static void RunScriptHook(this IScriptSource source, Action<Script> hook)
{
var iterator = source.GetScripts();
List<ScriptCategory>? suppressedCategories = null;
foreach (var container in iterator)
{
if (container.IsEmpty)
continue;
var script = container.Script;
script.OnBeforeAnyHookInvoked(ref suppressedCategories);
}
foreach (var container in iterator)
{
if (container.IsEmpty)
@@ -23,6 +31,8 @@ public static class ScriptExecution
var script = container.Script;
if (script.IsSuppressed)
continue;
if (suppressedCategories != null && suppressedCategories.Contains(script.Category))
continue;
hook(script);
}
}
@@ -33,6 +43,14 @@ public static class ScriptExecution
/// </summary>
public static void RunScriptHook(this IReadOnlyList<IEnumerable<ScriptContainer>> source, Action<Script> hook)
{
List<ScriptCategory>? suppressedCategories = null;
foreach (var container in source.SelectMany(x => x))
{
if (container.IsEmpty)
continue;
var script = container.Script;
script.OnBeforeAnyHookInvoked(ref suppressedCategories);
}
foreach (var container in source.SelectMany(x => x))
{
if (container.IsEmpty)
@@ -40,6 +58,8 @@ public static class ScriptExecution
var script = container.Script;
if (script.IsSuppressed)
continue;
if (suppressedCategories != null && suppressedCategories.Contains(script.Category))
continue;
hook(script);
}
}

View File

@@ -38,6 +38,11 @@ public interface IScriptSet : IEnumerable<ScriptContainer>
/// </summary>
void Remove(StringKey scriptKey);
/// <summary>
/// Removes a script from the set using its type.
/// </summary>
void Remove<T>() where T : Script => Remove(ScriptUtils.ResolveName<T>());
/// <summary>
/// Clears all scripts from the set.
/// </summary>