Bunch more moves, changes in how additional information for items works.
This commit is contained in:
@@ -11,18 +11,18 @@ internal static class MoveTurnExecutor
|
||||
internal static void ExecuteMoveChoice(IBattle battle, IMoveChoice moveChoice)
|
||||
{
|
||||
var chosenMove = moveChoice.ChosenMove;
|
||||
var moveData = chosenMove.MoveData;
|
||||
var useMove = chosenMove.MoveData;
|
||||
|
||||
var moveDataName = moveData.Name;
|
||||
var moveDataName = useMove.Name;
|
||||
moveChoice.RunScriptHook(x => x.ChangeMove(moveChoice, ref moveDataName));
|
||||
if (moveData.Name != moveDataName)
|
||||
if (useMove.Name != moveDataName)
|
||||
{
|
||||
if (!battle.Library.StaticLibrary.Moves.TryGet(moveDataName, out moveData))
|
||||
if (!battle.Library.StaticLibrary.Moves.TryGet(moveDataName, out useMove))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"The move was changed to '{moveDataName}' by a script, but this move does not exist.");
|
||||
}
|
||||
var secondaryEffect = moveData.SecondaryEffect;
|
||||
var secondaryEffect = useMove.SecondaryEffect;
|
||||
if (secondaryEffect != null)
|
||||
{
|
||||
if (moveChoice.User.Library.ScriptResolver.TryResolve(ScriptCategory.Move, secondaryEffect.Name,
|
||||
@@ -30,10 +30,18 @@ internal static class MoveTurnExecutor
|
||||
{
|
||||
moveChoice.Script.Set(script);
|
||||
}
|
||||
else
|
||||
{
|
||||
moveChoice.Script.Clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
moveChoice.Script.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
var targetType = moveData.Target;
|
||||
var targetType = useMove.Target;
|
||||
var targets =
|
||||
TargetResolver.ResolveTargets(battle, moveChoice.TargetSide, moveChoice.TargetPosition, targetType);
|
||||
moveChoice.RunScriptHook(x => x.ChangeTargets(moveChoice, ref targets));
|
||||
@@ -45,7 +53,7 @@ internal static class MoveTurnExecutor
|
||||
return;
|
||||
}
|
||||
|
||||
var executingMove = new ExecutingMoveImpl(targets, numberOfHits, chosenMove, moveData, moveChoice);
|
||||
var executingMove = new ExecutingMoveImpl(targets, numberOfHits, chosenMove, useMove, moveChoice);
|
||||
|
||||
var prevented = false;
|
||||
executingMove.RunScriptHook(x => x.PreventMove(executingMove, ref prevented));
|
||||
@@ -117,8 +125,14 @@ internal static class MoveTurnExecutor
|
||||
var hitData = (HitData)executingMove.GetDataFromRawIndex(targetHitStat + i);
|
||||
hitData.Type = hitType;
|
||||
|
||||
var effectiveness = battle.Library.StaticLibrary.Types.GetEffectiveness(hitType, target.Types);
|
||||
var types = target.Types.ToList();
|
||||
executingMove.RunScriptHook(x => x.ChangeTypesForMove(executingMove, target, hitIndex, types));
|
||||
target.RunScriptHook(x => x.ChangeTypesForIncomingMove(executingMove, target, hitIndex, types));
|
||||
|
||||
var effectiveness = battle.Library.StaticLibrary.Types.GetEffectiveness(hitType, types);
|
||||
executingMove.RunScriptHook(x => x.ChangeEffectiveness(executingMove, target, hitIndex, ref effectiveness));
|
||||
target.RunScriptHook(x =>
|
||||
x.ChangeIncomingEffectiveness(executingMove, target, hitIndex, ref effectiveness));
|
||||
hitData.Effectiveness = effectiveness;
|
||||
|
||||
var blockCritical = false;
|
||||
|
||||
@@ -235,6 +235,7 @@ public class BattleSideImpl : ScriptSource, IBattleSide
|
||||
var oldPokemon = _pokemon[position];
|
||||
if (oldPokemon is not null)
|
||||
{
|
||||
oldPokemon.RunScriptHook(script => script.OnSwitchOut(oldPokemon, position));
|
||||
oldPokemon.RunScriptHook(script => script.OnRemove());
|
||||
oldPokemon.SetOnBattlefield(false);
|
||||
}
|
||||
|
||||
@@ -183,6 +183,8 @@ public class ExecutingMoveImpl : ScriptSource, IExecutingMove
|
||||
/// <inheritdoc />
|
||||
public ScriptContainer Script => MoveChoice.Script;
|
||||
|
||||
public IScriptSet Volatile => MoveChoice.Volatile;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IHitData GetHitData(IPokemon target, byte hit)
|
||||
{
|
||||
@@ -224,18 +226,19 @@ public class ExecutingMoveImpl : ScriptSource, IExecutingMove
|
||||
public IMoveChoice MoveChoice { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int ScriptCount => 1 + User.ScriptCount;
|
||||
public override int ScriptCount => 2 + User.ScriptCount;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void GetOwnScripts(List<IEnumerable<ScriptContainer>> scripts)
|
||||
{
|
||||
scripts.Add(Volatile);
|
||||
scripts.Add(Script);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void CollectScripts(List<IEnumerable<ScriptContainer>> scripts)
|
||||
{
|
||||
scripts.Add(Script);
|
||||
GetOwnScripts(scripts);
|
||||
User.CollectScripts(scripts);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user