More move scripts
This commit is contained in:
parent
f8c43b6ba0
commit
1973ff50fa
@ -10,7 +10,7 @@
|
||||
"rollForward": false
|
||||
},
|
||||
"jetbrains.resharper.globaltools": {
|
||||
"version": "2024.3.6",
|
||||
"version": "2025.1.1",
|
||||
"commands": [
|
||||
"jb"
|
||||
],
|
||||
|
@ -4,6 +4,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<WarningsAsErrors>nullable</WarningsAsErrors>
|
||||
<UseArtifactsOutput>true</UseArtifactsOutput>
|
||||
</PropertyGroup>
|
||||
|
||||
|
@ -172,6 +172,7 @@ public class BattleImpl : ScriptSource, IBattle
|
||||
CanFlee = canFlee;
|
||||
NumberOfSides = numberOfSides;
|
||||
PositionsPerSide = positionsPerSide;
|
||||
Volatile = new ScriptSet(this);
|
||||
var sides = new IBattleSide[numberOfSides];
|
||||
for (byte i = 0; i < numberOfSides; i++)
|
||||
sides[i] = new BattleSideImpl(i, positionsPerSide, this);
|
||||
@ -399,7 +400,7 @@ public class BattleImpl : ScriptSource, IBattle
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IScriptSet Volatile { get; } = new ScriptSet();
|
||||
public IScriptSet Volatile { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public StringKey? WeatherName => WeatherScript.Script?.Name;
|
||||
|
@ -132,6 +132,9 @@ public class BattleChoiceQueue : IDeepCloneable
|
||||
public ITurnChoice? FirstOrDefault(Func<ITurnChoice, bool> predicate) =>
|
||||
_choices.Skip(_currentIndex).WhereNotNull().FirstOrDefault(predicate);
|
||||
|
||||
public IEnumerable<ITurnChoice> Where(Func<ITurnChoice, bool> predicate) =>
|
||||
_choices.Skip(_currentIndex).WhereNotNull().Where(predicate);
|
||||
|
||||
/// <summary>
|
||||
/// Removes a choice from the queue.
|
||||
/// </summary>
|
||||
|
@ -174,7 +174,7 @@ public class BattleSideImpl : ScriptSource, IBattleSide
|
||||
_fillablePositions[i] = true;
|
||||
}
|
||||
Battle = battle;
|
||||
VolatileScripts = new ScriptSet();
|
||||
VolatileScripts = new ScriptSet(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
@ -55,6 +55,7 @@ public class MoveChoice : TurnChoice, IMoveChoice
|
||||
ChosenMove = usedMove;
|
||||
TargetSide = targetSide;
|
||||
TargetPosition = targetPosition;
|
||||
Volatile = new ScriptSet(this);
|
||||
|
||||
var secondaryEffect = usedMove.MoveData.SecondaryEffect;
|
||||
if (secondaryEffect != null)
|
||||
@ -86,7 +87,7 @@ public class MoveChoice : TurnChoice, IMoveChoice
|
||||
public Dictionary<StringKey, object?>? AdditionalData { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IScriptSet Volatile { get; } = new ScriptSet();
|
||||
public IScriptSet Volatile { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int ScriptCount => 2 + User.ScriptCount;
|
||||
|
@ -37,6 +37,11 @@ public enum MoveLearnMethod
|
||||
/// The move is learned when the Pokémon changes form.
|
||||
/// </summary>
|
||||
FormChange,
|
||||
|
||||
/// <summary>
|
||||
/// The move is learned by using a move sketch.
|
||||
/// </summary>
|
||||
Sketch,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -487,6 +487,7 @@ public class PokemonImpl : ScriptSource, IPokemon
|
||||
WeightInKg = form.Weight;
|
||||
HeightInMeters = form.Height;
|
||||
Happiness = species.BaseHappiness;
|
||||
Volatile = new ScriptSet(this);
|
||||
if (!library.StaticLibrary.Natures.TryGet(natureName, out var nature))
|
||||
throw new KeyNotFoundException($"Nature {natureName} not found.");
|
||||
Nature = nature;
|
||||
@ -532,6 +533,7 @@ public class PokemonImpl : ScriptSource, IPokemon
|
||||
AbilityIndex = form.FindAbilityIndex(ability) ??
|
||||
throw new KeyNotFoundException(
|
||||
$"Ability {ability.Name} not found on species {species.Name} form {form.Name}.");
|
||||
Volatile = new ScriptSet(this);
|
||||
_learnedMoves = serializedPokemon.Moves.Select(move =>
|
||||
{
|
||||
if (move == null)
|
||||
@ -736,7 +738,7 @@ public class PokemonImpl : ScriptSource, IPokemon
|
||||
public ScriptContainer StatusScript { get; } = new();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IScriptSet Volatile { get; } = new ScriptSet();
|
||||
public IScriptSet Volatile { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasHeldItem(StringKey itemName) => HeldItem?.Name == itemName;
|
||||
@ -1097,6 +1099,11 @@ public class PokemonImpl : ScriptSource, IPokemon
|
||||
{
|
||||
if (!Library.ScriptResolver.TryResolve(ScriptCategory.Status, status, null, out var statusScript))
|
||||
throw new KeyNotFoundException($"Status script {status} not found");
|
||||
var preventStatus = false;
|
||||
this.RunScriptHook(script => script.PreventStatusChange(this, status, ref preventStatus));
|
||||
if (preventStatus)
|
||||
return false;
|
||||
|
||||
StatusScript.Set(statusScript);
|
||||
return true;
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<LangVersion>12</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<WarningsAsErrors>nullable</WarningsAsErrors>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
using System.Diagnostics;
|
||||
using PkmnLib.Dynamic.Models;
|
||||
using PkmnLib.Dynamic.Models.Choices;
|
||||
using PkmnLib.Dynamic.ScriptHandling.Registry;
|
||||
@ -12,6 +13,7 @@ namespace PkmnLib.Dynamic.ScriptHandling;
|
||||
/// changes. This allows for easily defining generational differences, and add effects that the
|
||||
/// developer might require.
|
||||
/// </summary>
|
||||
[DebuggerDisplay("{Category} - {Name}")]
|
||||
public abstract class Script : IDeepCloneable
|
||||
{
|
||||
internal event Action<Script>? OnRemoveEvent;
|
||||
@ -683,4 +685,12 @@ public abstract class Script : IDeepCloneable
|
||||
public virtual void OnBeforeHit(IExecutingMove move, IPokemon target, byte hitIndex)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreventStatusChange(IPokemon pokemonImpl, StringKey status, ref bool preventStatus)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreventVolatileAdd(Script script, ref bool preventVolatileAdd)
|
||||
{
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using System.Collections;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using PkmnLib.Dynamic.ScriptHandling.Registry;
|
||||
using PkmnLib.Static.Utils;
|
||||
|
||||
@ -14,8 +15,11 @@ public interface IScriptSet : IEnumerable<ScriptContainer>
|
||||
/// <summary>
|
||||
/// Adds a script to the set. If the script with that name already exists in this set, this
|
||||
/// makes that script stack instead. The return value here is that script.
|
||||
/// If the script was blocked from being added, this will return null.
|
||||
/// </summary>
|
||||
ScriptContainer Add(Script script);
|
||||
/// <param name="script">The script to add.</param>
|
||||
/// <param name="forceAdd">If true, the script cannot be blocked, and will always be added</param>
|
||||
ScriptContainer? Add(Script script, bool forceAdd = false);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a script with a name to the set. If the script with that name already exists in this
|
||||
@ -77,8 +81,15 @@ public interface IScriptSet : IEnumerable<ScriptContainer>
|
||||
/// <inheritdoc cref="IScriptSet"/>
|
||||
public class ScriptSet : IScriptSet
|
||||
{
|
||||
private IScriptSource _source;
|
||||
|
||||
private readonly List<ScriptContainer> _scripts = [];
|
||||
|
||||
public ScriptSet(IScriptSource source)
|
||||
{
|
||||
_source = source;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerator<ScriptContainer> GetEnumerator() => _scripts.GetEnumerator();
|
||||
|
||||
@ -86,8 +97,16 @@ public class ScriptSet : IScriptSet
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
/// <inheritdoc />
|
||||
public ScriptContainer Add(Script script)
|
||||
public ScriptContainer? Add(Script script, bool forceAdd = false)
|
||||
{
|
||||
if (!forceAdd)
|
||||
{
|
||||
var preventVolatileAdd = false;
|
||||
_source.RunScriptHook(x => x.PreventVolatileAdd(script, ref preventVolatileAdd));
|
||||
if (preventVolatileAdd)
|
||||
return null;
|
||||
}
|
||||
|
||||
var existing = _scripts.FirstOrDefault(s => s.Script?.Name == script.Name);
|
||||
if (existing != null)
|
||||
{
|
||||
|
57
PkmnLib.NET.sln
Normal file
57
PkmnLib.NET.sln
Normal file
@ -0,0 +1,57 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PkmnLib.Static", "PkmnLib.Static\PkmnLib.Static.csproj", "{312782DA-1066-4490-BD0E-DF4DF8713B4A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PkmnLib.Tests", "PkmnLib.Tests\PkmnLib.Tests.csproj", "{42DE3095-0468-4827-AF5C-691C94BA7F92}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PkmnLib.Dynamic", "PkmnLib.Dynamic\PkmnLib.Dynamic.csproj", "{D0CBA9A9-7288-41B4-B76B-CB4F20036AB2}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PkmnLib.Plugin.Gen7", "Plugins\PkmnLib.Plugin.Gen7\PkmnLib.Plugin.Gen7.csproj", "{FA5380F0-28CC-4AEC-8963-814B347A89BA}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugins", "Plugins", "{63C1B450-DC26-444A-AEBD-15979F3EEE53}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PkmnLib.Plugin.Gen7.Tests", "Plugins\PkmnLib.Plugin.Gen7.Tests\PkmnLib.Plugin.Gen7.Tests.csproj", "{FBB53861-081F-4DAC-B006-79EE238D0DFC}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PkmnLib.Dataloader", "PkmnLib.Dataloader\PkmnLib.Dataloader.csproj", "{E6A733FD-C2A3-4206-B9A9-40DBFBDBE1AC}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionFiles", "SolutionFiles", "{2B99ADF8-10E2-4A3D-906F-27DC8E312A79}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{312782DA-1066-4490-BD0E-DF4DF8713B4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{312782DA-1066-4490-BD0E-DF4DF8713B4A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{312782DA-1066-4490-BD0E-DF4DF8713B4A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{312782DA-1066-4490-BD0E-DF4DF8713B4A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{42DE3095-0468-4827-AF5C-691C94BA7F92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{42DE3095-0468-4827-AF5C-691C94BA7F92}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{42DE3095-0468-4827-AF5C-691C94BA7F92}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{42DE3095-0468-4827-AF5C-691C94BA7F92}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D0CBA9A9-7288-41B4-B76B-CB4F20036AB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D0CBA9A9-7288-41B4-B76B-CB4F20036AB2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D0CBA9A9-7288-41B4-B76B-CB4F20036AB2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D0CBA9A9-7288-41B4-B76B-CB4F20036AB2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FA5380F0-28CC-4AEC-8963-814B347A89BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FA5380F0-28CC-4AEC-8963-814B347A89BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FA5380F0-28CC-4AEC-8963-814B347A89BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FA5380F0-28CC-4AEC-8963-814B347A89BA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FBB53861-081F-4DAC-B006-79EE238D0DFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FBB53861-081F-4DAC-B006-79EE238D0DFC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FBB53861-081F-4DAC-B006-79EE238D0DFC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FBB53861-081F-4DAC-B006-79EE238D0DFC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E6A733FD-C2A3-4206-B9A9-40DBFBDBE1AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E6A733FD-C2A3-4206-B9A9-40DBFBDBE1AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E6A733FD-C2A3-4206-B9A9-40DBFBDBE1AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E6A733FD-C2A3-4206-B9A9-40DBFBDBE1AC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{FA5380F0-28CC-4AEC-8963-814B347A89BA} = {63C1B450-DC26-444A-AEBD-15979F3EEE53}
|
||||
{FBB53861-081F-4DAC-B006-79EE238D0DFC} = {63C1B450-DC26-444A-AEBD-15979F3EEE53}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
@ -4,7 +4,6 @@
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<LangVersion>12</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<WarningsAsErrors>nullable</WarningsAsErrors>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
|
@ -1570,7 +1570,8 @@
|
||||
"mirror",
|
||||
"sound",
|
||||
"distance",
|
||||
"ignore-substitute"
|
||||
"ignore-substitute",
|
||||
"not_sketchable"
|
||||
],
|
||||
"effect": {
|
||||
"name": "confuse"
|
||||
@ -3739,10 +3740,9 @@
|
||||
"defrost"
|
||||
],
|
||||
"effect": {
|
||||
"name": "set_status",
|
||||
"chance": 10,
|
||||
"name": "flame_wheel",
|
||||
"parameters": {
|
||||
"status": "burned"
|
||||
"burn_chance": 10.0
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -9249,7 +9249,13 @@
|
||||
"protect",
|
||||
"mirror",
|
||||
"defrost"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "flame_wheel",
|
||||
"parameters": {
|
||||
"burn_chance": 50.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sacred_sword",
|
||||
@ -9264,7 +9270,10 @@
|
||||
"contact",
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "chip_away"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "safeguard",
|
||||
@ -9277,7 +9286,10 @@
|
||||
"category": "status",
|
||||
"flags": [
|
||||
"snatch"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "safeguard"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sand_attack",
|
||||
@ -9292,7 +9304,13 @@
|
||||
"protect",
|
||||
"reflectable",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_target_accuracy",
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sand_tomb",
|
||||
@ -9306,7 +9324,10 @@
|
||||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "bind"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sandstorm",
|
||||
@ -9317,7 +9338,13 @@
|
||||
"priority": 0,
|
||||
"target": "All",
|
||||
"category": "status",
|
||||
"flags": []
|
||||
"flags": [],
|
||||
"effect": {
|
||||
"name": "set_weather",
|
||||
"parameters": {
|
||||
"weather": "sandstorm"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "savage_spin_out__physical",
|
||||
@ -9329,6 +9356,7 @@
|
||||
"target": "Any",
|
||||
"category": "physical",
|
||||
"flags": []
|
||||
// No secondary effect
|
||||
},
|
||||
{
|
||||
"name": "savage_spin_out__special",
|
||||
@ -9340,6 +9368,7 @@
|
||||
"target": "Any",
|
||||
"category": "special",
|
||||
"flags": []
|
||||
// No secondary effect
|
||||
},
|
||||
{
|
||||
"name": "scald",
|
||||
@ -9354,7 +9383,14 @@
|
||||
"protect",
|
||||
"mirror",
|
||||
"defrost"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "set_status",
|
||||
"chance": 30,
|
||||
"parameters": {
|
||||
"status": "burned"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "scary_face",
|
||||
@ -9369,7 +9405,13 @@
|
||||
"protect",
|
||||
"reflectable",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_target_speed",
|
||||
"parameters": {
|
||||
"amount": -2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "scratch",
|
||||
@ -9385,6 +9427,7 @@
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
// No secondary effect
|
||||
},
|
||||
{
|
||||
"name": "screech",
|
||||
@ -9401,7 +9444,13 @@
|
||||
"mirror",
|
||||
"sound",
|
||||
"ignore-substitute"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_target_defense",
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "searing_shot",
|
||||
@ -9415,7 +9464,14 @@
|
||||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "set_status",
|
||||
"chance": 30,
|
||||
"parameters": {
|
||||
"status": "burned"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "secret_power",
|
||||
@ -9429,7 +9485,10 @@
|
||||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "secret_power"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "secret_sword",
|
||||
@ -9443,7 +9502,10 @@
|
||||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "psyshock"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "seed_bomb",
|
||||
@ -9459,6 +9521,7 @@
|
||||
"mirror",
|
||||
"ballistics"
|
||||
]
|
||||
// No secondary effect
|
||||
},
|
||||
{
|
||||
"name": "seed_flare",
|
||||
@ -9472,7 +9535,14 @@
|
||||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_target_special_defense",
|
||||
"chance": 40,
|
||||
"parameters": {
|
||||
"amount": -2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "seismic_toss",
|
||||
@ -9488,7 +9558,10 @@
|
||||
"protect",
|
||||
"mirror",
|
||||
"nonskybattle"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "night_shade"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "self_destruct",
|
||||
@ -9502,7 +9575,10 @@
|
||||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "self_destruct"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "shadow_ball",
|
||||
@ -9517,7 +9593,14 @@
|
||||
"protect",
|
||||
"mirror",
|
||||
"ballistics"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_target_special_defense",
|
||||
"chance": 20,
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "shadow_bone",
|
||||
@ -9531,7 +9614,14 @@
|
||||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_target_defense",
|
||||
"chance": 20,
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "shadow_claw",
|
||||
@ -9546,7 +9636,10 @@
|
||||
"contact",
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "increased_critical_stage"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "shadow_force",
|
||||
@ -9561,14 +9654,17 @@
|
||||
"contact",
|
||||
"charge",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "shadow_force"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "shadow_punch",
|
||||
"type": "ghost",
|
||||
"power": 60,
|
||||
"pp": 20,
|
||||
"accuracy": 0,
|
||||
"accuracy": 255,
|
||||
"priority": 0,
|
||||
"target": "Any",
|
||||
"category": "physical",
|
||||
@ -9578,6 +9674,7 @@
|
||||
"mirror",
|
||||
"punch"
|
||||
]
|
||||
// No secondary effect
|
||||
},
|
||||
{
|
||||
"name": "shadow_sneak",
|
||||
@ -9593,6 +9690,7 @@
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
// No secondary effect
|
||||
},
|
||||
{
|
||||
"name": "sharpen",
|
||||
@ -9605,7 +9703,13 @@
|
||||
"category": "status",
|
||||
"flags": [
|
||||
"snatch"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_user_attack",
|
||||
"parameters": {
|
||||
"amount": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "shattered_psyche__physical",
|
||||
@ -9617,6 +9721,7 @@
|
||||
"target": "Any",
|
||||
"category": "physical",
|
||||
"flags": []
|
||||
// No secondary effect
|
||||
},
|
||||
{
|
||||
"name": "shattered_psyche__special",
|
||||
@ -9628,6 +9733,7 @@
|
||||
"target": "Any",
|
||||
"category": "special",
|
||||
"flags": []
|
||||
// No secondary effect
|
||||
},
|
||||
{
|
||||
"name": "sheer_cold",
|
||||
@ -9641,7 +9747,10 @@
|
||||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "one_hit_ko"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "shell_smash",
|
||||
@ -9654,7 +9763,10 @@
|
||||
"category": "status",
|
||||
"flags": [
|
||||
"snatch"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "shell_smash"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "shell_trap",
|
||||
@ -9667,7 +9779,10 @@
|
||||
"category": "special",
|
||||
"flags": [
|
||||
"protect"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "shell_trap"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "shift_gear",
|
||||
@ -9680,14 +9795,21 @@
|
||||
"category": "status",
|
||||
"flags": [
|
||||
"snatch"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_multiple_user_stat_boosts",
|
||||
"parameters": {
|
||||
"attack": 1,
|
||||
"speed": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "shock_wave",
|
||||
"type": "electric",
|
||||
"power": 60,
|
||||
"pp": 20,
|
||||
"accuracy": 0,
|
||||
"accuracy": 255,
|
||||
"priority": 0,
|
||||
"target": "Any",
|
||||
"category": "special",
|
||||
@ -9695,6 +9817,7 @@
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
// No secondary effect
|
||||
},
|
||||
{
|
||||
"name": "shore_up",
|
||||
@ -9708,7 +9831,10 @@
|
||||
"flags": [
|
||||
"snatch",
|
||||
"heal"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "shore_up"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "signal_beam",
|
||||
@ -9722,7 +9848,11 @@
|
||||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "confuse",
|
||||
"chance": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "silver_wind",
|
||||
@ -9736,7 +9866,18 @@
|
||||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_multiple_user_stat_boosts",
|
||||
"chance": 10,
|
||||
"parameters": {
|
||||
"attack": 1,
|
||||
"defense": 1,
|
||||
"specialAttack": 1,
|
||||
"specialDefense": 1,
|
||||
"speed": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "simple_beam",
|
||||
@ -9751,7 +9892,10 @@
|
||||
"protect",
|
||||
"reflectable",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "simple_beam"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sing",
|
||||
@ -9768,7 +9912,13 @@
|
||||
"mirror",
|
||||
"sound",
|
||||
"ignore-substitute"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "set_status",
|
||||
"parameters": {
|
||||
"status": "sleep"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sinister_arrow_raid",
|
||||
@ -9780,6 +9930,7 @@
|
||||
"target": "Any",
|
||||
"category": "physical",
|
||||
"flags": []
|
||||
// No secondary effect
|
||||
},
|
||||
{
|
||||
"name": "sketch",
|
||||
@ -9792,7 +9943,10 @@
|
||||
"category": "status",
|
||||
"flags": [
|
||||
"ignore-substitute"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "sketch"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "skill_swap",
|
||||
@ -9807,7 +9961,10 @@
|
||||
"protect",
|
||||
"mirror",
|
||||
"ignore-substitute"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "skill_swap"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "skull_bash",
|
||||
|
@ -1,7 +1,9 @@
|
||||
using System.Text.Json.Nodes;
|
||||
using PkmnLib.Dynamic.Libraries;
|
||||
using PkmnLib.Dynamic.ScriptHandling;
|
||||
using PkmnLib.Static.Moves;
|
||||
using PkmnLib.Tests.Integration;
|
||||
using TUnit.Core.Logging;
|
||||
|
||||
namespace PkmnLib.Tests.DataTests;
|
||||
|
||||
@ -39,6 +41,17 @@ public class MoveDataTests
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Helper method to find the line number of the effect in the JSON file
|
||||
var file = Path.GetFullPath("../../../../PkmnLib.Tests/Data/Moves.jsonc");
|
||||
var json = await File.ReadAllLinesAsync(file);
|
||||
var moveLineNumber = json.Select((line, index) => new { line, index })
|
||||
.FirstOrDefault(x => x.line.Contains($"\"name\": \"{test.Move.Name}\""))?.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.Move.Name} with effect {scriptName}",
|
||||
e);
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ public class SerializationTests
|
||||
var library = LibraryHelpers.LoadLibrary();
|
||||
await Assert.That(library.StaticLibrary.Species.TryGet("bulbasaur", out var species)).IsTrue();
|
||||
|
||||
var pokemon = new PokemonImpl(library, species!, species!.GetDefaultForm(), new AbilityIndex()
|
||||
var pokemon = new PokemonImpl(library, species!, species!.GetDefaultForm(), new AbilityIndex
|
||||
{
|
||||
Index = 0,
|
||||
IsHidden = false,
|
||||
|
@ -54,8 +54,8 @@ public class Gen7BattleStatCalculator : IBattleStatCalculator
|
||||
byte moveAccuracy)
|
||||
{
|
||||
var accuracyModifier = 1.0f;
|
||||
executingMove.RunScriptHook(
|
||||
x => x.ChangeAccuracyModifier(executingMove, target, hitIndex, ref accuracyModifier));
|
||||
executingMove.RunScriptHook(x =>
|
||||
x.ChangeAccuracyModifier(executingMove, target, hitIndex, ref accuracyModifier));
|
||||
var modifiedAccuracy = (int)(moveAccuracy * accuracyModifier);
|
||||
// ReSharper disable once AccessToModifiedClosure
|
||||
executingMove.RunScriptHook(x => x.ChangeAccuracy(executingMove, target, hitIndex, ref modifiedAccuracy));
|
||||
|
@ -12,7 +12,7 @@ public class Gen7MiscLibrary : IMiscLibrary
|
||||
{
|
||||
private readonly IMoveData _struggleData = new MoveDataImpl("struggle", new TypeIdentifier(0, "none"),
|
||||
MoveCategory.Physical, 50, 255, 255, MoveTarget.Any, 0,
|
||||
new SecondaryEffectImpl(-1, "struggle", new Dictionary<StringKey, object?>()), []);
|
||||
new SecondaryEffectImpl(-1, "struggle", new Dictionary<StringKey, object?>()), ["not_sketchable"]);
|
||||
|
||||
/// <inheritdoc />
|
||||
public ITurnChoice ReplacementChoice(IPokemon user, byte targetSide, byte targetPosition) =>
|
||||
|
@ -4,7 +4,6 @@
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>12</LangVersion>
|
||||
<WarningsAsErrors>nullable</WarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -0,0 +1,11 @@
|
||||
using PkmnLib.Static.Utils;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.MoveVolatile;
|
||||
|
||||
[Script(ScriptCategory.MoveVolatile, "round")]
|
||||
public class RoundPowerBoost : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref byte basePower) =>
|
||||
basePower = basePower.MultiplyOrMax(2f);
|
||||
}
|
@ -13,7 +13,7 @@ public abstract class BaseChargeMove<TVolatile> : Script where TVolatile : Requi
|
||||
return;
|
||||
|
||||
move.User.Volatile.Add(CreateVolatile(move.User));
|
||||
move.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("began_charging", new Dictionary<string, object>()
|
||||
move.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("began_charging", new Dictionary<string, object>
|
||||
{
|
||||
{ "user", move.User },
|
||||
}));
|
||||
|
@ -13,7 +13,7 @@ public class BeakBlast : Script
|
||||
if (battleData == null)
|
||||
return;
|
||||
choice.User.Volatile.Add(new BeakBlastEffect());
|
||||
battleData.Battle.EventHook.Invoke(new DialogEvent("beak_blast_charge", new Dictionary<string, object>()
|
||||
battleData.Battle.EventHook.Invoke(new DialogEvent("beak_blast_charge", new Dictionary<string, object>
|
||||
{
|
||||
{ "user", choice.User },
|
||||
}));
|
||||
|
@ -13,7 +13,7 @@ public class Bounce : Script
|
||||
return;
|
||||
|
||||
move.User.Volatile.Add(new ChargeBounceEffect(move.User));
|
||||
move.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("bounce_charge", new Dictionary<string, object>()
|
||||
move.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("bounce_charge", new Dictionary<string, object>
|
||||
{
|
||||
{ "user", move.User },
|
||||
}));
|
||||
|
@ -3,5 +3,5 @@ namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
[Script(ScriptCategory.Move, "camouflage")]
|
||||
public class Camouflage : Script
|
||||
{
|
||||
// FIXME: Implement this. How to get the terrain in a sane manner?
|
||||
// FIXME: Implement this. How to get the terrain in a sane manner? See also SecretPower.cs
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Side;
|
||||
using PkmnLib.Static.Utils;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
@ -6,16 +8,16 @@ namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
[Script(ScriptCategory.Move, "defog")]
|
||||
public class Defog : Script
|
||||
{
|
||||
public static HashSet<StringKey> DefoggedEffects = new()
|
||||
{
|
||||
"mist",
|
||||
"light_screen",
|
||||
"reflect",
|
||||
"safe_guard",
|
||||
[PublicAPI] public static HashSet<StringKey> DefoggedEffects =
|
||||
[
|
||||
ScriptUtils.ResolveName<MistEffect>(),
|
||||
ScriptUtils.ResolveName<LightScreenEffect>(),
|
||||
ScriptUtils.ResolveName<ReflectEffect>(),
|
||||
ScriptUtils.ResolveName<SafeguardEffect>(),
|
||||
"spikes",
|
||||
"toxic_spikes",
|
||||
"stealth_rock",
|
||||
};
|
||||
];
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
|
@ -13,7 +13,7 @@ public class Dig : Script
|
||||
return;
|
||||
|
||||
move.User.Volatile.Add(new DigEffect(move.User));
|
||||
move.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("dig_charge", new Dictionary<string, object>()
|
||||
move.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("dig_charge", new Dictionary<string, object>
|
||||
{
|
||||
{ "user", move.User },
|
||||
}));
|
||||
|
@ -13,7 +13,7 @@ public class Dive : Script
|
||||
return;
|
||||
|
||||
move.User.Volatile.Add(new DigEffect(move.User));
|
||||
move.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("dive_charge", new Dictionary<string, object>()
|
||||
move.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("dive_charge", new Dictionary<string, object>
|
||||
{
|
||||
{ "user", move.User },
|
||||
}));
|
||||
|
37
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FlameWheel.cs
Normal file
37
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/FlameWheel.cs
Normal file
@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using PkmnLib.Static.Utils;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "flame_wheel")]
|
||||
public class FlameWheel : Script
|
||||
{
|
||||
private float _burnChance;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnInitialize(IReadOnlyDictionary<StringKey, object?>? parameters)
|
||||
{
|
||||
if (parameters is null || !parameters.TryGetValue("burn_chance", out var burnChance) ||
|
||||
burnChance is not float chance)
|
||||
{
|
||||
throw new Exception("Flame Wheel: Missing or invalid parameters.");
|
||||
}
|
||||
_burnChance = chance;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
if (move.User.HasStatus("frozen"))
|
||||
{
|
||||
move.User.ClearStatus();
|
||||
}
|
||||
|
||||
var burnChance = _burnChance;
|
||||
if (move.Battle.Random.EffectChance(_burnChance, move, target, hit))
|
||||
{
|
||||
target.SetStatus("burned");
|
||||
}
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ public class Fly : Script
|
||||
return;
|
||||
|
||||
move.User.Volatile.Add(new ChargeFlyEffect(move.User));
|
||||
move.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("fly_charge", new Dictionary<string, object>()
|
||||
move.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("fly_charge", new Dictionary<string, object>
|
||||
{
|
||||
{ "user", move.User },
|
||||
}));
|
||||
|
@ -11,7 +11,7 @@ public class FocusPunch : Script
|
||||
{
|
||||
choice.User.Volatile.Add(new FocusPunchEffect());
|
||||
choice.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("focus_punch_charge",
|
||||
new Dictionary<string, object>()
|
||||
new Dictionary<string, object>
|
||||
{
|
||||
{ "pokemon", choice.User },
|
||||
}));
|
||||
|
@ -15,7 +15,7 @@ public class LightScreen : Script
|
||||
return;
|
||||
|
||||
var turns = 5;
|
||||
var dict = new Dictionary<StringKey, object?>()
|
||||
var dict = new Dictionary<StringKey, object?>
|
||||
{
|
||||
{ "duration", turns },
|
||||
};
|
||||
|
@ -32,7 +32,7 @@ public class Magnitude : Script
|
||||
// 5% chance for 10
|
||||
_ => 10,
|
||||
};
|
||||
battleData.Battle.EventHook.Invoke(new DialogEvent("magnitude", new Dictionary<string, object>()
|
||||
battleData.Battle.EventHook.Invoke(new DialogEvent("magnitude", new Dictionary<string, object>
|
||||
{
|
||||
{ "magnitude", magnitude },
|
||||
{ "user", move.User },
|
||||
|
@ -9,6 +9,11 @@ public class MeanLook : Script
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
var targetEffect = target.Volatile.Add(new MeanLookEffectTarget());
|
||||
if (targetEffect == null)
|
||||
{
|
||||
move.GetHitData(target, hit).Fail();
|
||||
return;
|
||||
}
|
||||
var userEffect = new MeanLookEffectUser(targetEffect);
|
||||
move.User.Volatile.Add(userEffect);
|
||||
}
|
||||
|
@ -13,6 +13,12 @@ public class RagePowder : Script
|
||||
return;
|
||||
|
||||
var effect = battleData.BattleSide.VolatileScripts.Add(new RagePowderEffect(move.User));
|
||||
if (effect == null)
|
||||
{
|
||||
move.GetHitData(target, hit).Fail();
|
||||
return;
|
||||
}
|
||||
|
||||
((RagePowderEffect)effect.Script!).User = move.User;
|
||||
}
|
||||
}
|
29
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Round.cs
Normal file
29
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Round.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using System.Linq;
|
||||
using PkmnLib.Plugin.Gen7.Scripts.MoveVolatile;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "round")]
|
||||
public class Round : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void OnAfterMove(IExecutingMove move)
|
||||
{
|
||||
var choiceQueue = move.Battle.ChoiceQueue;
|
||||
if (choiceQueue is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var otherRoundMoves = choiceQueue.Where(x => x is IMoveChoice mc && mc.ChosenMove.MoveData.Name == "round")
|
||||
.Cast<IMoveChoice>().ToList();
|
||||
|
||||
// We reverse the order here, as we're constantly pushing the choices to the front of the queue.
|
||||
// By reversing the order, we ensure that the first choice is the one that is up next.
|
||||
foreach (var otherRoundMove in otherRoundMoves.AsEnumerable().Reverse())
|
||||
{
|
||||
otherRoundMove.Volatile.Add(new RoundPowerBoost());
|
||||
choiceQueue.MovePokemonChoiceNext(otherRoundMove.User);
|
||||
}
|
||||
}
|
||||
}
|
11
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Safeguard.cs
Normal file
11
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Safeguard.cs
Normal file
@ -0,0 +1,11 @@
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "safeguard")]
|
||||
public class Safeguard : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
target.BattleData?.BattleSide.VolatileScripts.Add(new Side.SafeguardEffect());
|
||||
}
|
||||
}
|
7
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/SecretPower.cs
Normal file
7
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/SecretPower.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "secret_power")]
|
||||
public class SecretPower : Script
|
||||
{
|
||||
// FIXME: Implement this. How to get the terrain in a sane manner? See also Camouflage.cs
|
||||
}
|
14
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/SelfDestruct.cs
Normal file
14
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/SelfDestruct.cs
Normal file
@ -0,0 +1,14 @@
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "self_destruct")]
|
||||
public class SelfDestruct : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void OnAfterMove(IExecutingMove move)
|
||||
{
|
||||
if (move.User.IsFainted)
|
||||
return;
|
||||
|
||||
move.User.Faint(DamageSource.Misc);
|
||||
}
|
||||
}
|
32
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ShadowForce.cs
Normal file
32
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ShadowForce.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using System.Collections.Generic;
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "shadow_force")]
|
||||
public class ShadowForce : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void PreventMove(IExecutingMove move, ref bool prevent)
|
||||
{
|
||||
if (move.User.Volatile.Contains<ShadowForceCharge>())
|
||||
return;
|
||||
|
||||
move.User.Volatile.Add(new ShadowForceCharge(move.User));
|
||||
move.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("shadow_force_charge",
|
||||
new Dictionary<string, object>
|
||||
{
|
||||
{ "user", move.User },
|
||||
}));
|
||||
prevent = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
if (move.User.Volatile.Contains<ShadowForceCharge>())
|
||||
return;
|
||||
|
||||
move.User.Volatile.Add(new ShadowForceCharge(move.User));
|
||||
}
|
||||
}
|
19
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ShellSmash.cs
Normal file
19
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ShellSmash.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using PkmnLib.Static;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "shell_smash")]
|
||||
public class ShellSmash : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
EventBatchId eventBatchId = new();
|
||||
move.User.ChangeStatBoost(Statistic.Attack, 2, true, eventBatchId);
|
||||
move.User.ChangeStatBoost(Statistic.SpecialAttack, 2, true, eventBatchId);
|
||||
move.User.ChangeStatBoost(Statistic.Speed, 2, true, eventBatchId);
|
||||
eventBatchId = new EventBatchId();
|
||||
move.User.ChangeStatBoost(Statistic.Defense, -1, true, eventBatchId);
|
||||
move.User.ChangeStatBoost(Statistic.SpecialDefense, -1, true, eventBatchId);
|
||||
}
|
||||
}
|
23
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ShellTrap.cs
Normal file
23
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ShellTrap.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "shell_trap")]
|
||||
public class ShellTrap : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void OnBeforeMove(IExecutingMove move)
|
||||
{
|
||||
move.User.Volatile.Add(new ShellTrapHelper());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void FailMove(IExecutingMove move, ref bool fail)
|
||||
{
|
||||
var shellTrapHelper = move.User.Volatile.Get<ShellTrapHelper>();
|
||||
if (shellTrapHelper is not { HasHit: true })
|
||||
{
|
||||
fail = true;
|
||||
}
|
||||
}
|
||||
}
|
19
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ShoreUp.cs
Normal file
19
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ShoreUp.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Weather;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "shore_up")]
|
||||
public class ShoreUp : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
var healMod = 0.5f;
|
||||
if (move.Battle.WeatherName == ScriptUtils.ResolveName<Sandstorm>())
|
||||
{
|
||||
healMod = 2f / 3f;
|
||||
}
|
||||
var heal = (uint)(target.MaxHealth * healMod);
|
||||
target.Heal(heal);
|
||||
}
|
||||
}
|
16
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/SimpleBeam.cs
Normal file
16
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/SimpleBeam.cs
Normal file
@ -0,0 +1,16 @@
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "simple_beam")]
|
||||
public class SimpleBeam : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
if (!move.Battle.Library.StaticLibrary.Abilities.TryGet("simple", out var simpleAbility))
|
||||
{
|
||||
move.GetHitData(target, hit).Fail();
|
||||
return;
|
||||
}
|
||||
target.ChangeAbility(simpleAbility);
|
||||
}
|
||||
}
|
37
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Sketch.cs
Normal file
37
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Sketch.cs
Normal file
@ -0,0 +1,37 @@
|
||||
using System.Linq;
|
||||
using PkmnLib.Static.Utils;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "sketch")]
|
||||
public class Sketch : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
// Defensive programming; If the move we're using is not the same as the one picked, something changed
|
||||
// our move to sketch. This should never happen, as moves are not allowed to change to sketch, but in the
|
||||
// case it does, we should fail the move.
|
||||
if (move.ChosenMove.MoveData != move.UseMove)
|
||||
{
|
||||
move.GetHitData(target, hit).Fail();
|
||||
return;
|
||||
}
|
||||
var moveSlot = move.User.Moves.IndexOf(move.ChosenMove);
|
||||
if (moveSlot == -1)
|
||||
{
|
||||
move.GetHitData(target, hit).Fail();
|
||||
return;
|
||||
}
|
||||
|
||||
var choiceQueue = move.Battle.PreviousTurnChoices;
|
||||
var lastMove = choiceQueue.SelectMany(x => x).OfType<IMoveChoice>().LastOrDefault(x => x.User == target);
|
||||
if (lastMove == null || lastMove.ChosenMove.MoveData.HasFlag("not_sketchable"))
|
||||
{
|
||||
move.GetHitData(target, hit).Fail();
|
||||
return;
|
||||
}
|
||||
|
||||
move.User.LearnMove(lastMove.ChosenMove.MoveData.Name, MoveLearnMethod.Sketch, (byte)moveSlot);
|
||||
}
|
||||
}
|
25
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/SkillSwap.cs
Normal file
25
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/SkillSwap.cs
Normal file
@ -0,0 +1,25 @@
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "skill_swap")]
|
||||
public class SkillSwap : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
var targetAbility = target.ActiveAbility;
|
||||
var userAbility = move.User.ActiveAbility;
|
||||
if (targetAbility == null || userAbility == null)
|
||||
{
|
||||
move.GetHitData(target, hit).Fail();
|
||||
return;
|
||||
}
|
||||
if (targetAbility.HasFlag("cant_be_changed") || userAbility.HasFlag("cant_be_changed"))
|
||||
{
|
||||
move.GetHitData(target, hit).Fail();
|
||||
return;
|
||||
}
|
||||
|
||||
move.User.ChangeAbility(targetAbility);
|
||||
target.ChangeAbility(userAbility);
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ public class FocusPunchEffect : Script
|
||||
{
|
||||
WasHit = true;
|
||||
target.BattleData?.Battle.EventHook.Invoke(new DialogEvent("focus_punch_lost_focus",
|
||||
new Dictionary<string, object>()
|
||||
new Dictionary<string, object>
|
||||
{
|
||||
{ "pokemon", target },
|
||||
}));
|
||||
|
@ -33,7 +33,7 @@ public abstract class OutrageLikeEffect : Script
|
||||
if (_turns <= 0)
|
||||
{
|
||||
RemoveSelf();
|
||||
_owner.Volatile.Add(new Confusion());
|
||||
_owner.Volatile.Add(new Confusion(), true);
|
||||
}
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@ public class RequiresRechargeEffect : Script
|
||||
{
|
||||
RemoveSelf();
|
||||
_owner.BattleData?.Battle.EventHook.Invoke(new DialogEvent("pokemon_must_recharge",
|
||||
new Dictionary<string, object>()
|
||||
new Dictionary<string, object>
|
||||
{
|
||||
{ "pokemon", _owner },
|
||||
}));
|
||||
|
@ -0,0 +1,27 @@
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Utils;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
|
||||
[Script(ScriptCategory.Pokemon, "shadow_force")]
|
||||
public class ShadowForceCharge : Script
|
||||
{
|
||||
private readonly IPokemon _owner;
|
||||
|
||||
public ShadowForceCharge(IPokemon owner)
|
||||
{
|
||||
_owner = owner;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void ForceTurnSelection(byte sideIndex, byte position, ref ITurnChoice? choice)
|
||||
{
|
||||
var opposingSideIndex = (byte)(_owner.BattleData?.SideIndex == 0 ? 1 : 0);
|
||||
choice = TurnChoiceHelper.CreateMoveChoice(_owner, "shadow_force", opposingSideIndex, position);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void BlockIncomingHit(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref bool block)
|
||||
{
|
||||
block = true;
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
using PkmnLib.Static.Moves;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
|
||||
[Script(ScriptCategory.Pokemon, "shell_trap")]
|
||||
public class ShellTrapHelper : Script
|
||||
{
|
||||
public bool HasHit { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnIncomingHit(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
if (move.UseMove.Category == MoveCategory.Physical)
|
||||
HasHit = true;
|
||||
}
|
||||
}
|
20
Plugins/PkmnLib.Plugin.Gen7/Scripts/Side/SafeguardEffect.cs
Normal file
20
Plugins/PkmnLib.Plugin.Gen7/Scripts/Side/SafeguardEffect.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
using PkmnLib.Static.Utils;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Side;
|
||||
|
||||
public class SafeguardEffect : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void PreventStatusChange(IPokemon pokemonImpl, StringKey status, ref bool preventStatus)
|
||||
{
|
||||
preventStatus = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void PreventVolatileAdd(Script script, ref bool preventVolatileAdd)
|
||||
{
|
||||
if (script.Category == ScriptCategory.Pokemon && script.Name == ScriptUtils.ResolveName<Confusion>())
|
||||
preventVolatileAdd = true;
|
||||
}
|
||||
}
|
@ -32,8 +32,7 @@ public class Hail : Script, IWeatherScript
|
||||
if (pokemon.Types.Contains(iceType))
|
||||
continue;
|
||||
var ignoresHail = false;
|
||||
pokemon.RunScriptHook(x => x.CustomTrigger(CustomTriggers.IgnoreHail,
|
||||
new Dictionary<StringKey, object?>()
|
||||
pokemon.RunScriptHook(x => x.CustomTrigger(CustomTriggers.IgnoreHail, new Dictionary<StringKey, object?>
|
||||
{
|
||||
{ "ignoresHail", ignoresHail },
|
||||
}));
|
||||
|
Loading…
x
Reference in New Issue
Block a user