diff --git a/PkmnLib.Dynamic/BattleFlow/MoveTurnExecutor.cs b/PkmnLib.Dynamic/BattleFlow/MoveTurnExecutor.cs
index cd73eee..044cec5 100644
--- a/PkmnLib.Dynamic/BattleFlow/MoveTurnExecutor.cs
+++ b/PkmnLib.Dynamic/BattleFlow/MoveTurnExecutor.cs
@@ -255,8 +255,11 @@ public static class MoveTurnExecutor
if (secondaryEffect != null)
{
var preventSecondary = false;
- target.RunScriptHook(x =>
+ executingMove.RunScriptHook(x =>
x.PreventSecondaryEffect(executingMove, target, hitIndex, ref preventSecondary));
+ target.RunScriptHook(x =>
+ x.PreventIncomingSecondaryEffect(executingMove, target, hitIndex,
+ ref preventSecondary));
if (!preventSecondary)
{
diff --git a/PkmnLib.Dynamic/ScriptHandling/Script.cs b/PkmnLib.Dynamic/ScriptHandling/Script.cs
index 14dcdab..cbc0cf5 100644
--- a/PkmnLib.Dynamic/ScriptHandling/Script.cs
+++ b/PkmnLib.Dynamic/ScriptHandling/Script.cs
@@ -450,12 +450,21 @@ public abstract class Script : IDeepCloneable
{
}
+ ///
+ /// This function allows a script to prevent a secondary effect of a move from being applied.
+ /// This means the move will still hit and do damage, but not trigger its secondary effect. Note that this
+ /// function is not called for status moves.
+ ///
+ public virtual void PreventSecondaryEffect(IExecutingMove move, IPokemon target, byte hit, ref bool prevent)
+ {
+ }
+
///
/// This function allows a script attached to a Pokemon or its parents to prevent an incoming
/// secondary effect. This means the move will still hit and do damage, but not trigger its
/// secondary effect. Note that this function is not called for status moves.
///
- public virtual void PreventSecondaryEffect(IExecutingMove move, IPokemon target, byte hit, ref bool prevent)
+ public virtual void PreventIncomingSecondaryEffect(IExecutingMove move, IPokemon target, byte hit, ref bool prevent)
{
}
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Data/Abilities.jsonc b/Plugins/PkmnLib.Plugin.Gen7/Data/Abilities.jsonc
index 6b869bc..2a1f2d8 100755
--- a/Plugins/PkmnLib.Plugin.Gen7/Data/Abilities.jsonc
+++ b/Plugins/PkmnLib.Plugin.Gen7/Data/Abilities.jsonc
@@ -502,31 +502,71 @@
"canBeChanged": false,
"effect": "rks_system"
},
- "rock_head": {},
- "rough_skin": {},
- "run_away": {},
- "sand_force": {},
- "sand_rush": {},
- "sand_stream": {},
- "sand_veil": {},
- "sap_sipper": {},
+ "rock_head": {
+ "effect": "rock_head"
+ },
+ "rough_skin": {
+ "effect": "rough_skin"
+ },
+ "run_away": {
+ "effect": "run_away"
+ },
+ "sand_force": {
+ "effect": "sand_force"
+ },
+ "sand_rush": {
+ "effect": "sand_rush"
+ },
+ "sand_stream": {
+ "effect": "sand_stream"
+ },
+ "sand_veil": {
+ "effect": "sand_veil"
+ },
+ "sap_sipper": {
+ "effect": "sap_sipper"
+ },
"schooling": {
+ "effect": "schooling",
"canBeChanged": false
},
- "scrappy": {},
- "serene_grace": {},
- "shadow_shield": {},
- "shadow_tag": {},
- "shed_skin": {},
- "sheer_force": {},
- "shell_armor": {},
- "shield_dust": {},
+ "scrappy": {
+ "effect": "scrappy"
+ },
+ "serene_grace": {
+ "effect": "serene_grace"
+ },
+ "shadow_shield": {
+ "effect": "shadow_shield"
+ },
+ "shadow_tag": {
+ "effect": "shadow_tag"
+ },
+ "shed_skin": {
+ "effect": "shed_skin"
+ },
+ "sheer_force": {
+ "effect": "sheer_force"
+ },
+ "shell_armor": {
+ "effect": "shell_armor"
+ },
+ "shield_dust": {
+ "effect": "shield_dust"
+ },
"shields_down": {
+ "effect": "shields_down",
"canBeChanged": false
},
- "simple": {},
- "skill_link": {},
- "slow_start": {},
+ "simple": {
+ "effect": "simple"
+ },
+ "skill_link": {
+ "effect": "skill_link"
+ },
+ "slow_start": {
+ "effect": "slow_start"
+ },
"slush_rush": {},
"sniper": {},
"snow_cloak": {},
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Data/Pokemon.json b/Plugins/PkmnLib.Plugin.Gen7/Data/Pokemon.json
index 2b3a712..bb081fe 100755
--- a/Plugins/PkmnLib.Plugin.Gen7/Data/Pokemon.json
+++ b/Plugins/PkmnLib.Plugin.Gen7/Data/Pokemon.json
@@ -81395,7 +81395,7 @@
"eggCycles": 25,
"flags": [],
"formes": {
- "blue": {
+ "default": {
"abilities": [
"shields_down"
],
@@ -81526,136 +81526,7 @@
}
},
"blue-meteor": {
- "abilities": [
- "shields_down"
- ],
- "hiddenAbilities": [],
- "baseStats": {
- "attack": 60,
- "defense": 100,
- "hp": 60,
- "specialAttack": 60,
- "specialDefense": 100,
- "speed": 60
- },
- "evReward": {
- "defense": 1,
- "specialDefense": 1
- },
- "types": [
- "rock",
- "flying"
- ],
- "height": 0.3,
- "weight": 40,
- "baseExp": 154,
- "moves": {
- "levelMoves": [
- {
- "name": "tackle",
- "level": 1
- },
- {
- "name": "defense_curl",
- "level": 3
- },
- {
- "name": "rollout",
- "level": 8
- },
- {
- "name": "confuse_ray",
- "level": 10
- },
- {
- "name": "swift",
- "level": 15
- },
- {
- "name": "ancient_power",
- "level": 17
- },
- {
- "name": "self_destruct",
- "level": 22
- },
- {
- "name": "stealth_rock",
- "level": 24
- },
- {
- "name": "take_down",
- "level": 29
- },
- {
- "name": "autotomize",
- "level": 31
- },
- {
- "name": "cosmic_power",
- "level": 36
- },
- {
- "name": "power_gem",
- "level": 38
- },
- {
- "name": "double_edge",
- "level": 43
- },
- {
- "name": "shell_smash",
- "level": 45
- },
- {
- "name": "explosion",
- "level": 50
- }
- ],
- "eggMoves": [],
- "tutorMoves": [],
- "machine": [
- "hyper_beam",
- "solar_beam",
- "earthquake",
- "toxic",
- "psychic",
- "double_team",
- "light_screen",
- "reflect",
- "explosion",
- "rest",
- "rock_slide",
- "substitute",
- "protect",
- "sandstorm",
- "swagger",
- "attract",
- "sleep_talk",
- "return",
- "frustration",
- "safeguard",
- "hidden_power",
- "psych_up",
- "facade",
- "rock_tomb",
- "calm_mind",
- "gyro_ball",
- "u_turn",
- "rock_polish",
- "giga_impact",
- "stone_edge",
- "charge_beam",
- "round",
- "acrobatics",
- "bulldoze",
- "confide",
- "dazzling_gleam"
- ],
- "formeChange": []
- }
- },
- "default": {
+ "isBattleOnly": true,
"abilities": [
"shields_down"
],
@@ -81916,6 +81787,7 @@
}
},
"green-meteor": {
+ "isBattleOnly": true,
"abilities": [
"shields_down"
],
@@ -82176,6 +82048,7 @@
}
},
"indigo-meteor": {
+ "isBattleOnly": true,
"abilities": [
"shields_down"
],
@@ -82436,6 +82309,7 @@
}
},
"orange-meteor": {
+ "isBattleOnly": true,
"abilities": [
"shields_down"
],
@@ -82695,6 +82569,137 @@
"formeChange": []
}
},
+ "red-meteor": {
+ "isBattleOnly": true,
+ "abilities": [
+ "shields_down"
+ ],
+ "hiddenAbilities": [],
+ "baseStats": {
+ "attack": 60,
+ "defense": 100,
+ "hp": 60,
+ "specialAttack": 60,
+ "specialDefense": 100,
+ "speed": 60
+ },
+ "evReward": {
+ "defense": 1,
+ "specialDefense": 1
+ },
+ "types": [
+ "rock",
+ "flying"
+ ],
+ "height": 0.3,
+ "weight": 40,
+ "baseExp": 154,
+ "moves": {
+ "levelMoves": [
+ {
+ "name": "tackle",
+ "level": 1
+ },
+ {
+ "name": "defense_curl",
+ "level": 3
+ },
+ {
+ "name": "rollout",
+ "level": 8
+ },
+ {
+ "name": "confuse_ray",
+ "level": 10
+ },
+ {
+ "name": "swift",
+ "level": 15
+ },
+ {
+ "name": "ancient_power",
+ "level": 17
+ },
+ {
+ "name": "self_destruct",
+ "level": 22
+ },
+ {
+ "name": "stealth_rock",
+ "level": 24
+ },
+ {
+ "name": "take_down",
+ "level": 29
+ },
+ {
+ "name": "autotomize",
+ "level": 31
+ },
+ {
+ "name": "cosmic_power",
+ "level": 36
+ },
+ {
+ "name": "power_gem",
+ "level": 38
+ },
+ {
+ "name": "double_edge",
+ "level": 43
+ },
+ {
+ "name": "shell_smash",
+ "level": 45
+ },
+ {
+ "name": "explosion",
+ "level": 50
+ }
+ ],
+ "eggMoves": [],
+ "tutorMoves": [],
+ "machine": [
+ "hyper_beam",
+ "solar_beam",
+ "earthquake",
+ "toxic",
+ "psychic",
+ "double_team",
+ "light_screen",
+ "reflect",
+ "explosion",
+ "rest",
+ "rock_slide",
+ "substitute",
+ "protect",
+ "sandstorm",
+ "swagger",
+ "attract",
+ "sleep_talk",
+ "return",
+ "frustration",
+ "safeguard",
+ "hidden_power",
+ "psych_up",
+ "facade",
+ "rock_tomb",
+ "calm_mind",
+ "gyro_ball",
+ "u_turn",
+ "rock_polish",
+ "giga_impact",
+ "stone_edge",
+ "charge_beam",
+ "round",
+ "acrobatics",
+ "bulldoze",
+ "confide",
+ "dazzling_gleam"
+ ],
+ "formeChange": []
+ }
+ },
"violet": {
"abilities": [
"shields_down"
@@ -82826,6 +82831,7 @@
}
},
"violet-meteor": {
+ "isBattleOnly": true,
"abilities": [
"shields_down"
],
@@ -83086,6 +83092,7 @@
}
},
"yellow-meteor": {
+ "isBattleOnly": true,
"abilities": [
"shields_down"
],
@@ -141638,6 +141645,7 @@
}
},
"school": {
+ "isBattleOnly": true,
"abilities": [
"schooling"
],
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/RockHead.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/RockHead.cs
new file mode 100644
index 0000000..023850f
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/RockHead.cs
@@ -0,0 +1,21 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Rock Head is an ability that prevents the Pokémon from taking recoil damage from most moves.
+///
+/// Bulbapedia - Rock Head
+///
+[Script(ScriptCategory.Ability, "rock_head")]
+public class RockHead : Script
+{
+ ///
+ public override void CustomTrigger(StringKey eventName, ICustomTriggerArgs args)
+ {
+ if (eventName != CustomTriggers.ModifyRecoil)
+ return;
+ if (args is CustomTriggers.ModifyRecoilArgs recoilArgs)
+ {
+ recoilArgs.Prevent = true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/RoughSkin.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/RoughSkin.cs
new file mode 100644
index 0000000..95855fe
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/RoughSkin.cs
@@ -0,0 +1,19 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Rough Skin is an ability that damages attackers using contact moves.
+///
+/// Bulbapedia - Rough Skin
+///
+[Script(ScriptCategory.Ability, "rough_skin")]
+public class RoughSkin : Script
+{
+ ///
+ public override void OnIncomingHit(IExecutingMove move, IPokemon target, byte hit)
+ {
+ if (move.GetHitData(target, hit).IsContact)
+ {
+ move.User.Damage(move.User.MaxHealth / 8, DamageSource.Misc);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/RunAway.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/RunAway.cs
new file mode 100644
index 0000000..fe4e840
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/RunAway.cs
@@ -0,0 +1,12 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Run Away is an ability that guarantees escape from wild battles.
+///
+/// Bulbapedia - Run Away
+///
+[Script(ScriptCategory.Ability, "run_away")]
+public class RunAway : Script
+{
+ // No effect in battle
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SandForce.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SandForce.cs
new file mode 100644
index 0000000..a6c83f0
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SandForce.cs
@@ -0,0 +1,26 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Sand Force is an ability that boosts the power of Rock, Ground, and Steel-type moves in a sandstorm.
+///
+/// Bulbapedia - Sand Force
+///
+[Script(ScriptCategory.Ability, "sand_force")]
+public class SandForce : Script
+{
+ ///
+ public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref ushort basePower)
+ {
+ if (move.Battle.WeatherName == ScriptUtils.ResolveName())
+ {
+ var type = move.GetHitData(target, hit).Type;
+ if (type != null &&
+ (type.Value.Name == "rock" || type.Value.Name == "ground" || type.Value.Name == "steel"))
+ {
+ basePower = basePower.MultiplyOrMax(1.3f);
+ }
+ }
+ }
+
+ // TODO: Prevent sandstorm damage.
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SandRush.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SandRush.cs
new file mode 100644
index 0000000..c193dec
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SandRush.cs
@@ -0,0 +1,21 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Sand Rush is an ability that doubles the Pokémon's Speed during a sandstorm.
+///
+/// Bulbapedia - Sand Rush
+///
+[Script(ScriptCategory.Ability, "sand_rush")]
+public class SandRush : Script
+{
+ ///
+ public override void ChangeSpeed(ITurnChoice choice, ref uint speed)
+ {
+ if (choice.User.BattleData?.Battle.WeatherName == ScriptUtils.ResolveName())
+ {
+ speed = speed.MultiplyOrMax(2);
+ }
+ }
+
+ // TODO: Prevent sandstorm damage.
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SandStream.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SandStream.cs
new file mode 100644
index 0000000..2eaeb3f
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SandStream.cs
@@ -0,0 +1,25 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Sand Stream is an ability that creates a sandstorm when the Pokémon enters battle.
+///
+/// Bulbapedia - Sand Stream
+///
+[Script(ScriptCategory.Ability, "sand_stream")]
+public class SandStream : Script
+{
+ ///
+ public override void OnSwitchIn(IPokemon pokemon, byte position)
+ {
+ var battleData = pokemon.BattleData;
+ if (battleData == null)
+ return;
+
+ if (battleData.Battle.WeatherName == ScriptUtils.ResolveName())
+ return;
+
+ EventBatchId batchId = new();
+ battleData.Battle.EventHook.Invoke(new AbilityTriggerEvent(pokemon));
+ battleData.Battle.SetWeather(ScriptUtils.ResolveName(), 5, batchId);
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SandVeil.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SandVeil.cs
new file mode 100644
index 0000000..3b8ea70
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SandVeil.cs
@@ -0,0 +1,22 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Sand Veil is an ability that raises the Pokémon's evasion during a sandstorm.
+///
+/// Bulbapedia - Sand Veil
+///
+[Script(ScriptCategory.Ability, "sand_veil")]
+public class SandVeil : Script
+{
+ ///
+ public override void ChangeIncomingAccuracy(IExecutingMove executingMove, IPokemon target, byte hitIndex,
+ ref int modifiedAccuracy)
+ {
+ if (executingMove.Battle.WeatherName != ScriptUtils.ResolveName())
+ return;
+
+ modifiedAccuracy = (int)(modifiedAccuracy * (3277f / 4096f));
+ }
+
+ // TODO: Prevent sandstorm damage.
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SapSipper.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SapSipper.cs
new file mode 100644
index 0000000..2cc4b3b
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SapSipper.cs
@@ -0,0 +1,21 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Sap Sipper is an ability that grants immunity to Grass-type moves and raises Attack when hit by one.
+///
+/// Bulbapedia - Sap Sipper
+///
+[Script(ScriptCategory.Ability, "sap_sipper")]
+public class SapSipper : Script
+{
+ ///
+ public override void IsInvulnerableToMove(IExecutingMove move, IPokemon target, ref bool invulnerable)
+ {
+ if (move.GetHitData(target, 0).Type?.Name == "grass")
+ {
+ invulnerable = true;
+ move.Battle.EventHook.Invoke(new AbilityTriggerEvent(target));
+ target.ChangeStatBoost(Statistic.Attack, 1, true, false);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Schooling.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Schooling.cs
new file mode 100644
index 0000000..d92de29
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Schooling.cs
@@ -0,0 +1,45 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Schooling is an ability that changes Wishiwashi's form in battle.
+///
+/// Bulbapedia - Schooling
+///
+[Script(ScriptCategory.Ability, "schooling")]
+public class Schooling : Script
+{
+ private IPokemon? _owningPokemon;
+
+ ///
+ public override void OnAddedToParent(IScriptSource source)
+ {
+ if (source is not IPokemon pokemon)
+ throw new ArgumentException("Schooling script must be added to a Pokemon.", nameof(source));
+ _owningPokemon = pokemon;
+ }
+
+ ///
+ public override void OnSwitchIn(IPokemon pokemon, byte position) => ChangeFormIfNeeded(pokemon);
+
+ ///
+ public override void OnEndTurn(IBattle battle) => ChangeFormIfNeeded(_owningPokemon);
+
+ private static void ChangeFormIfNeeded(IPokemon? pokemon)
+ {
+ if (pokemon is null)
+ return;
+
+ if (pokemon.Species.Name != "wishiwashi" || pokemon.BattleData?.Battle == null)
+ return;
+ // If Wishiwashi has less than 25% health, change to Solo form
+ if (pokemon.CurrentHealth < pokemon.MaxHealth / 4 && pokemon.Form.Name != "default")
+ {
+ pokemon.ChangeForm(pokemon.Species.GetDefaultForm());
+ }
+ else if (pokemon.CurrentHealth >= pokemon.MaxHealth / 4 && pokemon.Form.Name != "school" &&
+ pokemon.Species.TryGetForm("school", out var schoolForm))
+ {
+ pokemon.ChangeForm(schoolForm);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Scrappy.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Scrappy.cs
new file mode 100644
index 0000000..7e605cc
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Scrappy.cs
@@ -0,0 +1,21 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Scrappy is an ability that allows the Pokémon to hit Ghost-type Pokémon with Normal- and Fighting-type moves.
+///
+/// Bulbapedia - Scrappy
+///
+[Script(ScriptCategory.Ability, "scrappy")]
+public class Scrappy : Script
+{
+ ///
+ public override void ChangeTypesForMove(IExecutingMove executingMove, IPokemon target, byte hitIndex,
+ IList types)
+ {
+ var hitType = executingMove.GetHitData(target, hitIndex).Type;
+ if (hitType?.Name != "normal" && hitType?.Name != "fighting")
+ return;
+ if (types.Any(x => x.Name == "ghost"))
+ types.RemoveAll(x => x.Name == "ghost");
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SereneGrace.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SereneGrace.cs
new file mode 100644
index 0000000..a87e172
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SereneGrace.cs
@@ -0,0 +1,16 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Serene Grace is an ability that doubles the chance of additional effects occurring when attacking.
+///
+/// Bulbapedia - Serene Grace
+///
+[Script(ScriptCategory.Ability, "serene_grace")]
+public class SereneGrace : Script
+{
+ ///
+ public override void ChangeEffectChance(IExecutingMove move, IPokemon target, byte hit, ref float chance)
+ {
+ chance *= 2;
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ShadowShield.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ShadowShield.cs
new file mode 100644
index 0000000..d4e339a
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ShadowShield.cs
@@ -0,0 +1,28 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Shadow Shield is an ability that reduces damage taken when at full HP.
+///
+/// Bulbapedia - Shadow Shield
+///
+[Script(ScriptCategory.Ability, "shadow_shield")]
+public class ShadowShield : Script
+{
+ ///
+ public override void ChangeIncomingMoveDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage)
+ {
+ if (target.CurrentHealth == target.BoostedStats.Hp)
+ {
+ damage = (uint)(damage * 0.5);
+ }
+ }
+
+ ///
+ public override void OnBeforeAnyHookInvoked(ref List? suppressedCategories)
+ {
+ // Shadow Shield can not be suppressed by any other script, so we remove it from the list of suppressed categories
+ // if it was added.
+ if (suppressedCategories != null && suppressedCategories.Contains(ScriptCategory.Ability))
+ suppressedCategories.Remove(ScriptCategory.Ability);
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ShadowTag.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ShadowTag.cs
new file mode 100644
index 0000000..db60113
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ShadowTag.cs
@@ -0,0 +1,16 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Shadow Tag is an ability that prevents opposing Pokémon from fleeing or switching out.
+///
+/// Bulbapedia - Shadow Tag
+///
+[Script(ScriptCategory.Ability, "shadow_tag")]
+public class ShadowTag : Script
+{
+ ///
+ public override void PreventOpponentRunAway(IFleeChoice choice, ref bool prevent) => prevent = true;
+
+ ///
+ public override void PreventOpponentSwitch(ISwitchChoice choice, ref bool prevent) => prevent = true;
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ShedSkin.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ShedSkin.cs
new file mode 100644
index 0000000..76db660
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ShedSkin.cs
@@ -0,0 +1,37 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Shed Skin is an ability that gives the Pokémon a chance to heal from a status condition at the end of each turn.
+///
+/// Bulbapedia - Shed Skin
+///
+[Script(ScriptCategory.Ability, "shed_skin")]
+public class ShedSkin : Script
+{
+ private IPokemon? _owningPokemon;
+
+ ///
+ public override void OnAddedToParent(IScriptSource source)
+ {
+ if (source is not IPokemon pokemon)
+ throw new ArgumentException("ShedSkin script must be added to a Pokemon.", nameof(source));
+ _owningPokemon = pokemon;
+ }
+
+ ///
+ public override void OnEndTurn(IBattle battle)
+ {
+ if (_owningPokemon is null || _owningPokemon.StatusScript.IsEmpty)
+ return;
+
+ if (battle.Random.GetInt(3) == 0)
+ {
+ EventBatchId batchId = new();
+ battle.EventHook.Invoke(new AbilityTriggerEvent(_owningPokemon)
+ {
+ BatchId = batchId,
+ });
+ _owningPokemon.ClearStatus(batchId);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SheerForce.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SheerForce.cs
new file mode 100644
index 0000000..25ef79b
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SheerForce.cs
@@ -0,0 +1,22 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Sheer Force is an ability that increases the power of moves with secondary effects, but removes those effects.
+///
+/// Bulbapedia - Sheer Force
+///
+[Script(ScriptCategory.Ability, "sheer_force")]
+public class SheerForce : Script
+{
+ ///
+ public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref ushort basePower)
+ {
+ basePower = basePower.MultiplyOrMax(5325f / 4096f);
+ }
+
+ ///
+ public override void PreventSecondaryEffect(IExecutingMove move, IPokemon target, byte hit, ref bool prevent)
+ {
+ prevent = true;
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ShellArmor.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ShellArmor.cs
new file mode 100644
index 0000000..ccab711
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ShellArmor.cs
@@ -0,0 +1,16 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Shell Armor is an ability that prevents the Pokémon from receiving critical hits.
+///
+/// Bulbapedia - Shell Armor
+///
+[Script(ScriptCategory.Ability, "shell_armor")]
+public class ShellArmor : Script
+{
+ ///
+ public override void BlockIncomingCriticalHit(IExecutingMove move, IPokemon target, byte hit, ref bool block)
+ {
+ block = true;
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ShieldDust.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ShieldDust.cs
new file mode 100644
index 0000000..c0321f3
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ShieldDust.cs
@@ -0,0 +1,17 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Shield Dust is an ability that blocks the additional effects of attacks taken.
+///
+/// Bulbapedia - Shield Dust
+///
+[Script(ScriptCategory.Ability, "shield_dust")]
+public class ShieldDust : Script
+{
+ ///
+ public override void PreventIncomingSecondaryEffect(IExecutingMove move, IPokemon target, byte hit,
+ ref bool prevent)
+ {
+ prevent = true;
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ShieldsDown.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ShieldsDown.cs
new file mode 100644
index 0000000..81dba86
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ShieldsDown.cs
@@ -0,0 +1,57 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Shields Down is an ability that changes Minior's form depending on its HP.
+///
+/// Bulbapedia - Shields Down
+///
+[Script(ScriptCategory.Ability, "shields_down")]
+public class ShieldsDown : Script
+{
+ private IPokemon? _owningPokemon;
+
+ ///
+ public override void OnAddedToParent(IScriptSource source)
+ {
+ if (source is not IPokemon pokemon)
+ throw new ArgumentException("ShieldsDown script must be added to a Pokemon.", nameof(source));
+ _owningPokemon = pokemon;
+ }
+
+ ///
+ public override void OnSwitchIn(IPokemon pokemon, byte position) => ChangeFormIfNeeded(pokemon);
+
+ ///
+ public override void OnEndTurn(IBattle battle) => ChangeFormIfNeeded(_owningPokemon);
+
+ private static void ChangeFormIfNeeded(IPokemon? pokemon)
+ {
+ if (pokemon is null)
+ return;
+
+ if (pokemon.Species.Name != "minior" || pokemon.BattleData?.Battle == null)
+ return;
+ if (pokemon.CurrentHealth < pokemon.MaxHealth / 2 && pokemon.Form.Name.ToString().EndsWith("-meteor"))
+ {
+ var coreForm = pokemon.Form.Name.ToString().Replace("-meteor", "");
+ if (coreForm == "blue")
+ coreForm = "default";
+ if (pokemon.Species.TryGetForm(coreForm, out var coreFormData))
+ {
+ pokemon.ChangeForm(coreFormData);
+ }
+ }
+ else if (pokemon.CurrentHealth >= pokemon.MaxHealth / 2 &&
+ pokemon.Form.Name.ToString().EndsWith("-meteor") == false)
+ {
+ var baseFormName = pokemon.Form.Name;
+ if (baseFormName == "default")
+ baseFormName = "blue";
+ var meteorFormName = baseFormName + "-meteor";
+ if (pokemon.Species.TryGetForm(meteorFormName, out var meteorFormData))
+ {
+ pokemon.ChangeForm(meteorFormData);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Simple.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Simple.cs
new file mode 100644
index 0000000..35535f7
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Simple.cs
@@ -0,0 +1,16 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Simple is an ability that doubles the effect of stat changes.
+///
+/// Bulbapedia - Simple
+///
+[Script(ScriptCategory.Ability, "simple")]
+public class Simple : Script
+{
+ ///
+ public override void ChangeStatBoostChange(IPokemon target, Statistic stat, bool selfInflicted, ref sbyte amount)
+ {
+ amount = amount.MultiplyOrMax(2);
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SkillLink.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SkillLink.cs
new file mode 100644
index 0000000..d912360
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SkillLink.cs
@@ -0,0 +1,21 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Skill Link is an ability that makes multi-strike moves always hit the maximum number of times.
+///
+/// Bulbapedia - Skill Link
+///
+[Script(ScriptCategory.Ability, "skill_link")]
+public class SkillLink : Script
+{
+ ///
+ public override void CustomTrigger(StringKey eventName, ICustomTriggerArgs args)
+ {
+ if (eventName != CustomTriggers.Modify2_5HitMove)
+ return;
+ if (args is CustomTriggers.Modify2_5HitMoveArgs triggerArgs)
+ {
+ triggerArgs.NumberOfHits = 5;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SlowStart.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SlowStart.cs
new file mode 100644
index 0000000..8532a5b
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/SlowStart.cs
@@ -0,0 +1,27 @@
+using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
+
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Slow Start is an ability that halves the user's Attack and Speed for five turns after entering battle.
+///
+/// Bulbapedia - Slow Start
+///
+[Script(ScriptCategory.Ability, "slow_start")]
+public class SlowStart : Script
+{
+ private IPokemon? _pokemon;
+
+ ///
+ public override void OnSwitchIn(IPokemon pokemon, byte position)
+ {
+ _pokemon = pokemon;
+ pokemon.Volatile.Add(new SlowStartEffect());
+ }
+
+ ///
+ public override void OnRemove()
+ {
+ _pokemon?.Volatile.Remove();
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/CustomTriggers.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/CustomTriggers.cs
index 4c7d6d6..504964a 100644
--- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/CustomTriggers.cs
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/CustomTriggers.cs
@@ -116,4 +116,20 @@ public static class CustomTriggers
public uint Damage { get; set; } = Damage;
public bool Invert { get; set; } = false;
}
+
+ public static readonly StringKey ModifyRecoil = "modify_recoil";
+
+ public record ModifyRecoilArgs(IExecutingMove Move, IPokemon Target, byte Hit, uint Damage, uint Recoil)
+ : ICustomTriggerArgs
+ {
+ public uint Recoil { get; set; } = Recoil;
+ public bool Prevent { get; set; } = false;
+ }
+
+ public static readonly StringKey Modify2_5HitMove = "modify_2_5_hit_move";
+
+ public record Modify2_5HitMoveArgs(IMoveChoice moveChoice, byte NumberOfHits) : ICustomTriggerArgs
+ {
+ public byte NumberOfHits { get; set; } = NumberOfHits;
+ }
}
\ 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
index 719d10d..dd08175 100644
--- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FlareBlitz.cs
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FlareBlitz.cs
@@ -10,13 +10,19 @@ public class FlareBlitz : Script
if (battleData == null)
return;
+ var hitData = move.GetHitData(target, hit);
+ var recoilDamage = hitData.Damage * (1 / 3);
+
+ var triggerArgs = new CustomTriggers.ModifyRecoilArgs(move, target, hit, hitData.Damage, recoilDamage);
+ move.RunScriptHook(x => x.CustomTrigger(CustomTriggers.ModifyRecoil, triggerArgs));
+ if (triggerArgs.Prevent)
+ return;
+
if (battleData.Battle.Random.EffectChance(10, move, target, hit))
{
target.SetStatus("burned", false);
}
- var hitData = move.GetHitData(target, hit);
- var recoilDamage = 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/MultiHitMove.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MultiHitMove.cs
index 0e11465..130665f 100644
--- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MultiHitMove.cs
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MultiHitMove.cs
@@ -19,6 +19,10 @@ public class MultiHitMove : Script
< 85 => 4,
_ => 5,
};
+ var triggerArgs = new CustomTriggers.Modify2_5HitMoveArgs(choice, (byte)newHits);
+ choice.RunScriptHook(x => x.CustomTrigger(CustomTriggers.Modify2_5HitMove, triggerArgs));
+ newHits = triggerArgs.NumberOfHits;
+
numberOfHits = (byte)newHits;
}
}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Recoil.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Recoil.cs
index 3baca7e..eca38a4 100644
--- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Recoil.cs
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Recoil.cs
@@ -1,5 +1,3 @@
-using PkmnLib.Static.Utils;
-
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "recoil")]
@@ -23,6 +21,12 @@ public class Recoil : Script
return;
var hitData = move.GetHitData(target, hit);
var recoilDamage = (uint)(hitData.Damage * _recoilPercentage);
+
+ var triggerArgs = new CustomTriggers.ModifyRecoilArgs(move, target, hit, hitData.Damage, recoilDamage);
+ move.RunScriptHook(x => x.CustomTrigger(CustomTriggers.ModifyRecoil, triggerArgs));
+ if (triggerArgs.Prevent)
+ return;
+
move.User.Damage(recoilDamage, DamageSource.Misc);
}
}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/SlowStartEffect.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/SlowStartEffect.cs
new file mode 100644
index 0000000..8d264f2
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/SlowStartEffect.cs
@@ -0,0 +1,33 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
+
+[Script(ScriptCategory.Pokemon, "slow_start")]
+public class SlowStartEffect : Script
+{
+ private int _turnsRemaining = 5;
+
+ ///
+ public override void ChangeSpeed(ITurnChoice choice, ref uint speed)
+ {
+ speed /= 2;
+ }
+
+ ///
+ public override void ChangeOffensiveStatValue(IExecutingMove move, IPokemon target, byte hit, uint defensiveStat,
+ ImmutableStatisticSet targetStats, Statistic stat, ref uint value)
+ {
+ if (stat == Statistic.Attack)
+ value /= 2;
+ }
+
+ ///
+ public override void OnEndTurn(IBattle battle)
+ {
+ if (_turnsRemaining <= 0)
+ return;
+ _turnsRemaining--;
+ if (_turnsRemaining == 0)
+ {
+ RemoveSelf();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Side/AromaVeilEffect.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Side/AromaVeilEffect.cs
index f93825f..3a57889 100644
--- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Side/AromaVeilEffect.cs
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Side/AromaVeilEffect.cs
@@ -24,7 +24,8 @@ public class AromaVeilEffect : Script
}
///
- public override void PreventSecondaryEffect(IExecutingMove move, IPokemon target, byte hit, ref bool prevent)
+ public override void PreventIncomingSecondaryEffect(IExecutingMove move, IPokemon target, byte hit,
+ ref bool prevent)
{
if (move.UseMove.HasFlag("mental"))
prevent = true;