class CardKingsCourt : public CardEffect { public: void PlayAction(State &s) const { s.stack.PushEnd(new EventPlayActionNTimes(c, 3)); } }; class CardMountebank : public CardEffect { public: void PlayAction(State &s) const { for(const PlayerInfo &p : s.data->players) { if(p.index != s.player) { s.stack.PushEnd(new EventMountebankAttack(c, p.index)); } } } }; class CardRabble : public CardEffect { public: void PlayAction(State &s) const { for(const PlayerInfo &p : s.data->players) { if(p.index != s.player) { s.stack.PushEnd(new EventRabbleAttack(c, p.index)); } } } }; class CardGoons : public CardEffect { public: void PlayAction(State &s) const { for(const PlayerInfo &p : s.data->players) { if(p.index != s.player) { s.stack.PushEnd(new EventDiscardDownToN(c, p.index, 3)); } } } }; class CardBishop : public CardEffect { public: void PlayAction(State &s) const { for(const PlayerInfo &p : s.data->players) s.stack.PushEnd(new EventBishop(c, p.index)); } }; class CardCity : public CardEffect { public: void PlayAction(State &s) const { int emptyPileCount = 0; for(UINT supplyIndex = 0; supplyIndex < s.data->supplyCards.Length(); supplyIndex++) { if(s.supply[supplyIndex].count == 0) emptyPileCount++; } if(emptyPileCount >= 1) s.stack.PushEnd(new EventDrawCard(s.player)); if(emptyPileCount >= 2) { s.players[s.player].buys++; s.players[s.player].money++; if(logging) s.LogIndent(1, "gains $1"); } } }; class CardLoan : public CardEffect { public: void PlayAction(State &s) const { s.stack.PushEnd(new EventLoan(c)); } }; class CardVenture : public CardEffect { public: void PlayAction(State &s) const { s.stack.PushEnd(new EventVenture(c)); } }; class CardCountingHouse : public CardEffect { public: void PlayAction(State &s) const { PlayerState &p = s.players[s.player]; int copperCount = 0; for(Card *c : p.discard) if(c == s.data->baseCards.copper) copperCount++; if(copperCount == 0) { if(logging) s.LogIndent(1, "has no coppers in their discard pile"); return; } if(logging) s.LogIndent(1, "reveals " + String(copperCount) + " coppers"); s.decision.MakeDiscreteChoice(c, copperCount + 1); if(decisionText) { s.decision.text = "Put how many coppers into your hand?"; for(int copperIndex = 0; copperIndex <= copperCount; copperIndex++) { s.decision.text += "|" + String(copperIndex); } } } bool CanProcessDecisions() const { return true; } void ProcessDecision(State &s, const DecisionResponse &response) const { if(logging) s.LogIndent(1, "puts " + String(response.choice) + " coppers into their hand"); PlayerState &p = s.players[s.player]; for(UINT copperIndex = 0; copperIndex < response.choice; copperIndex++) { p.discard.RemoveSlow(p.discard.FindFirstIndex(s.data->baseCards.copper)); p.hand.PushEnd(s.data->baseCards.copper); } } }; class CardWatchtower : public CardEffect { public: void PlayAction(State &s) const { PlayerState &p = s.players[s.player]; int handDeficit = Math::Max(6 - (int)p.hand.Length(), 0); if(handDeficit == 0 && logging) s.LogIndent(1, "already has 6 cards in hand"); for(int cardIndex = 0; cardIndex < handDeficit; cardIndex++) s.stack.PushEnd(new EventDrawCard(s.player)); } }; class CardExpand : public CardEffect { public: void PlayAction(State &s) const { if(s.players[s.player].hand.Length() > 0) { s.decision.SelectCards(c, 1, 1); if(decisionText) s.decision.text = "Select a card to trash:"; s.decision.cardChoices = s.players[s.player].hand; s.stack.PushEnd(new EventRemodelExpand(c, 3)); } else { if(logging) s.Log("has no cards to trash"); } } }; class CardTradeRoute : public CardEffect { public: void PlayAction(State &s) const { PlayerState &p = s.players[s.player]; p.money += s.tradeRouteValue; if(logging) s.LogIndent(1, "gets $" + String(s.tradeRouteValue)); s.stack.PushEnd(new EventTradeRoute(c)); } }; class CardMint : public CardEffect { public: void PlayAction(State &s) const { s.stack.PushEnd(new EventMint(c)); } }; class CardVault : public CardEffect { public: void PlayAction(State &s) const { for(const PlayerInfo &p : s.data->players) s.stack.PushEnd(new EventVault(c, p.index)); } };