using System; using System.Collections.Generic; using System.Linq; using PkmnLibSharp.Battling.ChoiceTurn; using PkmnLibSharp.Battling.Events; using PkmnLibSharp.Battling.History; using PkmnLibSharp.Utilities; namespace PkmnLibSharp.Battling { public class Battle : PointerWrapper { public Battle(BattleLibrary library, BattleParty[] parties, bool canFlee, byte numberOfSides, byte pokemonPerSide, ulong randomSeed) { var ptr = IntPtr.Zero; var arr = parties.Select(x => x.Ptr).ToArray(); Pkmnlib.Generated.Battle.Construct(ref ptr, library.Ptr, arr.ArrayPtr(), (ulong) arr.Length, canFlee.ToNative(), numberOfSides, pokemonPerSide, randomSeed).Assert(); Initialize(ptr); } public BattleLibrary Library { get { if (_library != null) return _library; var ptr = Creaturelib.Generated.Battle.GetLibrary(Ptr); if (TryResolvePointer(ptr, out _library)) { return _library!; } _library = new BattleLibrary(ptr); return _library; } } public BattleRandom Random { get { if (_random != null) return _random; var ptr = Creaturelib.Generated.Battle.GetRandom(Ptr); if (TryResolvePointer(ptr, out _random)) { return _random!; } _random = new BattleRandom(ptr); return _random; } } public bool CanFlee => Creaturelib.Generated.Battle.CanFlee(Ptr) == 1; public bool HasEnded => Creaturelib.Generated.Battle.HasEnded(Ptr) == 1; public bool HasConclusiveResult => Creaturelib.Generated.Battle.HasConclusiveResult(Ptr) == 1; public byte WinningSide => Creaturelib.Generated.Battle.GetWinningSide(Ptr); public ulong SidesCount => Creaturelib.Generated.Battle.GetSidesCount(Ptr); public ulong PartiesCount => Creaturelib.Generated.Battle.GetPartiesCount(Ptr); public ulong MonsPerSide => Creaturelib.Generated.Battle.GetCreaturesPerSide(Ptr); public long LastTurnTimeMicroseconds => Creaturelib.Generated.Battle.GetLastTurnTimeMicroseconds(Ptr); private bool _cleared; public ReadOnlyNativePtrArray Sides { get { if (_sides != null) return _sides; var ptr = Creaturelib.Generated.Battle.GetSides(Ptr); _sides = new ReadOnlyNativePtrArray(ptr, (int) SidesCount, Constructor.GenericType.BattleSide); return _sides; } } public uint CurrentTurn => Creaturelib.Generated.Battle.GetCurrentTurn(Ptr); public ReadOnlyNativePtrArray Parties { get { if (_parties != null) return _parties; var ptr = Creaturelib.Generated.Battle.GetParties(Ptr); _parties = new ReadOnlyNativePtrArray(ptr, (int) PartiesCount, Constructor.GenericType.BattleParty); return _parties; } } public string? WeatherName => Pkmnlib.Generated.Battle.GetWeatherName(Ptr).PtrString(); public HistoryHandler History { get { if (_history != null) return _history; var ptr = Creaturelib.Generated.Battle.GetHistory(Ptr); if (TryResolvePointer(ptr, out _history)) return _history!; _history = new HistoryHandler(ptr); return _history; } } public bool CanUse(BaseTurnChoice turnChoice) { byte b = 0; Creaturelib.Generated.Battle.CanUse(ref b, Ptr, turnChoice.Ptr).Assert(); return b == 1; } private readonly List _choiceCache = new List(); public bool TrySetChoice(BaseTurnChoice turnChoice) { byte b = 0; var initialTurn = CurrentTurn; _choiceCache.Add(turnChoice); var t1 = System.Diagnostics.Stopwatch.StartNew(); Creaturelib.Generated.Battle.TrySetChoice(ref b, Ptr, turnChoice.Ptr).Assert(); t1.Stop(); if (b == 1 && CurrentTurn != initialTurn) { LogHandler.Log(LogHandler.LogLevel.Information, $"Ran turn in {t1.ElapsedMilliseconds} ms, battle reported {LastTurnTimeMicroseconds} microseconds"); _choiceCache.Clear(); } return b == 1; } public void EndBattle() { Creaturelib.Generated.Battle.EndBattle(Ptr).Assert(); } public void CheckChoicesSetAndRun() { Creaturelib.Generated.Battle.CheckChoicesSetAndRun(Ptr); } public bool IsPokemonInField(Pokemon pokemon) { byte b = 0; Creaturelib.Generated.Battle.CreatureInField(ref b, Ptr, pokemon.Ptr).Assert(); return b == 1; } public Pokemon GetPokemonInField(byte side, byte index) { var ptr = IntPtr.Zero; Creaturelib.Generated.Battle.GetCreature(ref ptr, Ptr, side, index).Assert(); return TryResolvePointer(ptr, out Pokemon? pokemon) ? pokemon! : Constructor.Active.ConstructPokemon(ptr)!; } public void ForceRecall(byte side, byte index) { Creaturelib.Generated.Battle.ForceRecall(Ptr, side, index).Assert(); } public void SwitchPokemon(byte side, byte index, Pokemon newPokemon) { Creaturelib.Generated.Battle.SwitchCreature(Ptr, side, index, newPokemon.Ptr).Assert(); } public bool CanSlotBeFilled(byte side, byte index) { byte b = 0; Creaturelib.Generated.Battle.CanSlotBeFilled(ref b, Ptr, side, index).Assert(); return b == 1; } public void ValidateBattleState() { Creaturelib.Generated.Battle.ValidateBattleState(Ptr).Assert(); } public Script GetVolatileScript(string key) { var ptr = Creaturelib.Generated.Battle.GetVolatileScript(Ptr, key.ToPtr()); if (TryResolvePointer(ptr, out Script? script)) { return script!; } // TODO: Handle with different script providers. return new AngelscriptScript(ptr); } public void AddVolatileScript(string key) { Creaturelib.Generated.Battle.AddVolatileScriptByName(Ptr, key.ToPtr()).Assert(); } public void AddVolatileScript(Script script) { Creaturelib.Generated.Battle.AddVolatileScript(Ptr, script.Ptr).Assert(); } public void RemoveVolatileScript(string key) { Creaturelib.Generated.Battle.RemoveVolatileScript(Ptr, key.ToPtr()).Assert(); } public void RemoveVolatileScript(Script script) { Creaturelib.Generated.Battle.RemoveVolatileScriptWithScript(Ptr, script.Ptr).Assert(); } public bool HasVolatileScript(string key) { return Creaturelib.Generated.Battle.HasVolatileScript(Ptr, key.ToPtr()) == 1; } private List _listeners = new List(); public void RegisterEventListener(BattleEventListener listener) { _listeners.Add(listener); Creaturelib.Generated.Battle.RegisterEventListener(Ptr, listener.FunctionPtr).Assert(); } public void SetWeather(string weatherName) { Pkmnlib.Generated.Battle.SetWeather(Ptr, weatherName.ToPtr()); } public void ClearWeather() { Pkmnlib.Generated.Battle.ClearWeather(Ptr); } private BattleLibrary? _library; private BattleRandom? _random; private ReadOnlyNativePtrArray? _sides; private ReadOnlyNativePtrArray? _parties; private HistoryHandler? _history; public void ClearBattle() { if (_cleared) return; _cleared = true; Creaturelib.Generated.Battle.ClearBattle(Ptr); } protected override void DeletePtr() { Pkmnlib.Generated.Battle.Destruct(Ptr); } public override void Dispose() { if (!IsDeleted) { ClearBattle(); } base.Dispose(); } } }