using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
namespace TcgEngine
{
///
/// Resolve abilties and actions one by one, with an optional delay in between each
///
public class ResolveQueue
{
private Pool ability_elem_pool = new Pool();
private Pool secret_elem_pool = new Pool();
private Pool attack_elem_pool = new Pool();
private Pool callback_elem_pool = new Pool();
private Queue ability_queue = new Queue();
private Queue secret_queue = new Queue();
private Queue attack_queue = new Queue();
private Queue callback_queue = new Queue();
private Game game_data;
private bool is_resolving = false;
private float resolve_delay = 0f;
private bool skip_delay = false;
public ResolveQueue(Game data, bool skip)
{
game_data = data;
skip_delay = skip;
}
public void SetData(Game data)
{
game_data = data;
}
public virtual void Update(float delta)
{
if (resolve_delay > 0f)
{
resolve_delay -= delta;
if (resolve_delay <= 0f)
ResolveAll();
}
}
public virtual void AddAbility(AbilityData ability, Card caster, Card triggerer, Action callback)
{
if (ability != null && caster != null)
{
AbilityQueueElement elem = ability_elem_pool.Create();
elem.caster = caster;
elem.triggerer = triggerer;
elem.ability = ability;
elem.callback = callback;
ability_queue.Enqueue(elem);
}
}
public virtual void AddAttack(Card attacker, Card target, Action callback, bool skip_cost = false)
{
if (attacker != null && target != null)
{
AttackQueueElement elem = attack_elem_pool.Create();
elem.attacker = attacker;
elem.target = target;
elem.ptarget = null;
elem.skip_cost = skip_cost;
elem.callback = callback;
attack_queue.Enqueue(elem);
}
}
public virtual void AddAttack(Card attacker, Player target, Action callback, bool skip_cost = false)
{
if (attacker != null && target != null)
{
AttackQueueElement elem = attack_elem_pool.Create();
elem.attacker = attacker;
elem.target = null;
elem.ptarget = target;
elem.skip_cost = skip_cost;
elem.pcallback = callback;
attack_queue.Enqueue(elem);
}
}
public virtual void AddSecret(AbilityTrigger secret_trigger, Card secret, Card trigger, Action callback)
{
if (secret != null && trigger != null)
{
SecretQueueElement elem = secret_elem_pool.Create();
elem.secret_trigger = secret_trigger;
elem.secret = secret;
elem.triggerer = trigger;
elem.callback = callback;
secret_queue.Enqueue(elem);
}
}
public virtual void AddCallback(Action callback)
{
if (callback != null)
{
CallbackQueueElement elem = callback_elem_pool.Create();
elem.callback = callback;
callback_queue.Enqueue(elem);
}
}
public virtual void Resolve()
{
if (ability_queue.Count > 0)
{
//Resolve Ability
AbilityQueueElement elem = ability_queue.Dequeue();
ability_elem_pool.Dispose(elem);
elem.callback?.Invoke(elem.ability, elem.caster, elem.triggerer);
}
else if (secret_queue.Count > 0)
{
//Resolve Secret
SecretQueueElement elem = secret_queue.Dequeue();
secret_elem_pool.Dispose(elem);
elem.callback?.Invoke(elem.secret_trigger, elem.secret, elem.triggerer);
}
else if (attack_queue.Count > 0)
{
//Resolve Attack
AttackQueueElement elem = attack_queue.Dequeue();
attack_elem_pool.Dispose(elem);
if (elem.ptarget != null)
elem.pcallback?.Invoke(elem.attacker, elem.ptarget, elem.skip_cost);
else
elem.callback?.Invoke(elem.attacker, elem.target, elem.skip_cost);
}
else if (callback_queue.Count > 0)
{
CallbackQueueElement elem = callback_queue.Dequeue();
callback_elem_pool.Dispose(elem);
elem.callback.Invoke();
}
}
public virtual void ResolveAll(float delay)
{
SetDelay(delay);
ResolveAll(); //Resolve now if no delay
}
public virtual void ResolveAll()
{
if (is_resolving)
return;
is_resolving = true;
while (CanResolve())
{
Resolve();
}
is_resolving = false;
}
public virtual void SetDelay(float delay)
{
if (!skip_delay)
{
resolve_delay = Mathf.Max(resolve_delay, delay);
}
}
public virtual bool CanResolve()
{
if (resolve_delay > 0f)
return false; //Is waiting delay
if (game_data.state == GameState.GameEnded)
return false; //Cant execute anymore when game is ended
if (game_data.selector != SelectorType.None)
return false; //Waiting for player input, in the middle of resolve loop
return attack_queue.Count > 0 || ability_queue.Count > 0 || secret_queue.Count > 0 || callback_queue.Count > 0;
}
public virtual bool IsResolving()
{
return is_resolving || resolve_delay > 0f;
}
public virtual void Clear()
{
attack_elem_pool.DisposeAll();
ability_elem_pool.DisposeAll();
secret_elem_pool.DisposeAll();
callback_elem_pool.DisposeAll();
attack_queue.Clear();
ability_queue.Clear();
secret_queue.Clear();
callback_queue.Clear();
}
public Queue GetAttackQueue()
{
return attack_queue;
}
public Queue GetAbilityQueue()
{
return ability_queue;
}
public Queue GetSecretQueue()
{
return secret_queue;
}
public Queue GetCallbackQueue()
{
return callback_queue;
}
}
public class AbilityQueueElement
{
public AbilityData ability;
public Card caster;
public Card triggerer;
public Action callback;
}
public class AttackQueueElement
{
public Card attacker;
public Card target;
public Player ptarget;
public bool skip_cost;
public Action callback;
public Action pcallback;
}
public class SecretQueueElement
{
public AbilityTrigger secret_trigger;
public Card secret;
public Card triggerer;
public Action callback;
}
public class CallbackQueueElement
{
public Action callback;
}
}