Lots more work on implementing battling

This commit is contained in:
2024-08-10 09:44:46 +02:00
parent 554e1cf2cd
commit a049dda240
29 changed files with 1226 additions and 48 deletions

View File

@@ -217,7 +217,7 @@ public interface IPokemon : IScriptSource
/// <param name="stat">The stat to be changed</param>
/// <param name="change">The amount to change the stat by</param>
/// <param name="selfInflicted">Whether the change was self-inflicted. This can be relevant in scripts.</param>
void ChangeStatBoost(Statistic stat, sbyte change, bool selfInflicted);
bool ChangeStatBoost(Statistic stat, sbyte change, bool selfInflicted);
/// <summary>
/// Returns the currently active ability.
@@ -283,6 +283,27 @@ public interface IPokemon : IScriptSource
/// </summary>
void ChangeLevelBy(int change);
/// <summary>
/// Sets the current battle the Pokémon is in.
/// </summary>
void SetBattleData(IBattle battle, byte sideIndex);
/// <summary>
/// Sets whether the Pokémon is on the battlefield.
/// </summary>
void SetOnBattlefield(bool onBattleField);
/// <summary>
/// Sets the position the Pokémon has within its side.
/// </summary>
/// <param name="position"></param>
void SetBattleSidePosition(byte position);
/// <summary>
/// Marks a Pokemon as seen in the battle.
/// </summary>
void MarkOpponentAsSeen(IPokemon pokemon);
// TODO: (de)serialize
}
@@ -295,25 +316,35 @@ public interface IPokemonBattleData
/// <summary>
/// The battle the Pokemon is in.
/// </summary>
IBattle Battle { get; }
IBattle Battle { get; internal set; }
/// <summary>
/// The index of the side of the Pokemon
/// </summary>
byte SideIndex { get; }
byte SideIndex { get; internal set; }
/// <summary>
/// The index of the position of the Pokemon on the field
/// </summary>
byte Position { get; }
byte Position { get; internal set; }
/// <summary>
/// A list of opponents the Pokemon has seen this battle.
/// </summary>
IReadOnlyList<IPokemon> SeenOpponents { get; }
/// <summary>
/// Whether the Pokemon is on the battlefield.
/// </summary>
bool IsOnBattlefield { get; set; }
/// <summary>
/// Adds an opponent to the list of seen opponents.
/// </summary>
void MarkOpponentAsSeen(IPokemon opponent);
}
/// <inheritdoc />
/// <inheritdoc cref="IPokemon"/>
public class PokemonImpl : ScriptSource, IPokemon
{
/// <inheritdoc cref="PokemonImpl"/>
@@ -358,7 +389,7 @@ public class PokemonImpl : ScriptSource, IPokemon
public IForm? DisplayForm { get; set; }
/// <inheritdoc />
public LevelInt Level { get; }
public LevelInt Level { get; private set; }
/// <inheritdoc />
public uint Experience { get; }
@@ -468,13 +499,42 @@ public class PokemonImpl : ScriptSource, IPokemon
/// <inheritdoc />
public bool ConsumeHeldItem()
{
if (HeldItem is null)
return false;
if (!Library.ScriptResolver.TryResolveItemScript(HeldItem, out _))
return false;
// TODO: actually consume the item
throw new NotImplementedException();
}
/// <inheritdoc />
public void ChangeStatBoost(Statistic stat, sbyte change, bool selfInflicted)
public bool ChangeStatBoost(Statistic stat, sbyte change, bool selfInflicted)
{
throw new NotImplementedException();
var prevented = false;
this.RunScriptHook(script => script.PreventStatBoostChange(this, stat, change, selfInflicted, ref prevented));
if (prevented)
return false;
this.RunScriptHook(script => script.ChangeStatBoostChange(this, stat, selfInflicted, ref change));
if (change == 0)
return false;
var changed = false;
var oldBoost = StatBoost.GetStatistic(stat);
changed = change switch
{
> 0 => StatBoost.IncreaseStatistic(stat, change),
< 0 => StatBoost.DecreaseStatistic(stat, change),
_ => changed
};
if (!changed)
return false;
if (BattleData != null)
{
var newBoost = StatBoost.GetStatistic(stat);
BattleData.Battle.EventHook.Invoke(new StatBoostEvent(this, stat, oldBoost, newBoost));
}
RecalculateBoostedStats();
return true;
}
/// <inheritdoc />
@@ -499,10 +559,7 @@ public class PokemonImpl : ScriptSource, IPokemon
}
/// <inheritdoc />
public void RecalculateBoostedStats()
{
Library.StatCalculator.CalculateBoostedStats(this, BoostedStats);
}
public void RecalculateBoostedStats() => Library.StatCalculator.CalculateBoostedStats(this, BoostedStats);
/// <inheritdoc />
public void ChangeSpecies(ISpecies species, IForm form)
@@ -612,6 +669,7 @@ public class PokemonImpl : ScriptSource, IPokemon
break;
}
}
if (index >= Moves.Count)
throw new InvalidOperationException("No empty move slot found.");
if (!Library.StaticLibrary.Moves.TryGet(moveName, out var move))
@@ -621,17 +679,57 @@ public class PokemonImpl : ScriptSource, IPokemon
}
/// <inheritdoc />
public void ClearStatus()
{
throw new NotImplementedException();
}
public void ClearStatus() => StatusScript.Clear();
/// <inheritdoc />
public void ChangeLevelBy(int change)
{
throw new NotImplementedException();
var newLevel = Level + change;
Level = (LevelInt)Math.Clamp(newLevel, 1, Library.StaticLibrary.Settings.MaxLevel);
RecalculateFlatStats();
}
/// <inheritdoc />
public void SetBattleData(IBattle battle, byte sideIndex)
{
if (BattleData is not null)
{
BattleData.Battle = battle;
BattleData.SideIndex = sideIndex;
}
else
{
BattleData = new PokemonBattleDataImpl(battle, sideIndex);
}
}
/// <inheritdoc />
public void SetOnBattlefield(bool onBattleField)
{
if (BattleData is not null)
{
BattleData.IsOnBattlefield = onBattleField;
if (!onBattleField)
{
Volatile.Clear();
WeightInKm = Form.Weight;
HeightInMeters = Form.Height;
}
}
}
/// <inheritdoc />
public void SetBattleSidePosition(byte position)
{
if (BattleData is not null)
{
BattleData.Position = position;
}
}
/// <inheritdoc />
public void MarkOpponentAsSeen(IPokemon pokemon) => BattleData?.MarkOpponentAsSeen(pokemon);
/// <inheritdoc />
public override int ScriptCount
{
@@ -667,4 +765,37 @@ public class PokemonImpl : ScriptSource, IPokemon
side.CollectScripts(scripts);
}
}
}
/// <inheritdoc />
public class PokemonBattleDataImpl : IPokemonBattleData
{
/// <inheritdoc cref="PokemonBattleDataImpl"/>
public PokemonBattleDataImpl(IBattle battle, byte sideIndex)
{
Battle = battle;
SideIndex = sideIndex;
}
/// <inheritdoc />
public IBattle Battle { get; set; }
/// <inheritdoc />
public byte SideIndex { get; set; }
/// <inheritdoc />
public byte Position { get; set; }
private readonly List<IPokemon> _seenOpponents = [];
/// <inheritdoc />
public IReadOnlyList<IPokemon> SeenOpponents => _seenOpponents;
/// <inheritdoc />
public bool IsOnBattlefield { get; set; }
/// <inheritdoc />
public void MarkOpponentAsSeen(IPokemon opponent)
{
_seenOpponents.Add(opponent);
}
}