using DominionBase.Currencies;
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.Intrigue
{
public static class TypeClass
{
public static readonly Type Baron = typeof(Baron);
public static readonly Type Bridge = typeof(Bridge);
public static readonly Type Conspirator = typeof(Conspirator);
public static readonly Type Coppersmith = typeof(Coppersmith);
public static readonly Type Courtyard = typeof(Courtyard);
public static readonly Type Duke = typeof(Duke);
public static readonly Type GreatHall = typeof(GreatHall);
public static readonly Type Harem = typeof(Harem);
public static readonly Type Ironworks = typeof(Ironworks);
public static readonly Type Masquerade = typeof(Masquerade);
public static readonly Type MiningVillage = typeof(MiningVillage);
public static readonly Type Minion = typeof(Minion);
public static readonly Type Nobles = typeof(Nobles);
public static readonly Type Pawn = typeof(Pawn);
public static readonly Type Saboteur = typeof(Saboteur);
public static readonly Type Scout = typeof(Scout);
public static readonly Type SecretChamber = typeof(SecretChamber);
public static readonly Type ShantyTown = typeof(ShantyTown);
public static readonly Type Steward = typeof(Steward);
public static readonly Type Swindler = typeof(Swindler);
public static readonly Type Torturer = typeof(Torturer);
public static readonly Type TradingPost = typeof(TradingPost);
public static readonly Type Tribute = typeof(Tribute);
public static readonly Type Upgrade = typeof(Upgrade);
public static readonly Type WishingWell = typeof(WishingWell);
}
public class Baron : Card
{
public Baron() : this(Edition.First) { }
public Baron(Edition edition)
: base(Categories.Action, Source.Intrigue, Location.Kingdom, Traits.PlusCoin | Traits.PlusBuy | Traits.Gainer | Traits.Discard | Traits.Terminal | Traits.ConditionalBenefit, edition: edition)
{
BaseCost = new Cost(4);
Benefit.Buys = 1;
}
public override void FollowInstructions(IPlayer player)
{
Contract.Requires(player != null, "player cannot be null");
base.FollowInstructions(player);
if (player.Hand[Universal.TypeClass.Estate].Any())
{
var choice = Choice.CreateYesNoChoice("You may discard an Estate card for +4. Do you want to discard?", this, player);
var result = player.MakeChoice(choice);
if (result.Options.Contains(Resource.Yes))
{
player.Discard(DeckLocation.Hand, Universal.TypeClass.Estate, 1);
var benefit = new CardBenefit();
benefit.Currency.Coin += 4;
player.ReceiveBenefit(this, benefit);
return;
}
}
player.Gain(player._Game.Table.Estate, this);
}
}
public class Bridge : Card
{
private IPlayer _turnEndedPlayer;
private TurnEndedEventHandler _turnEndedEventHandler;
private readonly List _costComputeEventHandlers = new List();
public Bridge() : this(Edition.First) { }
public Bridge(Edition edition)
: base(Categories.Action, Source.Intrigue, Location.Kingdom, Traits.PlusCoin | Traits.PlusBuy | Traits.ModifyCost | Traits.Terminal, edition: edition)
{
BaseCost = new Cost(4);
Benefit.Currency.Coin.Value = 1;
Benefit.Buys = 1;
}
public override void TearDown(IGame game)
{
base.TearDown(game);
if (_turnEndedEventHandler != null && _turnEndedPlayer != null)
Player_TurnEnded(_turnEndedPlayer, new TurnEndedEventArgs(_turnEndedPlayer));
_turnEndedEventHandler = null;
}
protected override bool AllowUndo => true;
public override void FollowInstructions(IPlayer player)
{
Contract.Requires(player != null, "player cannot be null");
base.FollowInstructions(player);
if (_turnEndedEventHandler == null)
{
_turnEndedPlayer = player;
_turnEndedEventHandler = new TurnEndedEventHandler(Player_TurnEnded);
player.TurnEnded += _turnEndedEventHandler;
}
_costComputeEventHandlers.Add(new CostComputeEventHandler(Player_BridgePlayed));
player._Game.CostCompute += _costComputeEventHandlers[_costComputeEventHandlers.Count - 1];
player._Game.SendMessage(player, this, 1);
}
private void Player_BridgePlayed(object sender, CostComputeEventArgs e)
{
if (e.Card is ICard || e.Card is ISupply)
e.Cost.Coin -= 1;
}
private void Player_TurnEnded(object sender, TurnEndedEventArgs e)
{
var player = sender as IPlayer;
if (_turnEndedEventHandler != null && _turnEndedPlayer != null)
_turnEndedPlayer.TurnEnded -= _turnEndedEventHandler;
_turnEndedPlayer = null;
_turnEndedEventHandler = null;
foreach (var cceh in _costComputeEventHandlers)
player._Game.CostCompute -= cceh;
_costComputeEventHandlers.Clear();
}
}
public class Conspirator : Card
{
public Conspirator() : this(Edition.First) { }
public Conspirator(Edition edition)
: base(Categories.Action, Source.Intrigue, Location.Kingdom, Traits.PlusCard | Traits.PlusAction | Traits.PlusCoin | Traits.ConditionalBenefit, edition: edition)
{
BaseCost = new Cost(4);
Benefit.Currency.Coin.Value = 2;
}
public override void FollowInstructions(IPlayer player)
{
Contract.Requires(player != null, "player cannot be null");
base.FollowInstructions(player);
if (player.ActionsPlayed >= 3)
player.ReceiveBenefit(this, new CardBenefit() { Actions = 1, Cards = 1 });
}
}
public class Coppersmith : Card
{
private IPlayer _turnEndedPlayer;
private TurnEndedEventHandler _turnEndedEventHandler;
private readonly List _cardPlayedEventHandlers = new List();
public Coppersmith()
: base(Categories.Action, Source.Intrigue, Location.Kingdom, Traits.Basic | Traits.Terminal, edition: Edition.First)
{
BaseCost = new Cost(4);
}
protected override bool AllowUndo => true;
public override void TearDown(IGame game)
{
base.TearDown(game);
if (_turnEndedEventHandler != null && _turnEndedPlayer != null)
Player_TurnEnded(_turnEndedPlayer, new TurnEndedEventArgs(_turnEndedPlayer));
_turnEndedEventHandler = null;
}
public override void FollowInstructions(IPlayer player)
{
Contract.Requires(player != null, "player cannot be null");
base.FollowInstructions(player);
if (_turnEndedEventHandler == null)
{
_turnEndedPlayer = player;
_turnEndedEventHandler = new TurnEndedEventHandler(Player_TurnEnded);
player.TurnEnded += _turnEndedEventHandler;
}
_cardPlayedEventHandlers.Add(new CardPlayedEventHandler(ActivePlayer_CardPlayed));
player.CardPlayed += _cardPlayedEventHandlers[_cardPlayedEventHandlers.Count - 1];
}
private void ActivePlayer_CardPlayed(object sender, CardPlayedEventArgs e)
{
// TODO -- this should be converted to use BenefitReceiving event instead of CardPlayed
var benefit = new CardBenefit();
foreach (var card in e.Cards)
{
if (card is Universal.Copper)
benefit.Currency += new Coin(1);
}
e.Player.ReceiveBenefit(this, benefit);
}
private void Player_TurnEnded(object sender, TurnEndedEventArgs e)
{
var player = sender as IPlayer;
if (_turnEndedEventHandler != null && _turnEndedPlayer != null)
_turnEndedPlayer.TurnEnded -= _turnEndedEventHandler;
_turnEndedPlayer = null;
_turnEndedEventHandler = null;
foreach (var cpeh in _cardPlayedEventHandlers)
player.CardPlayed -= cpeh;
_cardPlayedEventHandlers.Clear();
}
}
public class Courtyard : Card
{
public Courtyard() : this(Edition.First) { }
public Courtyard(Edition edition)
: base(Categories.Action, Source.Intrigue, Location.Kingdom, Traits.CardOrdering | Traits.PlusCard | Traits.Terminal | Traits.NetCardDraw, edition: edition)
{
BaseCost = new Cost(2);
Benefit.Cards = 3;
}
public override void FollowInstructions(IPlayer player)
{
Contract.Requires(player != null, "player cannot be null");
base.FollowInstructions(player);
var choice = new Choice("Choose a card to put on top of your deck", this, player.Hand, ChoiceOutcome.Select, player);
var result = player.MakeChoice(choice);
if (result.Cards.Any())
player.AddCardToDeck(player.RetrieveCardFrom(DeckLocation.Hand, result.Cards[0]), DeckPosition.Top);
}
}
public class Duke : Card
{
public Duke()
: base(Categories.Victory, Source.Intrigue, Location.Kingdom, Traits.VariableVPs)
{
BaseCost = new Cost(5);
}
public override int ComputeVictoryPoints(IPlayer player, IEnumerable collection)
{
return base.ComputeVictoryPoints(player, collection) +
collection.Count(c => c is Universal.Duchy);
}
}
public class GreatHall : Card
{
public GreatHall()
: base(Categories.Action | Categories.Victory, Source.Intrigue, Location.Kingdom, Traits.PlusCard | Traits.PlusAction | Traits.Cantrip, edition: Edition.First)
{
BaseCost = new Cost(3);
Benefit.Actions = 1;
Benefit.Cards = 1;
VictoryPoints = 1;
}
}
public class Harem : Card
{
public Harem()
: base(Categories.Treasure | Categories.Victory, Source.Intrigue, Location.Kingdom, Traits.PlusCoin)
{
BaseCost = new Cost(6);
Benefit.Currency.Coin.Value = 2;
VictoryPoints = 2;
}
protected override bool AllowUndo => true;
}
public class Ironworks : Card
{
public Ironworks() : this(Edition.First) { }
public Ironworks(Edition edition)
: base(Categories.Action, Source.Intrigue, Location.Kingdom, Traits.PlusCard | Traits.PlusAction | Traits.PlusCoin | Traits.Gainer | Traits.ConditionalBenefit, edition: edition)
{
BaseCost = new Cost(4);
}
public override void FollowInstructions(IPlayer player)
{
Contract.Requires(player != null, "player cannot be null");
base.FollowInstructions(player);
var gainableSupplies = new SupplyCollection(player._Game.Table.TableEntities.FindAll(supply => supply.CanGain() && supply.CurrentCost <= new Coin(4)));
var choice = new Choice(Resource.GainUpTo4, this, gainableSupplies, ChoiceOutcome.Gain, player, false);
var result = player.MakeChoice(choice);
if (result.Supply != null)
{
var benefit = new CardBenefit();
var cardToGain = result.Supply.TopCard;
if (player.Gain(result.Supply, this))
{
if (cardToGain.Category.HasFlag(Categories.Action))
benefit.Actions = 1;
if (cardToGain.Category.HasFlag(Categories.Treasure))
benefit.Currency += new Coin(1);
if (cardToGain.Category.HasFlag(Categories.Victory))
benefit.Cards = 1;
player.ReceiveBenefit(this, benefit);
}
}
}
}
public class Masquerade : Card
{
public Masquerade()
: base(Categories.Action, Source.Intrigue, Location.Kingdom, Traits.DeckReduction | Traits.PlusCurses | Traits.PlusCard | Traits.Trasher | Traits.RemoveCurses | Traits.AffectOthers | Traits.Terminal | Traits.NetCardDraw | Traits.RemoveFromHand, edition: Edition.First)
{
BaseCost = new Cost(3);
Benefit.Cards = 2;
}
public override void FollowInstructions(IPlayer player)
{
Contract.Requires(player != null, "player cannot be null");
base.FollowInstructions(player);
var toPass = new List(player._Game.Players.Count);
var enumerator = player._Game.GetPlayersStartingWithEnumerator(player);
while (enumerator.MoveNext())
{
var choosingPlayer = enumerator.Current;
var choice = new Choice("Choose a card to pass to the left", this, choosingPlayer.Hand, ChoiceOutcome.Select, player);
var result = choosingPlayer.MakeChoice(choice);
if (result.Cards.Any())
{
var passingCard = choosingPlayer.RetrieveCardFrom(DeckLocation.Hand, result.Cards[0]);
choosingPlayer.Lose(passingCard);
toPass.Add(passingCard);
player._Game.SendMessage(choosingPlayer, player._Game.GetPlayerFromIndex(choosingPlayer, 1), this, result.Cards[0]);
}
else
toPass.Add(null);
}
enumerator = player._Game.GetPlayersStartingWithEnumerator(player);
var index = 0;
while (enumerator.MoveNext())
{
var fromRight = toPass[(index + player._Game.Players.Count - 1) % player._Game.Players.Count];
if (fromRight != null)
enumerator.Current.Receive(player._Game.GetPlayerFromIndex(enumerator.Current, -1), fromRight, DeckLocation.Hand, DeckPosition.Automatic);
index++;
}
var choiceTrash = new Choice(Resource.ChooseToTrashOptional, this, player.Hand, ChoiceOutcome.Trash, player, minimum: 0);
var resultTrash = player.MakeChoice(choiceTrash);
if (resultTrash.Cards.Any())
player.Trash(this, player.RetrieveCardFrom(DeckLocation.Hand, resultTrash.Cards[0]));
}
}
public class MiningVillage : Card
{
public MiningVillage() : this(Edition.First) { }
public MiningVillage(Edition edition)
: base(Categories.Action,
Source.Intrigue,
Location.Kingdom,
Traits.PlusCard | Traits.PlusAction | Traits.PlusMultipleActions | Traits.PlusCoin | Traits.Trasher | Traits.ConditionalBenefit | Traits.Cantrip,
edition: edition)
{
BaseCost = new Cost(4);
Benefit.Cards = 1;
Benefit.Actions = 2;
}
public override void FollowInstructions(IPlayer player)
{
Contract.Requires(player != null, "player cannot be null");
base.FollowInstructions(player);
if (player.InPlay.Contains(PhysicalCard))
{
var choice = Choice.CreateYesNoChoice("Do you want to trash this card for +2?", this, player);
var result = player.MakeChoice(choice);
if (result.Options[0] == Resource.Yes)
{
player.Trash(this, player.RetrieveCardFrom(DeckLocation.InPlay, PhysicalCard));
var benefit = new CardBenefit();
benefit.Currency += new Coin(2);
player.ReceiveBenefit(this, benefit);
}
}
}
}
public class Minion : Card
{
public Minion() : this(Edition.First) { }
public Minion(Edition edition)
: base(Categories.Action | Categories.Attack, Source.Intrigue, Location.Kingdom, Traits.PlusCard | Traits.PlusAction | Traits.PlusCoin | Traits.Discard | Traits.ConditionalBenefit, edition: edition)
{
BaseCost = new Cost(5);
Benefit.Actions = 1;
}
public override void FollowInstructions(IPlayer player)
{
Contract.Requires(player != null, "player cannot be null");
base.FollowInstructions(player);
var choice = new Choice(Resource.ChooseOne, this, this, new List() { "+2", "Discard your hand, +4Cards, and each other player with at least 5 cards in hand discards his hand and draws 4 cards" }, player);
var result = player.MakeChoice(choice);
if (result.Options.Contains("+2"))
{
var benefit = new CardBenefit();
benefit.Currency += new Coin(2);
player.ReceiveBenefit(this, benefit);
}
else
{
player.DiscardHand(true);
player.ReceiveBenefit(this, new CardBenefit() { Cards = 4 });
// Perform attack on each other player
var enumerator = player._Game.GetPlayersStartingWithEnumerator(player);
enumerator.MoveNext();
while (enumerator.MoveNext())
{
var attackee = enumerator.Current;
if (IsAttackBlocked[attackee])
continue;
if (attackee.Hand.Count >= 5)
{
attackee.DiscardHand(true);
attackee.DrawHand(4);
}
}
}
}
}
public class Nobles : Card
{
public Nobles() : this(Edition.First) { }
public Nobles(Edition edition)
: base(Categories.Action | Categories.Victory,
Source.Intrigue,
Location.Kingdom,
Traits.PlusCard | Traits.PlusAction | Traits.PlusMultipleActions | Traits.ConditionalBenefit | Traits.NetCardDraw,
edition: edition)
{
BaseCost = new Cost(6);
VictoryPoints = 2;
}
public override void FollowInstructions(IPlayer player)
{
Contract.Requires(player != null, "player cannot be null");
base.FollowInstructions(player);
var choice = new Choice(Resource.ChooseOne, this, this, new List() { "+3Cards", "+2Actions" }, player);
var result = player.MakeChoice(choice);
var benefit = new CardBenefit();
if (result.Options.Contains("+3Cards"))
benefit.Cards = 3;
if (result.Options.Contains("+2Actions"))
benefit.Actions = 2;
player.ReceiveBenefit(this, benefit);
}
}
public class Pawn : Card
{
public Pawn() : this(Edition.First) { }
public Pawn(Edition edition)
: base(Categories.Action, Source.Intrigue, Location.Kingdom, Traits.PlusCard | Traits.PlusAction | Traits.PlusCoin | Traits.PlusBuy | Traits.ConditionalBenefit, edition: edition)
{
BaseCost = new Cost(2);
}
public override void FollowInstructions(IPlayer player)
{
Contract.Requires(player != null, "player cannot be null");
base.FollowInstructions(player);
var choice = new Choice(Resource.ChooseTwo, this, this, new List() { "+1Card", "+1Action", "+1Buy", "+1" }, player, isOrdered: true, minimum: 2, maximum: 2);
var result = player.MakeChoice(choice);
foreach (var option in result.Options)
{
var benefit = new CardBenefit();
if (option == "+1Card")
benefit.Cards = 1;
if (option == "+1Action")
benefit.Actions = 1;
if (option == "+1Buy")
benefit.Buys = 1;
if (option == "+1")
benefit.Currency += new Coin(1);
player.ReceiveBenefit(this, benefit);
}
}
}
public class Saboteur : Card
{
public Saboteur()
: base(Categories.Action | Categories.Attack, Source.Intrigue, Location.Kingdom, Traits.Trasher | Traits.Discard | Traits.Terminal, edition: Edition.First)
{
BaseCost = new Cost(5);
}
public override void FollowInstructions(IPlayer player)
{
Contract.Requires(player != null, "player cannot be null");
base.FollowInstructions(player);
// Perform attack on every player
var enumerator = player._Game.GetPlayersStartingWithEnumerator(player);
enumerator.MoveNext(); // skip active player
while (enumerator.MoveNext())
{
var attackee = enumerator.Current;
// Skip if the attack is blocked (Moat, Lighthouse, etc.)
if (IsAttackBlocked[attackee])
continue;
attackee.BeginDrawing();
while (attackee.Revealed[card => player._Game.ComputeCost(card).Coin >= 3].Count < 1 && attackee.CanDraw)
attackee.Draw(DeckLocation.Revealed);
attackee.EndDrawing();
var cards = attackee.Revealed[c => player._Game.ComputeCost(c).Coin >= 3];
if (cards.Any())
{
var card = cards[0];
var trashedCardCost = player._Game.ComputeCost(card);
attackee.Trash(this, attackee.RetrieveCardFrom(DeckLocation.Revealed, card));
var gainableSupplies = new SupplyCollection(player._Game.Table.TableEntities.FindAll(supply => supply.CanGain() && supply.CurrentCost <= (trashedCardCost.Coin - 2)));
var choice = new Choice("You may gain a card", this, gainableSupplies, ChoiceOutcome.Gain, player, true);
var result = attackee.MakeChoice(choice);
if (result.Supply != null)
attackee.Gain(result.Supply, this);
}
attackee.DiscardRevealed();
}
}
}
public class Scout : Card
{
public Scout()
: base(Categories.Action, Source.Intrigue, Location.Kingdom, Traits.CardOrdering | Traits.PlusAction, edition: Edition.First)
{
BaseCost = new Cost(4);
Benefit.Actions = 1;
}
public override void FollowInstructions(IPlayer player)
{
Contract.Requires(player != null, "player cannot be null");
base.FollowInstructions(player);
player.Draw(4, DeckLocation.Revealed);
player.AddCardsToHand(player.RetrieveCardsFrom(DeckLocation.Revealed, Categories.Victory));
var replaceChoice = new Choice(Resource.ChooseOrderToTopdeck, this, player.Revealed, ChoiceOutcome.Select, player, isOrdered: true, minimum: player.Revealed.Count, maximum: player.Revealed.Count);
var replaceResult = player.MakeChoice(replaceChoice);
player.RetrieveCardsFrom(DeckLocation.Revealed, replaceResult.Cards);
player.AddCardsToDeck(replaceResult.Cards, DeckPosition.Top);
}
}
public class SecretChamber : Card
{
public SecretChamber()
: base(Categories.Action | Categories.Reaction, Source.Intrigue, Location.Kingdom, Traits.ReactToAttack | Traits.Defense | Traits.PlusCoin | Traits.Discard | Traits.Terminal | Traits.ConditionalBenefit, edition: Edition.First)
{
BaseCost = new Cost(2);
}
public override void FollowInstructions(IPlayer player)
{
Contract.Requires(player != null, "player cannot be null");
base.FollowInstructions(player);
var choice = new Choice("Discard any number of cards. +1 per card discarded.", this, player.Hand, ChoiceOutcome.Discard, player, minimum: 0, maximum: player.Hand.Count);
var result = player.MakeChoice(choice);
player.Discard(DeckLocation.Hand, result.Cards);
var benefit = new CardBenefit();
benefit.Currency += new Coin(result.Cards.Count);
player.ReceiveBenefit(this, benefit);
}
public override void AddedTo(DeckLocation location, IPlayer player)
{
Contract.Requires(player != null, "player cannot be null");
base.AddedTo(location, player);
if (location == DeckLocation.Hand)
{
player.Attacked -= Player_Attacked;
player.Attacked += Player_Attacked;
}
}
internal override void Player_Attacked(object sender, AttackedEventArgs e)
{
var player = sender as IPlayer;
// Secret Chamber only protects against other attackers
if (player == e.Attacker)
return;
// Only allow a single handling by a given card type
if (player.Hand.Contains(PhysicalCard) && !e.HandledBy.Contains(Type) && !e.Revealable.ContainsKey(Type))
e.Revealable[Type] = new AttackReaction(this, Resource.RevealCard.Replace("{card}", PhysicalCard.ToString()), Player_RevealSecretChamber);
}
internal void Player_RevealSecretChamber(IPlayer player, ref AttackedEventArgs e)
{
player.AddCardInto(DeckLocation.Revealed, player.RetrieveCardFrom(DeckLocation.Hand, PhysicalCard));
player.AddCardToHand(player.RetrieveCardFrom(DeckLocation.Revealed, PhysicalCard));
player.ReceiveBenefit(this, new CardBenefit { Cards = 2 });
var replaceChoice = new Choice(Resource.ChooseOrderToTopdeck, this, e.AttackCard, player.Hand, ChoiceOutcome.Select, player, true, 2, 2);
var replaceResult = player.MakeChoice(replaceChoice);
player.RetrieveCardsFrom(DeckLocation.Hand, replaceResult.Cards);
player.AddCardsToDeck(replaceResult.Cards, DeckPosition.Top);
e.HandledBy.Add(Type);
// Attack isn't cancelled... it's just mitigated
}
public override void RemovedFrom(DeckLocation location, IPlayer player)
{
Contract.Requires(player != null, "player cannot be null");
base.RemovedFrom(location, player);
player.Attacked -= Player_Attacked;
}
}
public class ShantyTown : Card
{
public ShantyTown() : this(Edition.First) { }
public ShantyTown(Edition edition)
: base(Categories.Action, Source.Intrigue, Location.Kingdom, Traits.PlusCard | Traits.PlusAction | Traits.PlusMultipleActions | Traits.ConditionalBenefit | Traits.NetCardDraw, edition: edition)
{
BaseCost = new Cost(3);
Benefit.Actions = 2;
}
public override void FollowInstructions(IPlayer player)
{
Contract.Requires(player != null, "player cannot be null");
base.FollowInstructions(player);
player.ReturnHand(player.RevealHand());
if (player.Hand[Categories.Action].Count == 0)
player.ReceiveBenefit(this, new CardBenefit { Cards = 2 });
}
}
public class Steward : Card
{
public Steward() : this(Edition.First) { }
public Steward(Edition edition)
: base(Categories.Action, Source.Intrigue, Location.Kingdom, Traits.DeckReduction | Traits.PlusCard | Traits.PlusCoin | Traits.Trasher | Traits.RemoveCurses | Traits.Terminal | Traits.ConditionalBenefit | Traits.NetCardDraw | Traits.RemoveFromHand, edition: edition)
{
BaseCost = new Cost(3);
}
public override void FollowInstructions(IPlayer player)
{
Contract.Requires(player != null, "player cannot be null");
base.FollowInstructions(player);
var benefit = new CardBenefit();
var choice = new Choice(Resource.ChooseOne, this, this, new List() { "+2Cards", "+2", "Trash 2 cards from your hand" }, player);
var result = player.MakeChoice(choice);
if (result.Options.Contains("+2Cards"))
benefit.Cards = 2;
else if (result.Options.Contains("+2"))
benefit.Currency += new Coin(2);
else
{
var choiceTrash = new Choice(Resource.Trash2, this, player.Hand, ChoiceOutcome.Trash, player, minimum: 2, maximum: 2);
var resultTrash = player.MakeChoice(choiceTrash);
player.Trash(this, player.RetrieveCardsFrom(DeckLocation.Hand, resultTrash.Cards));
}
player.ReceiveBenefit(this, benefit);
}
}
public class Swindler : Card
{
public Swindler() : this(Edition.First) { }
public Swindler(Edition edition)
: base(Categories.Action | Categories.Attack, Source.Intrigue, Location.Kingdom, Traits.PlusCurses | Traits.PlusCoin | Traits.Trasher | Traits.Terminal, edition: edition)
{
BaseCost = new Cost(3);
Benefit.Currency.Coin.Value = 2;
}
public override void FollowInstructions(IPlayer player)
{
Contract.Requires(player != null, "player cannot be null");
base.FollowInstructions(player);
// Perform attack on every player
var enumerator = player._Game.GetPlayersStartingWithEnumerator(player);
enumerator.MoveNext(); // skip active player
while (enumerator.MoveNext())
{
var attackee = enumerator.Current;
// Skip if the attack is blocked (Moat, Lighthouse, etc.)
if (IsAttackBlocked[attackee])
continue;
if (attackee.CanDraw)
{
var card = attackee.Draw(DeckLocation.Revealed);
var trashedCardCost = player._Game.ComputeCost(card);
attackee.Trash(this, attackee.RetrieveCardFrom(DeckLocation.Revealed, card));
var gainableSupplies = new SupplyCollection(player._Game.Table.TableEntities.FindAll(supply => supply.CanGain() && supply.CurrentCost == trashedCardCost));
var choice = new Choice($"Choose a card for {attackee} to gain", this, gainableSupplies, ChoiceOutcome.Gain, attackee, false);
var result = player.MakeChoice(choice);
if (result.Supply != null)
attackee.Gain(result.Supply, this);
}
}
}
}
public class Torturer : Card
{
public Torturer() : this(Edition.First) { }
public Torturer(Edition edition)
: base(Categories.Action | Categories.Attack, Source.Intrigue, Location.Kingdom, Traits.PlusCurses | Traits.PlusCard | Traits.Discard | Traits.Terminal | Traits.NetCardDraw, edition: edition)
{
BaseCost = new Cost(5);
Benefit.Cards = 3;
}
public override void FollowInstructions(IPlayer player)
{
Contract.Requires(player != null, "player cannot be null");
base.FollowInstructions(player);
// Perform attack on every player
var enumerator = player._Game.GetPlayersStartingWithEnumerator(player);
enumerator.MoveNext(); // skip active player
while (enumerator.MoveNext())
{
var attackee = enumerator.Current;
// Skip if the attack is blocked (Moat, Lighthouse, etc.)
if (IsAttackBlocked[attackee])
continue;
var choice = new Choice("Do you want to discard 2 cards or gain a Curse into your hand?", this, this, new List { Resource.Discard2Cards, "Gain a Curse in hand" }, attackee);
var result = attackee.MakeChoice(choice);
if (result.Options[0] == Resource.Discard2Cards)
{
var choiceDiscard = new Choice(Resource.Discard2Cards, this, attackee.Hand, ChoiceOutcome.Discard, attackee, minimum: 2, maximum: 2);
var discards = attackee.MakeChoice(choiceDiscard);
attackee.Discard(DeckLocation.Hand, discards.Cards);
}
else
{
attackee.Gain(player._Game.Table.Curse, this, DeckLocation.Hand);
}
}
}
}
public class TradingPost : Card
{
public TradingPost() : this(Edition.First) { }
public TradingPost(Edition edition)
: base(Categories.Action, Source.Intrigue, Location.Kingdom, Traits.DeckReduction | Traits.Gainer | Traits.Trasher | Traits.RemoveCurses | Traits.Terminal | Traits.RemoveFromHand, edition: edition)
{
BaseCost = new Cost(5);
}
public override void FollowInstructions(IPlayer player)
{
Contract.Requires(player != null, "player cannot be null");
base.FollowInstructions(player);
var choiceTrash = new Choice(Resource.Trash2, this, player.Hand, ChoiceOutcome.Trash, player, minimum: 2, maximum: 2);
var resultTrash = player.MakeChoice(choiceTrash);
player.Trash(this, player.RetrieveCardsFrom(DeckLocation.Hand, resultTrash.Cards));
if (resultTrash.Cards.Count == 2)
player.Gain(player._Game.Table.Silver, this, DeckLocation.Hand);
}
}
public class Tribute : Card
{
public Tribute()
: base(Categories.Action, Source.Intrigue, Location.Kingdom, Traits.PlusCard | Traits.PlusAction | Traits.PlusMultipleActions | Traits.Discard | Traits.AffectOthers | Traits.ConditionalBenefit, edition: Edition.First)
{
BaseCost = new Cost(5);
}
public override void FollowInstructions(IPlayer player)
{
Contract.Requires(player != null, "player cannot be null");
base.FollowInstructions(player);
// Get the player to my left
var playerToLeft = player._Game.GetPlayerFromIndex(player, 1);
playerToLeft.Draw(2, DeckLocation.Revealed);
var previousCardName = string.Empty;
var benefit = new CardBenefit();
foreach (var card in playerToLeft.Revealed)
{
if (card.Name != previousCardName)
{
if (card.Category.HasFlag(Categories.Action))
benefit.Actions += 2;
if (card.Category.HasFlag(Categories.Treasure))
benefit.Currency += new Coin(2);
if (card.Category.HasFlag(Categories.Victory))
benefit.Cards += 2;
}
previousCardName = card.Name;
}
playerToLeft.DiscardRevealed();
player.ReceiveBenefit(this, benefit);
}
}
public class Upgrade : Card
{
public Upgrade()
: base(Categories.Action, Source.Intrigue, Location.Kingdom, Traits.DeckReduction | Traits.PlusCard | Traits.PlusAction | Traits.Gainer | Traits.Trasher | Traits.RemoveCurses | Traits.Cantrip | Traits.TrashForBenefit | Traits.RemoveFromHand)
{
BaseCost = new Cost(5);
Benefit.Cards = 1;
Benefit.Actions = 1;
}
public override void FollowInstructions(IPlayer player)
{
Contract.Requires(player != null, "player cannot be null");
base.FollowInstructions(player);
var choiceTrash = new Choice(Resource.ChooseACardToTrash, this, player.Hand, ChoiceOutcome.Trash, player);
var resultTrash = player.MakeChoice(choiceTrash);
player.Trash(this, player.RetrieveCardsFrom(DeckLocation.Hand, resultTrash.Cards));
if (resultTrash.Cards.Any())
{
var trashedCardCost = player._Game.ComputeCost(resultTrash.Cards[0]);
var gainableSupplies = new SupplyCollection(player._Game.Table.TableEntities.FindAll(supply => supply.CanGain() && supply.CurrentCost == (trashedCardCost + new Coin(1))));
var choice = new Choice(Resource.GainCard, this, gainableSupplies, ChoiceOutcome.Gain, player, false);
var result = player.MakeChoice(choice);
if (result.Supply != null)
player.Gain(result.Supply, this);
}
}
}
public class WishingWell : Card
{
public WishingWell() : this(Edition.First) { }
public WishingWell(Edition edition)
: base(Categories.Action, Source.Intrigue, Location.Kingdom, Traits.PlusCard | Traits.PlusAction | Traits.ConditionalBenefit | Traits.Cantrip, edition: edition)
{
BaseCost = new Cost(3);
Benefit.Cards = 1;
Benefit.Actions = 1;
}
public override void FollowInstructions(IPlayer player)
{
Contract.Requires(player != null, "player cannot be null");
base.FollowInstructions(player);
var availableSupplies = new SupplyCollection(player._Game.Table.TableEntities.FindAll(
kvp =>
(kvp.Randomizer != null
&& !kvp.Randomizer.Traits.HasFlag(Traits.Randomizer))
|| kvp.Location == Location.General
));
var cards = new CardCollection();
var choice = new Choice(Resource.NameCard, this, availableSupplies, ChoiceOutcome.Select, player, false);
foreach (var supply in player._Game.Table.TableEntities.Values.OfType().Union(player._Game.Table.SpecialPiles.Values.OfType()))
{
foreach (var type in supply.Types)
{
if (choice.Supplies.All(kvp => kvp.Value is ISupply kvpSupply && kvpSupply.Type != type))
cards.Add(CreateInstance(type));
}
}
cards.Sort();
choice.AddCards(cards);
var result = player.MakeChoice(choice);
IDisplayable wishedCard;
if (result.Supply != null)
wishedCard = result.Supply;
else
wishedCard = result.Cards[0];
player._Game.SendMessage(player, this, wishedCard);
if (player.CanDraw)
{
player.Draw(DeckLocation.Revealed);
if (player.Revealed[wishedCard.Type].Any())
{
player.AddCardsToHand(DeckLocation.Revealed);
}
else
{
player.AddCardsToDeck(player.RetrieveCardsFrom(DeckLocation.Revealed), DeckPosition.Top);
}
}
}
}
}