Style cleanup
This commit is contained in:
@@ -15,8 +15,5 @@ public class PassTurnAI : PokemonAI
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ITurnChoice GetChoice(IBattle battle, IPokemon pokemon)
|
||||
{
|
||||
return new PassChoice(pokemon);
|
||||
}
|
||||
public override ITurnChoice GetChoice(IBattle battle, IPokemon pokemon) => new PassChoice(pokemon);
|
||||
}
|
||||
@@ -11,7 +11,7 @@ namespace PkmnLib.Dynamic.AI;
|
||||
public class RandomAI : PokemonAI
|
||||
{
|
||||
private IRandom _random;
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public RandomAI() : base("Random")
|
||||
{
|
||||
@@ -45,6 +45,4 @@ public class RandomAI : PokemonAI
|
||||
}
|
||||
return new PassChoice(pokemon);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -13,7 +13,7 @@ public class CaptureAttemptEvent : IEventData
|
||||
|
||||
public IPokemon Target { get; init; }
|
||||
public CaptureResult Result { get; init; }
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public EventBatchId BatchId { get; init; }
|
||||
}
|
||||
@@ -4,7 +4,7 @@ public class DialogEvent : IEventData
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public EventBatchId BatchId { get; init; } = new();
|
||||
|
||||
|
||||
public DialogEvent(string message, Dictionary<string, object>? parameters = null)
|
||||
{
|
||||
Message = message;
|
||||
@@ -12,6 +12,6 @@ public class DialogEvent : IEventData
|
||||
}
|
||||
|
||||
public string Message { get; set; }
|
||||
|
||||
|
||||
public Dictionary<string, object>? Parameters { get; set; }
|
||||
}
|
||||
@@ -10,12 +10,11 @@ public class ExperienceGainEvent : IEventData
|
||||
PreviousExperience = previousExperience;
|
||||
NewExperience = newExperience;
|
||||
}
|
||||
|
||||
|
||||
public IPokemon Pokemon { get; set; }
|
||||
public uint PreviousExperience { get; }
|
||||
public uint NewExperience { get; }
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public EventBatchId BatchId { get; init; }
|
||||
}
|
||||
@@ -17,7 +17,7 @@ public class FaintEvent : IEventData
|
||||
/// The Pokemon that fainted.
|
||||
/// </summary>
|
||||
public IPokemon Pokemon { get; init; }
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public EventBatchId BatchId { get; init; } = new();
|
||||
}
|
||||
@@ -13,7 +13,7 @@ public class FormChangeEvent : IEventData
|
||||
Pokemon = pokemon;
|
||||
Form = form;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public EventBatchId BatchId { get; init; }
|
||||
}
|
||||
@@ -14,7 +14,7 @@ public readonly record struct EventBatchId
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The unique identifier for this batch of events.
|
||||
/// </summary>
|
||||
|
||||
@@ -10,7 +10,7 @@ public class EventHook
|
||||
/// The event handler that is called when the event is triggered.
|
||||
/// </summary>
|
||||
public event EventHandler<IEventData>? Handler;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Triggers the event, calling the handler with the given data.
|
||||
/// </summary>
|
||||
|
||||
@@ -30,7 +30,6 @@ public class HealEvent : IEventData
|
||||
/// </summary>
|
||||
public uint NewHealth { get; }
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public EventBatchId BatchId { get; init; } = new();
|
||||
}
|
||||
@@ -17,7 +17,7 @@ public class MoveMissEvent : IEventData
|
||||
/// Data about the move that missed.
|
||||
/// </summary>
|
||||
public IExecutingMove ExecutingMove { get; }
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public EventBatchId BatchId { get; init; }
|
||||
}
|
||||
@@ -17,7 +17,7 @@ public class MoveUseEvent : IEventData
|
||||
{
|
||||
ExecutingMove = executingMove;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public EventBatchId BatchId { get; init; }
|
||||
}
|
||||
@@ -15,7 +15,7 @@ public class SpeciesChangeEvent : IEventData
|
||||
Species = species;
|
||||
Form = form;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public EventBatchId BatchId { get; init; }
|
||||
}
|
||||
@@ -12,22 +12,22 @@ public interface IBattleStatCalculator
|
||||
/// Calculate all the flat stats of a Pokemon, disregarding stat boosts.
|
||||
/// </summary>
|
||||
void CalculateFlatStats(IPokemon pokemon, StatisticSet<uint> stats);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Calculate a single flat stat of a Pokemon, disregarding stat boosts.
|
||||
/// </summary>
|
||||
uint CalculateFlatStat(IPokemon pokemon, Statistic stat);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Calculate all the boosted stats of a Pokemon, including stat boosts.
|
||||
/// </summary>
|
||||
void CalculateBoostedStats(IPokemon pokemon, StatisticSet<uint> stats);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Calculate a single boosted stat of a Pokemon, including stat boosts.
|
||||
/// </summary>
|
||||
uint CalculateBoostedStat(IPokemon pokemon, Statistic stat);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the accuracy for a move, taking into account any accuracy modifiers.
|
||||
/// </summary>
|
||||
|
||||
@@ -15,8 +15,8 @@ public record struct CaptureResult
|
||||
public bool IsCaught { get; init; }
|
||||
public int Shakes { get; init; }
|
||||
public bool CriticalCapture { get; init; }
|
||||
|
||||
public static CaptureResult Failed => new CaptureResult(false, 0, false);
|
||||
|
||||
public static CaptureResult Failed => new(false, 0, false);
|
||||
}
|
||||
|
||||
public interface ICaptureLibrary
|
||||
|
||||
@@ -31,12 +31,12 @@ public interface IDynamicLibrary
|
||||
/// calculators.
|
||||
/// </summary>
|
||||
IMiscLibrary MiscLibrary { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The capture library deals with the calculation of the capture rate of a Pokémon.
|
||||
/// </summary>
|
||||
ICaptureLibrary CaptureLibrary { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A holder of the script types that can be resolved by this library.
|
||||
/// </summary>
|
||||
@@ -66,12 +66,13 @@ public class DynamicLibraryImpl : IDynamicLibrary
|
||||
if (registry.CaptureLibrary is null)
|
||||
throw new InvalidOperationException("Capture library not found in plugins.");
|
||||
var scriptResolver = new ScriptResolver(registry.ScriptTypes, registry.ItemScriptTypes);
|
||||
return new DynamicLibraryImpl(staticLibrary, registry.BattleStatCalculator,
|
||||
registry.DamageCalculator, registry.MiscLibrary, registry.CaptureLibrary, scriptResolver);
|
||||
return new DynamicLibraryImpl(staticLibrary, registry.BattleStatCalculator, registry.DamageCalculator,
|
||||
registry.MiscLibrary, registry.CaptureLibrary, scriptResolver);
|
||||
}
|
||||
|
||||
|
||||
private DynamicLibraryImpl(IStaticLibrary staticLibrary, IBattleStatCalculator statCalculator,
|
||||
IDamageCalculator damageCalculator, IMiscLibrary miscLibrary, ICaptureLibrary captureLibrary, ScriptResolver scriptResolver)
|
||||
IDamageCalculator damageCalculator, IMiscLibrary miscLibrary, ICaptureLibrary captureLibrary,
|
||||
ScriptResolver scriptResolver)
|
||||
{
|
||||
StaticLibrary = staticLibrary;
|
||||
StatCalculator = statCalculator;
|
||||
|
||||
@@ -14,7 +14,7 @@ public interface IMiscLibrary
|
||||
/// moves left, yet wants to make a move.
|
||||
/// </summary>
|
||||
ITurnChoice ReplacementChoice(IPokemon user, byte targetSide, byte targetPosition);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current time of day for the battle.
|
||||
/// </summary>
|
||||
|
||||
@@ -94,7 +94,7 @@ public interface IBattle : IScriptSource, IDeepCloneable
|
||||
void ValidateBattleState();
|
||||
|
||||
bool HasForcedTurn(IPokemon pokemon, [NotNullWhen(true)] out ITurnChoice? choice);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a choice is actually possible.
|
||||
/// </summary>
|
||||
@@ -111,22 +111,22 @@ public interface IBattle : IScriptSource, IDeepCloneable
|
||||
void SetWeather(StringKey? weatherName);
|
||||
|
||||
public IScriptSet Volatile { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current weather of the battle. If no weather is present, this returns null.
|
||||
/// </summary>
|
||||
StringKey? WeatherName { get; }
|
||||
|
||||
void SetTerrain(StringKey? terrainName);
|
||||
|
||||
|
||||
StringKey? TerrainName { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the turn choices of the previous turn. This is a list of lists, where each list represents the choices
|
||||
/// for a single turn. The outer list is ordered from oldest to newest turn.
|
||||
/// </summary>
|
||||
IReadOnlyList<IReadOnlyList<ITurnChoice>> PreviousTurnChoices { get; }
|
||||
|
||||
|
||||
CaptureResult AttempCapture(byte sideIndex, byte position, IItem item);
|
||||
}
|
||||
|
||||
@@ -247,10 +247,10 @@ public class BattleImpl : ScriptSource, IBattle
|
||||
choice = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
ITurnChoice? forcedChoice = null;
|
||||
pokemon.RunScriptHook(
|
||||
script => script.ForceTurnSelection(battleData.SideIndex, battleData.Position, ref forcedChoice));
|
||||
pokemon.RunScriptHook(script =>
|
||||
script.ForceTurnSelection(battleData.SideIndex, battleData.Position, ref forcedChoice));
|
||||
choice = forcedChoice;
|
||||
return choice != null;
|
||||
}
|
||||
@@ -262,7 +262,7 @@ public class BattleImpl : ScriptSource, IBattle
|
||||
return false;
|
||||
if (HasForcedTurn(choice.User, out var forcedChoice) && choice != forcedChoice)
|
||||
return false;
|
||||
|
||||
|
||||
if (choice is IMoveChoice moveChoice)
|
||||
{
|
||||
// TODO: Hook to change number of PP needed.
|
||||
@@ -365,7 +365,7 @@ public class BattleImpl : ScriptSource, IBattle
|
||||
|
||||
/// <inheritdoc />
|
||||
public StringKey? WeatherName => _weatherScript.Script?.Name;
|
||||
|
||||
|
||||
private readonly ScriptContainer _terrainScript = new();
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -386,7 +386,6 @@ public class BattleImpl : ScriptSource, IBattle
|
||||
/// <inheritdoc />
|
||||
public StringKey? TerrainName => _terrainScript.Script?.Name;
|
||||
|
||||
|
||||
private readonly List<IReadOnlyList<ITurnChoice>> _previousTurnChoices = new();
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -398,7 +397,7 @@ public class BattleImpl : ScriptSource, IBattle
|
||||
var target = GetPokemon(sideIndex, position);
|
||||
if (target is not { IsUsable: true })
|
||||
return CaptureResult.Failed;
|
||||
|
||||
|
||||
var attemptCapture = Library.CaptureLibrary.TryCapture(target, item, Random);
|
||||
if (attemptCapture.IsCaught)
|
||||
{
|
||||
|
||||
@@ -23,7 +23,7 @@ public class BattleChoiceQueue : IDeepCloneable
|
||||
{
|
||||
_choices = choices;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Dequeues the next turn choice to be executed. This gives back the choice and sets it to null in the queue. It
|
||||
/// also increments the internal index.
|
||||
@@ -40,18 +40,17 @@ public class BattleChoiceQueue : IDeepCloneable
|
||||
LastRanChoice = choice;
|
||||
return choice;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This reads what the next choice to execute will be, without modifying state.
|
||||
/// </summary>
|
||||
public ITurnChoice? Peek() => _currentIndex >= _choices.Length ? null : _choices[_currentIndex];
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Checks if there are any more choices to execute.
|
||||
/// </summary>
|
||||
public bool HasNext() => _currentIndex < _choices.Length;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This resorts the yet to be executed choices. This can be useful for dealing with situations
|
||||
/// such as Pokémon changing forms just after the very start of a turn, when turn order has
|
||||
@@ -72,7 +71,7 @@ public class BattleChoiceQueue : IDeepCloneable
|
||||
choice.User.RunScriptHook(script => script.ChangeSpeed(choice, ref speed));
|
||||
choice.Speed = speed;
|
||||
}
|
||||
|
||||
|
||||
// We only sort the choices that are left
|
||||
Array.Sort(_choices, currentIndex, length - currentIndex, TurnChoiceComparer.Instance!);
|
||||
}
|
||||
@@ -99,8 +98,9 @@ public class BattleChoiceQueue : IDeepCloneable
|
||||
_choices[_currentIndex] = choice;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
internal IReadOnlyList<ITurnChoice?> GetChoices() => _choices;
|
||||
|
||||
public ITurnChoice? FirstOrDefault(Func<ITurnChoice, bool> predicate) => _choices.WhereNotNull().FirstOrDefault(predicate);
|
||||
|
||||
public ITurnChoice? FirstOrDefault(Func<ITurnChoice, bool> predicate) =>
|
||||
_choices.WhereNotNull().FirstOrDefault(predicate);
|
||||
}
|
||||
@@ -12,7 +12,7 @@ internal static class MoveTurnExecutor
|
||||
{
|
||||
var chosenMove = moveChoice.ChosenMove;
|
||||
var moveData = chosenMove.MoveData;
|
||||
|
||||
|
||||
var moveDataName = moveData.Name;
|
||||
moveChoice.RunScriptHook(x => x.ChangeMove(moveChoice, ref moveDataName));
|
||||
if (moveData.Name != moveDataName)
|
||||
@@ -31,11 +31,11 @@ internal static class MoveTurnExecutor
|
||||
moveChoice.Script.Set(script);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var targetType = moveData.Target;
|
||||
var targets = TargetResolver.ResolveTargets(battle, moveChoice.TargetSide, moveChoice.TargetPosition, targetType);
|
||||
var targets =
|
||||
TargetResolver.ResolveTargets(battle, moveChoice.TargetSide, moveChoice.TargetPosition, targetType);
|
||||
moveChoice.RunScriptHook(x => x.ChangeTargets(moveChoice, ref targets));
|
||||
|
||||
byte numberOfHits = 1;
|
||||
@@ -46,7 +46,7 @@ internal static class MoveTurnExecutor
|
||||
}
|
||||
|
||||
var executingMove = new ExecutingMoveImpl(targets, numberOfHits, chosenMove, moveData, moveChoice);
|
||||
|
||||
|
||||
var prevented = false;
|
||||
executingMove.RunScriptHook(x => x.PreventMove(executingMove, ref prevented));
|
||||
if (prevented)
|
||||
@@ -56,9 +56,9 @@ internal static class MoveTurnExecutor
|
||||
// TODO: Modify the PP used by the move.
|
||||
if (!executingMove.ChosenMove.TryUse(ppUsed))
|
||||
return;
|
||||
|
||||
|
||||
battle.EventHook.Invoke(new MoveUseEvent(executingMove));
|
||||
|
||||
|
||||
var failed = false;
|
||||
executingMove.RunScriptHook(x => x.FailMove(executingMove, ref failed));
|
||||
if (failed)
|
||||
@@ -66,12 +66,12 @@ internal static class MoveTurnExecutor
|
||||
// TODO: fail handling
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var stopped = false;
|
||||
executingMove.RunScriptHook(x => x.StopBeforeMove(executingMove, ref stopped));
|
||||
if (stopped)
|
||||
return;
|
||||
|
||||
|
||||
executingMove.RunScriptHook(x => x.OnBeforeMove(executingMove));
|
||||
foreach (var target in targets.WhereNotNull())
|
||||
{
|
||||
@@ -88,7 +88,7 @@ internal static class MoveTurnExecutor
|
||||
// TODO: fail handling
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var isInvulnerable = false;
|
||||
target.RunScriptHook(x => x.IsInvulnerableToMove(executingMove, target, ref isInvulnerable));
|
||||
if (isInvulnerable)
|
||||
@@ -96,7 +96,7 @@ internal static class MoveTurnExecutor
|
||||
// TODO: event?
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var numberOfHits = executingMove.NumberOfHits;
|
||||
var targetHitStat = executingMove.GetTargetIndex(target) * numberOfHits;
|
||||
|
||||
@@ -120,7 +120,7 @@ internal static class MoveTurnExecutor
|
||||
var effectiveness = battle.Library.StaticLibrary.Types.GetEffectiveness(hitType, target.Types);
|
||||
executingMove.RunScriptHook(x => x.ChangeEffectiveness(executingMove, target, hitIndex, ref effectiveness));
|
||||
hitData.Effectiveness = effectiveness;
|
||||
|
||||
|
||||
var blockCritical = false;
|
||||
executingMove.RunScriptHook(x => x.BlockCriticalHit(executingMove, target, hitIndex, ref blockCritical));
|
||||
target.RunScriptHook(x => x.BlockIncomingCriticalHit(executingMove, target, hitIndex, ref blockCritical));
|
||||
@@ -129,10 +129,10 @@ internal static class MoveTurnExecutor
|
||||
var critical = battle.Library.DamageCalculator.IsCritical(battle, executingMove, target, hitIndex);
|
||||
hitData.IsCritical = critical;
|
||||
}
|
||||
|
||||
|
||||
var basePower = battle.Library.DamageCalculator.GetBasePower(executingMove, target, hitIndex, hitData);
|
||||
hitData.BasePower = basePower;
|
||||
|
||||
|
||||
hitData.Damage = battle.Library.DamageCalculator.GetDamage(executingMove, target, hitIndex, hitData);
|
||||
|
||||
var accuracy = useMove.Accuracy;
|
||||
@@ -140,17 +140,17 @@ internal static class MoveTurnExecutor
|
||||
// modifying it.
|
||||
if (accuracy != 255)
|
||||
{
|
||||
accuracy = battle.Library.StatCalculator.CalculateModifiedAccuracy(executingMove, target,
|
||||
hitIndex, accuracy);
|
||||
accuracy = battle.Library.StatCalculator.CalculateModifiedAccuracy(executingMove, target, hitIndex,
|
||||
accuracy);
|
||||
}
|
||||
|
||||
|
||||
if (accuracy < 100 && battle.Random.GetInt(100) >= accuracy)
|
||||
{
|
||||
executingMove.RunScriptHook(x => x.OnMoveMiss(executingMove, target));
|
||||
battle.EventHook.Invoke(new MoveMissEvent(executingMove));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
var blockIncomingHit = false;
|
||||
target.RunScriptHook(x => x.BlockIncomingHit(executingMove, target, hitIndex, ref blockIncomingHit));
|
||||
executingMove.RunScriptHook(x => x.BlockOutgoingHit(executingMove, target, hitIndex, ref blockIncomingHit));
|
||||
@@ -187,7 +187,7 @@ internal static class MoveTurnExecutor
|
||||
BatchId = hitEventBatch,
|
||||
});
|
||||
target.Damage(damage, DamageSource.MoveDamage, hitEventBatch);
|
||||
if (!target.IsFainted)
|
||||
if (!target.IsFainted)
|
||||
target.RunScriptHook(x => x.OnIncomingHit(executingMove, target, hitIndex));
|
||||
else
|
||||
executingMove.RunScriptHook(x => x.OnOpponentFaints(executingMove, target, hitIndex));
|
||||
@@ -198,14 +198,16 @@ internal static class MoveTurnExecutor
|
||||
if (secondaryEffect != null)
|
||||
{
|
||||
var preventSecondary = false;
|
||||
target.RunScriptHook(x => x.PreventSecondaryEffect(executingMove, target, hitIndex, ref preventSecondary));
|
||||
target.RunScriptHook(x =>
|
||||
x.PreventSecondaryEffect(executingMove, target, hitIndex, ref preventSecondary));
|
||||
|
||||
if (!preventSecondary)
|
||||
{
|
||||
var chance = secondaryEffect.Chance;
|
||||
if (chance < 0 || battle.Random.EffectChance(chance, executingMove, target, hitIndex))
|
||||
{
|
||||
executingMove.RunScriptHook(x => x.OnSecondaryEffect(executingMove, target, hitIndex));
|
||||
executingMove.RunScriptHook(x =>
|
||||
x.OnSecondaryEffect(executingMove, target, hitIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -213,7 +215,7 @@ internal static class MoveTurnExecutor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (numberOfHits == 0)
|
||||
{
|
||||
target.RunScriptHook(x => x.OnMoveMiss(executingMove, target));
|
||||
@@ -224,6 +226,5 @@ internal static class MoveTurnExecutor
|
||||
{
|
||||
executingMove.RunScriptHook(x => x.OnAfterHits(executingMove, target));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,8 @@ public static class TargetResolver
|
||||
return target switch
|
||||
{
|
||||
MoveTarget.Adjacent or MoveTarget.AdjacentAlly or MoveTarget.AdjacentAllySelf or MoveTarget.AdjacentOpponent
|
||||
or MoveTarget.Any or MoveTarget.RandomOpponent
|
||||
or MoveTarget.SelfUse => [battle.GetPokemon(side, position)],
|
||||
or MoveTarget.Any or MoveTarget.RandomOpponent or MoveTarget.SelfUse =>
|
||||
[battle.GetPokemon(side, position)],
|
||||
MoveTarget.All => GetAllTargets(battle),
|
||||
MoveTarget.AllAdjacentOpponent => GetAllAdjacentAndOpponent(battle, side, position),
|
||||
MoveTarget.AllAdjacent => GetAllAdjacent(battle, side, position),
|
||||
@@ -144,7 +144,8 @@ public static class TargetResolver
|
||||
|
||||
return
|
||||
[
|
||||
battle.GetPokemon(side, position), battle.GetPokemon(side, (byte)left), battle.GetPokemon(side, (byte)right),
|
||||
battle.GetPokemon(side, position), battle.GetPokemon(side, (byte)left),
|
||||
battle.GetPokemon(side, (byte)right),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -16,9 +16,11 @@ public static class TurnRunner
|
||||
{
|
||||
var queue = battle.ChoiceQueue;
|
||||
if (queue == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(battle.ChoiceQueue),
|
||||
"The battle's choice queue must be set before running a turn.");
|
||||
|
||||
}
|
||||
|
||||
// We are now at the very beginning of a turn. We have assigned speeds and priorities to all
|
||||
// choices, and put them in the correct order.
|
||||
|
||||
@@ -30,7 +32,7 @@ public static class TurnRunner
|
||||
{
|
||||
choice.RunScriptHook(script => script.OnBeforeTurnStart(choice));
|
||||
}
|
||||
|
||||
|
||||
// Now we can properly begin executing choices.
|
||||
// One by one dequeue the turns, and run them. If the battle has ended we do not want to
|
||||
// continue running.
|
||||
@@ -41,7 +43,7 @@ public static class TurnRunner
|
||||
continue;
|
||||
ExecuteChoice(battle, next);
|
||||
}
|
||||
|
||||
|
||||
// If the battle is not ended, we have arrived at the normal end of a turn. and thus want
|
||||
// to run the end turn scripts.
|
||||
|
||||
@@ -122,7 +124,6 @@ public static class TurnRunner
|
||||
userSide.SwapPokemon(battleData.Position, fleeChoice.SwitchTo);
|
||||
}
|
||||
|
||||
|
||||
private static void ExecuteFleeChoice(IBattle battle, IFleeChoice fleeChoice)
|
||||
{
|
||||
var user = fleeChoice.User;
|
||||
@@ -131,7 +132,7 @@ public static class TurnRunner
|
||||
return;
|
||||
if (!battle.CanFlee)
|
||||
return;
|
||||
|
||||
|
||||
var preventFlee = false;
|
||||
fleeChoice.RunScriptHook(script => script.PreventSelfRunAway(fleeChoice, ref preventFlee));
|
||||
if (preventFlee)
|
||||
@@ -148,10 +149,10 @@ public static class TurnRunner
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!battle.Library.MiscLibrary.CanFlee(battle, fleeChoice))
|
||||
return;
|
||||
|
||||
|
||||
var userSide = battle.Sides[battleData.SideIndex];
|
||||
userSide.MarkAsFled();
|
||||
battle.ValidateBattleState();
|
||||
@@ -171,5 +172,4 @@ public static class TurnRunner
|
||||
}
|
||||
itemChoice.Item.RunItemScript(battle.Library.ScriptResolver, target ?? user);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,22 +10,22 @@ public record struct BattleResult
|
||||
ConclusiveResult = conclusiveResult;
|
||||
WinningSide = winningSide;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// An inconclusive battle result. This means no side has won.
|
||||
/// </summary>
|
||||
public static BattleResult Inconclusive => new(false, null);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A conclusive battle result. This means one side has won.
|
||||
/// </summary>
|
||||
public static BattleResult Conclusive(byte winningSide) => new(true, winningSide);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Whether the battle has a conclusive result. If false, no side has won.
|
||||
/// </summary>
|
||||
public bool ConclusiveResult { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The side that won the battle. If null, no side has won.
|
||||
/// </summary>
|
||||
|
||||
@@ -14,48 +14,48 @@ public interface IBattleSide : IScriptSource, IDeepCloneable
|
||||
/// The index of the side on the battle.
|
||||
/// </summary>
|
||||
byte Index { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The number of Pokémon that can be on the side.
|
||||
/// </summary>
|
||||
byte NumberOfPositions { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A list of Pokémon currently on the battlefield.
|
||||
/// </summary>
|
||||
IReadOnlyList<IPokemon?> Pokemon { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The currently set choices for all Pokémon on the battlefield. Cleared when the turn starts.
|
||||
/// </summary>
|
||||
IReadOnlyList<ITurnChoice?> SetChoices { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Whether every Pokémon on this side has its choices
|
||||
/// </summary>
|
||||
bool AllChoicesSet { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The slots on the side that can still be filled. Once all slots are set to false, this side
|
||||
/// has lost the battle.
|
||||
/// </summary>
|
||||
IReadOnlyList<bool> FillablePositions { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A reference to the battle this side is in.
|
||||
/// </summary>
|
||||
IBattle Battle { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Whether this side has fled.
|
||||
/// </summary>
|
||||
bool HasFledBattle { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The volatile scripts that are attached to the side.
|
||||
/// </summary>
|
||||
IScriptSet VolatileScripts { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if there are slots that need to be filled with a new pokemon, that have parties
|
||||
/// responsible for them. Returns false if all slots are filled with usable pokemon, or slots are
|
||||
@@ -67,7 +67,7 @@ public interface IBattleSide : IScriptSource, IDeepCloneable
|
||||
/// Sets a choice for a Pokémon on this side.
|
||||
/// </summary>
|
||||
void SetChoice(byte position, ITurnChoice choice);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Resets all choices on this side.
|
||||
/// </summary>
|
||||
@@ -110,12 +110,12 @@ public interface IBattleSide : IScriptSource, IDeepCloneable
|
||||
/// Checks whether the side has been defeated.
|
||||
/// </summary>
|
||||
bool IsDefeated();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The number of times this side has attempted to flee.
|
||||
/// </summary>
|
||||
uint FleeAttempts { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Registers a flee attempt for this side.
|
||||
/// </summary>
|
||||
@@ -150,7 +150,7 @@ public class BattleSideImpl : ScriptSource, IBattleSide
|
||||
Battle = battle;
|
||||
VolatileScripts = new ScriptSet();
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public byte Index { get; }
|
||||
|
||||
@@ -158,6 +158,7 @@ public class BattleSideImpl : ScriptSource, IBattleSide
|
||||
public byte NumberOfPositions { get; }
|
||||
|
||||
private readonly IPokemon?[] _pokemon;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<IPokemon?> Pokemon => _pokemon;
|
||||
|
||||
@@ -170,6 +171,7 @@ public class BattleSideImpl : ScriptSource, IBattleSide
|
||||
public bool AllChoicesSet => _setChoices.All(choice => choice is not null);
|
||||
|
||||
private readonly bool[] _fillablePositions;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<bool> FillablePositions => _fillablePositions;
|
||||
|
||||
@@ -223,7 +225,7 @@ public class BattleSideImpl : ScriptSource, IBattleSide
|
||||
pokemon.RunScriptHook(script => script.OnRemove());
|
||||
pokemon.SetOnBattlefield(false);
|
||||
}
|
||||
|
||||
|
||||
_pokemon[index] = null;
|
||||
}
|
||||
|
||||
@@ -259,7 +261,7 @@ public class BattleSideImpl : ScriptSource, IBattleSide
|
||||
{
|
||||
Battle.EventHook.Invoke(new SwitchEvent(Index, position, null));
|
||||
}
|
||||
|
||||
|
||||
return oldPokemon;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ namespace PkmnLib.Dynamic.Models.Choices;
|
||||
/// </summary>
|
||||
public interface IFleeChoice : ITurnChoice
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IFleeChoice"/>
|
||||
@@ -22,7 +21,9 @@ public class FleeTurnChoice : TurnChoice, IFleeChoice
|
||||
public override int ScriptCount => User.ScriptCount;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void GetOwnScripts(List<IEnumerable<ScriptContainer>> scripts) { }
|
||||
public override void GetOwnScripts(List<IEnumerable<ScriptContainer>> scripts)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void CollectScripts(List<IEnumerable<ScriptContainer>> scripts) => User.CollectScripts(scripts);
|
||||
|
||||
@@ -12,7 +12,7 @@ public interface IItemChoice : ITurnChoice
|
||||
/// The item that is used.
|
||||
/// </summary>
|
||||
public IItem Item { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The side the move is targeted at.
|
||||
/// </summary>
|
||||
|
||||
@@ -32,9 +32,9 @@ public interface IMoveChoice : ITurnChoice
|
||||
/// The underlying script of the move.
|
||||
/// </summary>
|
||||
ScriptContainer Script { get; set; }
|
||||
|
||||
|
||||
Dictionary<StringKey, object?>? AdditionalData { get; }
|
||||
|
||||
|
||||
IScriptSet Volatile { get; }
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public class MoveChoice : TurnChoice, IMoveChoice
|
||||
ChosenMove = usedMove;
|
||||
TargetSide = targetSide;
|
||||
TargetPosition = targetPosition;
|
||||
|
||||
|
||||
var secondaryEffect = usedMove.MoveData.SecondaryEffect;
|
||||
if (secondaryEffect != null)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,6 @@ namespace PkmnLib.Dynamic.Models.Choices;
|
||||
/// </summary>
|
||||
public interface IPassChoice : ITurnChoice
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class PassChoice : TurnChoice, IPassChoice
|
||||
|
||||
@@ -7,7 +7,7 @@ public class TurnChoiceComparer : IComparer<ITurnChoice>
|
||||
{
|
||||
/// <inheritdoc cref="TurnChoiceComparer"/>
|
||||
public static TurnChoiceComparer Instance { get; } = new();
|
||||
|
||||
|
||||
private enum CompareValues
|
||||
{
|
||||
XEqualsY = 0,
|
||||
@@ -25,7 +25,7 @@ public class TurnChoiceComparer : IComparer<ITurnChoice>
|
||||
// This is to ensure that the order of choices is deterministic.
|
||||
return (CompareValues)x.RandomValue.CompareTo(y.RandomValue);
|
||||
}
|
||||
|
||||
|
||||
private static CompareValues CompareImpl(ITurnChoice? x, ITurnChoice? y)
|
||||
{
|
||||
// Deal with possible null values
|
||||
@@ -77,10 +77,10 @@ public class TurnChoiceComparer : IComparer<ITurnChoice>
|
||||
_ => CompareValues.XGreaterThanY,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
return CompareValues.XLessThanY;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Compare(ITurnChoice? x, ITurnChoice? y) => (int) CompareImpl(x, y);
|
||||
public int Compare(ITurnChoice? x, ITurnChoice? y) => (int)CompareImpl(x, y);
|
||||
}
|
||||
@@ -19,13 +19,13 @@ public enum DamageSource
|
||||
/// The damage is done because of struggling.
|
||||
/// </summary>
|
||||
Struggle = 2,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The damage is done because of a form change.
|
||||
/// This happens when the form of a Pokemon changes, and it has less max HP than it had before.
|
||||
/// </summary>
|
||||
FormChange = 3,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The damage is done because of the weather.
|
||||
/// </summary>
|
||||
|
||||
@@ -129,12 +129,12 @@ public interface IExecutingMove : IScriptSource
|
||||
/// Gets a hit based on its raw index.
|
||||
/// </summary>
|
||||
IHitData GetDataFromRawIndex(int index);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the targets of this move.
|
||||
/// </summary>
|
||||
IReadOnlyList<IPokemon?> Targets { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The underlying move choice.
|
||||
/// </summary>
|
||||
|
||||
@@ -54,7 +54,7 @@ public interface ILearnedMove : IDeepCloneable
|
||||
/// The maximal power points for this move.
|
||||
/// </summary>
|
||||
byte MaxPp { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The current power points for this move.
|
||||
/// </summary>
|
||||
@@ -86,7 +86,7 @@ public interface ILearnedMove : IDeepCloneable
|
||||
public class LearnedMoveImpl : ILearnedMove
|
||||
{
|
||||
private byte _maxPpModification = 0;
|
||||
|
||||
|
||||
/// <inheritdoc cref="LearnedMoveImpl" />
|
||||
public LearnedMoveImpl(IMoveData moveData, MoveLearnMethod learnMethod)
|
||||
{
|
||||
@@ -95,8 +95,7 @@ public class LearnedMoveImpl : ILearnedMove
|
||||
CurrentPp = MaxPp;
|
||||
}
|
||||
|
||||
public LearnedMoveImpl(IMoveData moveData, MoveLearnMethod learnMethod, byte pp)
|
||||
: this(moveData, learnMethod)
|
||||
public LearnedMoveImpl(IMoveData moveData, MoveLearnMethod learnMethod, byte pp) : this(moveData, learnMethod)
|
||||
{
|
||||
CurrentPp = pp;
|
||||
}
|
||||
@@ -109,12 +108,12 @@ public class LearnedMoveImpl : ILearnedMove
|
||||
|
||||
/// <inheritdoc />
|
||||
public MoveLearnMethod LearnMethod { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The available power points for this move.
|
||||
/// </summary>
|
||||
public byte CurrentPp { get; private set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Try to use the move. This subtracts the amount of PP from the current PP. If the amount requested is
|
||||
/// higher than the current PP, this will return false, and the PP will not be reduced.
|
||||
@@ -123,7 +122,7 @@ public class LearnedMoveImpl : ILearnedMove
|
||||
{
|
||||
if (CurrentPp < amount)
|
||||
return false;
|
||||
|
||||
|
||||
CurrentPp -= amount;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ public interface IPokemon : IScriptSource, IDeepCloneable
|
||||
/// The amount of experience of the Pokemon.
|
||||
/// </summary>
|
||||
uint Experience { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Increases the experience of the Pokemon. Returns whether any experience was gained.
|
||||
/// </summary>
|
||||
@@ -71,7 +71,7 @@ public interface IPokemon : IScriptSource, IDeepCloneable
|
||||
/// currently not used, and can be used for other implementations.
|
||||
/// </summary>
|
||||
byte Coloring { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Whether the Pokemon is shiny.
|
||||
/// </summary>
|
||||
@@ -98,7 +98,7 @@ public interface IPokemon : IScriptSource, IDeepCloneable
|
||||
/// <param name="weightInKg">The new weight in kilograms</param>
|
||||
/// <returns></returns>
|
||||
public bool ChangeWeightInKgBy(float weightInKg);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The height of the Pokémon in meters.
|
||||
/// </summary>
|
||||
@@ -124,7 +124,7 @@ public interface IPokemon : IScriptSource, IDeepCloneable
|
||||
/// The stats of the Pokemon including the stat boosts
|
||||
/// </summary>
|
||||
StatisticSet<uint> BoostedStats { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The maximum health of the Pokemon.
|
||||
/// </summary>
|
||||
@@ -171,12 +171,12 @@ public interface IPokemon : IScriptSource, IDeepCloneable
|
||||
/// are null.
|
||||
/// </summary>
|
||||
IReadOnlyList<ILearnedMove?> Moves { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the Pokemon has a specific move in its current moveset.
|
||||
/// </summary>
|
||||
bool HasMove(StringKey moveName);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Swaps two moves of the Pokemon.
|
||||
/// </summary>
|
||||
@@ -201,7 +201,7 @@ public interface IPokemon : IScriptSource, IDeepCloneable
|
||||
/// Whether or not this Pokemon was caught this battle.
|
||||
/// </summary>
|
||||
bool IsCaught { get; }
|
||||
|
||||
|
||||
public void MarkAsCaught();
|
||||
|
||||
/// <summary>
|
||||
@@ -240,7 +240,7 @@ public interface IPokemon : IScriptSource, IDeepCloneable
|
||||
/// </summary>
|
||||
[MustUseReturnValue]
|
||||
IItem? RemoveHeldItem();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Removes the held item from the Pokemon for the duration of the battle. Returns the previously held item.
|
||||
/// </summary>
|
||||
@@ -249,7 +249,7 @@ public interface IPokemon : IScriptSource, IDeepCloneable
|
||||
/// restored after the battle.
|
||||
/// </remarks>
|
||||
IItem? RemoveHeldItemForBattle();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Restores the held item of a Pokémon if it was temporarily removed.
|
||||
/// </summary>
|
||||
@@ -273,7 +273,7 @@ public interface IPokemon : IScriptSource, IDeepCloneable
|
||||
/// Suppresses the ability of the Pokémon.
|
||||
/// </summary>
|
||||
public void SuppressAbility();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the currently active ability.
|
||||
/// </summary>
|
||||
@@ -322,7 +322,7 @@ public interface IPokemon : IScriptSource, IDeepCloneable
|
||||
/// heal if the Pokemon has 0 health. If the amount healed is 0, this will return false.
|
||||
/// </summary>
|
||||
bool Heal(uint heal, bool allowRevive = false);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Restores all PP of the Pokemon.
|
||||
/// </summary>
|
||||
@@ -337,10 +337,12 @@ public interface IPokemon : IScriptSource, IDeepCloneable
|
||||
/// Checks whether the Pokémon has a specific non-volatile status.
|
||||
/// </summary>
|
||||
bool HasStatus(StringKey status);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a non-volatile status to the Pokemon.
|
||||
/// </summary>
|
||||
void SetStatus(StringKey status);
|
||||
|
||||
/// <summary>
|
||||
/// Removes the current non-volatile status from the Pokemon.
|
||||
/// </summary>
|
||||
@@ -371,23 +373,23 @@ public interface IPokemon : IScriptSource, IDeepCloneable
|
||||
/// Marks a Pokemon as seen in the battle.
|
||||
/// </summary>
|
||||
void MarkOpponentAsSeen(IPokemon pokemon);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Removes a type from the Pokémon. Returns whether the type was removed.
|
||||
/// </summary>
|
||||
bool RemoveType(TypeIdentifier type);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Adds a type to the Pokémon. Returns whether the type was added. It will not add the type if
|
||||
/// the Pokémon already has it.
|
||||
/// </summary>
|
||||
bool AddType(TypeIdentifier type);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Replace the types of the Pokémon with the provided types.
|
||||
/// </summary>
|
||||
void SetTypes(IReadOnlyList<TypeIdentifier> types);
|
||||
|
||||
|
||||
void ChangeAbility(IAbility ability);
|
||||
|
||||
/// <summary>
|
||||
@@ -431,17 +433,17 @@ public interface IPokemonBattleData : IDeepCloneable
|
||||
/// Adds an opponent to the list of seen opponents.
|
||||
/// </summary>
|
||||
void MarkOpponentAsSeen(IPokemon opponent);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A list of items the Pokémon has consumed this battle.
|
||||
/// </summary>
|
||||
IReadOnlyList<IItem> ConsumedItems { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Marks an item as consumed.
|
||||
/// </summary>
|
||||
void MarkItemAsConsumed(IItem itemName);
|
||||
|
||||
|
||||
uint SwitchInTurn { get; internal set; }
|
||||
}
|
||||
|
||||
@@ -569,7 +571,7 @@ public class PokemonImpl : ScriptSource, IPokemon
|
||||
{
|
||||
BatchId = batchId,
|
||||
});
|
||||
|
||||
|
||||
var newLevel = Library.StaticLibrary.GrowthRates.CalculateLevel(Species.GrowthRate, Experience);
|
||||
if (newLevel > Level)
|
||||
{
|
||||
@@ -579,7 +581,7 @@ public class PokemonImpl : ScriptSource, IPokemon
|
||||
{
|
||||
BatchId = batchId,
|
||||
});
|
||||
|
||||
|
||||
if (newLevel >= maxLevel)
|
||||
{
|
||||
Experience = Library.StaticLibrary.GrowthRates.CalculateExperience(Species.GrowthRate, maxLevel);
|
||||
@@ -597,7 +599,7 @@ public class PokemonImpl : ScriptSource, IPokemon
|
||||
|
||||
/// <inheritdoc />
|
||||
public byte Coloring { get; }
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsShiny => Coloring == 1;
|
||||
|
||||
@@ -686,7 +688,11 @@ public class PokemonImpl : ScriptSource, IPokemon
|
||||
private List<TypeIdentifier> _types = new();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<TypeIdentifier> Types { get => _types; private set => _types = value.ToList(); }
|
||||
public IReadOnlyList<TypeIdentifier> Types
|
||||
{
|
||||
get => _types;
|
||||
private set => _types = value.ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsEgg { get; private set; }
|
||||
@@ -730,7 +736,7 @@ public class PokemonImpl : ScriptSource, IPokemon
|
||||
HeldItem = null;
|
||||
return previous;
|
||||
}
|
||||
|
||||
|
||||
private IItem? _stolenHeldItem;
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -753,7 +759,7 @@ public class PokemonImpl : ScriptSource, IPokemon
|
||||
return false;
|
||||
if (!Library.ScriptResolver.TryResolveBattleItemScript(HeldItem, out _))
|
||||
return false;
|
||||
|
||||
|
||||
if (BattleData != null)
|
||||
{
|
||||
var prevented = false;
|
||||
@@ -761,7 +767,7 @@ public class PokemonImpl : ScriptSource, IPokemon
|
||||
if (prevented)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// TODO: actually consume the item
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@@ -798,12 +804,12 @@ public class PokemonImpl : ScriptSource, IPokemon
|
||||
RecalculateBoostedStats();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Whether the ability of the Pokémon is suppressed.
|
||||
/// </summary>
|
||||
public bool AbilitySuppressed { get; private set; }
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SuppressAbility()
|
||||
{
|
||||
@@ -933,7 +939,7 @@ public class PokemonImpl : ScriptSource, IPokemon
|
||||
this.RunScriptHook(script => script.ChangeIncomingDamage(this, source, ref dmg));
|
||||
damage = dmg;
|
||||
}
|
||||
|
||||
|
||||
// If the damage is more than the current health, we cap it at the current health, to prevent
|
||||
// underflow.
|
||||
if (damage >= CurrentHealth)
|
||||
@@ -989,7 +995,7 @@ public class PokemonImpl : ScriptSource, IPokemon
|
||||
{
|
||||
if (IsFainted && !allowRevive)
|
||||
return false;
|
||||
var maxAmount = this.BoostedStats.Hp - CurrentHealth;
|
||||
var maxAmount = BoostedStats.Hp - CurrentHealth;
|
||||
if (heal > maxAmount)
|
||||
heal = maxAmount;
|
||||
if (heal == 0)
|
||||
@@ -1019,7 +1025,8 @@ public class PokemonImpl : ScriptSource, IPokemon
|
||||
{
|
||||
for (byte i = 0; i < Moves.Count; i++)
|
||||
{
|
||||
if (Moves[i] is not null) continue;
|
||||
if (Moves[i] is not null)
|
||||
continue;
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ public interface IPokemonParty : IReadOnlyList<IPokemon?>, IDeepCloneable
|
||||
{
|
||||
event EventHandler<(IPokemon?, int index)>? OnSwapInto;
|
||||
event EventHandler<(int index1, int index2)>? OnSwap;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sets the Pokemon at an index to a Pokemon, returning the old Pokemon.
|
||||
/// </summary>
|
||||
@@ -28,7 +28,7 @@ public interface IPokemonParty : IReadOnlyList<IPokemon?>, IDeepCloneable
|
||||
/// This will return false if all Pokemon are fainted, or eggs, etc.
|
||||
/// </remarks>
|
||||
bool HasUsablePokemon();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Packs the party so that all Pokémon are at the front, and the empty slots are at the back.
|
||||
/// </summary>
|
||||
@@ -46,7 +46,6 @@ public class PokemonParty : IPokemonParty
|
||||
_pokemon = new IPokemon[size];
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<(IPokemon?, int index)>? OnSwapInto;
|
||||
|
||||
@@ -73,10 +72,9 @@ public class PokemonParty : IPokemonParty
|
||||
OnSwap?.Invoke(this, (index1, index2));
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasUsablePokemon() => _pokemon.Any(p => p is { IsUsable: true });
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerator<IPokemon?> GetEnumerator() => ((IEnumerable<IPokemon?>)_pokemon).GetEnumerator();
|
||||
|
||||
@@ -95,11 +93,11 @@ public class PokemonParty : IPokemonParty
|
||||
// Pack the party so that all Pokémon are at the front.
|
||||
for (var i = 0; i < _pokemon.Length; i++)
|
||||
{
|
||||
if (_pokemon[i] != null)
|
||||
if (_pokemon[i] != null)
|
||||
continue;
|
||||
for (var j = i + 1; j < _pokemon.Length; j++)
|
||||
{
|
||||
if (_pokemon[j] == null)
|
||||
if (_pokemon[j] == null)
|
||||
continue;
|
||||
Swap(i, j);
|
||||
break;
|
||||
|
||||
@@ -134,7 +134,7 @@ public record SerializedStats
|
||||
public SerializedStats()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public SerializedStats(ImmutableStatisticSet<byte> stats)
|
||||
{
|
||||
Hp = stats.Hp;
|
||||
@@ -144,7 +144,7 @@ public record SerializedStats
|
||||
SpecialDefense = stats.SpecialDefense;
|
||||
Speed = stats.Speed;
|
||||
}
|
||||
|
||||
|
||||
public SerializedStats(long hp, long attack, long defense, long specialAttack, long specialDefense, long speed)
|
||||
{
|
||||
Hp = hp;
|
||||
|
||||
@@ -12,8 +12,7 @@ public abstract class ItemScript : IDeepCloneable
|
||||
}
|
||||
|
||||
protected IItem Item { get; private set; }
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the script with the given parameters for a specific item
|
||||
/// </summary>
|
||||
|
||||
@@ -11,14 +11,14 @@ public abstract class PokeballScript : ItemScript
|
||||
}
|
||||
|
||||
public abstract byte GetCatchRate(IPokemon target);
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnUseWithTarget(IPokemon target)
|
||||
{
|
||||
var battleData = target.BattleData;
|
||||
if (battleData == null)
|
||||
return;
|
||||
|
||||
|
||||
battleData.Battle.AttempCapture(battleData.SideIndex, battleData.Position, Item);
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,7 @@ using PkmnLib.Static.Utils;
|
||||
|
||||
namespace PkmnLib.Dynamic.ScriptHandling.Registry;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
[MeansImplicitUse]
|
||||
[AttributeUsage(AttributeTargets.Class), MeansImplicitUse]
|
||||
public class ItemScriptAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -11,11 +11,11 @@ public abstract class Plugin
|
||||
protected Plugin()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
protected Plugin(PluginConfiguration configuration)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The name of the plugin. Mostly used for debugging purposes.
|
||||
/// </summary>
|
||||
|
||||
@@ -6,8 +6,7 @@ namespace PkmnLib.Dynamic.ScriptHandling.Registry;
|
||||
/// <summary>
|
||||
/// Helper attribute to register scripts through reflection.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
|
||||
[MeansImplicitUse]
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = false), MeansImplicitUse]
|
||||
public class ScriptAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -64,7 +64,7 @@ public class ScriptRegistry
|
||||
// This is more performant than using Activator.CreateInstance.
|
||||
_scriptTypes[(category, name)] = Expression.Lambda<Func<Script>>(Expression.New(constructor)).Compile();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Register an item script type with the given name.
|
||||
/// </summary>
|
||||
@@ -83,32 +83,32 @@ public class ScriptRegistry
|
||||
// This is more performant than using Activator.CreateInstance.
|
||||
var parameterExpression = Expression.Parameter(typeof(IItem), "item");
|
||||
var newExpression = Expression.New(constructor, parameterExpression);
|
||||
_itemScriptTypes[name] = Expression.Lambda<Func<IItem, ItemScript>>(newExpression, parameterExpression).Compile();
|
||||
_itemScriptTypes[name] =
|
||||
Expression.Lambda<Func<IItem, ItemScript>>(newExpression, parameterExpression).Compile();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register a battle stat calculator.
|
||||
/// </summary>
|
||||
public void RegisterBattleStatCalculator<T>(T battleStatCalculator)
|
||||
where T : IBattleStatCalculator => _battleStatCalculator = battleStatCalculator;
|
||||
public void RegisterBattleStatCalculator<T>(T battleStatCalculator) where T : IBattleStatCalculator =>
|
||||
_battleStatCalculator = battleStatCalculator;
|
||||
|
||||
/// <summary>
|
||||
/// Register a damage calculator.
|
||||
/// </summary>
|
||||
public void RegisterDamageCalculator<T>(T damageCalculator)
|
||||
where T : IDamageCalculator => _damageCalculator = damageCalculator;
|
||||
public void RegisterDamageCalculator<T>(T damageCalculator) where T : IDamageCalculator =>
|
||||
_damageCalculator = damageCalculator;
|
||||
|
||||
/// <summary>
|
||||
/// Register a misc library.
|
||||
/// </summary>
|
||||
public void RegisterMiscLibrary<T>(T miscLibrary) where T : IMiscLibrary
|
||||
=> _miscLibrary = miscLibrary;
|
||||
|
||||
public void RegisterMiscLibrary<T>(T miscLibrary) where T : IMiscLibrary => _miscLibrary = miscLibrary;
|
||||
|
||||
/// <summary>
|
||||
/// Register a capture library.
|
||||
/// </summary>
|
||||
public void RegisterCaptureLibrary<T>(T captureLibrary) where T : ICaptureLibrary
|
||||
=> _captureLibrary = captureLibrary;
|
||||
public void RegisterCaptureLibrary<T>(T captureLibrary) where T : ICaptureLibrary =>
|
||||
_captureLibrary = captureLibrary;
|
||||
|
||||
internal IReadOnlyDictionary<(ScriptCategory category, StringKey name), Func<Script>> ScriptTypes => _scriptTypes;
|
||||
internal IReadOnlyDictionary<StringKey, Func<IItem, ItemScript>> ItemScriptTypes => _itemScriptTypes;
|
||||
|
||||
@@ -9,14 +9,14 @@ namespace PkmnLib.Dynamic.ScriptHandling.Registry;
|
||||
public static class ScriptUtils
|
||||
{
|
||||
private static readonly Dictionary<Type, StringKey> NameCache = new();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Resolve name from the <see cref="ScriptAttribute"/> of the given script.
|
||||
/// </summary>
|
||||
public static StringKey ResolveName(this Script script) => ResolveName(script.GetType());
|
||||
|
||||
|
||||
public static StringKey ResolveName<T>() where T : Script => ResolveName(typeof(T));
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Resolve name from the <see cref="ScriptAttribute"/> of the given type.
|
||||
/// </summary>
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace PkmnLib.Dynamic.ScriptHandling;
|
||||
public abstract class Script : IDeepCloneable
|
||||
{
|
||||
internal event Action<Script>? OnRemoveEvent;
|
||||
|
||||
|
||||
private int _suppressCount;
|
||||
|
||||
public void RemoveSelf()
|
||||
@@ -76,14 +76,14 @@ public abstract class Script : IDeepCloneable
|
||||
public virtual void OnInitialize(IReadOnlyDictionary<StringKey, object?>? parameters)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Override to customize whether the move can be selected at all.
|
||||
/// </summary>
|
||||
public virtual void PreventMoveSelection(IMoveChoice choice, ref bool prevent)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public virtual void ForceTurnSelection(byte sideIndex, byte position, ref ITurnChoice? choice)
|
||||
{
|
||||
}
|
||||
@@ -121,7 +121,7 @@ public abstract class Script : IDeepCloneable
|
||||
public virtual void ChangeMove(IMoveChoice choice, ref StringKey moveName)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Changes the targets of a move choice. This allows for changing the targets of a move before the move starts.
|
||||
/// </summary>
|
||||
@@ -267,7 +267,7 @@ public abstract class Script : IDeepCloneable
|
||||
public virtual void BypassDefensiveStatBoosts(IExecutingMove move, IPokemon target, byte hit, ref bool bypass)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This function allows a script to bypass evasion stat boosts for a move hit.
|
||||
/// If this is true, the move will handle the evasion stat boosts as if the target has no positive stat boosts.
|
||||
@@ -527,11 +527,11 @@ public abstract class Script : IDeepCloneable
|
||||
public virtual void BlockIncomingHit(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref bool block)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public virtual void BlockOutgoingHit(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref bool block)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Custom triggers for scripts. This allows scripts to run custom events that are not part of the
|
||||
/// standard battle flow.
|
||||
@@ -555,7 +555,8 @@ public abstract class Script : IDeepCloneable
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void ChangeAccuracy(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref int modifiedAccuracy)
|
||||
public virtual void ChangeAccuracy(IExecutingMove executingMove, IPokemon target, byte hitIndex,
|
||||
ref int modifiedAccuracy)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ public enum ScriptCategory
|
||||
/// <see cref="IMoveChoice"/> and <see cref="IExecutingMove"/>
|
||||
/// </summary>
|
||||
Move = 0,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A volatile script effect that is attached to a move choice.
|
||||
/// </summary>
|
||||
@@ -54,7 +54,7 @@ public enum ScriptCategory
|
||||
/// A special script for weather, for use on battles.
|
||||
/// </summary>
|
||||
Weather = 7,
|
||||
|
||||
|
||||
Terrain = 8,
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -38,11 +38,7 @@ public class ScriptContainer : IEnumerable<ScriptContainer>, IDeepCloneable
|
||||
yield return this;
|
||||
}
|
||||
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
/// <summary>
|
||||
/// Assigns a new script to this container. If there was a script already, it is removed.
|
||||
@@ -65,7 +61,7 @@ public class ScriptContainer : IEnumerable<ScriptContainer>, IDeepCloneable
|
||||
}
|
||||
Script = null;
|
||||
}
|
||||
|
||||
|
||||
public void ClearWithoutRemoving()
|
||||
{
|
||||
Script = null;
|
||||
|
||||
@@ -66,5 +66,4 @@ public static class ScriptExecution
|
||||
itemScript.OnUse();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -44,16 +44,10 @@ public class ScriptIterator : IEnumerable<ScriptContainer>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerator<ScriptContainer> GetEnumerator()
|
||||
{
|
||||
return GetAsEnumerable().GetEnumerator();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
public IEnumerator<ScriptContainer> GetEnumerator() => GetAsEnumerable().GetEnumerator();
|
||||
|
||||
/// <inheritdoc />
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
}
|
||||
@@ -38,7 +38,7 @@ public class ScriptResolver
|
||||
{
|
||||
script.OnInitialize(parameters);
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ public class ScriptResolver
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
var effect = item.BattleEffect;
|
||||
if (effect == null)
|
||||
{
|
||||
|
||||
@@ -27,7 +27,7 @@ public interface IScriptSet : IEnumerable<ScriptContainer>
|
||||
/// Gets a script from the set using its unique name.
|
||||
/// </summary>
|
||||
ScriptContainer? Get(StringKey scriptKey);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets a script from the set using its type.
|
||||
/// </summary>
|
||||
@@ -155,8 +155,5 @@ public class ScriptSet : IScriptSet
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<StringKey> GetScriptNames() =>
|
||||
_scripts
|
||||
.Select(x => x.Script)
|
||||
.WhereNotNull()
|
||||
.Select(s => s.Name);
|
||||
_scripts.Select(x => x.Script).WhereNotNull().Select(s => s.Name);
|
||||
}
|
||||
@@ -9,7 +9,7 @@ public interface IScriptSource
|
||||
/// Gets an iterator over all scripts that are relevant for this source.
|
||||
/// </summary>
|
||||
ScriptIterator GetScripts();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The number of scripts that are expected to be relevant for this source. This generally is
|
||||
/// The number of its own scripts + the number of scripts for any parents.
|
||||
|
||||
@@ -10,7 +10,7 @@ public static class StaticHelpers
|
||||
/// may not be the same as the system time.
|
||||
/// </summary>
|
||||
public static Func<DateTimeOffset> DateTimeProvider { get; set; } = () => DateTimeOffset.Now;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get the current date and time.
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user