Bunch more moves, changes in how additional information for items works.
This commit is contained in:
parent
2adbb12367
commit
7c2845502d
@ -29,12 +29,12 @@ public static class ItemDataLoader
|
||||
|
||||
public delegate IItem ItemFactoryDelegate(SerializedItem serialized, StringKey name, ItemCategory type,
|
||||
BattleItemCategory battleType, int price, ImmutableHashSet<StringKey> flags, ISecondaryEffect? effect,
|
||||
ISecondaryEffect? battleTriggerEffect, byte flingPower);
|
||||
ISecondaryEffect? battleTriggerEffect, Dictionary<StringKey, object?> additionalData);
|
||||
|
||||
[PublicAPI]
|
||||
public static ItemFactoryDelegate ItemConstructor { get; set; } =
|
||||
(_, name, type, battleType, price, flags, effect, battleTriggerEffect, flingPower) => new ItemImpl(name, type,
|
||||
battleType, price, flags, effect, battleTriggerEffect, flingPower);
|
||||
(_, name, type, battleType, price, flags, effect, battleTriggerEffect, additionalData) => new ItemImpl(name,
|
||||
type, battleType, price, flags, effect, battleTriggerEffect, additionalData);
|
||||
|
||||
private static IItem DeserializeItem(SerializedItem serialized)
|
||||
{
|
||||
@ -43,9 +43,12 @@ public static class ItemDataLoader
|
||||
Enum.TryParse(serialized.BattleType, true, out BattleItemCategory battleType);
|
||||
var effect = serialized.Effect?.ParseEffect();
|
||||
var battleTriggerEffect = serialized.BattleEffect?.ParseEffect();
|
||||
var additionalData =
|
||||
serialized.AdditionalData?.ToDictionary(x => (StringKey)x.Key, x => x.Value.ToParameter()) ??
|
||||
new Dictionary<StringKey, object?>();
|
||||
|
||||
return ItemConstructor(serialized, serialized.Name, itemType, battleType, serialized.Price,
|
||||
serialized.Flags.Select(x => (StringKey)x).ToImmutableHashSet(), effect, battleTriggerEffect,
|
||||
serialized.FlingPower);
|
||||
additionalData);
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace PkmnLib.Dataloader.Models;
|
||||
@ -11,9 +12,10 @@ public class SerializedItem
|
||||
public string BattleType { get; set; } = null!;
|
||||
public string[] Flags { get; set; } = null!;
|
||||
public int Price { get; set; }
|
||||
public byte FlingPower { get; set; }
|
||||
public SerializedMoveEffect? Effect { get; set; }
|
||||
public SerializedMoveEffect? BattleEffect { get; set; }
|
||||
|
||||
public Dictionary<string, JsonNode>? AdditionalData { get; set; } = null!;
|
||||
|
||||
[JsonExtensionData] public Dictionary<string, JsonElement>? ExtensionData { get; set; }
|
||||
}
|
@ -11,18 +11,18 @@ internal static class MoveTurnExecutor
|
||||
internal static void ExecuteMoveChoice(IBattle battle, IMoveChoice moveChoice)
|
||||
{
|
||||
var chosenMove = moveChoice.ChosenMove;
|
||||
var moveData = chosenMove.MoveData;
|
||||
var useMove = chosenMove.MoveData;
|
||||
|
||||
var moveDataName = moveData.Name;
|
||||
var moveDataName = useMove.Name;
|
||||
moveChoice.RunScriptHook(x => x.ChangeMove(moveChoice, ref moveDataName));
|
||||
if (moveData.Name != moveDataName)
|
||||
if (useMove.Name != moveDataName)
|
||||
{
|
||||
if (!battle.Library.StaticLibrary.Moves.TryGet(moveDataName, out moveData))
|
||||
if (!battle.Library.StaticLibrary.Moves.TryGet(moveDataName, out useMove))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"The move was changed to '{moveDataName}' by a script, but this move does not exist.");
|
||||
}
|
||||
var secondaryEffect = moveData.SecondaryEffect;
|
||||
var secondaryEffect = useMove.SecondaryEffect;
|
||||
if (secondaryEffect != null)
|
||||
{
|
||||
if (moveChoice.User.Library.ScriptResolver.TryResolve(ScriptCategory.Move, secondaryEffect.Name,
|
||||
@ -30,10 +30,18 @@ internal static class MoveTurnExecutor
|
||||
{
|
||||
moveChoice.Script.Set(script);
|
||||
}
|
||||
else
|
||||
{
|
||||
moveChoice.Script.Clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
moveChoice.Script.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
var targetType = moveData.Target;
|
||||
var targetType = useMove.Target;
|
||||
var targets =
|
||||
TargetResolver.ResolveTargets(battle, moveChoice.TargetSide, moveChoice.TargetPosition, targetType);
|
||||
moveChoice.RunScriptHook(x => x.ChangeTargets(moveChoice, ref targets));
|
||||
@ -45,7 +53,7 @@ internal static class MoveTurnExecutor
|
||||
return;
|
||||
}
|
||||
|
||||
var executingMove = new ExecutingMoveImpl(targets, numberOfHits, chosenMove, moveData, moveChoice);
|
||||
var executingMove = new ExecutingMoveImpl(targets, numberOfHits, chosenMove, useMove, moveChoice);
|
||||
|
||||
var prevented = false;
|
||||
executingMove.RunScriptHook(x => x.PreventMove(executingMove, ref prevented));
|
||||
@ -117,8 +125,14 @@ internal static class MoveTurnExecutor
|
||||
var hitData = (HitData)executingMove.GetDataFromRawIndex(targetHitStat + i);
|
||||
hitData.Type = hitType;
|
||||
|
||||
var effectiveness = battle.Library.StaticLibrary.Types.GetEffectiveness(hitType, target.Types);
|
||||
var types = target.Types.ToList();
|
||||
executingMove.RunScriptHook(x => x.ChangeTypesForMove(executingMove, target, hitIndex, types));
|
||||
target.RunScriptHook(x => x.ChangeTypesForIncomingMove(executingMove, target, hitIndex, types));
|
||||
|
||||
var effectiveness = battle.Library.StaticLibrary.Types.GetEffectiveness(hitType, types);
|
||||
executingMove.RunScriptHook(x => x.ChangeEffectiveness(executingMove, target, hitIndex, ref effectiveness));
|
||||
target.RunScriptHook(x =>
|
||||
x.ChangeIncomingEffectiveness(executingMove, target, hitIndex, ref effectiveness));
|
||||
hitData.Effectiveness = effectiveness;
|
||||
|
||||
var blockCritical = false;
|
||||
|
@ -235,6 +235,7 @@ public class BattleSideImpl : ScriptSource, IBattleSide
|
||||
var oldPokemon = _pokemon[position];
|
||||
if (oldPokemon is not null)
|
||||
{
|
||||
oldPokemon.RunScriptHook(script => script.OnSwitchOut(oldPokemon, position));
|
||||
oldPokemon.RunScriptHook(script => script.OnRemove());
|
||||
oldPokemon.SetOnBattlefield(false);
|
||||
}
|
||||
|
@ -183,6 +183,8 @@ public class ExecutingMoveImpl : ScriptSource, IExecutingMove
|
||||
/// <inheritdoc />
|
||||
public ScriptContainer Script => MoveChoice.Script;
|
||||
|
||||
public IScriptSet Volatile => MoveChoice.Volatile;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IHitData GetHitData(IPokemon target, byte hit)
|
||||
{
|
||||
@ -224,18 +226,19 @@ public class ExecutingMoveImpl : ScriptSource, IExecutingMove
|
||||
public IMoveChoice MoveChoice { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int ScriptCount => 1 + User.ScriptCount;
|
||||
public override int ScriptCount => 2 + User.ScriptCount;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void GetOwnScripts(List<IEnumerable<ScriptContainer>> scripts)
|
||||
{
|
||||
scripts.Add(Volatile);
|
||||
scripts.Add(Script);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void CollectScripts(List<IEnumerable<ScriptContainer>> scripts)
|
||||
{
|
||||
scripts.Add(Script);
|
||||
GetOwnScripts(scripts);
|
||||
User.CollectScripts(scripts);
|
||||
}
|
||||
}
|
@ -8,26 +8,46 @@ namespace PkmnLib.Dynamic.ScriptHandling.Registry;
|
||||
/// </summary>
|
||||
public static class ScriptUtils
|
||||
{
|
||||
private static readonly Dictionary<Type, StringKey> NameCache = new();
|
||||
private static readonly Dictionary<Type, (ScriptCategory category, StringKey name)> Cache = new();
|
||||
|
||||
/// <summary>
|
||||
/// Resolve name from the <see cref="ScriptAttribute"/> of the given script.
|
||||
/// </summary>
|
||||
public static StringKey ResolveName(this Script script) => ResolveName(script.GetType());
|
||||
|
||||
/// <summary>
|
||||
/// Resolve name from the <see cref="ScriptAttribute"/> of the given type.
|
||||
/// </summary>
|
||||
public static StringKey ResolveName<T>() where T : Script => ResolveName(typeof(T));
|
||||
|
||||
/// <summary>
|
||||
/// Resolve name from the <see cref="ScriptAttribute"/> of the given type.
|
||||
/// </summary>
|
||||
public static StringKey ResolveName(Type type)
|
||||
public static StringKey ResolveName(Type type) => GetFromCacheOrAdd(type).name;
|
||||
|
||||
/// <summary>
|
||||
/// Resolve category from the <see cref="ScriptAttribute"/> of the given script.
|
||||
/// </summary>
|
||||
public static ScriptCategory ResolveCategory(this Script script) => ResolveCategory(script.GetType());
|
||||
|
||||
/// <summary>
|
||||
/// Resolve category from the <see cref="ScriptAttribute"/> of the given script.
|
||||
/// </summary>
|
||||
public static ScriptCategory ResolveCategory<T>() where T : Script => ResolveCategory(typeof(T));
|
||||
|
||||
/// <summary>
|
||||
/// Resolve category from the <see cref="ScriptAttribute"/> of the given type.
|
||||
/// </summary>
|
||||
public static ScriptCategory ResolveCategory(Type type) => GetFromCacheOrAdd(type).category;
|
||||
|
||||
private static (ScriptCategory category, StringKey name) GetFromCacheOrAdd(Type type)
|
||||
{
|
||||
if (NameCache.TryGetValue(type, out var name))
|
||||
return name;
|
||||
if (Cache.TryGetValue(type, out var key))
|
||||
return key;
|
||||
|
||||
var scriptAttr = type.GetCustomAttribute<ScriptAttribute>();
|
||||
if (scriptAttr == null)
|
||||
throw new InvalidOperationException($"Type {type} does not have a {nameof(ScriptAttribute)}.");
|
||||
return NameCache[type] = scriptAttr.Name;
|
||||
return Cache[type] = (scriptAttr.Category, scriptAttr.Name);
|
||||
}
|
||||
}
|
@ -29,6 +29,12 @@ public abstract class Script : IDeepCloneable
|
||||
/// </summary>
|
||||
public virtual StringKey Name => this.ResolveName();
|
||||
|
||||
/// <summary>
|
||||
/// The category of a script is used to determine what kind of script it is. This is used to
|
||||
/// determine what kind of script it is, and what kind of events it can handle.
|
||||
/// </summary>
|
||||
public virtual ScriptCategory Category => this.ResolveCategory();
|
||||
|
||||
/// <summary>
|
||||
/// A script can be suppressed by other scripts. If a script is suppressed by at least one script
|
||||
/// we will not execute its methods. This should return the number of suppressions on the script.
|
||||
@ -55,6 +61,10 @@ public abstract class Script : IDeepCloneable
|
||||
/// </summary>
|
||||
public void Unsuppress() => _suppressCount--;
|
||||
|
||||
public virtual void OnBeforeAnyHookInvoked(ref List<ScriptCategory>? suppressedCategories)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function is ran when a volatile effect is added while that volatile effect already is
|
||||
/// in place. Instead of adding the volatile effect twice, it will execute this function instead.
|
||||
@ -206,6 +216,11 @@ public abstract class Script : IDeepCloneable
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void ChangeIncomingEffectiveness(IExecutingMove executingMove, IPokemon target, byte hitIndex,
|
||||
ref float effectiveness)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function allows a script to block an outgoing move from being critical.
|
||||
/// </summary>
|
||||
@ -473,6 +488,10 @@ public abstract class Script : IDeepCloneable
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void OnSwitchOut(IPokemon oldPokemon, byte position)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function is triggered on a Pokemon and its parents when the given Pokemon is switched into
|
||||
/// the battlefield.
|
||||
@ -567,4 +586,14 @@ public abstract class Script : IDeepCloneable
|
||||
public virtual void PreventHeal(IPokemon pokemon, uint heal, bool allowRevive, ref bool prevented)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void ChangeTypesForMove(IExecutingMove executingMove, IPokemon target, byte hitIndex,
|
||||
IList<TypeIdentifier> types)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void ChangeTypesForIncomingMove(IExecutingMove executingMove, IPokemon target, byte hitIndex,
|
||||
IList<TypeIdentifier> types)
|
||||
{
|
||||
}
|
||||
}
|
@ -16,6 +16,14 @@ public static class ScriptExecution
|
||||
public static void RunScriptHook(this IScriptSource source, Action<Script> hook)
|
||||
{
|
||||
var iterator = source.GetScripts();
|
||||
List<ScriptCategory>? suppressedCategories = null;
|
||||
foreach (var container in iterator)
|
||||
{
|
||||
if (container.IsEmpty)
|
||||
continue;
|
||||
var script = container.Script;
|
||||
script.OnBeforeAnyHookInvoked(ref suppressedCategories);
|
||||
}
|
||||
foreach (var container in iterator)
|
||||
{
|
||||
if (container.IsEmpty)
|
||||
@ -23,6 +31,8 @@ public static class ScriptExecution
|
||||
var script = container.Script;
|
||||
if (script.IsSuppressed)
|
||||
continue;
|
||||
if (suppressedCategories != null && suppressedCategories.Contains(script.Category))
|
||||
continue;
|
||||
hook(script);
|
||||
}
|
||||
}
|
||||
@ -33,6 +43,14 @@ public static class ScriptExecution
|
||||
/// </summary>
|
||||
public static void RunScriptHook(this IReadOnlyList<IEnumerable<ScriptContainer>> source, Action<Script> hook)
|
||||
{
|
||||
List<ScriptCategory>? suppressedCategories = null;
|
||||
foreach (var container in source.SelectMany(x => x))
|
||||
{
|
||||
if (container.IsEmpty)
|
||||
continue;
|
||||
var script = container.Script;
|
||||
script.OnBeforeAnyHookInvoked(ref suppressedCategories);
|
||||
}
|
||||
foreach (var container in source.SelectMany(x => x))
|
||||
{
|
||||
if (container.IsEmpty)
|
||||
@ -40,6 +58,8 @@ public static class ScriptExecution
|
||||
var script = container.Script;
|
||||
if (script.IsSuppressed)
|
||||
continue;
|
||||
if (suppressedCategories != null && suppressedCategories.Contains(script.Category))
|
||||
continue;
|
||||
hook(script);
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,11 @@ public interface IScriptSet : IEnumerable<ScriptContainer>
|
||||
/// </summary>
|
||||
void Remove(StringKey scriptKey);
|
||||
|
||||
/// <summary>
|
||||
/// Removes a script from the set using its type.
|
||||
/// </summary>
|
||||
void Remove<T>() where T : Script => Remove(ScriptUtils.ResolveName<T>());
|
||||
|
||||
/// <summary>
|
||||
/// Clears all scripts from the set.
|
||||
/// </summary>
|
||||
|
@ -109,7 +109,9 @@ public interface IItem : INamedValue
|
||||
ISecondaryEffect? Effect { get; }
|
||||
ISecondaryEffect? BattleEffect { get; }
|
||||
|
||||
byte FlingPower { get; }
|
||||
IReadOnlyDictionary<StringKey, object?> AdditionalData { get; }
|
||||
|
||||
bool TryGetAdditionalData<T>(StringKey key, out T? value);
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the item has a specific flag.
|
||||
@ -124,7 +126,8 @@ public class ItemImpl : IItem
|
||||
{
|
||||
/// <inheritdoc cref="ItemImpl"/>
|
||||
public ItemImpl(StringKey name, ItemCategory category, BattleItemCategory battleCategory, int price,
|
||||
IEnumerable<StringKey> flags, ISecondaryEffect? effect, ISecondaryEffect? battleTriggerEffect, byte flingPower)
|
||||
IEnumerable<StringKey> flags, ISecondaryEffect? effect, ISecondaryEffect? battleTriggerEffect,
|
||||
Dictionary<StringKey, object?> additionalData)
|
||||
{
|
||||
Name = name;
|
||||
Category = category;
|
||||
@ -132,7 +135,7 @@ public class ItemImpl : IItem
|
||||
Price = price;
|
||||
Effect = effect;
|
||||
BattleEffect = battleTriggerEffect;
|
||||
FlingPower = flingPower;
|
||||
AdditionalData = additionalData;
|
||||
Flags = [..flags];
|
||||
}
|
||||
|
||||
@ -158,7 +161,35 @@ public class ItemImpl : IItem
|
||||
public ISecondaryEffect? BattleEffect { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public byte FlingPower { get; }
|
||||
public IReadOnlyDictionary<StringKey, object?> AdditionalData { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool TryGetAdditionalData<T>(StringKey key, out T? value)
|
||||
{
|
||||
if (AdditionalData.TryGetValue(key, out var obj))
|
||||
{
|
||||
switch (obj)
|
||||
{
|
||||
case T t:
|
||||
value = t;
|
||||
return true;
|
||||
case IConvertible convertible:
|
||||
try
|
||||
{
|
||||
value = (T)convertible.ToType(typeof(T), null);
|
||||
return true;
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
// Ignore
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasFlag(string key) => Flags.Contains(key);
|
||||
|
@ -33,4 +33,13 @@ public static class EnumerableHelpers
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static void RemoveAll<T>(this IList<T> list, Func<T, bool> predicate)
|
||||
{
|
||||
for (var i = list.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (predicate(list[i]))
|
||||
list.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
@ -55,4 +55,10 @@ public static class NumericHelpers
|
||||
var result = (ulong)value * multiplier;
|
||||
return result > uint.MaxValue ? uint.MaxValue : (uint)result;
|
||||
}
|
||||
|
||||
public static uint MultiplyOrMax(this uint value, float multiplier)
|
||||
{
|
||||
var result = value * multiplier;
|
||||
return result > uint.MaxValue ? uint.MaxValue : (uint)result;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -6478,14 +6478,17 @@
|
||||
"category": "status",
|
||||
"flags": [
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "magic_room"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "magical_leaf",
|
||||
"type": "grass",
|
||||
"power": 60,
|
||||
"pp": 20,
|
||||
"accuracy": 0,
|
||||
"accuracy": 255,
|
||||
"priority": 0,
|
||||
"target": "Any",
|
||||
"category": "special",
|
||||
@ -6493,6 +6496,7 @@
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
// No secondary effect
|
||||
},
|
||||
{
|
||||
"name": "magma_storm",
|
||||
@ -6506,14 +6510,17 @@
|
||||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "magma_storm"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "magnet_bomb",
|
||||
"type": "steel",
|
||||
"power": 60,
|
||||
"pp": 20,
|
||||
"accuracy": 0,
|
||||
"accuracy": 255,
|
||||
"priority": 0,
|
||||
"target": "Any",
|
||||
"category": "physical",
|
||||
@ -6522,6 +6529,7 @@
|
||||
"mirror",
|
||||
"ballistics"
|
||||
]
|
||||
// No secondary effect
|
||||
},
|
||||
{
|
||||
"name": "magnet_rise",
|
||||
@ -6535,7 +6543,10 @@
|
||||
"flags": [
|
||||
"snatch",
|
||||
"gravity"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "magnet_rise"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "magnetic_flux",
|
||||
@ -6565,7 +6576,10 @@
|
||||
"protect",
|
||||
"mirror",
|
||||
"nonskybattle"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "magnitude"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "malicious_moonsault",
|
||||
@ -6579,6 +6593,7 @@
|
||||
"flags": [
|
||||
"contact"
|
||||
]
|
||||
// No secondary effect
|
||||
},
|
||||
{
|
||||
"name": "mat_block",
|
||||
@ -6592,7 +6607,10 @@
|
||||
"flags": [
|
||||
"snatch",
|
||||
"nonskybattle"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "mat_block"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "me_first",
|
||||
@ -6606,7 +6624,10 @@
|
||||
"flags": [
|
||||
"protect",
|
||||
"ignore-substitute"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "me_first"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mean_look",
|
||||
@ -6620,7 +6641,10 @@
|
||||
"flags": [
|
||||
"reflectable",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "mean_look"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "meditate",
|
||||
@ -6633,7 +6657,13 @@
|
||||
"category": "status",
|
||||
"flags": [
|
||||
"snatch"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_user_attack",
|
||||
"parameters": {
|
||||
"amount": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mega_drain",
|
||||
@ -6648,7 +6678,13 @@
|
||||
"protect",
|
||||
"mirror",
|
||||
"heal"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "drain",
|
||||
"parameters": {
|
||||
"drain_modifier": 0.5
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mega_kick",
|
||||
@ -6664,6 +6700,7 @@
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
// No secondary effect
|
||||
},
|
||||
{
|
||||
"name": "mega_punch",
|
||||
@ -6680,6 +6717,7 @@
|
||||
"mirror",
|
||||
"punch"
|
||||
]
|
||||
// No secondary effect
|
||||
},
|
||||
{
|
||||
"name": "megahorn",
|
||||
@ -6695,6 +6733,7 @@
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
// No secondary effect
|
||||
},
|
||||
{
|
||||
"name": "memento",
|
||||
@ -6708,7 +6747,10 @@
|
||||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "memento"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "metal_burst",
|
||||
@ -6722,7 +6764,10 @@
|
||||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "metal_burst"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "metal_claw",
|
||||
@ -6737,7 +6782,14 @@
|
||||
"contact",
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_user_attack",
|
||||
"chance": 10,
|
||||
"parameters": {
|
||||
"amount": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "metal_sound",
|
||||
@ -6754,7 +6806,13 @@
|
||||
"mirror",
|
||||
"sound",
|
||||
"ignore-substitute"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_target_special_defense",
|
||||
"parameters": {
|
||||
"amount": -2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "meteor_mash",
|
||||
@ -6770,7 +6828,14 @@
|
||||
"protect",
|
||||
"mirror",
|
||||
"punch"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_user_attack",
|
||||
"chance": 20,
|
||||
"parameters": {
|
||||
"amount": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "metronome",
|
||||
@ -6781,7 +6846,10 @@
|
||||
"priority": 0,
|
||||
"target": "Self",
|
||||
"category": "status",
|
||||
"flags": []
|
||||
"flags": [],
|
||||
"effect": {
|
||||
"name": "metronome"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "milk_drink",
|
||||
@ -6795,7 +6863,13 @@
|
||||
"flags": [
|
||||
"snatch",
|
||||
"heal"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "heal_percent",
|
||||
"parameters": {
|
||||
"healPercent": 0.5
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mimic",
|
||||
@ -6809,7 +6883,10 @@
|
||||
"flags": [
|
||||
"protect",
|
||||
"ignore-substitute"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "mimic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mind_reader",
|
||||
@ -6823,27 +6900,36 @@
|
||||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "lock_on"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "minimize",
|
||||
"type": "normal",
|
||||
"power": 0,
|
||||
"pp": 10,
|
||||
"accuracy": 0,
|
||||
"accuracy": 255,
|
||||
"priority": 0,
|
||||
"target": "Self",
|
||||
"category": "status",
|
||||
"flags": [
|
||||
"snatch"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_user_evasion",
|
||||
"parameters": {
|
||||
"amount": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "miracle_eye",
|
||||
"type": "psychic",
|
||||
"power": 0,
|
||||
"pp": 40,
|
||||
"accuracy": 0,
|
||||
"accuracy": 255,
|
||||
"priority": 0,
|
||||
"target": "Any",
|
||||
"category": "status",
|
||||
@ -6852,7 +6938,10 @@
|
||||
"reflectable",
|
||||
"mirror",
|
||||
"ignore-substitute"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "miracle_eye"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mirror_coat",
|
||||
@ -6865,7 +6954,10 @@
|
||||
"category": "special",
|
||||
"flags": [
|
||||
"protect"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "mirror_coat"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mirror_move",
|
||||
@ -6876,7 +6968,10 @@
|
||||
"priority": 0,
|
||||
"target": "Any",
|
||||
"category": "status",
|
||||
"flags": []
|
||||
"flags": [],
|
||||
"effect": {
|
||||
"name": "mirror_move"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mirror_shot",
|
||||
@ -6890,7 +6985,14 @@
|
||||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_target_special_defense",
|
||||
"chance": 30,
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mist",
|
||||
@ -6903,7 +7005,10 @@
|
||||
"category": "status",
|
||||
"flags": [
|
||||
"snatch"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "mist"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mist_ball",
|
||||
@ -6917,7 +7022,14 @@
|
||||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_target_special_attack",
|
||||
"chance": 50,
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "misty_terrain",
|
||||
@ -6930,7 +7042,10 @@
|
||||
"category": "status",
|
||||
"flags": [
|
||||
"nonskybattle"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "misty_terrain"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "moonblast",
|
||||
@ -6944,7 +7059,14 @@
|
||||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_target_special_attack",
|
||||
"chance": 30,
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "moongeist_beam",
|
||||
@ -6958,7 +7080,10 @@
|
||||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "moongeist_beam"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "moonlight",
|
||||
@ -6972,7 +7097,10 @@
|
||||
"flags": [
|
||||
"snatch",
|
||||
"heal"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "moonlight"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "morning_sun",
|
||||
@ -6986,7 +7114,10 @@
|
||||
"flags": [
|
||||
"snatch",
|
||||
"heal"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "moonlight"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mud_bomb",
|
||||
@ -7001,7 +7132,14 @@
|
||||
"protect",
|
||||
"mirror",
|
||||
"ballistics"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_target_accuracy",
|
||||
"chance": 30,
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mud_shot",
|
||||
@ -7015,7 +7153,13 @@
|
||||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_target_speed",
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mud_slap",
|
||||
@ -7029,7 +7173,13 @@
|
||||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_target_accuracy",
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mud_sport",
|
||||
@ -7042,7 +7192,10 @@
|
||||
"category": "status",
|
||||
"flags": [
|
||||
"nonskybattle"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "mud_sport"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "muddy_water",
|
||||
@ -7057,7 +7210,14 @@
|
||||
"protect",
|
||||
"mirror",
|
||||
"nonskybattle"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_target_accuracy",
|
||||
"chance": 30,
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "multi_attack",
|
||||
@ -7072,7 +7232,10 @@
|
||||
"contact",
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "multi_attack"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mystical_fire",
|
||||
@ -7086,7 +7249,13 @@
|
||||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_target_special_attack",
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "nasty_plot",
|
||||
@ -7099,7 +7268,13 @@
|
||||
"category": "status",
|
||||
"flags": [
|
||||
"snatch"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_user_special_attack",
|
||||
"parameters": {
|
||||
"amount": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "natural_gift",
|
||||
@ -7113,7 +7288,10 @@
|
||||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "natural_gift"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "nature_power",
|
||||
@ -7124,7 +7302,10 @@
|
||||
"priority": 0,
|
||||
"target": "Any",
|
||||
"category": "status",
|
||||
"flags": []
|
||||
"flags": [],
|
||||
"effect": {
|
||||
"name": "nature_power"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "natures_madness",
|
||||
@ -7138,7 +7319,10 @@
|
||||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "natures_madness"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "needle_arm",
|
||||
@ -7153,7 +7337,11 @@
|
||||
"contact",
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "flinch",
|
||||
"chance": 30
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "never_ending_nightmare__physical",
|
||||
@ -7165,6 +7353,7 @@
|
||||
"target": "Any",
|
||||
"category": "physical",
|
||||
"flags": []
|
||||
// No secondary effect
|
||||
},
|
||||
{
|
||||
"name": "never_ending_nightmare__special",
|
||||
@ -7176,6 +7365,7 @@
|
||||
"target": "Any",
|
||||
"category": "special",
|
||||
"flags": []
|
||||
// No secondary effect
|
||||
},
|
||||
{
|
||||
"name": "night_daze",
|
||||
@ -7189,7 +7379,14 @@
|
||||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_target_accuracy",
|
||||
"chance": 40,
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "night_shade",
|
||||
@ -7203,7 +7400,10 @@
|
||||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "night_shade"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "night_slash",
|
||||
@ -7218,7 +7418,10 @@
|
||||
"contact",
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "increased_critical_stage"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "nightmare",
|
||||
@ -7232,7 +7435,10 @@
|
||||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "nightmare"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "noble_roar",
|
||||
@ -7249,7 +7455,14 @@
|
||||
"mirror",
|
||||
"sound",
|
||||
"ignore-substitute"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_multiple_target_stat_boosts",
|
||||
"parameters": {
|
||||
"attack": -1,
|
||||
"specialAttack": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "nuzzle",
|
||||
@ -7264,7 +7477,13 @@
|
||||
"contact",
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "set_status",
|
||||
"parameters": {
|
||||
"status": "paralyzed"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "oblivion_wing",
|
||||
@ -7280,7 +7499,13 @@
|
||||
"mirror",
|
||||
"distance",
|
||||
"heal"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "drain",
|
||||
"parameters": {
|
||||
"drain_modifier": 0.75
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "oceanic_operetta",
|
||||
@ -7292,6 +7517,7 @@
|
||||
"target": "Any",
|
||||
"category": "special",
|
||||
"flags": []
|
||||
// No secondary effect
|
||||
},
|
||||
{
|
||||
"name": "octazooka",
|
||||
@ -7306,7 +7532,14 @@
|
||||
"protect",
|
||||
"mirror",
|
||||
"ballistics"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_target_accuracy",
|
||||
"chance": 50,
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "odor_sleuth",
|
||||
|
@ -0,0 +1,89 @@
|
||||
using PkmnLib.Dynamic.Libraries;
|
||||
using PkmnLib.Dynamic.Models;
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
using PkmnLib.Static;
|
||||
using PkmnLib.Static.Libraries;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
|
||||
public class MultiAttackTests
|
||||
{
|
||||
public record TestCaseData(string? ItemName, string ExpectedTypeName)
|
||||
{
|
||||
public override string ToString() => $"MultiAttack {ItemName ?? "None"} => {ExpectedTypeName}";
|
||||
}
|
||||
|
||||
public static IEnumerable<Func<TestCaseData>> ChangeMoveTypeData()
|
||||
{
|
||||
yield return () => new TestCaseData("bug_memory", "bug");
|
||||
yield return () => new TestCaseData("dark_memory", "dark");
|
||||
yield return () => new TestCaseData("dragon_memory", "dragon");
|
||||
yield return () => new TestCaseData("electric_memory", "electric");
|
||||
yield return () => new TestCaseData("fairy_memory", "fairy");
|
||||
yield return () => new TestCaseData("fighting_memory", "fighting");
|
||||
yield return () => new TestCaseData("fire_memory", "fire");
|
||||
yield return () => new TestCaseData("flying_memory", "flying");
|
||||
yield return () => new TestCaseData("ghost_memory", "ghost");
|
||||
yield return () => new TestCaseData("grass_memory", "grass");
|
||||
yield return () => new TestCaseData("ground_memory", "ground");
|
||||
yield return () => new TestCaseData("ice_memory", "ice");
|
||||
yield return () => new TestCaseData("poison_memory", "poison");
|
||||
yield return () => new TestCaseData("psychic_memory", "psychic");
|
||||
yield return () => new TestCaseData("rock_memory", "rock");
|
||||
yield return () => new TestCaseData("steel_memory", "steel");
|
||||
yield return () => new TestCaseData("water_memory", "water");
|
||||
yield return () => new TestCaseData("something_random", "normal");
|
||||
yield return () => new TestCaseData(null, "normal");
|
||||
}
|
||||
|
||||
[Test, MethodDataSource(nameof(ChangeMoveTypeData))]
|
||||
public async Task ChangeMoveType_UserHoldingMemoryItem_ChangeMoveType(TestCaseData test)
|
||||
{
|
||||
var typeLibrary = new TypeLibrary();
|
||||
typeLibrary.RegisterType("normal");
|
||||
typeLibrary.RegisterType("fighting");
|
||||
typeLibrary.RegisterType("flying");
|
||||
typeLibrary.RegisterType("poison");
|
||||
typeLibrary.RegisterType("ground");
|
||||
typeLibrary.RegisterType("rock");
|
||||
typeLibrary.RegisterType("bug");
|
||||
typeLibrary.RegisterType("ghost");
|
||||
typeLibrary.RegisterType("steel");
|
||||
typeLibrary.RegisterType("fire");
|
||||
typeLibrary.RegisterType("water");
|
||||
typeLibrary.RegisterType("grass");
|
||||
typeLibrary.RegisterType("electric");
|
||||
typeLibrary.RegisterType("psychic");
|
||||
typeLibrary.RegisterType("ice");
|
||||
typeLibrary.RegisterType("dragon");
|
||||
typeLibrary.RegisterType("dark");
|
||||
typeLibrary.RegisterType("fairy");
|
||||
|
||||
// Arrange
|
||||
var move = new Mock<IExecutingMove>();
|
||||
var target = new Mock<IPokemon>();
|
||||
var user = new Mock<IPokemon>();
|
||||
var typeIdentifier = new TypeIdentifier(1, "Normal");
|
||||
var dynamicLibrary = new Mock<IDynamicLibrary>();
|
||||
var staticLibrary = new Mock<IStaticLibrary>();
|
||||
var item = new Mock<IItem>();
|
||||
|
||||
user.Setup(u => u.Library).Returns(dynamicLibrary.Object);
|
||||
dynamicLibrary.Setup(d => d.StaticLibrary).Returns(staticLibrary.Object);
|
||||
staticLibrary.Setup(s => s.Types).Returns(typeLibrary);
|
||||
item.Setup(i => i.Name).Returns(test.ItemName!);
|
||||
move.Setup(m => m.User).Returns(user.Object);
|
||||
|
||||
if (test.ItemName != null)
|
||||
move.Setup(m => m.User.HeldItem).Returns(item.Object);
|
||||
else
|
||||
move.Setup(m => m.User.HeldItem).Returns((IItem?)null);
|
||||
var multiAttack = new MultiAttack();
|
||||
|
||||
// Act
|
||||
multiAttack.ChangeMoveType(move.Object, target.Object, 0, ref typeIdentifier);
|
||||
|
||||
// Assert
|
||||
await Assert.That(typeIdentifier.Name).IsEqualTo(test.ExpectedTypeName);
|
||||
}
|
||||
}
|
@ -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 />
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
28
Plugins/PkmnLib.Plugin.Gen7/Scripts/Battle/MudSportEffect.cs
Normal file
28
Plugins/PkmnLib.Plugin.Gen7/Scripts/Battle/MudSportEffect.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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 />
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
18
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MagicRoom.cs
Normal file
18
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MagicRoom.cs
Normal 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());
|
||||
}
|
||||
}
|
13
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MagmaStorm.cs
Normal file
13
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MagmaStorm.cs
Normal 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));
|
||||
}
|
||||
}
|
19
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MagnetRise.cs
Normal file
19
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MagnetRise.cs
Normal 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());
|
||||
}
|
||||
}
|
52
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Magnitude.cs
Normal file
52
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Magnitude.cs
Normal 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,
|
||||
};
|
||||
}
|
||||
}
|
22
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MatBlock.cs
Normal file
22
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MatBlock.cs
Normal 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());
|
||||
}
|
||||
}
|
31
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MeFirst.cs
Normal file
31
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MeFirst.cs
Normal 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());
|
||||
}
|
||||
}
|
15
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MeanLook.cs
Normal file
15
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MeanLook.cs
Normal 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);
|
||||
}
|
||||
}
|
17
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Memento.cs
Normal file
17
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Memento.cs
Normal 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);
|
||||
}
|
||||
}
|
51
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MetalBurst.cs
Normal file
51
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MetalBurst.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
38
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Metronome.cs
Normal file
38
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Metronome.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
9
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Mimic.cs
Normal file
9
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Mimic.cs
Normal 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.
|
||||
}
|
18
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MiracleEye.cs
Normal file
18
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MiracleEye.cs
Normal 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());
|
||||
}
|
||||
}
|
51
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MirrorCoat.cs
Normal file
51
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MirrorCoat.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
30
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MirrorMove.cs
Normal file
30
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MirrorMove.cs
Normal 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;
|
||||
}
|
||||
}
|
17
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Mist.cs
Normal file
17
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Mist.cs
Normal 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());
|
||||
}
|
||||
}
|
14
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MistyTerrain.cs
Normal file
14
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MistyTerrain.cs
Normal 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>());
|
||||
}
|
||||
}
|
14
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MoongeistBeam.cs
Normal file
14
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MoongeistBeam.cs
Normal 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);
|
||||
}
|
||||
}
|
28
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Moonlight.cs
Normal file
28
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Moonlight.cs
Normal 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);
|
||||
}
|
||||
}
|
17
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MudSport.cs
Normal file
17
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MudSport.cs
Normal 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());
|
||||
}
|
||||
}
|
20
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MultiAttack.cs
Normal file
20
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/MultiAttack.cs
Normal 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);
|
||||
}
|
||||
}
|
60
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/NaturalGift.cs
Normal file
60
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/NaturalGift.cs
Normal 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;
|
||||
}
|
||||
}
|
7
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/NaturePower.cs
Normal file
7
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/NaturePower.cs
Normal 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?
|
||||
}
|
12
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/NaturesMadness.cs
Normal file
12
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/NaturesMadness.cs
Normal 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;
|
||||
}
|
||||
}
|
11
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/NightShade.cs
Normal file
11
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/NightShade.cs
Normal 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;
|
||||
}
|
||||
}
|
19
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Nightmare.cs
Normal file
19
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Nightmare.cs
Normal 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));
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
19
Plugins/PkmnLib.Plugin.Gen7/Scripts/Side/MatBlockEffect.cs
Normal file
19
Plugins/PkmnLib.Plugin.Gen7/Scripts/Side/MatBlockEffect.cs
Normal 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();
|
||||
}
|
||||
}
|
15
Plugins/PkmnLib.Plugin.Gen7/Scripts/Side/MistEffect.cs
Normal file
15
Plugins/PkmnLib.Plugin.Gen7/Scripts/Side/MistEffect.cs
Normal 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;
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Terrain;
|
||||
|
||||
[Script(ScriptCategory.Terrain, "misty_terrain")]
|
||||
public class MistyTerrain : Script
|
||||
{
|
||||
// TODO: Implement Terrain
|
||||
}
|
7
Plugins/PkmnLib.Plugin.Gen7/Scripts/Weather/Rain.cs
Normal file
7
Plugins/PkmnLib.Plugin.Gen7/Scripts/Weather/Rain.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Weather;
|
||||
|
||||
[Script(ScriptCategory.Weather, "rain")]
|
||||
public class Rain : Script
|
||||
{
|
||||
// TODO: Implement Rain
|
||||
}
|
7
Plugins/PkmnLib.Plugin.Gen7/Scripts/Weather/Sandstorm.cs
Normal file
7
Plugins/PkmnLib.Plugin.Gen7/Scripts/Weather/Sandstorm.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Weather;
|
||||
|
||||
[Script(ScriptCategory.Weather, "sandstorm")]
|
||||
public class Sandstorm : Script
|
||||
{
|
||||
// TODO: Implement Sandstorm
|
||||
}
|
7
Plugins/PkmnLib.Plugin.Gen7/Scripts/Weather/Sunny.cs
Normal file
7
Plugins/PkmnLib.Plugin.Gen7/Scripts/Weather/Sunny.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Weather;
|
||||
|
||||
[Script(ScriptCategory.Weather, "sunny")]
|
||||
public class Sunny : Script
|
||||
{
|
||||
// TODO: Implement Sunny
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user