using MessagePack; using OECS; namespace Game.CardWars; /// /// Play a card from hand to the field, choosing a rank. /// Resolves on-play effects via the CardEffectRegistry. /// [MessagePackObject] public struct PlayCardCommand : ICommand { [Key(0)] public Entity CardEntity; [Key(1)] public int Rank; [Key(2)] public bool FaceDown; [Key(3)] public Entity? TargetPlayer; public void Execute(World world) { var state = world.ReadSingleton(); if (state.Phase is not GamePhase.PlayPhase) return; if (!world.IsAlive(CardEntity)) return; Entity player = FindPlayerByIndex(world, state.CurrentPlayerIndex); if (player == Entity.Null) return; // Verify the card is in the player's hand. if (!world.HasComponent(CardEntity)) return; var heldBy = world.ReadComponent(CardEntity); if (heldBy.Target != player) return; var def = world.ReadComponent(CardEntity); // Determine target: Witch/Thief are played to another player's field. Entity fieldOwner = def.Effect is CardEffect.Witch or CardEffect.Thief ? (TargetPlayer ?? player) : player; // Move from hand to field. world.RemoveComponent(CardEntity); world.AddComponent(CardEntity, new OnField { Target = fieldOwner }); world.AddComponent(CardEntity, new Card { Rank = Rank, FaceDown = FaceDown }); // Resolve on-play effects via registry. if (!FaceDown) CardEffectRegistry.Dispatch(world, def.Effect, CardEntity, player, fieldOwner); world.MarkModified(World.SingletonEntity); } public static Entity FindPlayerByIndex(World world, int index) { using var iter = world.Select(); while (iter.MoveNext()) { if (iter.CurrentEntity == World.SingletonEntity) continue; if (iter.Current1.Index == index) return iter.CurrentEntity; } return Entity.Null; } }