Bunch more moves, changes in how additional information for items works.

This commit is contained in:
2025-04-14 15:29:26 +02:00
parent 2adbb12367
commit 7c2845502d
60 changed files with 4275 additions and 963 deletions

View File

@@ -1,4 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using PkmnLib.Static;
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Battle;
@@ -6,24 +9,15 @@ namespace PkmnLib.Plugin.Gen7.Scripts.Battle;
public class Gravity : Script
{
/// <inheritdoc />
public override void ChangeEffectiveness(IExecutingMove move, IPokemon target, byte hit, ref float effectiveness)
public override void ChangeTypesForIncomingMove(IExecutingMove executingMove, IPokemon target, byte hitIndex,
IList<TypeIdentifier> types)
{
var battleData = target.BattleData;
if (battleData == null)
return;
var typeLibrary = target.Library.StaticLibrary.Types;
if (move.UseMove.MoveType.Name == "ground")
{
var targetTypes = target.Types;
var typeLibrary = battleData.Battle.Library.StaticLibrary.Types;
effectiveness =
// Get the effectiveness of the move against each target type
targetTypes.Select(x => typeLibrary.GetSingleEffectiveness(move.UseMove.MoveType, x))
// Ignore all types that are immune to ground moves
.Where(x => x > 0)
// Multiply all effectiveness values together
.Aggregate(1.0f, (current, x) => current * x);
}
if (executingMove.UseMove.MoveType.Name != "ground")
return;
// Remove all types that are immune to ground moves
types.RemoveAll(x => typeLibrary.GetSingleEffectiveness(executingMove.UseMove.MoveType, x) == 0);
}
/// <inheritdoc />

View File

@@ -0,0 +1,32 @@
using System.Collections.Generic;
using PkmnLib.Static;
namespace PkmnLib.Plugin.Gen7.Scripts.Battle;
[Script(ScriptCategory.Battle, "magic_room")]
public class MagicRoomEffect : Script
{
private int _turnsLeft = 5;
/// <inheritdoc />
public override void PreventHeldItemConsume(IPokemon pokemon, IItem heldItem, ref bool prevented)
{
prevented = true;
}
/// <inheritdoc />
public override void OnBeforeAnyHookInvoked(ref List<ScriptCategory>? suppressedCategories)
{
suppressedCategories ??= [];
suppressedCategories.Add(ScriptCategory.ItemBattleTrigger);
}
/// <inheritdoc />
public override void OnEndTurn(IBattle battle)
{
if (_turnsLeft > 0)
_turnsLeft--;
else
RemoveSelf();
}
}

View File

@@ -0,0 +1,28 @@
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Battle;
[Script(ScriptCategory.Battle, "mud_sport")]
public class MudSportEffect : Script
{
private int _turnsLeft = 5;
/// <inheritdoc />
public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref byte basePower)
{
if (move.UseMove.MoveType.Name == "electric")
{
basePower = basePower.MultiplyOrMax(2f / 3f);
}
}
/// <inheritdoc />
public override void OnEndTurn(IBattle battle)
{
_turnsLeft--;
if (_turnsLeft <= 0)
{
RemoveSelf();
}
}
}

View File

@@ -0,0 +1,11 @@
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.MoveVolatile;
[Script(ScriptCategory.MoveVolatile, "me_first")]
public class MeFirstPowerBoost : Script
{
/// <inheritdoc />
public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref byte basePower) =>
basePower = basePower.MultiplyOrMax(1.5f);
}

View File

@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using PkmnLib.Static;
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "change_multiple_target_stat_boosts")]
public class ChangeMultipleTargetStatBoosts : Script
{
private Dictionary<Statistic, sbyte> _statBoosts = new();
/// <inheritdoc />
public override void OnInitialize(IReadOnlyDictionary<StringKey, object?>? parameters)
{
if (parameters == null)
{
throw new ArgumentNullException(nameof(parameters));
}
foreach (var par in parameters)
{
if (!Enum.TryParse<Statistic>(par.Key, true, out var stat))
throw new ArgumentException($"Invalid stat name: {par.Key}");
if (par.Value is sbyte value)
{
_statBoosts[stat] = value;
}
}
}
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
EventBatchId batchId = new();
foreach (var stat in _statBoosts!)
{
target.ChangeStatBoost(stat.Key, stat.Value, true, batchId);
}
}
}

View File

@@ -21,8 +21,13 @@ public class Fling : Script
move.GetHitData(target, hit).Fail();
return;
}
if (!item.TryGetAdditionalData<byte>("fling_power", out var flingPower))
{
move.GetHitData(target, hit).Fail();
return;
}
basePower = item.FlingPower;
basePower = flingPower;
}
/// <inheritdoc />

View File

@@ -1,20 +1,18 @@
using System.Collections.Generic;
using PkmnLib.Static;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "flying_press")]
public class FlyingPress : Script
{
/// <inheritdoc />
public override void ChangeEffectiveness(IExecutingMove move, IPokemon target, byte hit, ref float effectiveness)
public override void ChangeTypesForMove(IExecutingMove executingMove, IPokemon target, byte hitIndex,
IList<TypeIdentifier> types)
{
var battleData = move.User.BattleData;
if (battleData == null)
return;
var typeLibrary = battleData.Battle.Library.StaticLibrary.Types;
// If flying type is not found, return
var typeLibrary = executingMove.User.Library.StaticLibrary.Types;
if (!typeLibrary.TryGetTypeIdentifier("flying", out var flyingType))
return;
var flyingEffectiveness = typeLibrary.GetEffectiveness(flyingType, target.Types);
effectiveness *= flyingEffectiveness;
types.Add(flyingType);
}
}

View File

@@ -0,0 +1,18 @@
using PkmnLib.Plugin.Gen7.Scripts.Battle;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "magic_room")]
public class MagicRoom : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var battleData = move.User.BattleData;
if (battleData == null)
return;
var battle = battleData.Battle;
battle.Volatile.Add(new MagicRoomEffect());
}
}

View File

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

View File

@@ -0,0 +1,19 @@
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "magnet_rise")]
public class MagnetRise : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
if (move.User.Volatile.Contains(ScriptUtils.ResolveName<IngrainEffect>()) ||
move.User.ActiveAbility?.Name == "levitate")
{
move.GetHitData(target, hit).Fail();
return;
}
move.User.Volatile.Add(new MagnetRiseEffect());
}
}

View File

@@ -0,0 +1,52 @@
using System.Collections.Generic;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "magnitude")]
public class Magnitude : Script
{
/// <inheritdoc />
public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref byte basePower)
{
var battleData = move.User.BattleData;
if (battleData == null)
return;
var random = battleData.Battle.Random;
var magnitudePercentage = random.GetInt(0, 100);
var magnitude = magnitudePercentage switch
{
// 5% chance for 4
< 5 => 4,
// 10% chance for 5
< 15 => 5,
// 20% chance for 6
< 35 => 6,
// 30% chance for 7
< 65 => 7,
// 20% chance for 8
< 85 => 8,
// 10% chance for 9
< 95 => 9,
// 5% chance for 10
_ => 10,
};
battleData.Battle.EventHook.Invoke(new DialogEvent("magnitude", new Dictionary<string, object>()
{
{ "magnitude", magnitude },
{ "user", move.User },
{ "target", target },
}));
basePower = magnitude switch
{
4 => 10,
5 => 30,
6 => 50,
7 => 70,
8 => 90,
9 => 110,
_ => 150,
};
}
}

View File

@@ -0,0 +1,22 @@
using PkmnLib.Plugin.Gen7.Scripts.Side;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "mat_block")]
public class MatBlock : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var battleData = move.User.BattleData;
if (battleData == null)
return;
if (battleData.SwitchInTurn != battleData.Battle.CurrentTurnNumber)
{
move.GetHitData(target, hit).Fail();
return;
}
battleData.BattleSide.VolatileScripts.Add(new MatBlockEffect());
}
}

View File

@@ -0,0 +1,31 @@
using PkmnLib.Plugin.Gen7.Scripts.MoveVolatile;
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "me_first")]
public class MeFirst : Script
{
/// <inheritdoc />
public override void ChangeMove(IMoveChoice choice, ref StringKey moveName)
{
var battleData = choice.User.BattleData;
if (battleData == null)
return;
var target = battleData.Battle.Sides[choice.TargetSide].Pokemon[choice.TargetPosition];
if (target == null)
{
choice.Fail();
return;
}
if (battleData.Battle.ChoiceQueue?.FirstOrDefault(x => x.User == target) is not IMoveChoice targetMove)
{
choice.Fail();
return;
}
var targetMoveData = targetMove.ChosenMove.MoveData;
moveName = targetMoveData.Name;
choice.Volatile.Add(new MeFirstPowerBoost());
}
}

View File

@@ -0,0 +1,15 @@
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "mean_look")]
public class MeanLook : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var targetEffect = target.Volatile.Add(new MeanLookEffectTarget());
var userEffect = new MeanLookEffectUser(targetEffect);
move.User.Volatile.Add(userEffect);
}
}

View File

@@ -0,0 +1,17 @@
using PkmnLib.Static;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "memento")]
public class Memento : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var evtBatch = new EventBatchId();
target.ChangeStatBoost(Statistic.Attack, -2, false, evtBatch);
target.ChangeStatBoost(Statistic.SpecialAttack, -2, false, evtBatch);
move.User.Faint(DamageSource.Misc);
}
}

View File

@@ -0,0 +1,51 @@
using PkmnLib.Static.Moves;
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "metal_burst")]
public class MetalBurst : Script
{
/// <inheritdoc />
public override void OnBeforeTurnStart(ITurnChoice choice)
{
choice.User.Volatile.Add(new MetalBurstHelper());
}
/// <inheritdoc />
public override void ChangeMoveDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage)
{
var helper = target.Volatile.Get<MetalBurstHelper>();
if (helper?.LastAttacker == null || helper.LastAttacker != move.User)
{
move.GetHitData(target, hit).Fail();
return;
}
damage = helper.LastDamage.MultiplyOrMax(1.5f);
target.Volatile.Remove<MetalBurstHelper>();
}
[Script(ScriptCategory.Pokemon, "metal_burst_helper")]
private class MetalBurstHelper : Script
{
public IPokemon? LastAttacker { get; set; }
public uint LastDamage { get; set; }
/// <inheritdoc />
public override void OnIncomingHit(IExecutingMove move, IPokemon target, byte hit)
{
if (move.UseMove.Category == MoveCategory.Status)
return;
LastAttacker = move.User;
LastDamage = move.GetHitData(target, hit).Damage;
}
/// <inheritdoc />
public override void OnEndTurn(IBattle battle)
{
RemoveSelf();
}
}
}

View File

@@ -0,0 +1,38 @@
using System;
using PkmnLib.Plugin.Gen7.Scripts.Utils;
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "metronome")]
public class Metronome : Script
{
/// <inheritdoc />
public override void ChangeMove(IMoveChoice choice, ref StringKey moveName)
{
var battleData = choice.User.BattleData;
if (battleData == null)
return;
var library = choice.User.Library;
var moveLibrary = library.StaticLibrary.Moves;
var retryCount = 0;
while (true)
{
// Breaker for infinite loop. The odds that we'd accidentally roll a non-copyable move 100 times in a row
// is extremely unlikely, unless the loaded move library only contains non-copyable moves.
// This is a failsafe.
if (retryCount > 100)
throw new Exception("Metronome failed to find a valid move after 100 attempts.");
var randomMove = moveLibrary.GetRandom(battleData.Battle.Random);
if (!randomMove.CanCopyMove())
{
retryCount++;
continue;
}
moveName = randomMove.Name;
break;
}
}
}

View File

@@ -0,0 +1,9 @@
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "mimic")]
public class Mimic : Script
{
// FIXME: support for temporarily copying moves to a move slot.
}

View File

@@ -0,0 +1,18 @@
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
using PkmnLib.Static;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "miracle_eye")]
public class MiracleEye : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
if (target.StatBoost.Evasion > 0)
{
target.ChangeStatBoost(Statistic.Evasion, (sbyte)-target.StatBoost.Evasion, false);
}
target.Volatile.Add(new MiracleEyeEffect());
}
}

View File

@@ -0,0 +1,51 @@
using PkmnLib.Static.Moves;
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "mirror_coat")]
public class MirrorCoat : Script
{
/// <inheritdoc />
public override void OnBeforeTurnStart(ITurnChoice choice)
{
choice.User.Volatile.Add(new MirrorCoatHelper());
}
/// <inheritdoc />
public override void ChangeMoveDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage)
{
var helper = target.Volatile.Get<MirrorCoatHelper>();
if (helper?.LastAttacker == null || helper.LastAttacker != move.User)
{
move.GetHitData(target, hit).Fail();
return;
}
damage = helper.LastDamage.MultiplyOrMax(2f);
target.Volatile.Remove<MirrorCoatHelper>();
}
[Script(ScriptCategory.Pokemon, "mirror_coat_helper")]
private class MirrorCoatHelper : Script
{
public IPokemon? LastAttacker { get; set; }
public uint LastDamage { get; set; }
/// <inheritdoc />
public override void OnIncomingHit(IExecutingMove move, IPokemon target, byte hit)
{
if (move.UseMove.Category != MoveCategory.Special)
return;
LastAttacker = move.User;
LastDamage = move.GetHitData(target, hit).Damage;
}
/// <inheritdoc />
public override void OnEndTurn(IBattle battle)
{
RemoveSelf();
}
}
}

View File

@@ -0,0 +1,30 @@
using System.Linq;
using PkmnLib.Plugin.Gen7.Scripts.Utils;
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "mirror_move")]
public class MirrorMove : Script
{
/// <inheritdoc />
public override void ChangeMove(IMoveChoice choice, ref StringKey moveName)
{
var battleData = choice.User.BattleData;
if (battleData == null)
return;
var battle = battleData.Battle;
var currentTurn = battle.ChoiceQueue!.LastRanChoice;
var lastMove = battle.PreviousTurnChoices.SelectMany(x => x).OfType<IMoveChoice>()
.TakeWhile(x => x != currentTurn).LastOrDefault(x => x.TargetPosition == choice.TargetPosition &&
x.TargetSide == choice.TargetSide &&
x.User.BattleData?.IsOnBattlefield == true);
if (lastMove == null || !lastMove.ChosenMove.MoveData.CanCopyMove())
{
choice.Fail();
return;
}
moveName = lastMove.ChosenMove.MoveData.Name;
}
}

View File

@@ -0,0 +1,17 @@
using PkmnLib.Plugin.Gen7.Scripts.Side;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "mist")]
public class Mist : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var battleData = move.User.BattleData;
if (battleData == null)
return;
battleData.BattleSide.VolatileScripts.Add(new MistEffect());
}
}

View File

@@ -0,0 +1,14 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "misty_terrain")]
public class MistyTerrain : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var battle = move.User.BattleData?.Battle;
if (battle is null)
return;
battle.SetTerrain(ScriptUtils.ResolveName<Terrain.MistyTerrain>());
}
}

View File

@@ -0,0 +1,14 @@
using System.Collections.Generic;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "moongeist_beam")]
public class MoongeistBeam : Script
{
/// <inheritdoc />
public override void OnBeforeAnyHookInvoked(ref List<ScriptCategory>? suppressedCategories)
{
suppressedCategories ??= [];
suppressedCategories.Add(ScriptCategory.Ability);
}
}

View File

@@ -0,0 +1,28 @@
using PkmnLib.Plugin.Gen7.Scripts.Weather;
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "moonlight")]
public class Moonlight : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var battleData = move.User.BattleData;
if (battleData == null)
return;
var fraction = 0.5f;
var weather = battleData.Battle.WeatherName;
if (weather == ScriptUtils.ResolveName<Sunny>())
fraction = 2f / 3f;
else if (weather == ScriptUtils.ResolveName<Rain>() || weather == ScriptUtils.ResolveName<Hail>() ||
weather == ScriptUtils.ResolveName<Sandstorm>())
fraction = 0.25f;
var maxHp = target.BoostedStats.Hp;
var healAmount = maxHp.MultiplyOrMax(fraction);
move.User.Heal(healAmount);
}
}

View File

@@ -0,0 +1,17 @@
using PkmnLib.Plugin.Gen7.Scripts.Battle;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "mud_sport")]
public class MudSport : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var battle = move.User.BattleData?.Battle;
if (battle == null)
return;
battle.Volatile.Add(new MudSportEffect());
}
}

View File

@@ -0,0 +1,20 @@
using PkmnLib.Static;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "multi_attack")]
public class MultiAttack : Script
{
/// <inheritdoc />
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;
if (item?.EndsWith("_memory") != true)
return;
var memoryType = item[..^7];
typeLibrary.TryGetTypeIdentifier(memoryType, out moveType);
}
}

View File

@@ -0,0 +1,60 @@
using System.Collections.Generic;
using PkmnLib.Static;
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "natural_gift")]
public class NaturalGift : Script
{
/// <inheritdoc />
public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref byte basePower)
{
var naturalGiftData = GetNaturalGiftData(move.User.HeldItem);
if (naturalGiftData == null)
{
move.GetHitData(target, hit).Fail();
return;
}
basePower = (byte)naturalGiftData.Value.power;
}
/// <inheritdoc />
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier moveType)
{
var naturalGiftData = GetNaturalGiftData(move.User.HeldItem);
if (naturalGiftData == null)
{
move.GetHitData(target, hit).Fail();
return;
}
var typeLibrary = move.User.Library.StaticLibrary.Types;
if (!typeLibrary.TryGetTypeIdentifier(naturalGiftData.Value.type, out var type))
{
move.GetHitData(target, hit).Fail();
return;
}
moveType = type;
}
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
_ = move.User.RemoveHeldItem();
}
private static (int power, StringKey type)? GetNaturalGiftData(IItem? item)
{
if (item == null)
return null;
if (!item.AdditionalData.TryGetValue("naturalGift", out var data) ||
data is not IReadOnlyDictionary<string, object> dict)
return null;
if (dict.TryGetValue("power", out var power) && dict.TryGetValue("type", out var type))
{
return ((int)power, (StringKey)(string)type);
}
return null;
}
}

View File

@@ -0,0 +1,7 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "nature_power")]
public class NaturePower : Script
{
// FIXME: Implement this. How to get the terrain in a sane manner?
}

View File

@@ -0,0 +1,12 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "natures_madness")]
public class NaturesMadness : Script
{
/// <inheritdoc />
public override void ChangeMoveDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage)
{
var targetMaxHp = target.BoostedStats.Hp;
damage = targetMaxHp / 2;
}
}

View File

@@ -0,0 +1,11 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "night_shade")]
public class NightShade : Script
{
/// <inheritdoc />
public override void ChangeMoveDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage)
{
damage = move.User.Level;
}
}

View File

@@ -0,0 +1,19 @@
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
using PkmnLib.Plugin.Gen7.Scripts.Status;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "nightmare")]
public class Nightmare : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
if (!target.HasStatus(ScriptUtils.ResolveName<Sleep>()))
{
move.GetHitData(target, hit).Fail();
return;
}
target.Volatile.Add(new NightmareEffect(target));
}
}

View File

@@ -1,6 +1,8 @@
using System.Collections.Generic;
using System.Linq;
using PkmnLib.Static;
using PkmnLib.Static.Libraries;
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
@@ -29,12 +31,12 @@ public class ForesightEffect : Script
}
/// <inheritdoc />
public override void ChangeEffectiveness(IExecutingMove move, IPokemon target, byte hit, ref float effectiveness)
public override void ChangeTypesForIncomingMove(IExecutingMove executingMove, IPokemon target, byte hitIndex,
IList<TypeIdentifier> types)
{
var hitData = move.GetHitData(target, hit);
if (hitData.Type == _normalType && target.Types.Contains(_fightingType))
effectiveness = _typeLibrary.GetEffectiveness(_normalType, target.Types.Where(x => x != _ghostType));
else if (hitData.Type == _fightingType && target.Types.Contains(_ghostType))
effectiveness = _typeLibrary.GetEffectiveness(_fightingType, target.Types.Where(x => x != _ghostType));
if (executingMove.UseMove.MoveType == _normalType || executingMove.UseMove.MoveType == _fightingType)
{
types.RemoveAll(x => x == _ghostType);
}
}
}

View File

@@ -1,4 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using PkmnLib.Static;
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
@@ -35,22 +38,14 @@ public class IngrainEffect : Script
}
/// <inheritdoc />
public override void ChangeEffectiveness(IExecutingMove move, IPokemon target, byte hit, ref float effectiveness)
public override void ChangeTypesForIncomingMove(IExecutingMove executingMove, IPokemon target, byte hitIndex,
IList<TypeIdentifier> types)
{
var battleData = target.BattleData;
if (battleData == null)
return;
if (move.UseMove.MoveType.Name != "ground")
return;
var targetTypes = target.Types;
var typeLibrary = battleData.Battle.Library.StaticLibrary.Types;
effectiveness =
// Get the effectiveness of the move against each target type
targetTypes.Select(x => typeLibrary.GetSingleEffectiveness(move.UseMove.MoveType, x))
// Ignore all types that are immune to ground moves
.Where(x => x > 0)
// Multiply all effectiveness values together
.Aggregate(1.0f, (current, x) => current * x);
if (executingMove.UseMove.MoveType.Name == "ground")
{
var typeLibrary = target.Library.StaticLibrary.Types;
// Remove all types that are immune to ground moves
types.RemoveAll(x => typeLibrary.GetSingleEffectiveness(executingMove.UseMove.MoveType, x) == 0);
}
}
}

View File

@@ -0,0 +1,24 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
[Script(ScriptCategory.Pokemon, "magma_storm")]
public class MagmaStormEffect : Script
{
private readonly IPokemon _owner;
public MagmaStormEffect(IPokemon owner)
{
_owner = owner;
}
/// <inheritdoc />
public override void OnEndTurn(IBattle battle)
{
_owner.Damage(_owner.BoostedStats.Hp / 16, DamageSource.Misc);
}
/// <inheritdoc />
public override void PreventSelfRunAway(IFleeChoice choice, ref bool prevent) => prevent = true;
/// <inheritdoc />
public override void PreventSelfSwitch(ISwitchChoice choice, ref bool prevent) => prevent = true;
}

View File

@@ -0,0 +1,25 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
[Script(ScriptCategory.Pokemon, "magnet_rise")]
public class MagnetRiseEffect : Script
{
private int _turnsRemaining = 5;
/// <inheritdoc />
public override void ChangeEffectiveness(IExecutingMove move, IPokemon target, byte hit, ref float effectiveness)
{
if (move.UseMove.MoveType.Name == "ground")
{
effectiveness = 0.0f;
}
}
/// <inheritdoc />
public override void OnEndTurn(IBattle battle)
{
if (_turnsRemaining > 0)
_turnsRemaining--;
else
RemoveSelf();
}
}

View File

@@ -0,0 +1,29 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
[Script(ScriptCategory.Pokemon, "mean_look_user")]
public class MeanLookEffectUser : Script
{
private readonly ScriptContainer _targetScriptEffect;
public MeanLookEffectUser(ScriptContainer targetScriptEffect)
{
_targetScriptEffect = targetScriptEffect;
}
/// <inheritdoc />
public override void OnRemove()
{
// Remove the effect from the target
_targetScriptEffect.Clear();
}
}
[Script(ScriptCategory.Pokemon, "mean_look_target")]
public class MeanLookEffectTarget : 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 @@
using System.Collections.Generic;
using System.Linq;
using PkmnLib.Static;
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
[Script(ScriptCategory.Pokemon, "miracle_eye")]
public class MiracleEyeEffect : Script
{
/// <inheritdoc />
public override void PreventStatBoostChange(IPokemon target, Statistic stat, sbyte amount, bool selfInflicted,
ref bool prevent)
{
if (stat == Statistic.Evasion && amount > 0)
prevent = true;
}
/// <inheritdoc />
public override void ChangeTypesForIncomingMove(IExecutingMove executingMove, IPokemon target, byte hitIndex,
IList<TypeIdentifier> types)
{
if (executingMove.UseMove.MoveType.Name != "psychic")
return;
var darkType = types.FirstOrDefault(x => x.Name == "dark");
if (darkType == null)
return;
types.Remove(darkType);
}
}

View File

@@ -0,0 +1,26 @@
using PkmnLib.Plugin.Gen7.Scripts.Status;
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
[Script(ScriptCategory.Pokemon, "nightmare")]
public class NightmareEffect : Script
{
private readonly IPokemon _owner;
public NightmareEffect(IPokemon owner)
{
_owner = owner;
}
/// <inheritdoc />
public override void OnEndTurn(IBattle battle)
{
if (!_owner.HasStatus(ScriptUtils.ResolveName<Sleep>()))
{
RemoveSelf();
return;
}
var maxHp = _owner.MaxHealth;
_owner.Damage(maxHp / 4, DamageSource.Misc);
}
}

View File

@@ -0,0 +1,19 @@
using PkmnLib.Static.Moves;
namespace PkmnLib.Plugin.Gen7.Scripts.Side;
public class MatBlockEffect : Script
{
/// <inheritdoc />
public override void BlockIncomingHit(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref bool block)
{
if (executingMove.UseMove.Category != MoveCategory.Status)
block = true;
}
/// <inheritdoc />
public override void OnEndTurn(IBattle battle)
{
RemoveSelf();
}
}

View File

@@ -0,0 +1,15 @@
using PkmnLib.Static;
namespace PkmnLib.Plugin.Gen7.Scripts.Side;
[Script(ScriptCategory.Side, "mist")]
public class MistEffect : Script
{
/// <inheritdoc />
public override void PreventStatBoostChange(IPokemon target, Statistic stat, sbyte amount, bool selfInflicted,
ref bool prevent)
{
if (amount < 0)
prevent = true;
}
}

View File

@@ -0,0 +1,7 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Terrain;
[Script(ScriptCategory.Terrain, "misty_terrain")]
public class MistyTerrain : Script
{
// TODO: Implement Terrain
}

View File

@@ -0,0 +1,7 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Weather;
[Script(ScriptCategory.Weather, "rain")]
public class Rain : Script
{
// TODO: Implement Rain
}

View File

@@ -0,0 +1,7 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Weather;
[Script(ScriptCategory.Weather, "sandstorm")]
public class Sandstorm : Script
{
// TODO: Implement Sandstorm
}

View File

@@ -0,0 +1,7 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Weather;
[Script(ScriptCategory.Weather, "sunny")]
public class Sunny : Script
{
// TODO: Implement Sunny
}