diff --git a/PkmnLib.Dynamic/Models/Pokemon.cs b/PkmnLib.Dynamic/Models/Pokemon.cs index eac1629..217cb4b 100644 --- a/PkmnLib.Dynamic/Models/Pokemon.cs +++ b/PkmnLib.Dynamic/Models/Pokemon.cs @@ -263,6 +263,11 @@ public interface IPokemon : IScriptSource, IDeepCloneable /// bool ConsumeHeldItem(); + /// + /// Uses an item on the Pokemon. + /// + void UseItem(IItem item); + /// /// Change a boosted stat by a certain amount. /// @@ -805,8 +810,15 @@ public class PokemonImpl : ScriptSource, IPokemon BattleData.MarkItemAsConsumed(HeldItem); } + UseItem(SetHeldItem(null)!); + return true; + } + + public void UseItem(IItem item) + { // TODO: actually consume the item - throw new NotImplementedException(); + + this.RunScriptHook(x => x.OnAfterItemConsume(this, item)); } /// diff --git a/PkmnLib.Dynamic/ScriptHandling/Script.cs b/PkmnLib.Dynamic/ScriptHandling/Script.cs index c1e0928..e6ec591 100644 --- a/PkmnLib.Dynamic/ScriptHandling/Script.cs +++ b/PkmnLib.Dynamic/ScriptHandling/Script.cs @@ -557,7 +557,7 @@ public abstract class Script : IDeepCloneable /// This function is triggered on a Pokemon and its parents when the given Pokemon consumes the /// held item it had. /// - public virtual void OnAfterHeldItemConsume(IPokemon pokemon, IItem item) + public virtual void OnAfterItemConsume(IPokemon pokemon, IItem item) { } diff --git a/Plugins/PkmnLib.Plugin.Gen7/Data/Abilities.json b/Plugins/PkmnLib.Plugin.Gen7/Data/Abilities.jsonc similarity index 95% rename from Plugins/PkmnLib.Plugin.Gen7/Data/Abilities.json rename to Plugins/PkmnLib.Plugin.Gen7/Data/Abilities.jsonc index f4fb4f9..74b9deb 100755 --- a/Plugins/PkmnLib.Plugin.Gen7/Data/Abilities.json +++ b/Plugins/PkmnLib.Plugin.Gen7/Data/Abilities.jsonc @@ -72,22 +72,24 @@ "effect": "bulletproof" }, "cheek_pouch": { - "effect": "CheekPouch" + "effect": "cheek_pouch" }, "chlorophyll": { - "effect": "DoubleSpeedInWeather", + "effect": "speed_modifier_in_weather", "parameters": { - "weather": "HarshSunlight" + "weather": "sunny", + "modifier": 2.0 } }, "clear_body": { - "effect": "PreventStatLowering" + "effect": "prevent_stat_lowering" + // By not specifying a stat, it applies to all stats }, "cloud_nine": { - "effect": "SuppressWeather" + "effect": "suppress_weather" }, "color_change": { - "effect": "ColorChange" + "effect": "color_change" }, "comatose": { "canBeChanged": false diff --git a/Plugins/PkmnLib.Plugin.Gen7/Gen7Plugin.cs b/Plugins/PkmnLib.Plugin.Gen7/Gen7Plugin.cs index 44ebec7..a7c2442 100644 --- a/Plugins/PkmnLib.Plugin.Gen7/Gen7Plugin.cs +++ b/Plugins/PkmnLib.Plugin.Gen7/Gen7Plugin.cs @@ -69,7 +69,7 @@ public class Gen7Plugin : Plugin, IResourceProvider typeof(Gen7Plugin).Assembly), ResourceFileType.Items => new AssemblyResourceResult("PkmnLib.Plugin.Gen7.Data.Items.json", typeof(Gen7Plugin).Assembly), - ResourceFileType.Abilities => new AssemblyResourceResult("PkmnLib.Plugin.Gen7.Data.Abilities.json", + ResourceFileType.Abilities => new AssemblyResourceResult("PkmnLib.Plugin.Gen7.Data.Abilities.jsonc", typeof(Gen7Plugin).Assembly), ResourceFileType.GrowthRates => new AssemblyResourceResult("PkmnLib.Plugin.Gen7.Data.GrowthRates.json", typeof(Gen7Plugin).Assembly), diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/CheekPouch.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/CheekPouch.cs new file mode 100644 index 0000000..a845a78 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/CheekPouch.cs @@ -0,0 +1,15 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Abilities; + +[Script(ScriptCategory.Ability, "cheek_pouch")] +public class CheekPouch : Script +{ + /// + public override void OnAfterItemConsume(IPokemon pokemon, IItem item) + { + if (item.Category == ItemCategory.Berry) + { + pokemon.BattleData?.Battle.EventHook.Invoke(new AbilityTriggerEvent(pokemon)); + pokemon.Heal(pokemon.MaxHealth / 3); + } + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ColorChange.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ColorChange.cs new file mode 100644 index 0000000..f589c90 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ColorChange.cs @@ -0,0 +1,16 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Abilities; + +[Script(ScriptCategory.Ability, "color_change")] +public class ColorChange : Script +{ + /// + public override void OnIncomingHit(IExecutingMove move, IPokemon target, byte hit) + { + var hitData = move.GetHitData(target, hit); + if (hitData.Type != null && (hitData.Type != target.Types.FirstOrDefault() || target.Types.Count > 1)) + { + target.BattleData?.Battle.EventHook.Invoke(new AbilityTriggerEvent(target)); + target.SetTypes([hitData.Type.Value]); + } + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/PreventStatLowering.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/PreventStatLowering.cs index e501b83..719f6fb 100644 --- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/PreventStatLowering.cs +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/PreventStatLowering.cs @@ -5,26 +5,37 @@ namespace PkmnLib.Plugin.Gen7.Scripts.Abilities; [Script(ScriptCategory.Ability, "prevent_stat_lowering")] public class PreventStatLowering : Script { - private Statistic _statistic; + /// + /// The statistic that this ability prevents from being lowered. + /// Null means it prevents all stat lowering. + /// + private Statistic? _statistic; /// public override void OnInitialize(IReadOnlyDictionary? parameters) { if (parameters is null) throw new ArgumentNullException(nameof(parameters), "Parameters cannot be null."); - if (!parameters.TryGetValue("stat", out var statObj) || statObj is not string statStr) - throw new ArgumentException("Parameter 'stat' is required and must be a string.", nameof(parameters)); - if (!Enum.TryParse(statStr, true, out Statistic stat)) - throw new ArgumentException($"Invalid statistic '{statStr}' provided.", nameof(statStr)); - - _statistic = stat; + if (parameters.TryGetValue("stat", out var statObj) && statObj is string statStr) + { + if (!Enum.TryParse(statStr, true, out Statistic stat)) + throw new ArgumentException($"Invalid statistic '{statStr}' provided.", nameof(statStr)); + _statistic = stat; + } } /// public override void PreventStatBoostChange(IPokemon target, Statistic stat, sbyte amount, bool selfInflicted, ref bool prevent) { + if (_statistic is not null && _statistic != stat) + return; + if (amount >= 0) + return; if (!selfInflicted) - prevent = false; + { + target.BattleData?.Battle.EventHook.Invoke(new AbilityTriggerEvent(target)); + prevent = true; + } } } \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SpeedModifierInWeather.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SpeedModifierInWeather.cs new file mode 100644 index 0000000..52ee809 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SpeedModifierInWeather.cs @@ -0,0 +1,41 @@ +using PkmnLib.Static.Utils; + +namespace PkmnLib.Plugin.Gen7.Scripts.Abilities; + +[Script(ScriptCategory.Ability, "speed_modifier_in_weather")] +public class SpeedModifierInWeather : Script +{ + private StringKey _weather; + private float _modifier; + + /// + public override void OnInitialize(IReadOnlyDictionary? parameters) + { + if (parameters is null) + throw new ArgumentNullException(nameof(parameters)); + + if (!parameters.TryGetValue("weather", out var weatherObj) || weatherObj is not string weatherStr) + throw new ArgumentException("Parameter 'weather' is required and must be a string.", nameof(parameters)); + if (!parameters.TryGetValue("modifier", out var modifierObj)) + throw new ArgumentException("Parameter 'modifier' is required", nameof(parameters)); + if (modifierObj is not float modifier && modifierObj is not int) + throw new ArgumentException("Parameter 'modifier' must be a float or int.", nameof(parameters)); + var weatherModifier = modifierObj is float modFloat ? modFloat : (int)modifierObj; + + _weather = weatherStr; + _modifier = weatherModifier; + } + + /// + public override void ChangeSpeed(ITurnChoice choice, ref uint speed) + { + var battle = choice.User.BattleData?.Battle; + if (battle is null) + return; + var weather = battle.WeatherName; + if (weather == _weather) + { + speed = speed.MultiplyOrMax(_modifier); + } + } +} \ No newline at end of file