diff --git a/Plugins/PkmnLib.Plugin.Gen7/Data/Abilities.jsonc b/Plugins/PkmnLib.Plugin.Gen7/Data/Abilities.jsonc index c229176..189ea87 100755 --- a/Plugins/PkmnLib.Plugin.Gen7/Data/Abilities.jsonc +++ b/Plugins/PkmnLib.Plugin.Gen7/Data/Abilities.jsonc @@ -437,9 +437,13 @@ "effect": "poison_touch" }, "power_construct": { + "canBeChanged": false, "effect": "power_construct" }, "power_of_alchemy": { + "flags": [ + "cant_be_copied" + ], "effect": "power_of_alchemy" }, "prankster": { @@ -448,13 +452,27 @@ "pressure": { "effect": "pressure" }, - "primordial_sea": {}, - "prism_armor": {}, - "protean": {}, - "psychic_surge": {}, - "pure_power": {}, - "queenly_majesty": {}, - "quick_feet": {}, + "primordial_sea": { + "effect": "primordial_sea" + }, + "prism_armor": { + "effect": "prism_armor" + }, + "protean": { + "effect": "protean" + }, + "psychic_surge": { + "effect": "psychic_surge" + }, + "pure_power": { + "effect": "pure_power" + }, + "queenly_majesty": { + "effect": "queenly_majesty" + }, + "quick_feet": { + "effect": "quick_feet" + }, "rain_dish": {}, "rattled": {}, "receiver": { diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ParentalBond.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ParentalBond.cs index 2a7c2ef..8e82aba 100644 --- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ParentalBond.cs +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ParentalBond.cs @@ -8,5 +8,17 @@ namespace PkmnLib.Plugin.Gen7.Scripts.Abilities; [Script(ScriptCategory.Ability, "parental_bond")] public class ParentalBond : Script { - // TODO: Implement Parental Bond effect. + /// + public override void ChangeNumberOfHits(IMoveChoice choice, ref byte numberOfHits) + { + if (numberOfHits == 1) + numberOfHits = 2; + } + + /// + public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref ushort basePower) + { + if (hit == 1) + basePower = (ushort)(basePower / 4); + } } \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/PrimordialSeaAbility.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/PrimordialSeaAbility.cs new file mode 100644 index 0000000..e3a3b5f --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/PrimordialSeaAbility.cs @@ -0,0 +1,25 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Abilities; + +/// +/// Primordial Sea is an ability that creates heavy rain when the Pokémon enters battle and prevents Fire-type moves from being used. +/// +/// Bulbapedia - Primordial Sea +/// +[Script(ScriptCategory.Ability, "primordial_sea")] +public class PrimordialSeaAbility : Script +{ + /// + public override void OnSwitchIn(IPokemon pokemon, byte position) + { + var battle = pokemon.BattleData?.Battle; + if (battle == null) + return; + + battle.SetWeather(ScriptUtils.ResolveName(), -1); + if (battle.WeatherName == ScriptUtils.ResolveName()) + { + ((Weather.PrimordialSea)battle.WeatherScript.Script!).MarkAsPlaced(pokemon); + battle.EventHook.Invoke(new AbilityTriggerEvent(pokemon)); + } + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/PrismArmor.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/PrismArmor.cs new file mode 100644 index 0000000..cac72a5 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/PrismArmor.cs @@ -0,0 +1,17 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Abilities; + +/// +/// Prism Armor is an ability that reduces the damage taken from super effective moves. +/// +/// Bulbapedia - Prism Armor +/// +[Script(ScriptCategory.Ability, "prism_armor")] +public class PrismArmor : Script +{ + /// + public override void ChangeIncomingMoveDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage) + { + if (move.GetHitData(target, hit).Effectiveness >= 2) + damage = (uint)(damage * 0.75); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Protean.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Protean.cs new file mode 100644 index 0000000..4fd6eff --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Protean.cs @@ -0,0 +1,19 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Abilities; + +/// +/// Protean is an ability that changes the Pokémon's type to the type of the move it is about to use. +/// +/// Bulbapedia - Protean +/// +[Script(ScriptCategory.Ability, "protean")] +public class Protean : Script +{ + /// + public override void OnBeforeMove(IExecutingMove move) + { + if (move.User.Types.Count == 1 && move.User.Types[0] == move.UseMove.MoveType) + return; + move.Battle.EventHook.Invoke(new AbilityTriggerEvent(move.User)); + move.User.SetTypes([move.UseMove.MoveType]); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/PsychicSurge.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/PsychicSurge.cs new file mode 100644 index 0000000..75ea46d --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/PsychicSurge.cs @@ -0,0 +1,28 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Abilities; + +/// +/// Psychic Surge is an ability that creates Psychic Terrain when the Pokémon enters battle. +/// +/// Bulbapedia - Psychic Surge +/// +[Script(ScriptCategory.Ability, "psychic_surge")] +public class PsychicSurge : Script +{ + /// + public override void OnSwitchIn(IPokemon pokemon, byte position) + { + if (pokemon.BattleData?.Battle is null) + return; + + var terrainName = ScriptUtils.ResolveName(); + if (pokemon.BattleData.Battle.TerrainName == terrainName) + return; + + EventBatchId batchId = new(); + pokemon.BattleData.Battle.EventHook.Invoke(new AbilityTriggerEvent(pokemon) + { + BatchId = batchId, + }); + pokemon.BattleData.Battle.SetTerrain(terrainName, batchId); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/PurePower.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/PurePower.cs new file mode 100644 index 0000000..bd50db2 --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/PurePower.cs @@ -0,0 +1,20 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Abilities; + +/// +/// Pure Power is an ability that doubles the Pokémon's Attack stat. +/// +/// Bulbapedia - Pure Power +/// +[Script(ScriptCategory.Ability, "pure_power")] +public class PurePower : 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/QueenlyMajesty.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/QueenlyMajesty.cs new file mode 100644 index 0000000..2acbdfa --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/QueenlyMajesty.cs @@ -0,0 +1,22 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Abilities; + +/// +/// Queenly Majesty is an ability that prevents priority moves from being used against the Pokémon. +/// +/// Bulbapedia - Queenly Majesty +/// +[Script(ScriptCategory.Ability, "queenly_majesty")] +public class QueenlyMajesty : Script +{ + /// + public override void FailIncomingMove(IExecutingMove move, IPokemon target, ref bool fail) + { + if (move.Targets.Count != 1) + return; + + if (move.MoveChoice.Priority > 0) + { + fail = true; + } + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/QuickFeet.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/QuickFeet.cs new file mode 100644 index 0000000..fd836ee --- /dev/null +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/QuickFeet.cs @@ -0,0 +1,20 @@ +namespace PkmnLib.Plugin.Gen7.Scripts.Abilities; + +/// +/// Quick Feet is an ability that boosts Speed when the Pokémon has a status condition. +/// +/// Bulbapedia - Quick Feet +/// +[Script(ScriptCategory.Ability, "quick_feet")] +public class QuickFeet : Script +{ + /// + public override void ChangeSpeed(ITurnChoice choice, ref uint speed) + { + if (choice.User.StatusScript.IsEmpty) + return; + if (choice.User.StatusScript.Script?.Name == "paralyzed") + speed = speed.MultiplyOrMax(2); + speed = speed.MultiplyOrMax(1.5f); + } +} \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Weather/DesolateLands.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Weather/DesolateLands.cs index 995d536..6afc004 100644 --- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Weather/DesolateLands.cs +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Weather/DesolateLands.cs @@ -33,4 +33,10 @@ public class DesolateLands : HarshSunlight if (move.UseMove.MoveType.Name == "water") fail = true; } + + /// + public override void OnEndTurn(IBattle battle) + { + // We don't want to call base.OnEndTurn here, as we want to prevent the weather from ending + } } \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Weather/HarshSunlight.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Weather/HarshSunlight.cs index db0d8c7..e32b7d2 100644 --- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Weather/HarshSunlight.cs +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Weather/HarshSunlight.cs @@ -6,8 +6,29 @@ namespace PkmnLib.Plugin.Gen7.Scripts.Weather; /// Bulbapedia - Harsh Sunlight /// [Script(ScriptCategory.Weather, "harsh_sunlight")] -public class HarshSunlight : Script +public class HarshSunlight : Script, ILimitedTurnsScript { + private int? _duration; + + /// + public int TurnsRemaining => _duration ?? 0; + + /// + public void SetTurns(int turns) + { + _duration = turns; + } + + /// + public override void OnEndTurn(IBattle battle) + { + _duration--; + if (_duration <= 0) + { + battle.SetWeather(null, 0); + } + } + /// public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref ushort basePower) { diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Weather/PrimordialSea.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Weather/PrimordialSea.cs index 7d42bbe..a47224f 100644 --- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Weather/PrimordialSea.cs +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Weather/PrimordialSea.cs @@ -1,7 +1,7 @@ namespace PkmnLib.Plugin.Gen7.Scripts.Weather; [Script(ScriptCategory.Weather, "primordial_sea")] -public class PrimordialSea : Script +public class PrimordialSea : Rain { private HashSet _placers = new(); @@ -26,4 +26,16 @@ public class PrimordialSea : Script return; preventWeatherChange = true; } + + public override void FailMove(IExecutingMove move, ref bool fail) + { + if (move.UseMove.MoveType.Name == "fire") + fail = true; + } + + /// + public override void OnEndTurn(IBattle battle) + { + // We don't want to call base.OnEndTurn here, as we want to prevent the weather from ending + } } \ No newline at end of file diff --git a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Weather/Rain.cs b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Weather/Rain.cs index 5851366..c228075 100644 --- a/Plugins/PkmnLib.Plugin.Gen7/Scripts/Weather/Rain.cs +++ b/Plugins/PkmnLib.Plugin.Gen7/Scripts/Weather/Rain.cs @@ -1,7 +1,53 @@ namespace PkmnLib.Plugin.Gen7.Scripts.Weather; [Script(ScriptCategory.Weather, "rain")] -public class Rain : Script +public class Rain : Script, ILimitedTurnsScript { - // TODO: Implement Rain + private int? _duration; + + /// + public int TurnsRemaining => _duration ?? 0; + + /// + public void SetTurns(int turns) + { + _duration = turns; + } + + /// + public override void OnEndTurn(IBattle battle) + { + _duration--; + if (_duration <= 0) + { + battle.SetWeather(null, 0); + } + } + + /// + public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref ushort basePower) + { + var hitType = move.GetHitData(target, hit).Type; + if (hitType?.Name == "water") + { + // Increase Water-type move power by 50% in rain + basePower = (ushort)(basePower * 1.5); + } + else if (hitType?.Name == "fire") + { + // Decrease Fire-type move power by 50% in rain + basePower = (ushort)(basePower * 0.5); + } + } + + /// + public override void ChangeAccuracy(IExecutingMove executingMove, IPokemon target, byte hitIndex, + ref int modifiedAccuracy) + { + modifiedAccuracy = executingMove.UseMove.Name.ToString() switch + { + "thunder" or "hurricane" or "bleakwind_storm" or "windbolt_storm" or "sandsear_storm" => 1000, + _ => modifiedAccuracy, + }; + } } \ No newline at end of file