First couple abilities implemented
All checks were successful
Build / Build (push) Successful in 48s
All checks were successful
Build / Build (push) Successful in 48s
This commit is contained in:
parent
c1a7b806b1
commit
b090aa65f9
@ -263,6 +263,8 @@ public static class MoveTurnExecutor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (target.IsFainted)
|
||||||
|
executingMove.RunScriptHook(x => x.OnOpponentFaints(executingMove, target, hitIndex));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
20
PkmnLib.Dynamic/Events/AbilityTriggerEvent.cs
Normal file
20
PkmnLib.Dynamic/Events/AbilityTriggerEvent.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using PkmnLib.Dynamic.Models;
|
||||||
|
using PkmnLib.Static.Species;
|
||||||
|
using PkmnLib.Static.Utils;
|
||||||
|
|
||||||
|
namespace PkmnLib.Dynamic.Events;
|
||||||
|
|
||||||
|
public record AbilityTriggerEvent : IEventData
|
||||||
|
{
|
||||||
|
public IPokemon Pokemon { get; }
|
||||||
|
public IAbility? Ability { get; }
|
||||||
|
|
||||||
|
public AbilityTriggerEvent(IPokemon pokemon)
|
||||||
|
{
|
||||||
|
Pokemon = pokemon;
|
||||||
|
Ability = pokemon.ActiveAbility;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public EventBatchId BatchId { get; init; }
|
||||||
|
}
|
@ -59,7 +59,7 @@ public static class AbilityDataLoader
|
|||||||
|
|
||||||
var flags = serialized.Flags.Select(x => new StringKey(x)).ToImmutableHashSet();
|
var flags = serialized.Flags.Select(x => new StringKey(x)).ToImmutableHashSet();
|
||||||
|
|
||||||
var ability = new AbilityImpl(name, effectName, parameters, flags);
|
var ability = new AbilityImpl(name, effectName, parameters, flags, serialized.CanBeChanged ?? true);
|
||||||
return ability;
|
return ability;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -19,4 +19,6 @@ public class SerializedAbility
|
|||||||
/// A collection of arbitrary flags that can be used to mark the ability with specific properties.
|
/// A collection of arbitrary flags that can be used to mark the ability with specific properties.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string[] Flags { get; set; } = [];
|
public string[] Flags { get; set; } = [];
|
||||||
|
|
||||||
|
public bool? CanBeChanged { get; set; }
|
||||||
}
|
}
|
@ -271,18 +271,25 @@ public class BattleSideImpl : ScriptSource, IBattleSide
|
|||||||
pokemon.SetBattleData(Battle, Index);
|
pokemon.SetBattleData(Battle, Index);
|
||||||
pokemon.SetOnBattlefield(true);
|
pokemon.SetOnBattlefield(true);
|
||||||
pokemon.SetBattleSidePosition(position);
|
pokemon.SetBattleSidePosition(position);
|
||||||
|
Battle.EventHook.Invoke(new SwitchEvent(Index, position, pokemon));
|
||||||
|
pokemon.RunScriptHook(script => script.OnSwitchIn(pokemon, position));
|
||||||
|
|
||||||
foreach (var side in Battle.Sides)
|
foreach (var side in Battle.Sides)
|
||||||
{
|
{
|
||||||
if (side == this)
|
if (side == this)
|
||||||
continue;
|
continue;
|
||||||
|
var scripts = new List<IEnumerable<ScriptContainer>>(10);
|
||||||
foreach (var opponent in side.Pokemon.WhereNotNull())
|
foreach (var opponent in side.Pokemon.WhereNotNull())
|
||||||
{
|
{
|
||||||
opponent.MarkOpponentAsSeen(pokemon);
|
opponent.MarkOpponentAsSeen(pokemon);
|
||||||
pokemon.MarkOpponentAsSeen(opponent);
|
pokemon.MarkOpponentAsSeen(opponent);
|
||||||
|
|
||||||
|
scripts.Clear();
|
||||||
|
opponent.GetOwnScripts(scripts);
|
||||||
|
opponent.RunScriptHook(script => script.OnOpponentSwitchIn(pokemon, position));
|
||||||
}
|
}
|
||||||
|
side.RunScriptHook(script => script.OnOpponentSwitchIn(pokemon, position));
|
||||||
}
|
}
|
||||||
Battle.EventHook.Invoke(new SwitchEvent(Index, position, pokemon));
|
|
||||||
pokemon.RunScriptHook(script => script.OnSwitchIn(pokemon, position));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -46,6 +46,16 @@ public interface IHitData
|
|||||||
/// Fails the hit.
|
/// Fails the hit.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Fail();
|
void Fail();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets a flag on the hit data. This is used to mark certain conditions or states
|
||||||
|
/// </summary>
|
||||||
|
void SetFlag(StringKey flag);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks whether a flag is set on the hit data.
|
||||||
|
/// </summary>
|
||||||
|
bool HasFlag(StringKey flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -71,6 +81,18 @@ public record HitData : IHitData
|
|||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Fail() => HasFailed = true;
|
public void Fail() => HasFailed = true;
|
||||||
|
|
||||||
|
private HashSet<StringKey>? _flags;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void SetFlag(StringKey flag)
|
||||||
|
{
|
||||||
|
_flags ??= [];
|
||||||
|
_flags.Add(flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool HasFlag(StringKey flag) => _flags != null && _flags.Contains(flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -401,7 +401,7 @@ public interface IPokemon : IScriptSource, IDeepCloneable
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Changes the ability of the Pokémon.
|
/// Changes the ability of the Pokémon.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void ChangeAbility(IAbility ability);
|
bool ChangeAbility(IAbility ability);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the Pokémon is levitating. This is used for moves like Magnet Rise, and abilities such as
|
/// Whether the Pokémon is levitating. This is used for moves like Magnet Rise, and abilities such as
|
||||||
@ -1197,8 +1197,10 @@ public class PokemonImpl : ScriptSource, IPokemon
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void ChangeAbility(IAbility ability)
|
public bool ChangeAbility(IAbility ability)
|
||||||
{
|
{
|
||||||
|
if (!ability.CanBeChanged)
|
||||||
|
return false;
|
||||||
OverrideAbility = ability;
|
OverrideAbility = ability;
|
||||||
if (Library.ScriptResolver.TryResolve(ScriptCategory.Ability, ability.Name, ability.Parameters,
|
if (Library.ScriptResolver.TryResolve(ScriptCategory.Ability, ability.Name, ability.Parameters,
|
||||||
out var abilityScript))
|
out var abilityScript))
|
||||||
@ -1210,6 +1212,7 @@ public class PokemonImpl : ScriptSource, IPokemon
|
|||||||
{
|
{
|
||||||
AbilityScript.Clear();
|
AbilityScript.Clear();
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -546,6 +546,13 @@ public abstract class Script : IDeepCloneable
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This function is triggered on a Pokemon and its parents when an opponent switches in.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void OnOpponentSwitchIn(IPokemon pokemon, byte position)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This function is triggered on a Pokemon and its parents when the given Pokemon consumes the
|
/// This function is triggered on a Pokemon and its parents when the given Pokemon consumes the
|
||||||
/// held item it had.
|
/// held item it had.
|
||||||
|
@ -34,10 +34,7 @@ public class ScriptResolver
|
|||||||
}
|
}
|
||||||
|
|
||||||
script = scriptCtor();
|
script = scriptCtor();
|
||||||
if (parameters != null)
|
script.OnInitialize(parameters);
|
||||||
{
|
|
||||||
script.OnInitialize(parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,8 @@ public interface IAbility : INamedValue
|
|||||||
/// Checks whether the ability has a specific flag.
|
/// Checks whether the ability has a specific flag.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool HasFlag(StringKey key);
|
bool HasFlag(StringKey key);
|
||||||
|
|
||||||
|
bool CanBeChanged { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -30,12 +32,13 @@ public class AbilityImpl : IAbility
|
|||||||
{
|
{
|
||||||
/// <inheritdoc cref="AbilityImpl" />
|
/// <inheritdoc cref="AbilityImpl" />
|
||||||
public AbilityImpl(StringKey name, StringKey? effect, IReadOnlyDictionary<StringKey, object?> parameters,
|
public AbilityImpl(StringKey name, StringKey? effect, IReadOnlyDictionary<StringKey, object?> parameters,
|
||||||
ImmutableHashSet<StringKey> flags)
|
ImmutableHashSet<StringKey> flags, bool canBeChanged)
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
Effect = effect;
|
Effect = effect;
|
||||||
Parameters = parameters;
|
Parameters = parameters;
|
||||||
Flags = flags;
|
Flags = flags;
|
||||||
|
CanBeChanged = canBeChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -54,6 +57,9 @@ public class AbilityImpl : IAbility
|
|||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool HasFlag(StringKey key) => Flags.Contains(key);
|
public bool HasFlag(StringKey key) => Flags.Contains(key);
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool CanBeChanged { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -5,6 +5,12 @@ namespace PkmnLib.Static.Utils;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static class NumericHelpers
|
public static class NumericHelpers
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if two floating-point values are approximately equal within a specified tolerance.
|
||||||
|
/// </summary>
|
||||||
|
public static bool IsApproximatelyEqualTo(this float value, float other, float tolerance = 0.0001f) =>
|
||||||
|
MathF.Abs(value - other) <= tolerance;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Multiplies two values. If this overflows, returns <see cref="byte.MaxValue"/>.
|
/// Multiplies two values. If this overflows, returns <see cref="byte.MaxValue"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
using PkmnLib.Dynamic.Libraries;
|
||||||
|
using PkmnLib.Dynamic.ScriptHandling;
|
||||||
|
using PkmnLib.Static.Species;
|
||||||
|
|
||||||
|
namespace PkmnLib.Plugin.Gen7.Tests.DataTests;
|
||||||
|
|
||||||
|
public class AbilityDataTests
|
||||||
|
{
|
||||||
|
public record TestCaseData(IDynamicLibrary Library, IAbility Ability)
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString() => Ability.Name + " has valid scripts";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<Func<TestCaseData>> AllAbilitiesHaveValidScriptsData()
|
||||||
|
{
|
||||||
|
var library = LibraryHelpers.LoadLibrary();
|
||||||
|
var abilityLibrary = library.StaticLibrary.Abilities;
|
||||||
|
foreach (var ability in abilityLibrary)
|
||||||
|
{
|
||||||
|
if (ability.Effect is null)
|
||||||
|
continue;
|
||||||
|
yield return () => new TestCaseData(library, ability);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test, MethodDataSource(nameof(AllAbilitiesHaveValidScriptsData)), Explicit]
|
||||||
|
public async Task AllAbilitiesEffectsHaveValidScripts(TestCaseData test)
|
||||||
|
{
|
||||||
|
var scriptName = test.Ability.Effect;
|
||||||
|
if (scriptName is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Assert.That(test.Library.ScriptResolver.TryResolve(ScriptCategory.Ability, scriptName.Value,
|
||||||
|
test.Ability.Parameters, out _)).IsTrue();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
// Helper method to find the line number of the effect in the JSON file
|
||||||
|
var file = Path.GetFullPath("../../../../Plugins/PkmnLib.Plugin.Gen7/Data/Abilities.json");
|
||||||
|
var json = await File.ReadAllLinesAsync(file);
|
||||||
|
var moveLineNumber = json.Select((line, index) => new { line, index })
|
||||||
|
.FirstOrDefault(x => x.line.Contains($"\"name\": \"{test.Ability.Effect}\""))?.index + 1;
|
||||||
|
var effectLineNumber = moveLineNumber + json.Skip(moveLineNumber ?? 0)
|
||||||
|
.Select((line, index) => new { line, index }).FirstOrDefault(x => x.line.Contains("effect"))
|
||||||
|
?.index +
|
||||||
|
1 ?? 0;
|
||||||
|
|
||||||
|
await TestContext.Current!.OutputWriter.WriteLineAsync("File: " + $"file://{file}:{effectLineNumber}");
|
||||||
|
throw new AggregateException($"Failed to resolve script for move {test.Ability} with effect {scriptName}",
|
||||||
|
e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,68 +1,75 @@
|
|||||||
{
|
{
|
||||||
"adaptability": {
|
"adaptability": {
|
||||||
"effect": "IncreasedStab"
|
"effect": "increased_stab"
|
||||||
},
|
},
|
||||||
"aerilate": {
|
"aerilate": {
|
||||||
"effect": "ChangeMoveType",
|
"effect": "change_move_type",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"from": "normal",
|
"from_type": "normal",
|
||||||
"to": "flying"
|
"to_type": "flying"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"aftermath": {
|
"aftermath": {
|
||||||
"effect": "Aftermath"
|
"effect": "aftermath"
|
||||||
},
|
},
|
||||||
"air_lock": {
|
"air_lock": {
|
||||||
"effect": "SuppressWeather"
|
"effect": "suppress_weather"
|
||||||
},
|
},
|
||||||
"analytic": {
|
"analytic": {
|
||||||
"effect": "Analytic"
|
"effect": "analytic"
|
||||||
},
|
},
|
||||||
"anger_point": {
|
"anger_point": {
|
||||||
"effect": "AngerPoint"
|
"effect": "anger_point"
|
||||||
},
|
},
|
||||||
"anticipation": {
|
"anticipation": {
|
||||||
"effect": "Anticipation"
|
"effect": "anticipation"
|
||||||
},
|
},
|
||||||
"arena_trap": {
|
"arena_trap": {
|
||||||
"effect": "ArenaTrap"
|
"effect": "arena_trap"
|
||||||
},
|
},
|
||||||
"aroma_veil": {
|
"aroma_veil": {
|
||||||
"effect": "AromaVeil"
|
"effect": "aroma_veil"
|
||||||
},
|
},
|
||||||
"aura_break": {
|
"aura_break": {
|
||||||
"effect": "AuraBreal"
|
"effect": "aura_break"
|
||||||
},
|
},
|
||||||
"bad_dreams": {
|
"bad_dreams": {
|
||||||
"effect": "BadDreams"
|
"effect": "bad_dreams"
|
||||||
},
|
},
|
||||||
"battery": {
|
"battery": {
|
||||||
"effect": "Battery"
|
"effect": "battery"
|
||||||
},
|
},
|
||||||
"battle_armor": {
|
"battle_armor": {
|
||||||
"effect": "PreventCritical"
|
"effect": "prevent_critical"
|
||||||
},
|
},
|
||||||
"battle_bond": {
|
"battle_bond": {
|
||||||
"effect": "BattleBond",
|
"effect": "battle_bond",
|
||||||
"flags": ["cant_be_changed"]
|
"canBeChanged": false,
|
||||||
|
"flags": [
|
||||||
|
"cant_be_copied"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"beast_boost": {
|
"beast_boost": {
|
||||||
"effect": "BeastBoost"
|
"effect": "beast_boost"
|
||||||
},
|
},
|
||||||
"berserk": {
|
"berserk": {
|
||||||
"effect": "Berserk"
|
"effect": "berserk"
|
||||||
},
|
},
|
||||||
"big_pecks": {
|
"big_pecks": {
|
||||||
"effect": "PreventDefLowering"
|
"effect": "prevent_stat_lowering",
|
||||||
|
"parameters": {
|
||||||
|
"stat": "defense"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"blaze": {
|
"blaze": {
|
||||||
"effect": "PowerUpType",
|
"effect": "power_up_type_at_low_health",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"type": "fire"
|
"type": "fire",
|
||||||
|
"threshold": 0.33333
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"bulletproof": {
|
"bulletproof": {
|
||||||
"effect": "Bulletproof"
|
"effect": "bulletproof"
|
||||||
},
|
},
|
||||||
"cheek_pouch": {
|
"cheek_pouch": {
|
||||||
"effect": "CheekPouch"
|
"effect": "CheekPouch"
|
||||||
@ -83,7 +90,7 @@
|
|||||||
"effect": "ColorChange"
|
"effect": "ColorChange"
|
||||||
},
|
},
|
||||||
"comatose": {
|
"comatose": {
|
||||||
"flags": ["cant_be_changed"]
|
"canBeChanged": false
|
||||||
},
|
},
|
||||||
"competitive": {},
|
"competitive": {},
|
||||||
"compound_eyes": {},
|
"compound_eyes": {},
|
||||||
@ -100,7 +107,10 @@
|
|||||||
"delta_stream": {},
|
"delta_stream": {},
|
||||||
"desolate_land": {},
|
"desolate_land": {},
|
||||||
"disguise": {
|
"disguise": {
|
||||||
"flags": ["cant_be_changed", "cant_be_copied"]
|
"canBeChanged": false,
|
||||||
|
"flags": [
|
||||||
|
"cant_be_copied"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"download": {},
|
"download": {},
|
||||||
"drizzle": {},
|
"drizzle": {},
|
||||||
@ -116,12 +126,16 @@
|
|||||||
"flare_boost": {},
|
"flare_boost": {},
|
||||||
"flash_fire": {},
|
"flash_fire": {},
|
||||||
"flower_gift": {
|
"flower_gift": {
|
||||||
"flags": ["cant_be_copied"]
|
"flags": [
|
||||||
|
"cant_be_copied"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"flower_veil": {},
|
"flower_veil": {},
|
||||||
"fluffy": {},
|
"fluffy": {},
|
||||||
"forecast": {
|
"forecast": {
|
||||||
"flags": ["cant_be_copied"]
|
"flags": [
|
||||||
|
"cant_be_copied"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"forewarn": {},
|
"forewarn": {},
|
||||||
"friend_guard": {},
|
"friend_guard": {},
|
||||||
@ -147,11 +161,15 @@
|
|||||||
"ice_body": {},
|
"ice_body": {},
|
||||||
"illuminate": {},
|
"illuminate": {},
|
||||||
"illusion": {
|
"illusion": {
|
||||||
"flags": ["cant_be_copied"]
|
"flags": [
|
||||||
|
"cant_be_copied"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"immunity": {},
|
"immunity": {},
|
||||||
"imposter": {
|
"imposter": {
|
||||||
"flags": ["cant_be_copied"]
|
"flags": [
|
||||||
|
"cant_be_copied"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"infiltrator": {},
|
"infiltrator": {},
|
||||||
"innards_out": {},
|
"innards_out": {},
|
||||||
@ -187,7 +205,7 @@
|
|||||||
"moxie": {},
|
"moxie": {},
|
||||||
"multiscale": {},
|
"multiscale": {},
|
||||||
"multitype": {
|
"multitype": {
|
||||||
"flags": ["cant_be_changed"]
|
"canBeChanged": false
|
||||||
},
|
},
|
||||||
"mummy": {},
|
"mummy": {},
|
||||||
"natural_cure": {},
|
"natural_cure": {},
|
||||||
@ -206,10 +224,15 @@
|
|||||||
"poison_point": {},
|
"poison_point": {},
|
||||||
"poison_touch": {},
|
"poison_touch": {},
|
||||||
"power_construct": {
|
"power_construct": {
|
||||||
"flags": ["cant_be_changed", "cant_be_copied"]
|
"canBeChanged": false,
|
||||||
|
"flags": [
|
||||||
|
"cant_be_copied"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"power_of_alchemy": {
|
"power_of_alchemy": {
|
||||||
"flags": ["cant_be_copied"]
|
"flags": [
|
||||||
|
"cant_be_copied"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"prankster": {},
|
"prankster": {},
|
||||||
"pressure": {},
|
"pressure": {},
|
||||||
@ -223,14 +246,16 @@
|
|||||||
"rain_dish": {},
|
"rain_dish": {},
|
||||||
"rattled": {},
|
"rattled": {},
|
||||||
"receiver": {
|
"receiver": {
|
||||||
"flags": ["cant_be_copied"]
|
"flags": [
|
||||||
|
"cant_be_copied"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"reckless": {},
|
"reckless": {},
|
||||||
"refrigerate": {},
|
"refrigerate": {},
|
||||||
"regenerator": {},
|
"regenerator": {},
|
||||||
"rivalry": {},
|
"rivalry": {},
|
||||||
"rks_system": {
|
"rks_system": {
|
||||||
"flags": ["cant_be_changed"]
|
"canBeChanged": false
|
||||||
},
|
},
|
||||||
"rock_head": {},
|
"rock_head": {},
|
||||||
"rough_skin": {},
|
"rough_skin": {},
|
||||||
@ -241,7 +266,7 @@
|
|||||||
"sand_veil": {},
|
"sand_veil": {},
|
||||||
"sap_sipper": {},
|
"sap_sipper": {},
|
||||||
"schooling": {
|
"schooling": {
|
||||||
"flags": ["cant_be_changed"]
|
"canBeChanged": false
|
||||||
},
|
},
|
||||||
"scrappy": {},
|
"scrappy": {},
|
||||||
"serene_grace": {},
|
"serene_grace": {},
|
||||||
@ -252,7 +277,7 @@
|
|||||||
"shell_armor": {},
|
"shell_armor": {},
|
||||||
"shield_dust": {},
|
"shield_dust": {},
|
||||||
"shields_down": {
|
"shields_down": {
|
||||||
"flags": ["cant_be_changed"]
|
"canBeChanged": false
|
||||||
},
|
},
|
||||||
"simple": {},
|
"simple": {},
|
||||||
"skill_link": {},
|
"skill_link": {},
|
||||||
@ -270,7 +295,7 @@
|
|||||||
"stall": {},
|
"stall": {},
|
||||||
"stamina": {},
|
"stamina": {},
|
||||||
"stance_change": {
|
"stance_change": {
|
||||||
"flags": ["cant_be_changed"]
|
"canBeChanged": false
|
||||||
},
|
},
|
||||||
"static": {},
|
"static": {},
|
||||||
"steadfast": {},
|
"steadfast": {},
|
||||||
@ -299,11 +324,13 @@
|
|||||||
"tough_claws": {},
|
"tough_claws": {},
|
||||||
"toxic_boost": {},
|
"toxic_boost": {},
|
||||||
"trace": {
|
"trace": {
|
||||||
"flags": ["cant_be_copied"]
|
"flags": [
|
||||||
|
"cant_be_copied"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"triage": {},
|
"triage": {},
|
||||||
"truant": {
|
"truant": {
|
||||||
"flags": ["cant_be_changed"]
|
"canBeChanged": false
|
||||||
},
|
},
|
||||||
"turboblaze": {},
|
"turboblaze": {},
|
||||||
"unaware": {},
|
"unaware": {},
|
||||||
@ -322,6 +349,8 @@
|
|||||||
"wonder_guard": {},
|
"wonder_guard": {},
|
||||||
"wonder_skin": {},
|
"wonder_skin": {},
|
||||||
"zen_mode": {
|
"zen_mode": {
|
||||||
"flags": ["cant_be_copied"]
|
"flags": [
|
||||||
|
"cant_be_copied"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
33
Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Aftermath.cs
Normal file
33
Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Aftermath.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Ability, "aftermath")]
|
||||||
|
public class Aftermath : Script
|
||||||
|
{
|
||||||
|
private IExecutingMove? _lastAttack;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnIncomingHit(IExecutingMove move, IPokemon target, byte hit)
|
||||||
|
{
|
||||||
|
_lastAttack = move;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnFaint(IPokemon pokemon, DamageSource source)
|
||||||
|
{
|
||||||
|
if (source != DamageSource.MoveDamage)
|
||||||
|
return;
|
||||||
|
if (_lastAttack is null || !_lastAttack.UseMove.HasFlag("contact"))
|
||||||
|
return;
|
||||||
|
var user = _lastAttack.User;
|
||||||
|
if (!user.IsUsable)
|
||||||
|
return;
|
||||||
|
if (user.BattleData is null)
|
||||||
|
return;
|
||||||
|
EventBatchId eventBatchId = new();
|
||||||
|
user.BattleData.Battle.EventHook.Invoke(new AbilityTriggerEvent(pokemon)
|
||||||
|
{
|
||||||
|
BatchId = eventBatchId,
|
||||||
|
});
|
||||||
|
user.Damage(user.MaxHealth / 4, DamageSource.Misc, eventBatchId);
|
||||||
|
}
|
||||||
|
}
|
15
Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Analytic.cs
Normal file
15
Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Analytic.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Ability, "analytic")]
|
||||||
|
public class Analytic : Script
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void ChangeDamageModifier(IExecutingMove move, IPokemon target, byte hit, ref float modifier)
|
||||||
|
{
|
||||||
|
if (move.Battle.ChoiceQueue?.HasNext() == false)
|
||||||
|
{
|
||||||
|
move.Battle.EventHook.Invoke(new AbilityTriggerEvent(move.User));
|
||||||
|
modifier *= 1.3f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/AngerPoint.cs
Normal file
19
Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/AngerPoint.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Ability, "anger_point")]
|
||||||
|
public class AngerPoint : Script
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnIncomingHit(IExecutingMove move, IPokemon target, byte hit)
|
||||||
|
{
|
||||||
|
if (move.GetHitData(target, hit).IsCritical)
|
||||||
|
{
|
||||||
|
EventBatchId batchId = new();
|
||||||
|
move.Battle.EventHook.Invoke(new AbilityTriggerEvent(target)
|
||||||
|
{
|
||||||
|
BatchId = batchId,
|
||||||
|
});
|
||||||
|
target.ChangeStatBoost(Statistic.Attack, 12, true, batchId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
using PkmnLib.Static.Utils;
|
||||||
|
|
||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Ability, "anticipation")]
|
||||||
|
public class Anticipation : Script
|
||||||
|
{
|
||||||
|
private IPokemon? _owner;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnAddedToParent(IScriptSource source)
|
||||||
|
{
|
||||||
|
if (source is not IPokemon pokemon)
|
||||||
|
throw new ArgumentException("Anticipation script can only be added to a Pokemon.", nameof(source));
|
||||||
|
_owner = pokemon;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnOpponentSwitchIn(IPokemon pokemon, byte position)
|
||||||
|
{
|
||||||
|
if (_owner is null)
|
||||||
|
return;
|
||||||
|
var pokemonMoves = pokemon.Moves.WhereNotNull();
|
||||||
|
var typeLibrary = pokemon.Library.StaticLibrary.Types;
|
||||||
|
var relevantMoves = pokemonMoves.Any(move =>
|
||||||
|
// Either the move is super effective against the owner or
|
||||||
|
typeLibrary.GetEffectiveness(move.MoveData.MoveType, _owner.Types) > 1.0f ||
|
||||||
|
// the move is a OHKO move
|
||||||
|
move.MoveData.SecondaryEffect?.Name == "one_hit_ko" ||
|
||||||
|
// the move is a self-destruct move
|
||||||
|
move.MoveData.SecondaryEffect?.Name == "self_destruct" ||
|
||||||
|
move.MoveData.SecondaryEffect?.Name == "explosion");
|
||||||
|
|
||||||
|
if (relevantMoves)
|
||||||
|
{
|
||||||
|
pokemon.BattleData?.Battle.EventHook.Invoke(new AbilityTriggerEvent(_owner));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ArenaTrap.cs
Normal file
35
Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/ArenaTrap.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Ability, "arena_trap")]
|
||||||
|
public class ArenaTrap : Script
|
||||||
|
{
|
||||||
|
private IPokemon? _owner;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnAddedToParent(IScriptSource source)
|
||||||
|
{
|
||||||
|
if (source is not IPokemon pokemon)
|
||||||
|
throw new InvalidOperationException("ArenaTrap can only be added to a Pokemon.");
|
||||||
|
_owner = pokemon;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void PreventOpponentRunAway(IFleeChoice choice, ref bool prevent)
|
||||||
|
{
|
||||||
|
if (choice.User.IsFloating)
|
||||||
|
return;
|
||||||
|
if (_owner is not null)
|
||||||
|
choice.User.BattleData?.Battle.EventHook.Invoke(new AbilityTriggerEvent(_owner));
|
||||||
|
prevent = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void PreventOpponentSwitch(ISwitchChoice choice, ref bool prevent)
|
||||||
|
{
|
||||||
|
if (choice.User.IsFloating)
|
||||||
|
return;
|
||||||
|
if (_owner is not null)
|
||||||
|
choice.User.BattleData?.Battle.EventHook.Invoke(new AbilityTriggerEvent(_owner));
|
||||||
|
prevent = true;
|
||||||
|
}
|
||||||
|
}
|
21
Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/AromaVeil.cs
Normal file
21
Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/AromaVeil.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Ability, "aroma_veil")]
|
||||||
|
public class AromaVeil : Script
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnSwitchIn(IPokemon pokemon, byte position)
|
||||||
|
{
|
||||||
|
var side = pokemon.BattleData?.BattleSide;
|
||||||
|
var effect = side?.VolatileScripts.Add(new Side.AromaVeilEffect())?.Script as Side.AromaVeilEffect;
|
||||||
|
effect?.PlacerActivated(pokemon);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnSwitchOut(IPokemon oldPokemon, byte position)
|
||||||
|
{
|
||||||
|
var side = oldPokemon.BattleData?.BattleSide;
|
||||||
|
var effect = side?.VolatileScripts.Get<Side.AromaVeilEffect>();
|
||||||
|
effect?.PlacerDeactivated(oldPokemon);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Ability, "aura_break")]
|
||||||
|
public class AuraBreak : Script
|
||||||
|
{
|
||||||
|
// FIXME: Implement together with Dark Aura and Fairy Aura.
|
||||||
|
}
|
35
Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/BadDreams.cs
Normal file
35
Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/BadDreams.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
using PkmnLib.Static.Utils;
|
||||||
|
|
||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Ability, "bad_dreams")]
|
||||||
|
public class BadDreams : Script
|
||||||
|
{
|
||||||
|
private IPokemon? _owner;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnAddedToParent(IScriptSource source)
|
||||||
|
{
|
||||||
|
if (source is not IPokemon pokemon)
|
||||||
|
throw new InvalidOperationException("Bad Dreams ability can only be added to a Pokemon.");
|
||||||
|
_owner = pokemon;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnEndTurn(IBattle battle)
|
||||||
|
{
|
||||||
|
if (_owner is null)
|
||||||
|
return;
|
||||||
|
var opponents = battle.Sides.Where(x => x != _owner?.BattleData?.BattleSide).SelectMany(x => x.Pokemon)
|
||||||
|
.WhereNotNull();
|
||||||
|
|
||||||
|
foreach (var opponent in opponents)
|
||||||
|
{
|
||||||
|
if (!opponent.HasStatus(ScriptUtils.ResolveName<Status.Sleep>()))
|
||||||
|
continue;
|
||||||
|
EventBatchId batchId = new();
|
||||||
|
battle.EventHook.Invoke(new AbilityTriggerEvent(_owner));
|
||||||
|
opponent.Damage(opponent.MaxHealth / 8, DamageSource.Misc, batchId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Battery.cs
Normal file
21
Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Battery.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Ability, "battery")]
|
||||||
|
public class Battery : Script
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnSwitchIn(IPokemon pokemon, byte position)
|
||||||
|
{
|
||||||
|
var side = pokemon.BattleData?.BattleSide;
|
||||||
|
var effect = side?.VolatileScripts.Add(new Side.BatteryAbilityEffect())?.Script as Side.BatteryAbilityEffect;
|
||||||
|
effect?.PlacerActivated(pokemon);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnSwitchOut(IPokemon oldPokemon, byte position)
|
||||||
|
{
|
||||||
|
var side = oldPokemon.BattleData?.BattleSide;
|
||||||
|
var effect = side?.VolatileScripts.Get<Side.BatteryAbilityEffect>();
|
||||||
|
effect?.PlacerDeactivated(oldPokemon);
|
||||||
|
}
|
||||||
|
}
|
32
Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/BattleBond.cs
Normal file
32
Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/BattleBond.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Ability, "battle_bond")]
|
||||||
|
public class BattleBond : Script
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnOpponentFaints(IExecutingMove move, IPokemon target, byte hit)
|
||||||
|
{
|
||||||
|
if (move.User.Species.Name == "greninja" && move.User.Form.Name != "ash" &&
|
||||||
|
move.User.Species.TryGetForm("ash", out var ashForm))
|
||||||
|
{
|
||||||
|
move.User.BattleData?.Battle.EventHook.Invoke(new AbilityTriggerEvent(move.User));
|
||||||
|
move.User.ChangeForm(ashForm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref ushort basePower)
|
||||||
|
{
|
||||||
|
if (move.UseMove.Name == "water_shuriken" && move.User.Form.Name == "ash")
|
||||||
|
basePower = 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void ChangeNumberOfHits(IMoveChoice choice, ref byte numberOfHits)
|
||||||
|
{
|
||||||
|
if (choice.ChosenMove.MoveData.Name == "water_shuriken" && choice.User.Form.Name == "ash")
|
||||||
|
{
|
||||||
|
numberOfHits = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/BeastBoost.cs
Normal file
17
Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/BeastBoost.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Ability, "beast_boost")]
|
||||||
|
public class BeastBoost : Script
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnOpponentFaints(IExecutingMove move, IPokemon target, byte hit)
|
||||||
|
{
|
||||||
|
var highestStat = move.User.BoostedStats.OrderByDescending(x => x.value).First().statistic;
|
||||||
|
EventBatchId batchId = new();
|
||||||
|
move.User.BattleData?.Battle.EventHook.Invoke(new AbilityTriggerEvent(move.User)
|
||||||
|
{
|
||||||
|
BatchId = batchId,
|
||||||
|
});
|
||||||
|
move.User.ChangeStatBoost(highestStat, 1, true, batchId);
|
||||||
|
}
|
||||||
|
}
|
21
Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Berserk.cs
Normal file
21
Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Berserk.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Ability, "berserk")]
|
||||||
|
public class Berserk : Script
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnDamage(IPokemon pokemon, DamageSource source, uint oldHealth, uint newHealth)
|
||||||
|
{
|
||||||
|
if (source is not DamageSource.MoveDamage)
|
||||||
|
return;
|
||||||
|
if (oldHealth > pokemon.MaxHealth / 2 || newHealth > pokemon.MaxHealth / 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
EventBatchId batchId = new();
|
||||||
|
pokemon.BattleData?.Battle.EventHook.Invoke(new AbilityTriggerEvent(pokemon)
|
||||||
|
{
|
||||||
|
BatchId = batchId,
|
||||||
|
});
|
||||||
|
pokemon.ChangeStatBoost(Statistic.SpecialAttack, 1, true, batchId);
|
||||||
|
}
|
||||||
|
}
|
12
Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Bulletproof.cs
Normal file
12
Plugins/PkmnLib.Plugin.Gen7/Scripts/Abilities/Bulletproof.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Ability, "bulletproof")]
|
||||||
|
public class Bulletproof : Script
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void FailIncomingMove(IExecutingMove move, IPokemon target, ref bool fail)
|
||||||
|
{
|
||||||
|
if (move.UseMove.HasFlag("ballistics"))
|
||||||
|
fail = true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
using PkmnLib.Static.Utils;
|
||||||
|
|
||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Ability, "change_move_type")]
|
||||||
|
public class ChangeMoveTypeAbility : Script
|
||||||
|
{
|
||||||
|
private StringKey _fromType;
|
||||||
|
private StringKey _toType;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnInitialize(IReadOnlyDictionary<StringKey, object?>? parameters)
|
||||||
|
{
|
||||||
|
if (parameters == null)
|
||||||
|
throw new ArgumentNullException(nameof(parameters));
|
||||||
|
|
||||||
|
if (!parameters.TryGetValue("from_type", out var fromTypeObj) || fromTypeObj is not string fromType)
|
||||||
|
throw new ArgumentException("Missing 'from_type' parameter.", nameof(parameters));
|
||||||
|
if (!parameters.TryGetValue("to_type", out var toTypeObj) || toTypeObj is not string toType)
|
||||||
|
throw new ArgumentException("Missing 'to_type' parameter.", nameof(parameters));
|
||||||
|
_fromType = fromType;
|
||||||
|
_toType = toType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit,
|
||||||
|
ref TypeIdentifier? typeIdentifier)
|
||||||
|
{
|
||||||
|
var typeLibrary = target.Library.StaticLibrary.Types;
|
||||||
|
// Both types must be valid and the current type must match the from type
|
||||||
|
if (!typeLibrary.TryGetTypeIdentifier(_fromType, out var fromType) ||
|
||||||
|
!typeLibrary.TryGetTypeIdentifier(_toType, out var toType) || typeIdentifier != fromType)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
move.Battle.EventHook.Invoke(new AbilityTriggerEvent(move.User));
|
||||||
|
typeIdentifier = toType;
|
||||||
|
move.GetHitData(target, hit).SetFlag("change_move_type_ability");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref ushort basePower)
|
||||||
|
{
|
||||||
|
if (move.GetHitData(target, hit).HasFlag("change_move_type_ability"))
|
||||||
|
basePower = basePower.MultiplyOrMax(1.3f);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
using PkmnLib.Static.Utils;
|
||||||
|
|
||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Ability, "increased_stab")]
|
||||||
|
public class IncreasedStab : Script
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void ChangeStabModifier(IExecutingMove executingMove, IPokemon target, byte hitNumber,
|
||||||
|
ref float modifier)
|
||||||
|
{
|
||||||
|
if (modifier.IsApproximatelyEqualTo(1.5f))
|
||||||
|
{
|
||||||
|
executingMove.Battle.EventHook.Invoke(new AbilityTriggerEvent(executingMove.User));
|
||||||
|
modifier = 2.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
using PkmnLib.Static.Utils;
|
||||||
|
|
||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Ability, "power_up_type_at_low_health")]
|
||||||
|
public class PowerUpTypeAtLowHealth : Script
|
||||||
|
{
|
||||||
|
private StringKey _type;
|
||||||
|
private float _threshold;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnInitialize(IReadOnlyDictionary<StringKey, object?>? parameters)
|
||||||
|
{
|
||||||
|
if (parameters == null)
|
||||||
|
throw new ArgumentNullException(nameof(parameters));
|
||||||
|
|
||||||
|
if (!parameters.TryGetValue("type", out var type) || type is not string typeName)
|
||||||
|
throw new ArgumentException("Parameter 'type' is required and must be a string.", nameof(parameters));
|
||||||
|
if (!parameters.TryGetValue("threshold", out var threshold) || threshold is not float thresholdValue)
|
||||||
|
throw new ArgumentException("Parameter 'threshold' is required and must be a float.", nameof(parameters));
|
||||||
|
|
||||||
|
if (thresholdValue < 0 || thresholdValue > 1)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(threshold), "Threshold must be between 0 and 1.");
|
||||||
|
|
||||||
|
_type = typeName;
|
||||||
|
_threshold = thresholdValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void ChangeDamageModifier(IExecutingMove move, IPokemon target, byte hit, ref float modifier)
|
||||||
|
{
|
||||||
|
var currentHealthFraction = move.User.CurrentHealth / (float)move.User.MaxHealth;
|
||||||
|
if (currentHealthFraction <= _threshold && move.GetHitData(target, hit).Type?.Name == _type)
|
||||||
|
{
|
||||||
|
modifier *= 1.5f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Ability, "prevent_critical")]
|
||||||
|
public class PreventCritical : Script
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void BlockIncomingCriticalHit(IExecutingMove move, IPokemon target, byte hit, ref bool block) =>
|
||||||
|
block = true;
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
using PkmnLib.Static.Utils;
|
||||||
|
|
||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Ability, "prevent_stat_lowering")]
|
||||||
|
public class PreventStatLowering : Script
|
||||||
|
{
|
||||||
|
private Statistic _statistic;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnInitialize(IReadOnlyDictionary<StringKey, object?>? parameters)
|
||||||
|
{
|
||||||
|
if (parameters is null)
|
||||||
|
throw new ArgumentNullException(nameof(parameters), "Parameters cannot be null.");
|
||||||
|
if (!parameters.TryGetValue("stat", out var statObj) || statObj is not string statStr)
|
||||||
|
throw new ArgumentException("Parameter 'stat' is required and must be a string.", nameof(parameters));
|
||||||
|
if (!Enum.TryParse(statStr, true, out Statistic stat))
|
||||||
|
throw new ArgumentException($"Invalid statistic '{statStr}' provided.", nameof(statStr));
|
||||||
|
|
||||||
|
_statistic = stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void PreventStatBoostChange(IPokemon target, Statistic stat, sbyte amount, bool selfInflicted,
|
||||||
|
ref bool prevent)
|
||||||
|
{
|
||||||
|
if (!selfInflicted)
|
||||||
|
prevent = false;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Ability, "suppress_weather")]
|
||||||
|
public class SuppressWeatherAbility : Script
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnBeforeAnyHookInvoked(ref List<ScriptCategory>? suppressedCategories)
|
||||||
|
{
|
||||||
|
suppressedCategories ??= [];
|
||||||
|
suppressedCategories.Add(ScriptCategory.Weather);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnSwitchIn(IPokemon pokemon, byte position)
|
||||||
|
{
|
||||||
|
pokemon.BattleData?.Battle.EventHook.Invoke(new AbilityTriggerEvent(pokemon));
|
||||||
|
}
|
||||||
|
}
|
32
Plugins/PkmnLib.Plugin.Gen7/Scripts/Side/AromaVeilEffect.cs
Normal file
32
Plugins/PkmnLib.Plugin.Gen7/Scripts/Side/AromaVeilEffect.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
using PkmnLib.Static.Moves;
|
||||||
|
|
||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Side;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Side, "aroma_veil")]
|
||||||
|
public class AromaVeilEffect : Script
|
||||||
|
{
|
||||||
|
private HashSet<IPokemon> _placers = new();
|
||||||
|
|
||||||
|
public void PlacerActivated(IPokemon placer) => _placers.Add(placer);
|
||||||
|
|
||||||
|
public void PlacerDeactivated(IPokemon placer)
|
||||||
|
{
|
||||||
|
_placers.Remove(placer);
|
||||||
|
if (_placers.Count == 0)
|
||||||
|
RemoveSelf();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void FailIncomingMove(IExecutingMove move, IPokemon target, ref bool fail)
|
||||||
|
{
|
||||||
|
if (move.UseMove.HasFlag("mental") && move.UseMove.Category == MoveCategory.Status)
|
||||||
|
fail = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void PreventSecondaryEffect(IExecutingMove move, IPokemon target, byte hit, ref bool prevent)
|
||||||
|
{
|
||||||
|
if (move.UseMove.HasFlag("mental"))
|
||||||
|
prevent = true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
using PkmnLib.Static.Moves;
|
||||||
|
|
||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Side;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Side, "battery")]
|
||||||
|
public class BatteryAbilityEffect : Script
|
||||||
|
{
|
||||||
|
private HashSet<IPokemon> _placers = new();
|
||||||
|
|
||||||
|
public void PlacerActivated(IPokemon placer) => _placers.Add(placer);
|
||||||
|
|
||||||
|
public void PlacerDeactivated(IPokemon placer)
|
||||||
|
{
|
||||||
|
_placers.Remove(placer);
|
||||||
|
if (_placers.Count == 0)
|
||||||
|
RemoveSelf();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void ChangeDamageModifier(IExecutingMove move, IPokemon target, byte hit, ref float modifier)
|
||||||
|
{
|
||||||
|
if (move.UseMove.Category == MoveCategory.Special)
|
||||||
|
{
|
||||||
|
modifier *= 5325f / 4096f; // ~1.3x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user