Initial set up for item use
This commit is contained in:
parent
85ea31f7cd
commit
0518499a4c
|
@ -0,0 +1,21 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using PkmnLib.Dataloader.Models;
|
||||||
|
using PkmnLib.Static.Moves;
|
||||||
|
using PkmnLib.Static.Utils;
|
||||||
|
|
||||||
|
namespace PkmnLib.Dataloader;
|
||||||
|
|
||||||
|
internal static class CommonDataLoaderHelper
|
||||||
|
{
|
||||||
|
internal static ISecondaryEffect? ParseEffect(this SerializedMoveEffect? effect)
|
||||||
|
{
|
||||||
|
if (effect == null)
|
||||||
|
return null;
|
||||||
|
var name = effect.Name;
|
||||||
|
var chance = effect.Chance;
|
||||||
|
var parameters = effect.Parameters?.ToDictionary(x => (StringKey)x.Key, x => x.Value.ToParameter()) ??
|
||||||
|
new Dictionary<StringKey, object?>();
|
||||||
|
return new SecondaryEffectImpl(chance, name, parameters);
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ using System.Text.Json;
|
||||||
using PkmnLib.Dataloader.Models;
|
using PkmnLib.Dataloader.Models;
|
||||||
using PkmnLib.Static;
|
using PkmnLib.Static;
|
||||||
using PkmnLib.Static.Libraries;
|
using PkmnLib.Static.Libraries;
|
||||||
|
using PkmnLib.Static.Moves;
|
||||||
using PkmnLib.Static.Utils;
|
using PkmnLib.Static.Utils;
|
||||||
|
|
||||||
namespace PkmnLib.Dataloader;
|
namespace PkmnLib.Dataloader;
|
||||||
|
@ -28,19 +29,22 @@ public static class ItemDataLoader
|
||||||
return library;
|
return library;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReSharper disable once MemberCanBePrivate.Global
|
||||||
public static Func<SerializedItem, StringKey, ItemCategory, BattleItemCategory, int,
|
public static Func<SerializedItem, StringKey, ItemCategory, BattleItemCategory, int,
|
||||||
IEnumerable<StringKey>, IItem> ItemConstructor = (_, name, type, battleType, price, flags) =>
|
IEnumerable<StringKey>, ISecondaryEffect?, ISecondaryEffect?,
|
||||||
{
|
// ReSharper disable once FieldCanBeMadeReadOnly.Global
|
||||||
return new ItemImpl(name, type, battleType, price, flags);
|
IItem> ItemConstructor = (_, name, type, battleType, price, flags, effect, battleTriggerEffect) =>
|
||||||
};
|
new ItemImpl(name, type, battleType, price, flags, effect, battleTriggerEffect);
|
||||||
|
|
||||||
private static IItem DeserializeItem(SerializedItem serialized)
|
private static IItem DeserializeItem(SerializedItem serialized)
|
||||||
{
|
{
|
||||||
if (!Enum.TryParse<ItemCategory>(serialized.ItemType, true, out var itemType))
|
if (!Enum.TryParse<ItemCategory>(serialized.ItemType, true, out var itemType))
|
||||||
throw new InvalidDataException($"Item type {serialized.ItemType} is not valid for item {serialized.Name}.");
|
throw new InvalidDataException($"Item type {serialized.ItemType} is not valid for item {serialized.Name}.");
|
||||||
Enum.TryParse(serialized.BattleType, true, out BattleItemCategory battleType);
|
Enum.TryParse(serialized.BattleType, true, out BattleItemCategory battleType);
|
||||||
|
var effect = serialized.Effect?.ParseEffect();
|
||||||
|
var battleTriggerEffect = serialized.BattleEffect?.ParseEffect();
|
||||||
|
|
||||||
return ItemConstructor(serialized, serialized.Name, itemType, battleType, serialized.Price,
|
return ItemConstructor(serialized, serialized.Name, itemType, battleType, serialized.Price,
|
||||||
serialized.Flags.Select(x => (StringKey)x).ToImmutableHashSet());
|
serialized.Flags.Select(x => (StringKey)x).ToImmutableHashSet(), effect, battleTriggerEffect);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -12,6 +12,8 @@ public class SerializedItem
|
||||||
public string[] Flags { get; set; } = null!;
|
public string[] Flags { get; set; } = null!;
|
||||||
public int Price { get; set; }
|
public int Price { get; set; }
|
||||||
public byte FlingPower { get; set; }
|
public byte FlingPower { get; set; }
|
||||||
|
public SerializedMoveEffect? Effect { get; set; }
|
||||||
|
public SerializedMoveEffect? BattleEffect { get; set; }
|
||||||
|
|
||||||
[JsonExtensionData]
|
[JsonExtensionData]
|
||||||
public Dictionary<string, JsonElement>? ExtensionData { get; set; }
|
public Dictionary<string, JsonElement>? ExtensionData { get; set; }
|
||||||
|
|
|
@ -57,21 +57,11 @@ public static class MoveDataLoader
|
||||||
throw new InvalidDataException($"Category {category} is not a valid category.");
|
throw new InvalidDataException($"Category {category} is not a valid category.");
|
||||||
if (!Enum.TryParse<MoveTarget>(target, true, out var targetEnum))
|
if (!Enum.TryParse<MoveTarget>(target, true, out var targetEnum))
|
||||||
throw new InvalidDataException($"Target {target} is not a valid target.");
|
throw new InvalidDataException($"Target {target} is not a valid target.");
|
||||||
var secondaryEffect = ParseEffect(effect);
|
var secondaryEffect = effect.ParseEffect();
|
||||||
|
|
||||||
var move = MoveConstructor(serialized, serialized.Name, typeIdentifier, categoryEnum, power, accuracy, pp, targetEnum,
|
var move = MoveConstructor(serialized, serialized.Name, typeIdentifier, categoryEnum, power, accuracy, pp, targetEnum,
|
||||||
priority, secondaryEffect, flags.Select(x => (StringKey)x).ToImmutableHashSet());
|
priority, secondaryEffect, flags.Select(x => (StringKey)x).ToImmutableHashSet());
|
||||||
return move;
|
return move;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ISecondaryEffect? ParseEffect(SerializedMoveEffect? effect)
|
|
||||||
{
|
|
||||||
if (effect == null)
|
|
||||||
return null;
|
|
||||||
var name = effect.Name;
|
|
||||||
var chance = effect.Chance;
|
|
||||||
var parameters = effect.Parameters?.ToDictionary(x => (StringKey)x.Key, x => x.Value.ToParameter()) ??
|
|
||||||
new Dictionary<StringKey, object?>();
|
|
||||||
return new SecondaryEffectImpl(chance, name, parameters);
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -58,7 +58,7 @@ public class DynamicLibraryImpl : IDynamicLibrary
|
||||||
throw new InvalidOperationException("Stat calculator not found in plugins.");
|
throw new InvalidOperationException("Stat calculator not found in plugins.");
|
||||||
if (registry.MiscLibrary is null)
|
if (registry.MiscLibrary is null)
|
||||||
throw new InvalidOperationException("Misc library not found in plugins.");
|
throw new InvalidOperationException("Misc library not found in plugins.");
|
||||||
var scriptResolver = new ScriptResolver(registry.ScriptTypes);
|
var scriptResolver = new ScriptResolver(registry.ScriptTypes, registry.ItemScriptTypes);
|
||||||
return new DynamicLibraryImpl(staticLibrary, registry.BattleStatCalculator,
|
return new DynamicLibraryImpl(staticLibrary, registry.BattleStatCalculator,
|
||||||
registry.DamageCalculator, registry.MiscLibrary, scriptResolver);
|
registry.DamageCalculator, registry.MiscLibrary, scriptResolver);
|
||||||
}
|
}
|
||||||
|
|
|
@ -314,10 +314,9 @@ public class BattleImpl : ScriptSource, IBattle
|
||||||
{
|
{
|
||||||
if (weatherName.HasValue)
|
if (weatherName.HasValue)
|
||||||
{
|
{
|
||||||
if (!Library.ScriptResolver.TryResolve(ScriptCategory.Weather, weatherName.Value, out var script))
|
if (!Library.ScriptResolver.TryResolve(ScriptCategory.Weather, weatherName.Value, null, out var script))
|
||||||
throw new InvalidOperationException($"Weather script {weatherName} not found.");
|
throw new InvalidOperationException($"Weather script {weatherName} not found.");
|
||||||
_weatherScript.Set(script);
|
_weatherScript.Set(script);
|
||||||
script.OnInitialize(Library, null);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -25,10 +25,10 @@ internal static class MoveTurnExecutor
|
||||||
var secondaryEffect = moveData.SecondaryEffect;
|
var secondaryEffect = moveData.SecondaryEffect;
|
||||||
if (secondaryEffect != null)
|
if (secondaryEffect != null)
|
||||||
{
|
{
|
||||||
if (moveChoice.User.Library.ScriptResolver.TryResolve(ScriptCategory.Move, secondaryEffect.Name, out var script))
|
if (moveChoice.User.Library.ScriptResolver.TryResolve(ScriptCategory.Move, secondaryEffect.Name,
|
||||||
|
secondaryEffect.Parameters, out var script))
|
||||||
{
|
{
|
||||||
moveChoice.Script.Set(script);
|
moveChoice.Script.Set(script);
|
||||||
script.OnInitialize(moveChoice.User.Library, secondaryEffect.Parameters);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,9 @@ public static class TurnRunner
|
||||||
case IFleeChoice fleeChoice:
|
case IFleeChoice fleeChoice:
|
||||||
ExecuteFleeChoice(battle, fleeChoice);
|
ExecuteFleeChoice(battle, fleeChoice);
|
||||||
break;
|
break;
|
||||||
// TODO: Implement item choice types
|
case IItemChoice itemChoice:
|
||||||
|
ExecuteItemChoice(battle, itemChoice);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,4 +157,36 @@ public static class TurnRunner
|
||||||
battle.ValidateBattleState();
|
battle.ValidateBattleState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void ExecuteItemChoice(IBattle battle, IItemChoice itemChoice)
|
||||||
|
{
|
||||||
|
var user = itemChoice.User;
|
||||||
|
var battleData = user.BattleData;
|
||||||
|
if (battleData == null)
|
||||||
|
return;
|
||||||
|
if (!battle.Library.ScriptResolver.TryResolveBattleItemScript(itemChoice.Item, out var itemScript))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!itemScript.IsItemUsable)
|
||||||
|
return;
|
||||||
|
itemScript.OnInitialize(itemChoice.Item.BattleEffect!.Parameters);
|
||||||
|
IPokemon? target = null;
|
||||||
|
if (itemChoice is { TargetSide: not null, TargetPosition: not null })
|
||||||
|
{
|
||||||
|
var side = battle.Sides[itemChoice.TargetSide.Value];
|
||||||
|
target = side.Pokemon[itemChoice.TargetPosition.Value];
|
||||||
|
}
|
||||||
|
|
||||||
|
var requiresTarget = itemScript.RequiresTarget;
|
||||||
|
if (requiresTarget)
|
||||||
|
{
|
||||||
|
target ??= user;
|
||||||
|
itemScript.OnUseWithTarget(target);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
itemScript.OnUse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -8,19 +8,40 @@ namespace PkmnLib.Dynamic.Models.Choices;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IItemChoice : ITurnChoice
|
public interface IItemChoice : ITurnChoice
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The item that is used.
|
||||||
|
/// </summary>
|
||||||
|
public IItem Item { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The side the move is targeted at.
|
||||||
|
/// </summary>
|
||||||
|
byte? TargetSide { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The position the move is targeted at.
|
||||||
|
/// </summary>
|
||||||
|
byte? TargetPosition { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="IItemChoice"/>
|
/// <inheritdoc cref="IItemChoice"/>
|
||||||
public class ItemChoice : TurnChoice, IItemChoice
|
public class ItemChoice : TurnChoice, IItemChoice
|
||||||
{
|
{
|
||||||
public ItemChoice(IPokemon user, IItem item) : base(user)
|
public ItemChoice(IPokemon user, IItem item, byte? targetSide, byte? targetPosition) : base(user)
|
||||||
{
|
{
|
||||||
Item = item;
|
Item = item;
|
||||||
|
TargetSide = targetSide;
|
||||||
|
TargetPosition = targetPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IItem Item { get; }
|
public IItem Item { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte? TargetSide { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte? TargetPosition { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override int ScriptCount => User.ScriptCount;
|
public override int ScriptCount => User.ScriptCount;
|
||||||
|
|
||||||
|
|
|
@ -46,10 +46,10 @@ public class MoveChoice : TurnChoice, IMoveChoice
|
||||||
var secondaryEffect = usedMove.MoveData.SecondaryEffect;
|
var secondaryEffect = usedMove.MoveData.SecondaryEffect;
|
||||||
if (secondaryEffect != null)
|
if (secondaryEffect != null)
|
||||||
{
|
{
|
||||||
if (user.Library.ScriptResolver.TryResolve(ScriptCategory.Move, secondaryEffect.Name, out var script))
|
if (user.Library.ScriptResolver.TryResolve(ScriptCategory.Move, secondaryEffect.Name,
|
||||||
|
secondaryEffect.Parameters, out var script))
|
||||||
{
|
{
|
||||||
Script.Set(script);
|
Script.Set(script);
|
||||||
script.OnInitialize(user.Library, secondaryEffect.Parameters);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -465,7 +465,7 @@ public class PokemonImpl : ScriptSource, IPokemon
|
||||||
|
|
||||||
if (serializedPokemon.Status != null)
|
if (serializedPokemon.Status != null)
|
||||||
{
|
{
|
||||||
if (!library.ScriptResolver.TryResolve(ScriptCategory.Status, serializedPokemon.Status,
|
if (!library.ScriptResolver.TryResolve(ScriptCategory.Status, serializedPokemon.Status, null,
|
||||||
out var statusScript))
|
out var statusScript))
|
||||||
throw new KeyNotFoundException($"Status script {serializedPokemon.Status} not found");
|
throw new KeyNotFoundException($"Status script {serializedPokemon.Status} not found");
|
||||||
StatusScript.Set(statusScript);
|
StatusScript.Set(statusScript);
|
||||||
|
@ -668,7 +668,7 @@ public class PokemonImpl : ScriptSource, IPokemon
|
||||||
{
|
{
|
||||||
if (HeldItem is null)
|
if (HeldItem is null)
|
||||||
return false;
|
return false;
|
||||||
if (!Library.ScriptResolver.TryResolveItemScript(HeldItem, out _))
|
if (!Library.ScriptResolver.TryResolveBattleItemScript(HeldItem, out _))
|
||||||
return false;
|
return false;
|
||||||
// TODO: actually consume the item
|
// TODO: actually consume the item
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
@ -777,10 +777,10 @@ public class PokemonImpl : ScriptSource, IPokemon
|
||||||
AbilityScript.Clear();
|
AbilityScript.Clear();
|
||||||
if (!Library.StaticLibrary.Abilities.TryGet(newAbility, out var ability))
|
if (!Library.StaticLibrary.Abilities.TryGet(newAbility, out var ability))
|
||||||
throw new KeyNotFoundException($"Ability {newAbility} not found.");
|
throw new KeyNotFoundException($"Ability {newAbility} not found.");
|
||||||
if (Library.ScriptResolver.TryResolve(ScriptCategory.Ability, newAbility, out var abilityScript))
|
if (Library.ScriptResolver.TryResolve(ScriptCategory.Ability, newAbility, ability.Parameters,
|
||||||
|
out var abilityScript))
|
||||||
{
|
{
|
||||||
AbilityScript.Set(abilityScript);
|
AbilityScript.Set(abilityScript);
|
||||||
abilityScript.OnInitialize(Library, ability.Parameters);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
using PkmnLib.Dynamic.Models;
|
||||||
|
using PkmnLib.Static.Utils;
|
||||||
|
|
||||||
|
namespace PkmnLib.Dynamic.ScriptHandling;
|
||||||
|
|
||||||
|
public abstract class ItemScript : IDeepCloneable
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the script with the given parameters for a specific item
|
||||||
|
/// </summary>
|
||||||
|
public virtual void OnInitialize(IReadOnlyDictionary<StringKey, object?>? parameters)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns whether the item is usable in the current context.
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool IsItemUsable => false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns whether the item requires a target to be used.
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool RequiresTarget => false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns whether the item is usable on the given target.
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool IsTargetValid(IPokemon target) => false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns whether the item can be held by a Pokémon.
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool IsHoldable => false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns whether the item can be held by the given target.
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool CanTargetHold(IPokemon pokemon) => false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles the use of the item.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void OnUse()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles the use of the item on the given target.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target"></param>
|
||||||
|
public virtual void OnUseWithTarget(IPokemon target)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using PkmnLib.Static.Utils;
|
||||||
|
|
||||||
|
namespace PkmnLib.Dynamic.ScriptHandling.Registry;
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Class)]
|
||||||
|
[MeansImplicitUse]
|
||||||
|
public class ItemScriptAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The name of the script.
|
||||||
|
/// </summary>
|
||||||
|
public StringKey Name { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ItemScriptAttribute"/>
|
||||||
|
public ItemScriptAttribute(string name)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,6 +13,7 @@ namespace PkmnLib.Dynamic.ScriptHandling.Registry;
|
||||||
public class ScriptRegistry
|
public class ScriptRegistry
|
||||||
{
|
{
|
||||||
private readonly Dictionary<(ScriptCategory category, StringKey name), Func<Script>> _scriptTypes = new();
|
private readonly Dictionary<(ScriptCategory category, StringKey name), Func<Script>> _scriptTypes = new();
|
||||||
|
private readonly Dictionary<StringKey, Func<ItemScript>> _itemScriptTypes = new();
|
||||||
private IBattleStatCalculator? _battleStatCalculator;
|
private IBattleStatCalculator? _battleStatCalculator;
|
||||||
private IDamageCalculator? _damageCalculator;
|
private IDamageCalculator? _damageCalculator;
|
||||||
private IMiscLibrary? _miscLibrary;
|
private IMiscLibrary? _miscLibrary;
|
||||||
|
@ -32,6 +33,15 @@ public class ScriptRegistry
|
||||||
|
|
||||||
RegisterScriptType(attribute.Category, attribute.Name, type);
|
RegisterScriptType(attribute.Category, attribute.Name, type);
|
||||||
}
|
}
|
||||||
|
var itemBaseType = typeof(ItemScript);
|
||||||
|
foreach (var type in assembly.GetTypes().Where(t => itemBaseType.IsAssignableFrom(t)))
|
||||||
|
{
|
||||||
|
var attribute = type.GetCustomAttribute<ItemScriptAttribute>();
|
||||||
|
if (attribute == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
RegisterItemScriptType(attribute.Name, type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -53,6 +63,25 @@ public class ScriptRegistry
|
||||||
_scriptTypes[(category, name)] = Expression.Lambda<Func<Script>>(Expression.New(constructor)).Compile();
|
_scriptTypes[(category, name)] = Expression.Lambda<Func<Script>>(Expression.New(constructor)).Compile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Register an item script type with the given name.
|
||||||
|
/// </summary>
|
||||||
|
[PublicAPI]
|
||||||
|
public void RegisterItemScriptType(StringKey name, Type type)
|
||||||
|
{
|
||||||
|
if (type == null)
|
||||||
|
throw new ArgumentNullException(nameof(type));
|
||||||
|
|
||||||
|
var constructor = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
|
||||||
|
null, Type.EmptyTypes, null);
|
||||||
|
if (constructor == null)
|
||||||
|
throw new ArgumentException($"Type {type} does not have a parameterless constructor.");
|
||||||
|
|
||||||
|
// We create a lambda that creates a new instance of the script type.
|
||||||
|
// This is more performant than using Activator.CreateInstance.
|
||||||
|
_itemScriptTypes[name] = Expression.Lambda<Func<ItemScript>>(Expression.New(constructor)).Compile();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Register a battle stat calculator.
|
/// Register a battle stat calculator.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -71,7 +100,8 @@ public class ScriptRegistry
|
||||||
public void RegisterMiscLibrary<T>(T miscLibrary) where T : IMiscLibrary
|
public void RegisterMiscLibrary<T>(T miscLibrary) where T : IMiscLibrary
|
||||||
=> _miscLibrary = miscLibrary;
|
=> _miscLibrary = miscLibrary;
|
||||||
|
|
||||||
internal Dictionary<(ScriptCategory category, StringKey name), Func<Script>> ScriptTypes => _scriptTypes;
|
internal IReadOnlyDictionary<(ScriptCategory category, StringKey name), Func<Script>> ScriptTypes => _scriptTypes;
|
||||||
|
internal IReadOnlyDictionary<StringKey, Func<ItemScript>> ItemScriptTypes => _itemScriptTypes;
|
||||||
internal IBattleStatCalculator? BattleStatCalculator => _battleStatCalculator;
|
internal IBattleStatCalculator? BattleStatCalculator => _battleStatCalculator;
|
||||||
internal IDamageCalculator? DamageCalculator => _damageCalculator;
|
internal IDamageCalculator? DamageCalculator => _damageCalculator;
|
||||||
internal IMiscLibrary? MiscLibrary => _miscLibrary;
|
internal IMiscLibrary? MiscLibrary => _miscLibrary;
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using PkmnLib.Dynamic.Libraries;
|
|
||||||
using PkmnLib.Dynamic.Models;
|
using PkmnLib.Dynamic.Models;
|
||||||
using PkmnLib.Dynamic.Models.Choices;
|
using PkmnLib.Dynamic.Models.Choices;
|
||||||
using PkmnLib.Dynamic.ScriptHandling.Registry;
|
using PkmnLib.Dynamic.ScriptHandling.Registry;
|
||||||
|
@ -74,7 +73,7 @@ public abstract class Script : IDeepCloneable
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This function is ran when this script starts being in effect.
|
/// This function is ran when this script starts being in effect.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual void OnInitialize(IDynamicLibrary library, IReadOnlyDictionary<StringKey, object?>? parameters)
|
public virtual void OnInitialize(IReadOnlyDictionary<StringKey, object?>? parameters)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,33 +9,57 @@ namespace PkmnLib.Dynamic.ScriptHandling;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ScriptResolver
|
public class ScriptResolver
|
||||||
{
|
{
|
||||||
private Dictionary<(ScriptCategory, StringKey), Func<Script>> _scriptCtors;
|
private IReadOnlyDictionary<(ScriptCategory, StringKey), Func<Script>> _scriptCtors;
|
||||||
|
private IReadOnlyDictionary<StringKey, Func<ItemScript>> _itemScriptCtors;
|
||||||
|
|
||||||
/// <inheritdoc cref="ScriptResolver"/>
|
/// <inheritdoc cref="ScriptResolver"/>
|
||||||
public ScriptResolver(Dictionary<(ScriptCategory, StringKey), Func<Script>> scriptCtors)
|
public ScriptResolver(IReadOnlyDictionary<(ScriptCategory, StringKey), Func<Script>> scriptCtors,
|
||||||
|
IReadOnlyDictionary<StringKey, Func<ItemScript>> itemScriptCtors)
|
||||||
{
|
{
|
||||||
_scriptCtors = scriptCtors;
|
_scriptCtors = scriptCtors;
|
||||||
|
_itemScriptCtors = itemScriptCtors;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Try and create a new script for the given category and key. If the script does not exist, return false.
|
/// Try and create a new script for the given category and key. If the script does not exist, return false.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool TryResolve(ScriptCategory category, StringKey key, [MaybeNullWhen(false)] out Script script)
|
public bool TryResolve(ScriptCategory category, StringKey key, IReadOnlyDictionary<StringKey, object?>? parameters,
|
||||||
|
[MaybeNullWhen(false)] out Script script)
|
||||||
{
|
{
|
||||||
if (!_scriptCtors.TryGetValue((category, key), out var scriptCtor))
|
if (!_scriptCtors.TryGetValue((category, key), out var scriptCtor))
|
||||||
{
|
{
|
||||||
script = null;
|
script = null;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
script = scriptCtor();
|
script = scriptCtor();
|
||||||
|
if (parameters != null)
|
||||||
|
{
|
||||||
|
script.OnInitialize(parameters);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Try and resolve an item script for the given item. If the item does not have a script, return false.
|
/// Try and resolve an item script for the given item. If the item does not have a script, return false.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool TryResolveItemScript(IItem item, [MaybeNullWhen(false)] out Script script)
|
public bool TryResolveBattleItemScript(IItem item, [MaybeNullWhen(false)] out ItemScript script)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
var effect = item.BattleEffect;
|
||||||
|
if (effect == null)
|
||||||
|
{
|
||||||
|
script = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!_itemScriptCtors.TryGetValue(effect.Name, out var scriptCtor))
|
||||||
|
{
|
||||||
|
script = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
script = scriptCtor();
|
||||||
|
script.OnInitialize(effect.Parameters);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
|
using PkmnLib.Static.Moves;
|
||||||
using PkmnLib.Static.Utils;
|
using PkmnLib.Static.Utils;
|
||||||
|
|
||||||
namespace PkmnLib.Static;
|
namespace PkmnLib.Static;
|
||||||
|
@ -105,6 +106,9 @@ public interface IItem : INamedValue
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ImmutableHashSet<StringKey> Flags { get; }
|
ImmutableHashSet<StringKey> Flags { get; }
|
||||||
|
|
||||||
|
ISecondaryEffect? Effect { get; }
|
||||||
|
ISecondaryEffect? BattleEffect { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks whether the item has a specific flag.
|
/// Checks whether the item has a specific flag.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -118,12 +122,14 @@ public class ItemImpl : IItem
|
||||||
{
|
{
|
||||||
/// <inheritdoc cref="ItemImpl"/>
|
/// <inheritdoc cref="ItemImpl"/>
|
||||||
public ItemImpl(StringKey name, ItemCategory category, BattleItemCategory battleCategory, int price,
|
public ItemImpl(StringKey name, ItemCategory category, BattleItemCategory battleCategory, int price,
|
||||||
IEnumerable<StringKey> flags)
|
IEnumerable<StringKey> flags, ISecondaryEffect? effect, ISecondaryEffect? battleTriggerEffect)
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
Category = category;
|
Category = category;
|
||||||
BattleCategory = battleCategory;
|
BattleCategory = battleCategory;
|
||||||
Price = price;
|
Price = price;
|
||||||
|
Effect = effect;
|
||||||
|
BattleEffect = battleTriggerEffect;
|
||||||
Flags = [..flags];
|
Flags = [..flags];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,6 +148,12 @@ public class ItemImpl : IItem
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ImmutableHashSet<StringKey> Flags { get; }
|
public ImmutableHashSet<StringKey> Flags { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public ISecondaryEffect? Effect { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public ISecondaryEffect? BattleEffect { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool HasFlag(string key)
|
public bool HasFlag(string key)
|
||||||
{
|
{
|
||||||
|
|
|
@ -3326,10 +3326,10 @@
|
||||||
"price": 200,
|
"price": 200,
|
||||||
"flingPower": 0,
|
"flingPower": 0,
|
||||||
"battleEffect": {
|
"battleEffect": {
|
||||||
"name": "Pokeball",
|
"name": "pokeball",
|
||||||
"parameters": [
|
"parameters": {
|
||||||
1.0
|
"catchRate": 1
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -3388,10 +3388,10 @@
|
||||||
"price": 200,
|
"price": 200,
|
||||||
"flingPower": 30,
|
"flingPower": 30,
|
||||||
"effect": {
|
"effect": {
|
||||||
"name": "heal",
|
"name": "healing_item",
|
||||||
"parameters": [
|
"parameters": {
|
||||||
20
|
"heal_amount": 20
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using PkmnLib.Dynamic.Models;
|
||||||
|
using PkmnLib.Dynamic.ScriptHandling;
|
||||||
|
using PkmnLib.Dynamic.ScriptHandling.Registry;
|
||||||
|
using PkmnLib.Static.Utils;
|
||||||
|
|
||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Items;
|
||||||
|
|
||||||
|
[ItemScript("healing_item")]
|
||||||
|
public class HealingItem : ItemScript
|
||||||
|
{
|
||||||
|
private uint _healAmount;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool IsItemUsable => true;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool RequiresTarget => true;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnInitialize(IReadOnlyDictionary<StringKey, object?>? parameters)
|
||||||
|
{
|
||||||
|
if (parameters == null || !parameters.TryGetValue("heal_amount", out var healAmountObj) ||
|
||||||
|
healAmountObj is not int healAmount)
|
||||||
|
{
|
||||||
|
healAmount = 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
_healAmount = (uint)healAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool IsTargetValid(IPokemon target) => !target.IsFainted;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnUseWithTarget(IPokemon target)
|
||||||
|
{
|
||||||
|
target.Heal(_healAmount);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using PkmnLib.Dynamic.Libraries;
|
|
||||||
using PkmnLib.Dynamic.Models;
|
using PkmnLib.Dynamic.Models;
|
||||||
using PkmnLib.Dynamic.ScriptHandling;
|
using PkmnLib.Dynamic.ScriptHandling;
|
||||||
using PkmnLib.Dynamic.ScriptHandling.Registry;
|
using PkmnLib.Dynamic.ScriptHandling.Registry;
|
||||||
|
@ -15,7 +14,7 @@ public class ChangeAllTargetStats : Script
|
||||||
private sbyte _amount;
|
private sbyte _amount;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void OnInitialize(IDynamicLibrary library, IReadOnlyDictionary<StringKey, object?>? parameters)
|
public override void OnInitialize(IReadOnlyDictionary<StringKey, object?>? parameters)
|
||||||
{
|
{
|
||||||
if (parameters == null)
|
if (parameters == null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using PkmnLib.Dynamic.Libraries;
|
|
||||||
using PkmnLib.Dynamic.Models;
|
using PkmnLib.Dynamic.Models;
|
||||||
using PkmnLib.Dynamic.ScriptHandling;
|
using PkmnLib.Dynamic.ScriptHandling;
|
||||||
using PkmnLib.Dynamic.ScriptHandling.Registry;
|
using PkmnLib.Dynamic.ScriptHandling.Registry;
|
||||||
|
@ -20,7 +19,7 @@ public abstract class ChangeTargetStats : Script
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void OnInitialize(IDynamicLibrary library, IReadOnlyDictionary<StringKey, object?>? parameters)
|
public override void OnInitialize(IReadOnlyDictionary<StringKey, object?>? parameters)
|
||||||
{
|
{
|
||||||
if (parameters == null)
|
if (parameters == null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using PkmnLib.Dynamic.Libraries;
|
|
||||||
using PkmnLib.Dynamic.Models;
|
using PkmnLib.Dynamic.Models;
|
||||||
using PkmnLib.Dynamic.ScriptHandling;
|
using PkmnLib.Dynamic.ScriptHandling;
|
||||||
using PkmnLib.Dynamic.ScriptHandling.Registry;
|
using PkmnLib.Dynamic.ScriptHandling.Registry;
|
||||||
|
@ -13,9 +12,9 @@ public class Drain : Script
|
||||||
public float DrainModifier { get; set; } = 0.5f;
|
public float DrainModifier { get; set; } = 0.5f;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void OnInitialize(IDynamicLibrary library, IReadOnlyDictionary<StringKey, object?>? parameters)
|
public override void OnInitialize(IReadOnlyDictionary<StringKey, object?>? parameters)
|
||||||
{
|
{
|
||||||
base.OnInitialize(library, parameters);
|
base.OnInitialize(parameters);
|
||||||
if (parameters == null)
|
if (parameters == null)
|
||||||
return;
|
return;
|
||||||
DrainModifier = parameters.GetValueOrDefault("drain_modifier") as float? ?? DrainModifier;
|
DrainModifier = parameters.GetValueOrDefault("drain_modifier") as float? ?? DrainModifier;
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using PkmnLib.Dynamic.Libraries;
|
|
||||||
using PkmnLib.Dynamic.Models;
|
using PkmnLib.Dynamic.Models;
|
||||||
using PkmnLib.Dynamic.ScriptHandling;
|
using PkmnLib.Dynamic.ScriptHandling;
|
||||||
using PkmnLib.Dynamic.ScriptHandling.Registry;
|
using PkmnLib.Dynamic.ScriptHandling.Registry;
|
||||||
|
@ -14,9 +13,9 @@ public class HealEachEndOfTurn : Script
|
||||||
private float _healPercentage;
|
private float _healPercentage;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void OnInitialize(IDynamicLibrary library, IReadOnlyDictionary<StringKey, object?>? parameters)
|
public override void OnInitialize(IReadOnlyDictionary<StringKey, object?>? parameters)
|
||||||
{
|
{
|
||||||
base.OnInitialize(library, parameters);
|
base.OnInitialize(parameters);
|
||||||
if (parameters == null || !parameters.TryGetValue("percent", out var healPercentageObj) ||
|
if (parameters == null || !parameters.TryGetValue("percent", out var healPercentageObj) ||
|
||||||
healPercentageObj is not float healPercentage)
|
healPercentageObj is not float healPercentage)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue