using System; using System.Collections.Generic; using System.Linq; using System.Text; using DominionBase.Currencies; using DominionBase.Piles; using DominionBase.Players; namespace DominionBase.Cards.Seaside { public static class TypeClass { public static Type Ambassador = typeof(Ambassador); public static Type Bazaar = typeof(Bazaar); public static Type Caravan = typeof(Caravan); public static Type Cutpurse = typeof(Cutpurse); public static Type Embargo = typeof(Embargo); public static Type Explorer = typeof(Explorer); public static Type FishingVillage = typeof(FishingVillage); public static Type GhostShip = typeof(GhostShip); public static Type Haven = typeof(Haven); public static Type Island = typeof(Island); public static Type Lighthouse = typeof(Lighthouse); public static Type Lookout = typeof(Lookout); public static Type MerchantShip = typeof(MerchantShip); public static Type NativeVillage = typeof(NativeVillage); public static Type Navigator = typeof(Navigator); public static Type Outpost = typeof(Outpost); public static Type PearlDiver = typeof(PearlDiver); public static Type PirateShip = typeof(PirateShip); public static Type Salvager = typeof(Salvager); public static Type SeaHag = typeof(SeaHag); public static Type Smugglers = typeof(Smugglers); public static Type Tactician = typeof(Tactician); public static Type TreasureMap = typeof(TreasureMap); public static Type Treasury = typeof(Treasury); public static Type Warehouse = typeof(Warehouse); public static Type Wharf = typeof(Wharf); public static Type EmbargoToken = typeof(EmbargoToken); public static Type PirateShipToken = typeof(PirateShipToken); public static Type IslandMat = typeof(IslandMat); public static Type NativeVillageMat = typeof(NativeVillageMat); } public class Ambassador : Card { public Ambassador() : base("Ambassador", Category.Action | Category.Attack, Source.Seaside, Location.Kingdom, Group.DeckReduction | Group.PlusCurses | Group.RemoveCurses | Group.Terminal) { this.BaseCost = new Cost(3); this.Text = "Reveal a card from your hand.Return up to 2 copies of it from your hand to the Supply. Then each other player gains a copy of it."; } public override void Play(Player player) { base.Play(player); Choice choiceCard = new Choice("Reveal a card from your hand to return up to 2 to the Supply.", this, player.Hand, player); ChoiceResult resultCard = player.MakeChoice(choiceCard); if (resultCard.Cards.Count > 0) { Card revealedCard = resultCard.Cards[0]; player.AddCardInto(DeckLocation.Revealed, player.RetrieveCardFrom(DeckLocation.Hand, revealedCard)); player.AddCardInto(DeckLocation.Hand, player.RetrieveCardFrom(DeckLocation.Revealed, revealedCard)); Supply supply = player._Game.Table.FindSupplyPileByCard(revealedCard, false); if (supply != null) { List options = new List() { "0", "1" }; if (player.Hand[revealedCard.CardType].Count > 1) options.Add("2"); Choice choice = new Choice("How many would you like to return to the Supply?", this, new CardCollection() { revealedCard }, options, player); ChoiceResult result = player.MakeChoice(choice); int numberToReturn = int.Parse(result.Options[0]); if (numberToReturn > 0) { CardCollection cardsToReturn = player.RetrieveCardsFrom(DeckLocation.Hand, revealedCard.CardType, numberToReturn); player.Lose(cardsToReturn); supply.AddTo(cardsToReturn); } player._Game.SendMessage(player, this, supply, numberToReturn); } IEnumerator enumerator = player._Game.GetPlayersStartingWithEnumerator(player); enumerator.MoveNext(); while (enumerator.MoveNext()) { Player attackee = enumerator.Current; // Skip if the attack is blocked (Moat, Lighthouse, etc.) if (this.IsAttackBlocked[attackee]) continue; if (supply != null && supply.CanGain() && supply.TopCard.Name == revealedCard.Name) attackee.Gain(supply); } } } } public class Bazaar : Card { public Bazaar() : base("Bazaar", Category.Action, Source.Seaside, Location.Kingdom, Group.PlusCard | Group.PlusAction | Group.PlusMultipleActions | Group.PlusCoin) { this.BaseCost = new Cost(5); this.Benefit.Actions = 2; this.Benefit.Cards = 1; this.Benefit.Currency.Coin.Value = 1; } } public class Caravan : Card { private Boolean _CanCleanUp = true; public Caravan() : base("Caravan", Category.Action | Category.Duration, Source.Seaside, Location.Kingdom, Group.PlusCard | Group.PlusAction) { this.BaseCost = new Cost(4); this.Benefit.Actions = 1; this.Benefit.Cards = 1; this.DurationBenefit.Cards = 1; } public override Boolean CanCleanUp { get { return this._CanCleanUp; } } public override void AddedTo(DeckLocation location, Player player) { base.AddedTo(location, player); if (location == DeckLocation.Tableau) this._CanCleanUp = false; else this._CanCleanUp = true; } } public class Cutpurse : Card { public Cutpurse() : base("Cutpurse", Category.Action | Category.Attack, Source.Seaside, Location.Kingdom, Group.PlusCoin | Group.Discard | Group.Terminal) { this.BaseCost = new Cost(4); this.Benefit.Currency.Coin.Value = 2; this.Text = "Each other player discards a Copper card (or reveals a hand with no Copper)."; } public override void Play(Player player) { base.Play(player); IEnumerator enumerator = player._Game.GetPlayersStartingWithEnumerator(player); enumerator.MoveNext(); while (enumerator.MoveNext()) { Player attackee = enumerator.Current; // Skip if the attack is blocked (Moat, Lighthouse, etc.) if (this.IsAttackBlocked[attackee]) continue; if (attackee.Hand.LookThrough(c => c.CardType == Cards.Universal.TypeClass.Copper).Count > 0) { attackee.Discard(DeckLocation.Hand, Cards.Universal.TypeClass.Copper, 1); } else { attackee.ReturnHand(attackee.RevealHand()); } } } } public class Embargo : Card { public Embargo() : base("Embargo", Category.Action, Source.Seaside, Location.Kingdom, Group.Component | Group.PlusCurses | Group.PlusCoin | Group.Gain | Group.Trash | Group.Terminal) { this.BaseCost = new Cost(2); this.Benefit.Currency.Coin.Value = 2; this.Text = "Trash this card. Put an Embargo token on top of a Supply pile.
When a player buys a card, he gains a Curse card per Embargo token on that pile."; } public override void Play(Player player) { base.Play(player); if (player.Tableau.Contains(this)) { player.RetrieveCardFrom(DeckLocation.Tableau, this); player.Trash(this); } Choice choice = new Choice("Choose a supply pile to put an Embargo token on", this, player._Game.Table.Supplies, player, false); ChoiceResult result = player.MakeChoice(choice); if (result.Supply != null) { player._Game.SendMessage(player, this, result.Supply); result.Supply.AddToken(new EmbargoToken(player._Game, result.Supply)); } } } public class EmbargoToken : Token { private Dictionary _CardBoughtHandlers = new Dictionary(); private Supply _SupplyPile = null; public EmbargoToken(Game game, Supply supply) : base("", "Embargo token") { _SupplyPile = supply; IEnumerator enumPlayers = game.GetPlayersStartingWithActiveEnumerator(); while (enumPlayers.MoveNext()) { _CardBoughtHandlers[enumPlayers.Current] = new Player.CardBoughtEventHandler(player_CardBought); enumPlayers.Current.CardBought += _CardBoughtHandlers[enumPlayers.Current]; } } internal override void TearDown() { base.TearDown(); _SupplyPile = null; foreach (Player playerLoop in _CardBoughtHandlers.Keys) playerLoop.CardBought -= _CardBoughtHandlers[playerLoop]; _CardBoughtHandlers.Clear(); } void player_CardBought(object sender, Players.CardBuyEventArgs e) { // This is not the card you are looking for if (e.Card.CardType != _SupplyPile.CardType) return; if (e.Actions.ContainsKey(TypeClass.EmbargoToken) || e.HandledBy.Contains(this) || !e.Game.Table.Curse.CanGain()) return; Player player = sender as Player; e.Actions[TypeClass.EmbargoToken] = new Players.CardBuyAction(player, e.Card, "gain a Curse", player_BuyCursePile, true); } internal void player_BuyCursePile(Player player, ref Players.CardBuyEventArgs e) { player.Gain(e.Game.Table.Curse); e.HandledBy.Add(this); } public override string Title { get { return "A player that buys a card off this supply pile will gain 1 Curse card for each of these tokens on it"; } } } public class Explorer : Card { public Explorer() : base("Explorer", Category.Action, Source.Seaside, Location.Kingdom, Group.Gain | Group.Terminal) { this.BaseCost = new Cost(5); this.Text = "You may reveal a Province card from your hand. If you do, gain a Gold card, putting it into your hand. Otherwise, gain a Silver card, putting it into your hand."; } public override void Play(Player player) { base.Play(player); Boolean provinceRevealed = false; if (player.Hand[Cards.Universal.TypeClass.Province].Count > 0) { Choice choice = Choice.CreateYesNoChoice("You may reveal a Province card to gain a Gold in your hand. Otherwise, gain a Silver in your hand. Do you want to reveal?", this, player); ChoiceResult result = player.MakeChoice(choice); if (result.Options.Contains("Yes")) { CardCollection singleProvince = player.RetrieveCardsFrom(DeckLocation.Hand, Cards.Universal.TypeClass.Province, 1); player.AddCardInto(DeckLocation.Revealed, singleProvince[0]); provinceRevealed = true; player.Gain(player._Game.Table.Gold, DeckLocation.Hand, DeckPosition.Bottom); player.AddCardsToHand(DeckLocation.Revealed); } } if (!provinceRevealed) player.Gain(player._Game.Table.Silver, DeckLocation.Hand, DeckPosition.Bottom); } } public class FishingVillage : Card { private Boolean _CanCleanUp = true; public FishingVillage() : base("Fishing Village", Category.Action | Category.Duration, Source.Seaside, Location.Kingdom, Group.PlusAction | Group.PlusMultipleActions | Group.PlusCoin) { this.BaseCost = new Cost(3); this.Benefit.Actions = 2; this.Benefit.Currency.Coin.Value = 1; this.DurationBenefit.Actions = 1; this.DurationBenefit.Currency.Coin.Value = 1; } public override Boolean CanCleanUp { get { return this._CanCleanUp; } } public override void AddedTo(DeckLocation location, Player player) { base.AddedTo(location, player); if (location == DeckLocation.Tableau) this._CanCleanUp = false; else this._CanCleanUp = true; } } public class GhostShip : Card { public GhostShip() : base("Ghost Ship", Category.Action | Category.Attack, Source.Seaside, Location.Kingdom, Group.PlusCard | Group.Terminal) { this.BaseCost = new Cost(5); this.Benefit.Cards = 2; this.Text = "Each other player with 4 or more cards in hand puts cards from his hand on top of his deck until he has 3 cards in his hand."; } public override void Play(Player player) { base.Play(player); IEnumerator enumerator = player._Game.GetPlayersStartingWithEnumerator(player); enumerator.MoveNext(); while (enumerator.MoveNext()) { Player attackee = enumerator.Current; // Skip if the attack is blocked (Moat, Lighthouse, etc.) if (this.IsAttackBlocked[attackee]) continue; Choice choice = new Choice("Choose cards to put on top of your deck, until you have 3 cards in hand.", this, attackee.Hand, player, true, attackee.Hand.Count - 3, attackee.Hand.Count - 3); ChoiceResult result = attackee.MakeChoice(choice); attackee.RetrieveCardsFrom(DeckLocation.Hand, result.Cards); attackee.AddCardsToDeck(result.Cards, DeckPosition.Top); } } } public class Haven : Card { private CardCollection _HavenedCards = new CardCollection(); private Boolean _CanCleanUp = true; public Haven() : base("Haven", Category.Action | Category.Duration, Source.Seaside, Location.Kingdom, Group.PlusCard | Group.PlusAction) { this.BaseCost = new Cost(2); this.Benefit.Actions = 1; this.Benefit.Cards = 1; this.Text = "Set aside a card from your hand face down. At the start of your next turn, put it into your hand."; } internal override void TearDown() { base.TearDown(); _HavenedCards.Clear(); } public override bool IsStackable { get { return _HavenedCards.Count == 0; } } public override CardCollection CardStack() { CardCollection cc = new CardCollection(); _HavenedCards.ForEach(c => cc.Add(new Cards.Universal.Dummy())); cc.Add(this); return cc; } public override Boolean CanCleanUp { get { return this._CanCleanUp; } } public override void AddedTo(DeckLocation location, Player player) { base.AddedTo(location, player); if (location == DeckLocation.Tableau) this._CanCleanUp = false; else this._CanCleanUp = true; } public override void Play(Player player) { base.Play(player); Choice choice = new Choice("Which card would you like to set aside?", this, player.Hand, player); ChoiceResult result = player.MakeChoice(choice); if (result.Cards.Count > 0) { _HavenedCards.Add(player.RetrieveCardFrom(DeckLocation.Hand, result.Cards[0])); player._Game.SendMessage(player, this, result.Cards[0]); } } public override void PlayDuration(Player player) { base.PlayDuration(player); if (_HavenedCards.Count > 0) { player.AddCardsToHand(_HavenedCards); _HavenedCards.Clear(); } } internal override void End(Player player, Deck deck) { // Add back any Haven'ed cards that are still on this deck.AddRange(player, _HavenedCards); } } public class Island : Card { public Island() : base("Island", Category.Action | Category.Victory, Source.Seaside, Location.Kingdom, Group.Component | Group.DeckReduction | Group.Terminal) { this.BaseCost = new Cost(4); this.VictoryPoints = 2; this.Text = "Set aside this and another card from your hand. Return them to your deck at the end of the game."; } internal override void ReceivedBy(Player player) { base.ReceivedBy(player); if (!player.PlayerMats.ContainsKey(TypeClass.IslandMat)) player.PlayerMats[TypeClass.IslandMat] = new IslandMat(); } public override void Play(Player player) { base.Play(player); if (player.Tableau.Contains(this)) player.AddCardInto(TypeClass.IslandMat, player.RetrieveCardFrom(DeckLocation.Tableau, this)); Choice choice = new Choice("Which card would you like to put on your island?", this, player.Hand, player); ChoiceResult result = player.MakeChoice(choice); if (result.Cards.Count > 0) { player.AddCardInto(TypeClass.IslandMat, player.RetrieveCardFrom(DeckLocation.Hand, result.Cards[0])); } } } public class IslandMat : CardMat { public IslandMat() : base(Visibility.All, VisibilityTo.All, new DominionBase.Cards.Sorting.ByTypeName(DominionBase.Cards.Sorting.SortDirection.Descending), true) { } } public class Lighthouse : Card { private Player.AttackedEventHandler _AttackHandler = null; private Boolean _CanCleanUp = true; public Lighthouse() : base("Lighthouse", Category.Action | Category.Duration, Source.Seaside, Location.Kingdom, Group.Defense | Group.PlusAction | Group.PlusCoin) { this.BaseCost = new Cost(2); this.Benefit.Actions = 1; this.Benefit.Currency.Coin.Value = 1; this.DurationBenefit.Currency.Coin.Value = 1; this.Text = "
While this is in play, when another player plays an Attack card, it does not affect you."; } public override Boolean CanCleanUp { get { return this._CanCleanUp; } } public override void AddedTo(DeckLocation location, Player player) { base.AddedTo(location, player); if (location == DeckLocation.Tableau || location == DeckLocation.PreviousTableau) { _AttackHandler = new Player.AttackedEventHandler(player_Attacked_InTableau); player.Attacked += _AttackHandler; } if (location == DeckLocation.Tableau) this._CanCleanUp = false; else this._CanCleanUp = true; } private void player_Attacked_InTableau(object sender, AttackedEventArgs e) { // Already been cancelled -- don't need to process this one if (e.Cancelled) return; Player player = sender as Player; // Lighthouse only protects against other attackers if (player == e.Attacker) return; // Passively cancels any attack e.Cancelled = true; player._Game.SendMessage(player, this); } public override void RemovedFrom(DeckLocation location, Player player) { base.RemovedFrom(location, player); if (_AttackHandler != null) player.Attacked -= _AttackHandler; _AttackHandler = null; } } public class Lookout : Card { public Lookout() : base("Lookout", Category.Action, Source.Seaside, Location.Kingdom, Group.DeckReduction | Group.PlusAction | Group.Trash | Group.RemoveCurses | Group.Discard) { this.BaseCost = new Cost(3); this.Benefit.Actions = 1; this.Text = "Look at the top 3 cards of your deck. Trash one of them. Discard one of them. Put the other one on top of your deck."; } public override void Play(Player player) { base.Play(player); CardCollection newCards = player.Draw(3, DeckLocation.Private); Choice trashChoice = new Choice("Choose a card to trash", this, newCards, player); ChoiceResult trashResult = player.MakeChoice(trashChoice); if (trashResult.Cards.Count > 0) { newCards.Remove(trashResult.Cards[0]); player.Trash(player.RetrieveCardFrom(DeckLocation.Private, trashResult.Cards[0])); } Choice discardChoice = new Choice("Choose a card to discard", this, newCards, player); ChoiceResult discardResult = player.MakeChoice(discardChoice); if (discardResult.Cards.Count > 0) { newCards.Remove(discardResult.Cards[0]); player.Discard(DeckLocation.Private, discardResult.Cards[0]); } player.AddCardsToDeck(player.RetrieveCardsFrom(DeckLocation.Private), DeckPosition.Top); } } public class MerchantShip : Card { private Boolean _CanCleanUp = true; public MerchantShip() : base("Merchant Ship", Category.Action | Category.Duration, Source.Seaside, Location.Kingdom, Group.PlusCoin | Group.Terminal) { this.BaseCost = new Cost(5); this.Benefit.Currency.Coin.Value = 2; this.DurationBenefit.Currency.Coin.Value = 2; } public override Boolean CanCleanUp { get { return this._CanCleanUp; } } public override void AddedTo(DeckLocation location, Player player) { base.AddedTo(location, player); if (location == DeckLocation.Tableau) this._CanCleanUp = false; else this._CanCleanUp = true; } } public class NativeVillage : Card { public NativeVillage() : base("Native Village", Category.Action, Source.Seaside, Location.Kingdom, Group.Component | Group.PlusCard | Group.PlusAction | Group.PlusMultipleActions) { this.BaseCost = new Cost(2); this.Benefit.Actions = 2; this.Text = "Choose one: Set aside the top card of your deck face down on your Native Village mat; or put all the cards from your mat into your hand.You may look at the cards on your mat at any time; return them to your deck at the end of the game."; } internal override void ReceivedBy(Player player) { base.ReceivedBy(player); if (!player.PlayerMats.ContainsKey(TypeClass.NativeVillageMat)) player.PlayerMats[TypeClass.NativeVillageMat] = new NativeVillageMat(); } public override void Play(Player player) { base.Play(player); Choice choice = new Choice("Choose one:", this, new CardCollection() { this }, new List() { "Set aside the top card of your deck face down on your Native Village mat", "Put all the cards from your mat into your hand" }, player); ChoiceResult result = player.MakeChoice(choice); if (result.Options.Contains("Set aside the top card of your deck face down on your Native Village mat")) { if (player.CanDraw) player.Draw(TypeClass.NativeVillageMat); } else { player.AddCardsToHand(player.RetrieveCardsFrom(TypeClass.NativeVillageMat)); } } } public class NativeVillageMat : CardMat { public NativeVillageMat() : base(Visibility.All, VisibilityTo.Owner, new DominionBase.Cards.Sorting.ByTypeName(DominionBase.Cards.Sorting.SortDirection.Descending), false) { this.IsObtainable = false; } } public class Navigator : Card { public Navigator() : base("Navigator", Category.Action, Source.Seaside, Location.Kingdom, Group.CardOrdering | Group.PlusCoin | Group.Discard | Group.Terminal) { this.BaseCost = new Cost(4); this.Benefit.Currency.Coin.Value = 2; this.Text = "Look at the top 5 cards of your deck. Either discard all of them, or put them back on top of your deck in any order."; } public override void Play(Player player) { base.Play(player); player.Draw(5, DeckLocation.Private); Choice keepDiscard = new Choice(String.Format("You drew: {1}{0}Do you want to discard them all or put them back on your deck?", System.Environment.NewLine, player.Private), this, new CardCollection(player.Private), new List() { "Discard them all", "Put them back" }, player); ChoiceResult keepDiscardResult = player.MakeChoice(keepDiscard); if (keepDiscardResult.Options[0] == "Discard them all") { player.Discard(DeckLocation.Private, player.Private); } else { Choice replaceChoice = new Choice("Choose order of cards to put back on your deck", this, player.Private, player, true, player.Private.Count, player.Private.Count); ChoiceResult replaceResult = player.MakeChoice(replaceChoice); player.AddCardsToDeck(player.RetrieveCardsFrom(DeckLocation.Private, replaceResult.Cards), DeckPosition.Top); } } } public class Outpost : Card { private Player.CleaningUpEventHandler _CleaningUpEventHandler = null; private Boolean _CanCleanUp = true; public Outpost() : base("Outpost", Category.Action | Category.Duration, Source.Seaside, Location.Kingdom, Group.Basic | Group.Terminal) { this.BaseCost = new Cost(5); this.Text = "You only draw 3 cards (instead of 5) in this turn's Clean-up phase.Take an extra turn after this one.This can't cause you to take more than two consecutive turns."; } public override Boolean CanCleanUp { get { return this._CanCleanUp; } } public override void AddedTo(DeckLocation location, Player player) { base.AddedTo(location, player); if (location == DeckLocation.Tableau) this._CanCleanUp = false; else this._CanCleanUp = true; } public override void Play(Player player) { base.Play(player); if (_CleaningUpEventHandler == null) { _CleaningUpEventHandler = new Player.CleaningUpEventHandler(player_CleaningUp); player.CleaningUp += _CleaningUpEventHandler; } } void player_CleaningUp(object sender, CleaningUpEventArgs e) { e.DrawSize = 3; if (e.CurrentPlayer._Game.TurnsTaken.Count > 1 && e.CurrentPlayer._Game.TurnsTaken[e.CurrentPlayer._Game.TurnsTaken.Count - 2].Player != e.CurrentPlayer) { e.NextPlayer = e.CurrentPlayer; e.NextGrantedBy = this; } } public override void RemovedFrom(DeckLocation location, Player player) { base.RemovedFrom(location, player); if (_CleaningUpEventHandler != null) player.CleaningUp -= _CleaningUpEventHandler; _CleaningUpEventHandler = null; } } public class PearlDiver : Card { public PearlDiver() : base("Pearl Diver", Category.Action, Source.Seaside, Location.Kingdom, Group.CardOrdering | Group.PlusCard | Group.PlusAction) { this.BaseCost = new Cost(2); this.Benefit.Cards = 1; this.Benefit.Actions = 1; this.Text = "Look at the bottom card of your deck. You may put it on top."; } public override void Play(Player player) { base.Play(player); if (player.CanDraw) { Card card = player.DrawFrom(DeckPosition.Bottom, 1, DeckLocation.Private)[0]; Choice choice = Choice.CreateYesNoChoice(String.Format("Do you want to put {0} on top of your deck?", card.Name), this, card, player, null); ChoiceResult result = player.MakeChoice(choice); card = player.RetrieveCardFrom(DeckLocation.Private, card); if (result.Options[0] == "Yes") player.AddCardToDeck(card, DeckPosition.Top); else if (result.Options[0] == "No") player.AddCardToDeck(card, DeckPosition.Bottom); } } } public class PirateShip : Card { public PirateShip() : base("Pirate Ship", Category.Action | Category.Attack, Source.Seaside, Location.Kingdom, Group.Component | Group.PlusCoin | Group.Trash | Group.Discard | Group.Terminal) { this.BaseCost = new Cost(4); this.Text = "Choose one: Each other player reveals the top 2 cards of his deck, trashes a revealed Treasure card that you choose, discards the rest, and if anyone trashed a Treasure you take a Coin token; or, +1 per Coin token you've taken with Pirate Ships this game."; } internal override void ReceivedBy(Player player) { base.ReceivedBy(player); if (!player.TokenPiles.ContainsKey(TypeClass.PirateShipToken)) player.TokenPiles[TypeClass.PirateShipToken] = new TokenCollection(); } public override void Play(Player player) { base.Play(player); Choice choice = new Choice("Choose 1:", this, new CardCollection() { this }, new List() { "Perform attack", String.Format("+{0} (from Pirate Ship tokens)", player.TokenPiles[TypeClass.PirateShipToken].Count) }, player); ChoiceResult result = player.MakeChoice(choice); if (result.Options.Contains("Perform attack")) { // Perform attack on every player (including you) IEnumerator enumerator = player._Game.GetPlayersStartingWithEnumerator(player); enumerator.MoveNext(); Boolean anyTrashed = false; while (enumerator.MoveNext()) { Player attackee = enumerator.Current; if (this.IsAttackBlocked[attackee]) continue; attackee.Draw(2, DeckLocation.Revealed); CardCollection treasures = attackee.Revealed[Category.Treasure]; Choice choiceTrash = new Choice(String.Format("Choose a Treasure card of {0} to trash", attackee), this, treasures, attackee); ChoiceResult resultTrash = player.MakeChoice(choiceTrash); if (resultTrash.Cards.Count > 0) { attackee.Trash(attackee.RetrieveCardFrom(DeckLocation.Revealed, resultTrash.Cards[0])); anyTrashed = true; } attackee.DiscardRevealed(); } if (anyTrashed) player.AddToken(new PirateShipToken()); } else { CardBenefit benefit = new CardBenefit(); benefit.Currency += new Coin(player.TokenPiles[TypeClass.PirateShipToken].Count); player.ReceiveBenefit(this, benefit); } } } public class PirateShipToken : Token { public PirateShipToken() : base("P", "Pirate Ship coin") { } public override string Title { get { return "Worth 1 for each token when the 2nd option is chosen for the Pirate Ship"; } } } public class Salvager : Card { public Salvager() : base("Salvager", Category.Action, Source.Seaside, Location.Kingdom, Group.DeckReduction | Group.PlusCoin | Group.PlusBuy | Group.Trash | Group.RemoveCurses | Group.Terminal) { this.BaseCost = new Cost(4); this.Benefit.Buys = 1; this.Text = "Trash a card from your hand.+ equal to its cost."; } public override void Play(Player player) { base.Play(player); Choice choice = new Choice("Choose a card to trash", this, player.Hand, player); ChoiceResult result = player.MakeChoice(choice); if (result.Cards.Count > 0) { Cost trashedCardCost = player._Game.Cost(result.Cards[0]); player.Trash(player.RetrieveCardFrom(DeckLocation.Hand, result.Cards[0])); CardBenefit benefit = new CardBenefit(); benefit.Currency += trashedCardCost.Coin; player.ReceiveBenefit(this, benefit); } } } public class SeaHag : Card { public SeaHag() : base("Sea Hag", Category.Action | Category.Attack, Source.Seaside, Location.Kingdom, Group.PlusCurses | Group.Discard | Group.Terminal) { this.BaseCost = new Cost(4); this.Text = "Each other player discards the top card of his deck, then gains a Curse card, putting it on top of his deck."; } public override void Play(Player player) { base.Play(player); IEnumerator enumerator = player._Game.GetPlayersStartingWithEnumerator(player); enumerator.MoveNext(); while (enumerator.MoveNext()) { Player attackee = enumerator.Current; // Skip if the attack is blocked (Moat, Lighthouse, etc.) if (this.IsAttackBlocked[attackee]) continue; if (attackee.CanDraw) { attackee.Draw(DeckLocation.Revealed); attackee.DiscardRevealed(); } attackee.Gain(player._Game.Table.Curse, DeckLocation.Deck, DeckPosition.Top); } } } public class Smugglers : Card { public Smugglers() : base("Smugglers", Category.Action, Source.Seaside, Location.Kingdom, Group.Gain | Group.Terminal) { this.BaseCost = new Cost(3); this.Text = "Gain a copy of a card costing up to 6 that the player to your right gained on his last turn."; } public override void Play(Player player) { base.Play(player); // Get the player to my right Player playerToRight = player._Game.GetPlayerFromIndex(player, -1); Turn mostRecentTurn = player._Game.TurnsTaken.Last(turn => turn.Player == playerToRight); Cost cost6 = new Cards.Cost(6); IEnumerable cardsAvailableToGain = mostRecentTurn.CardsGained.Where(card => player._Game.Cost(card) <= cost6); SupplyCollection scAvailable = player._Game.Table.Supplies.FindAll(supply => cardsAvailableToGain.FirstOrDefault(card => card.CardType == supply.SupplyCardType) != null); Choice choice = new Choice("Choose a card to gain", this, scAvailable, player, false); ChoiceResult result = player.MakeChoice(choice); if (result.Supply != null) player.Gain(result.Supply); } } public class Tactician : Card { private Boolean _CanCleanUp = true; public Tactician() : base("Tactician", Category.Action | Category.Duration, Source.Seaside, Location.Kingdom, Group.PlusCard | Group.PlusAction | Group.PlusBuy) { this.BaseCost = new Cost(5); this.Text = "Discard your hand.If you discarded any cards this way, then at the start of your next turn, +5Cards, +1Buy, and +1Action."; } public override Boolean CanCleanUp { get { return this._CanCleanUp; } } public override void AddedTo(DeckLocation location, Player player) { base.AddedTo(location, player); this._CanCleanUp = true; } public override void Play(Player player) { base.Play(player); if (player.Hand.Count > 0) _CanCleanUp = false; player.Discard(DeckLocation.Hand); } protected override void GainDurationBenefits(Player player) { player.ReceiveBenefit(this, new CardBenefit() { Cards = 5, Actions = 1, Buys = 1 }); } } public class TreasureMap : Card { public TreasureMap() : base("Treasure Map", Category.Action, Source.Seaside, Location.Kingdom, Group.Gain | Group.Trash | Group.Terminal) { this.BaseCost = new Cost(4); this.Text = "Trash this and another copy of Treasure Map from your hand.If you do trash two Treasure Maps, gain 4 Gold cards, putting them on top of your deck."; } public override void Play(Player player) { base.Play(player); int trashed = 0; if (player.Tableau.Contains(this)) { player.RetrieveCardFrom(DeckLocation.Tableau, this); player.Trash(this); trashed++; } CardCollection anotherTreasure = player.RetrieveCardsFrom(DeckLocation.Hand, Cards.Seaside.TypeClass.TreasureMap, 1); if (anotherTreasure.Count == 1) { player.Trash(anotherTreasure); trashed++; if (trashed == 2) { for (int i = 0; i < 4; i++) player.Gain(player._Game.Table.Gold, DeckLocation.Deck, DeckPosition.Top); } } } } public class Treasury : Card { private Player.CardsDiscardingEventHandler _CardsDiscardingEventHandler = null; public Treasury() : base("Treasury", Category.Action, Source.Seaside, Location.Kingdom, Group.CardOrdering | Group.PlusCard | Group.PlusAction | Group.PlusCoin) { this.BaseCost = new Cost(5); this.Benefit.Cards = 1; this.Benefit.Actions = 1; this.Benefit.Currency.Coin.Value = 1; this.Text = "
When you discard this from play, if you didn't buy a Victory card this turn, you may put it on top of your deck."; this.OwnerChanged += new OwnerChangedEventHandler(Treasury_OwnerChanged); } internal override void TearDown() { base.TearDown(); this.OwnerChanged -= new OwnerChangedEventHandler(Treasury_OwnerChanged); } void Treasury_OwnerChanged(object sender, OwnerChangedEventArgs e) { if (_CardsDiscardingEventHandler != null && e.OldOwner != null) { e.OldOwner.CardsDiscarding -= _CardsDiscardingEventHandler; _CardsDiscardingEventHandler = null; } if (e.NewOwner != null) { _CardsDiscardingEventHandler = new Player.CardsDiscardingEventHandler(player_CardsDiscarding); e.NewOwner.CardsDiscarding += _CardsDiscardingEventHandler; } } void player_CardsDiscarding(object sender, CardsDiscardEventArgs e) { if (!e.Cards.Contains(this) || e.Actions.ContainsKey(TypeClass.Treasury) || e.HandledBy.Contains(this) || (e.FromLocation != DeckLocation.Tableau && e.FromLocation != DeckLocation.PreviousTableau)) return; // Only allow this if no Victory cards were bought this turn if (!((sender as Player).CurrentTurn.CardsBought.Any(c => (c.Category & Cards.Category.Victory) == Cards.Category.Victory))) e.Actions[TypeClass.Treasury] = new CardsDiscardAction(sender as Player, this, String.Format("Put {0} on your deck", this), player_Action, false); } internal void player_Action(Player player, ref CardsDiscardEventArgs e) { e.Cards.Remove(this); if (player.Tableau.Contains(this)) player.RetrieveCardFrom(DeckLocation.Tableau, this); else player.RetrieveCardFrom(DeckLocation.PreviousTableau, this); player.AddCardToDeck(this, DeckPosition.Top); e.HandledBy.Add(this); } } public class Warehouse : Card { public Warehouse() : base("Warehouse", Category.Action, Source.Seaside, Location.Kingdom, Group.PlusCard | Group.PlusAction | Group.Discard) { this.BaseCost = new Cost(3); this.Benefit.Cards = 3; this.Benefit.Actions = 1; this.Text = "Discard 3 cards."; } public override void Play(Player player) { base.Play(player); Choice choice = new Choice("Discard 3 cards.", this, player.Hand, player, false, 3, 3); ChoiceResult result = player.MakeChoice(choice); player.Discard(DeckLocation.Hand, result.Cards); } } public class Wharf : Card { private Boolean _CanCleanUp = true; public Wharf() : base("Wharf", Category.Action | Category.Duration, Source.Seaside, Location.Kingdom, Group.PlusCard | Group.PlusBuy | Group.Terminal) { this.BaseCost = new Cost(5); this.Benefit.Cards = 2; this.Benefit.Buys = 1; this.DurationBenefit.Cards = 2; this.DurationBenefit.Buys = 1; } public override Boolean CanCleanUp { get { return this._CanCleanUp; } } public override void AddedTo(DeckLocation location, Player player) { base.AddedTo(location, player); if (location == DeckLocation.Tableau) this._CanCleanUp = false; else this._CanCleanUp = true; } } }