using OECS;
namespace Game.CardWars;
///
/// Shared utility methods for querying and manipulating the game world.
///
public static class GameUtil
{
public static Entity FindEntity(World world) where T : struct
{
using var iter = world.Select();
while (iter.MoveNext())
{
if (iter.CurrentEntity != World.SingletonEntity)
return iter.CurrentEntity;
}
return Entity.Null;
}
public static List FindAllEntities(World world) where T : struct
{
var list = new List();
using var iter = world.Select();
while (iter.MoveNext())
{
if (iter.CurrentEntity != World.SingletonEntity)
list.Add(iter.CurrentEntity);
}
return list;
}
/// Draw the top card from a deck and add it to the player's hand.
public static bool DrawCard(World world, Entity deck, Entity player)
{
var cards = world.GetSources(deck);
if (cards.Count == 0) return false;
var cardEntity = cards.First();
world.RemoveComponent(cardEntity);
world.AddComponent(cardEntity, new HeldBy { Source = cardEntity, Target = player });
return true;
}
/// Shuffle cards in a deck using Fisher-Yates with the given seed.
public static void ShuffleDeck(World world, Entity deck, ref uint seed)
{
var cards = world.GetSources(deck).ToArray();
for (int i = cards.Length - 1; i > 0; i--)
{
int j = Mulberry32.NextInt(ref seed, 0, i);
(cards[i], cards[j]) = (cards[j], cards[i]);
}
for (int i = cards.Length - 1; i >= 0; i--)
world.RemoveComponent(cards[i]);
for (int i = 0; i < cards.Length; i++)
world.AddComponent(cards[i], new InDeck { Source = cards[i], Target = deck });
}
/// Get all field cards for a player.
public static List GetFieldCards(World world, Entity player)
{
return world.GetSources(player).ToList();
}
/// Get all cards in a player's hand.
public static List GetHandCards(World world, Entity player)
{
return world.GetSources(player).ToList();
}
/// Calculate a player's total battle power.
public static int CalculatePower(World world, Entity player)
{
int total = 0;
// Leader power.
using var leaderIter = world.Select();
while (leaderIter.MoveNext())
{
if (leaderIter.CurrentEntity == World.SingletonEntity) continue;
var onFieldSources = world.GetSources(player);
if (onFieldSources.Contains(leaderIter.CurrentEntity))
{
if (world.TryGetComponent(leaderIter.CurrentEntity, out var leaderCard))
total += leaderCard.Rank;
}
}
// Find the player's banner.
var banner = CardEffectHelpers.GetBanner(world, player);
bool bannerHasHorn = banner != Entity.Null && world.HasComponent(banner);
bool bannerHasSkull = banner != Entity.Null && world.HasComponent(banner);
// Field cards.
var fieldCards = GetFieldCards(world, player);
int poweredCount = 0;
foreach (var card in fieldCards)
{
if (!world.TryGetComponent(card, out var cardData)) continue;
if (cardData.FaceDown) continue;
if (cardData.Rank <= 0) continue;
poweredCount++;
int rank = cardData.Rank;
if (world.HasComponent(card))
rank *= 2;
if (world.HasComponent(card))
rank = 0;
total += rank;
}
if (bannerHasHorn) total += poweredCount;
if (bannerHasSkull) total -= poweredCount;
return total;
}
/// Move all field cards (except leaders and banners) to the discard pile.
public static void DiscardField(World world, Entity player, Entity discardDeck)
{
var fieldCards = GetFieldCards(world, player);
var toDiscard = new List();
foreach (var card in fieldCards)
{
// Keep leaders and banners on the field.
if (world.HasComponent(card)) continue;
if (world.HasComponent(card)) continue;
toDiscard.Add(card);
}
foreach (var card in toDiscard)
{
world.RemoveComponent(card);
world.RemoveComponent(card);
world.AddComponent(card, new InDeck { Source = card, Target = discardDeck });
}
// Destroy horns and skulls placed on discarded cards.
var tokenTargets = new HashSet();
foreach (var card in toDiscard)
{
foreach (var token in world.GetSources(card))
tokenTargets.Add(token);
}
foreach (var token in tokenTargets)
world.DestroyEntity(token);
}
/// Recycle discard pile into draw pile.
public static void RecycleDiscard(World world, Entity drawDeck, Entity discardDeck)
{
var cards = world.GetSources(discardDeck).ToList();
foreach (var card in cards)
{
world.RemoveComponent(card);
world.AddComponent(card, new InDeck { Source = card, Target = drawDeck });
}
}
}