using System; using System.Collections.Generic; using System.Linq; using System.Text; using DominionBase.Cards; using DominionBase.Players; namespace DominionBase.Piles { public class BuyCheckEventArgs : EventArgs { public Player CurrentPlayer; public Boolean Cancelled = false; public BuyCheckEventArgs(Player player) { CurrentPlayer = player; } } public class TokensChangedEventArgs : EventArgs { public Token _Token = null; public TokensChangedEventArgs(Token token) { _Token = token; } } public class CardGainEventArgs : EventArgs { public Card Card; public Boolean Cancelled = false; public Dictionary Actions = new Dictionary(); public List HandledBy = new List(); public CardGainEventArgs(Card card) { this.Card = card; } } public delegate void CardGainMethod(Player player, ref CardGainEventArgs cardGainEventArgs); public class CardGainAction { private Player _Player = null; private Card _Card = null; private String _Text = String.Empty; private CardGainMethod _Method = null; public Player Player { get { return _Player; } } public Card Card { get { return _Card; } } public String Text { get { return _Text; } } public CardGainMethod Method { get { return _Method; } } public CardGainAction(Player player, Card card, String text, CardGainMethod method) { _Player = player; _Card = card; _Text = text; _Method = method; } } public class Supply : Pile, IComparable, ICard { public delegate void BuyCheckEventHandler(object sender, BuyCheckEventArgs e); public virtual event BuyCheckEventHandler BuyCheck = null; public delegate void TokensChangedEventHandler(object sender, TokensChangedEventArgs e); public virtual event TokensChangedEventHandler TokensChanged = null; public override event Pile.PileChangedEventHandler PileChanged; private Game _Game = null; private CardCollection _OriginalCards = new CardCollection(); private Category _Category = Category.Unknown; private Type _CardClassType = null; private Card _CardBase = null; private Cost _LastComputedCost = null; private TokenCollection _Tokens = new TokenCollection(); internal Supply(Game game, PlayerCollection players, Type cardType, int count) : base(Visibility.All, VisibilityTo.All, null, false) { Init(game, players, cardType, count); } internal Supply(Game game, PlayerCollection players, Type cardType, Visibility visibility) : base(visibility, VisibilityTo.All, null, false) { Init(game, players, cardType, 0); } private void Init(Game game, PlayerCollection players, Type cardType, int count) { if (!cardType.IsSubclassOf(typeof(Card))) throw new System.ArgumentException("Type must be a subclass of Card class"); _Game = game; //_Table = table; _CardClassType = cardType; _CardBase = Card.CreateInstance(_CardClassType); _CardBase.AddedToSupply(this._Game, this); AddTo(count); _Category = this.Randomizer.Category; if (players != null) { foreach (Player player in players) player.PhaseChanged += new Player.PhaseChangedEventHandler(player_PhaseChangedEvent); } } internal void Empty() { _OriginalCards.Clear(); _Cards.Clear(); } internal new void Clear() { this.Empty(); _CardBase = null; _Game = null; } internal override void TearDown() { base.TearDown(); _Tokens.TearDown(); _OriginalCards.TearDown(); _CardBase.TearDown(); foreach (Player player in _Game.Players) player.PhaseChanged -= new Player.PhaseChangedEventHandler(player_PhaseChangedEvent); } public override void EndChanges() { _AsynchronousChanging = false; if (_AsynchronousPileChangedEventArgs != null && PileChanged != null) { PileChanged(this, _AsynchronousPileChangedEventArgs); } _AsynchronousPileChangedEventArgs = null; } void player_PhaseChangedEvent(object sender, PhaseChangedEventArgs e) { if (_CardBase != null) _CardBase.PhaseChanged(sender, e); _Cards.PhaseChanged(sender, e); } public int OriginalCount { get { return _OriginalCards.Count; } } public TokenCollection Tokens { get { return _Tokens; } } public void AddToken(Token token) { _Tokens.Add(token); if (TokensChanged != null) { TokensChangedEventArgs etcea = new TokensChangedEventArgs(token); TokensChanged(this, etcea); } PileChangedEventArgs pcea = new PileChangedEventArgs(PileChangedEventArgs.Operation.Reset); if (_AsynchronousChanging) { _AsynchronousPileChangedEventArgs = pcea; } else if (PileChanged != null) { PileChanged(this, pcea); } } public Category Category { get { return _Category; } } public Source Source { get { return this.Randomizer.Source; } } public Location Location { get { return this.Randomizer.Location; } } public CardBack CardBack { get { return this.Randomizer.CardBack; } } public Card Randomizer { get { return _CardBase; } } public Card TopCard { get { if (this.Count > 0) return this.First(); else return null; } } public Type SupplyCardType { get { return CardType; } } public Type CardType { get { return this.Randomizer.CardType; } } public List CardTypes { get { List types = new List(); foreach (Card card in _OriginalCards) if (!types.Contains(card.CardType)) types.Add(card.CardType); return types; } } public CardBenefit Benefit { get { return _CardBase.Benefit; } } public Boolean IsEndgameTriggered { get { return this.Randomizer.IsEndgameTriggered(this); } } internal void AddTo(IEnumerable cards) { foreach (Card card in cards) AddTo(card); } internal void AddTo(Card card) { if (card.Category == Cards.Category.Unknown) throw new Exception("Cannot add card of a different type to Supply pile"); _Cards.Insert(0, card); card.AddedToSupply(this._Game, this); if (PileChanged != null) { lock (PileChanged) { PileChangedEventArgs pcea = new PileChangedEventArgs(null, PileChangedEventArgs.Operation.Added, new CardCollection() { card }); PileChanged(this, pcea); } } } internal void AddTo(int count) { if (_CardClassType == null) throw new Exception("Cannot use this method without a proper Card Type"); for (int i = 0; i < count; i++) AddTo(Card.CreateInstance(_CardClassType)); } internal void FinalizeSetup() { if (_OriginalCards.Count > 0) throw new Exception("Cannot call this method more than once!"); Card[] cards = new Card[this.Count]; _Cards.CopyTo(cards); _OriginalCards = new CardCollection(cards); } public void Bought(Player player) { foreach (Token token in _Tokens) { if (token.Buying(_Game.Table, player)) { _Tokens.Remove(token); _Game.Table.TokenPiles.Add(token); if (TokensChanged != null) { TokensChangedEventArgs etcea = new TokensChangedEventArgs(token); TokensChanged(this, etcea); } } } } public Card Take() { return Take(this.TopCard.CardType, 1).ElementAt(0); } public IEnumerable Take(int count) { return Take(this.TopCard.CardType, count); } public Card Take(Type cardType) { return Take(cardType, 1).ElementAt(0); } public IEnumerable Take(Type cardType, int count) { IEnumerable returnCards = _Cards.FindAll(card => card.CardType == cardType).Take(count); if (count == 0) return returnCards; if (returnCards.Count() == 0) throw new Exception("Nothing to take!"); if (_Game.State != GameState.Setup) { for (int index = _Tokens.Count - 1; index >= 0; index--) { Token token = _Tokens[index]; if (token.Gaining()) { _Tokens.Remove(token); _Game.Table.TokenPiles.Add(token); if (TokensChanged != null) { TokensChangedEventArgs etcea = new TokensChangedEventArgs(token); TokensChanged(this, etcea); } } } } _Cards.RemoveAll(c => returnCards.Contains(c)); if (_Game.State != GameState.Setup) { if (_AsynchronousChanging) { if (_AsynchronousPileChangedEventArgs == null) _AsynchronousPileChangedEventArgs = new PileChangedEventArgs(null, PileChangedEventArgs.Operation.Removed, returnCards); else _AsynchronousPileChangedEventArgs.RemovedCards.AddRange(returnCards); } else if (PileChanged != null) { PileChangedEventArgs pcea = new PileChangedEventArgs(null, PileChangedEventArgs.Operation.Removed, returnCards); PileChanged(this, pcea); } } return returnCards; } public Cards.Cost BaseCost { get { if (this.TopCard != null) return this.TopCard.BaseCost; return _CardBase.BaseCost; } } public Cards.Cost CurrentCost { get { Cost currentCost = _Game.Cost(_CardBase); if (this.TopCard != null) currentCost = _Game.Cost(this.TopCard); if (_LastComputedCost == (Cost)null) _LastComputedCost = currentCost; if (_LastComputedCost != currentCost) { PileChangedEventArgs pcea = new PileChangedEventArgs(PileChangedEventArgs.Operation.Reset); if (_AsynchronousChanging) { _AsynchronousPileChangedEventArgs = pcea; } else if (PileChanged != null) { PileChanged(this, pcea); } } _LastComputedCost = currentCost; return currentCost; } } public override void Reset() { base.Reset(); if (_Tokens.RemoveAll(token => token.IsTemporary) > 0) { if (TokensChanged != null) { TokensChangedEventArgs tcea = new TokensChangedEventArgs(null); TokensChanged(this, tcea); } } PileChangedEventArgs pcea = new PileChangedEventArgs(PileChangedEventArgs.Operation.Reset); if (_AsynchronousChanging) { _AsynchronousPileChangedEventArgs = pcea; } else if (PileChanged != null) { PileChanged(this, pcea); } } public override string ToString() { StringBuilder sb = new StringBuilder(); switch (this.Visibility) { case Visibility.None: return String.Format("{0} Cards", Count); case Visibility.All: sb.Append(_Cards.ToString()); break; case Visibility.Top: sb.AppendFormat("{0}: Cost:{1}; {2} Cards", _CardBase, this.CurrentCost, Count); break; default: return "<>"; } return sb.ToString(); } public Boolean CanBuy(Player player) { if (this.CanGain() && player.Currency >= this.CurrentCost) { if (BuyCheck != null) { BuyCheckEventArgs bcea = new BuyCheckEventArgs(player); BuyCheck(this, bcea); if (bcea.Cancelled) return false; } return _CardBase.CanBuy(player); } return false; } public Boolean CanGain() { if (this.TopCard == null) return false; //if (_CardBase.Location == Cards.Location.General) // return CanGain(_CardBase.CardType); //else return CanGain(this.TopCard.CardType); } public Boolean CanGain(Type cardType) { Card gainCard = _Cards.Find(card => card.CardType == cardType); if (gainCard == null) return false; return this.Count > 0 && gainCard.CanGain(); } public int CompareTo(Supply obj) { return _CardBase.CompareTo(obj._CardBase); } public String Text { get { return _CardBase.Text; } } public String Name { get { return _CardBase.Name; } } internal void Setup() { if (_CardBase != null) _CardBase.Setup(this._Game, this); FinalizeSetup(); } } public class SupplyCollection : Dictionary { public SupplyCollection() { } public SupplyCollection(IEnumerable> keyValuePairs) { foreach (KeyValuePair kvp in keyValuePairs) this[kvp.Key] = kvp.Value; } public Supply this[Card card] { get { return this[card.BaseType]; } } public int EmptySupplyPiles { get { return this.Values.Count(s => s.Count == 0); } } public void Reset() { foreach (Supply supply in this.Values) supply.Reset(); } internal void Setup() { List supplies = new List(this.Values); foreach (Supply supply in supplies) supply.Setup(); } public SupplyCollection FindAll(Func predicate) { SupplyCollection supplies = new SupplyCollection(); foreach (Supply supply in this.Values.Where(predicate)) supplies[supply.SupplyCardType] = supply; return supplies; } public Boolean ContainsKey(Card card) { return this.ContainsKey(card.BaseType); } internal void TearDown() { foreach (Supply supply in this.Values) supply.TearDown(); } } }