162 lines
5.5 KiB
C#
162 lines
5.5 KiB
C#
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 { 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 { 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 { 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 { Target = drawDeck });
|
|
}
|
|
}
|
|
} |