Implements a bunch more moves

This commit is contained in:
2025-03-08 14:39:50 +01:00
parent 8f262cb4a6
commit 77f1ab243b
33 changed files with 935 additions and 57 deletions

View File

@@ -1,4 +1,6 @@
using System;
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
@@ -12,7 +14,8 @@ public class FuryCutter : Script
if (userEffect == null)
return;
userEffect.TurnCount++;
basePower = (byte)(basePower * (userEffect.TurnCount + 1));
if (userEffect.TurnCount < 5)
userEffect.TurnCount++;
basePower = basePower.MultiplyOrMax((byte)Math.Pow(2, userEffect.TurnCount));
}
}

View File

@@ -0,0 +1,25 @@
using System.Linq;
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "heal_bell")]
public class HealBell : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var party = move.User.BattleData?.Battle.Parties.FirstOrDefault(p => p.Party.Contains(target));
if (party == null)
return;
foreach (var pokemon in party.Party.WhereNotNull())
{
pokemon.ClearStatus();
var confusion = ScriptUtils.ResolveName<Confusion>();
if (pokemon.Volatile.Contains(confusion))
pokemon.Volatile.Remove(confusion);
}
}
}

View File

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

View File

@@ -0,0 +1,25 @@
using System.Collections.Generic;
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "heal_percent")]
public class HealPercent : Script
{
private float _healPercent = 0.5f;
/// <inheritdoc />
public override void OnInitialize(IReadOnlyDictionary<StringKey, object?>? parameters)
{
if (parameters?.TryGetValue("healPercent", out var variable) == true && variable is float healPercent)
{
_healPercent = healPercent;
}
}
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
target.Heal((uint)(move.User.BoostedStats.Hp * _healPercent));
}
}

View File

@@ -0,0 +1,20 @@
using PkmnLib.Plugin.Gen7.Scripts.Side;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "healing_wish")]
public class HealingWish : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var battleData = move.User.BattleData;
if (battleData == null)
return;
var side = battleData.Battle.Sides[battleData.SideIndex];
side.VolatileScripts.Add(new HealingWishEffect(battleData.Position));
move.User.Faint(DamageSource.Misc);
}
}

View File

@@ -0,0 +1,26 @@
using System;
using PkmnLib.Static;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "heart_swap")]
public class HeartSwap : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
EventBatchId eventBatchId = new();
var userStats = move.User.StatBoost;
var targetStats = target.StatBoost;
foreach (Statistic stat in Enum.GetValues(typeof(Statistic)))
{
var userStat = userStats.GetStatistic(stat);
var targetStat = targetStats.GetStatistic(stat);
if (userStat == targetStat)
continue;
move.User.ChangeStatBoost(stat, (sbyte)(userStat - targetStat), true, eventBatchId);
target.ChangeStatBoost(stat, (sbyte)(targetStat - userStat), false, eventBatchId);
}
}
}

View File

@@ -0,0 +1,19 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "heat_crash")]
public class HeatCrash : Script
{
/// <inheritdoc />
public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref byte basePower)
{
var weightMultiplier = move.User.WeightInKg / target.WeightInKg;
basePower = weightMultiplier switch
{
> 5 => 120,
> 4 => 100,
> 3 => 80,
> 2 => 60,
_ => 40,
};
}
}

View File

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

View File

@@ -0,0 +1,16 @@
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "hex")]
public class Hex : Script
{
/// <inheritdoc />
public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref byte basePower)
{
if (!target.StatusScript.IsEmpty)
{
basePower = basePower.MultiplyOrMax(2);
}
}
}

View File

@@ -0,0 +1,39 @@
using System;
using PkmnLib.Static;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "hidden_power")]
public class HiddenPower : Script
{
/// <inheritdoc />
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier moveType)
{
var ivs = move.User.IndividualValues;
var type = GetHiddenPowerValue(ivs, 0x00000001) * 15 / 63;
move.User.Library.StaticLibrary.Types.TryGetTypeIdentifierFromIndex((byte)(type + 2), out moveType);
}
/// <inheritdoc />
public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref byte basePower)
{
var ivs = move.User.IndividualValues;
var power = GetHiddenPowerValue(ivs, 0x00000002) * 40 / 63 + 30;
// cast to byte with overflow check
basePower = (byte)Math.Min(power, byte.MaxValue);
}
/// <summary>
/// Helper method to calculate the hidden power value from the IVs.
/// This is used to determine the type and power of the move.
/// </summary>
private static int GetHiddenPowerValue(IndividualValueStatisticSet ivs, int significance) =>
((ivs.Hp & significance) >> (significance - 1)) + (((ivs.Attack & significance) >> (significance - 1)) << 1) +
(((ivs.Defense & significance) >> (significance - 1)) << 2) +
(((ivs.Speed & significance) >> (significance - 1)) << 3) +
(((ivs.SpecialAttack & significance) >> (significance - 1)) << 4) +
(((ivs.SpecialDefense & significance) >> (significance - 1)) << 5);
}

View File

@@ -0,0 +1,18 @@
using System;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "high_jump_kick")]
public class HighJumpKick : Script
{
/// <inheritdoc />
public override void OnMoveMiss(IExecutingMove move, IPokemon target)
{
var damage = move.GetHitData(target, 0).Damage;
var recoil = damage / 2;
// This recoil damage will not exceed half the user's max HP
var maxHp = move.User.BoostedStats.Hp;
recoil = Math.Min(recoil, maxHp / 2);
move.User.Damage(recoil, DamageSource.Misc);
}
}

View File

@@ -0,0 +1,18 @@
using System.Linq;
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "hyperspace_fury")]
public class HyperspaceFury : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var protectionScripts = target.Volatile.Select(x => x.Script).OfType<ProtectionEffectScript>();
foreach (var protectionScript in protectionScripts.ToList())
{
target.Volatile.Remove(protectionScript.Name);
}
}
}

View File

@@ -0,0 +1,34 @@
using System;
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "ice_ball")]
public class IceBall : Script
{
/// <inheritdoc />
public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref byte basePower)
{
var userEffect = move.User.Volatile.Get<IceBallEffect>();
if (userEffect == null)
return;
basePower = basePower.MultiplyOrMax((byte)Math.Pow(2, userEffect.TurnCount));
}
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var userEffect = move.User.Volatile.Get<IceBallEffect>();
if (userEffect == null)
{
userEffect = new IceBallEffect(move.User, move.UseMove.Name);
move.User.Volatile.Add(userEffect);
}
else
{
userEffect.TurnCount++;
}
}
}

View File

@@ -0,0 +1,24 @@
using System;
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "ice_burn")]
public class IceBurn : BaseChargeMove<RequireChargeEffect>
{
/// <inheritdoc />
public override RequireChargeEffect CreateVolatile(IPokemon user) => new(user, "ice_burn");
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var battleData = move.User.BattleData;
if (battleData == null)
return;
if (battleData.Battle.Random.EffectChance(30, move, target, hit))
{
target.SetStatus("burned");
}
}
}

View File

@@ -0,0 +1,24 @@
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "ice_fang")]
public class IceFang : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var battleData = move.User.BattleData;
if (battleData == null)
return;
if (battleData.Battle.Random.EffectChance(10, move, target, hit))
{
target.SetStatus("frozen");
}
if (battleData.Battle.Random.EffectChance(10, move, target, hit))
{
target.Volatile.Add(new FlinchEffect());
}
}
}

View File

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

View File

@@ -0,0 +1,16 @@
using PkmnLib.Static;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "incinerate")]
public class Incinerate : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
if (target.HeldItem is { Category: ItemCategory.Berry })
{
target.RemoveHeldItemForBattle();
}
}
}

View File

@@ -0,0 +1,29 @@
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "infestation")]
public class Infestation : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var infestationEffect = ScriptUtils.ResolveName<InfestationEffect>();
if (target.Volatile.Contains(infestationEffect))
{
move.GetHitData(target, hit).Fail();
return;
}
var battleData = move.User.BattleData;
if (battleData == null)
return;
var turns = 4;
if (battleData.Battle.Random.GetBool())
{
turns = 5;
}
target.Volatile.Add(new InfestationEffect(target, turns));
}
}

View File

@@ -0,0 +1,40 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
[Script(ScriptCategory.Pokemon, "heal_block")]
public class HealBlockEffect : Script
{
private int _duration;
public HealBlockEffect(int duration = 5)
{
_duration = duration;
}
/// <inheritdoc />
public override void OnEndTurn(IBattle battle)
{
_duration--;
if (_duration <= 0)
RemoveSelf();
}
/// <inheritdoc />
public override void PreventMoveSelection(IMoveChoice choice, ref bool prevent)
{
if (choice.ChosenMove.MoveData.HasFlag("heal"))
prevent = true;
}
/// <inheritdoc />
public override void PreventMove(IExecutingMove move, ref bool prevent)
{
if (move.ChosenMove.MoveData.HasFlag("heal"))
prevent = true;
}
/// <inheritdoc />
public override void PreventHeal(IPokemon pokemon, uint heal, bool allowRevive, ref bool prevented)
{
prevented = true;
}
}

View File

@@ -0,0 +1,13 @@
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
public class HelpingHandEffect : Script
{
/// <inheritdoc />
public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref byte basePower) =>
basePower = basePower.MultiplyOrMax(1.5f);
/// <inheritdoc />
public override void OnEndTurn(IBattle battle) => RemoveSelf();
}

View File

@@ -0,0 +1,41 @@
using PkmnLib.Plugin.Gen7.Scripts.Utils;
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
[Script(ScriptCategory.Pokemon, "ice_ball")]
public class IceBallEffect : Script
{
private readonly IPokemon _owner;
private readonly StringKey _moveName;
public int TurnCount { get; set; }
public IceBallEffect(IPokemon owner, StringKey moveName)
{
_owner = owner;
_moveName = moveName;
TurnCount = 0;
}
/// <inheritdoc />
public override void ForceTurnSelection(byte sideIndex, byte position, ref ITurnChoice? choice)
{
var opposingSideIndex = (byte)(_owner.BattleData?.SideIndex == 0 ? 1 : 0);
choice = TurnChoiceHelper.CreateMoveChoice(_owner, _moveName, opposingSideIndex, position);
}
/// <inheritdoc />
public override void OnMoveMiss(IExecutingMove move, IPokemon target)
{
RemoveSelf();
}
/// <inheritdoc />
public override void OnEndTurn(IBattle battle)
{
if (TurnCount < 5)
TurnCount++;
else
RemoveSelf();
}
}

View File

@@ -0,0 +1,22 @@
using System.Linq;
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
[Script(ScriptCategory.Pokemon, "imprison")]
public class ImprisonEffect : Script
{
private readonly IPokemon _user;
public ImprisonEffect(IPokemon user)
{
_user = user;
}
/// <inheritdoc />
public override void PreventMoveSelection(IMoveChoice choice, ref bool prevent)
{
if (_user.Moves.WhereNotNull().Any(x => x.MoveData.Name == choice.ChosenMove.MoveData.Name))
prevent = true;
}
}

View File

@@ -0,0 +1,33 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
[Script(ScriptCategory.Pokemon, "infestation")]
public class InfestationEffect : Script
{
private readonly IPokemon _owner;
private int _turns;
public InfestationEffect(IPokemon owner, int turns)
{
_owner = owner;
_turns = turns;
}
/// <inheritdoc />
public override void PreventSelfSwitch(ISwitchChoice choice, ref bool prevent) => prevent = true;
/// <inheritdoc />
public override void PreventSelfRunAway(IFleeChoice choice, ref bool prevent) => prevent = true;
/// <inheritdoc />
public override void OnEndTurn(IBattle battle)
{
var damage = _owner.BoostedStats.Hp / 8;
_owner.Damage(damage, DamageSource.Misc);
_turns--;
if (_turns <= 0)
{
RemoveSelf();
}
}
}

View File

@@ -0,0 +1,23 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Side;
[Script(ScriptCategory.Side, "healing_wish")]
public class HealingWishEffect : Script
{
private readonly byte _position;
public HealingWishEffect(byte position)
{
_position = position;
}
/// <inheritdoc />
public override void OnSwitchIn(IPokemon pokemon, byte position)
{
if (position == _position)
{
pokemon.Heal(pokemon.BoostedStats.Hp);
pokemon.ClearStatus();
RemoveSelf();
}
}
}