More moves, allow for typeless moves

This commit is contained in:
2025-05-02 15:46:37 +02:00
parent 807acf1947
commit 068ff8d5b7
33 changed files with 525 additions and 56 deletions

View File

@@ -7,13 +7,14 @@ namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
public class HiddenPower : Script
{
/// <inheritdoc />
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier moveType)
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);
if (move.User.Library.StaticLibrary.Types.TryGetTypeIdentifierFromIndex((byte)(type + 2), out var t))
moveType = t;
}
/// <inheritdoc />

View File

@@ -6,7 +6,7 @@ namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
public class Judgement : Script
{
/// <inheritdoc />
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier moveType)
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier? moveType)
{
var heldItem = move.User.HeldItem;
if (heldItem == null)

View File

@@ -6,7 +6,7 @@ namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
public class MultiAttack : Script
{
/// <inheritdoc />
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier moveType)
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier? moveType)
{
var item = move.User.HeldItem?.Name.ToString();
var typeLibrary = move.User.Library.StaticLibrary.Types;
@@ -15,6 +15,7 @@ public class MultiAttack : Script
return;
var memoryType = item[..^7];
typeLibrary.TryGetTypeIdentifier(memoryType, out moveType);
if (typeLibrary.TryGetTypeIdentifier(memoryType, out var t))
moveType = t;
}
}

View File

@@ -20,7 +20,7 @@ public class NaturalGift : Script
}
/// <inheritdoc />
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier moveType)
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier? moveType)
{
var naturalGiftData = GetNaturalGiftData(move.User.HeldItem);
if (naturalGiftData == null)

View File

@@ -0,0 +1,25 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "recycle")]
public class Recycle : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
if (move.User.HeldItem is not null)
{
move.GetHitData(target, hit).Fail();
return;
}
var battleData = move.User.BattleData;
if (battleData is null)
return;
var lastItem = battleData.BattleSide.GetLastConsumedItem(battleData.Position);
if (lastItem is null)
{
move.GetHitData(target, hit).Fail();
return;
}
_ = move.User.SetHeldItem(lastItem);
}
}

View File

@@ -0,0 +1,25 @@
using System.Collections.Generic;
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "reflect")]
public class Reflect : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var battleData = move.User.BattleData;
if (battleData is null)
return;
var numberOfTurns = 5;
var dict = new Dictionary<StringKey, object?>
{
{ "duration", numberOfTurns },
};
move.User.RunScriptHook(x => x.CustomTrigger(CustomTriggers.ReflectNumberOfTurns, dict));
numberOfTurns = (int)dict.GetOrDefault("duration", numberOfTurns)!;
battleData.BattleSide.VolatileScripts.Add(new Side.ReflectEffect(numberOfTurns));
}
}

View File

@@ -0,0 +1,12 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "reflect_type")]
public class ReflectType : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var targetTypes = target.Types;
move.User.SetTypes(targetTypes);
}
}

View File

@@ -0,0 +1,23 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "refresh")]
public class Refresh : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var userStatus = move.User.StatusScript;
switch (userStatus.Script?.Name)
{
case "paralyzed":
case "burned":
case "poisoned":
case "badly_poisoned":
move.User.ClearStatus();
break;
default:
move.GetHitData(target, hit).Fail();
break;
}
}
}

View File

@@ -0,0 +1,24 @@
using PkmnLib.Plugin.Gen7.Scripts.Status;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "rest")]
public class Rest : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
if (move.User.HasStatus(ScriptUtils.ResolveName<Sleep>()))
{
move.GetHitData(target, hit).Fail();
return;
}
if (!move.User.Heal(move.User.MaxHealth, false, forceHeal: false))
{
move.GetHitData(target, hit).Fail();
return;
}
move.User.SetStatus(ScriptUtils.ResolveName<Sleep>());
((Sleep)move.User.StatusScript.Script!).Turns = 2;
}
}

View File

@@ -0,0 +1,24 @@
using System.Linq;
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "retaliate")]
public class Retaliate : Script
{
/// <inheritdoc />
public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref byte basePower)
{
var battleData = move.User.BattleData;
if (battleData is null)
return;
var lastFaint = battleData.BattleSide.GetLastFaintTurn();
if (lastFaint == null)
return;
if (lastFaint >= battleData.Battle.CurrentTurnNumber - 1)
{
basePower = basePower.MultiplyOrMax(2);
}
}
}

View File

@@ -0,0 +1,17 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "return")]
public class Return : Script
{
/// <inheritdoc />
public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref byte basePower)
{
var friendship = move.User.Happiness;
var power = friendship * 2 / 5;
// The power is capped at 102, but as friendship is a byte, and thus max 255, this is already heuristically
// capped (255 * 2 / 5 = 102).
if (power < 1)
power = 1;
basePower = (byte)power;
}
}

View File

@@ -0,0 +1,25 @@
using System.Collections.Generic;
using System.Linq;
using PkmnLib.Static;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "revelation_dance")]
public class RevelationDance : Script
{
/// <inheritdoc />
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier? moveType)
{
// The type of the move is the same as the user's first type.
var user = move.User;
if (user.Types.Count > 0)
{
moveType = user.Types[0];
}
// If the user has no types, the move is typeless.
else
{
moveType = null;
}
}
}

View File

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

View File

@@ -0,0 +1,17 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "role_play")]
public class RolePlay : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var ability = target.ActiveAbility;
if (ability is null || ability.HasFlag("cant_be_copied"))
{
move.GetHitData(target, hit).Fail();
return;
}
move.User.ChangeAbility(ability);
}
}

View File

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

View File

@@ -0,0 +1,22 @@
using System.Linq;
using PkmnLib.Static;
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "rototiller")]
public class Rototiller : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var pokemon = move.Battle.Sides.SelectMany(x => x.Pokemon).WhereNotNull()
.Where(x => x.Types.Any(y => y.Name == "grass"));
EventBatchId batchId = new();
foreach (var pkmn in pokemon)
{
pkmn.ChangeStatBoost(Statistic.Attack, 1, pkmn == move.User, batchId);
pkmn.ChangeStatBoost(Statistic.SpecialAttack, 1, pkmn == move.User, batchId);
}
}
}