From c0bc905c46b1e3e0c334a01ed2466eea1dd10a04 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sun, 2 Mar 2025 14:03:51 +0100 Subject: [PATCH] More move effects --- PkmnLib.Dataloader/ItemDataLoader.cs | 18 +- PkmnLib.Dataloader/PkmnLib.Dataloader.csproj | 6 + PkmnLib.Dynamic/Models/Pokemon.cs | 29 +++ .../Registry/ScriptAttribute.cs | 2 +- PkmnLib.Dynamic/ScriptHandling/Script.cs | 4 + PkmnLib.Static/Item.cs | 9 +- PkmnLib.Static/Libraries/TypeLibrary.cs | 4 +- PkmnLib.Tests/Data/Moves.json | 165 +++++++++++++++--- PkmnLib.Tests/PkmnLib.Tests.csproj | 2 +- .../Libraries/Gen7BattleStatCalculator.cs | 1 + .../Scripts/Moves/Bestow.cs | 2 +- .../Scripts/Moves/Bounce.cs | 7 +- .../Scripts/Moves/ChangeTargetStats.cs | 8 + .../Scripts/Moves/Covet.cs | 2 +- .../PkmnLib.Plugin.Gen7/Scripts/Moves/Dig.cs | 5 +- .../Scripts/Moves/FireSpin.cs | 13 ++ .../Scripts/Moves/FirstImpression.cs | 14 ++ .../Scripts/Moves/Flail.cs | 21 +++ .../Scripts/Moves/FlameBurst.cs | 43 +++++ .../Scripts/Moves/FlareBlitz.cs | 23 +++ .../Scripts/Moves/Flatter.cs | 15 ++ .../Scripts/Moves/Fling.cs | 31 ++++ .../Scripts/Moves/FloralHealing.cs | 24 +++ .../Scripts/Moves/FlowerShield.cs | 32 ++++ .../PkmnLib.Plugin.Gen7/Scripts/Moves/Fly.cs | 28 +++ .../Scripts/Moves/FlyingPress.cs | 20 +++ .../Scripts/Moves/FocusEnergy.cs | 11 ++ .../Scripts/Moves/FocusPunch.cs | 29 +++ .../Scripts/Moves/FollowMe.cs | 22 +++ .../Scripts/Moves/Foresight.cs | 19 ++ .../Scripts/Moves/ForestsCurse.cs | 17 ++ .../Scripts/Moves/FoulPlay.cs | 15 ++ .../Scripts/Moves/FreezeDry.cs | 41 +++++ .../Scripts/Moves/OneHitKo.cs | 25 +++ .../Scripts/Pokemon/ChargeFlyEffect.cs | 35 ++++ .../Scripts/Pokemon/FireSpinEffect.cs | 24 +++ .../Scripts/Pokemon/FocusPunchEffect.cs | 20 +++ .../Scripts/Pokemon/ForesightEffect.cs | 40 +++++ .../Scripts/Pokemon/IncreasedCriticalStage.cs | 17 ++ .../Scripts/Terrain/GrassyTerrain.cs | 7 + 40 files changed, 804 insertions(+), 46 deletions(-) create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FireSpin.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FirstImpression.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Flail.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FlameBurst.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FlareBlitz.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Flatter.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Fling.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FloralHealing.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FlowerShield.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Fly.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FlyingPress.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FocusEnergy.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FocusPunch.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FollowMe.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Foresight.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ForestsCurse.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FoulPlay.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FreezeDry.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/OneHitKo.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/ChargeFlyEffect.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/FireSpinEffect.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/FocusPunchEffect.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/ForesightEffect.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/IncreasedCriticalStage.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Terrain/GrassyTerrain.cs diff --git a/PkmnLib.Dataloader/ItemDataLoader.cs b/PkmnLib.Dataloader/ItemDataLoader.cs index 34a12d8..0b80521 100644 --- a/PkmnLib.Dataloader/ItemDataLoader.cs +++ b/PkmnLib.Dataloader/ItemDataLoader.cs @@ -4,6 +4,7 @@ using System.Collections.Immutable; using System.IO; using System.Linq; using System.Text.Json; +using JetBrains.Annotations; using PkmnLib.Dataloader.Models; using PkmnLib.Static; using PkmnLib.Static.Libraries; @@ -25,13 +26,15 @@ public static class ItemDataLoader library.Add(i); return library; } + + public delegate IItem ItemFactoryDelegate(SerializedItem serialized, StringKey name, ItemCategory type, + BattleItemCategory battleType, int price, ImmutableHashSet flags, + ISecondaryEffect? effect, ISecondaryEffect? battleTriggerEffect, byte flingPower); - // ReSharper disable once MemberCanBePrivate.Global - public static Func, ISecondaryEffect?, ISecondaryEffect?, - // ReSharper disable once FieldCanBeMadeReadOnly.Global - IItem> ItemConstructor = (_, name, type, battleType, price, flags, effect, battleTriggerEffect) => - new ItemImpl(name, type, battleType, price, flags, effect, battleTriggerEffect); + [PublicAPI] + public static ItemFactoryDelegate ItemConstructor { get; set; } = (_, name, type, battleType, price, flags, effect, + battleTriggerEffect, flingPower) => + new ItemImpl(name, type, battleType, price, flags, effect, battleTriggerEffect, flingPower); private static IItem DeserializeItem(SerializedItem serialized) { @@ -42,6 +45,7 @@ public static class ItemDataLoader var battleTriggerEffect = serialized.BattleEffect?.ParseEffect(); return ItemConstructor(serialized, serialized.Name, itemType, battleType, serialized.Price, - serialized.Flags.Select(x => (StringKey)x).ToImmutableHashSet(), effect, battleTriggerEffect); + serialized.Flags.Select(x => (StringKey)x).ToImmutableHashSet(), effect, battleTriggerEffect, + serialized.FlingPower); } } \ No newline at end of file diff --git a/PkmnLib.Dataloader/PkmnLib.Dataloader.csproj b/PkmnLib.Dataloader/PkmnLib.Dataloader.csproj index 0c32822..ef26f4e 100644 --- a/PkmnLib.Dataloader/PkmnLib.Dataloader.csproj +++ b/PkmnLib.Dataloader/PkmnLib.Dataloader.csproj @@ -14,4 +14,10 @@ + + + ..\..\..\..\.nuget\packages\jetbrains.annotations\2024.2.0\lib\netstandard2.0\JetBrains.Annotations.dll + + + diff --git a/PkmnLib.Dynamic/Models/Pokemon.cs b/PkmnLib.Dynamic/Models/Pokemon.cs index 4f54841..b07404e 100644 --- a/PkmnLib.Dynamic/Models/Pokemon.cs +++ b/PkmnLib.Dynamic/Models/Pokemon.cs @@ -240,6 +240,20 @@ public interface IPokemon : IScriptSource, IDeepCloneable /// [MustUseReturnValue] IItem? RemoveHeldItem(); + + /// + /// Removes the held item from the Pokemon for the duration of the battle. Returns the previously held item. + /// + /// + /// This is used for moves that remove a held item, but do not consume it. In this case, the item needs to be + /// restored after the battle. + /// + IItem? RemoveHeldItemForBattle(); + + /// + /// Restores the held item of a Pokémon if it was temporarily removed. + /// + void RestoreStolenHeldItem(); /// /// Makes the Pokemon uses its held item. Returns whether the item was consumed. @@ -716,6 +730,21 @@ public class PokemonImpl : ScriptSource, IPokemon HeldItem = null; return previous; } + + private IItem? _stolenHeldItem; + + /// + public IItem? RemoveHeldItemForBattle() + { + return _stolenHeldItem = RemoveHeldItem(); + } + + /// + public void RestoreStolenHeldItem() + { + _ = SetHeldItem(_stolenHeldItem); + _stolenHeldItem = null; + } /// public bool ConsumeHeldItem() diff --git a/PkmnLib.Dynamic/ScriptHandling/Registry/ScriptAttribute.cs b/PkmnLib.Dynamic/ScriptHandling/Registry/ScriptAttribute.cs index b0201c4..adb8deb 100644 --- a/PkmnLib.Dynamic/ScriptHandling/Registry/ScriptAttribute.cs +++ b/PkmnLib.Dynamic/ScriptHandling/Registry/ScriptAttribute.cs @@ -6,7 +6,7 @@ namespace PkmnLib.Dynamic.ScriptHandling.Registry; /// /// Helper attribute to register scripts through reflection. /// -[AttributeUsage(AttributeTargets.Class)] +[AttributeUsage(AttributeTargets.Class, Inherited = false)] [MeansImplicitUse] public class ScriptAttribute : Attribute { diff --git a/PkmnLib.Dynamic/ScriptHandling/Script.cs b/PkmnLib.Dynamic/ScriptHandling/Script.cs index a53ba68..fabf91f 100644 --- a/PkmnLib.Dynamic/ScriptHandling/Script.cs +++ b/PkmnLib.Dynamic/ScriptHandling/Script.cs @@ -554,4 +554,8 @@ public abstract class Script : IDeepCloneable public virtual void ChangeIncomingDamage(IPokemon pokemon, DamageSource source, ref uint damage) { } + + public virtual void ChangeAccuracy(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref int modifiedAccuracy) + { + } } \ No newline at end of file diff --git a/PkmnLib.Static/Item.cs b/PkmnLib.Static/Item.cs index d43f783..7be3a34 100644 --- a/PkmnLib.Static/Item.cs +++ b/PkmnLib.Static/Item.cs @@ -108,6 +108,8 @@ public interface IItem : INamedValue ISecondaryEffect? Effect { get; } ISecondaryEffect? BattleEffect { get; } + + byte FlingPower { get; } /// /// Checks whether the item has a specific flag. @@ -122,7 +124,7 @@ public class ItemImpl : IItem { /// public ItemImpl(StringKey name, ItemCategory category, BattleItemCategory battleCategory, int price, - IEnumerable flags, ISecondaryEffect? effect, ISecondaryEffect? battleTriggerEffect) + IEnumerable flags, ISecondaryEffect? effect, ISecondaryEffect? battleTriggerEffect, byte flingPower) { Name = name; Category = category; @@ -130,6 +132,7 @@ public class ItemImpl : IItem Price = price; Effect = effect; BattleEffect = battleTriggerEffect; + FlingPower = flingPower; Flags = [..flags]; } @@ -154,6 +157,10 @@ public class ItemImpl : IItem /// public ISecondaryEffect? BattleEffect { get; } + /// + public byte FlingPower { get; } + + /// public bool HasFlag(string key) { diff --git a/PkmnLib.Static/Libraries/TypeLibrary.cs b/PkmnLib.Static/Libraries/TypeLibrary.cs index 9123d36..1d78ffa 100644 --- a/PkmnLib.Static/Libraries/TypeLibrary.cs +++ b/PkmnLib.Static/Libraries/TypeLibrary.cs @@ -27,7 +27,7 @@ public interface IReadOnlyTypeLibrary /// Gets the effectiveness for a single attacking type against an amount of defending types. /// This is equivalent to running get_single_effectiveness on each defending type, and multiplying the results with each other. /// - float GetEffectiveness(TypeIdentifier attacking, IReadOnlyList defending); + float GetEffectiveness(TypeIdentifier attacking, IEnumerable defending); IEnumerable<(TypeIdentifier type, float effectiveness)> GetAllEffectivenessFromAttacking(TypeIdentifier attacking); } @@ -68,7 +68,7 @@ public class TypeLibrary : IReadOnlyTypeLibrary } /// - public float GetEffectiveness(TypeIdentifier attacking, IReadOnlyList defending) => + public float GetEffectiveness(TypeIdentifier attacking, IEnumerable defending) => defending.Aggregate(1, (current, type) => current * GetSingleEffectiveness(attacking, type)); diff --git a/PkmnLib.Tests/Data/Moves.json b/PkmnLib.Tests/Data/Moves.json index 551e25b..20b5019 100755 --- a/PkmnLib.Tests/Data/Moves.json +++ b/PkmnLib.Tests/Data/Moves.json @@ -3614,7 +3614,6 @@ } } }, - // Done up to here { "name": "fire_spin", "type": "fire", @@ -3627,7 +3626,10 @@ "flags": [ "protect", "mirror" - ] + ], + "effect": { + "name": "fire_spin" + } }, { "name": "first_impression", @@ -3642,7 +3644,10 @@ "contact", "protect", "mirror" - ] + ], + "effect": { + "name": "first_impression" + } }, { "name": "fissure", @@ -3657,7 +3662,10 @@ "protect", "mirror", "nonskybattle" - ] + ], + "effect": { + "name": "one_hit_ko" + } }, { "name": "flail", @@ -3672,7 +3680,10 @@ "contact", "protect", "mirror" - ] + ], + "effect": { + "name": "flail" + } }, { "name": "flame_burst", @@ -3686,7 +3697,10 @@ "flags": [ "protect", "mirror" - ] + ], + "effect": { + "name": "flame_burst" + } }, { "name": "flame_charge", @@ -3701,7 +3715,13 @@ "contact", "protect", "mirror" - ] + ], + "effect": { + "name": "change_user_speed", + "parameters": { + "amount": 1 + } + } }, { "name": "flame_wheel", @@ -3717,7 +3737,14 @@ "protect", "mirror", "defrost" - ] + ], + "effect": { + "name": "set_status", + "chance": 10, + "parameters": { + "status": "burned" + } + } }, { "name": "flamethrower", @@ -3731,7 +3758,14 @@ "flags": [ "protect", "mirror" - ] + ], + "effect": { + "name": "set_status", + "chance": 10, + "parameters": { + "status": "burned" + } + } }, { "name": "flare_blitz", @@ -3747,7 +3781,10 @@ "protect", "mirror", "defrost" - ] + ], + "effect": { + "name": "flare_blitz" + } }, { "name": "flash", @@ -3762,7 +3799,13 @@ "protect", "reflectable", "mirror" - ] + ], + "effect": { + "name": "change_target_accuracy", + "parameters": { + "amount": -1 + } + } }, { "name": "flash_cannon", @@ -3776,7 +3819,14 @@ "flags": [ "protect", "mirror" - ] + ], + "effect": { + "name": "change_target_special_defense", + "chance": 10, + "parameters": { + "amount": -1 + } + } }, { "name": "flatter", @@ -3791,7 +3841,10 @@ "protect", "reflectable", "mirror" - ] + ], + "effect": { + "name": "flatter" + } }, { "name": "fleur_cannon", @@ -3805,7 +3858,13 @@ "flags": [ "protect", "mirror" - ] + ], + "effect": { + "name": "change_user_special_attack", + "parameters": { + "amount": -2 + } + } }, { "name": "fling", @@ -3819,7 +3878,10 @@ "flags": [ "protect", "mirror" - ] + ], + "effect": { + "name": "fling" + } }, { "name": "floral_healing", @@ -3834,7 +3896,10 @@ "protect", "reflectable", "heal" - ] + ], + "effect": { + "name": "floral_healing" + } }, { "name": "flower_shield", @@ -3847,7 +3912,10 @@ "category": "status", "flags": [ "distance" - ] + ], + "effect": { + "name": "flower_shield" + } }, { "name": "fly", @@ -3865,7 +3933,10 @@ "mirror", "gravity", "distance" - ] + ], + "effect": { + "name": "fly" + } }, { "name": "flying_press", @@ -3883,7 +3954,10 @@ "gravity", "distance", "nonskybattle" - ] + ], + "effect": { + "name": "flying_press" + } }, { "name": "focus_blast", @@ -3898,7 +3972,14 @@ "protect", "mirror", "ballistics" - ] + ], + "effect": { + "name": "change_target_special_defense", + "chance": 10, + "parameters": { + "amount": -1 + } + } }, { "name": "focus_energy", @@ -3911,7 +3992,10 @@ "category": "status", "flags": [ "snatch" - ] + ], + "effect": { + "name": "focus_energy" + } }, { "name": "focus_punch", @@ -3926,7 +4010,10 @@ "contact", "protect", "punch" - ] + ], + "effect": { + "name": "focus_punch" + } }, { "name": "follow_me", @@ -3937,7 +4024,10 @@ "priority": 2, "target": "Self", "category": "status", - "flags": [] + "flags": [], + "effect": { + "name": "follow_me" + } }, { "name": "force_palm", @@ -3952,7 +4042,14 @@ "contact", "protect", "mirror" - ] + ], + "effect": { + "name": "set_status", + "chance": 30, + "parameters": { + "status": "paralyzed" + } + } }, { "name": "foresight", @@ -3968,7 +4065,10 @@ "reflectable", "mirror", "ignore-substitute" - ] + ], + "effect": { + "name": "foresight" + } }, { "name": "forests_curse", @@ -3983,7 +4083,10 @@ "protect", "reflectable", "mirror" - ] + ], + "effect": { + "name": "forests_curse" + } }, { "name": "foul_play", @@ -3998,7 +4101,10 @@ "contact", "protect", "mirror" - ] + ], + "effect": { + "name": "foul_play" + } }, { "name": "freeze_dry", @@ -4012,7 +4118,10 @@ "flags": [ "protect", "mirror" - ] + ], + "effect": { + "name": "freeze_dry" + } }, { "name": "freeze_shock", diff --git a/PkmnLib.Tests/PkmnLib.Tests.csproj b/PkmnLib.Tests/PkmnLib.Tests.csproj index bb21f73..26ec4be 100644 --- a/PkmnLib.Tests/PkmnLib.Tests.csproj +++ b/PkmnLib.Tests/PkmnLib.Tests.csproj @@ -1,7 +1,7 @@ - net8.0 + net9.0 enable enable diff --git a/Plugins/PkmnLib.Plugin.Gen7/Libraries/Gen7BattleStatCalculator.cs b/Plugins/PkmnLib.Plugin.Gen7/Libraries/Gen7BattleStatCalculator.cs index 0919646..c193099 100644 --- a/Plugins/PkmnLib.Plugin.Gen7/Libraries/Gen7BattleStatCalculator.cs +++ b/Plugins/PkmnLib.Plugin.Gen7/Libraries/Gen7BattleStatCalculator.cs @@ -54,6 +54,7 @@ public class Gen7BattleStatCalculator : IBattleStatCalculator var accuracyModifier = 1.0f; executingMove.RunScriptHook(x => x.ChangeAccuracyModifier(executingMove, target, hitIndex, ref accuracyModifier)); var modifiedAccuracy = (int)(moveAccuracy * accuracyModifier); + executingMove.RunScriptHook(x => x.ChangeAccuracy(executingMove, target, hitIndex, ref modifiedAccuracy)); var targetEvasion = target.StatBoost.Evasion; var ignoreEvasion = false; executingMove.RunScriptHook(x => x.BypassEvasionStatBoosts(executingMove, target, hitIndex, ref ignoreEvasion)); diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Bestow.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Bestow.cs index 1a84d2e..7b46bd5 100644 --- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Bestow.cs +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Bestow.cs @@ -7,7 +7,7 @@ public class Bestow : Script public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) { var user = move.User; - var userHeldItem = user.HeldItem; + var userHeldItem = user.RemoveHeldItemForBattle(); var targetHeldItem = target.HeldItem; if (userHeldItem == null || targetHeldItem != null) diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Bounce.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Bounce.cs index 1601684..12fa214 100644 --- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Bounce.cs +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Bounce.cs @@ -20,6 +20,12 @@ public class Bounce : Script prevent = true; } + /// + public override void OnBeforeMove(IExecutingMove move) + { + move.User.Volatile.Remove(ScriptUtils.ResolveName()); + } + /// public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) { @@ -31,6 +37,5 @@ public class Bounce : Script { target.SetStatus("paralyzed"); } - move.User.Volatile.Remove(ScriptUtils.ResolveName()); } } \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ChangeTargetStats.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ChangeTargetStats.cs index 11888ec..aa66775 100644 --- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ChangeTargetStats.cs +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ChangeTargetStats.cs @@ -76,4 +76,12 @@ public class ChangeTargetSpeed : ChangeTargetStats public ChangeTargetSpeed() : base(Statistic.Speed) { } +} + +[Script(ScriptCategory.Move, "change_target_accuracy")] +public class ChangeTargetAccuracy : ChangeTargetStats +{ + public ChangeTargetAccuracy() : base(Statistic.Accuracy) + { + } } \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Covet.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Covet.cs index a5fb91a..1e501fb 100644 --- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Covet.cs +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Covet.cs @@ -10,6 +10,6 @@ public class Covet : Script return; if (move.User.HeldItem != null) return; - _ = move.User.SetHeldItem(target.RemoveHeldItem()); + _ = move.User.SetHeldItem(target.RemoveHeldItemForBattle()); } } \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Dig.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Dig.cs index 99b5fd5..123aabf 100644 --- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Dig.cs +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Dig.cs @@ -19,11 +19,10 @@ public class Dig : Script })); prevent = true; } - + /// - public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + public override void OnBeforeMove(IExecutingMove move) { move.User.Volatile.Remove(ScriptUtils.ResolveName()); } - } \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FireSpin.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FireSpin.cs new file mode 100644 index 0000000..a6f5048 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FireSpin.cs @@ -0,0 +1,13 @@ +using PkmnLib.Plugin.Gen7.Scripts.Pokemon; + +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "fire_spin")] +public class FireSpin : MultiHitMove +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + target.Volatile.StackOrAdd("fire_spin", () => new FireSpinEffect(target)); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FirstImpression.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FirstImpression.cs new file mode 100644 index 0000000..05beaa0 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FirstImpression.cs @@ -0,0 +1,14 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "first_impression")] +public class FirstImpression : Script +{ + public override void StopBeforeMove(IExecutingMove move, ref bool stop) + { + var battleData = move.User.BattleData; + if (battleData == null) + return; + if (battleData.SwitchInTurn != battleData.Battle.CurrentTurnNumber) + stop = true; + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Flail.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Flail.cs new file mode 100644 index 0000000..3419784 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Flail.cs @@ -0,0 +1,21 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "flail")] +public class Flail : Script +{ + /// + public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref byte basePower) + { + var remainingHealth = move.User.CurrentHealth / move.User.BoostedStats.Hp; + var fraction = remainingHealth * 48; + basePower = fraction switch + { + < 2 => 200, + < 5 => 150, + < 10 => 100, + < 17 => 80, + < 33 => 40, + _ => 20 + }; + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FlameBurst.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FlameBurst.cs new file mode 100644 index 0000000..70743b2 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FlameBurst.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using System.Linq; +using PkmnLib.Static.Utils; + +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "flame_burst")] +public class FlameBurst : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + var adjacentFoes = GetAdjacentFoes(move.User).WhereNotNull(); + EventBatchId batchId = new(); + foreach (var adjacentFoe in adjacentFoes) + { + adjacentFoe.Damage(adjacentFoe.BoostedStats.Hp / 16, DamageSource.Misc, batchId); + } + } + + private static IEnumerable GetAdjacentFoes(IPokemon pokemon) + { + var battleData = pokemon.BattleData; + if (battleData == null) + yield break; + if (battleData.Battle.PositionsPerSide == 1) + yield break; + + var position = battleData.Position; + var side = battleData.Battle.Sides[battleData.SideIndex]; + + if (position == 0) + { + yield return side.Pokemon[1]; + } + else + { + yield return side.Pokemon[position - 1]; + if (position < side.Pokemon.Count - 1) + yield return side.Pokemon[position + 1]; + } + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FlareBlitz.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FlareBlitz.cs new file mode 100644 index 0000000..ca423e8 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FlareBlitz.cs @@ -0,0 +1,23 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "flare_blitz")] +public class FlareBlitz : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + var battleData = target.BattleData; + if (battleData == null) + return; + + if (battleData.Battle.Random.EffectChance(10, move, target, hit)) + { + target.SetStatus("burned"); + } + + + var hitData = move.GetHitData(target, hit); + var recoilDamage = (uint)(hitData.Damage * (1 / 3)); + move.User.Damage(recoilDamage, DamageSource.Misc); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Flatter.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Flatter.cs new file mode 100644 index 0000000..2dd6e79 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Flatter.cs @@ -0,0 +1,15 @@ +using PkmnLib.Plugin.Gen7.Scripts.Pokemon; +using PkmnLib.Static; + +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "flatter")] +public class Flatter : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + target.ChangeStatBoost(Statistic.SpecialAttack, 1, false); + target.Volatile.StackOrAdd("confusion", () => new Confusion()); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Fling.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Fling.cs new file mode 100644 index 0000000..a2ea983 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Fling.cs @@ -0,0 +1,31 @@ +using PkmnLib.Static; + +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "fling")] +public class Fling : Script +{ + /// + public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref byte basePower) + { + var item = move.User.HeldItem; + if (item == null) + { + move.GetHitData(target, hit).Fail(); + return; + } + + if (item.Category is ItemCategory.FormChanger or ItemCategory.Pokeball or ItemCategory.Mail + or ItemCategory.KeyItem or ItemCategory.TmHm) + { + move.GetHitData(target, hit).Fail(); + return; + } + + basePower = item.FlingPower; + } + + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) => + move.User.RemoveHeldItemForBattle(); +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FloralHealing.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FloralHealing.cs new file mode 100644 index 0000000..3f83fc1 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FloralHealing.cs @@ -0,0 +1,24 @@ +using PkmnLib.Plugin.Gen7.Scripts.Terrain; + +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "floral_healing")] +public class FloralHealing : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + if (target.IsFainted) + return; + var battleData = target.BattleData; + if (battleData == null) + return; + + var modifier = 1f / 2; + if (battleData.Battle.TerrainName == ScriptUtils.ResolveName()) + modifier = 2f / 3; + + var healing = target.BoostedStats.Hp * modifier; + target.Heal((uint)healing); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FlowerShield.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FlowerShield.cs new file mode 100644 index 0000000..3c4de61 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FlowerShield.cs @@ -0,0 +1,32 @@ +using System.Linq; +using PkmnLib.Static; + +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "flower_shield")] +public class FlowerShield : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + var battleData = target.BattleData; + if (battleData == null) + return; + if (!battleData.Battle.Library.StaticLibrary.Types.TryGetTypeIdentifier("grass", out var grassType)) + return; + + var batchId = new EventBatchId(); + var sides = battleData.Battle.Sides; + foreach (var side in sides) + { + foreach (var pokemon in side.Pokemon) + { + if (pokemon == null || pokemon.IsFainted) + continue; + if (!pokemon.Types.Contains(grassType)) + continue; + pokemon.ChangeStatBoost(Statistic.Defense, 1, pokemon == move.User, batchId); + } + } + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Fly.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Fly.cs new file mode 100644 index 0000000..dadf9ad --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Fly.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using PkmnLib.Plugin.Gen7.Scripts.Pokemon; + +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "fly")] +public class Fly : Script +{ + /// + public override void PreventMove(IExecutingMove move, ref bool prevent) + { + if (move.User.Volatile.Contains()) + return; + + move.User.Volatile.Add(new ChargeFlyEffect(move.User)); + move.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("fly_charge", new Dictionary() + { + { "user", move.User } + })); + prevent = true; + } + + /// + public override void OnBeforeMove(IExecutingMove move) + { + move.User.Volatile.Remove(ScriptUtils.ResolveName()); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FlyingPress.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FlyingPress.cs new file mode 100644 index 0000000..c210a47 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FlyingPress.cs @@ -0,0 +1,20 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "flying_press")] +public class FlyingPress : Script +{ + /// + public override void ChangeEffectiveness(IExecutingMove move, IPokemon target, byte hit, ref float effectiveness) + { + var battleData = move.User.BattleData; + if (battleData == null) + return; + + var typeLibrary = battleData.Battle.Library.StaticLibrary.Types; + // If flying type is not found, return + if (!typeLibrary.TryGetTypeIdentifier("flying", out var flyingType)) + return; + var flyingEffectiveness = typeLibrary.GetEffectiveness(flyingType, target.Types); + effectiveness *= flyingEffectiveness; + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FocusEnergy.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FocusEnergy.cs new file mode 100644 index 0000000..7f28b65 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FocusEnergy.cs @@ -0,0 +1,11 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "focus_energy")] +public class FocusEnergy : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + target.Volatile.Add(new Pokemon.IncreasedCriticalStage()); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FocusPunch.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FocusPunch.cs new file mode 100644 index 0000000..86bc9d0 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FocusPunch.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using PkmnLib.Plugin.Gen7.Scripts.Pokemon; + +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "focus_punch")] +public class FocusPunch : Script +{ + /// + public override void OnBeforeTurnStart(ITurnChoice choice) + { + choice.User.Volatile.Add(new FocusPunchEffect()); + choice.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("focus_punch_charge", + new Dictionary() + { + { "pokemon", choice.User } + })); + } + + /// + public override void PreventMove(IExecutingMove move, ref bool prevent) + { + var focusPunchEffect = move.User.Volatile.Get(); + if (focusPunchEffect == null || focusPunchEffect.WasHit) + { + prevent = true; + } + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FollowMe.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FollowMe.cs new file mode 100644 index 0000000..21a0ed1 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FollowMe.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; + +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "follow_me")] +public class FollowMe : Script +{ + /// + public override void ChangeTargets(IMoveChoice moveChoice, ref IReadOnlyList targets) + { + if (targets.Count != 1) + return; + + var target = targets[0]; + if (target == null) + return; + if (target.BattleData?.SideIndex != moveChoice.User.BattleData?.SideIndex) + return; + + targets = [moveChoice.User]; + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Foresight.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Foresight.cs new file mode 100644 index 0000000..e8c2a91 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Foresight.cs @@ -0,0 +1,19 @@ +using PkmnLib.Plugin.Gen7.Scripts.Pokemon; +using PkmnLib.Static; + +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "foresight")] +public class Foresight : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + var battleData = target.BattleData; + if (battleData == null) + return; + var typeLibrary = battleData.Battle.Library.StaticLibrary.Types; + target.Volatile.Add(new ForesightEffect(typeLibrary)); + target.ChangeStatBoost(Statistic.Evasion, (sbyte)-target.StatBoost.Evasion, false); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ForestsCurse.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ForestsCurse.cs new file mode 100644 index 0000000..8405f72 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ForestsCurse.cs @@ -0,0 +1,17 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "forests_curse")] +public class ForestsCurse : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + var battleData = target.BattleData; + if (battleData == null) + return; + var typeLibrary = battleData.Battle.Library.StaticLibrary.Types; + if (!typeLibrary.TryGetTypeIdentifier("grass", out var grassType)) + return; + target.AddType(grassType); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FoulPlay.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FoulPlay.cs new file mode 100644 index 0000000..2e92a0e --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FoulPlay.cs @@ -0,0 +1,15 @@ +using PkmnLib.Static.Moves; + +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "foul_play")] +public class FoulPlay : Script +{ + /// + public override void ChangeOffensiveStatValue(IExecutingMove move, IPokemon target, byte hit, ref uint value) + { + value = move.UseMove.Category == MoveCategory.Physical + ? target.BoostedStats.Attack + : target.BoostedStats.SpecialAttack; + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FreezeDry.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FreezeDry.cs new file mode 100644 index 0000000..6031348 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FreezeDry.cs @@ -0,0 +1,41 @@ +using System.Linq; + +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "freeze_dry")] +public class FreezeDry : Script +{ + /// + public override void ChangeEffectiveness(IExecutingMove move, IPokemon target, byte hit, ref float effectiveness) + { + var battleData = target.BattleData; + if (battleData == null) + return; + + var typeLibrary = battleData.Battle.Library.StaticLibrary.Types; + if (!typeLibrary.TryGetTypeIdentifier("water", out var waterType)) + return; + + if (target.Types.Contains(waterType)) + { + var effectivenessWithoutWater = target.Types + .Where(x => x != waterType) + .Select(x => typeLibrary.GetEffectiveness(x, target.Types)) + .Aggregate(1f, (a, b) => a * b); + effectiveness = effectivenessWithoutWater * 2; + } + } + + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + var battleData = target.BattleData; + if (battleData == null) + return; + + if (battleData.Battle.Random.EffectChance(10, move, target, hit)) + { + target.SetStatus("frozen"); + } + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/OneHitKo.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/OneHitKo.cs new file mode 100644 index 0000000..bfe5ad0 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/OneHitKo.cs @@ -0,0 +1,25 @@ +using PkmnLib.Static.Utils; + +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "one_hit_ko")] +public class OneHitKo : Script +{ + /// + public override void ChangeAccuracy(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref int modifiedAccuracy) + { + var levelDifference = executingMove.User.Level - target.Level; + if (levelDifference < 0) + { + executingMove.GetHitData(target, hitIndex).Fail(); + return; + } + modifiedAccuracy = 30 + levelDifference; + } + + /// + public override void ChangeMoveDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage) + { + damage = target.BoostedStats.Hp.MultiplyOrMax(10); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/ChargeFlyEffect.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/ChargeFlyEffect.cs new file mode 100644 index 0000000..037f9b3 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/ChargeFlyEffect.cs @@ -0,0 +1,35 @@ +using PkmnLib.Plugin.Gen7.Scripts.Utils; + +namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon; + +[Script(ScriptCategory.Pokemon, "charge_fly")] +public class ChargeFlyEffect : Script +{ + private readonly IPokemon _owner; + + public ChargeFlyEffect(IPokemon owner) + { + _owner = owner; + } + + /// + public override void ForceTurnSelection(byte sideIndex, byte position, ref ITurnChoice? choice) + { + var opposingSideIndex = (byte)(_owner.BattleData?.SideIndex == 0 ? 1 : 0); + choice = TurnChoiceHelper.CreateMoveChoice(_owner, "fly", opposingSideIndex, position); + } + + /// + public override void BlockIncomingHit(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref bool block) + { + if (!executingMove.UseMove.HasFlag("hit_flying")) + block = true; + } + + /// + public override void ChangeIncomingMoveDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage) + { + if (!move.UseMove.HasFlag("effective_against_fly")) + damage *= 2; + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/FireSpinEffect.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/FireSpinEffect.cs new file mode 100644 index 0000000..99e9555 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/FireSpinEffect.cs @@ -0,0 +1,24 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon; + +[Script(ScriptCategory.Pokemon, "fire_spin")] +public class FireSpinEffect : Script +{ + private readonly IPokemon _owner; + + public FireSpinEffect(IPokemon owner) + { + _owner = owner; + } + + /// + public override void OnEndTurn(IBattle battle) + { + _owner.Damage(_owner.BoostedStats.Hp / 8, DamageSource.Misc); + } + + /// + public override void PreventSelfRunAway(IFleeChoice choice, ref bool prevent) => prevent = true; + + /// + public override void PreventSelfSwitch(ISwitchChoice choice, ref bool prevent) => prevent = true; +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/FocusPunchEffect.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/FocusPunchEffect.cs new file mode 100644 index 0000000..0c32852 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/FocusPunchEffect.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; + +namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon; + +[Script(ScriptCategory.Pokemon, "focus_punch")] +public class FocusPunchEffect : Script +{ + public bool WasHit { get; private set; } + + /// + public override void OnIncomingHit(IExecutingMove move, IPokemon target, byte hit) + { + WasHit = true; + target.BattleData?.Battle.EventHook.Invoke(new DialogEvent("focus_punch_lost_focus", + new Dictionary() + { + { "pokemon", target } + })); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/ForesightEffect.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/ForesightEffect.cs new file mode 100644 index 0000000..cd99df9 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/ForesightEffect.cs @@ -0,0 +1,40 @@ +using System.Linq; +using PkmnLib.Static; +using PkmnLib.Static.Libraries; + +namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon; + +[Script(ScriptCategory.Pokemon, "foresight")] +public class ForesightEffect : Script +{ + private readonly IReadOnlyTypeLibrary _typeLibrary; + private readonly TypeIdentifier _normalType; + private readonly TypeIdentifier _fightingType; + private readonly TypeIdentifier _ghostType; + + public ForesightEffect(IReadOnlyTypeLibrary typeLibrary) + { + _typeLibrary = typeLibrary; + typeLibrary.TryGetTypeIdentifier("normal", out _normalType); + typeLibrary.TryGetTypeIdentifier("fighting", out _fightingType); + typeLibrary.TryGetTypeIdentifier("ghost", out _ghostType); + } + + /// + public override void PreventStatBoostChange(IPokemon target, Statistic stat, sbyte amount, bool selfInflicted, ref bool prevent) + { + if (stat == Statistic.Evasion) + prevent = true; + } + + /// + public override void ChangeEffectiveness(IExecutingMove move, IPokemon target, byte hit, ref float effectiveness) + { + + var hitData = move.GetHitData(target, hit); + if (hitData.Type == _normalType && target.Types.Contains(_fightingType)) + effectiveness = _typeLibrary.GetEffectiveness(_normalType, target.Types.Where(x => x != _ghostType)); + else if (hitData.Type == _fightingType && target.Types.Contains(_ghostType)) + effectiveness = _typeLibrary.GetEffectiveness(_fightingType, target.Types.Where(x => x != _ghostType)); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/IncreasedCriticalStage.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/IncreasedCriticalStage.cs new file mode 100644 index 0000000..60517a4 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/IncreasedCriticalStage.cs @@ -0,0 +1,17 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon; + +[Script(ScriptCategory.Pokemon, "increased_critical_stage")] +public class IncreasedCriticalStage : Script +{ + /// + public override void ChangeCriticalStage(IExecutingMove move, IPokemon target, byte hit, ref byte stage) + { + // Extreme edge case, should never happen + if (stage == byte.MaxValue) + { + move.GetHitData(target, hit).Fail(); + return; + } + stage += 1; + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Terrain/GrassyTerrain.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Terrain/GrassyTerrain.cs new file mode 100644 index 0000000..82aebff --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Terrain/GrassyTerrain.cs @@ -0,0 +1,7 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Terrain; + +[Script(ScriptCategory.Terrain, "grassy_terrain")] +public class GrassyTerrain : Script +{ + // TODO: Implement Electric Terrain +} \ No newline at end of file