using DominionBase.Enums; using DominionBase.Piles; using DominionBase.Players; using DominionBase.Properties; using System; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Linq; namespace DominionBase.Cards.Nocturne { public class Ghost : Card { private readonly CardCollection _ghostedCards = new CardCollection(); private IPlayer _turnStartedPlayer; public const int BaseCount = 6; public Ghost() : base(Categories.Night | Categories.Duration | Categories.Spirit, Source.Nocturne, Location.Special, Traits.Multiplier) { BaseCost = new Cost(4, special: true); } public static void SetupSupply(IGame game) { Contract.Requires(game != null, "game cannot be null"); if (!game.Table.SpecialPiles.ContainsKey(TypeClass.Ghost)) { var supply = new Supply(game, game.Players, TypeClass.Ghost, BaseCount); supply.FullSetup(); game.Table.SpecialPiles.Add(TypeClass.Ghost, supply); } } public override void TearDown(IGame game) { base.TearDown(game); _ghostedCards.Clear(); if (_turnStartedPlayer != null) _turnStartedPlayer.TurnStarted -= Player_TurnStarted; _turnStartedPlayer = null; } public override IEnumerable LookThrough(Predicate predicate) { return _ghostedCards.Where(c => predicate(c)); } public override bool IsStackable => _ghostedCards.Count == 0; public override DisplayableCollection Stack() { var cc = new DisplayableCollection(_ghostedCards) { this }; return cc; } public override void FollowInstructions(IPlayer player) { Contract.Requires(player != null, "player cannot be null"); base.FollowInstructions(player); player.BeginDrawing(); while (!player.Revealed[Categories.Action].Any() && player.CanDraw) player.Draw(DeckLocation.Revealed); player.EndDrawing(); player.Revealed.BeginChanges(); var actions = player.Revealed[Categories.Action]; player.DiscardRevealed(c => !actions.Contains(c)); player.Revealed.EndChanges(); // Set the card aside var setAside = player.RetrieveCardsFrom(DeckLocation.Revealed); _ghostedCards.AddRange(setAside); CanCleanUpPlayed.Add(!setAside.Any()); //CanCleanUp = !_ghostedCards.Any(); if (_ghostedCards.Any()) { _turnStartedPlayer = player; _turnStartedPlayer.TurnStarted += Player_TurnStarted; } player._Game.SendMessage(player, this, "SetAside", setAside.ToArray()); } public override void ResolveDuration(IPlayer player) { Contract.Requires(player != null, "player cannot be null"); base.ResolveDuration(player); // Play Ghost'ed card if (_ghostedCards.Any()) { var ghostedCard = _ghostedCards.First(); _ghostedCards.Remove(ghostedCard); player._Game.SendMessage(player, this, "Retrieve", ghostedCard); // Put the Ghost'ed card in the Set Aside pile, so PutCardIntoPlay can find it player.SetAside.Add(ghostedCard); player.Actions++; var previousPlayerMode = player.PutCardIntoPlay(ghostedCard, Resource.FromCard.Replace("{card}", this.ToString())); var logicalCard = ghostedCard.LogicalCard; player.PlayCard(logicalCard, previousPlayerMode); player.Actions++; previousPlayerMode = player.PutCardIntoPlay(ghostedCard, Resource.AgainFromCard.Replace("{card}", this.ToString())); player.PlayCard(logicalCard, previousPlayerMode); ghostedCard.ModifiedBy = this; _ghostedCards.Clear(); } CanCleanUpPlayed.Remove(false); } public override void PerformEndgameCalculations(IPlayer player, PointsCollection collection) { if (collection == null) throw new ArgumentNullException(nameof(collection)); // Add back any Ghost'ed cards that are still on this collection.AddRange(_ghostedCards); _ghostedCards.Clear(); } private void Player_TurnStarted(object sender, TurnStartedEventArgs e) { var key = UniqueId.ToString(); if (!e.Resolvers.ContainsKey(key)) e.Resolvers[key] = new TurnStartedResolver(e.Player, this, Resource.ResolveCard.Replace("{card}", PhysicalCard.ToString()), Player_Action, true); } internal void Player_Action(IPlayer player, ref TurnStartedEventArgs e) { ResolveDuration(e.Player); e.Player.TurnStarted -= Player_TurnStarted; _turnStartedPlayer = null; } } }