More moves, allow for typeless moves
This commit is contained in:
parent
807acf1947
commit
068ff8d5b7
@ -1,6 +1,7 @@
|
|||||||
using PkmnLib.Dynamic.Events;
|
using PkmnLib.Dynamic.Events;
|
||||||
using PkmnLib.Dynamic.Models.Choices;
|
using PkmnLib.Dynamic.Models.Choices;
|
||||||
using PkmnLib.Dynamic.ScriptHandling;
|
using PkmnLib.Dynamic.ScriptHandling;
|
||||||
|
using PkmnLib.Static;
|
||||||
using PkmnLib.Static.Moves;
|
using PkmnLib.Static.Moves;
|
||||||
using PkmnLib.Static.Utils;
|
using PkmnLib.Static.Utils;
|
||||||
|
|
||||||
@ -55,7 +56,7 @@ internal static class MoveTurnExecutor
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var executingMove = new ExecutingMoveImpl(targets, numberOfHits, chosenMove, useMove, moveChoice);
|
var executingMove = new ExecutingMoveImpl(targets, numberOfHits, chosenMove, useMove, moveChoice, battle);
|
||||||
|
|
||||||
var prevented = false;
|
var prevented = false;
|
||||||
executingMove.RunScriptHook(x => x.PreventMove(executingMove, ref prevented));
|
executingMove.RunScriptHook(x => x.PreventMove(executingMove, ref prevented));
|
||||||
@ -124,7 +125,7 @@ internal static class MoveTurnExecutor
|
|||||||
executingMove.RunScriptHook(x => x.OnBeforeHit(executingMove, target, hitIndex));
|
executingMove.RunScriptHook(x => x.OnBeforeHit(executingMove, target, hitIndex));
|
||||||
|
|
||||||
var useMove = executingMove.UseMove;
|
var useMove = executingMove.UseMove;
|
||||||
var hitType = useMove.MoveType;
|
var hitType = (TypeIdentifier?)useMove.MoveType;
|
||||||
executingMove.RunScriptHook(x => x.ChangeMoveType(executingMove, target, hitIndex, ref hitType));
|
executingMove.RunScriptHook(x => x.ChangeMoveType(executingMove, target, hitIndex, ref hitType));
|
||||||
|
|
||||||
var hitData = (HitData)executingMove.GetDataFromRawIndex(targetHitStat + i);
|
var hitData = (HitData)executingMove.GetDataFromRawIndex(targetHitStat + i);
|
||||||
@ -134,7 +135,9 @@ internal static class MoveTurnExecutor
|
|||||||
executingMove.RunScriptHook(x => x.ChangeTypesForMove(executingMove, target, hitIndex, types));
|
executingMove.RunScriptHook(x => x.ChangeTypesForMove(executingMove, target, hitIndex, types));
|
||||||
target.RunScriptHook(x => x.ChangeTypesForIncomingMove(executingMove, target, hitIndex, types));
|
target.RunScriptHook(x => x.ChangeTypesForIncomingMove(executingMove, target, hitIndex, types));
|
||||||
|
|
||||||
var effectiveness = battle.Library.StaticLibrary.Types.GetEffectiveness(hitType, types);
|
var effectiveness = hitType == null
|
||||||
|
? 1
|
||||||
|
: battle.Library.StaticLibrary.Types.GetEffectiveness(hitType.Value, types);
|
||||||
executingMove.RunScriptHook(x => x.ChangeEffectiveness(executingMove, target, hitIndex, ref effectiveness));
|
executingMove.RunScriptHook(x => x.ChangeEffectiveness(executingMove, target, hitIndex, ref effectiveness));
|
||||||
target.RunScriptHook(x =>
|
target.RunScriptHook(x =>
|
||||||
x.ChangeIncomingEffectiveness(executingMove, target, hitIndex, ref effectiveness));
|
x.ChangeIncomingEffectiveness(executingMove, target, hitIndex, ref effectiveness));
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using PkmnLib.Dynamic.Events;
|
using PkmnLib.Dynamic.Events;
|
||||||
using PkmnLib.Dynamic.Models.Choices;
|
using PkmnLib.Dynamic.Models.Choices;
|
||||||
using PkmnLib.Dynamic.ScriptHandling;
|
using PkmnLib.Dynamic.ScriptHandling;
|
||||||
|
using PkmnLib.Static;
|
||||||
using PkmnLib.Static.Utils;
|
using PkmnLib.Static.Utils;
|
||||||
|
|
||||||
namespace PkmnLib.Dynamic.Models;
|
namespace PkmnLib.Dynamic.Models;
|
||||||
@ -130,6 +131,21 @@ public interface IBattleSide : IScriptSource, IDeepCloneable
|
|||||||
/// Gets a random Pokémon on the given side.
|
/// Gets a random Pokémon on the given side.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
byte GetRandomPosition();
|
byte GetRandomPosition();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Marks an item as consumed for a position. Can be used by moves such as Recycle to get the item back.
|
||||||
|
/// </summary>
|
||||||
|
void SetConsumedItem(byte battleDataPosition, IItem heldItem);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the last consumed item for a position. Can be used by moves such as Recycle to get the item back.
|
||||||
|
/// </summary>
|
||||||
|
IItem? GetLastConsumedItem(byte battleDataPosition);
|
||||||
|
|
||||||
|
void MarkFaint(byte position);
|
||||||
|
|
||||||
|
uint? GetLastFaintTurn(byte position);
|
||||||
|
uint? GetLastFaintTurn();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="IBattleSide"/>
|
/// <inheritdoc cref="IBattleSide"/>
|
||||||
@ -302,6 +318,42 @@ public class BattleSideImpl : ScriptSource, IBattleSide
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public byte GetRandomPosition() => (byte)Battle.Random.GetInt(0, NumberOfPositions);
|
public byte GetRandomPosition() => (byte)Battle.Random.GetInt(0, NumberOfPositions);
|
||||||
|
|
||||||
|
private Dictionary<byte, IItem>? _lastConsumedItems;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void SetConsumedItem(byte battleDataPosition, IItem heldItem)
|
||||||
|
{
|
||||||
|
_lastConsumedItems ??= new Dictionary<byte, IItem>();
|
||||||
|
_lastConsumedItems[battleDataPosition] = heldItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IItem? GetLastConsumedItem(byte battleDataPosition) =>
|
||||||
|
_lastConsumedItems?.GetValueOrDefault(battleDataPosition);
|
||||||
|
|
||||||
|
private Dictionary<byte, uint>? _lastFaintTurn;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void MarkFaint(byte position)
|
||||||
|
{
|
||||||
|
_lastFaintTurn ??= new Dictionary<byte, uint>();
|
||||||
|
_lastFaintTurn[position] = Battle.CurrentTurnNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public uint? GetLastFaintTurn(byte position)
|
||||||
|
{
|
||||||
|
if (_lastFaintTurn is null)
|
||||||
|
return null;
|
||||||
|
if (_lastFaintTurn.TryGetValue(position, out var turn))
|
||||||
|
return turn;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public uint? GetLastFaintTurn() =>
|
||||||
|
_lastFaintTurn?.Values.Max() ?? null;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override int ScriptCount => 1 + Battle.ScriptCount;
|
public override int ScriptCount => 1 + Battle.ScriptCount;
|
||||||
|
|
||||||
|
@ -33,9 +33,9 @@ public interface IHitData
|
|||||||
uint Damage { get; }
|
uint Damage { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The type of the hit.
|
/// The type of the hit. Null if the move is typeless.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
TypeIdentifier Type { get; }
|
TypeIdentifier? Type { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the hit has failed.
|
/// Whether the hit has failed.
|
||||||
@ -64,7 +64,7 @@ public record HitData : IHitData
|
|||||||
public uint Damage { get; internal set; }
|
public uint Damage { get; internal set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public TypeIdentifier Type { get; internal set; }
|
public TypeIdentifier? Type { get; internal set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool HasFailed { get; private set; }
|
public bool HasFailed { get; private set; }
|
||||||
@ -141,6 +141,8 @@ public interface IExecutingMove : IScriptSource
|
|||||||
IMoveChoice MoveChoice { get; }
|
IMoveChoice MoveChoice { get; }
|
||||||
|
|
||||||
IReadOnlyList<IHitData> Hits { get; }
|
IReadOnlyList<IHitData> Hits { get; }
|
||||||
|
|
||||||
|
IBattle Battle { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="IExecutingMove"/>
|
/// <inheritdoc cref="IExecutingMove"/>
|
||||||
@ -148,16 +150,18 @@ public class ExecutingMoveImpl : ScriptSource, IExecutingMove
|
|||||||
{
|
{
|
||||||
private readonly IReadOnlyList<IPokemon?> _targets;
|
private readonly IReadOnlyList<IPokemon?> _targets;
|
||||||
private readonly IHitData[] _hits;
|
private readonly IHitData[] _hits;
|
||||||
|
private readonly IBattle _battle;
|
||||||
|
|
||||||
/// <inheritdoc cref="ExecutingMoveImpl"/>
|
/// <inheritdoc cref="ExecutingMoveImpl"/>
|
||||||
public ExecutingMoveImpl(IReadOnlyList<IPokemon?> targets, byte numberOfHits, ILearnedMove chosenMove,
|
public ExecutingMoveImpl(IReadOnlyList<IPokemon?> targets, byte numberOfHits, ILearnedMove chosenMove,
|
||||||
IMoveData useMove, IMoveChoice moveChoice)
|
IMoveData useMove, IMoveChoice moveChoice, IBattle battle)
|
||||||
{
|
{
|
||||||
_targets = targets;
|
_targets = targets;
|
||||||
NumberOfHits = numberOfHits;
|
NumberOfHits = numberOfHits;
|
||||||
ChosenMove = chosenMove;
|
ChosenMove = chosenMove;
|
||||||
UseMove = useMove;
|
UseMove = useMove;
|
||||||
MoveChoice = moveChoice;
|
MoveChoice = moveChoice;
|
||||||
|
_battle = battle;
|
||||||
|
|
||||||
var totalHits = targets.Count * numberOfHits;
|
var totalHits = targets.Count * numberOfHits;
|
||||||
_hits = new IHitData[totalHits];
|
_hits = new IHitData[totalHits];
|
||||||
@ -230,6 +234,9 @@ public class ExecutingMoveImpl : ScriptSource, IExecutingMove
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IReadOnlyList<IHitData> Hits => _hits;
|
public IReadOnlyList<IHitData> Hits => _hits;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IBattle Battle => _battle;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override int ScriptCount => 2 + User.ScriptCount;
|
public override int ScriptCount => 2 + User.ScriptCount;
|
||||||
|
|
||||||
|
@ -346,7 +346,7 @@ public interface IPokemon : IScriptSource, IDeepCloneable
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a non-volatile status to the Pokemon.
|
/// Adds a non-volatile status to the Pokemon.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void SetStatus(StringKey status);
|
bool SetStatus(StringKey status);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes the current non-volatile status from the Pokemon.
|
/// Removes the current non-volatile status from the Pokemon.
|
||||||
@ -447,7 +447,7 @@ public interface IPokemonBattleData : IDeepCloneable
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Marks an item as consumed.
|
/// Marks an item as consumed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void MarkItemAsConsumed(IItem itemName);
|
void MarkItemAsConsumed(IItem item);
|
||||||
|
|
||||||
uint SwitchInTurn { get; internal set; }
|
uint SwitchInTurn { get; internal set; }
|
||||||
|
|
||||||
@ -780,6 +780,7 @@ public class PokemonImpl : ScriptSource, IPokemon
|
|||||||
this.RunScriptHook(script => script.PreventHeldItemConsume(this, HeldItem, ref prevented));
|
this.RunScriptHook(script => script.PreventHeldItemConsume(this, HeldItem, ref prevented));
|
||||||
if (prevented)
|
if (prevented)
|
||||||
return false;
|
return false;
|
||||||
|
BattleData.MarkItemAsConsumed(HeldItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: actually consume the item
|
// TODO: actually consume the item
|
||||||
@ -1007,6 +1008,7 @@ public class PokemonImpl : ScriptSource, IPokemon
|
|||||||
{
|
{
|
||||||
BattleData.Battle.Sides[BattleData.SideIndex].MarkPositionAsUnfillable(BattleData.Position);
|
BattleData.Battle.Sides[BattleData.SideIndex].MarkPositionAsUnfillable(BattleData.Position);
|
||||||
}
|
}
|
||||||
|
BattleData.BattleSide.MarkFaint(BattleData.Position);
|
||||||
|
|
||||||
// Validate the battle state to see if the battle is over.
|
// Validate the battle state to see if the battle is over.
|
||||||
BattleData.Battle.ValidateBattleState();
|
BattleData.Battle.ValidateBattleState();
|
||||||
@ -1078,11 +1080,12 @@ public class PokemonImpl : ScriptSource, IPokemon
|
|||||||
public bool HasStatus(StringKey status) => StatusScript.Script?.Name == status;
|
public bool HasStatus(StringKey status) => StatusScript.Script?.Name == status;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void SetStatus(StringKey status)
|
public bool SetStatus(StringKey status)
|
||||||
{
|
{
|
||||||
if (!Library.ScriptResolver.TryResolve(ScriptCategory.Status, status, null, out var statusScript))
|
if (!Library.ScriptResolver.TryResolve(ScriptCategory.Status, status, null, out var statusScript))
|
||||||
throw new KeyNotFoundException($"Status script {status} not found");
|
throw new KeyNotFoundException($"Status script {status} not found");
|
||||||
StatusScript.Set(statusScript);
|
StatusScript.Set(statusScript);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -1255,9 +1258,10 @@ public class PokemonBattleDataImpl : IPokemonBattleData
|
|||||||
public IReadOnlyList<IItem> ConsumedItems => _consumedItems;
|
public IReadOnlyList<IItem> ConsumedItems => _consumedItems;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void MarkItemAsConsumed(IItem itemName)
|
public void MarkItemAsConsumed(IItem item)
|
||||||
{
|
{
|
||||||
_consumedItems.Add(itemName);
|
_consumedItems.Add(item);
|
||||||
|
BattleSide.SetConsumedItem(Position, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -216,8 +216,10 @@ public abstract class Script : IDeepCloneable
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This function allows the script to change the actual type that is used for the move on a target.
|
/// This function allows the script to change the actual type that is used for the move on a target.
|
||||||
|
/// If this is set to null, the move will be treated as a typeless move.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier moveType)
|
public virtual void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit,
|
||||||
|
ref TypeIdentifier? typeIdentifier)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -601,20 +603,35 @@ public abstract class Script : IDeepCloneable
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This function allows a script to change the types a target has. Multiple types can be set, and will be used
|
||||||
|
/// for the effectiveness calculation.
|
||||||
|
/// </summary>
|
||||||
public virtual void ChangeTypesForMove(IExecutingMove executingMove, IPokemon target, byte hitIndex,
|
public virtual void ChangeTypesForMove(IExecutingMove executingMove, IPokemon target, byte hitIndex,
|
||||||
IList<TypeIdentifier> types)
|
IList<TypeIdentifier> types)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This function allows a script to change the types a Pokemon has for a move that's incoming. Multiple types can
|
||||||
|
/// be set, and will be used for the effectiveness calculation.
|
||||||
|
/// </summary>
|
||||||
public virtual void ChangeTypesForIncomingMove(IExecutingMove executingMove, IPokemon target, byte hitIndex,
|
public virtual void ChangeTypesForIncomingMove(IExecutingMove executingMove, IPokemon target, byte hitIndex,
|
||||||
IList<TypeIdentifier> types)
|
IList<TypeIdentifier> types)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This function allows a script to change the handling of the move category. This is used for moves that
|
||||||
|
/// are sometimes a status move, and sometimes a damaging move, such as pollen puff.
|
||||||
|
/// </summary>
|
||||||
public virtual void ChangeCategory(IExecutingMove move, IPokemon target, byte hitIndex, ref MoveCategory category)
|
public virtual void ChangeCategory(IExecutingMove move, IPokemon target, byte hitIndex, ref MoveCategory category)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Triggers first when we're about to hit a target.
|
||||||
|
/// </summary>
|
||||||
public virtual void OnBeforeHit(IExecutingMove move, IPokemon target, byte hitIndex)
|
public virtual void OnBeforeHit(IExecutingMove move, IPokemon target, byte hitIndex)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -8763,7 +8763,10 @@
|
|||||||
"category": "status",
|
"category": "status",
|
||||||
"flags": [
|
"flags": [
|
||||||
"snatch"
|
"snatch"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "recycle"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "reflect",
|
"name": "reflect",
|
||||||
@ -8776,7 +8779,10 @@
|
|||||||
"category": "status",
|
"category": "status",
|
||||||
"flags": [
|
"flags": [
|
||||||
"snatch"
|
"snatch"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "reflect"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "reflect_type",
|
"name": "reflect_type",
|
||||||
@ -8790,7 +8796,10 @@
|
|||||||
"flags": [
|
"flags": [
|
||||||
"protect",
|
"protect",
|
||||||
"ignore-substitute"
|
"ignore-substitute"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "reflect_type"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "refresh",
|
"name": "refresh",
|
||||||
@ -8803,7 +8812,10 @@
|
|||||||
"category": "status",
|
"category": "status",
|
||||||
"flags": [
|
"flags": [
|
||||||
"snatch"
|
"snatch"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "refresh"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "relic_song",
|
"name": "relic_song",
|
||||||
@ -8819,7 +8831,14 @@
|
|||||||
"mirror",
|
"mirror",
|
||||||
"sound",
|
"sound",
|
||||||
"ignore-substitute"
|
"ignore-substitute"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "set_status",
|
||||||
|
"chance": 10,
|
||||||
|
"parameters": {
|
||||||
|
"status": "sleep"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "rest",
|
"name": "rest",
|
||||||
@ -8833,7 +8852,10 @@
|
|||||||
"flags": [
|
"flags": [
|
||||||
"snatch",
|
"snatch",
|
||||||
"heal"
|
"heal"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "rest"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "retaliate",
|
"name": "retaliate",
|
||||||
@ -8848,7 +8870,10 @@
|
|||||||
"contact",
|
"contact",
|
||||||
"protect",
|
"protect",
|
||||||
"mirror"
|
"mirror"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "retaliate"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "return",
|
"name": "return",
|
||||||
@ -8863,7 +8888,10 @@
|
|||||||
"contact",
|
"contact",
|
||||||
"protect",
|
"protect",
|
||||||
"mirror"
|
"mirror"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "return"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "revelation_dance",
|
"name": "revelation_dance",
|
||||||
@ -8878,7 +8906,10 @@
|
|||||||
"protect",
|
"protect",
|
||||||
"mirror",
|
"mirror",
|
||||||
"dance"
|
"dance"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "revelation_dance"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "revenge",
|
"name": "revenge",
|
||||||
@ -8893,7 +8924,10 @@
|
|||||||
"contact",
|
"contact",
|
||||||
"protect",
|
"protect",
|
||||||
"mirror"
|
"mirror"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "double_power_if_target_damaged_in_turn"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "reversal",
|
"name": "reversal",
|
||||||
@ -8908,7 +8942,10 @@
|
|||||||
"contact",
|
"contact",
|
||||||
"protect",
|
"protect",
|
||||||
"mirror"
|
"mirror"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "flail"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "roar",
|
"name": "roar",
|
||||||
@ -8924,7 +8961,10 @@
|
|||||||
"mirror",
|
"mirror",
|
||||||
"sound",
|
"sound",
|
||||||
"ignore-substitute"
|
"ignore-substitute"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "roar"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "roar_of_time",
|
"name": "roar_of_time",
|
||||||
@ -8939,7 +8979,10 @@
|
|||||||
"recharge",
|
"recharge",
|
||||||
"protect",
|
"protect",
|
||||||
"mirror"
|
"mirror"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "requires_recharge"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "rock_blast",
|
"name": "rock_blast",
|
||||||
@ -8953,7 +8996,10 @@
|
|||||||
"flags": [
|
"flags": [
|
||||||
"protect",
|
"protect",
|
||||||
"mirror"
|
"mirror"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "2_5_hit_move"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "rock_climb",
|
"name": "rock_climb",
|
||||||
@ -8968,7 +9014,11 @@
|
|||||||
"contact",
|
"contact",
|
||||||
"protect",
|
"protect",
|
||||||
"mirror"
|
"mirror"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "confuse",
|
||||||
|
"chance": 20
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "rock_polish",
|
"name": "rock_polish",
|
||||||
@ -8981,7 +9031,13 @@
|
|||||||
"category": "status",
|
"category": "status",
|
||||||
"flags": [
|
"flags": [
|
||||||
"snatch"
|
"snatch"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "change_user_speed",
|
||||||
|
"parameters": {
|
||||||
|
"amount": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "rock_slide",
|
"name": "rock_slide",
|
||||||
@ -8995,7 +9051,11 @@
|
|||||||
"flags": [
|
"flags": [
|
||||||
"protect",
|
"protect",
|
||||||
"mirror"
|
"mirror"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "flinch",
|
||||||
|
"chance": 30
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "rock_smash",
|
"name": "rock_smash",
|
||||||
@ -9010,7 +9070,14 @@
|
|||||||
"contact",
|
"contact",
|
||||||
"protect",
|
"protect",
|
||||||
"mirror"
|
"mirror"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "change_target_defense",
|
||||||
|
"chance": 50,
|
||||||
|
"parameters": {
|
||||||
|
"amount": -1
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "rock_throw",
|
"name": "rock_throw",
|
||||||
@ -9025,6 +9092,7 @@
|
|||||||
"protect",
|
"protect",
|
||||||
"mirror"
|
"mirror"
|
||||||
]
|
]
|
||||||
|
// No secondary effect
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "rock_tomb",
|
"name": "rock_tomb",
|
||||||
@ -9038,7 +9106,14 @@
|
|||||||
"flags": [
|
"flags": [
|
||||||
"protect",
|
"protect",
|
||||||
"mirror"
|
"mirror"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "change_target_speed",
|
||||||
|
"chance": 100,
|
||||||
|
"parameters": {
|
||||||
|
"amount": -1
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "rock_wrecker",
|
"name": "rock_wrecker",
|
||||||
@ -9053,7 +9128,10 @@
|
|||||||
"recharge",
|
"recharge",
|
||||||
"protect",
|
"protect",
|
||||||
"mirror"
|
"mirror"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "requires_recharge"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "role_play",
|
"name": "role_play",
|
||||||
@ -9066,7 +9144,10 @@
|
|||||||
"category": "status",
|
"category": "status",
|
||||||
"flags": [
|
"flags": [
|
||||||
"ignore-substitute"
|
"ignore-substitute"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "role_play"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "rolling_kick",
|
"name": "rolling_kick",
|
||||||
@ -9081,7 +9162,11 @@
|
|||||||
"contact",
|
"contact",
|
||||||
"protect",
|
"protect",
|
||||||
"mirror"
|
"mirror"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "flinch",
|
||||||
|
"chance": 30
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "rollout",
|
"name": "rollout",
|
||||||
@ -9096,7 +9181,10 @@
|
|||||||
"contact",
|
"contact",
|
||||||
"protect",
|
"protect",
|
||||||
"mirror"
|
"mirror"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "ice_ball"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "roost",
|
"name": "roost",
|
||||||
@ -9110,7 +9198,10 @@
|
|||||||
"flags": [
|
"flags": [
|
||||||
"snatch",
|
"snatch",
|
||||||
"heal"
|
"heal"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "roost"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "rototiller",
|
"name": "rototiller",
|
||||||
@ -9124,7 +9215,10 @@
|
|||||||
"flags": [
|
"flags": [
|
||||||
"distance",
|
"distance",
|
||||||
"nonskybattle"
|
"nonskybattle"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "rototiller"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "round",
|
"name": "round",
|
||||||
|
@ -59,12 +59,12 @@ public class HiddenPowerTests
|
|||||||
staticLibrary.Setup(x => x.Types).Returns(typeLibrary);
|
staticLibrary.Setup(x => x.Types).Returns(typeLibrary);
|
||||||
dynamicLibrary.Setup(x => x.StaticLibrary).Returns(staticLibrary.Object);
|
dynamicLibrary.Setup(x => x.StaticLibrary).Returns(staticLibrary.Object);
|
||||||
|
|
||||||
var moveType = new TypeIdentifier(1, "normal");
|
TypeIdentifier? moveType = new TypeIdentifier(1, "normal");
|
||||||
|
|
||||||
var hiddenPower = new HiddenPower();
|
var hiddenPower = new HiddenPower();
|
||||||
hiddenPower.ChangeMoveType(executingMove.Object, target.Object, 0, ref moveType);
|
hiddenPower.ChangeMoveType(executingMove.Object, target.Object, 0, ref moveType);
|
||||||
|
|
||||||
await Assert.That(moveType.Name).IsEqualTo(test.ExpectedType);
|
await Assert.That(moveType!.Value.Name).IsEqualTo(test.ExpectedType);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, MethodDataSource(nameof(HiddenPowerTestData))]
|
[Test, MethodDataSource(nameof(HiddenPowerTestData))]
|
||||||
|
@ -63,7 +63,7 @@ public class MultiAttackTests
|
|||||||
var move = new Mock<IExecutingMove>();
|
var move = new Mock<IExecutingMove>();
|
||||||
var target = new Mock<IPokemon>();
|
var target = new Mock<IPokemon>();
|
||||||
var user = new Mock<IPokemon>();
|
var user = new Mock<IPokemon>();
|
||||||
var typeIdentifier = new TypeIdentifier(1, "Normal");
|
TypeIdentifier? typeIdentifier = new TypeIdentifier(1, "Normal");
|
||||||
var dynamicLibrary = new Mock<IDynamicLibrary>();
|
var dynamicLibrary = new Mock<IDynamicLibrary>();
|
||||||
var staticLibrary = new Mock<IStaticLibrary>();
|
var staticLibrary = new Mock<IStaticLibrary>();
|
||||||
var item = new Mock<IItem>();
|
var item = new Mock<IItem>();
|
||||||
@ -84,6 +84,6 @@ public class MultiAttackTests
|
|||||||
multiAttack.ChangeMoveType(move.Object, target.Object, 0, ref typeIdentifier);
|
multiAttack.ChangeMoveType(move.Object, target.Object, 0, ref typeIdentifier);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
await Assert.That(typeIdentifier.Name).IsEqualTo(test.ExpectedTypeName);
|
await Assert.That(typeIdentifier!.Value.Name).IsEqualTo(test.ExpectedTypeName);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -47,7 +47,7 @@ public class Gen7DamageCalculator(bool hasRandomness) : IDamageCalculator
|
|||||||
floatDamage = MathF.Floor(floatDamage * randomFactor);
|
floatDamage = MathF.Floor(floatDamage * randomFactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (executingMove.User.Types.Contains(hitData.Type))
|
if (hitData.Type != null && executingMove.User.Types.Contains(hitData.Type.Value))
|
||||||
{
|
{
|
||||||
var stabModifier = 1.5f;
|
var stabModifier = 1.5f;
|
||||||
executingMove.RunScriptHook(script =>
|
executingMove.RunScriptHook(script =>
|
||||||
|
@ -25,7 +25,7 @@ public class FutureSightEffect : Script
|
|||||||
}
|
}
|
||||||
var damageCalculator = battle.Library.DamageCalculator;
|
var damageCalculator = battle.Library.DamageCalculator;
|
||||||
var executingMove = new ExecutingMoveImpl([target], 1, _moveChoice.ChosenMove,
|
var executingMove = new ExecutingMoveImpl([target], 1, _moveChoice.ChosenMove,
|
||||||
_moveChoice.ChosenMove.MoveData, _moveChoice);
|
_moveChoice.ChosenMove.MoveData, _moveChoice, battle);
|
||||||
var hitData = executingMove.GetHitData(target, 0);
|
var hitData = executingMove.GetHitData(target, 0);
|
||||||
var damage = damageCalculator.GetDamage(executingMove, target, 1, hitData);
|
var damage = damageCalculator.GetDamage(executingMove, target, 1, hitData);
|
||||||
|
|
||||||
|
@ -6,9 +6,9 @@ namespace PkmnLib.Plugin.Gen7.Scripts.Battle;
|
|||||||
public class IonDelugeEffect : Script
|
public class IonDelugeEffect : Script
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier moveType)
|
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier? moveType)
|
||||||
{
|
{
|
||||||
if (moveType.Name == "normal" &&
|
if (moveType?.Name == "normal" &&
|
||||||
target.Library.StaticLibrary.Types.TryGetTypeIdentifier("electric", out var electricType))
|
target.Library.StaticLibrary.Types.TryGetTypeIdentifier("electric", out var electricType))
|
||||||
{
|
{
|
||||||
moveType = electricType;
|
moveType = electricType;
|
||||||
|
@ -13,4 +13,6 @@ public static class CustomTriggers
|
|||||||
public static readonly StringKey IgnoreHail = "ignores_hail";
|
public static readonly StringKey IgnoreHail = "ignores_hail";
|
||||||
|
|
||||||
public static readonly StringKey LightScreenNumberOfTurns = "light_screen_number_of_turns";
|
public static readonly StringKey LightScreenNumberOfTurns = "light_screen_number_of_turns";
|
||||||
|
|
||||||
|
public static readonly StringKey ReflectNumberOfTurns = "reflect_number_of_turns";
|
||||||
}
|
}
|
@ -6,7 +6,7 @@ namespace PkmnLib.Plugin.Gen7.Scripts.MoveVolatile;
|
|||||||
public class ElectrifyEffect : Script
|
public class ElectrifyEffect : Script
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier moveType)
|
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier? moveType)
|
||||||
{
|
{
|
||||||
var battleData = target.BattleData;
|
var battleData = target.BattleData;
|
||||||
if (battleData == null)
|
if (battleData == null)
|
||||||
|
@ -7,13 +7,14 @@ namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
|||||||
public class HiddenPower : Script
|
public class HiddenPower : Script
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier moveType)
|
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier? moveType)
|
||||||
{
|
{
|
||||||
var ivs = move.User.IndividualValues;
|
var ivs = move.User.IndividualValues;
|
||||||
|
|
||||||
var type = GetHiddenPowerValue(ivs, 0x00000001) * 15 / 63;
|
var type = GetHiddenPowerValue(ivs, 0x00000001) * 15 / 63;
|
||||||
|
|
||||||
move.User.Library.StaticLibrary.Types.TryGetTypeIdentifierFromIndex((byte)(type + 2), out moveType);
|
if (move.User.Library.StaticLibrary.Types.TryGetTypeIdentifierFromIndex((byte)(type + 2), out var t))
|
||||||
|
moveType = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -6,7 +6,7 @@ namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
|||||||
public class Judgement : Script
|
public class Judgement : Script
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier moveType)
|
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier? moveType)
|
||||||
{
|
{
|
||||||
var heldItem = move.User.HeldItem;
|
var heldItem = move.User.HeldItem;
|
||||||
if (heldItem == null)
|
if (heldItem == null)
|
||||||
|
@ -6,7 +6,7 @@ namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
|||||||
public class MultiAttack : Script
|
public class MultiAttack : Script
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier moveType)
|
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier? moveType)
|
||||||
{
|
{
|
||||||
var item = move.User.HeldItem?.Name.ToString();
|
var item = move.User.HeldItem?.Name.ToString();
|
||||||
var typeLibrary = move.User.Library.StaticLibrary.Types;
|
var typeLibrary = move.User.Library.StaticLibrary.Types;
|
||||||
@ -15,6 +15,7 @@ public class MultiAttack : Script
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var memoryType = item[..^7];
|
var memoryType = item[..^7];
|
||||||
typeLibrary.TryGetTypeIdentifier(memoryType, out moveType);
|
if (typeLibrary.TryGetTypeIdentifier(memoryType, out var t))
|
||||||
|
moveType = t;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -20,7 +20,7 @@ public class NaturalGift : Script
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier moveType)
|
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier? moveType)
|
||||||
{
|
{
|
||||||
var naturalGiftData = GetNaturalGiftData(move.User.HeldItem);
|
var naturalGiftData = GetNaturalGiftData(move.User.HeldItem);
|
||||||
if (naturalGiftData == null)
|
if (naturalGiftData == null)
|
||||||
|
25
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Recycle.cs
Normal file
25
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Recycle.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Move, "recycle")]
|
||||||
|
public class Recycle : Script
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||||
|
{
|
||||||
|
if (move.User.HeldItem is not null)
|
||||||
|
{
|
||||||
|
move.GetHitData(target, hit).Fail();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var battleData = move.User.BattleData;
|
||||||
|
if (battleData is null)
|
||||||
|
return;
|
||||||
|
var lastItem = battleData.BattleSide.GetLastConsumedItem(battleData.Position);
|
||||||
|
if (lastItem is null)
|
||||||
|
{
|
||||||
|
move.GetHitData(target, hit).Fail();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_ = move.User.SetHeldItem(lastItem);
|
||||||
|
}
|
||||||
|
}
|
25
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Reflect.cs
Normal file
25
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Reflect.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using PkmnLib.Static.Utils;
|
||||||
|
|
||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Move, "reflect")]
|
||||||
|
public class Reflect : Script
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||||
|
{
|
||||||
|
var battleData = move.User.BattleData;
|
||||||
|
if (battleData is null)
|
||||||
|
return;
|
||||||
|
var numberOfTurns = 5;
|
||||||
|
var dict = new Dictionary<StringKey, object?>
|
||||||
|
{
|
||||||
|
{ "duration", numberOfTurns },
|
||||||
|
};
|
||||||
|
move.User.RunScriptHook(x => x.CustomTrigger(CustomTriggers.ReflectNumberOfTurns, dict));
|
||||||
|
numberOfTurns = (int)dict.GetOrDefault("duration", numberOfTurns)!;
|
||||||
|
|
||||||
|
battleData.BattleSide.VolatileScripts.Add(new Side.ReflectEffect(numberOfTurns));
|
||||||
|
}
|
||||||
|
}
|
12
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ReflectType.cs
Normal file
12
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/ReflectType.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Move, "reflect_type")]
|
||||||
|
public class ReflectType : Script
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||||
|
{
|
||||||
|
var targetTypes = target.Types;
|
||||||
|
move.User.SetTypes(targetTypes);
|
||||||
|
}
|
||||||
|
}
|
23
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Refresh.cs
Normal file
23
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Refresh.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Move, "refresh")]
|
||||||
|
public class Refresh : Script
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||||
|
{
|
||||||
|
var userStatus = move.User.StatusScript;
|
||||||
|
switch (userStatus.Script?.Name)
|
||||||
|
{
|
||||||
|
case "paralyzed":
|
||||||
|
case "burned":
|
||||||
|
case "poisoned":
|
||||||
|
case "badly_poisoned":
|
||||||
|
move.User.ClearStatus();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
move.GetHitData(target, hit).Fail();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Rest.cs
Normal file
24
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Rest.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using PkmnLib.Plugin.Gen7.Scripts.Status;
|
||||||
|
|
||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Move, "rest")]
|
||||||
|
public class Rest : Script
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||||
|
{
|
||||||
|
if (move.User.HasStatus(ScriptUtils.ResolveName<Sleep>()))
|
||||||
|
{
|
||||||
|
move.GetHitData(target, hit).Fail();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!move.User.Heal(move.User.MaxHealth, false, forceHeal: false))
|
||||||
|
{
|
||||||
|
move.GetHitData(target, hit).Fail();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
move.User.SetStatus(ScriptUtils.ResolveName<Sleep>());
|
||||||
|
((Sleep)move.User.StatusScript.Script!).Turns = 2;
|
||||||
|
}
|
||||||
|
}
|
24
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Retaliate.cs
Normal file
24
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Retaliate.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using PkmnLib.Static.Utils;
|
||||||
|
|
||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Move, "retaliate")]
|
||||||
|
public class Retaliate : Script
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref byte basePower)
|
||||||
|
{
|
||||||
|
var battleData = move.User.BattleData;
|
||||||
|
if (battleData is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var lastFaint = battleData.BattleSide.GetLastFaintTurn();
|
||||||
|
if (lastFaint == null)
|
||||||
|
return;
|
||||||
|
if (lastFaint >= battleData.Battle.CurrentTurnNumber - 1)
|
||||||
|
{
|
||||||
|
basePower = basePower.MultiplyOrMax(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Return.cs
Normal file
17
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Return.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Move, "return")]
|
||||||
|
public class Return : Script
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref byte basePower)
|
||||||
|
{
|
||||||
|
var friendship = move.User.Happiness;
|
||||||
|
var power = friendship * 2 / 5;
|
||||||
|
// The power is capped at 102, but as friendship is a byte, and thus max 255, this is already heuristically
|
||||||
|
// capped (255 * 2 / 5 = 102).
|
||||||
|
if (power < 1)
|
||||||
|
power = 1;
|
||||||
|
basePower = (byte)power;
|
||||||
|
}
|
||||||
|
}
|
25
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/RevelationDance.cs
Normal file
25
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/RevelationDance.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using PkmnLib.Static;
|
||||||
|
|
||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Move, "revelation_dance")]
|
||||||
|
public class RevelationDance : Script
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier? moveType)
|
||||||
|
{
|
||||||
|
// The type of the move is the same as the user's first type.
|
||||||
|
var user = move.User;
|
||||||
|
if (user.Types.Count > 0)
|
||||||
|
{
|
||||||
|
moveType = user.Types[0];
|
||||||
|
}
|
||||||
|
// If the user has no types, the move is typeless.
|
||||||
|
else
|
||||||
|
{
|
||||||
|
moveType = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Roar.cs
Normal file
7
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Roar.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Move, "roar")]
|
||||||
|
public class Roar : Script
|
||||||
|
{
|
||||||
|
// FIXME: Implement roar
|
||||||
|
}
|
17
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/RolePlay.cs
Normal file
17
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/RolePlay.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Move, "role_play")]
|
||||||
|
public class RolePlay : Script
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||||
|
{
|
||||||
|
var ability = target.ActiveAbility;
|
||||||
|
if (ability is null || ability.HasFlag("cant_be_copied"))
|
||||||
|
{
|
||||||
|
move.GetHitData(target, hit).Fail();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
move.User.ChangeAbility(ability);
|
||||||
|
}
|
||||||
|
}
|
14
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Roost.cs
Normal file
14
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Roost.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||||
|
|
||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Move, "roost")]
|
||||||
|
public class Roost : Script
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||||
|
{
|
||||||
|
target.Heal(target.MaxHealth / 2);
|
||||||
|
target.Volatile.Add(new RoostEffect());
|
||||||
|
}
|
||||||
|
}
|
22
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Rototiller.cs
Normal file
22
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/Rototiller.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using PkmnLib.Static;
|
||||||
|
using PkmnLib.Static.Utils;
|
||||||
|
|
||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Move, "rototiller")]
|
||||||
|
public class Rototiller : Script
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||||
|
{
|
||||||
|
var pokemon = move.Battle.Sides.SelectMany(x => x.Pokemon).WhereNotNull()
|
||||||
|
.Where(x => x.Types.Any(y => y.Name == "grass"));
|
||||||
|
EventBatchId batchId = new();
|
||||||
|
foreach (var pkmn in pokemon)
|
||||||
|
{
|
||||||
|
pkmn.ChangeStatBoost(Statistic.Attack, 1, pkmn == move.User, batchId);
|
||||||
|
pkmn.ChangeStatBoost(Statistic.SpecialAttack, 1, pkmn == move.User, batchId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -10,7 +10,7 @@ public class PowderEffect : Script
|
|||||||
public override void BlockOutgoingHit(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref bool block)
|
public override void BlockOutgoingHit(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref bool block)
|
||||||
{
|
{
|
||||||
var hit = executingMove.GetHitData(target, hitIndex);
|
var hit = executingMove.GetHitData(target, hitIndex);
|
||||||
if (hit.Type.Name == "fire")
|
if (hit.Type?.Name == "fire")
|
||||||
{
|
{
|
||||||
executingMove.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("powder_explodes",
|
executingMove.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("powder_explodes",
|
||||||
new Dictionary<string, object>
|
new Dictionary<string, object>
|
||||||
|
19
Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/RoostEffect.cs
Normal file
19
Plugins/PkmnLib.Plugin.Gen7/Scripts/Pokemon/RoostEffect.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using PkmnLib.Static;
|
||||||
|
using PkmnLib.Static.Utils;
|
||||||
|
|
||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Pokemon, "roost_effect")]
|
||||||
|
public class RoostEffect : Script
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void ChangeTypesForIncomingMove(IExecutingMove executingMove, IPokemon target, byte hitIndex,
|
||||||
|
IList<TypeIdentifier> types)
|
||||||
|
{
|
||||||
|
types.RemoveAll(x => x.Name == "flying");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnEndTurn(IBattle battle) => RemoveSelf();
|
||||||
|
}
|
@ -1,7 +1,40 @@
|
|||||||
|
using PkmnLib.Static.Moves;
|
||||||
|
|
||||||
namespace PkmnLib.Plugin.Gen7.Scripts.Side;
|
namespace PkmnLib.Plugin.Gen7.Scripts.Side;
|
||||||
|
|
||||||
[Script(ScriptCategory.Side, "reflect")]
|
[Script(ScriptCategory.Side, "reflect")]
|
||||||
public class ReflectEffect : Script
|
public class ReflectEffect(int turns) : Script
|
||||||
{
|
{
|
||||||
// TODO: Implement ReflectEffect
|
private int _turns = turns;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void ChangeIncomingMoveDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage)
|
||||||
|
{
|
||||||
|
var hitData = move.GetHitData(target, hit);
|
||||||
|
if (move.UseMove.Category != MoveCategory.Physical)
|
||||||
|
return;
|
||||||
|
if (hitData.IsCritical)
|
||||||
|
return;
|
||||||
|
switch (move.Battle.PositionsPerSide)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
damage /= 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
damage *= 2 / 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnEndTurn(IBattle battle)
|
||||||
|
{
|
||||||
|
if (_turns > 0)
|
||||||
|
{
|
||||||
|
_turns--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveSelf();
|
||||||
|
}
|
||||||
}
|
}
|
@ -3,4 +3,5 @@ namespace PkmnLib.Plugin.Gen7.Scripts.Status;
|
|||||||
[Script(ScriptCategory.Status, "sleep")]
|
[Script(ScriptCategory.Status, "sleep")]
|
||||||
public class Sleep : Script
|
public class Sleep : Script
|
||||||
{
|
{
|
||||||
|
public int Turns { get; set; }
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user