class EventMountebankAttack : public Event { public: EventMountebankAttack(Card *_source, UINT _player) { source = _source; player = _player; done = false; } bool IsAttack() const { return true; } int AttackedPlayer() const { return player; } AttackAnnotations* Annotations() { return &annotations; } bool CanProcessDecisions() const { return true; } bool Advance(State &s) { if(done) return true; PlayerState &p = s.players[player]; if(p.hand.Contains(s.data->baseCards.curse)) { s.decision.MakeDiscreteChoice(source, 2); s.decision.controllingPlayer = player; if(decisionText) s.decision.text = "Discard a curse?|Yes|No"; return false; } else { s.stack.PushEnd(new EventGainCard(player, s.data->baseCards.curse)); s.stack.PushEnd(new EventGainCard(player, s.data->baseCards.copper)); return true; } } void ProcessDecision(State &s, const DecisionResponse &response) { if(response.choice == 0) { s.stack.PushEnd(new EventDiscardCard(player, s.data->baseCards.curse, DiscardFromHand)); } else if(response.choice == 1) { s.stack.PushEnd(new EventGainCard(player, s.data->baseCards.curse)); s.stack.PushEnd(new EventGainCard(player, s.data->baseCards.curse)); } done = true; } Card *source; UINT player; AttackAnnotations annotations; bool done; }; class EventRabbleAttack : public Event { public: EventRabbleAttack(Card *_source, UINT _player) { source = _source; player = _player; } bool IsAttack() const { return true; } int AttackedPlayer() const { return player; } AttackAnnotations* Annotations() { return &annotations; } bool Advance(State &s) { PlayerState &p = s.players[player]; if(p.deck.Length() <= 3) s.Shuffle(player); int cardsToReveal = Math::Min(3, (int)p.deck.Length()); if(cardsToReveal == 0) { if(logging) s.LogIndent(1, player, "has no cards to reveal"); return true; } Vector<Card*> discardCards; Vector<Card*> topDeckCards; for(int cardIndex = 0; cardIndex < cardsToReveal; cardIndex++) { Card *c = p.deck.Last(); if(logging) s.LogIndent(1, player, "reveals " + c->PrettyName()); p.deck.PopEnd(); if(c->isAction || c->isTreasure) discardCards.PushEnd(c); else topDeckCards.PushEnd(c); } for(Card *c : discardCards) s.stack.PushEnd(new EventDiscardCard(player, c, DiscardFromSideZone)); for(Card *c : topDeckCards) p.deck.PushEnd(c); if(topDeckCards.Length() >= 2) s.stack.PushEnd(new EventReorderDeck(source, player, topDeckCards.Length())); return true; } Card *source; UINT player; AttackAnnotations annotations; }; class EventLoan : public Event { public: EventLoan(Card *_source) { source = _source; treasureCard = NULL; done = false; } bool CanProcessDecisions() const { return true; } bool Advance(State &s) { if(done) return true; PlayerState &p = s.players[s.player]; while(treasureCard == NULL) { Card *revealedCard = NULL; if(p.deck.Length() == 0) s.Shuffle(s.player); if(p.deck.Length() == 0) { if(logging) s.Log("tries to draw, but has no cards left"); for(Card *c : discardZone) s.stack.PushEnd(new EventDiscardCard(s.player, c, DiscardFromSideZone)); return true; } else { revealedCard = p.deck.Last(); p.deck.PopEnd(); if(logging) s.LogIndent(1, "reveals " + revealedCard->PrettyName()); if(revealedCard->isTreasure) { treasureCard = revealedCard; s.decision.MakeDiscreteChoice(source, 2); if(decisionText) s.decision.text = "Discard or trash" + revealedCard->PrettyName() + "?|Discard|Trash"; } else { discardZone.PushEnd(revealedCard); } } } return false; } void ProcessDecision(State &s, const DecisionResponse &response) { if(response.choice == 0) { s.stack.PushEnd(new EventDiscardCard(s.player, treasureCard, DiscardFromSideZone)); } else if(response.choice == 1) { s.stack.PushEnd(new EventTrashCardFromSideZone(s.player, treasureCard)); } for(Card *c : discardZone) s.stack.PushEnd(new EventDiscardCard(s.player, c, DiscardFromSideZone)); done = true; } Vector<Card*> discardZone; Card *source; Card *treasureCard; bool done; }; class EventVenture : public Event { public: EventVenture(Card *_source) { source = _source; } bool Advance(State &s) { PlayerState &p = s.players[s.player]; Vector<Card*> discardZone; bool deckExhausted = false; Card *treasureCard = NULL; while(treasureCard == NULL && !deckExhausted) { Card *revealedCard = NULL; if(p.deck.Length() == 0) s.Shuffle(s.player); if(p.deck.Length() == 0) { if(logging) s.Log("tries to draw, but has no cards left"); deckExhausted = true; } else { revealedCard = p.deck.Last(); p.deck.PopEnd(); if(logging) s.LogIndent(1, "reveals " + revealedCard->PrettyName()); if(revealedCard->isTreasure) { treasureCard = revealedCard; if(logging) s.LogIndent(1, "plays " + treasureCard->PrettyName()); p.playArea.PushEnd(CardPlayInfo(treasureCard, 0)); s.ProcessTreasure(treasureCard); } else { discardZone.PushEnd(revealedCard); } } } for(Card *c : discardZone) s.stack.PushEnd(new EventDiscardCard(s.player, c, DiscardFromSideZone)); return true; } Card *source; }; class EventBishop : public Event { public: EventBishop(Card *_source, int _player) { source = _source; player = _player; done = false; } bool CanProcessDecisions() const { return true; } bool Advance(State &s) { if(done) return true; PlayerState &p = s.players[player]; if(p.hand.Length() == 0) { if(logging) s.LogIndent(1, player, "has no cards to trash"); return true; } if(player == s.player) { s.decision.SelectCards(source, 1, 1); if(decisionText) s.decision.text = "Choose a card to trash:"; } else { s.decision.SelectCards(source, 0, 1); if(decisionText) s.decision.text = "You may trash a card:"; } s.decision.AddUniqueCards(p.hand); s.decision.controllingPlayer = player; return false; } void ProcessDecision(State &s, const DecisionResponse &response) { for(Card *c : response.cards) { s.stack.PushEnd(new EventTrashCardFromHand(player, c)); if(player == s.player) { int VPValue = s.SupplyCost(c) / 2; s.players[player].VPTokens += VPValue; if(logging) s.LogIndent(1, "gains " + String(VPValue) + " VP"); } } done = true; } int player; Card *source; bool done; }; class EventTradeRoute : public Event { public: EventTradeRoute(Card *_source) { source = _source; done = false; } bool CanProcessDecisions() const { return true; } bool Advance(State &s) { if(done) return true; PlayerState &p = s.players[s.player]; if(p.hand.Length() == 0) { if(logging) s.LogIndent(1, "has no cards to trash"); return true; } s.decision.SelectCards(source, 1, 1); if(decisionText) s.decision.text = "Choose a card to trash:"; s.decision.AddUniqueCards(p.hand); return false; } void ProcessDecision(State &s, const DecisionResponse &response) { s.stack.PushEnd(new EventTrashCardFromHand(s.player, response.cards[0])); done = true; } Card *source; bool done; }; class EventMint : public Event { public: EventMint(Card *_source) { source = _source; done = false; } bool CanProcessDecisions() const { return true; } bool Advance(State &s) { if(done) return true; PlayerState &p = s.players[s.player]; if(p.TreasureCount() == 0) { if(logging) s.LogIndent(1, "has no cards to copy"); return true; } s.decision.SelectCards(source, 0, 1); if(decisionText) s.decision.text = "Gain a copy of which treasure?"; for(Card *c : p.hand) if(c->isTreasure) s.decision.AddUniqueCard(c); return false; } void ProcessDecision(State &s, const DecisionResponse &response) { if(response.cards.Length() == 0) { if(logging) s.LogIndent(1, "does not gain a treasure"); } else { if(logging) s.LogIndent(1, "reveals " + response.cards[0]->PrettyName()); s.stack.PushEnd(new EventGainCard(s.player, response.cards[0])); } done = true; } Card *source; bool done; }; class EventVault : public Event { public: EventVault(Card *_source, int _player) { source = _source; player = _player; done = false; } bool CanProcessDecisions() const { return true; } bool Advance(State &s) { if(done) return true; PlayerState &p = s.players[player]; if(player == s.player) { if(p.hand.Length() == 0) { if(logging) s.LogIndent(1, player, "has no cards to discard"); return true; } s.decision.SelectCards(source, 0, s.players[player].hand.Length()); if(decisionText) s.decision.text = "Select cards to discard:"; } else { if(p.hand.Length() < 2) { if(logging) s.LogIndent(1, player, "does not have enough cards to discard"); return true; } s.decision.SelectCards(source, 0, 2); if(decisionText) s.decision.text = "Discard 2 cards to draw a card:"; } s.decision.cardChoices = s.players[player].hand; s.decision.controllingPlayer = player; return false; } void ProcessDecision(State &s, const DecisionResponse &response) { PlayerState &p = s.players[player]; if(player == s.player) { p.money += response.cards.Length(); if(logging) s.LogIndent(1, "gets $" + String(response.cards.Length())); for(Card *c : response.cards) { s.stack.PushEnd(new EventDiscardCard(player, c, DiscardFromHand)); } } else { if(response.cards.Length() <= 1) { if(logging) s.LogIndent(1, player, "does not discard to " + source->PrettyName()); } else { s.stack.PushEnd(new EventDrawCard(player)); for(Card *c : response.cards) { s.stack.PushEnd(new EventDiscardCard(player, c, DiscardFromHand)); } } } done = true; } int player; Card *source; bool done; };