Lots more work on implementing battling

This commit is contained in:
2024-08-10 09:44:46 +02:00
parent 554e1cf2cd
commit a049dda240
29 changed files with 1226 additions and 48 deletions

View File

@@ -0,0 +1,31 @@
using System.Reflection;
using PkmnLib.Static.Utils;
namespace PkmnLib.Dynamic.ScriptHandling.Registry;
/// <summary>
/// Extension methods for scripts.
/// </summary>
public static class ScriptUtils
{
private static readonly Dictionary<Type, StringKey> NameCache = 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(Type type)
{
if (NameCache.TryGetValue(type, out var name))
return name;
var scriptAttr = type.GetCustomAttribute<ScriptAttribute>();
if (scriptAttr == null)
throw new InvalidOperationException($"Type {type} does not have a {nameof(ScriptAttribute)}.");
return NameCache[type] = scriptAttr.Name;
}
}

View File

@@ -1,6 +1,7 @@
using PkmnLib.Dynamic.Libraries;
using PkmnLib.Dynamic.Models;
using PkmnLib.Dynamic.Models.Choices;
using PkmnLib.Dynamic.ScriptHandling.Registry;
using PkmnLib.Static;
using PkmnLib.Static.Utils;
@@ -17,10 +18,11 @@ public abstract class Script
private int _suppressCount;
/// <summary>
/// The name of a script is its unique identifier. This should generally be set on load, and be
/// the same as the key that was used to load it.
/// The name of a script is its unique identifier.
/// If not overridden, this will resolve the name from the <see cref="ScriptAttribute"/> of the
/// script.
/// </summary>
public abstract StringKey Name { get; }
public virtual StringKey Name => this.ResolveName();
public bool MarkForDeletion() => _markedForDeletion = true;
public bool IsMarkedForDeletion() => _markedForDeletion;
@@ -69,7 +71,7 @@ public abstract class Script
/// <summary>
/// This function is ran when this script starts being in effect.
/// </summary>
public virtual void OnInitialize(IDynamicLibrary library, IReadOnlyDictionary<StringKey, object> parameters)
public virtual void OnInitialize(IDynamicLibrary library, IReadOnlyDictionary<StringKey, object>? parameters)
{
}
@@ -356,7 +358,7 @@ public abstract class Script
/// so changing this to above or equal to 100 will make it always hit, while setting it to equal
/// or below 0 will make it never hit.
/// </summary>
public virtual void ChangeIncomingEffectChance(IExecutingMove move, IPokemon target, ref float chance)
public virtual void ChangeIncomingEffectChance(IExecutingMove move, IPokemon target, byte hit, ref float chance)
{
}

View File

@@ -1,5 +1,6 @@
using System.Collections;
using System.Diagnostics.CodeAnalysis;
using PkmnLib.Static.Utils;
namespace PkmnLib.Dynamic.ScriptHandling;
@@ -29,7 +30,7 @@ public class ScriptContainer : IEnumerable<ScriptContainer>
/// <summary>
/// The script in this container.
/// </summary>
public Script? Script { get; set; } = null;
public Script? Script { get; private set; }
/// <inheritdoc />
public IEnumerator<ScriptContainer> GetEnumerator()
@@ -42,4 +43,27 @@ public class ScriptContainer : IEnumerable<ScriptContainer>
{
return GetEnumerator();
}
public void Set(Script script)
{
if (Script is not null)
{
Script.OnRemove();
Script.MarkForDeletion();
}
Script = script;
}
/// <summary>
/// Removes the script from this container.
/// </summary>
public void Clear()
{
if (Script is not null)
{
Script.OnRemove();
Script.MarkForDeletion();
}
Script = null;
}
}

View File

@@ -24,4 +24,18 @@ public static class ScriptExecution
hook(script);
}
}
public static void RunScriptHook(this IReadOnlyList<IEnumerable<ScriptContainer>> source, Action<Script> hook)
{
foreach (var container in source.SelectMany(x => x))
{
if (container.IsEmpty)
continue;
var script = container.Script;
if (script.IsSuppressed)
continue;
hook(script);
}
}
}

View File

@@ -0,0 +1,41 @@
using System.Diagnostics.CodeAnalysis;
using PkmnLib.Static;
using PkmnLib.Static.Utils;
namespace PkmnLib.Dynamic.ScriptHandling;
/// <summary>
/// Class responsible for the creation of <see cref="Script"/> instances.
/// </summary>
public class ScriptResolver
{
private Dictionary<(ScriptCategory, StringKey), Func<Script>> _scriptCtors;
/// <inheritdoc cref="ScriptResolver"/>
public ScriptResolver(Dictionary<(ScriptCategory, StringKey), Func<Script>> scriptCtors)
{
_scriptCtors = scriptCtors;
}
/// <summary>
/// Try and create a new script for the given category and key. If the script does not exist, return false.
/// </summary>
public bool TryResolve(ScriptCategory category, StringKey key, [MaybeNullWhen(false)] out Script script)
{
if (!_scriptCtors.TryGetValue((category, key), out var scriptCtor))
{
script = null;
return false;
}
script = scriptCtor();
return true;
}
/// <summary>
/// Try and resolve an item script for the given item. If the item does not have a script, return false.
/// </summary>
public bool TryResolveItemScript(IItem item, [MaybeNullWhen(false)] out Script script)
{
throw new NotImplementedException();
}
}

View File

@@ -115,7 +115,18 @@ public class ScriptSet : IScriptSet
}
/// <inheritdoc />
public void Clear() => _scripts.Clear();
public void Clear()
{
foreach (var script in _scripts)
{
if (!script.IsEmpty)
{
script.Script.OnRemove();
script.Script.MarkForDeletion();
}
}
_scripts.Clear();
}
/// <inheritdoc />
public bool Contains(StringKey scriptKey) => _scripts.Any(s => s.Script?.Name == scriptKey);