Initial set up for item use

This commit is contained in:
Deukhoofd 2025-01-10 11:11:50 +01:00
parent 85ea31f7cd
commit 0518499a4c
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
23 changed files with 305 additions and 59 deletions

View File

@ -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);
}
}

View File

@ -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);
} }
} }

View File

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

View File

@ -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);
}
} }

View File

@ -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);
} }

View File

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

View File

@ -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);
} }
} }

View File

@ -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();
}
}
} }

View File

@ -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;

View File

@ -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);
} }
} }
} }

View File

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

View File

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

View File

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

View File

@ -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;

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
}
}

View File

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

View File

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

View File

@ -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;

View File

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