diff --git a/PkmnLib.Dynamic/Events/DisplaySpeciesChangeEvent.cs b/PkmnLib.Dynamic/Events/DisplaySpeciesChangeEvent.cs
new file mode 100644
index 0000000..ff53918
--- /dev/null
+++ b/PkmnLib.Dynamic/Events/DisplaySpeciesChangeEvent.cs
@@ -0,0 +1,21 @@
+using PkmnLib.Dynamic.Events;
+using PkmnLib.Static.Species;
+
+namespace PkmnLib.Dynamic.Models;
+
+public class DisplaySpeciesChangeEvent : IEventData
+{
+ public IPokemon Pokemon { get; }
+ public ISpecies? Species { get; }
+ public IForm? Form { get; }
+
+ public DisplaySpeciesChangeEvent(IPokemon pokemon, ISpecies? species, IForm? form)
+ {
+ Pokemon = pokemon;
+ Species = species;
+ Form = form;
+ }
+
+ ///
+ public EventBatchId BatchId { get; init; }
+}
\ No newline at end of file
diff --git a/PkmnLib.Dynamic/Models/Pokemon.cs b/PkmnLib.Dynamic/Models/Pokemon.cs
index 76386ef..09b0ea1 100644
--- a/PkmnLib.Dynamic/Models/Pokemon.cs
+++ b/PkmnLib.Dynamic/Models/Pokemon.cs
@@ -41,6 +41,11 @@ public interface IPokemon : IScriptSource, IDeepCloneable
///
IForm? DisplayForm { get; }
+ ///
+ /// Sets the display species and form of the Pokemon. This is used for abilities like Illusion.
+ ///
+ void SetDisplaySpecies(ISpecies? species, IForm? form);
+
///
/// The current level of the Pokemon.
///
@@ -90,14 +95,7 @@ public interface IPokemon : IScriptSource, IDeepCloneable
///
/// The weight of the Pokemon in kilograms.
///
- float WeightInKg { get; set; }
-
- ///
- /// Sets the weight of the Pokémon in kilograms. Returns whether the weight was changed.
- ///
- /// The new weight in kilograms
- ///
- public bool ChangeWeightInKgBy(float weightInKg);
+ float WeightInKg { get; }
///
/// The height of the Pokémon in meters.
@@ -511,7 +509,6 @@ public class PokemonImpl : ScriptSource, IPokemon
Types = form.Types.ToList();
Experience = library.StaticLibrary.GrowthRates.CalculateExperience(species.GrowthRate, level);
- WeightInKg = form.Weight;
HeightInMeters = form.Height;
Happiness = species.BaseHappiness;
Volatile = new ScriptSet(this);
@@ -546,7 +543,6 @@ public class PokemonImpl : ScriptSource, IPokemon
}
CurrentHealth = serializedPokemon.CurrentHealth;
- WeightInKg = form.Weight;
HeightInMeters = form.Height;
Happiness = serializedPokemon.Happiness;
IndividualValues = serializedPokemon.IndividualValues.ToIndividualValueStatisticSet();
@@ -599,6 +595,18 @@ public class PokemonImpl : ScriptSource, IPokemon
///
public IForm? DisplayForm { get; set; }
+ ///
+ public void SetDisplaySpecies(ISpecies? species, IForm? form)
+ {
+ DisplaySpecies = species;
+ DisplayForm = form;
+
+ BattleData?.Battle.EventHook.Invoke(new DisplaySpeciesChangeEvent(this, species, form)
+ {
+ BatchId = new EventBatchId(),
+ });
+ }
+
///
public LevelInt Level { get; private set; }
@@ -660,18 +668,18 @@ public class PokemonImpl : ScriptSource, IPokemon
public uint CurrentHealth { get; private set; }
///
- public float WeightInKg { get; set; }
-
- ///
- public bool ChangeWeightInKgBy(float weightInKg)
+ public float WeightInKg
{
- if (WeightInKg <= 0.1f)
- return false;
- var newWeight = WeightInKg + weightInKg;
- if (newWeight <= 0.1f)
- newWeight = 0.1f;
- WeightInKg = newWeight;
- return true;
+ get
+ {
+ var weight = Form.Weight;
+ if (BattleData is not null)
+ // ReSharper disable once AccessToModifiedClosure
+ this.RunScriptHook(script => script.ModifyWeight(ref weight));
+ if (weight < 0.1f)
+ weight = 0.1f;
+ return weight;
+ }
}
///
@@ -958,7 +966,6 @@ public class PokemonImpl : ScriptSource, IPokemon
Form = form;
Types = form.Types.ToList();
- WeightInKg = form.Weight;
HeightInMeters = form.Height;
var newAbility = Form.GetAbility(AbilityIndex);
@@ -1216,7 +1223,6 @@ public class PokemonImpl : ScriptSource, IPokemon
if (!onBattleField)
{
Volatile.Clear();
- WeightInKg = Form.Weight;
HeightInMeters = Form.Height;
Types = Form.Types;
OverrideAbility = null;
@@ -1241,7 +1247,6 @@ public class PokemonImpl : ScriptSource, IPokemon
var battleData = BattleData;
BattleData = null;
Volatile.Clear();
- WeightInKg = Form.Weight;
HeightInMeters = Form.Height;
Types = Form.Types;
OverrideAbility = null;
diff --git a/PkmnLib.Dynamic/ScriptHandling/Script.cs b/PkmnLib.Dynamic/ScriptHandling/Script.cs
index 6db2c4e..d335b94 100644
--- a/PkmnLib.Dynamic/ScriptHandling/Script.cs
+++ b/PkmnLib.Dynamic/ScriptHandling/Script.cs
@@ -761,4 +761,12 @@ public abstract class Script : IDeepCloneable
public virtual void OnWeatherChange(IBattle battle, StringKey? weatherName, StringKey? oldWeatherName)
{
}
+
+ ///
+ /// Modifies the weight of a Pokemon.
+ ///
+ /// The weight in kilograms
+ public virtual void ModifyWeight(ref float weight)
+ {
+ }
}
\ 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 03d7e4e..75d4d21 100755
--- a/Plugins/PkmnLib.Plugin.Gen7/Data/Abilities.jsonc
+++ b/Plugins/PkmnLib.Plugin.Gen7/Data/Abilities.jsonc
@@ -184,6 +184,9 @@
"effect": "flash_fire"
},
"flower_gift": {
+ "flags": [
+ "cant_be_copied"
+ ],
"effect": "flower_gift"
},
"flower_veil": {
@@ -193,6 +196,9 @@
"effect": "fluffy"
},
"forecast": {
+ "flags": [
+ "cant_be_copied"
+ ],
"effect": "forecast"
},
"forewarn": {
@@ -240,26 +246,48 @@
"heatproof": {
"effect": "heatproof"
},
- "heavy_metal": {},
- "honey_gather": {},
- "huge_power": {},
- "hustle": {},
- "hydration": {},
- "hyper_cutter": {},
- "ice_body": {},
- "illuminate": {},
+ "heavy_metal": {
+ "effect": "heavy_metal"
+ },
+ "honey_gather": {
+ "effect": "honey_gather"
+ },
+ "huge_power": {
+ "effect": "huge_power"
+ },
+ "hustle": {
+ "effect": "hustle"
+ },
+ "hydration": {
+ "effect": "hydration"
+ },
+ "hyper_cutter": {
+ "effect": "hyper_cutter"
+ },
+ "ice_body": {
+ "effect": "ice_body"
+ },
+ "illuminate": {
+ "effect": "illuminate"
+ },
"illusion": {
+ "effect": "illusion",
"flags": [
"cant_be_copied"
]
},
- "immunity": {},
+ "immunity": {
+ "effect": "immunity"
+ },
"imposter": {
+ "effect": "imposter",
"flags": [
"cant_be_copied"
]
},
- "infiltrator": {},
+ "infiltrator": {
+ "effect": "infiltrator"
+ },
"innards_out": {},
"inner_focus": {},
"insomnia": {},
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/HeavyMetal.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/HeavyMetal.cs
new file mode 100644
index 0000000..5f8ad17
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/HeavyMetal.cs
@@ -0,0 +1,16 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Heavy Metal is an ability that doubles the Pokémon's weight.
+///
+/// Bulbapedia - Heavy Metal
+///
+[Script(ScriptCategory.Ability, "heavy_metal")]
+public class HeavyMetal : Script
+{
+ ///
+ public override void ModifyWeight(ref float weight)
+ {
+ weight *= 2f;
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/HoneyGather.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/HoneyGather.cs
new file mode 100644
index 0000000..c2f6627
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/HoneyGather.cs
@@ -0,0 +1,12 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Honey Gather is an ability that may allow the Pokémon to collect Honey after battle.
+///
+/// Bulbapedia - Honey Gather
+///
+[Script(ScriptCategory.Ability, "honey_gather")]
+public class HoneyGather : Script
+{
+ // No Effect in battle
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/HugePower.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/HugePower.cs
new file mode 100644
index 0000000..82c76dc
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/HugePower.cs
@@ -0,0 +1,20 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Huge Power is an ability that doubles the Pokémon's Attack stat.
+///
+/// Bulbapedia - Huge Power
+///
+[Script(ScriptCategory.Ability, "huge_power")]
+public class HugePower : Script
+{
+ ///
+ public override void ChangeOffensiveStatValue(IExecutingMove move, IPokemon target, byte hit, uint defensiveStat,
+ ImmutableStatisticSet targetStats, Statistic stat, ref uint value)
+ {
+ if (stat == Statistic.Attack)
+ {
+ value = value.MultiplyOrMax(2);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Hustle.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Hustle.cs
new file mode 100644
index 0000000..c6a7219
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Hustle.cs
@@ -0,0 +1,31 @@
+using PkmnLib.Static.Moves;
+
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Hustle is an ability that increases the Pokémon's Attack by 50% but lowers the accuracy of its physical moves.
+///
+/// Bulbapedia - Hustle
+///
+[Script(ScriptCategory.Ability, "hustle")]
+public class Hustle : Script
+{
+ ///
+ public override void ChangeOffensiveStatValue(IExecutingMove move, IPokemon target, byte hit, uint defensiveStat,
+ ImmutableStatisticSet targetStats, Statistic stat, ref uint value)
+ {
+ if (stat != Statistic.Attack)
+ return;
+ value = value.MultiplyOrMax(1.5f);
+ }
+
+ ///
+ public override void ChangeAccuracy(IExecutingMove executingMove, IPokemon target, byte hitIndex,
+ ref int modifiedAccuracy)
+ {
+ if (executingMove.UseMove.Category == MoveCategory.Physical)
+ {
+ modifiedAccuracy = (int)(modifiedAccuracy * 0.8f);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Hydration.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Hydration.cs
new file mode 100644
index 0000000..490f1f5
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Hydration.cs
@@ -0,0 +1,40 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Hydration is an ability that heals status conditions if it is raining at the end of the turn.
+///
+/// Bulbapedia - Hydration
+///
+[Script(ScriptCategory.Ability, "hydration")]
+public class Hydration : Script
+{
+ private IPokemon? _pokemon;
+
+ ///
+ public override void OnAddedToParent(IScriptSource source)
+ {
+ if (source is not IPokemon pokemon)
+ throw new InvalidOperationException("Hydration can only be added to a Pokemon script source.");
+ _pokemon = pokemon;
+ }
+
+ ///
+ public override void OnEndTurn(IBattle battle)
+ {
+ if (_pokemon is null)
+ return;
+
+ if (battle.WeatherName != ScriptUtils.ResolveName())
+ return;
+ if (_pokemon.StatusScript.IsEmpty)
+ return;
+
+ EventBatchId batchId = new();
+
+ battle.EventHook.Invoke(new AbilityTriggerEvent(_pokemon)
+ {
+ BatchId = batchId,
+ });
+ _pokemon.ClearStatus(batchId);
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/HyperCutter.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/HyperCutter.cs
new file mode 100644
index 0000000..e1003b7
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/HyperCutter.cs
@@ -0,0 +1,22 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Hyper Cutter is an ability that prevents the Pokémon's Attack stat from being lowered by other Pokémon.
+///
+/// Bulbapedia - Hyper Cutter
+///
+[Script(ScriptCategory.Ability, "hyper_cutter")]
+public class HyperCutter : Script
+{
+ ///
+ public override void PreventStatBoostChange(IPokemon target, Statistic stat, sbyte amount, bool selfInflicted,
+ ref bool prevent)
+ {
+ if (stat != Statistic.Attack)
+ return;
+
+ // Prevent the Attack stat from being lowered by any means
+ if (amount < 0 && !selfInflicted)
+ prevent = true;
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/IceBody.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/IceBody.cs
new file mode 100644
index 0000000..67fbc60
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/IceBody.cs
@@ -0,0 +1,51 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Ice Body is an ability that heals the Pokémon for 1/16 of its maximum HP each turn during hail.
+///
+/// Bulbapedia - Ice Body
+///
+[Script(ScriptCategory.Ability, "ice_body")]
+public class IceBody : Script
+{
+ private IPokemon? _pokemon;
+
+ ///
+ public override void OnAddedToParent(IScriptSource source)
+ {
+ if (source is not IPokemon pokemon)
+ throw new InvalidOperationException("Ice Body can only be added to a Pokemon script source.");
+ _pokemon = pokemon;
+ }
+
+ ///
+ public override void OnEndTurn(IBattle battle)
+ {
+ if (_pokemon is null)
+ return;
+
+ // Check if the weather is hail
+ if (battle.WeatherName != ScriptUtils.ResolveName())
+ return;
+
+ // Heal the Pokémon for 1/16 of its maximum HP
+ EventBatchId batchId = new();
+ var healAmount = _pokemon.MaxHealth / 16;
+ _pokemon.Heal(healAmount, true, batchId);
+
+ // Trigger the ability event
+ battle.EventHook.Invoke(new AbilityTriggerEvent(_pokemon)
+ {
+ BatchId = batchId,
+ });
+ }
+
+ ///
+ public override void CustomTrigger(StringKey eventName, IDictionary? parameters)
+ {
+ if (eventName != CustomTriggers.IgnoreHail || parameters is null)
+ return;
+
+ parameters["ignoresHail"] = true;
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Illuminate.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Illuminate.cs
new file mode 100644
index 0000000..4a1f9e4
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Illuminate.cs
@@ -0,0 +1,12 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Illuminate is an ability that increases the wild encounter rate when the Pokémon is leading the party.
+///
+/// Bulbapedia - Illuminate
+///
+[Script(ScriptCategory.Ability, "illuminate")]
+public class Illuminate : Script
+{
+ // No effect in battle.
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Illusion.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Illusion.cs
new file mode 100644
index 0000000..2685511
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Illusion.cs
@@ -0,0 +1,55 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Illusion is an ability that disguises the Pokémon as the last non-fainted Pokémon in the party until it takes damage.
+///
+/// Bulbapedia - Illusion
+///
+[Script(ScriptCategory.Ability, "illusion")]
+public class Illusion : Script
+{
+ private IPokemon? _pokemon;
+
+ ///
+ public override void OnAddedToParent(IScriptSource source)
+ {
+ if (source is not IPokemon pokemon)
+ throw new InvalidOperationException("Illusion can only be added to a Pokemon script source.");
+ _pokemon = pokemon;
+ }
+
+ ///
+ public override void OnSwitchIn(IPokemon pokemon, byte position)
+ {
+ var battleData = pokemon.BattleData;
+ if (battleData is null)
+ return;
+ var lastNonFaintedPokemon = battleData.Battle.Parties.FirstOrDefault(p => p.Party.Any(pkmn => pkmn == pokemon))
+ ?.Party.WhereNotNull().FirstOrDefault(x => x.IsUsable);
+ if (lastNonFaintedPokemon is null || lastNonFaintedPokemon == pokemon)
+ return;
+
+ pokemon.SetDisplaySpecies(lastNonFaintedPokemon.Species, lastNonFaintedPokemon.Form);
+ }
+
+ ///
+ public override void OnRemove()
+ {
+ if (_pokemon is null)
+ return;
+
+ _pokemon.SetDisplaySpecies(null, null);
+ _pokemon.BattleData?.Battle.EventHook.Invoke(new AbilityTriggerEvent(_pokemon));
+ }
+
+ ///
+ public override void OnIncomingHit(IExecutingMove move, IPokemon target, byte hit)
+ {
+ if (_pokemon?.BattleData?.Battle is null)
+ return;
+
+ // Remove the illusion when the Pokémon takes damage
+ _pokemon.SetDisplaySpecies(null, null);
+ _pokemon.BattleData.Battle.EventHook.Invoke(new AbilityTriggerEvent(_pokemon));
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Immunity.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Immunity.cs
new file mode 100644
index 0000000..eb84141
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Immunity.cs
@@ -0,0 +1,21 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Immunity is an ability that prevents the Pokémon from being poisoned.
+///
+/// Bulbapedia - Immunity
+///
+[Script(ScriptCategory.Ability, "immunity")]
+public class Immunity : Script
+{
+ ///
+ public override void PreventStatusChange(IPokemon pokemon, StringKey status, bool selfInflicted,
+ ref bool preventStatus)
+ {
+ if (status == ScriptUtils.ResolveName() ||
+ status == ScriptUtils.ResolveName())
+ {
+ preventStatus = true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Imposter.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Imposter.cs
new file mode 100644
index 0000000..9fdb34a
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Imposter.cs
@@ -0,0 +1,12 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Imposter is an ability that transforms the Pokémon into its opponent upon entering battle.
+///
+/// Bulbapedia - Imposter
+///
+[Script(ScriptCategory.Ability, "imposter")]
+public class Imposter : Script
+{
+ // TODO: Implement Imposter effect.
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Infiltrator.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Infiltrator.cs
new file mode 100644
index 0000000..9069bab
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Infiltrator.cs
@@ -0,0 +1,20 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
+
+///
+/// Infiltrator is an ability that allows the Pokémon's moves to ignore the opposing side's barriers and substitutes.
+///
+/// Bulbapedia - Infiltrator
+///
+[Script(ScriptCategory.Ability, "infiltrator")]
+public class Infiltrator : Script
+{
+ ///
+ public override void CustomTrigger(StringKey eventName, IDictionary? parameters)
+ {
+ if ((eventName != CustomTriggers.BypassProtection && eventName != CustomTriggers.BypassSubstitute) ||
+ parameters is null)
+ return;
+
+ parameters["bypass"] = true;
+ }
+}
\ 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 f39cfd0..132bf9b 100644
--- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/CustomTriggers.cs
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/CustomTriggers.cs
@@ -23,4 +23,8 @@ public static class CustomTriggers
public static readonly StringKey BypassChargeMove = "bypass_charge_move";
public static readonly StringKey ModifySleepTurns = "modify_sleep_turns";
+
+ public static readonly StringKey BypassProtection = "bypass_protection";
+
+ public static readonly StringKey BypassSubstitute = "bypass_subsitute";
}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Autotomize.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Autotomize.cs
index f2cc786..f8e3034 100644
--- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Autotomize.cs
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Autotomize.cs
@@ -1,3 +1,5 @@
+using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
+
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
///
@@ -21,13 +23,18 @@ public class Autotomize : Script
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var user = move.User;
- if (user.ChangeStatBoost(Statistic.Speed, 2, true, false) && user.ChangeWeightInKgBy(-100.0f))
+
+ var existingEffect = user.Volatile.Get();
+ var stacks = existingEffect?.Stacks ?? 0;
+
+ if (!user.ChangeStatBoost(Statistic.Speed, 2, true, false) || !(user.WeightInKg - 100f * stacks >= 0.1f))
+ return;
+
+ user.Volatile.StackOrAdd(ScriptUtils.ResolveName(), () => new AutotomizeEffect());
+ var battle = user.BattleData?.Battle;
+ battle?.EventHook.Invoke(new DialogEvent("pokemon_became_nimble", new Dictionary
{
- var battle = user.BattleData?.Battle;
- battle?.EventHook.Invoke(new DialogEvent("pokemon_became_nimble", new Dictionary
- {
- { "pokemon", user },
- }));
- }
+ { "pokemon", user },
+ }));
}
}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/BatonPass.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/BatonPass.cs
index 4d440b6..7a2d51d 100644
--- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/BatonPass.cs
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/BatonPass.cs
@@ -1,3 +1,4 @@
+using PkmnLib.Plugin.Gen7.Scripts.Utils;
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
@@ -36,6 +37,8 @@ public class BatonPass : Script
foreach (var script in volatileScripts)
{
+ if (script is not IBatonPassException)
+ return;
toSwitch.Volatile.Add(script);
}
}
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/AutotomizeEffect.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/AutotomizeEffect.cs
new file mode 100644
index 0000000..396b9e7
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/AutotomizeEffect.cs
@@ -0,0 +1,21 @@
+using PkmnLib.Plugin.Gen7.Scripts.Utils;
+
+namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
+
+[Script(ScriptCategory.Pokemon, "autotomize")]
+public class AutotomizeEffect : Script, IBatonPassException
+{
+ public int Stacks { get; private set; } = 1;
+
+ ///
+ public override void Stack()
+ {
+ Stacks++;
+ }
+
+ ///
+ public override void ModifyWeight(ref float weight)
+ {
+ weight -= 100f * Stacks;
+ }
+}
\ No newline at end of file
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/ProtectionEffectScript.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/ProtectionEffectScript.cs
index e8efba2..e2fc3ee 100644
--- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/ProtectionEffectScript.cs
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/ProtectionEffectScript.cs
@@ -11,6 +11,18 @@ public class ProtectionEffectScript : Script
if (!executingMove.UseMove.HasFlag("protect"))
return;
+ var bypass = false;
+ var parameters = new Dictionary
+ {
+ { "target", target },
+ { "move", executingMove },
+ { "hitIndex", hitIndex },
+ { "bypass", bypass },
+ };
+ executingMove.User.RunScriptHook(x => x.CustomTrigger(CustomTriggers.BypassProtection, parameters));
+ bypass = parameters.GetValueOrDefault("bypass", false) as bool? ?? false;
+ if (bypass)
+ return;
block = true;
}
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/SubstituteEffect.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/SubstituteEffect.cs
index d4bd91b..7890e1c 100644
--- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/SubstituteEffect.cs
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/SubstituteEffect.cs
@@ -11,6 +11,19 @@ public class SubstituteEffect(uint health) : Script
if (executingMove.UseMove.HasFlag("ignore-substitute"))
return;
+ var bypass = false;
+ var parameters = new Dictionary
+ {
+ { "target", target },
+ { "move", executingMove },
+ { "hitIndex", hitIndex },
+ { "bypass", bypass },
+ };
+ executingMove.User.RunScriptHook(x => x.CustomTrigger(CustomTriggers.BypassProtection, parameters));
+ bypass = parameters.GetValueOrDefault("bypass", false) as bool? ?? false;
+ if (bypass)
+ return;
+
block = true;
var damage = executingMove.GetHitData(target, hitIndex).Damage;
if (damage >= _health)
diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Utils/BatonPassException.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Utils/BatonPassException.cs
new file mode 100644
index 0000000..3d236de
--- /dev/null
+++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Utils/BatonPassException.cs
@@ -0,0 +1,5 @@
+namespace PkmnLib.Plugin.Gen7.Scripts.Utils;
+
+public interface IBatonPassException
+{
+}
\ No newline at end of file