class TradingPost(ActionCard): name = _("Trading Post") edition = Intrigue cost = 5 desc = _( "Trash 2 cards from your hand. If you do, gain a Silver card; put it into your hand." ) def activate_action(self, game, player): if player.hand: cards = yield SelectHandCards( game, player, count_lower=2, count_upper=2, msg=_("Which cards do you want to trash?")) else: return # trash cards for card in cards: card.trash(game, player) for info_player in game.following_participants(player): yield InfoRequest(game, info_player, _("%s trashes these cards:", (player.name, )), cards) if game.supply["Silver"]: new_card = game.supply["Silver"].pop() player.hand.append(new_card) for info_player in game.following_participants(player): yield InfoRequest(game, info_player, _("%s gains:", (player.name, )), [new_card]) for val in game.check_empty_pile("Silver"): yield val
def activate_action(self, game, player): player.remaining_actions += 1 player.draw_cards(1) player.draw_cards(4) drawn, player.hand = player.hand[-4:], player.hand[:-4] card_classes = [type(c) for c in drawn] # FIXME any numer part still missing card_cls = (yield SelectCard(game, player, _("Which card do you want to discard?"), card_classes=card_classes)) card = [c for c in drawn if isinstance(c, card_cls)][0] drawn.remove(card) player.discard_pile.append(card) while drawn: card_classes = [type(c) for c in drawn] card_cls = (yield SelectCard(game, player, _("Which card do you want to put back?"), card_classes=card_classes)) card = [c for c in drawn if isinstance(c, card_cls)][0] drawn.remove(card) player.discard_pile.append(card)
class Trader(ReactionCard): name = _("Trader") edition = Hinterlands implemented = False #FIXME Second half of the action should be triggered when card is gained. cost = 4 desc = _( "Trash a card from your hand. Gain a number of Silvers equal to its cost in coins. " "| When you would gain a card, you may reveal this from your hand. If you do, instead, gain a silver." ) def activate_action(self, game, player): cards = yield SelectHandCards( game, player, cls=TreasureCard, count_lower=0, count_upper=1, msg= _("Select a treasure card you want to convert to a potentially better card." )) if cards: card = cards[0] new_cards = [] for i in range(0, 4): if game.supply["Silver"]: new_cards.append(game.supply["Silver"].pop()) for val in game.check_empty_pile("Silver"): yield val card.trash(game, player) player.hand.append(new_card) for info_player in game.following_participants(player): yield InfoRequest(game, info_player, _("%s trashes:", (player.name, )), [card]) yield InfoRequest(game, info_player, _("%s gains:", (player.name, )), new_cards)
class Inn(ActionCard): name = _("Inn") edition = Hinterlands implemented = False #FIXME Second half of the action should be triggered when card is gained. cost = 5 desc = _( "+2 Cards +2 Actions. Discard 2 Cards. | When you gain this, look through your " "discard pile (including this), reveal any number of Action cards from it, " "and shuffle them into your deck.") def activate_action(self, game, player): player.remaining_actions += 2 player.draw_cards(2) cards = yield SelectHandCards( game, player, count_lower=2, count_upper=2, msg=_("Which cards do you want to discard?")) #FIXME make sure player has enough cards to do that if cards is not None: for card in cards: card.discard(player) player.draw_cards(len(cards)) for info_player in game.participants: if info_player is not player: yield InfoRequest( game, info_player, _("%s discards these cards:", (player.name, )), cards)
def activate_action(self, game, player): player.draw_cards(3) player.remaining_deals += 1 for other_player in game.following_players(player): try: handle_defense(self, game, other_player) except Defended: continue other_player.draw_cards(1) if len(other_player.hand) < 4: continue count = len(other_player.hand) - 3 if count <= 0: continue cards = yield SelectHandCards( game, other_player, count_lower=count, count_upper=count, msg=_( "%s played Margrave, you need to discard your hand down to three cards. Which cards do you want to discard?", (player.name, ))) for card in cards: card.discard(other_player) for info_player in game.participants: if info_player is not other_player: # TODO: info players may only see one of the discarded cards yield InfoRequest( game, info_player, _("%s discards these cards:", (other_player.name, )), cards)
class Navigator(ActionCard): name = _("Navigator") edition = Seaside cost = 4 desc = _( "+2 Money. Look at the top 5 Cards of your deck. Either discard all of them, or put them back on top of your deck in any order." ) def activate_action(self, game, player): player.virtual_money += 2 player.draw_cards(5) drawn, player.hand = player.hand[-5:], player.hand[:-5] for info_player in game.following_participants(player): yield InfoRequest(game, info_player, _("%s draws:", (player.name, )), drawn) yield InfoRequest(game, player, _("You draw:", ), drawn) actions = [("discard", _("discard all 5 cards")), ("backondeck", _("put the cards back in your specified order"))] answer = yield Question(game, player, _("What do you want to do?"), actions) if answer == "discard": player.discard_pile.extend(drawn) else: while drawn: card_classes = [type(c) for c in drawn] card_cls = (yield SelectCard( game, player, _("Which card do you want to put back?"), card_classes=card_classes)) card = [c for c in drawn if isinstance(c, card_cls)][0] drawn.remove(card) player.discard_pile.append(card)
class BorderVillage(ActionCard): name = _("Border Village") edition = Hinterlands cost = 6 desc = _( "+1 Card +2 Actions. | When you gain this, gain a card costing less than this." ) def activate_action(self, game, player): player.remaining_actions += 2 player.draw_cards(1) @classmethod def on_gain_card(cls, game, player, card): if not isinstance(card, BorderVillage): return card_classes = [ c for c in game.card_classes.itervalues() if c.cost < cls.cost and game.supply.get(c.__name__) ] card_cls = yield SelectCard( game, player, card_classes=card_classes, msg=_("Select a card that you want to have."), show_supply_count=True) with fetch_card_from_supply(game, card_cls) as new_card: player.discard_pile.append(new_card) for info_player in game.following_participants(player): yield InfoRequest(game, info_player, _("%s gains:", (player.name, )), [new_card])
def activate_action(self, game, player): player.draw_cards(5) drawn, player.hand = player.hand[-5:], player.hand[:-5] for info_player in game.participants: yield InfoRequest( game, info_player, _("%s reveals the top 5 cards of his deck:", (player.name, )), drawn) card_classes = [type(c) for c in drawn] card_cls = yield SelectCard( game, player.left(game), card_classes=card_classes, msg=_("Select a card that %(playername)s should discard.", {"playername": player.name}), show_supply_count=False) for info_player in game.participants: yield InfoRequest( game, info_player, _( "%(player2name)s does not allow %(player2name)s's to buy:", { "playername": player.name, "player2name": player.left(game).name }), [card_cls])
class Stash(TreasureCard): name = _("Stash") edition = Promo implemented = False #FIXME not implemented completely cost = 5 worth = 2 desc = _("When you shuffle, you may put this anywhere in your deck.")
def activate_action(self, game, player): player.draw_cards(1) player.remaining_actions += 1 card_cls = yield SelectCard( game, player, card_classes=[ c for c in game.card_classes.itervalues() if c.__name__ in game.supply ], msg=_("Name a card."), show_supply_count=True) for info_player in game.following_participants(player): yield InfoRequest(game, info_player, _("%s names:", (player.name, )), [card_cls]) player.draw_cards(1) card = player.hand.pop() for info_player in game.participants: yield InfoRequest(game, info_player, _("%s reveals:", (player.name, )), [card]) if isinstance(card, card_cls): player.hand.append(card) else: player.deck.append(card)
class Envoy(ActionCard): name = _("Envoy") edition = Promo implemented = False #FIXME not implemented completely cost = 4 desc = _( "Reveal the top 5 cards of your deck. The player to your left chooses one for you to discard. Draw the rest." ) def activate_action(self, game, player): player.draw_cards(5) drawn, player.hand = player.hand[-5:], player.hand[:-5] for info_player in game.participants: yield InfoRequest( game, info_player, _("%s reveals the top 5 cards of his deck:", (player.name, )), drawn) card_classes = [type(c) for c in drawn] card_cls = yield SelectCard( game, player.left(game), card_classes=card_classes, msg=_("Select a card that %(playername)s should discard.", {"playername": player.name}), show_supply_count=False) for info_player in game.participants: yield InfoRequest( game, info_player, _( "%(player2name)s does not allow %(player2name)s's to buy:", { "playername": player.name, "player2name": player.left(game).name }), [card_cls])
class WishingWell(ActionCard): name = _("Wishing Well") edition = Intrigue cost = 3 desc = _("+1 Card, +1 Action, Name a card. Reveal the top card of your " "deck. If it's the named card, put it into your hand.") def activate_action(self, game, player): player.draw_cards(1) player.remaining_actions += 1 card_cls = yield SelectCard( game, player, card_classes=[ c for c in game.card_classes.itervalues() if c.__name__ in game.supply ], msg=_("Name a card."), show_supply_count=True) for info_player in game.following_participants(player): yield InfoRequest(game, info_player, _("%s names:", (player.name, )), [card_cls]) player.draw_cards(1) card = player.hand.pop() for info_player in game.participants: yield InfoRequest(game, info_player, _("%s reveals:", (player.name, )), [card]) if isinstance(card, card_cls): player.hand.append(card) else: player.deck.append(card)
class Tribute(ActionCard): name = _("Tribute") edition = Intrigue cost = 5 desc = _("The player to your left reveals then discards the top 2 cards " "of his deck. For each differently named card revealed, if it is " "an Action Card: +2 Actions. If it is a Treasure Card: +2 Money. " "If it is a Victory Card: +2 Cards.") def activate_action(self, game, player): cards = [] other_player = player.left(game) other_player.draw_cards(2) drawn, other_player.hand = other_player.hand[ -2:], other_player.hand[:-2] for info_player in game.participants: yield InfoRequest( game, info_player, _("%s reveals the top 2 cards of his deck:", (other_player.name, )), drawn) for i, card in enumerate(drawn): if i == 1 and drawn[1].__name__ == drawn[0].__name__: other_player.discard_pile.append(card) break if isinstance(card, ActionCard): player.remaining_actions += 2 if isinstance(card, TreasureCard): player.virtual_money += 2 if isinstance(card, VictoryCard): player.draw_cards(2) other_player.discard_pile.append(card)
def activate_action(self, game, player): if player.hand: cards = yield SelectHandCards( game, player, count_lower=2, count_upper=2, msg=_("Which cards do you want to trash?")) else: return # trash cards for card in cards: card.trash(game, player) for info_player in game.following_participants(player): yield InfoRequest(game, info_player, _("%s trashes these cards:", (player.name, )), cards) if game.supply["Silver"]: new_card = game.supply["Silver"].pop() player.hand.append(new_card) for info_player in game.following_participants(player): yield InfoRequest(game, info_player, _("%s gains:", (player.name, )), [new_card]) for val in game.check_empty_pile("Silver"): yield val
def activate_action(self, game, player): if player.hand: cards = yield SelectHandCards( game, player, count_lower=1, count_upper=1, msg=_("Which card do you want to Ambassador?")) card = cards[0] samecards = [c for c in player.hand if isinstance(c, type(card))] if len(samecards) >= 2: for info_player in game.participants: yield InfoRequest(game, info_player, _("%s reveals:", (player.name, )), [samecards[0]]) for i in range(2): player.hand.remove(samecards[i]) game.supply[samecards[i].__name__].append(samecards[i]) new_cards = game.supply[samecards[0].__name__] for other_player in game.following_players(player): try: handle_defense(self, game, other_player) except Defended: continue if new_cards: newcard = new_cards.pop() yield InfoRequest( game, other_player, _("%s ambassadors you. You gain a card:", (player.name, )), [newcard]) other_player.discard_pile.append(newcard) for val in game.check_empty_pile( samecards[0].__name__): yield val
class Salvager(ActionCard): name = _("Salvager") edition = Seaside cost = 4 desc = _("+1 Buy. Trash a Card from your hand. +Money equal to its costs.") def activate_action(self, game, player): player.remaining_deals += 1 if player.hand: cards = yield SelectHandCards( game, player, count_lower=1, count_upper=1, msg=_("Which card do you want to trash?")) else: return # trash cards for card in cards: player.virtual_money += card.cost card.trash(game, player) for info_player in game.following_participants(player): yield InfoRequest(game, info_player, _("%s trashes these cards:", (player.name, )), cards)
def activate_action(self, game, player): if not hasattr(player, "seaside_nativevillage_set_aside_cards"): player.seaside_nativevillage_set_aside_cards = [] player.remaining_actions += 2 actions = [("setaside", _("Set aside a card on the Native Village")), ("return", _("Put all cards from the Native Village into your hand.")) ] answer = yield Question(game, player, _("What do you want to do?"), actions) for info_player in game.following_participants(player): yield InfoRequest( game, info_player, _("%(player)s chooses '%(action)s'", { "player": player.name, "action": _(dict(actions)[answer]) }), []) if answer == "setaside": player.draw_cards(1) drawn, player.hand = player.hand[-1:], player.hand[:-1] player.seaside_nativevillage_set_aside_cards.extend(drawn) elif answer == "return": if getattr(player, "seaside_nativevillage_set_aside_cards", None): player.hand.extend( player.seaside_nativevillage_set_aside_cards) player.seaside_nativevillage_set_aside_cards = []
class SeaHag(AttackCard): name = _("Sea Hag") edition = Seaside cost = 4 desc = _( "Each other player discards the top card of his deck, then gains a Curse card, putting it on top of his deck." ) def activate_action(self, game, player): curse_cards = game.supply["Curse"] for other_player in game.following_players(player): try: handle_defense(self, game, other_player) except Defended: continue other_player.draw_cards(1) card = other_player.hand.pop() for info_player in game.participants: yield InfoRequest( game, info_player, _("%s discards the top card of his deck:", (other_player.name, )), [card]) other_player.discard_pile.append(card) if curse_cards: other_player.deck.append(curse_cards.pop()) yield InfoRequest( game, other_player, _("%s curses you. You gain a curse card.", (player.name, )), []) for val in game.check_empty_pile("Curse"): yield val
class TreasureMap(ActionCard): name = _("Treasure Map") edition = Seaside cost = 4 trash_after_playing = True desc = _( "Trash this and another copy of Treasure map from your hand. If you do trash two Treasure maps, gain 4 Gold cards, putting them on top of your deck." ) def activate_action(self, game, player): treasure_map_cards = [ c for c in player.hand if isinstance(c, TreasureMap) ] if len( treasure_map_cards ) >= 1: # only need one other treasure map in hand, because the other has already been played card = treasure_map_cards[0] card.trash(game, player) for info_player in game.participants: yield InfoRequest(game, info_player, _("%s trashes:", (player.name, )), [card]) new_cards = [] for i in range(0, 4): if game.supply["Gold"]: new_cards.append(game.supply["Gold"].pop()) for val in game.check_empty_pile("Gold"): yield val player.deck.extend(new_cards) for info_player in game.participants: yield InfoRequest( game, info_player, _("%s gains on top of his deck:", (player.name, )), new_cards)
class Smugglers(ActionCard): name = _("Smugglers") edition = Seaside implemented = False cost = 3 desc = _( "Gain a copy of a Card costing up to 6 that the player to your right gained on his last turn." ) def activate_action(self, game, player): if len(player.right(game).cards_gained) > 1: card_classes = [ c for c in player.right(game).cards_gained if c.cost <= 6 and game.supply.get(c.__name__) ] card_cls = yield SelectCard( game, player, card_classes=card_classes, msg=_("Select a card that you want to have."), show_supply_count=True) else: card_cls = type(player.right(game).cards_gained[0]) new_card = game.supply[card_cls.__name__].pop() player.discard_pile.append(new_card) for info_player in game.following_participants(player): yield InfoRequest(game, info_player, _("%s gains:", (player.name, )), [new_card]) for val in game.check_empty_pile(card_cls.__name__): yield val
def boughtthis(self, game, player): cards = yield SelectHandCards( game, player, count_lower=0, count_upper=1, msg= _("Select a card you want to convert to a 2 Money more expensive Card." )) if cards: card = cards[0] card_classes = [ c for c in game.card_classes.itervalues() if c.cost == card.cost + 2 and game.supply.get(c.__name__) ] card_cls = yield SelectCard( game, player, card_classes=card_classes, msg=_("Select a treasure card that you want to have."), show_supply_count=True) card.trash(game, player) new_card = game.supply[card_cls.__name__].pop() player.hand.append(new_card) for info_player in game.following_participants(player): yield InfoRequest(game, info_player, _("%s trashes:", (player.name, )), [card]) yield InfoRequest(game, info_player, _("%s gains:", (player.name, )), [new_card]) for val in game.check_empty_pile(card_cls.__name__): yield val
def activate_action(self, game, player): player.virtual_money += 2 for other_player in game.following_players(player): try: handle_defense(self, game, other_player) except Defended: continue copper_cards = [ c for c in other_player.hand if isinstance(c, Copper) ] if copper_cards: cards = yield SelectHandCards( game, other_player, count_lower=1, count_upper=1, msg=_( "%s played Cutpurse. Which Copper do you want to discard?", (player.name, )), cls=Copper) for card in cards: card.discard(other_player) for info_player in game.following_participants( other_player): yield InfoRequest( game, info_player, _("%s discards these cards:", (other_player.name, )), cards) else: for info_player in game.following_participants(player): yield InfoRequest( game, info_player, _("%s reveals his hand:", (other_player.name, )), other_player.hand[:])
def activate_action(self, game, player): with fetch_card_from_supply(game, Silver) as new_card: player.discard_pile.append(new_card) for info_player in game.following_participants(player): yield InfoRequest(game, info_player, _("%s gains:", (player.name, )), [new_card]) player.draw_cards(1) drawn, player.hand = player.hand[-1:], player.hand[:-1] if (yield YesNoQuestion( game, player, _("Do you want to keep the card '%s' on your hand?", (drawn[0].name, )))): player.hand.extend(drawn) else: player.discard_pile.extend(drawn) while len(player.hand) < 5: if player.draw_cards(1) is None: break #FIXME only cards that are no treasure cards = yield SelectHandCards( game, player, count_lower=0, count_upper=1, not_selectable=[ c for c in player.hand if isinstance(c, TreasureCard) ], msg=_("Select a card you want to trash.")) if cards: card = cards[0] card.trash(game, player)
class GhostShip(AttackCard): name = _("Ghost Ship") edition = Seaside cost = 5 desc = _( "+2 Cards. Each other player with 4 or more cards in hand puts cards from his hand on top of his deck until he has 3 cards in his hand." ) def activate_action(self, game, player): player.draw_cards(2) for other_player in game.following_players(player): try: handle_defense(self, game, other_player) except Defended: continue if len(other_player.hand) < 4: continue count = len(other_player.hand) - 3 cards = yield SelectHandCards( game, other_player, count_lower=count, count_upper=count, msg=_( "%s played Ghost Ship. Which cards do you want to put on the top of your deck?", (player.name, ))) for card in cards: card.backondeck(game, other_player)
class Oasis(ActionCard): name = _("Oasis") edition = Hinterlands cost = 3 desc = _("+1 Card +1 Action +1 Money. Discard a card.") def activate_action(self, game, player): player.virtual_money += 1 player.draw_cards(1) player.remaining_actions += 1 cards = yield SelectHandCards( game, player, count_lower=1, count_upper=1, msg=_("Which cards do you want to discard?")) #FIXME make sure player has enough cards to do that # discard cards if cards is not None: for card in cards: card.discard(player) player.draw_cards(len(cards)) for info_player in game.participants: if info_player is not player: yield InfoRequest( game, info_player, _("%s discards these cards:", (player.name, )), cards)
class Explorer(ActionCard): name = _("Explorer") edition = Seaside cost = 5 desc = _( "You may reveal a Province card from your hand. If you do, gain a Gold card, putting it into your hand. Otherwise, gain a Silver card, putting it into your hand." ) def activate_action(self, game, player): province_cards = [c for c in player.hand if isinstance(c, Province)] if province_cards: if game.supply["Gold"]: new_card = game.supply["Gold"].pop() player.hand.append(new_card) for info_player in game.following_participants(player): yield InfoRequest(game, info_player, _("%s gains:", (player.name, )), [new_card]) for val in game.check_empty_pile("Gold"): yield val else: if game.supply["Silver"]: new_card = game.supply["Silver"].pop() player.hand.append(new_card) for info_player in game.following_participants(player): yield InfoRequest(game, info_player, _("%s gains:", (player.name, )), [new_card]) for val in game.check_empty_pile("Silver"): yield val
class Stables(ActionCard): name = _("Stables") edition = Hinterlands cost = 5 desc = _("You may discard a Treasure. If you do, +3 Cards and +1 Action.") def activate_action(self, game, player): cards = yield SelectHandCards( game, player, cls=TreasureCard, count_lower=0, count_upper=1, msg=_("Select a treasure card you want to discard.")) if cards is not None: for card in cards: card.discard(player) player.draw_cards(len(cards)) for info_player in game.participants: if info_player is not player: yield InfoRequest( game, info_player, _("%s discards these cards:", (player.name, )), cards) player.remaining_actions += 1 player.draw_cards(3)
class Island(ActionCard, VictoryCard): name = _("Island") edition = Seaside cost = 4 points = 2 desc = _("Set aside this and another card from your hand. Return them to" " your deck at the end of the game.") def activate_action(self, game, player): if not hasattr(player, "seaside_island_set_aside_cards"): player.seaside_island_set_aside_cards = [] island_cards = [c for c in player.aux_cards if isinstance(c, Island)] player.seaside_island_set_aside_cards.append(island_cards[0]) player.aux_cards.remove(island_cards[0]) if player.hand: cards = yield SelectHandCards( game, player, count_lower=1, count_upper=1, msg=_("Which card do you want to set aside?")) if cards: card = cards[0] player.hand.remove(card) player.seaside_island_set_aside_cards.append(card) @classmethod def on_end_of_game(cls, game): for player in game.players: if getattr(player, "seaside_island_set_aside_cards", None): player.hand.extend( getattr(player, "seaside_island_set_aside_cards", [])) player.seaside_island_set_aside_cards = []
def activate_action(self, game, player): cards = yield SelectHandCards( game, player, cls=TreasureCard, count_lower=0, count_upper=1, msg= _("Select a treasure card you want to convert to a potentially better card." )) if cards: card = cards[0] new_cards = [] for i in range(0, 4): if game.supply["Silver"]: new_cards.append(game.supply["Silver"].pop()) for val in game.check_empty_pile("Silver"): yield val card.trash(game, player) player.hand.append(new_card) for info_player in game.following_participants(player): yield InfoRequest(game, info_player, _("%s trashes:", (player.name, )), [card]) yield InfoRequest(game, info_player, _("%s gains:", (player.name, )), new_cards)
def activate_action(self, game, player): player.virtual_money += 2 for other_player in game.following_players(player): try: handle_defense(self, game, other_player) except Defended: continue if other_player.draw_cards(1) is None: continue card = other_player.hand.pop() for info_player in game.participants: yield InfoRequest(game, info_player, _("%s trashes:", (other_player.name, )), [card]) req = SelectCard( game, player, card_classes=[ c for c in game.card_classes.itervalues() if c.cost == card.cost and game.supply.get(c.__name__) ], msg=_("Select a card that you want to give."), show_supply_count=True) if not req.fulfillable(): continue card_cls = yield req new_card = game.supply[card_cls.__name__].pop() other_player.discard_pile.append(new_card) for info_player in game.following_participants(player): yield InfoRequest(game, info_player, _("%s gains:", (other_player.name, )), [new_card]) for val in game.check_empty_pile(card_cls.__name__): yield val