using DominionBase.Enums; using DominionBase.Players; using DominionBase.Properties; using System.Diagnostics.Contracts; using System.Linq; namespace DominionBase.Cards.Menagerie { public class Gatekeeper : Card { private int _playCount; public Gatekeeper() : base(Categories.Action | Categories.Attack | Categories.Duration, Source.Menagerie, Location.Kingdom, Traits.AffectOthers | Traits.Exiler | Traits.PlusCoin | Traits.ReactToGain | Traits.Terminal) { BaseCost = new Cost(5); DurationBenefit.Currency.Coin.Value = 3; } public override void TearDown(IGame game) { Contract.Requires(game != null, "game cannot be null"); base.TearDown(game); foreach (var player in game.Players) { player.CardGained -= Player_CardGained; player.TurnEnded -= Player_TurnEnded; player.TurnStarted -= Player_TurnStarted; } } public override void FollowInstructions(IPlayer player) { Contract.Requires(player != null, "player cannot be null"); base.FollowInstructions(player); var enumerator = player._Game.GetPlayersStartingWithEnumerator(player); enumerator.MoveNext(); while (enumerator.MoveNext()) { var attackee = enumerator.Current; // Skip if the attack is blocked (Moat, Lighthouse, etc.) attackee.CardGained -= Player_CardGained; if (!IsAttackBlocked[attackee]) attackee.CardGained += Player_CardGained; } CanCleanUpPlayed.Add(false); _playCount++; player.TurnEnded += Player_TurnEnded; } private void Player_TurnEnded(object sender, TurnEndedEventArgs e) { e.Player.TurnEnded -= Player_TurnEnded; e.Player.TurnStarted += Player_TurnStarted; } private void Player_CardGained(object sender, CardGainEventArgs e) { var key = Type.ToString(); var playerAttacked = sender as IPlayer; if (e.Resolvers.ContainsKey(key) || e.HandledBy.Count(o => o == this) >= _playCount || e.IsLostTrackOf || !e.Card.Type.IsSubclassOf(typeof(Card))) return; // If the card isn't an Action or Treasure card, skip resolving the Attack if (!e.Card.Category.HasFlag(Categories.Action) && !e.Card.Category.HasFlag(Categories.Treasure)) return; // If the player has a copy of it in Exile, skip resolving the Attack if (playerAttacked.PlayerMats.ContainsKey(TypeClass.Exile) && playerAttacked.PlayerMats[TypeClass.Exile].Any(c => c.Name == e.Card.Name)) return; e.Resolvers[key] = new CardGainResolver(playerAttacked, e.Card, "ExileCard", Resource.ExileCard.Replace("{card}", e.Card.ToString()), Player_GainCard, true); } internal void Player_GainCard(IPlayer playerAttacked, ref CardGainEventArgs e) { e.Cancelled = true; var card = playerAttacked.RetrieveCardFrom(e.Location, e.Card); if (card != null) { playerAttacked.AddCardInto(TypeClass.Exile, card); playerAttacked._Game.SendMessage(playerAttacked, this, "Exile", card); } e.IsLostTrackOf = true; e.HandledBy.Add(this); } private void Player_TurnStarted(object sender, TurnStartedEventArgs e) { var key = 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); CanCleanUpPlayed.Remove(false); foreach (var attackee in player._Game.Players) { for (var p = 0; p < _playCount; p++) attackee.CardGained -= Player_CardGained; } _playCount = 0; e.Player.TurnStarted -= Player_TurnStarted; } public override void RemovedFrom(DeckLocation location, IPlayer player) { Contract.Requires(player != null, "player cannot be null"); base.RemovedFrom(location, player); foreach (var attackee in player._Game.Players) { for (var p = 0; p < _playCount; p++) attackee.CardGained -= Player_CardGained; } _playCount = 0; player.TurnStarted -= Player_TurnStarted; } } }