using PkmnLib.Dynamic.Models.Choices; using PkmnLib.Dynamic.ScriptHandling; using PkmnLib.Static.Utils; namespace PkmnLib.Dynamic.Models.BattleFlow; public static class TurnRunner { public static void RunTurn(this IBattle battle) { 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. // The first thing to do is to run the on_before_turn script hook on every choice. This script hook // is primarily intended to be used to reset variables on a script (for example scripts that need // to check whether a Pokémon was hit this turn. By resetting here, and setting a variable to true // they can then know this later on.) foreach (var choice in queue.GetChoices().WhereNotNull()) { 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. while (queue.HasNext() && !battle.HasEnded) { var next = queue.Dequeue(); if (next == null) 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. // As we want all scripts to run exactly once, including those on the sides and battles, // we can't just use the default script hook on each Pokémon. Instead, manually call // the script functions on every script. if (!battle.HasEnded) { var scripts = new List>(10); foreach (var side in battle.Sides) { foreach (var pokemon in side.Pokemon.WhereNotNull()) { scripts.Clear(); pokemon.GetOwnScripts(scripts); scripts.RunScriptHook(x => x.OnEndTurn()); } scripts.Clear(); side.GetOwnScripts(scripts); scripts.RunScriptHook(x => x.OnEndTurn()); } scripts.Clear(); battle.GetOwnScripts(scripts); scripts.RunScriptHook(x => x.OnEndTurn()); } } private static void ExecuteChoice(IBattle battle, ITurnChoice choice) { if (choice is IPassChoice) return; if (battle.HasEnded) return; if (!choice.User.IsUsable) return; if (choice.User.BattleData?.IsOnBattlefield != true) return; switch (choice) { case IMoveChoice moveChoice: MoveTurnExecutor.ExecuteMoveChoice(battle, moveChoice); break; // TODO: Implement other choice types } } }