Implements a bunch more moves
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
Deukhoofd 2025-05-17 17:44:15 +02:00
parent ecabe2fd10
commit a17cb92c5a
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
62 changed files with 1180 additions and 81 deletions

View File

@ -1,11 +1,12 @@
using PkmnLib.Dynamic.Events;
using PkmnLib.Dynamic.Models;
using PkmnLib.Dynamic.Models.Choices;
using PkmnLib.Dynamic.ScriptHandling;
using PkmnLib.Static;
using PkmnLib.Static.Moves;
using PkmnLib.Static.Utils;
namespace PkmnLib.Dynamic.Models.BattleFlow;
namespace PkmnLib.Dynamic.BattleFlow;
/// <summary>
/// Helper class for executing moves.
@ -50,6 +51,12 @@ public static class MoveTurnExecutor
var targets =
TargetResolver.ResolveTargets(battle, moveChoice.TargetSide, moveChoice.TargetPosition, targetType);
moveChoice.RunScriptHook(x => x.ChangeTargets(moveChoice, ref targets));
if (targets.Count == 0)
{
moveChoice.Fail();
return;
}
var targetSide = battle.Sides[moveChoice.TargetSide];
targetSide.RunScriptHook(x => x.ChangeIncomingTargets(moveChoice, ref targets));
@ -142,12 +149,14 @@ public static class MoveTurnExecutor
var hitIndex = i;
executingMove.RunScriptHook(x => x.OnBeforeHit(executingMove, target, hitIndex));
var hitData = (HitData)executingMove.GetDataFromRawIndex(targetHitStat + i);
if (hitData.HasFailed)
break;
var useMove = executingMove.UseMove;
var hitType = (TypeIdentifier?)useMove.MoveType;
executingMove.RunScriptHook(x => x.ChangeMoveType(executingMove, target, hitIndex, ref hitType));
var hitData = (HitData)executingMove.GetDataFromRawIndex(targetHitStat + i);
hitData.Type = hitType;
var types = target.Types.ToList();

View File

@ -1,6 +1,7 @@
using PkmnLib.Dynamic.Models;
using PkmnLib.Static.Moves;
namespace PkmnLib.Dynamic.Models.BattleFlow;
namespace PkmnLib.Dynamic.BattleFlow;
/// <summary>
/// Helper class for resolving the targets of a move.

View File

@ -1,8 +1,9 @@
using PkmnLib.Dynamic.Models;
using PkmnLib.Dynamic.Models.Choices;
using PkmnLib.Dynamic.ScriptHandling;
using PkmnLib.Static.Utils;
namespace PkmnLib.Dynamic.Models.BattleFlow;
namespace PkmnLib.Dynamic.BattleFlow;
/// <summary>
/// Helper class for handling the running of a turn in a battle.

View File

@ -1,7 +1,7 @@
using System.Diagnostics.CodeAnalysis;
using PkmnLib.Dynamic.BattleFlow;
using PkmnLib.Dynamic.Events;
using PkmnLib.Dynamic.Libraries;
using PkmnLib.Dynamic.Models.BattleFlow;
using PkmnLib.Dynamic.Models.Choices;
using PkmnLib.Dynamic.ScriptHandling;
using PkmnLib.Static;

View File

@ -646,6 +646,16 @@ public abstract class Script : IDeepCloneable
{
}
/// <summary>
/// This function allows a script to change the accuracy of a move that is incoming. The value for accuracy is in percentage.
/// A custom case goes when 255 is returned, in which case the entire accuracy check is skipped, and the move
/// will always hit.
/// </summary>
public virtual void ChangeIncomingAccuracy(IExecutingMove executingMove, IPokemon target, byte hitIndex,
ref int modifiedAccuracy)
{
}
/// <summary>
/// This function allows a script to change the weather duration of a weather effect.
/// </summary>

View File

@ -46,6 +46,8 @@ public interface IRandom
/// Get a random boolean. 50% chance of being true.
/// </summary>
public bool GetBool();
public T OneOf<T>(IReadOnlyList<T> list);
}
/// <inheritdoc />
@ -94,4 +96,12 @@ public class RandomImpl : IRandom
/// <inheritdoc />
public bool GetBool() => _random.Next(2) == 1;
/// <inheritdoc />
public T OneOf<T>(IReadOnlyList<T> list)
{
if (list.Count == 0)
throw new ArgumentException("List cannot be empty.", nameof(list));
return list[GetInt(list.Count)];
}
}

View File

@ -1,9 +1,8 @@
using PkmnLib.Dynamic.Libraries;
using PkmnLib.Dynamic.ScriptHandling;
using PkmnLib.Static.Moves;
using PkmnLib.Tests.Integration;
namespace PkmnLib.Tests.DataTests;
namespace PkmnLib.Plugin.Gen7.Tests.DataTests;
public class MoveDataTests
{

View File

@ -0,0 +1,17 @@
using PkmnLib.Dynamic.Libraries;
namespace PkmnLib.Plugin.Gen7.Tests;
public static class LibraryHelpers
{
public static IDynamicLibrary LoadLibrary()
{
var dynamicLibrary = DynamicLibraryImpl.Create([
new Gen7Plugin(new Gen7PluginConfiguration
{
DamageCalculatorHasRandomness = false,
}),
]);
return dynamicLibrary;
}
}

View File

@ -11080,7 +11080,10 @@
"flags": [
"snatch",
"nonskybattle"
]
],
"effect": {
"name": "substitute"
}
},
{
"name": "subzero_slammer__physical",
@ -11092,6 +11095,7 @@
"target": "Any",
"category": "physical",
"flags": []
// No secondary effect
},
{
"name": "subzero_slammer__special",
@ -11103,6 +11107,7 @@
"target": "Any",
"category": "special",
"flags": []
// No secondary effect
},
{
"name": "sucker_punch",
@ -11117,7 +11122,10 @@
"contact",
"protect",
"mirror"
]
],
"effect": {
"name": "sucker_punch"
}
},
{
"name": "sunny_day",
@ -11128,7 +11136,13 @@
"priority": 0,
"target": "All",
"category": "status",
"flags": []
"flags": [],
"effect": {
"name": "set_weather",
"parameters": {
"weather": "sunny"
}
}
},
{
"name": "sunsteel_strike",
@ -11143,7 +11157,10 @@
"contact",
"protect",
"mirror"
]
],
"effect": {
"name": "moongeist_beam"
}
},
{
"name": "super_fang",
@ -11158,7 +11175,10 @@
"contact",
"protect",
"mirror"
]
],
"effect": {
"name": "super_fang"
}
},
{
"name": "superpower",
@ -11173,7 +11193,10 @@
"contact",
"protect",
"mirror"
]
],
"effect": {
"name": "superpower"
}
},
{
"name": "supersonic",
@ -11190,7 +11213,10 @@
"mirror",
"sound",
"ignore-substitute"
]
],
"effect": {
"name": "confuse"
}
},
{
"name": "supersonic_skystrike__physical",
@ -11202,6 +11228,7 @@
"target": "Any",
"category": "physical",
"flags": []
// No secondary effect
},
{
"name": "supersonic_skystrike__special",
@ -11213,6 +11240,7 @@
"target": "Any",
"category": "special",
"flags": []
// No secondary effect
},
{
"name": "surf",
@ -11226,8 +11254,10 @@
"flags": [
"protect",
"mirror",
"nonskybattle"
"nonskybattle",
"effective_against_underwater"
]
// No secondary effect
},
{
"name": "swagger",
@ -11242,7 +11272,10 @@
"protect",
"reflectable",
"mirror"
]
],
"effect": {
"name": "swagger"
}
},
{
"name": "swallow",
@ -11256,7 +11289,10 @@
"flags": [
"snatch",
"heal"
]
],
"effect": {
"name": "swallow"
}
},
{
"name": "sweet_kiss",
@ -11271,7 +11307,10 @@
"protect",
"reflectable",
"mirror"
]
],
"effect": {
"name": "confuse"
}
},
{
"name": "sweet_scent",
@ -11286,14 +11325,20 @@
"protect",
"reflectable",
"mirror"
]
],
"effect": {
"name": "change_target_evasion",
"parameters": {
"amount": -1
}
}
},
{
"name": "swift",
"type": "normal",
"power": 60,
"pp": 20,
"accuracy": 0,
"accuracy": 255,
"priority": 0,
"target": "AllOpponent",
"category": "special",
@ -11301,6 +11346,7 @@
"protect",
"mirror"
]
// No secondary effect
},
{
"name": "switcheroo",
@ -11314,7 +11360,10 @@
"flags": [
"protect",
"mirror"
]
],
"effect": {
"name": "switcheroo"
}
},
{
"name": "swords_dance",
@ -11328,7 +11377,13 @@
"flags": [
"snatch",
"dance"
]
],
"effect": {
"name": "change_user_attack",
"parameters": {
"amount": 2
}
}
},
{
"name": "synchronoise",
@ -11342,7 +11397,10 @@
"flags": [
"protect",
"mirror"
]
],
"effect": {
"name": "synchronoise"
}
},
{
"name": "synthesis",
@ -11356,7 +11414,10 @@
"flags": [
"snatch",
"heal"
]
],
"effect": {
"name": "synthesis"
}
},
{
"name": "tackle",
@ -11372,6 +11433,7 @@
"protect",
"mirror"
]
// No secondary effect
},
{
"name": "tail_glow",
@ -11384,7 +11446,13 @@
"category": "status",
"flags": [
"snatch"
]
],
"effect": {
"name": "change_user_special_attack",
"parameters": {
"amount": 3
}
}
},
{
"name": "tail_slap",
@ -11399,7 +11467,10 @@
"contact",
"protect",
"mirror"
]
],
"effect": {
"name": "2_5_hit_move"
}
},
{
"name": "tail_whip",
@ -11414,7 +11485,13 @@
"protect",
"reflectable",
"mirror"
]
],
"effect": {
"name": "change_target_defense",
"parameters": {
"amount": -1
}
}
},
{
"name": "tailwind",
@ -11427,7 +11504,10 @@
"category": "status",
"flags": [
"snatch"
]
],
"effect": {
"name": "tailwind"
}
},
{
"name": "take_down",
@ -11442,7 +11522,13 @@
"contact",
"protect",
"mirror"
]
],
"effect": {
"name": "recoil",
"parameters": {
"recoilPercent": 0.25
}
}
},
{
"name": "taunt",
@ -11460,7 +11546,10 @@
"ignore-substitute",
"mental",
"limit_move_choice"
]
],
"effect": {
"name": "taunt"
}
},
{
"name": "tearful_look",
@ -11474,7 +11563,14 @@
"flags": [
"reflectable",
"mirror"
]
],
"effect": {
"name": "change_multiple_target_stat_boosts",
"parameters": {
"attack": -1,
"specialAttack": -1
}
}
},
{
"name": "techno_blast",
@ -11488,7 +11584,10 @@
"flags": [
"protect",
"mirror"
]
],
"effect": {
"name": "techno_blast"
}
},
{
"name": "tectonic_rage__physical",
@ -11500,6 +11599,7 @@
"target": "Any",
"category": "physical",
"flags": []
// No secondary effect
},
{
"name": "tectonic_rage__special",
@ -11511,6 +11611,7 @@
"target": "Any",
"category": "special",
"flags": []
// No secondary effect
},
{
"name": "teeter_dance",
@ -11525,7 +11626,10 @@
"protect",
"mirror",
"dance"
]
],
"effect": {
"name": "confuse"
}
},
{
"name": "telekinesis",
@ -11541,7 +11645,10 @@
"reflectable",
"mirror",
"gravity"
]
],
"effect": {
"name": "telekinesis"
}
},
{
"name": "teleport",
@ -11552,7 +11659,10 @@
"priority": 0,
"target": "Self",
"category": "status",
"flags": []
"flags": [],
"effect": {
"name": "teleport"
}
},
{
"name": "thief",
@ -11567,7 +11677,10 @@
"contact",
"protect",
"mirror"
]
],
"effect": {
"name": "covet"
}
},
{
"name": "thousand_arrows",
@ -11581,8 +11694,12 @@
"flags": [
"protect",
"mirror",
"nonskybattle"
]
"nonskybattle",
"hit_flying"
],
"effect": {
"name": "thousand_arrows"
}
},
{
"name": "thousand_waves",
@ -11597,7 +11714,10 @@
"protect",
"mirror",
"nonskybattle"
]
],
"effect": {
"name": "thousand_waves"
}
},
{
"name": "thrash",
@ -11630,7 +11750,10 @@
"contact",
"protect",
"mirror"
]
],
"effect": {
"name": "throat_chop"
}
},
{
"name": "thunder",
@ -11645,7 +11768,14 @@
"protect",
"mirror",
"hit_flying"
]
],
"effect": {
"name": "set_status",
"chance": 30,
"parameters": {
"status": "paralyzed"
}
}
},
{
"name": "thunder_fang",
@ -11661,7 +11791,10 @@
"protect",
"mirror",
"bite"
]
],
"effect": {
"name": "thunder_fang"
}
},
{
"name": "thunder_punch",
@ -11677,7 +11810,14 @@
"protect",
"mirror",
"punch"
]
],
"effect": {
"name": "set_status",
"chance": 10,
"parameters": {
"status": "paralyzed"
}
}
},
{
"name": "thunder_shock",
@ -11691,7 +11831,14 @@
"flags": [
"protect",
"mirror"
]
],
"effect": {
"name": "set_status",
"chance": 10,
"parameters": {
"status": "paralyzed"
}
}
},
{
"name": "thunder_wave",
@ -11706,7 +11853,13 @@
"protect",
"reflectable",
"mirror"
]
],
"effect": {
"name": "set_status",
"parameters": {
"status": "paralyzed"
}
}
},
{
"name": "thunderbolt",
@ -11720,7 +11873,14 @@
"flags": [
"protect",
"mirror"
]
],
"effect": {
"name": "set_status",
"chance": 10,
"parameters": {
"status": "paralyzed"
}
}
},
{
"name": "tickle",
@ -11735,7 +11895,14 @@
"protect",
"reflectable",
"mirror"
]
],
"effect": {
"name": "change_multiple_target_stat_boosts",
"parameters": {
"attack": -1,
"defense": -1
}
}
},
{
"name": "topsy_turvy",
@ -11750,7 +11917,10 @@
"protect",
"reflectable",
"mirror"
]
],
"effect": {
"name": "topsy_turvy"
}
},
{
"name": "torment",
@ -11768,7 +11938,10 @@
"ignore-substitute",
"mental",
"limit_move_choice"
]
],
"effect": {
"name": "torment"
}
},
{
"name": "toxic",
@ -11783,7 +11956,13 @@
"protect",
"reflectable",
"mirror"
]
],
"effect": {
"name": "set_status",
"parameters": {
"status": "badly_poisoned"
}
}
},
{
"name": "toxic_spikes",
@ -11797,7 +11976,10 @@
"flags": [
"reflectable",
"nonskybattle"
]
],
"effect": {
"name": "toxic_spikes"
}
},
{
"name": "toxic_thread",
@ -11812,7 +11994,10 @@
"protect",
"reflectable",
"mirror"
]
],
"effect": {
"name": "toxic_thread"
}
},
{
"name": "transform",
@ -11823,7 +12008,10 @@
"priority": 0,
"target": "Any",
"category": "status",
"flags": []
"flags": [],
"effect": {
"name": "transform"
}
},
{
"name": "tri_attack",
@ -11837,7 +12025,10 @@
"flags": [
"protect",
"mirror"
]
],
"effect": {
"name": "tri_attack"
}
},
{
"name": "trick",
@ -11851,7 +12042,10 @@
"flags": [
"protect",
"mirror"
]
],
"effect": {
"name": "switcheroo"
}
},
{
"name": "trick_or_treat",
@ -11866,7 +12060,10 @@
"protect",
"reflectable",
"mirror"
]
],
"effect": {
"name": "trick_or_treat"
}
},
{
"name": "trick_room",
@ -11879,7 +12076,10 @@
"category": "status",
"flags": [
"mirror"
]
],
"effect": {
"name": "trick_room"
}
},
{
"name": "triple_kick",
@ -11894,7 +12094,10 @@
"contact",
"protect",
"mirror"
]
],
"effect": {
"name": "triple_kick"
}
},
{
"name": "trop_kick",
@ -11909,7 +12112,13 @@
"contact",
"protect",
"mirror"
]
],
"effect": {
"name": "change_target_attack",
"parameters": {
"amount": -1
}
}
},
{
"name": "trump_card",
@ -11924,7 +12133,10 @@
"contact",
"protect",
"mirror"
]
],
"effect": {
"name": "trump_card"
}
},
{
"name": "twineedle",
@ -11938,7 +12150,10 @@
"flags": [
"protect",
"mirror"
]
],
"effect": {
"name": "twineedle"
}
},
{
"name": "twinkle_tackle__physical",
@ -11950,6 +12165,7 @@
"target": "Any",
"category": "physical",
"flags": []
// No secondary effect
},
{
"name": "twinkle_tackle__special",
@ -11961,6 +12177,7 @@
"target": "Any",
"category": "special",
"flags": []
// No secondary effect
},
{
"name": "twister",
@ -11976,7 +12193,11 @@
"mirror",
"hit_flying",
"effective_against_fly"
]
],
"effect": {
"name": "flinch",
"chance": 20
}
},
{
"name": "u_turn",
@ -11991,7 +12212,10 @@
"contact",
"protect",
"mirror"
]
],
"effect": {
"name": "u_turn"
}
},
{
"name": "uproar",
@ -12022,7 +12246,15 @@
"contact",
"protect",
"mirror"
]
],
"effect": {
"name": "change_multiple_user_stat_boosts",
"parameters": {
"defense": -1,
"specialDefense": -1,
"speed": -1
}
}
},
{
"name": "vacuum_wave",
@ -12037,6 +12269,7 @@
"protect",
"mirror"
]
// No secondary effect
},
{
"name": "venom_drench",
@ -12051,7 +12284,10 @@
"protect",
"reflectable",
"mirror"
]
],
"effect": {
"name": "venom_drench"
}
},
{
"name": "venoshock",
@ -12065,7 +12301,10 @@
"flags": [
"protect",
"mirror"
]
],
"effect": {
"name": "venoshock"
}
},
{
"name": "vice_grip",
@ -12081,6 +12320,7 @@
"protect",
"mirror"
]
// No secondary effect
},
{
"name": "vine_whip",
@ -12096,13 +12336,14 @@
"protect",
"mirror"
]
// No secondary effect
},
{
"name": "vital_throw",
"type": "fighting",
"power": 70,
"pp": 10,
"accuracy": 0,
"accuracy": 255,
"priority": -1,
"target": "Any",
"category": "physical",
@ -12111,6 +12352,7 @@
"protect",
"mirror"
]
// No secondary effect
},
{
"name": "volt_switch",
@ -12124,7 +12366,10 @@
"flags": [
"protect",
"mirror"
]
],
"effect": {
"name": "u_turn"
}
},
{
"name": "volt_tackle",

View File

@ -58,7 +58,10 @@ public class Gen7BattleStatCalculator : IBattleStatCalculator
var modifiedAccuracy = (int)(moveAccuracy * accuracyModifier);
// ReSharper disable once AccessToModifiedClosure
executingMove.RunScriptHook(x => x.ChangeAccuracy(executingMove, target, hitIndex, ref modifiedAccuracy));
if (modifiedAccuracy == 255)
if (modifiedAccuracy >= 255)
return 255;
target.RunScriptHook(x => x.ChangeIncomingAccuracy(executingMove, target, hitIndex, ref modifiedAccuracy));
if (modifiedAccuracy >= 255)
return 255;
var targetEvasion = target.StatBoost.Evasion;
var ignoreEvasion = false;

View File

@ -1,7 +1,7 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using PkmnLib.Dynamic.Models.BattleFlow;
using PkmnLib.Dynamic.BattleFlow;
namespace PkmnLib.Plugin.Gen7.Scripts.Battle;

View File

@ -0,0 +1,21 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Battle;
[Script(ScriptCategory.Battle, "trick_room")]
public class TrickRoomEffect : Script
{
private int _turnsLeft = 5;
/// <inheritdoc />
public override void ChangeSpeed(ITurnChoice choice, ref uint speed)
{
speed = uint.MaxValue - speed;
}
/// <inheritdoc />
public override void OnEndTurn(IBattle battle)
{
_turnsLeft--;
if (_turnsLeft <= 0)
RemoveSelf();
}
}

View File

@ -83,4 +83,12 @@ public class ChangeTargetAccuracy : ChangeTargetStats
public ChangeTargetAccuracy() : base(Statistic.Accuracy)
{
}
}
[Script(ScriptCategory.Move, "change_target_evasion")]
public class ChangeTargetEvasion : ChangeTargetStats
{
public ChangeTargetEvasion() : base(Statistic.Evasion)
{
}
}

View File

@ -12,7 +12,7 @@ public class Dive : Script
if (move.User.Volatile.Contains<DiveEffect>())
return;
move.User.Volatile.Add(new DigEffect(move.User));
move.User.Volatile.Add(new DiveEffect(move.User));
move.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("dive_charge", new Dictionary<string, object>
{
{ "user", move.User },

View File

@ -22,17 +22,21 @@ public class Gravity : Script
return script;
});
var chargeBounceEffect = ScriptUtils.ResolveName<ChargeBounceEffect>();
var flyEffect = ScriptUtils.ResolveName<ChargeFlyEffect>();
var skyDropEffect = ScriptUtils.ResolveName<ChargeSkyDropEffect>();
var telekinesisEffect = ScriptUtils.ResolveName<TelekinesisEffect>();
foreach (var pokemon in battleData.Battle.Sides.SelectMany(x => x.Pokemon).WhereNotNull())
{
var chargeBounceEffect = ScriptUtils.ResolveName<ChargeBounceEffect>();
if (pokemon.Volatile.Contains(chargeBounceEffect))
pokemon.Volatile.Remove(chargeBounceEffect);
var flyEffect = ScriptUtils.ResolveName<ChargeFlyEffect>();
if (pokemon.Volatile.Contains(flyEffect))
pokemon.Volatile.Remove(flyEffect);
var skyDropEffect = ScriptUtils.ResolveName<ChargeSkyDropEffect>();
if (pokemon.Volatile.Contains(skyDropEffect))
pokemon.Volatile.Remove(skyDropEffect);
if (pokemon.Volatile.Contains(telekinesisEffect))
pokemon.Volatile.Remove(telekinesisEffect);
}
}
}

View File

@ -1,5 +1,5 @@
using System.Linq;
using PkmnLib.Dynamic.Models.BattleFlow;
using PkmnLib.Dynamic.BattleFlow;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;

View File

@ -17,5 +17,6 @@ public class SpitUp : Script
}
var stockpileCount = stockpileEffect.StockpileCount;
basePower = basePower.MultiplyOrMax(stockpileCount);
move.User.Volatile.Remove<StockpileEffect>();
}
}

View File

@ -8,10 +8,6 @@ public class Stockpile : Script
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
EventBatchId batchId = new();
move.User.ChangeStatBoost(Statistic.Defense, 1, true, batchId);
move.User.ChangeStatBoost(Statistic.SpecialDefense, 1, true, batchId);
move.User.Volatile.StackOrAdd(ScriptUtils.ResolveName<StockpileEffect>(), () => new StockpileEffect());
}
}

View File

@ -0,0 +1,27 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
/// <remarks>
/// Named 'SubstituteMove' to avoid namespace conflicts with NSubstitute.
/// </remarks>
[Script(ScriptCategory.Move, "substitute")]
public class SubstituteMove : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var hp = move.User.MaxHealth / 4;
if (move.User.CurrentHealth > hp)
{
move.User.Damage(hp, DamageSource.Misc, forceDamage: true);
move.User.Volatile.Add(new Pokemon.SubstituteEffect(hp));
move.Battle.EventHook.Invoke(new DialogEvent("substitute", new Dictionary<string, object>
{
{ "user", move.User },
}));
}
else
{
move.Battle.EventHook.Invoke(new DialogEvent("substitute_fail"));
}
}
}

View File

@ -0,0 +1,18 @@
using PkmnLib.Static.Moves;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "sucker_punch")]
public class SuckerPunch : Script
{
/// <inheritdoc />
public override void OnBeforeHit(IExecutingMove move, IPokemon target, byte hitIndex)
{
var targetChoice = move.Battle.ChoiceQueue?.Where(x => x.User == target).FirstOrDefault();
if (targetChoice is not IMoveChoice moveChoice ||
moveChoice.ChosenMove.MoveData.Category == MoveCategory.Status)
{
move.GetHitData(target, hitIndex).Fail();
}
}
}

View File

@ -0,0 +1,12 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "super_fang")]
public class SuperFang : Script
{
/// <inheritdoc />
public override void ChangeMoveDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage)
{
// Super Fang always does 50% of the target's current HP
damage = target.CurrentHealth / 2;
}
}

View File

@ -0,0 +1,13 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "superpower")]
public class Superpower : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
EventBatchId eventBatch = new();
move.User.ChangeStatBoost(Statistic.Attack, -1, true, eventBatch);
move.User.ChangeStatBoost(Statistic.Defense, -1, true, eventBatch);
}
}

View File

@ -0,0 +1,12 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "swagger")]
public class Swagger : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
target.ChangeStatBoost(Statistic.Attack, 2, false);
target.Volatile.Add(new Pokemon.Confusion());
}
}

View File

@ -0,0 +1,29 @@
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "swallow")]
public class Swallow : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var stockpileEffect = move.User.Volatile.Get<StockpileEffect>();
if (stockpileEffect == null || stockpileEffect.StockpileCount == 0)
{
move.GetHitData(target, hit).Fail();
return;
}
var stockpileCount = stockpileEffect.StockpileCount;
var modifier = stockpileCount switch
{
1 => 0.25f,
2 => 0.5f,
_ => 1f,
};
var heal = move.User.MaxHealth * modifier;
move.User.Heal((uint)heal);
move.User.Volatile.Remove<StockpileEffect>();
}
}

View File

@ -0,0 +1,24 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "switcheroo")]
public class Switcheroo : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var targetHeldItem = target.HeldItem;
var userHeldItem = move.User.HeldItem;
if (targetHeldItem?.Category is ItemCategory.FormChanger or ItemCategory.Mail ||
userHeldItem?.Category is ItemCategory.FormChanger or ItemCategory.Mail)
{
// Cannot switch items if one of them is a form changer or mail
move.GetHitData(target, hit).Fail();
return;
}
targetHeldItem = target.RemoveHeldItem();
userHeldItem = move.User.RemoveHeldItem();
_ = target.SetHeldItem(userHeldItem);
_ = move.User.SetHeldItem(targetHeldItem);
}
}

View File

@ -0,0 +1,18 @@
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "synchronoise")]
public class Synchronoise : Script
{
/// <inheritdoc />
public override void ChangeTargets(IMoveChoice moveChoice, ref IReadOnlyList<IPokemon?> targets)
{
var battleData = moveChoice.User.BattleData;
if (battleData == null)
throw new InvalidOperationException("Battle data is null.");
targets = battleData.Battle.Sides.SelectMany(x => x.Pokemon).WhereNotNull()
.Where(x => x.Types.Any(y => moveChoice.User.Types.Contains(y))).ToList();
}
}

View File

@ -0,0 +1,20 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "synthesis")]
public class Synthesis : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var healModifier = 0.5f;
var weatherName = target.BattleData?.Battle?.WeatherName;
if (weatherName == ScriptUtils.ResolveName<Weather.Sunny>())
healModifier = 2 / 3f;
else if (weatherName == ScriptUtils.ResolveName<Weather.Rain>() ||
weatherName == ScriptUtils.ResolveName<Weather.Hail>() ||
weatherName == ScriptUtils.ResolveName<Weather.Sandstorm>())
healModifier = 1 / 4f;
move.User.Heal((uint)(move.User.MaxHealth * healModifier));
}
}

View File

@ -0,0 +1,11 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "tailwind")]
public class Tailwind : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
move.User.BattleData?.BattleSide.VolatileScripts.Add(new Side.TailwindEffect());
}
}

View File

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

View File

@ -0,0 +1,23 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "techno_blast")]
public class TechnoBlast : Script
{
/// <inheritdoc />
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier? moveType)
{
var heldItem = move.User.HeldItem;
if (heldItem == null)
return;
var typeLibrary = target.Library.StaticLibrary.Types;
moveType = heldItem.Name.ToString().ToLowerInvariant() switch
{
"burn_drive" when typeLibrary.TryGetTypeIdentifier("fire", out var fire) => fire,
"chill_drive" when typeLibrary.TryGetTypeIdentifier("ice", out var ice) => ice,
"douse_drive" when typeLibrary.TryGetTypeIdentifier("water", out var water) => water,
"shock_drive" when typeLibrary.TryGetTypeIdentifier("electric", out var electric) => electric,
_ => moveType,
};
}
}

View File

@ -0,0 +1,19 @@
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "telekinesis")]
public class Telekinesis : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
if (move.Battle.Volatile.Contains<Battle.Gravity>())
{
move.GetHitData(target, hit).Fail();
return;
}
target.Volatile.Add(new TelekinesisEffect());
}
}

View File

@ -0,0 +1,7 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "teleport")]
public class Teleport : Script
{
// FIXME: Implement teleport
}

View File

@ -0,0 +1,23 @@
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "thousand_arrows")]
public class ThousandArrows : Script
{
/// <inheritdoc />
public override void ChangeEffectiveness(IExecutingMove move, IPokemon target, byte hit, ref float effectiveness)
{
if (effectiveness == 0)
effectiveness = 1;
}
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
target.Volatile.Add(new ThousandArrowsEffect());
target.Volatile.Remove<ChargeFlyEffect>();
target.Volatile.Remove<ChargeSkyDropEffect>();
target.Volatile.Remove<ChargeBounceEffect>();
}
}

View File

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

View File

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

View File

@ -0,0 +1,22 @@
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
using PkmnLib.Plugin.Gen7.Scripts.Status;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "thunder_fang")]
public class ThunderFang : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var random = move.Battle.Random;
if (random.EffectChance(10, move, target, hit))
{
target.SetStatus(ScriptUtils.ResolveName<Paralyzed>());
}
if (random.EffectChance(10, move, target, hit))
{
target.Volatile.Add(new FlinchEffect());
}
}
}

View File

@ -0,0 +1,26 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "topsy_turvy")]
public class TopsyTurvy : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
EventBatchId batchId = new();
var hasChanged = false;
foreach (Statistic stat in Enum.GetValues(typeof(Statistic)))
{
var statBoost = target.StatBoost.GetStatistic(stat);
if (statBoost == 0)
continue;
hasChanged = true;
var newStatBoost = -statBoost;
target.ChangeStatBoost(stat, (sbyte)newStatBoost, target == move.User, batchId);
}
if (!hasChanged)
{
move.GetHitData(target, hit).Fail();
}
}
}

View File

@ -0,0 +1,13 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "torment")]
public class Torment : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var lastTargetChoice = move.Battle.PreviousTurnChoices.SelectMany(x => x).Reverse().OfType<IMoveChoice>()
.FirstOrDefault(x => x.User == target);
target.Volatile.Add(new Pokemon.TormentEffect(lastTargetChoice));
}
}

View File

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

View File

@ -0,0 +1,12 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "toxic_thread")]
public class ToxicThread : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
target.SetStatus(ScriptUtils.ResolveName<Status.Poisoned>());
target.ChangeStatBoost(Statistic.Speed, -1, false);
}
}

View File

@ -0,0 +1,7 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "transform")]
public class Transform : Script
{
// FIXME: implement this
}

View File

@ -0,0 +1,19 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "tri_attack")]
public class TriAttack : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var random = move.Battle.Random;
if (!random.EffectChance(20, move, target, hit))
return;
var status = random.OneOf([
ScriptUtils.ResolveName<Status.Burned>(),
ScriptUtils.ResolveName<Status.Paralyzed>(),
ScriptUtils.ResolveName<Status.Frozen>(),
]);
target.SetStatus(status);
}
}

View File

@ -0,0 +1,14 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "trick_or_treat")]
public class TrickOrTreat : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var library = move.Battle.Library.StaticLibrary.Types;
if (!library.TryGetTypeIdentifier("ghost", out var ghostType))
return;
target.AddType(ghostType);
}
}

View File

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

View File

@ -0,0 +1,17 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "triple_kick")]
public class TripleKick : Script
{
/// <inheritdoc />
public override void ChangeNumberOfHits(IMoveChoice choice, ref byte numberOfHits)
{
numberOfHits = 3;
}
/// <inheritdoc />
public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref ushort basePower)
{
basePower *= (ushort)(hit + 1);
}
}

View File

@ -0,0 +1,20 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "trump_card")]
public class TrumpCard : Script
{
/// <inheritdoc />
public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref ushort basePower)
{
var remainingPp = move.ChosenMove.CurrentPp;
basePower = remainingPp switch
{
>= 4 => 40,
3 => 50,
2 => 60,
1 => 80,
0 => 200,
};
}
}

View File

@ -0,0 +1,17 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "twineedle")]
public class Twineedle : Script
{
/// <inheritdoc />
public override void ChangeNumberOfHits(IMoveChoice choice, ref byte numberOfHits) => numberOfHits = 2;
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
if (move.Battle.Random.EffectChance(20, move, target, hit))
{
target.SetStatus(ScriptUtils.ResolveName<Status.Poisoned>());
}
}
}

View File

@ -0,0 +1,12 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "u_turn")]
public class UTurn : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var battleData = move.User.BattleData;
battleData?.BattleSide.SwapPokemon(battleData.Position, null);
}
}

View File

@ -0,0 +1,18 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "venom_drench")]
public class VenomDrench : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
if (!target.HasStatus(ScriptUtils.ResolveName<Status.Poisoned>()) &&
!target.HasStatus(ScriptUtils.ResolveName<Status.BadlyPoisoned>()))
return;
EventBatchId eventBatch = new();
target.ChangeStatBoost(Statistic.Attack, -1, false, eventBatch);
target.ChangeStatBoost(Statistic.SpecialAttack, -1, false, eventBatch);
target.ChangeStatBoost(Statistic.Speed, -1, false, eventBatch);
}
}

View File

@ -0,0 +1,15 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "venoshock")]
public class Venoshock : Script
{
/// <inheritdoc />
public override void ChangeMoveDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage)
{
if (target.HasStatus(ScriptUtils.ResolveName<Status.Poisoned>()) ||
target.HasStatus(ScriptUtils.ResolveName<Status.BadlyPoisoned>()))
{
damage *= 2;
}
}
}

View File

@ -1,4 +1,4 @@
using PkmnLib.Dynamic.Models.BattleFlow;
using PkmnLib.Dynamic.BattleFlow;
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;

View File

@ -3,14 +3,45 @@ namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
[Script(ScriptCategory.Pokemon, "stockpile_effect")]
public class StockpileEffect : Script
{
private IPokemon? _pokemon;
public int StockpileCount { get; set; } = 1;
/// <inheritdoc />
public override void OnAddedToParent(IScriptSource source)
{
if (source is not IPokemon pokemon)
{
throw new InvalidOperationException("StockpileEffect can only be added to a Pokemon.");
}
_pokemon = pokemon;
EventBatchId batchId = new();
pokemon.ChangeStatBoost(Statistic.Defense, 1, true, batchId);
pokemon.ChangeStatBoost(Statistic.SpecialDefense, 1, true, batchId);
StockpileCount = 1;
}
/// <inheritdoc />
public override void Stack()
{
if (StockpileCount < 3)
{
EventBatchId batchId = new();
_pokemon?.ChangeStatBoost(Statistic.Defense, 1, true, batchId);
_pokemon?.ChangeStatBoost(Statistic.SpecialDefense, 1, true, batchId);
StockpileCount++;
}
}
/// <inheritdoc />
public override void OnRemove()
{
if (_pokemon == null)
{
return;
}
EventBatchId batchId = new();
_pokemon.ChangeStatBoost(Statistic.Defense, (sbyte)-StockpileCount, true, batchId);
_pokemon.ChangeStatBoost(Statistic.SpecialDefense, (sbyte)-StockpileCount, true, batchId);
StockpileCount = 0;
}
}

View File

@ -0,0 +1,24 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
[Script(ScriptCategory.Pokemon, "substitute")]
public class SubstituteEffect(uint health) : Script
{
private uint _health = health;
/// <inheritdoc />
public override void BlockIncomingHit(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref bool block)
{
if (executingMove.UseMove.HasFlag("ignore-substitute"))
return;
block = true;
var damage = executingMove.GetHitData(target, hitIndex).Damage;
if (damage >= _health)
{
executingMove.Battle.EventHook.Invoke(new DialogEvent("substitute_broken"));
RemoveSelf();
return;
}
_health -= damage;
}
}

View File

@ -0,0 +1,34 @@
using PkmnLib.Static.Moves;
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
[Script(ScriptCategory.Pokemon, "taunt")]
public class TauntEffect(int turns) : Script
{
private int _turns = turns;
/// <inheritdoc />
public override void PreventMoveSelection(IMoveChoice choice, ref bool prevent)
{
if (choice.ChosenMove.MoveData.Category == MoveCategory.Status)
{
prevent = true;
}
}
/// <inheritdoc />
public override void FailMove(IExecutingMove move, ref bool fail)
{
if (move.ChosenMove.MoveData.Category == MoveCategory.Status)
{
fail = true;
}
}
public override void OnEndTurn(IBattle battle)
{
_turns--;
if (_turns <= 0)
RemoveSelf();
}
}

View File

@ -0,0 +1,26 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
[Script(ScriptCategory.Pokemon, "telekinesis")]
public class TelekinesisEffect : Script
{
/// <inheritdoc />
public override void ChangeIncomingAccuracy(IExecutingMove executingMove, IPokemon target, byte hitIndex,
ref int modifiedAccuracy)
{
modifiedAccuracy = 255;
}
/// <inheritdoc />
public override void IsFloating(IPokemon pokemon, ref bool isFloating)
{
isFloating = true;
}
/// <inheritdoc />
public override void ChangeIncomingEffectiveness(IExecutingMove executingMove, IPokemon target, byte hitIndex,
ref float effectiveness)
{
if (executingMove.UseMove.MoveType.Name == "ground")
effectiveness = 0;
}
}

View File

@ -0,0 +1,23 @@
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
[Script(ScriptCategory.Move, "thousand_arrows")]
public class ThousandArrowsEffect : Script
{
/// <inheritdoc />
public override void IsFloating(IPokemon pokemon, ref bool isFloating)
{
isFloating = false;
}
/// <inheritdoc />
public override void ChangeTypesForIncomingMove(IExecutingMove executingMove, IPokemon target, byte hitIndex,
IList<TypeIdentifier> types)
{
if (executingMove.UseMove.MoveType.Name == "ground")
{
types.RemoveAll(x => x.Name == "flying");
}
}
}

View File

@ -0,0 +1,11 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
[Script(ScriptCategory.Pokemon, "thousand_waves")]
public class ThousandWavesEffect : Script
{
/// <inheritdoc />
public override void PreventSelfSwitch(ISwitchChoice choice, ref bool prevent) => prevent = true;
/// <inheritdoc />
public override void PreventSelfRunAway(IFleeChoice choice, ref bool prevent) => prevent = true;
}

View File

@ -0,0 +1,29 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
[Script(ScriptCategory.Pokemon, "throat_chop")]
public class ThroatChopEffect : Script
{
private int _turns = 3;
/// <inheritdoc />
public override void PreventMoveSelection(IMoveChoice choice, ref bool prevent)
{
if (choice.ChosenMove.MoveData.HasFlag("sound"))
prevent = true;
}
/// <inheritdoc />
public override void FailMove(IExecutingMove move, ref bool fail)
{
if (move.UseMove.HasFlag("sound"))
fail = true;
}
/// <inheritdoc />
public override void OnEndTurn(IBattle battle)
{
_turns--;
if (_turns <= 0)
RemoveSelf();
}
}

View File

@ -0,0 +1,25 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
[Script(ScriptCategory.Pokemon, "torment")]
public class TormentEffect(IMoveChoice? moveChoice) : Script
{
private IMoveChoice? _moveChoice = moveChoice;
/// <inheritdoc />
public override void PreventMoveSelection(IMoveChoice choice, ref bool prevent)
{
if (_moveChoice == null)
return;
if (choice.ChosenMove.MoveData == _moveChoice.ChosenMove.MoveData)
{
prevent = true;
}
}
/// <inheritdoc />
public override void OnBeforeTurnStart(ITurnChoice choice)
{
if (choice is IMoveChoice moveChoice)
_moveChoice = moveChoice;
}
}

View File

@ -1,5 +1,5 @@
using System.Collections.Generic;
using PkmnLib.Dynamic.Models.BattleFlow;
using PkmnLib.Dynamic.BattleFlow;
namespace PkmnLib.Plugin.Gen7.Scripts.Side;

View File

@ -0,0 +1,21 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Side;
[Script(ScriptCategory.Side, "tailwind")]
public class TailwindEffect : Script
{
private int _duration = 3;
/// <inheritdoc />
public override void ChangeSpeed(ITurnChoice choice, ref uint speed)
{
speed *= 2;
}
/// <inheritdoc />
public override void OnEndTurn(IBattle battle)
{
_duration--;
if (_duration <= 0)
RemoveSelf();
}
}

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
namespace PkmnLib.Plugin.Gen7.Scripts.Side;
[Script(ScriptCategory.Side, "toxic_spikes")]
public class ToxicSpikesEffect : Script
{
/// <inheritdoc />
public override void OnSwitchIn(IPokemon pokemon, byte position)
{
if (pokemon.IsFloating)
return;
pokemon.SetStatus(ScriptUtils.ResolveName<Status.Poisoned>());
}
}