using OECS; namespace Game.CardWars; // ──────────────────────────────────────────────────────────── // Simple effects that resolve immediately. // ──────────────────────────────────────────────────────────── public class WarriorEffect : ICardEffect { public CardEffect Effect => CardEffect.Warrior; public bool Resolve(World world, Entity card, Entity player, Entity owner) { if (HasOtherOnField(world, owner, card, CardEffect.Warrior)) CardEffectHelpers.AddHorn(world, card); return true; } public bool ResolveChoice(World world, Entity target) => true; private static bool HasOtherOnField(World world, Entity player, Entity self, CardEffect effect) { return GameUtil.GetFieldCards(world, player) .Any(c => c != self && world.HasComponent(c) && world.ReadComponent(c).Effect == effect); } } public class ArcherEffect : ICardEffect { public CardEffect Effect => CardEffect.Archer; public bool Resolve(World world, Entity card, Entity player, Entity owner) { if (HasOtherOnField(world, owner, card, CardEffect.Archer)) { var banner = CardEffectHelpers.GetBanner(world, owner); if (banner != Entity.Null) CardEffectHelpers.AddHorn(world, banner); } return true; } public bool ResolveChoice(World world, Entity target) => true; private static bool HasOtherOnField(World world, Entity player, Entity self, CardEffect effect) { return GameUtil.GetFieldCards(world, player) .Any(c => c != self && world.HasComponent(c) && world.ReadComponent(c).Effect == effect); } } public class MercenaryEffect : ICardEffect { public CardEffect Effect => CardEffect.Mercenary; public bool Resolve(World world, Entity card, Entity player, Entity owner) { if (!HasOtherOnField(world, owner, card, CardEffect.Mercenary)) return true; world.SetSingleton(new PendingMercenary { CardEntity = card, Player = player }); return false; } public bool ResolveChoice(World world, Entity target) { var pending = world.ReadSingleton(); if (target != Entity.Null) CardEffectHelpers.AddSkull(world, target); world.RemoveSingleton(); return true; } private static bool HasOtherOnField(World world, Entity player, Entity self, CardEffect effect) { return GameUtil.GetFieldCards(world, player) .Any(c => c != self && world.HasComponent(c) && world.ReadComponent(c).Effect == effect); } } public class MerchantEffect : ICardEffect { public CardEffect Effect => CardEffect.Merchant; public bool Resolve(World world, Entity card, Entity player, Entity owner) { world.Commands.Enqueue(new DrawCardCommand { Player = player, Kind = null }); world.Commands.Enqueue(new ExtraActionCommand()); return true; } public bool ResolveChoice(World world, Entity target) => true; } public class DancerEffect : ICardEffect { public CardEffect Effect => CardEffect.Dancer; public bool Resolve(World world, Entity card, Entity player, Entity owner) { var powered = GameUtil.GetFieldCards(world, owner) .Where(c => world.HasComponent(c) && world.ReadComponent(c).Rank > 0) .ToList(); if (powered.Count == 0) return true; if (powered.Count <= 2) { foreach (var c in powered) CardEffectHelpers.AddHorn(world, c); return true; } world.SetSingleton(new PendingDancer { CardEntity = card, Player = player, Step = 0 }); return false; } public bool ResolveChoice(World world, Entity target) { var pending = world.ReadSingleton(); if (target != Entity.Null) CardEffectHelpers.AddHorn(world, target); if (pending.Step == 0) { world.SetSingleton(new PendingDancer { CardEntity = pending.CardEntity, Player = pending.Player, Step = 1 }); return false; } world.RemoveSingleton(); return true; } } public class PaladinEffect : ICardEffect { public CardEffect Effect => CardEffect.Paladin; public bool Resolve(World world, Entity card, Entity player, Entity owner) { world.SetSingleton(new PendingPaladin { CardEntity = card, Player = player }); return false; } public bool ResolveChoice(World world, Entity target) { if (target != Entity.Null) CardEffectHelpers.AddHorn(world, target); world.RemoveSingleton(); return true; } } public class PrincessEffect : ICardEffect { public CardEffect Effect => CardEffect.Princess; public bool Resolve(World world, Entity card, Entity player, Entity owner) { world.Commands.Enqueue(new ReplaceCastleCommand()); return true; } public bool ResolveChoice(World world, Entity target) => true; } public class DuelistEffect : ICardEffect { public CardEffect Effect => CardEffect.Duelist; public bool Resolve(World world, Entity card, Entity player, Entity owner) { world.Commands.Enqueue(new EndPlayPhaseCommand()); return true; } public bool ResolveChoice(World world, Entity target) => true; } public class NunEffect : ICardEffect { public CardEffect Effect => CardEffect.Nun; public bool Resolve(World world, Entity card, Entity player, Entity owner) { var fieldCards = GameUtil.GetFieldCards(world, owner); if (fieldCards.Count == 0) { world.Commands.Enqueue(new DrawCardCommand { Player = player, Kind = null }); return true; } world.SetSingleton(new PendingNun { CardEntity = card, Player = player }); return false; } public bool ResolveChoice(World world, Entity target) { var pending = world.ReadSingleton(); if (target != Entity.Null) { var discardDeck = CardEffectHelpers.GetDiscardDeck(world, pending.Player); world.RemoveComponent(target); if (world.HasComponent(target)) world.RemoveComponent(target); world.AddComponent(target, new InDeck { Target = discardDeck }); } world.Commands.Enqueue(new DrawCardCommand { Player = pending.Player, Kind = null }); world.RemoveSingleton(); return true; } } public class ScoutEffect : ICardEffect { public CardEffect Effect => CardEffect.Scout; public bool Resolve(World world, Entity card, Entity player, Entity owner) { world.SetSingleton(new PendingScout { CardEntity = card, Player = player }); return false; } public bool ResolveChoice(World world, Entity target) { var pending = world.ReadSingleton(); if (target != Entity.Null && world.HasComponent(target)) { foreach (var c in GameUtil.GetFieldCards(world, target)) { if (world.TryGetComponent(c, out var cd) && cd.FaceDown) { ref var cardRef = ref world.GetComponent(c); cardRef.FaceDown = false; world.MarkModified(c); } } } world.RemoveSingleton(); return true; } } public class WitchEffect : ICardEffect { public CardEffect Effect => CardEffect.Witch; public bool Resolve(World world, Entity card, Entity player, Entity owner) { var banner = CardEffectHelpers.GetBanner(world, owner); if (banner != Entity.Null) CardEffectHelpers.AddSkull(world, banner); return true; } public bool ResolveChoice(World world, Entity target) => true; } public class ThiefEffect : ICardEffect { public CardEffect Effect => CardEffect.Thief; public bool Resolve(World world, Entity card, Entity player, Entity owner) { return true; } public bool ResolveChoice(World world, Entity target) => true; } // ──────────────────────────────────────────────────────────── // Face-down flip effects // ──────────────────────────────────────────────────────────── public class PegasusEffect : ICardEffect { public CardEffect Effect => CardEffect.Pegasus; public bool Resolve(World world, Entity card, Entity player, Entity owner) { world.SetSingleton(new PendingPegasus { CardEntity = card, Player = player }); return false; } public bool ResolveChoice(World world, Entity target) { var pending = world.ReadSingleton(); if (target != Entity.Null && target != pending.CardEntity) { world.RemoveComponent(target); if (world.HasComponent(target)) world.RemoveComponent(target); world.AddComponent(target, new HeldBy { Target = pending.Player }); } world.RemoveSingleton(); return true; } } public class CurseMasterEffect : ICardEffect { public CardEffect Effect => CardEffect.CurseMaster; public bool Resolve(World world, Entity card, Entity player, Entity owner) { world.SetSingleton(new PendingCurseMaster { CardEntity = card, Player = player }); return false; } public bool ResolveChoice(World world, Entity target) { var pending = world.ReadSingleton(); if (target != Entity.Null && world.HasComponent(target)) { var placedTargets = world.GetSources(target).ToList(); world.DestroyEntity(target); foreach (var pt in placedTargets) { var skull = world.CreateEntity(); world.AddComponent(skull, new Skull()); world.AddComponent(skull, new PlacedOn { Target = pt }); } } world.RemoveSingleton(); return true; } } public class MageEffect : ICardEffect { public CardEffect Effect => CardEffect.Mage; public bool Resolve(World world, Entity card, Entity player, Entity owner) { Entity best = Entity.Null; int bestRank = int.MinValue; foreach (var p in GameUtil.FindAllEntities(world)) { foreach (var c in GameUtil.GetFieldCards(world, p)) { if (world.TryGetComponent(c, out var cd) && !cd.FaceDown && cd.Rank > bestRank) { bestRank = cd.Rank; best = c; } } } if (best != Entity.Null) CardEffectHelpers.AddSkull(world, best); return true; } public bool ResolveChoice(World world, Entity target) => true; } // ──────────────────────────────────────────────────────────── // Shared helpers // ──────────────────────────────────────────────────────────── public static class CardEffectHelpers { public static void AddHorn(World world, Entity target) { var horn = world.CreateEntity(); world.AddComponent(horn, new Horn()); world.AddComponent(horn, new PlacedOn { Target = target }); } public static void AddSkull(World world, Entity target) { var skull = world.CreateEntity(); world.AddComponent(skull, new Skull()); world.AddComponent(skull, new PlacedOn { Target = target }); } public static Entity GetBanner(World world, Entity player) { using var iter = world.Select(); while (iter.MoveNext()) { if (iter.CurrentEntity == World.SingletonEntity) continue; var onField = world.GetSources(player); if (onField.Contains(iter.CurrentEntity)) return iter.CurrentEntity; } return Entity.Null; } public static Entity GetDiscardDeck(World world, Entity player) { using var iter = world.Select(); while (iter.MoveNext()) { if (iter.CurrentEntity != World.SingletonEntity) return iter.CurrentEntity; } return Entity.Null; } }