Finishes the last few moves
All checks were successful
Build / Build (push) Successful in 49s

This commit is contained in:
Deukhoofd 2025-05-18 12:20:21 +02:00
parent 3a9123b5ba
commit 9ff4745c0a
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
19 changed files with 585 additions and 27 deletions

View File

@ -11,6 +11,7 @@
"target": "Any", "target": "Any",
"category": "special", "category": "special",
"flags": [] "flags": []
// No secondary effect
}, },
{ {
"name": "absorb", "name": "absorb",
@ -12384,7 +12385,10 @@
"contact", "contact",
"protect", "protect",
"mirror" "mirror"
] ],
"effect": {
"name": "volt_tackle"
}
}, },
{ {
"name": "wake_up_slap", "name": "wake_up_slap",
@ -12399,7 +12403,10 @@
"contact", "contact",
"protect", "protect",
"mirror" "mirror"
] ],
"effect": {
"name": "wake_up_slap"
}
}, },
{ {
"name": "water_gun", "name": "water_gun",
@ -12414,6 +12421,7 @@
"protect", "protect",
"mirror" "mirror"
] ]
// No secondary effect
}, },
{ {
"name": "water_pledge", "name": "water_pledge",
@ -12428,7 +12436,10 @@
"protect", "protect",
"mirror", "mirror",
"nonskybattle" "nonskybattle"
] ],
"effect": {
"name": "water_pledge"
}
}, },
{ {
"name": "water_pulse", "name": "water_pulse",
@ -12444,7 +12455,11 @@
"mirror", "mirror",
"distance", "distance",
"pulse" "pulse"
] ],
"effect": {
"name": "confuse",
"chance": 20
}
}, },
{ {
"name": "water_shuriken", "name": "water_shuriken",
@ -12458,7 +12473,10 @@
"flags": [ "flags": [
"protect", "protect",
"mirror" "mirror"
] ],
"effect": {
"name": "2_5_hit_move"
}
}, },
{ {
"name": "water_sport", "name": "water_sport",
@ -12471,7 +12489,10 @@
"category": "status", "category": "status",
"flags": [ "flags": [
"nonskybattle" "nonskybattle"
] ],
"effect": {
"name": "water_sport"
}
}, },
{ {
"name": "water_spout", "name": "water_spout",
@ -12485,7 +12506,10 @@
"flags": [ "flags": [
"protect", "protect",
"mirror" "mirror"
] ],
"effect": {
"name": "eruption"
}
}, },
{ {
"name": "waterfall", "name": "waterfall",
@ -12500,7 +12524,11 @@
"contact", "contact",
"protect", "protect",
"mirror" "mirror"
] ],
"effect": {
"name": "flinch",
"chance": 20
}
}, },
{ {
"name": "weather_ball", "name": "weather_ball",
@ -12515,7 +12543,10 @@
"protect", "protect",
"mirror", "mirror",
"ballistics" "ballistics"
] ],
"effect": {
"name": "weather_ball"
}
}, },
{ {
"name": "whirlpool", "name": "whirlpool",
@ -12529,8 +12560,13 @@
"flags": [ "flags": [
"protect", "protect",
"mirror", "mirror",
"mental" "mental",
] "hit_underwater",
"effective_against_underwater"
],
"effect": {
"name": "whirlpool"
}
}, },
{ {
"name": "whirlwind", "name": "whirlwind",
@ -12545,7 +12581,10 @@
"reflectable", "reflectable",
"mirror", "mirror",
"ignore-substitute" "ignore-substitute"
] ],
"effect": {
"name": "roar"
}
}, },
{ {
"name": "wide_guard", "name": "wide_guard",
@ -12558,7 +12597,10 @@
"category": "status", "category": "status",
"flags": [ "flags": [
"snatch" "snatch"
] ],
"effect": {
"name": "wide_guard"
}
}, },
{ {
"name": "wild_charge", "name": "wild_charge",
@ -12573,7 +12615,13 @@
"contact", "contact",
"protect", "protect",
"mirror" "mirror"
] ],
"effect": {
"name": "recoil",
"parameters": {
"recoilPercent": 0.25
}
}
}, },
{ {
"name": "will_o_wisp", "name": "will_o_wisp",
@ -12588,7 +12636,13 @@
"protect", "protect",
"reflectable", "reflectable",
"mirror" "mirror"
] ],
"effect": {
"name": "set_status",
"parameters": {
"status": "burned"
}
}
}, },
{ {
"name": "wing_attack", "name": "wing_attack",
@ -12605,6 +12659,7 @@
"mirror", "mirror",
"distance" "distance"
] ]
// No secondary effect
}, },
{ {
"name": "wish", "name": "wish",
@ -12618,7 +12673,10 @@
"flags": [ "flags": [
"snatch", "snatch",
"heal" "heal"
] ],
"effect": {
"name": "wish"
}
}, },
{ {
"name": "withdraw", "name": "withdraw",
@ -12631,7 +12689,13 @@
"category": "status", "category": "status",
"flags": [ "flags": [
"snatch" "snatch"
] ],
"effect": {
"name": "change_user_defense",
"parameters": {
"amount": 1
}
}
}, },
{ {
"name": "wonder_room", "name": "wonder_room",
@ -12644,7 +12708,10 @@
"category": "status", "category": "status",
"flags": [ "flags": [
"mirror" "mirror"
] ],
"effect": {
"name": "wonder_room"
}
}, },
{ {
"name": "wood_hammer", "name": "wood_hammer",
@ -12659,7 +12726,13 @@
"contact", "contact",
"protect", "protect",
"mirror" "mirror"
] ],
"effect": {
"name": "recoil",
"parameters": {
"recoilPercent": 0.33
}
}
}, },
{ {
"name": "work_up", "name": "work_up",
@ -12672,7 +12745,14 @@
"category": "status", "category": "status",
"flags": [ "flags": [
"snatch" "snatch"
] ],
"effect": {
"name": "change_multiple_user_stat_boosts",
"parameters": {
"attack": 1,
"specialAttack": 1
}
}
}, },
{ {
"name": "worry_seed", "name": "worry_seed",
@ -12687,7 +12767,10 @@
"protect", "protect",
"reflectable", "reflectable",
"mirror" "mirror"
] ],
"effect": {
"name": "worry_seed"
}
}, },
{ {
"name": "wrap", "name": "wrap",
@ -12702,7 +12785,10 @@
"contact", "contact",
"protect", "protect",
"mirror" "mirror"
] ],
"effect": {
"name": "bind"
}
}, },
{ {
"name": "wring_out", "name": "wring_out",
@ -12717,7 +12803,10 @@
"contact", "contact",
"protect", "protect",
"mirror" "mirror"
] ],
"effect": {
"name": "crush_grip"
}
}, },
{ {
"name": "x_scissor", "name": "x_scissor",
@ -12733,6 +12822,7 @@
"protect", "protect",
"mirror" "mirror"
] ]
// No secondary effect
}, },
{ {
"name": "yawn", "name": "yawn",
@ -12747,7 +12837,10 @@
"protect", "protect",
"reflectable", "reflectable",
"mirror" "mirror"
] ],
"effect": {
"name": "yawn"
}
}, },
{ {
"name": "zap_cannon", "name": "zap_cannon",
@ -12761,7 +12854,13 @@
"flags": [ "flags": [
"protect", "protect",
"mirror" "mirror"
] ],
"effect": {
"name": "set_status",
"parameters": {
"status": "paralyzed"
}
}
}, },
{ {
"name": "zen_headbutt", "name": "zen_headbutt",
@ -12776,7 +12875,11 @@
"contact", "contact",
"protect", "protect",
"mirror" "mirror"
] ],
"effect": {
"name": "flinch",
"chance": 20
}
}, },
{ {
"name": "zing_zap", "name": "zing_zap",
@ -12791,7 +12894,11 @@
"contact", "contact",
"protect", "protect",
"mirror" "mirror"
] ],
"effect": {
"name": "flinch",
"chance": 30
}
} }
] ]
} }

View File

@ -0,0 +1,28 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Battle;
[Script(ScriptCategory.Battle, "water_sport")]
public class WaterSportEffect : Script
{
public readonly HashSet<IPokemon> Placers = new();
/// <inheritdoc />
public override void ChangeMoveDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage)
{
if (move.UseMove.MoveType.Name == "fire")
{
damage = damage / 2;
}
}
/// <inheritdoc />
public override void OnSwitchOut(IPokemon oldPokemon, byte position)
{
if (!Placers.Contains(oldPokemon))
return;
Placers.Remove(oldPokemon);
if (Placers.Count == 0)
{
RemoveSelf();
}
}
}

View File

@ -0,0 +1,30 @@
using PkmnLib.Static.Moves;
namespace PkmnLib.Plugin.Gen7.Scripts.Battle;
public class WonderRoomEffect : Script
{
public int TurnsLeft { get; private set; } = 5;
/// <inheritdoc />
public override void ChangeDefensiveStatValue(IExecutingMove move, IPokemon target, byte hit, uint offensiveStat,
ImmutableStatisticSet<uint> targetStats, ref uint value)
{
value = move.UseMove.Category switch
{
MoveCategory.Special => targetStats.Defense,
MoveCategory.Physical => targetStats.SpecialDefense,
_ => value,
};
}
/// <inheritdoc />
public override void OnEndTurn(IBattle battle)
{
TurnsLeft--;
if (TurnsLeft <= 0)
{
RemoveSelf();
}
}
}

View File

@ -17,4 +17,6 @@ public static class CustomTriggers
public static readonly StringKey ReflectNumberOfTurns = "reflect_number_of_turns"; public static readonly StringKey ReflectNumberOfTurns = "reflect_number_of_turns";
public static readonly StringKey BypassSleep = "bypass_sleep"; public static readonly StringKey BypassSleep = "bypass_sleep";
public static readonly StringKey Whirlpool = "whirlpool";
} }

View File

@ -0,0 +1,18 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "volt_tackle")]
public class VoltTackle : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var hitData = move.GetHitData(target, hit);
var recoilDamage = (uint)(hitData.Damage * (1f / 3f));
move.User.Damage(recoilDamage, DamageSource.Misc);
if (move.Battle.Random.EffectChance(10, move, target, hit))
{
target.SetStatus(ScriptUtils.ResolveName<Status.Paralyzed>());
}
}
}

View File

@ -0,0 +1,26 @@
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "wake_up_slap")]
public class WakeUpSlap : Script
{
/// <inheritdoc />
public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref ushort basePower)
{
if (target.HasStatus(ScriptUtils.ResolveName<Status.Sleep>()))
{
basePower = basePower.MultiplyOrMax(2);
}
}
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
// Wake up the target if it is asleep
if (target.HasStatus(ScriptUtils.ResolveName<Status.Sleep>()))
{
target.ClearStatus();
}
}
}

View File

@ -0,0 +1,7 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "water_pledge")]
public class WaterPledge : Script
{
// TODO: pledge moves
}

View File

@ -0,0 +1,17 @@
using PkmnLib.Plugin.Gen7.Scripts.Battle;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "water_sport")]
public class WaterSport : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var effect = move.Battle.Volatile.Add(new WaterSportEffect());
if (effect?.Script is WaterSportEffect waterSportEffect)
{
waterSportEffect.Placers.Add(move.User);
}
}
}

View File

@ -0,0 +1,39 @@
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "weather_ball")]
public class WeatherBall : Script
{
/// <inheritdoc />
public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref ushort basePower)
{
if (move.Battle.WeatherName is not null)
{
basePower = basePower.MultiplyOrMax(2);
}
}
/// <inheritdoc />
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit,
ref TypeIdentifier? typeIdentifier)
{
var weather = move.Battle.WeatherName;
var typeLibrary = move.Battle.Library.StaticLibrary.Types;
if (weather is null)
return;
if (weather == ScriptUtils.ResolveName<Weather.Sunny>() &&
typeLibrary.TryGetTypeIdentifier("fire", out var fireType))
typeIdentifier = fireType;
else if (weather == ScriptUtils.ResolveName<Weather.Rain>() &&
typeLibrary.TryGetTypeIdentifier("water", out var waterType))
typeIdentifier = waterType;
else if (weather == ScriptUtils.ResolveName<Weather.Hail>() &&
typeLibrary.TryGetTypeIdentifier("ice", out var iceType))
typeIdentifier = iceType;
else if (weather == ScriptUtils.ResolveName<Weather.Sandstorm>() &&
typeLibrary.TryGetTypeIdentifier("rock", out var rockType))
typeIdentifier = rockType;
}
}

View File

@ -0,0 +1,28 @@
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "whirlpool")]
public class Whirlpool : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var userVolatile = move.User.Volatile.Add(new WhirlpoolEffect());
if (userVolatile?.Script is WhirlpoolEffect whirlpoolEffect)
{
var turns = move.Battle.Random.GetInt(4, 6);
var damagePercent = 0.125f;
var parameters = new Dictionary<StringKey, object?>
{
{ "number_of_turns", turns },
{ "damage_percent", damagePercent },
};
move.RunScriptHook(x => x.CustomTrigger(CustomTriggers.Whirlpool, parameters));
turns = parameters.GetValueOrDefault("number_of_turns", turns) as int? ?? turns;
damagePercent = parameters.GetValueOrDefault("damage_percent", damagePercent) as float? ?? damagePercent;
whirlpoolEffect.AddTargetedPokemon(target, turns, damagePercent);
}
}
}

View File

@ -0,0 +1,18 @@
using PkmnLib.Plugin.Gen7.Scripts.Side;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "wide_guard")]
public class WideGuard : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
if (move.Battle.ChoiceQueue?.HasNext() != true)
{
move.GetHitData(target, hit).Fail();
return;
}
move.User.BattleData?.BattleSide.VolatileScripts.Add(new WideGuardEffect());
}
}

View File

@ -0,0 +1,11 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "wish")]
public class Wish : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
move.User.Volatile.Add(new Pokemon.WishEffect());
}
}

View File

@ -0,0 +1,13 @@
using PkmnLib.Plugin.Gen7.Scripts.Battle;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "wonder_room")]
public class WonderRoom : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
move.Battle.Volatile.Add(new WonderRoomEffect());
}
}

View File

@ -0,0 +1,17 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "worry_seed")]
public class WorrySeed : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var abilityLibrary = move.Battle.Library.StaticLibrary.Abilities;
if (!abilityLibrary.TryGet("insomnia", out var ability))
{
// Edge case: if the ability is not found, we should not change the ability.
return;
}
target.ChangeAbility(ability);
}
}

View File

@ -0,0 +1,13 @@
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "yawn")]
public class Yawn : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
target.Volatile.Add(new YawnEffect());
}
}

View File

@ -0,0 +1,75 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
[Script(ScriptCategory.Pokemon, "whirlpool")]
public class WhirlpoolEffect : Script
{
public record PokemonTurn
{
public PokemonTurn(IPokemon pokemon, int turns, float damagePercent)
{
Pokemon = pokemon;
Turns = turns;
DamagePercent = damagePercent;
}
public IPokemon Pokemon { get; }
public int Turns { get; set; }
public float DamagePercent { get; }
}
private IPokemon? _user;
private readonly IList<PokemonTurn> _targetedPokemon = [];
/// <inheritdoc />
public override void OnAddedToParent(IScriptSource source)
{
if (source is IPokemon pokemon)
{
_user = pokemon;
}
else
{
throw new InvalidOperationException("WhirlpoolEffect can only be added to a Pokemon.");
}
}
public void AddTargetedPokemon(IPokemon pokemon, int turns, float damagePercent)
{
if (_targetedPokemon.All(x => x.Pokemon != pokemon))
{
_targetedPokemon.Add(new PokemonTurn(pokemon, turns, damagePercent));
}
}
/// <inheritdoc />
public override void PreventOpponentRunAway(IFleeChoice choice, ref bool prevent)
{
if (_targetedPokemon.Any(x => x.Pokemon == choice.User))
prevent = true;
}
/// <inheritdoc />
public override void PreventOpponentSwitch(ISwitchChoice choice, ref bool prevent)
{
if (_targetedPokemon.Any(x => x.Pokemon == choice.User))
prevent = true;
}
/// <inheritdoc />
public override void OnEndTurn(IBattle battle)
{
if (_user == null)
return;
foreach (var pokemonTurn in _targetedPokemon.Where(x => x.Pokemon.BattleData?.IsOnBattlefield == true))
{
var pokemon = pokemonTurn.Pokemon;
pokemon.Damage((uint)(pokemon.MaxHealth * pokemonTurn.DamagePercent), DamageSource.Misc);
pokemonTurn.Turns--;
if (pokemonTurn.Turns <= 0)
{
_targetedPokemon.Remove(pokemonTurn);
}
}
}
}

View File

@ -0,0 +1,35 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
[Script(ScriptCategory.Pokemon, "wish")]
public class WishEffect : Script
{
private IPokemon? _pokemon;
private bool _hasDoneFirstTurn;
/// <inheritdoc />
public override void OnAddedToParent(IScriptSource source)
{
if (source is not IPokemon pokemon)
{
throw new InvalidOperationException("Wish script can only be added to a Pokemon.");
}
_pokemon = pokemon;
}
/// <inheritdoc />
public override void OnEndTurn(IBattle battle)
{
if (_pokemon == null)
return;
if (!_hasDoneFirstTurn)
{
_hasDoneFirstTurn = true;
return;
}
if (_pokemon.BattleData?.IsOnBattlefield == true)
{
_pokemon.Heal(_pokemon.MaxHealth / 2);
}
}
}

View File

@ -0,0 +1,36 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
[Script(ScriptCategory.Pokemon, "yawn")]
public class YawnEffect : Script
{
private IPokemon? _pokemon;
private bool _hasDoneFirstTurn;
/// <inheritdoc />
public override void OnAddedToParent(IScriptSource source)
{
if (source is IPokemon pokemon)
{
_pokemon = pokemon;
}
else
{
throw new InvalidOperationException("YawnEffect can only be added to a Pokemon.");
}
}
/// <inheritdoc />
public override void OnEndTurn(IBattle battle)
{
if (_pokemon == null)
{
return;
}
if (!_hasDoneFirstTurn)
{
_hasDoneFirstTurn = true;
return;
}
_pokemon.SetStatus(ScriptUtils.ResolveName<Status.Sleep>());
}
}

View File

@ -0,0 +1,38 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Side;
[Script(ScriptCategory.Side, "wide_guard")]
public class WideGuardEffect : Script
{
private IBattleSide? _side;
/// <inheritdoc />
public override void OnAddedToParent(IScriptSource source)
{
if (source is IBattleSide side)
{
_side = side;
}
else
{
throw new InvalidOperationException("WideGuard can only be added to a battle side.");
}
}
/// <inheritdoc />
public override void ChangeTargets(IMoveChoice moveChoice, ref IReadOnlyList<IPokemon?> targets)
{
if (_side == null)
return;
if (targets.Count > 1)
{
targets = targets.Where(x => x?.BattleData?.BattleSide != _side).ToList();
}
}
/// <inheritdoc />
public override void OnEndTurn(IBattle battle)
{
RemoveSelf();
}
}