diff --git a/PkmnLib.Dynamic/BattleFlow/MoveTurnExecutor.cs b/PkmnLib.Dynamic/BattleFlow/MoveTurnExecutor.cs
index 044cec5..03c2b2b 100644
--- a/PkmnLib.Dynamic/BattleFlow/MoveTurnExecutor.cs
+++ b/PkmnLib.Dynamic/BattleFlow/MoveTurnExecutor.cs
@@ -46,6 +46,7 @@ public static class MoveTurnExecutor
moveChoice.Script.Clear();
}
}
+ moveChoice.RunScriptHook(x => x.OnBeforeMoveChoice(moveChoice));
var targetType = useMove.Target;
var targets =
diff --git a/PkmnLib.Dynamic/BattleFlow/TurnRunner.cs b/PkmnLib.Dynamic/BattleFlow/TurnRunner.cs
index 1e9f605..defd738 100644
--- a/PkmnLib.Dynamic/BattleFlow/TurnRunner.cs
+++ b/PkmnLib.Dynamic/BattleFlow/TurnRunner.cs
@@ -89,6 +89,7 @@ public static class TurnRunner
{
case IMoveChoice moveChoice:
MoveTurnExecutor.ExecuteMoveChoice(battle, moveChoice);
+ moveChoice.RunScriptHook(script => script.OnAfterMoveChoice(moveChoice));
break;
case ISwitchChoice switchChoice:
ExecuteSwitchChoice(battle, switchChoice);
diff --git a/PkmnLib.Dynamic/ScriptHandling/Script.cs b/PkmnLib.Dynamic/ScriptHandling/Script.cs
index a991219..f3525e8 100644
--- a/PkmnLib.Dynamic/ScriptHandling/Script.cs
+++ b/PkmnLib.Dynamic/ScriptHandling/Script.cs
@@ -843,4 +843,12 @@ public abstract class Script : IDeepCloneable
public virtual void ModifyPPUsedForIncomingMove(IExecutingMove executingMove, ref byte ppUsed)
{
}
+
+ public virtual void OnBeforeMoveChoice(IMoveChoice moveChoice)
+ {
+ }
+
+ public virtual void OnAfterMoveChoice(IMoveChoice moveChoice)
+ {
+ }
}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Data/Abilities.jsonc b/Plugins/PkmnLib.Plugin.Gen7/Data/Abilities.jsonc
index 415b074..acfdc04 100755
--- a/Plugins/PkmnLib.Plugin.Gen7/Data/Abilities.jsonc
+++ b/Plugins/PkmnLib.Plugin.Gen7/Data/Abilities.jsonc
@@ -407,7 +407,11 @@
"effect": "overcoat"
},
"overgrow": {
- "effect": "overgrow"
+ "effect": "power_up_type_at_low_health",
+ "parameters": {
+ "type": "grass",
+ "threshold": 0.33333
+ }
},
"own_tempo": {
"effect": "own_tempo"
@@ -625,26 +629,67 @@
"storm_drain": {
"effect": "storm_drain"
},
- "strong_jaw": {},
- "sturdy": {},
- "suction_cups": {},
- "super_luck": {},
- "surge_surfer": {},
- "swarm": {},
- "sweet_veil": {},
- "swift_swim": {},
- "symbiosis": {},
- "synchronize": {},
- "tangled_feet": {},
- "tangling_hair": {},
- "technician": {},
- "telepathy": {},
- "teravolt": {},
- "thick_fat": {},
- "tinted_lens": {},
- "torrent": {},
- "tough_claws": {},
- "toxic_boost": {},
+ "strong_jaw": {
+ "effect": "strong_jaw"
+ },
+ "sturdy": {
+ "effect": "sturdy"
+ },
+ "suction_cups": {
+ "effect": "suction_cups"
+ },
+ "super_luck": {
+ "effect": "super_luck"
+ },
+ "surge_surfer": {
+ "effect": "surge_surfer"
+ },
+ "swarm": {
+ "effect": "power_up_type_at_low_health",
+ "parameters": {
+ "type": "bug",
+ "threshold": 0.33333
+ }
+ },
+ "sweet_veil": {
+ "effect": "sweet_veil"
+ },
+ "swift_swim": {
+ "effect": "swift_swim"
+ },
+ "symbiosis": {
+ "effect": "symbiosis"
+ },
+ "synchronize": {
+ "effect": "synchronize"
+ },
+ "tangled_feet": {
+ "effect": "tangled_feet"
+ },
+ "tangling_hair": {
+ "effect": "tangling_hair"
+ },
+ "technician": {
+ "effect": "technician"
+ },
+ "telepathy": {
+ "effect": "telepathy"
+ },
+ "teravolt": {
+ "effect": "teravolt"
+ },
+ "thick_fat": {
+ "effect": "thick_fat"
+ },
+ "tinted_lens": {
+ "effect": "tinted_lens"
+ },
+ "tough_claws": {
+ "effect": "tough_claws"
+ },
+ "toxic_boost": {
+ "effect": "toxic_boost"
+ },
"trace": {
"flags": [
"cant_be_copied"
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Overgrow.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Overgrow.cs
deleted file mode 100644
index b305efe..0000000
--- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Overgrow.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
-
-///
-/// Overgrow is an ability that boosts the power of Grass-type moves when the Pokémon's HP is low.
-///
-/// Bulbapedia - Overgrow
-///
-[Script(ScriptCategory.Ability, "overgrow")]
-public class Overgrow : Script
-{
- ///
- public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref ushort basePower)
- {
- if (move.GetHitData(target, hit).Type?.Name == "grass" && target.CurrentHealth <= target.BoostedStats.Hp / 3)
- basePower = basePower.MultiplyOrMax(1.5f);
- }
-}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/PowerUpTypeAtLowHealth.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/PowerUpTypeAtLowHealth.cs
index b3a7d14..daa7684 100644
--- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/PowerUpTypeAtLowHealth.cs
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/PowerUpTypeAtLowHealth.cs
@@ -27,7 +27,7 @@ public class PowerUpTypeAtLowHealth : Script
if (!parameters.TryGetValue("threshold", out var threshold) || threshold is not float thresholdValue)
throw new ArgumentException("Parameter 'threshold' is required and must be a float.", nameof(parameters));
- if (thresholdValue < 0 || thresholdValue > 1)
+ if (thresholdValue is < 0 or > 1)
throw new ArgumentOutOfRangeException(nameof(threshold), "Threshold must be between 0 and 1.");
_type = typeName;
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Swarm.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Swarm.cs
deleted file mode 100644
index 68f187b..0000000
--- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Swarm.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
-
-///
-/// Swarm is an ability that powers up Bug-type moves when the Pokémon's HP is low.
-///
-/// Bulbapedia - Swarm
-///
-[Script(ScriptCategory.Ability, "swarm")]
-public class Swarm : Script
-{
- ///
- public override void ChangeOffensiveStatValue(IExecutingMove move, IPokemon target, byte hit, uint defensiveStat,
- ImmutableStatisticSet targetStats, Statistic stat, ref uint value)
- {
- if (move.GetHitData(target, hit).Type?.Name == "bug" && target.CurrentHealth <= target.MaxHealth / 3)
- {
- value = value.MultiplyOrMax(1.5f);
- }
- }
-}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/TangledFeet.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/TangledFeet.cs
new file mode 100644
index 0000000..a2029a1
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/TangledFeet.cs
@@ -0,0 +1,20 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Tangled Feet is an ability that raises evasion if the Pokémon is confused.
+///
+/// Bulbapedia - Tangled Feet
+///
+[Script(ScriptCategory.Ability, "tangled_feet")]
+public class TangledFeet : Script
+{
+ ///
+ public override void ChangeIncomingAccuracy(IExecutingMove executingMove, IPokemon target, byte hitIndex,
+ ref int modifiedAccuracy)
+ {
+ if (modifiedAccuracy != 255 && target.Volatile.Contains())
+ {
+ modifiedAccuracy /= 2;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/TanglingHair.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/TanglingHair.cs
new file mode 100644
index 0000000..e07e077
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/TanglingHair.cs
@@ -0,0 +1,24 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Tangling Hair is an ability that lowers the Speed of attackers making contact.
+///
+/// Bulbapedia - Tangling Hair
+///
+[Script(ScriptCategory.Ability, "tangling_hair")]
+public class TanglingHair : Script
+{
+ ///
+ public override void OnIncomingHit(IExecutingMove move, IPokemon target, byte hit)
+ {
+ if (!move.GetHitData(target, hit).IsContact)
+ return;
+
+ EventBatchId batchId = new();
+ move.Battle.EventHook.Invoke(new AbilityTriggerEvent(target)
+ {
+ BatchId = batchId,
+ });
+ move.User.ChangeStatBoost(Statistic.Speed, -1, false, false, batchId);
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Technician.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Technician.cs
new file mode 100644
index 0000000..515a71e
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Technician.cs
@@ -0,0 +1,19 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Technician is an ability that boosts the power of the Pokémon's weaker moves.
+///
+/// Bulbapedia - Technician
+///
+[Script(ScriptCategory.Ability, "technician")]
+public class Technician : Script
+{
+ ///
+ public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref ushort basePower)
+ {
+ if (move.UseMove.BasePower <= 60)
+ {
+ basePower = basePower.MultiplyOrMax(1.5f);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Telepathy.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Telepathy.cs
new file mode 100644
index 0000000..a5d59e8
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Telepathy.cs
@@ -0,0 +1,17 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Telepathy is an ability that prevents damage from allies' moves.
+///
+/// Bulbapedia - Telepathy
+///
+[Script(ScriptCategory.Ability, "telepathy")]
+public class Telepathy : Script
+{
+ ///
+ public override void IsInvulnerableToMove(IExecutingMove move, IPokemon target, ref bool invulnerable)
+ {
+ if (move.User.BattleData?.BattleSide == target.BattleData?.BattleSide)
+ invulnerable = true;
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Teravolt.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Teravolt.cs
new file mode 100644
index 0000000..2710738
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Teravolt.cs
@@ -0,0 +1,41 @@
+using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
+using PkmnLib.Plugin.Gen7.Scripts.Side;
+
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Teravolt is an ability that allows moves to ignore the target's abilities if they could hinder or prevent the move.
+///
+/// Bulbapedia - Teravolt
+///
+[Script(ScriptCategory.Ability, "teravolt")]
+public class Teravolt : Script
+{
+ ///
+ public override void OnBeforeMoveChoice(IMoveChoice moveChoice)
+ {
+ var battleData = moveChoice.User.BattleData;
+ if (battleData is null)
+ return;
+
+ var sides = battleData.Battle.Sides.Where(x => x != battleData.BattleSide);
+ foreach (var side in sides)
+ {
+ side.VolatileScripts.Add(new TeravoltEffect());
+ }
+ }
+
+ ///
+ public override void OnAfterMoveChoice(IMoveChoice move)
+ {
+ var battleData = move.User.BattleData;
+ if (battleData is null)
+ return;
+
+ var sides = battleData.Battle.Sides.Where(x => x != battleData.BattleSide);
+ foreach (var side in sides)
+ {
+ side.VolatileScripts.Remove();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ThickFat.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ThickFat.cs
new file mode 100644
index 0000000..e942fa8
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ThickFat.cs
@@ -0,0 +1,20 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Thick Fat is an ability that halves the damage taken from Fire- and Ice-type moves.
+///
+/// Bulbapedia - Thick Fat
+///
+[Script(ScriptCategory.Ability, "thick_fat")]
+public class ThickFat : Script
+{
+ ///
+ public override void ChangeMoveDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage)
+ {
+ var type = move.GetHitData(target, hit).Type;
+ if (type is not null && (type.Value.Name == "ice" || type.Value.Name == "fire"))
+ {
+ damage /= 2;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/TintedLens.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/TintedLens.cs
new file mode 100644
index 0000000..5c8e021
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/TintedLens.cs
@@ -0,0 +1,19 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Tinted Lens is an ability that doubles the damage of not very effective moves.
+///
+/// Bulbapedia - Tinted Lens
+///
+[Script(ScriptCategory.Ability, "tinted_lens")]
+public class TintedLens : Script
+{
+ ///
+ public override void ChangeMoveDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage)
+ {
+ if (move.GetHitData(target, hit).Effectiveness < 1.0f)
+ {
+ damage = damage.MultiplyOrMax(2);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ToughClaws.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ToughClaws.cs
new file mode 100644
index 0000000..52d6f59
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ToughClaws.cs
@@ -0,0 +1,19 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Tough Claws is an ability that boosts the power of contact moves.
+///
+/// Bulbapedia - Tough Claws
+///
+[Script(ScriptCategory.Ability, "tough_claws")]
+public class ToughClaws : Script
+{
+ ///
+ public override void ChangeMoveDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage)
+ {
+ if (move.GetHitData(target, hit).IsContact)
+ {
+ damage = damage.MultiplyOrMax(5325 / 4096f);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ToxicBoost.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ToxicBoost.cs
new file mode 100644
index 0000000..e19b33d
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ToxicBoost.cs
@@ -0,0 +1,20 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Toxic Boost is an ability that increases Attack when the Pokémon is poisoned.
+///
+/// Bulbapedia - Toxic Boost
+///
+[Script(ScriptCategory.Ability, "toxic_boost")]
+public class ToxicBoost : Script
+{
+ ///
+ public override void ChangeMoveDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage)
+ {
+ if (move.User.HasStatus(ScriptUtils.ResolveName()) ||
+ move.User.HasStatus(ScriptUtils.ResolveName()))
+ {
+ damage = damage.MultiplyOrMax(1.5f);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Side/TeravoltEffect.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Side/TeravoltEffect.cs
new file mode 100644
index 0000000..b197fc5
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Side/TeravoltEffect.cs
@@ -0,0 +1,18 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Side;
+
+[Script(ScriptCategory.Side, "teravolt")]
+public class TeravoltEffect : Script
+{
+ ///
+ public override void OnBeforeAnyHookInvoked(ref List? suppressedCategories)
+ {
+ suppressedCategories ??= [];
+ suppressedCategories.Add(ScriptCategory.Ability);
+ }
+
+ ///
+ public override void OnEndTurn(IScriptSource owner, IBattle battle)
+ {
+ RemoveSelf();
+ }
+}
\ No newline at end of file