From a17cb92c5aa4c3f2e0a56f9812848da9cfa8979a Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sat, 17 May 2025 17:44:15 +0200 Subject: [PATCH] Implements a bunch more moves --- .../BattleFlow/MoveTurnExecutor.cs | 13 +- .../{Models => }/BattleFlow/TargetResolver.cs | 3 +- .../{Models => }/BattleFlow/TurnRunner.cs | 3 +- PkmnLib.Dynamic/Models/Battle.cs | 2 +- PkmnLib.Dynamic/ScriptHandling/Script.cs | 10 + PkmnLib.Static/Utils/Random.cs | 10 + .../DataTests/MoveDataTests.cs | 3 +- .../LibraryHelpers.cs | 17 + Plugins/PkmnLib.Plugin.Gen7/Data/Moves.jsonc | 367 +++++++++++++++--- .../Battling/Gen7BattleStatCalculator.cs | 5 +- .../Scripts/Battle/SnatchEffect.cs | 2 +- .../Scripts/Battle/TrickRoomEffect.cs | 21 + .../Scripts/Moves/ChangeTargetStats.cs | 8 + .../PkmnLib.Plugin.Gen7/Scripts/Moves/Dive.cs | 2 +- .../Scripts/Moves/Gravity.cs | 10 +- .../Scripts/Moves/Instruct.cs | 2 +- .../Scripts/Moves/SpitUp.cs | 1 + .../Scripts/Moves/Stockpile.cs | 4 - .../Scripts/Moves/SubstituteMove.cs | 27 ++ .../Scripts/Moves/SuckerPunch.cs | 18 + .../Scripts/Moves/SuperFang.cs | 12 + .../Scripts/Moves/Superpower.cs | 13 + .../Scripts/Moves/Swagger.cs | 12 + .../Scripts/Moves/Swallow.cs | 29 ++ .../Scripts/Moves/Switcheroo.cs | 24 ++ .../Scripts/Moves/Synchronoise.cs | 18 + .../Scripts/Moves/Synthesis.cs | 20 + .../Scripts/Moves/Tailwind.cs | 11 + .../Scripts/Moves/Taunt.cs | 13 + .../Scripts/Moves/TechnoBlast.cs | 23 ++ .../Scripts/Moves/Telekinesis.cs | 19 + .../Scripts/Moves/Teleport.cs | 7 + .../Scripts/Moves/ThousandArrows.cs | 23 ++ .../Scripts/Moves/ThousandWaves.cs | 13 + .../Scripts/Moves/ThroatChop.cs | 13 + .../Scripts/Moves/ThunderFang.cs | 22 ++ .../Scripts/Moves/TopsyTurvy.cs | 26 ++ .../Scripts/Moves/Torment.cs | 13 + .../Scripts/Moves/ToxicSpikes.cs | 13 + .../Scripts/Moves/ToxicThread.cs | 12 + .../Scripts/Moves/Transform.cs | 7 + .../Scripts/Moves/TriAttack.cs | 19 + .../Scripts/Moves/TrickOrTreat.cs | 14 + .../Scripts/Moves/TrickRoom.cs | 13 + .../Scripts/Moves/TripleKick.cs | 17 + .../Scripts/Moves/TrumpCard.cs | 20 + .../Scripts/Moves/Twineedle.cs | 17 + .../Scripts/Moves/UTurn.cs | 12 + .../Scripts/Moves/VenomDrench.cs | 18 + .../Scripts/Moves/Venoshock.cs | 15 + .../Scripts/Pokemon/PursuitEffect.cs | 2 +- .../Scripts/Pokemon/StockpileEffect.cs | 31 ++ .../Scripts/Pokemon/SubstituteEffect.cs | 24 ++ .../Scripts/Pokemon/TauntEffect.cs | 34 ++ .../Scripts/Pokemon/TelekinesisEffect.cs | 26 ++ .../Scripts/Pokemon/ThousandArrowsEffect.cs | 23 ++ .../Scripts/Pokemon/ThousandWavesEffect.cs | 11 + .../Scripts/Pokemon/ThroatChopEffect.cs | 29 ++ .../Scripts/Pokemon/TormentEffect.cs | 25 ++ .../Scripts/Side/SpotlightEffect.cs | 2 +- .../Scripts/Side/TailwindEffect.cs | 21 + .../Scripts/Side/ToxicSpikesEffect.cs | 17 + 62 files changed, 1180 insertions(+), 81 deletions(-) rename PkmnLib.Dynamic/{Models => }/BattleFlow/MoveTurnExecutor.cs (97%) rename PkmnLib.Dynamic/{Models => }/BattleFlow/TargetResolver.cs (98%) rename PkmnLib.Dynamic/{Models => }/BattleFlow/TurnRunner.cs (98%) rename {PkmnLib.Tests => Plugins/PkmnLib.Plugin.Gen7.Tests}/DataTests/MoveDataTests.cs (98%) create mode 100644 Plugins/PkmnLib.Plugin.Gen7.Tests/LibraryHelpers.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Battle/TrickRoomEffect.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/SubstituteMove.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/SuckerPunch.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/SuperFang.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Superpower.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Swagger.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Swallow.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Switcheroo.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Synchronoise.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Synthesis.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Tailwind.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Taunt.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/TechnoBlast.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Telekinesis.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Teleport.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ThousandArrows.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ThousandWaves.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ThroatChop.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ThunderFang.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/TopsyTurvy.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Torment.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ToxicSpikes.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ToxicThread.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Transform.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/TriAttack.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/TrickOrTreat.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/TrickRoom.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/TripleKick.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/TrumpCard.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Twineedle.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/UTurn.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/VenomDrench.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Venoshock.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/SubstituteEffect.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/TauntEffect.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/TelekinesisEffect.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/ThousandArrowsEffect.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/ThousandWavesEffect.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/ThroatChopEffect.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/TormentEffect.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Side/TailwindEffect.cs create mode 100644 Plugins/PkmnLib.Plugin.Gen7/Scripts/Side/ToxicSpikesEffect.cs diff --git a/PkmnLib.Dynamic/Models/BattleFlow/MoveTurnExecutor.cs b/PkmnLib.Dynamic/BattleFlow/MoveTurnExecutor.cs similarity index 97% rename from PkmnLib.Dynamic/Models/BattleFlow/MoveTurnExecutor.cs rename to PkmnLib.Dynamic/BattleFlow/MoveTurnExecutor.cs index 811b14b..876a405 100644 --- a/PkmnLib.Dynamic/Models/BattleFlow/MoveTurnExecutor.cs +++ b/PkmnLib.Dynamic/BattleFlow/MoveTurnExecutor.cs @@ -1,11 +1,12 @@ using PkmnLib.Dynamic.Events; +using PkmnLib.Dynamic.Models; using PkmnLib.Dynamic.Models.Choices; using PkmnLib.Dynamic.ScriptHandling; using PkmnLib.Static; using PkmnLib.Static.Moves; using PkmnLib.Static.Utils; -namespace PkmnLib.Dynamic.Models.BattleFlow; +namespace PkmnLib.Dynamic.BattleFlow; /// /// Helper class for executing moves. @@ -50,6 +51,12 @@ public static class MoveTurnExecutor var targets = TargetResolver.ResolveTargets(battle, moveChoice.TargetSide, moveChoice.TargetPosition, targetType); moveChoice.RunScriptHook(x => x.ChangeTargets(moveChoice, ref targets)); + if (targets.Count == 0) + { + moveChoice.Fail(); + return; + } + var targetSide = battle.Sides[moveChoice.TargetSide]; targetSide.RunScriptHook(x => x.ChangeIncomingTargets(moveChoice, ref targets)); @@ -142,12 +149,14 @@ public static class MoveTurnExecutor var hitIndex = i; executingMove.RunScriptHook(x => x.OnBeforeHit(executingMove, target, hitIndex)); + var hitData = (HitData)executingMove.GetDataFromRawIndex(targetHitStat + i); + if (hitData.HasFailed) + break; var useMove = executingMove.UseMove; var hitType = (TypeIdentifier?)useMove.MoveType; executingMove.RunScriptHook(x => x.ChangeMoveType(executingMove, target, hitIndex, ref hitType)); - var hitData = (HitData)executingMove.GetDataFromRawIndex(targetHitStat + i); hitData.Type = hitType; var types = target.Types.ToList(); diff --git a/PkmnLib.Dynamic/Models/BattleFlow/TargetResolver.cs b/PkmnLib.Dynamic/BattleFlow/TargetResolver.cs similarity index 98% rename from PkmnLib.Dynamic/Models/BattleFlow/TargetResolver.cs rename to PkmnLib.Dynamic/BattleFlow/TargetResolver.cs index 76754d0..090edc4 100644 --- a/PkmnLib.Dynamic/Models/BattleFlow/TargetResolver.cs +++ b/PkmnLib.Dynamic/BattleFlow/TargetResolver.cs @@ -1,6 +1,7 @@ +using PkmnLib.Dynamic.Models; using PkmnLib.Static.Moves; -namespace PkmnLib.Dynamic.Models.BattleFlow; +namespace PkmnLib.Dynamic.BattleFlow; /// /// Helper class for resolving the targets of a move. diff --git a/PkmnLib.Dynamic/Models/BattleFlow/TurnRunner.cs b/PkmnLib.Dynamic/BattleFlow/TurnRunner.cs similarity index 98% rename from PkmnLib.Dynamic/Models/BattleFlow/TurnRunner.cs rename to PkmnLib.Dynamic/BattleFlow/TurnRunner.cs index 238bb4f..e6afc1c 100644 --- a/PkmnLib.Dynamic/Models/BattleFlow/TurnRunner.cs +++ b/PkmnLib.Dynamic/BattleFlow/TurnRunner.cs @@ -1,8 +1,9 @@ +using PkmnLib.Dynamic.Models; using PkmnLib.Dynamic.Models.Choices; using PkmnLib.Dynamic.ScriptHandling; using PkmnLib.Static.Utils; -namespace PkmnLib.Dynamic.Models.BattleFlow; +namespace PkmnLib.Dynamic.BattleFlow; /// /// Helper class for handling the running of a turn in a battle. diff --git a/PkmnLib.Dynamic/Models/Battle.cs b/PkmnLib.Dynamic/Models/Battle.cs index 9e54516..423d2b1 100644 --- a/PkmnLib.Dynamic/Models/Battle.cs +++ b/PkmnLib.Dynamic/Models/Battle.cs @@ -1,7 +1,7 @@ using System.Diagnostics.CodeAnalysis; +using PkmnLib.Dynamic.BattleFlow; using PkmnLib.Dynamic.Events; using PkmnLib.Dynamic.Libraries; -using PkmnLib.Dynamic.Models.BattleFlow; using PkmnLib.Dynamic.Models.Choices; using PkmnLib.Dynamic.ScriptHandling; using PkmnLib.Static; diff --git a/PkmnLib.Dynamic/ScriptHandling/Script.cs b/PkmnLib.Dynamic/ScriptHandling/Script.cs index 740afa9..65f47e8 100644 --- a/PkmnLib.Dynamic/ScriptHandling/Script.cs +++ b/PkmnLib.Dynamic/ScriptHandling/Script.cs @@ -646,6 +646,16 @@ public abstract class Script : IDeepCloneable { } + /// + /// This function allows a script to change the accuracy of a move that is incoming. The value for accuracy is in percentage. + /// A custom case goes when 255 is returned, in which case the entire accuracy check is skipped, and the move + /// will always hit. + /// + public virtual void ChangeIncomingAccuracy(IExecutingMove executingMove, IPokemon target, byte hitIndex, + ref int modifiedAccuracy) + { + } + /// /// This function allows a script to change the weather duration of a weather effect. /// diff --git a/PkmnLib.Static/Utils/Random.cs b/PkmnLib.Static/Utils/Random.cs index 497ed76..edc75ac 100644 --- a/PkmnLib.Static/Utils/Random.cs +++ b/PkmnLib.Static/Utils/Random.cs @@ -46,6 +46,8 @@ public interface IRandom /// Get a random boolean. 50% chance of being true. /// public bool GetBool(); + + public T OneOf(IReadOnlyList list); } /// @@ -94,4 +96,12 @@ public class RandomImpl : IRandom /// public bool GetBool() => _random.Next(2) == 1; + + /// + public T OneOf(IReadOnlyList list) + { + if (list.Count == 0) + throw new ArgumentException("List cannot be empty.", nameof(list)); + return list[GetInt(list.Count)]; + } } \ No newline at end of file diff --git a/PkmnLib.Tests/DataTests/MoveDataTests.cs b/Plugins/PkmnLib.Plugin.Gen7.Tests/DataTests/MoveDataTests.cs similarity index 98% rename from PkmnLib.Tests/DataTests/MoveDataTests.cs rename to Plugins/PkmnLib.Plugin.Gen7.Tests/DataTests/MoveDataTests.cs index 816b837..00a265b 100644 --- a/PkmnLib.Tests/DataTests/MoveDataTests.cs +++ b/Plugins/PkmnLib.Plugin.Gen7.Tests/DataTests/MoveDataTests.cs @@ -1,9 +1,8 @@ using PkmnLib.Dynamic.Libraries; using PkmnLib.Dynamic.ScriptHandling; using PkmnLib.Static.Moves; -using PkmnLib.Tests.Integration; -namespace PkmnLib.Tests.DataTests; +namespace PkmnLib.Plugin.Gen7.Tests.DataTests; public class MoveDataTests { diff --git a/Plugins/PkmnLib.Plugin.Gen7.Tests/LibraryHelpers.cs b/Plugins/PkmnLib.Plugin.Gen7.Tests/LibraryHelpers.cs new file mode 100644 index 0000000..04ab417 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7.Tests/LibraryHelpers.cs @@ -0,0 +1,17 @@ +using PkmnLib.Dynamic.Libraries; + +namespace PkmnLib.Plugin.Gen7.Tests; + +public static class LibraryHelpers +{ + public static IDynamicLibrary LoadLibrary() + { + var dynamicLibrary = DynamicLibraryImpl.Create([ + new Gen7Plugin(new Gen7PluginConfiguration + { + DamageCalculatorHasRandomness = false, + }), + ]); + return dynamicLibrary; + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Data/Moves.jsonc b/Plugins/PkmnLib.Plugin.Gen7/Data/Moves.jsonc index 21935fb..dd048ae 100755 --- a/Plugins/PkmnLib.Plugin.Gen7/Data/Moves.jsonc +++ b/Plugins/PkmnLib.Plugin.Gen7/Data/Moves.jsonc @@ -11080,7 +11080,10 @@ "flags": [ "snatch", "nonskybattle" - ] + ], + "effect": { + "name": "substitute" + } }, { "name": "subzero_slammer__physical", @@ -11092,6 +11095,7 @@ "target": "Any", "category": "physical", "flags": [] + // No secondary effect }, { "name": "subzero_slammer__special", @@ -11103,6 +11107,7 @@ "target": "Any", "category": "special", "flags": [] + // No secondary effect }, { "name": "sucker_punch", @@ -11117,7 +11122,10 @@ "contact", "protect", "mirror" - ] + ], + "effect": { + "name": "sucker_punch" + } }, { "name": "sunny_day", @@ -11128,7 +11136,13 @@ "priority": 0, "target": "All", "category": "status", - "flags": [] + "flags": [], + "effect": { + "name": "set_weather", + "parameters": { + "weather": "sunny" + } + } }, { "name": "sunsteel_strike", @@ -11143,7 +11157,10 @@ "contact", "protect", "mirror" - ] + ], + "effect": { + "name": "moongeist_beam" + } }, { "name": "super_fang", @@ -11158,7 +11175,10 @@ "contact", "protect", "mirror" - ] + ], + "effect": { + "name": "super_fang" + } }, { "name": "superpower", @@ -11173,7 +11193,10 @@ "contact", "protect", "mirror" - ] + ], + "effect": { + "name": "superpower" + } }, { "name": "supersonic", @@ -11190,7 +11213,10 @@ "mirror", "sound", "ignore-substitute" - ] + ], + "effect": { + "name": "confuse" + } }, { "name": "supersonic_skystrike__physical", @@ -11202,6 +11228,7 @@ "target": "Any", "category": "physical", "flags": [] + // No secondary effect }, { "name": "supersonic_skystrike__special", @@ -11213,6 +11240,7 @@ "target": "Any", "category": "special", "flags": [] + // No secondary effect }, { "name": "surf", @@ -11226,8 +11254,10 @@ "flags": [ "protect", "mirror", - "nonskybattle" + "nonskybattle", + "effective_against_underwater" ] + // No secondary effect }, { "name": "swagger", @@ -11242,7 +11272,10 @@ "protect", "reflectable", "mirror" - ] + ], + "effect": { + "name": "swagger" + } }, { "name": "swallow", @@ -11256,7 +11289,10 @@ "flags": [ "snatch", "heal" - ] + ], + "effect": { + "name": "swallow" + } }, { "name": "sweet_kiss", @@ -11271,7 +11307,10 @@ "protect", "reflectable", "mirror" - ] + ], + "effect": { + "name": "confuse" + } }, { "name": "sweet_scent", @@ -11286,14 +11325,20 @@ "protect", "reflectable", "mirror" - ] + ], + "effect": { + "name": "change_target_evasion", + "parameters": { + "amount": -1 + } + } }, { "name": "swift", "type": "normal", "power": 60, "pp": 20, - "accuracy": 0, + "accuracy": 255, "priority": 0, "target": "AllOpponent", "category": "special", @@ -11301,6 +11346,7 @@ "protect", "mirror" ] + // No secondary effect }, { "name": "switcheroo", @@ -11314,7 +11360,10 @@ "flags": [ "protect", "mirror" - ] + ], + "effect": { + "name": "switcheroo" + } }, { "name": "swords_dance", @@ -11328,7 +11377,13 @@ "flags": [ "snatch", "dance" - ] + ], + "effect": { + "name": "change_user_attack", + "parameters": { + "amount": 2 + } + } }, { "name": "synchronoise", @@ -11342,7 +11397,10 @@ "flags": [ "protect", "mirror" - ] + ], + "effect": { + "name": "synchronoise" + } }, { "name": "synthesis", @@ -11356,7 +11414,10 @@ "flags": [ "snatch", "heal" - ] + ], + "effect": { + "name": "synthesis" + } }, { "name": "tackle", @@ -11372,6 +11433,7 @@ "protect", "mirror" ] + // No secondary effect }, { "name": "tail_glow", @@ -11384,7 +11446,13 @@ "category": "status", "flags": [ "snatch" - ] + ], + "effect": { + "name": "change_user_special_attack", + "parameters": { + "amount": 3 + } + } }, { "name": "tail_slap", @@ -11399,7 +11467,10 @@ "contact", "protect", "mirror" - ] + ], + "effect": { + "name": "2_5_hit_move" + } }, { "name": "tail_whip", @@ -11414,7 +11485,13 @@ "protect", "reflectable", "mirror" - ] + ], + "effect": { + "name": "change_target_defense", + "parameters": { + "amount": -1 + } + } }, { "name": "tailwind", @@ -11427,7 +11504,10 @@ "category": "status", "flags": [ "snatch" - ] + ], + "effect": { + "name": "tailwind" + } }, { "name": "take_down", @@ -11442,7 +11522,13 @@ "contact", "protect", "mirror" - ] + ], + "effect": { + "name": "recoil", + "parameters": { + "recoilPercent": 0.25 + } + } }, { "name": "taunt", @@ -11460,7 +11546,10 @@ "ignore-substitute", "mental", "limit_move_choice" - ] + ], + "effect": { + "name": "taunt" + } }, { "name": "tearful_look", @@ -11474,7 +11563,14 @@ "flags": [ "reflectable", "mirror" - ] + ], + "effect": { + "name": "change_multiple_target_stat_boosts", + "parameters": { + "attack": -1, + "specialAttack": -1 + } + } }, { "name": "techno_blast", @@ -11488,7 +11584,10 @@ "flags": [ "protect", "mirror" - ] + ], + "effect": { + "name": "techno_blast" + } }, { "name": "tectonic_rage__physical", @@ -11500,6 +11599,7 @@ "target": "Any", "category": "physical", "flags": [] + // No secondary effect }, { "name": "tectonic_rage__special", @@ -11511,6 +11611,7 @@ "target": "Any", "category": "special", "flags": [] + // No secondary effect }, { "name": "teeter_dance", @@ -11525,7 +11626,10 @@ "protect", "mirror", "dance" - ] + ], + "effect": { + "name": "confuse" + } }, { "name": "telekinesis", @@ -11541,7 +11645,10 @@ "reflectable", "mirror", "gravity" - ] + ], + "effect": { + "name": "telekinesis" + } }, { "name": "teleport", @@ -11552,7 +11659,10 @@ "priority": 0, "target": "Self", "category": "status", - "flags": [] + "flags": [], + "effect": { + "name": "teleport" + } }, { "name": "thief", @@ -11567,7 +11677,10 @@ "contact", "protect", "mirror" - ] + ], + "effect": { + "name": "covet" + } }, { "name": "thousand_arrows", @@ -11581,8 +11694,12 @@ "flags": [ "protect", "mirror", - "nonskybattle" - ] + "nonskybattle", + "hit_flying" + ], + "effect": { + "name": "thousand_arrows" + } }, { "name": "thousand_waves", @@ -11597,7 +11714,10 @@ "protect", "mirror", "nonskybattle" - ] + ], + "effect": { + "name": "thousand_waves" + } }, { "name": "thrash", @@ -11630,7 +11750,10 @@ "contact", "protect", "mirror" - ] + ], + "effect": { + "name": "throat_chop" + } }, { "name": "thunder", @@ -11645,7 +11768,14 @@ "protect", "mirror", "hit_flying" - ] + ], + "effect": { + "name": "set_status", + "chance": 30, + "parameters": { + "status": "paralyzed" + } + } }, { "name": "thunder_fang", @@ -11661,7 +11791,10 @@ "protect", "mirror", "bite" - ] + ], + "effect": { + "name": "thunder_fang" + } }, { "name": "thunder_punch", @@ -11677,7 +11810,14 @@ "protect", "mirror", "punch" - ] + ], + "effect": { + "name": "set_status", + "chance": 10, + "parameters": { + "status": "paralyzed" + } + } }, { "name": "thunder_shock", @@ -11691,7 +11831,14 @@ "flags": [ "protect", "mirror" - ] + ], + "effect": { + "name": "set_status", + "chance": 10, + "parameters": { + "status": "paralyzed" + } + } }, { "name": "thunder_wave", @@ -11706,7 +11853,13 @@ "protect", "reflectable", "mirror" - ] + ], + "effect": { + "name": "set_status", + "parameters": { + "status": "paralyzed" + } + } }, { "name": "thunderbolt", @@ -11720,7 +11873,14 @@ "flags": [ "protect", "mirror" - ] + ], + "effect": { + "name": "set_status", + "chance": 10, + "parameters": { + "status": "paralyzed" + } + } }, { "name": "tickle", @@ -11735,7 +11895,14 @@ "protect", "reflectable", "mirror" - ] + ], + "effect": { + "name": "change_multiple_target_stat_boosts", + "parameters": { + "attack": -1, + "defense": -1 + } + } }, { "name": "topsy_turvy", @@ -11750,7 +11917,10 @@ "protect", "reflectable", "mirror" - ] + ], + "effect": { + "name": "topsy_turvy" + } }, { "name": "torment", @@ -11768,7 +11938,10 @@ "ignore-substitute", "mental", "limit_move_choice" - ] + ], + "effect": { + "name": "torment" + } }, { "name": "toxic", @@ -11783,7 +11956,13 @@ "protect", "reflectable", "mirror" - ] + ], + "effect": { + "name": "set_status", + "parameters": { + "status": "badly_poisoned" + } + } }, { "name": "toxic_spikes", @@ -11797,7 +11976,10 @@ "flags": [ "reflectable", "nonskybattle" - ] + ], + "effect": { + "name": "toxic_spikes" + } }, { "name": "toxic_thread", @@ -11812,7 +11994,10 @@ "protect", "reflectable", "mirror" - ] + ], + "effect": { + "name": "toxic_thread" + } }, { "name": "transform", @@ -11823,7 +12008,10 @@ "priority": 0, "target": "Any", "category": "status", - "flags": [] + "flags": [], + "effect": { + "name": "transform" + } }, { "name": "tri_attack", @@ -11837,7 +12025,10 @@ "flags": [ "protect", "mirror" - ] + ], + "effect": { + "name": "tri_attack" + } }, { "name": "trick", @@ -11851,7 +12042,10 @@ "flags": [ "protect", "mirror" - ] + ], + "effect": { + "name": "switcheroo" + } }, { "name": "trick_or_treat", @@ -11866,7 +12060,10 @@ "protect", "reflectable", "mirror" - ] + ], + "effect": { + "name": "trick_or_treat" + } }, { "name": "trick_room", @@ -11879,7 +12076,10 @@ "category": "status", "flags": [ "mirror" - ] + ], + "effect": { + "name": "trick_room" + } }, { "name": "triple_kick", @@ -11894,7 +12094,10 @@ "contact", "protect", "mirror" - ] + ], + "effect": { + "name": "triple_kick" + } }, { "name": "trop_kick", @@ -11909,7 +12112,13 @@ "contact", "protect", "mirror" - ] + ], + "effect": { + "name": "change_target_attack", + "parameters": { + "amount": -1 + } + } }, { "name": "trump_card", @@ -11924,7 +12133,10 @@ "contact", "protect", "mirror" - ] + ], + "effect": { + "name": "trump_card" + } }, { "name": "twineedle", @@ -11938,7 +12150,10 @@ "flags": [ "protect", "mirror" - ] + ], + "effect": { + "name": "twineedle" + } }, { "name": "twinkle_tackle__physical", @@ -11950,6 +12165,7 @@ "target": "Any", "category": "physical", "flags": [] + // No secondary effect }, { "name": "twinkle_tackle__special", @@ -11961,6 +12177,7 @@ "target": "Any", "category": "special", "flags": [] + // No secondary effect }, { "name": "twister", @@ -11976,7 +12193,11 @@ "mirror", "hit_flying", "effective_against_fly" - ] + ], + "effect": { + "name": "flinch", + "chance": 20 + } }, { "name": "u_turn", @@ -11991,7 +12212,10 @@ "contact", "protect", "mirror" - ] + ], + "effect": { + "name": "u_turn" + } }, { "name": "uproar", @@ -12022,7 +12246,15 @@ "contact", "protect", "mirror" - ] + ], + "effect": { + "name": "change_multiple_user_stat_boosts", + "parameters": { + "defense": -1, + "specialDefense": -1, + "speed": -1 + } + } }, { "name": "vacuum_wave", @@ -12037,6 +12269,7 @@ "protect", "mirror" ] + // No secondary effect }, { "name": "venom_drench", @@ -12051,7 +12284,10 @@ "protect", "reflectable", "mirror" - ] + ], + "effect": { + "name": "venom_drench" + } }, { "name": "venoshock", @@ -12065,7 +12301,10 @@ "flags": [ "protect", "mirror" - ] + ], + "effect": { + "name": "venoshock" + } }, { "name": "vice_grip", @@ -12081,6 +12320,7 @@ "protect", "mirror" ] + // No secondary effect }, { "name": "vine_whip", @@ -12096,13 +12336,14 @@ "protect", "mirror" ] + // No secondary effect }, { "name": "vital_throw", "type": "fighting", "power": 70, "pp": 10, - "accuracy": 0, + "accuracy": 255, "priority": -1, "target": "Any", "category": "physical", @@ -12111,6 +12352,7 @@ "protect", "mirror" ] + // No secondary effect }, { "name": "volt_switch", @@ -12124,7 +12366,10 @@ "flags": [ "protect", "mirror" - ] + ], + "effect": { + "name": "u_turn" + } }, { "name": "volt_tackle", diff --git a/Plugins/PkmnLib.Plugin.Gen7/Libraries/Battling/Gen7BattleStatCalculator.cs b/Plugins/PkmnLib.Plugin.Gen7/Libraries/Battling/Gen7BattleStatCalculator.cs index 347af3a..85a44ec 100644 --- a/Plugins/PkmnLib.Plugin.Gen7/Libraries/Battling/Gen7BattleStatCalculator.cs +++ b/Plugins/PkmnLib.Plugin.Gen7/Libraries/Battling/Gen7BattleStatCalculator.cs @@ -58,7 +58,10 @@ public class Gen7BattleStatCalculator : IBattleStatCalculator var modifiedAccuracy = (int)(moveAccuracy * accuracyModifier); // ReSharper disable once AccessToModifiedClosure executingMove.RunScriptHook(x => x.ChangeAccuracy(executingMove, target, hitIndex, ref modifiedAccuracy)); - if (modifiedAccuracy == 255) + if (modifiedAccuracy >= 255) + return 255; + target.RunScriptHook(x => x.ChangeIncomingAccuracy(executingMove, target, hitIndex, ref modifiedAccuracy)); + if (modifiedAccuracy >= 255) return 255; var targetEvasion = target.StatBoost.Evasion; var ignoreEvasion = false; diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Battle/SnatchEffect.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Battle/SnatchEffect.cs index e3634f2..332dabb 100644 --- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Battle/SnatchEffect.cs +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Battle/SnatchEffect.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; -using PkmnLib.Dynamic.Models.BattleFlow; +using PkmnLib.Dynamic.BattleFlow; namespace PkmnLib.Plugin.Gen7.Scripts.Battle; diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Battle/TrickRoomEffect.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Battle/TrickRoomEffect.cs new file mode 100644 index 0000000..77a94cc --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Battle/TrickRoomEffect.cs @@ -0,0 +1,21 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Battle; + +[Script(ScriptCategory.Battle, "trick_room")] +public class TrickRoomEffect : Script +{ + private int _turnsLeft = 5; + + /// + public override void ChangeSpeed(ITurnChoice choice, ref uint speed) + { + speed = uint.MaxValue - speed; + } + + /// + public override void OnEndTurn(IBattle battle) + { + _turnsLeft--; + if (_turnsLeft <= 0) + RemoveSelf(); + } +} \ 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 daea692..6c5ee41 100644 --- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ChangeTargetStats.cs +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ChangeTargetStats.cs @@ -83,4 +83,12 @@ public class ChangeTargetAccuracy : ChangeTargetStats public ChangeTargetAccuracy() : base(Statistic.Accuracy) { } +} + +[Script(ScriptCategory.Move, "change_target_evasion")] +public class ChangeTargetEvasion : ChangeTargetStats +{ + public ChangeTargetEvasion() : base(Statistic.Evasion) + { + } } \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Dive.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Dive.cs index 645756c..df89c39 100644 --- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Dive.cs +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Dive.cs @@ -12,7 +12,7 @@ public class Dive : Script if (move.User.Volatile.Contains()) return; - move.User.Volatile.Add(new DigEffect(move.User)); + move.User.Volatile.Add(new DiveEffect(move.User)); move.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("dive_charge", new Dictionary { { "user", move.User }, diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Gravity.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Gravity.cs index ab599ff..14c0f39 100644 --- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Gravity.cs +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Gravity.cs @@ -22,17 +22,21 @@ public class Gravity : Script return script; }); + var chargeBounceEffect = ScriptUtils.ResolveName(); + var flyEffect = ScriptUtils.ResolveName(); + var skyDropEffect = ScriptUtils.ResolveName(); + var telekinesisEffect = ScriptUtils.ResolveName(); + foreach (var pokemon in battleData.Battle.Sides.SelectMany(x => x.Pokemon).WhereNotNull()) { - var chargeBounceEffect = ScriptUtils.ResolveName(); if (pokemon.Volatile.Contains(chargeBounceEffect)) pokemon.Volatile.Remove(chargeBounceEffect); - var flyEffect = ScriptUtils.ResolveName(); if (pokemon.Volatile.Contains(flyEffect)) pokemon.Volatile.Remove(flyEffect); - var skyDropEffect = ScriptUtils.ResolveName(); if (pokemon.Volatile.Contains(skyDropEffect)) pokemon.Volatile.Remove(skyDropEffect); + if (pokemon.Volatile.Contains(telekinesisEffect)) + pokemon.Volatile.Remove(telekinesisEffect); } } } \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Instruct.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Instruct.cs index 235cd1c..f4ea65d 100644 --- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Instruct.cs +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Instruct.cs @@ -1,5 +1,5 @@ using System.Linq; -using PkmnLib.Dynamic.Models.BattleFlow; +using PkmnLib.Dynamic.BattleFlow; namespace PkmnLib.Plugin.Gen7.Scripts.Moves; diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/SpitUp.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/SpitUp.cs index 9e8e58f..d06f5e5 100644 --- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/SpitUp.cs +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/SpitUp.cs @@ -17,5 +17,6 @@ public class SpitUp : Script } var stockpileCount = stockpileEffect.StockpileCount; basePower = basePower.MultiplyOrMax(stockpileCount); + move.User.Volatile.Remove(); } } \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Stockpile.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Stockpile.cs index 31107be..4563c20 100644 --- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Stockpile.cs +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Stockpile.cs @@ -8,10 +8,6 @@ public class Stockpile : Script /// public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) { - EventBatchId batchId = new(); - move.User.ChangeStatBoost(Statistic.Defense, 1, true, batchId); - move.User.ChangeStatBoost(Statistic.SpecialDefense, 1, true, batchId); - move.User.Volatile.StackOrAdd(ScriptUtils.ResolveName(), () => new StockpileEffect()); } } \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/SubstituteMove.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/SubstituteMove.cs new file mode 100644 index 0000000..2f8816c --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/SubstituteMove.cs @@ -0,0 +1,27 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +/// +/// Named 'SubstituteMove' to avoid namespace conflicts with NSubstitute. +/// +[Script(ScriptCategory.Move, "substitute")] +public class SubstituteMove : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + var hp = move.User.MaxHealth / 4; + if (move.User.CurrentHealth > hp) + { + move.User.Damage(hp, DamageSource.Misc, forceDamage: true); + move.User.Volatile.Add(new Pokemon.SubstituteEffect(hp)); + move.Battle.EventHook.Invoke(new DialogEvent("substitute", new Dictionary + { + { "user", move.User }, + })); + } + else + { + move.Battle.EventHook.Invoke(new DialogEvent("substitute_fail")); + } + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/SuckerPunch.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/SuckerPunch.cs new file mode 100644 index 0000000..21ad986 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/SuckerPunch.cs @@ -0,0 +1,18 @@ +using PkmnLib.Static.Moves; + +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "sucker_punch")] +public class SuckerPunch : Script +{ + /// + public override void OnBeforeHit(IExecutingMove move, IPokemon target, byte hitIndex) + { + var targetChoice = move.Battle.ChoiceQueue?.Where(x => x.User == target).FirstOrDefault(); + if (targetChoice is not IMoveChoice moveChoice || + moveChoice.ChosenMove.MoveData.Category == MoveCategory.Status) + { + move.GetHitData(target, hitIndex).Fail(); + } + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/SuperFang.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/SuperFang.cs new file mode 100644 index 0000000..aea1b66 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/SuperFang.cs @@ -0,0 +1,12 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "super_fang")] +public class SuperFang : Script +{ + /// + public override void ChangeMoveDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage) + { + // Super Fang always does 50% of the target's current HP + damage = target.CurrentHealth / 2; + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Superpower.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Superpower.cs new file mode 100644 index 0000000..1edeff9 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Superpower.cs @@ -0,0 +1,13 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "superpower")] +public class Superpower : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + EventBatchId eventBatch = new(); + move.User.ChangeStatBoost(Statistic.Attack, -1, true, eventBatch); + move.User.ChangeStatBoost(Statistic.Defense, -1, true, eventBatch); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Swagger.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Swagger.cs new file mode 100644 index 0000000..80961ac --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Swagger.cs @@ -0,0 +1,12 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "swagger")] +public class Swagger : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + target.ChangeStatBoost(Statistic.Attack, 2, false); + target.Volatile.Add(new Pokemon.Confusion()); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Swallow.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Swallow.cs new file mode 100644 index 0000000..c92c6a3 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Swallow.cs @@ -0,0 +1,29 @@ +using PkmnLib.Plugin.Gen7.Scripts.Pokemon; + +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "swallow")] +public class Swallow : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + var stockpileEffect = move.User.Volatile.Get(); + if (stockpileEffect == null || stockpileEffect.StockpileCount == 0) + { + move.GetHitData(target, hit).Fail(); + return; + } + var stockpileCount = stockpileEffect.StockpileCount; + + var modifier = stockpileCount switch + { + 1 => 0.25f, + 2 => 0.5f, + _ => 1f, + }; + var heal = move.User.MaxHealth * modifier; + move.User.Heal((uint)heal); + move.User.Volatile.Remove(); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Switcheroo.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Switcheroo.cs new file mode 100644 index 0000000..66170af --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Switcheroo.cs @@ -0,0 +1,24 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "switcheroo")] +public class Switcheroo : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + var targetHeldItem = target.HeldItem; + var userHeldItem = move.User.HeldItem; + if (targetHeldItem?.Category is ItemCategory.FormChanger or ItemCategory.Mail || + userHeldItem?.Category is ItemCategory.FormChanger or ItemCategory.Mail) + { + // Cannot switch items if one of them is a form changer or mail + move.GetHitData(target, hit).Fail(); + return; + } + targetHeldItem = target.RemoveHeldItem(); + userHeldItem = move.User.RemoveHeldItem(); + + _ = target.SetHeldItem(userHeldItem); + _ = move.User.SetHeldItem(targetHeldItem); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Synchronoise.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Synchronoise.cs new file mode 100644 index 0000000..5680571 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Synchronoise.cs @@ -0,0 +1,18 @@ +using PkmnLib.Static.Utils; + +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "synchronoise")] +public class Synchronoise : Script +{ + /// + public override void ChangeTargets(IMoveChoice moveChoice, ref IReadOnlyList targets) + { + var battleData = moveChoice.User.BattleData; + if (battleData == null) + throw new InvalidOperationException("Battle data is null."); + + targets = battleData.Battle.Sides.SelectMany(x => x.Pokemon).WhereNotNull() + .Where(x => x.Types.Any(y => moveChoice.User.Types.Contains(y))).ToList(); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Synthesis.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Synthesis.cs new file mode 100644 index 0000000..a09926e --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Synthesis.cs @@ -0,0 +1,20 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "synthesis")] +public class Synthesis : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + var healModifier = 0.5f; + var weatherName = target.BattleData?.Battle?.WeatherName; + if (weatherName == ScriptUtils.ResolveName()) + healModifier = 2 / 3f; + else if (weatherName == ScriptUtils.ResolveName() || + weatherName == ScriptUtils.ResolveName() || + weatherName == ScriptUtils.ResolveName()) + healModifier = 1 / 4f; + + move.User.Heal((uint)(move.User.MaxHealth * healModifier)); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Tailwind.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Tailwind.cs new file mode 100644 index 0000000..14265c6 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Tailwind.cs @@ -0,0 +1,11 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "tailwind")] +public class Tailwind : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + move.User.BattleData?.BattleSide.VolatileScripts.Add(new Side.TailwindEffect()); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Taunt.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Taunt.cs new file mode 100644 index 0000000..07de5ab --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Taunt.cs @@ -0,0 +1,13 @@ +using PkmnLib.Plugin.Gen7.Scripts.Pokemon; + +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "taunt")] +public class Taunt : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + target.Volatile.Add(new TauntEffect(4)); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/TechnoBlast.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/TechnoBlast.cs new file mode 100644 index 0000000..5d51b57 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/TechnoBlast.cs @@ -0,0 +1,23 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "techno_blast")] +public class TechnoBlast : Script +{ + /// + public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier? moveType) + { + var heldItem = move.User.HeldItem; + if (heldItem == null) + return; + var typeLibrary = target.Library.StaticLibrary.Types; + + moveType = heldItem.Name.ToString().ToLowerInvariant() switch + { + "burn_drive" when typeLibrary.TryGetTypeIdentifier("fire", out var fire) => fire, + "chill_drive" when typeLibrary.TryGetTypeIdentifier("ice", out var ice) => ice, + "douse_drive" when typeLibrary.TryGetTypeIdentifier("water", out var water) => water, + "shock_drive" when typeLibrary.TryGetTypeIdentifier("electric", out var electric) => electric, + _ => moveType, + }; + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Telekinesis.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Telekinesis.cs new file mode 100644 index 0000000..48fdde5 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Telekinesis.cs @@ -0,0 +1,19 @@ +using PkmnLib.Plugin.Gen7.Scripts.Pokemon; + +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "telekinesis")] +public class Telekinesis : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + if (move.Battle.Volatile.Contains()) + { + move.GetHitData(target, hit).Fail(); + return; + } + + target.Volatile.Add(new TelekinesisEffect()); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Teleport.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Teleport.cs new file mode 100644 index 0000000..391662e --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Teleport.cs @@ -0,0 +1,7 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "teleport")] +public class Teleport : Script +{ + // FIXME: Implement teleport +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ThousandArrows.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ThousandArrows.cs new file mode 100644 index 0000000..197af4c --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ThousandArrows.cs @@ -0,0 +1,23 @@ +using PkmnLib.Plugin.Gen7.Scripts.Pokemon; + +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "thousand_arrows")] +public class ThousandArrows : Script +{ + /// + public override void ChangeEffectiveness(IExecutingMove move, IPokemon target, byte hit, ref float effectiveness) + { + if (effectiveness == 0) + effectiveness = 1; + } + + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + target.Volatile.Add(new ThousandArrowsEffect()); + target.Volatile.Remove(); + target.Volatile.Remove(); + target.Volatile.Remove(); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ThousandWaves.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ThousandWaves.cs new file mode 100644 index 0000000..8d3324d --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ThousandWaves.cs @@ -0,0 +1,13 @@ +using PkmnLib.Plugin.Gen7.Scripts.Pokemon; + +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "thousand_waves")] +public class ThousandWaves : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + target.Volatile.Add(new ThousandWavesEffect()); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ThroatChop.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ThroatChop.cs new file mode 100644 index 0000000..6666f7a --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ThroatChop.cs @@ -0,0 +1,13 @@ +using PkmnLib.Plugin.Gen7.Scripts.Pokemon; + +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "throat_chop")] +public class ThroatChop : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + target.Volatile.Add(new ThroatChopEffect()); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ThunderFang.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ThunderFang.cs new file mode 100644 index 0000000..ee28876 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ThunderFang.cs @@ -0,0 +1,22 @@ +using PkmnLib.Plugin.Gen7.Scripts.Pokemon; +using PkmnLib.Plugin.Gen7.Scripts.Status; + +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "thunder_fang")] +public class ThunderFang : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + var random = move.Battle.Random; + if (random.EffectChance(10, move, target, hit)) + { + target.SetStatus(ScriptUtils.ResolveName()); + } + if (random.EffectChance(10, move, target, hit)) + { + target.Volatile.Add(new FlinchEffect()); + } + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/TopsyTurvy.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/TopsyTurvy.cs new file mode 100644 index 0000000..71b5641 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/TopsyTurvy.cs @@ -0,0 +1,26 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "topsy_turvy")] +public class TopsyTurvy : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + EventBatchId batchId = new(); + var hasChanged = false; + foreach (Statistic stat in Enum.GetValues(typeof(Statistic))) + { + var statBoost = target.StatBoost.GetStatistic(stat); + if (statBoost == 0) + continue; + + hasChanged = true; + var newStatBoost = -statBoost; + target.ChangeStatBoost(stat, (sbyte)newStatBoost, target == move.User, batchId); + } + if (!hasChanged) + { + move.GetHitData(target, hit).Fail(); + } + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Torment.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Torment.cs new file mode 100644 index 0000000..b2195b5 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Torment.cs @@ -0,0 +1,13 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "torment")] +public class Torment : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + var lastTargetChoice = move.Battle.PreviousTurnChoices.SelectMany(x => x).Reverse().OfType() + .FirstOrDefault(x => x.User == target); + target.Volatile.Add(new Pokemon.TormentEffect(lastTargetChoice)); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ToxicSpikes.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ToxicSpikes.cs new file mode 100644 index 0000000..c300b7b --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ToxicSpikes.cs @@ -0,0 +1,13 @@ +using PkmnLib.Plugin.Gen7.Scripts.Side; + +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "toxic_spikes")] +public class ToxicSpikes : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + target.BattleData?.Battle.Volatile.Add(new ToxicSpikesEffect()); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ToxicThread.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ToxicThread.cs new file mode 100644 index 0000000..d72f630 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ToxicThread.cs @@ -0,0 +1,12 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "toxic_thread")] +public class ToxicThread : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + target.SetStatus(ScriptUtils.ResolveName()); + target.ChangeStatBoost(Statistic.Speed, -1, false); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Transform.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Transform.cs new file mode 100644 index 0000000..1e3c46c --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Transform.cs @@ -0,0 +1,7 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "transform")] +public class Transform : Script +{ + // FIXME: implement this +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/TriAttack.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/TriAttack.cs new file mode 100644 index 0000000..6f8fd58 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/TriAttack.cs @@ -0,0 +1,19 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "tri_attack")] +public class TriAttack : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + var random = move.Battle.Random; + if (!random.EffectChance(20, move, target, hit)) + return; + var status = random.OneOf([ + ScriptUtils.ResolveName(), + ScriptUtils.ResolveName(), + ScriptUtils.ResolveName(), + ]); + target.SetStatus(status); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/TrickOrTreat.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/TrickOrTreat.cs new file mode 100644 index 0000000..354fc87 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/TrickOrTreat.cs @@ -0,0 +1,14 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "trick_or_treat")] +public class TrickOrTreat : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + var library = move.Battle.Library.StaticLibrary.Types; + if (!library.TryGetTypeIdentifier("ghost", out var ghostType)) + return; + target.AddType(ghostType); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/TrickRoom.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/TrickRoom.cs new file mode 100644 index 0000000..7a2d011 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/TrickRoom.cs @@ -0,0 +1,13 @@ +using PkmnLib.Plugin.Gen7.Scripts.Battle; + +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "trick_room")] +public class TrickRoom : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + move.Battle.Volatile.Add(new TrickRoomEffect()); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/TripleKick.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/TripleKick.cs new file mode 100644 index 0000000..cb34a48 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/TripleKick.cs @@ -0,0 +1,17 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "triple_kick")] +public class TripleKick : Script +{ + /// + public override void ChangeNumberOfHits(IMoveChoice choice, ref byte numberOfHits) + { + numberOfHits = 3; + } + + /// + public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref ushort basePower) + { + basePower *= (ushort)(hit + 1); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/TrumpCard.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/TrumpCard.cs new file mode 100644 index 0000000..454bc19 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/TrumpCard.cs @@ -0,0 +1,20 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "trump_card")] +public class TrumpCard : Script +{ + /// + public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref ushort basePower) + { + var remainingPp = move.ChosenMove.CurrentPp; + + basePower = remainingPp switch + { + >= 4 => 40, + 3 => 50, + 2 => 60, + 1 => 80, + 0 => 200, + }; + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Twineedle.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Twineedle.cs new file mode 100644 index 0000000..892b07e --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Twineedle.cs @@ -0,0 +1,17 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "twineedle")] +public class Twineedle : Script +{ + /// + public override void ChangeNumberOfHits(IMoveChoice choice, ref byte numberOfHits) => numberOfHits = 2; + + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + if (move.Battle.Random.EffectChance(20, move, target, hit)) + { + target.SetStatus(ScriptUtils.ResolveName()); + } + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/UTurn.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/UTurn.cs new file mode 100644 index 0000000..eb64e12 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/UTurn.cs @@ -0,0 +1,12 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "u_turn")] +public class UTurn : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + var battleData = move.User.BattleData; + battleData?.BattleSide.SwapPokemon(battleData.Position, null); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/VenomDrench.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/VenomDrench.cs new file mode 100644 index 0000000..11337a8 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/VenomDrench.cs @@ -0,0 +1,18 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "venom_drench")] +public class VenomDrench : Script +{ + /// + public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit) + { + if (!target.HasStatus(ScriptUtils.ResolveName()) && + !target.HasStatus(ScriptUtils.ResolveName())) + return; + + EventBatchId eventBatch = new(); + target.ChangeStatBoost(Statistic.Attack, -1, false, eventBatch); + target.ChangeStatBoost(Statistic.SpecialAttack, -1, false, eventBatch); + target.ChangeStatBoost(Statistic.Speed, -1, false, eventBatch); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Venoshock.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Venoshock.cs new file mode 100644 index 0000000..99f1d9e --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Venoshock.cs @@ -0,0 +1,15 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Moves; + +[Script(ScriptCategory.Move, "venoshock")] +public class Venoshock : Script +{ + /// + public override void ChangeMoveDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage) + { + if (target.HasStatus(ScriptUtils.ResolveName()) || + target.HasStatus(ScriptUtils.ResolveName())) + { + damage *= 2; + } + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/PursuitEffect.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/PursuitEffect.cs index d68ef41..d7ca0df 100644 --- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/PursuitEffect.cs +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/PursuitEffect.cs @@ -1,4 +1,4 @@ -using PkmnLib.Dynamic.Models.BattleFlow; +using PkmnLib.Dynamic.BattleFlow; using PkmnLib.Static.Utils; namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon; diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/StockpileEffect.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/StockpileEffect.cs index 4ce7a1a..c63e2f3 100644 --- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/StockpileEffect.cs +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/StockpileEffect.cs @@ -3,14 +3,45 @@ namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon; [Script(ScriptCategory.Pokemon, "stockpile_effect")] public class StockpileEffect : Script { + private IPokemon? _pokemon; public int StockpileCount { get; set; } = 1; + /// + public override void OnAddedToParent(IScriptSource source) + { + if (source is not IPokemon pokemon) + { + throw new InvalidOperationException("StockpileEffect can only be added to a Pokemon."); + } + _pokemon = pokemon; + EventBatchId batchId = new(); + pokemon.ChangeStatBoost(Statistic.Defense, 1, true, batchId); + pokemon.ChangeStatBoost(Statistic.SpecialDefense, 1, true, batchId); + StockpileCount = 1; + } + /// public override void Stack() { if (StockpileCount < 3) { + EventBatchId batchId = new(); + _pokemon?.ChangeStatBoost(Statistic.Defense, 1, true, batchId); + _pokemon?.ChangeStatBoost(Statistic.SpecialDefense, 1, true, batchId); StockpileCount++; } } + + /// + public override void OnRemove() + { + if (_pokemon == null) + { + return; + } + EventBatchId batchId = new(); + _pokemon.ChangeStatBoost(Statistic.Defense, (sbyte)-StockpileCount, true, batchId); + _pokemon.ChangeStatBoost(Statistic.SpecialDefense, (sbyte)-StockpileCount, true, batchId); + StockpileCount = 0; + } } \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/SubstituteEffect.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/SubstituteEffect.cs new file mode 100644 index 0000000..d4bd91b --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/SubstituteEffect.cs @@ -0,0 +1,24 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon; + +[Script(ScriptCategory.Pokemon, "substitute")] +public class SubstituteEffect(uint health) : Script +{ + private uint _health = health; + + /// + public override void BlockIncomingHit(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref bool block) + { + if (executingMove.UseMove.HasFlag("ignore-substitute")) + return; + + block = true; + var damage = executingMove.GetHitData(target, hitIndex).Damage; + if (damage >= _health) + { + executingMove.Battle.EventHook.Invoke(new DialogEvent("substitute_broken")); + RemoveSelf(); + return; + } + _health -= damage; + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/TauntEffect.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/TauntEffect.cs new file mode 100644 index 0000000..76c6d75 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/TauntEffect.cs @@ -0,0 +1,34 @@ +using PkmnLib.Static.Moves; + +namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon; + +[Script(ScriptCategory.Pokemon, "taunt")] +public class TauntEffect(int turns) : Script +{ + private int _turns = turns; + + /// + public override void PreventMoveSelection(IMoveChoice choice, ref bool prevent) + { + if (choice.ChosenMove.MoveData.Category == MoveCategory.Status) + { + prevent = true; + } + } + + /// + public override void FailMove(IExecutingMove move, ref bool fail) + { + if (move.ChosenMove.MoveData.Category == MoveCategory.Status) + { + fail = true; + } + } + + public override void OnEndTurn(IBattle battle) + { + _turns--; + if (_turns <= 0) + RemoveSelf(); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/TelekinesisEffect.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/TelekinesisEffect.cs new file mode 100644 index 0000000..80e3140 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/TelekinesisEffect.cs @@ -0,0 +1,26 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon; + +[Script(ScriptCategory.Pokemon, "telekinesis")] +public class TelekinesisEffect : Script +{ + /// + public override void ChangeIncomingAccuracy(IExecutingMove executingMove, IPokemon target, byte hitIndex, + ref int modifiedAccuracy) + { + modifiedAccuracy = 255; + } + + /// + public override void IsFloating(IPokemon pokemon, ref bool isFloating) + { + isFloating = true; + } + + /// + public override void ChangeIncomingEffectiveness(IExecutingMove executingMove, IPokemon target, byte hitIndex, + ref float effectiveness) + { + if (executingMove.UseMove.MoveType.Name == "ground") + effectiveness = 0; + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/ThousandArrowsEffect.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/ThousandArrowsEffect.cs new file mode 100644 index 0000000..5a35530 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/ThousandArrowsEffect.cs @@ -0,0 +1,23 @@ +using PkmnLib.Static.Utils; + +namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon; + +[Script(ScriptCategory.Move, "thousand_arrows")] +public class ThousandArrowsEffect : Script +{ + /// + public override void IsFloating(IPokemon pokemon, ref bool isFloating) + { + isFloating = false; + } + + /// + public override void ChangeTypesForIncomingMove(IExecutingMove executingMove, IPokemon target, byte hitIndex, + IList types) + { + if (executingMove.UseMove.MoveType.Name == "ground") + { + types.RemoveAll(x => x.Name == "flying"); + } + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/ThousandWavesEffect.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/ThousandWavesEffect.cs new file mode 100644 index 0000000..6073698 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/ThousandWavesEffect.cs @@ -0,0 +1,11 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon; + +[Script(ScriptCategory.Pokemon, "thousand_waves")] +public class ThousandWavesEffect : Script +{ + /// + public override void PreventSelfSwitch(ISwitchChoice choice, ref bool prevent) => prevent = true; + + /// + public override void PreventSelfRunAway(IFleeChoice choice, ref bool prevent) => prevent = true; +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/ThroatChopEffect.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/ThroatChopEffect.cs new file mode 100644 index 0000000..756e344 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/ThroatChopEffect.cs @@ -0,0 +1,29 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon; + +[Script(ScriptCategory.Pokemon, "throat_chop")] +public class ThroatChopEffect : Script +{ + private int _turns = 3; + + /// + public override void PreventMoveSelection(IMoveChoice choice, ref bool prevent) + { + if (choice.ChosenMove.MoveData.HasFlag("sound")) + prevent = true; + } + + /// + public override void FailMove(IExecutingMove move, ref bool fail) + { + if (move.UseMove.HasFlag("sound")) + fail = true; + } + + /// + public override void OnEndTurn(IBattle battle) + { + _turns--; + if (_turns <= 0) + RemoveSelf(); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/TormentEffect.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/TormentEffect.cs new file mode 100644 index 0000000..cb59ae4 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/TormentEffect.cs @@ -0,0 +1,25 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon; + +[Script(ScriptCategory.Pokemon, "torment")] +public class TormentEffect(IMoveChoice? moveChoice) : Script +{ + private IMoveChoice? _moveChoice = moveChoice; + + /// + public override void PreventMoveSelection(IMoveChoice choice, ref bool prevent) + { + if (_moveChoice == null) + return; + if (choice.ChosenMove.MoveData == _moveChoice.ChosenMove.MoveData) + { + prevent = true; + } + } + + /// + public override void OnBeforeTurnStart(ITurnChoice choice) + { + if (choice is IMoveChoice moveChoice) + _moveChoice = moveChoice; + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Side/SpotlightEffect.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Side/SpotlightEffect.cs index cf5c59a..851d356 100644 --- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Side/SpotlightEffect.cs +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Side/SpotlightEffect.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using PkmnLib.Dynamic.Models.BattleFlow; +using PkmnLib.Dynamic.BattleFlow; namespace PkmnLib.Plugin.Gen7.Scripts.Side; diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Side/TailwindEffect.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Side/TailwindEffect.cs new file mode 100644 index 0000000..f8c20e9 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Side/TailwindEffect.cs @@ -0,0 +1,21 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Side; + +[Script(ScriptCategory.Side, "tailwind")] +public class TailwindEffect : Script +{ + private int _duration = 3; + + /// + public override void ChangeSpeed(ITurnChoice choice, ref uint speed) + { + speed *= 2; + } + + /// + public override void OnEndTurn(IBattle battle) + { + _duration--; + if (_duration <= 0) + RemoveSelf(); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Side/ToxicSpikesEffect.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Side/ToxicSpikesEffect.cs new file mode 100644 index 0000000..3d02fcb --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Side/ToxicSpikesEffect.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; + +namespace PkmnLib.Plugin.Gen7.Scripts.Side; + +[Script(ScriptCategory.Side, "toxic_spikes")] +public class ToxicSpikesEffect : Script +{ + /// + public override void OnSwitchIn(IPokemon pokemon, byte position) + { + if (pokemon.IsFloating) + return; + + pokemon.SetStatus(ScriptUtils.ResolveName()); + } +} \ No newline at end of file