More moves, allow for typeless moves
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using PkmnLib.Dynamic.Events;
|
||||
using PkmnLib.Dynamic.Models.Choices;
|
||||
using PkmnLib.Dynamic.ScriptHandling;
|
||||
using PkmnLib.Static;
|
||||
using PkmnLib.Static.Moves;
|
||||
using PkmnLib.Static.Utils;
|
||||
|
||||
@@ -55,7 +56,7 @@ internal static class MoveTurnExecutor
|
||||
return;
|
||||
}
|
||||
|
||||
var executingMove = new ExecutingMoveImpl(targets, numberOfHits, chosenMove, useMove, moveChoice);
|
||||
var executingMove = new ExecutingMoveImpl(targets, numberOfHits, chosenMove, useMove, moveChoice, battle);
|
||||
|
||||
var prevented = false;
|
||||
executingMove.RunScriptHook(x => x.PreventMove(executingMove, ref prevented));
|
||||
@@ -124,7 +125,7 @@ internal static class MoveTurnExecutor
|
||||
executingMove.RunScriptHook(x => x.OnBeforeHit(executingMove, target, hitIndex));
|
||||
|
||||
var useMove = executingMove.UseMove;
|
||||
var hitType = useMove.MoveType;
|
||||
var hitType = (TypeIdentifier?)useMove.MoveType;
|
||||
executingMove.RunScriptHook(x => x.ChangeMoveType(executingMove, target, hitIndex, ref hitType));
|
||||
|
||||
var hitData = (HitData)executingMove.GetDataFromRawIndex(targetHitStat + i);
|
||||
@@ -134,7 +135,9 @@ internal static class MoveTurnExecutor
|
||||
executingMove.RunScriptHook(x => x.ChangeTypesForMove(executingMove, target, hitIndex, types));
|
||||
target.RunScriptHook(x => x.ChangeTypesForIncomingMove(executingMove, target, hitIndex, types));
|
||||
|
||||
var effectiveness = battle.Library.StaticLibrary.Types.GetEffectiveness(hitType, types);
|
||||
var effectiveness = hitType == null
|
||||
? 1
|
||||
: battle.Library.StaticLibrary.Types.GetEffectiveness(hitType.Value, types);
|
||||
executingMove.RunScriptHook(x => x.ChangeEffectiveness(executingMove, target, hitIndex, ref effectiveness));
|
||||
target.RunScriptHook(x =>
|
||||
x.ChangeIncomingEffectiveness(executingMove, target, hitIndex, ref effectiveness));
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using PkmnLib.Dynamic.Events;
|
||||
using PkmnLib.Dynamic.Models.Choices;
|
||||
using PkmnLib.Dynamic.ScriptHandling;
|
||||
using PkmnLib.Static;
|
||||
using PkmnLib.Static.Utils;
|
||||
|
||||
namespace PkmnLib.Dynamic.Models;
|
||||
@@ -130,6 +131,21 @@ public interface IBattleSide : IScriptSource, IDeepCloneable
|
||||
/// Gets a random Pokémon on the given side.
|
||||
/// </summary>
|
||||
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"/>
|
||||
@@ -302,6 +318,42 @@ public class BattleSideImpl : ScriptSource, IBattleSide
|
||||
/// <inheritdoc />
|
||||
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 />
|
||||
public override int ScriptCount => 1 + Battle.ScriptCount;
|
||||
|
||||
|
||||
@@ -33,9 +33,9 @@ public interface IHitData
|
||||
uint Damage { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The type of the hit.
|
||||
/// The type of the hit. Null if the move is typeless.
|
||||
/// </summary>
|
||||
TypeIdentifier Type { get; }
|
||||
TypeIdentifier? Type { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the hit has failed.
|
||||
@@ -64,7 +64,7 @@ public record HitData : IHitData
|
||||
public uint Damage { get; internal set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public TypeIdentifier Type { get; internal set; }
|
||||
public TypeIdentifier? Type { get; internal set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasFailed { get; private set; }
|
||||
@@ -141,6 +141,8 @@ public interface IExecutingMove : IScriptSource
|
||||
IMoveChoice MoveChoice { get; }
|
||||
|
||||
IReadOnlyList<IHitData> Hits { get; }
|
||||
|
||||
IBattle Battle { get; }
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IExecutingMove"/>
|
||||
@@ -148,16 +150,18 @@ public class ExecutingMoveImpl : ScriptSource, IExecutingMove
|
||||
{
|
||||
private readonly IReadOnlyList<IPokemon?> _targets;
|
||||
private readonly IHitData[] _hits;
|
||||
private readonly IBattle _battle;
|
||||
|
||||
/// <inheritdoc cref="ExecutingMoveImpl"/>
|
||||
public ExecutingMoveImpl(IReadOnlyList<IPokemon?> targets, byte numberOfHits, ILearnedMove chosenMove,
|
||||
IMoveData useMove, IMoveChoice moveChoice)
|
||||
IMoveData useMove, IMoveChoice moveChoice, IBattle battle)
|
||||
{
|
||||
_targets = targets;
|
||||
NumberOfHits = numberOfHits;
|
||||
ChosenMove = chosenMove;
|
||||
UseMove = useMove;
|
||||
MoveChoice = moveChoice;
|
||||
_battle = battle;
|
||||
|
||||
var totalHits = targets.Count * numberOfHits;
|
||||
_hits = new IHitData[totalHits];
|
||||
@@ -230,6 +234,9 @@ public class ExecutingMoveImpl : ScriptSource, IExecutingMove
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<IHitData> Hits => _hits;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IBattle Battle => _battle;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int ScriptCount => 2 + User.ScriptCount;
|
||||
|
||||
|
||||
@@ -346,7 +346,7 @@ public interface IPokemon : IScriptSource, IDeepCloneable
|
||||
/// <summary>
|
||||
/// Adds a non-volatile status to the Pokemon.
|
||||
/// </summary>
|
||||
void SetStatus(StringKey status);
|
||||
bool SetStatus(StringKey status);
|
||||
|
||||
/// <summary>
|
||||
/// Removes the current non-volatile status from the Pokemon.
|
||||
@@ -447,7 +447,7 @@ public interface IPokemonBattleData : IDeepCloneable
|
||||
/// <summary>
|
||||
/// Marks an item as consumed.
|
||||
/// </summary>
|
||||
void MarkItemAsConsumed(IItem itemName);
|
||||
void MarkItemAsConsumed(IItem item);
|
||||
|
||||
uint SwitchInTurn { get; internal set; }
|
||||
|
||||
@@ -780,6 +780,7 @@ public class PokemonImpl : ScriptSource, IPokemon
|
||||
this.RunScriptHook(script => script.PreventHeldItemConsume(this, HeldItem, ref prevented));
|
||||
if (prevented)
|
||||
return false;
|
||||
BattleData.MarkItemAsConsumed(HeldItem);
|
||||
}
|
||||
|
||||
// TODO: actually consume the item
|
||||
@@ -1007,6 +1008,7 @@ public class PokemonImpl : ScriptSource, IPokemon
|
||||
{
|
||||
BattleData.Battle.Sides[BattleData.SideIndex].MarkPositionAsUnfillable(BattleData.Position);
|
||||
}
|
||||
BattleData.BattleSide.MarkFaint(BattleData.Position);
|
||||
|
||||
// Validate the battle state to see if the battle is over.
|
||||
BattleData.Battle.ValidateBattleState();
|
||||
@@ -1078,11 +1080,12 @@ public class PokemonImpl : ScriptSource, IPokemon
|
||||
public bool HasStatus(StringKey status) => StatusScript.Script?.Name == status;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetStatus(StringKey status)
|
||||
public bool SetStatus(StringKey status)
|
||||
{
|
||||
if (!Library.ScriptResolver.TryResolve(ScriptCategory.Status, status, null, out var statusScript))
|
||||
throw new KeyNotFoundException($"Status script {status} not found");
|
||||
StatusScript.Set(statusScript);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -1255,9 +1258,10 @@ public class PokemonBattleDataImpl : IPokemonBattleData
|
||||
public IReadOnlyList<IItem> ConsumedItems => _consumedItems;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void MarkItemAsConsumed(IItem itemName)
|
||||
public void MarkItemAsConsumed(IItem item)
|
||||
{
|
||||
_consumedItems.Add(itemName);
|
||||
_consumedItems.Add(item);
|
||||
BattleSide.SetConsumedItem(Position, item);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
Reference in New Issue
Block a user