oecs-sharp/Game.CardWars/GameUtil.cs

162 lines
5.5 KiB
C#
Raw Normal View History

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