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 }); } } }