private void PerformCleanup() { // Sets up card movements to indicate where each card should go. CardMovementCollection cardsToMove = new CardMovementCollection(this.SetAside, c => c.CanCleanUp, DeckLocation.SetAside, DeckLocation.Discard); cardsToMove.AddRange(this.Hand, DeckLocation.Hand, DeckLocation.Discard); cardsToMove.AddRange(this.InPlay, DeckLocation.InPlay, DeckLocation.Discard); foreach (Card durationCard in this.InPlay.Where(c => !c.CanCleanUp)) cardsToMove[durationCard].Destination = DeckLocation.SetAside; IEnumerable<CardMovement> inPlayCards = cardsToMove.Where(cm => cm.CurrentLocation == DeckLocation.InPlay); ParallelQuery<CardMovement> pqCardsToMove = cardsToMove.AsParallel().Where(cm => cm.CurrentLocation == DeckLocation.InPlay && cm.Destination == DeckLocation.SetAside && cm.Card.ModifiedBy != null && cardsToMove.Contains(cm.Card.ModifiedBy.PhysicalCard) && cardsToMove[cm.Card.ModifiedBy.PhysicalCard].Destination == DeckLocation.Discard); pqCardsToMove.ForAll(cm => cardsToMove[cm.Card.ModifiedBy.PhysicalCard].Destination = DeckLocation.SetAside); int drawSize = 5; if (CleaningUp != null) { Boolean cancelled = false; // Possibly changing events that can happen in the game CleaningUpEventArgs cuea = null; do { cuea = new CleaningUpEventArgs(this, 5, ref cardsToMove); cuea.Cancelled |= cancelled; CleaningUp(this, cuea); OptionCollection options = new OptionCollection(); IEnumerable<Type> cardTypes = cuea.Actions.Keys; foreach (Type key in cardTypes) options.Add(new Option(cuea.Actions[key].Text, false)); if (options.Count > 0) { options.Sort(); Choice choice = new Choice("Performing Clean-up", options, this, cuea); ChoiceResult result = this.MakeChoice(choice); if (result.Options.Count > 0) cuea.Actions.First(kvp => kvp.Value.Text == result.Options[0]).Value.Method(this, ref cuea); else break; } else break; cancelled |= cuea.Cancelled; } while (CleaningUp != null); if (cuea != null) cancelled |= cuea.Cancelled; if (cancelled) return; if (cuea.NextPlayer != null) _CurrentTurn.NextPlayer = cuea.NextPlayer; _CurrentTurn.NextGrantedBy = cuea.NextGrantedBy; drawSize = cuea.DrawSize; } // Discard any Revealed cards (should be none?) this.DiscardRevealed(); CardsDiscardAction cdaHand = null; if (cardsToMove.Count(c => c.CurrentLocation == DeckLocation.Hand) > 0) cdaHand = new CardsDiscardAction(this, null, "Discard hand", player_DiscardHand, true) { Data = cardsToMove }; // Discard non-Duration (or Duration-modifying) cards in In Play & Set Aside at the same time this.Discard(DeckLocation.InPlayAndSetAside, cardsToMove.Where(cm => (cm.CurrentLocation == DeckLocation.InPlay || cm.CurrentLocation == DeckLocation.SetAside) && cm.Destination == DeckLocation.Discard).Select<CardMovement, Card>(cm => cm.Card), cdaHand); // Discard Hand this.AddCardsInto(DeckLocation.Discard, this.RetrieveCardsFrom(DeckLocation.Hand, c => cardsToMove[c].CurrentLocation == DeckLocation.Hand && cardsToMove[c].Destination == DeckLocation.Discard)); // Move Duration (and Duration-modifying) cards from In Play into Set Aside this.MoveInPlayToSetAside(c => cardsToMove.Contains(c) && cardsToMove[c].CurrentLocation == DeckLocation.InPlay && cardsToMove[c].Destination == DeckLocation.SetAside); // Move any cards that have had their Destination changed to their appropriate locations IEnumerable<Card> replaceCards = cardsToMove.Where(cm => cm.Destination == DeckLocation.Deck).Select(cm => cm.Card); if (replaceCards.Count() > 0) { Choice replaceChoice = new Choice("Choose order of cards to put back on your deck", null, replaceCards, this, true, replaceCards.Count(), replaceCards.Count()); ChoiceResult replaceResult = this.MakeChoice(replaceChoice); this.RetrieveCardsFrom(DeckLocation.InPlay, c => cardsToMove[c].CurrentLocation == DeckLocation.InPlay && replaceResult.Cards.Contains(c)); this.RetrieveCardsFrom(DeckLocation.SetAside, c => cardsToMove[c].CurrentLocation == DeckLocation.SetAside && replaceResult.Cards.Contains(c)); this.AddCardsToDeck(replaceResult.Cards, DeckPosition.Top); } #if DEBUG if (this.InPlay.Count > 0) throw new Exception("Something happened -- there are cards left in the player's In Play area!"); #endif if (CurrentTurn != null) CurrentTurn.Finished(); _Actions = _Buys = 0; _Currency.Coin.Value = 0; _Currency.Potion.Value = 0; _ActionsPlayed = 0; #if DEBUG // Check to see that there are no duplicate cards anywhere CardCollection allCards = new CardCollection(); allCards.AddRange(this.Hand); allCards.AddRange(this.Revealed); allCards.AddRange(this.Private); allCards.AddRange(this.InPlay); allCards.AddRange(this.SetAside); allCards.AddRange(this.DrawPile.LookThrough(c => true)); allCards.AddRange(this.DiscardPile.LookThrough(c => true)); foreach (CardMat mat in this.PlayerMats.Values) allCards.AddRange(mat); ParallelQuery<Card> duplicateCards = allCards.AsParallel().Where(c => allCards.Count(ct => ct == c) > 1); //IEnumerable<Card> duplicateCards = allCards.FindAll(c => allCards.Count(ct => ct == c) > 1); if (duplicateCards.Count() > 0) { // Ruh Roh throw new Exception("Duplicate cards found! Something went wrong!"); } #endif DrawHand(drawSize); if (CleanedUp != null) { CleanedUp(this, new CleanedUpEventArgs(this, drawSize)); } if (TurnEnded != null) { TurnEnded(this, new TurnEndedEventArgs(this)); } }
internal void Start(Turn turn) { if (TurnStarting != null) { TurnStartingEventArgs tsea = new TurnStartingEventArgs(this); tsea.GrantedBy = turn.GrantedBy; TurnStarting(this, tsea); if (tsea.Cancelled) return; } _CurrentTurn = turn; _Actions = _Buys = 1; Phase = PhaseEnum.Starting; if (BenefitsChanged != null) { BenefitsChangedEventArgs bcea = new BenefitsChangedEventArgs(this); BenefitsChanged(this, bcea); } if (TurnStarted != null) { TurnStartedEventArgs tsea = null; List<Object> handledBy = new List<Object>(); Boolean actionPerformed = false; do { actionPerformed = false; tsea = new TurnStartedEventArgs(this); tsea.HandledBy.AddRange(handledBy); TurnStarted(this, tsea); handledBy = tsea.HandledBy; IEnumerator<Player> enumerator = this._Game.GetPlayersStartingWithEnumerator(this); while (enumerator.MoveNext()) { OptionCollection options = new OptionCollection(); IEnumerable<String> cardTypes = tsea.Actions.Keys; foreach (String key in cardTypes) { if (enumerator.Current == tsea.Actions[key].Player) options.Add(tsea.Actions[key].Text, tsea.Actions[key].IsRequired); } if (options.Count > 0) { options.Sort(); Choice choice = new Choice(String.Format("{0} turn has started", this == enumerator.Current ? "Your" : String.Format("{0}'s", this)), options, this, tsea); ChoiceResult result = enumerator.Current.MakeChoice(choice); if (result.Options.Count > 0) { tsea.Actions.First(kvp => kvp.Value.Text == result.Options[0]).Value.Method(enumerator.Current, ref tsea); actionPerformed = true; } } } } while (TurnStarted != null && actionPerformed); } _SetAside.Refresh(this); Phase = PhaseEnum.Action; //TakeTurn(this._Game, this); }
public void Discard(DeckLocation fromLocation, Predicate<Card> match, int count, CardsDiscardAction discardAction) { CardCollection matchingCards = this.ResolveDeck(fromLocation)[match]; if (count >= 0 && count < matchingCards.Count) { matchingCards.RemoveRange(count, matchingCards.Count - count); if (matchingCards.Count != count) throw new Exception("Incorrect number of cards found!"); } if (matchingCards.Count == 0) return; if (CardsDiscarding != null) { CardsDiscardEventArgs cdea = null; List<Object> handledBy = new List<Object>(); Boolean actionPerformed = false; Boolean cancelled = false; do { actionPerformed = false; cdea = new CardsDiscardEventArgs(fromLocation, matchingCards); cdea.Cancelled = cancelled; cdea.HandledBy.AddRange(handledBy); CardsDiscarding(this, cdea); handledBy = cdea.HandledBy; matchingCards = cdea.Cards; cancelled |= cdea.Cancelled; OptionCollection options = new OptionCollection(); IEnumerable<Tuple<Type, Type>> cardTypes = cdea.Actions.Keys; foreach (Tuple<Type, Type> key in cardTypes) options.Add(new Option(cdea.Actions[key].Text, cdea.Actions[key].IsRequired)); if (options.Count > 0) { if (discardAction != null && !cdea.HandledBy.Contains(this)) { cdea.AddAction(this.GetType(), discardAction); options.Add(new Option(discardAction.Text, true)); } options.Sort(); Choice choice = new Choice(String.Format("You are discarding {0}", Utilities.StringUtility.Plural("card", matchingCards.Count)), options, this, cdea); ChoiceResult result = this.MakeChoice(choice); if (result.Options.Count > 0) { CardsDiscardAction action = cdea.Actions.First(kvp => kvp.Value.Text == result.Options[0]).Value; cdea.Data = action.Data; action.Method(this, ref cdea); actionPerformed = true; handledBy = cdea.HandledBy; matchingCards = cdea.Cards; cancelled |= cdea.Cancelled; } } } while (CardsDiscarding != null && actionPerformed); if (cancelled) return; } this.RetrieveCardsFrom(fromLocation, matchingCards); if (CardsDiscard != null) { CardsDiscardEventArgs cdea = null; List<Object> handledBy = new List<Object>(); cdea = new CardsDiscardEventArgs(fromLocation, matchingCards); cdea.HandledBy.AddRange(handledBy); CardsDiscard(this, cdea); handledBy = cdea.HandledBy; matchingCards = cdea.Cards; } this.AddCardsInto(DeckLocation.Discard, matchingCards); if (CardsDiscarded != null) { CardsDiscardEventArgs cdea = null; List<Object> handledBy = new List<Object>(); Boolean actionPerformed = false; do { actionPerformed = false; cdea = new CardsDiscardEventArgs(fromLocation, matchingCards); cdea.HandledBy.AddRange(handledBy); CardsDiscarded(this, cdea); handledBy = cdea.HandledBy; OptionCollection options = new OptionCollection(); IEnumerable<Tuple<Type, Type>> cardTypes = cdea.Actions.Keys; foreach (Tuple<Type, Type> key in cardTypes) options.Add(new Option(cdea.Actions[key].Text, false)); if (options.Count > 0) { options.Sort(); Choice choice = new Choice(String.Format("You discarded {0}", Utilities.StringUtility.Plural("card", matchingCards.Count)), options, this, cdea); ChoiceResult result = this.MakeChoice(choice); if (result.Options.Count > 0) { cdea.Actions.First(kvp => kvp.Value.Text == result.Options[0]).Value.Method(this, ref cdea); actionPerformed = true; } } } while (CardsDiscarded != null && actionPerformed); } }