merge from Paul's branch again

This commit is contained in:
sumpfork@mailmight.com 2014-01-01 13:18:02 -08:00
commit 73544ed3c8
3 changed files with 251 additions and 107 deletions

View File

@ -1,6 +1,9 @@
:::Copper
60 cards per game.
:::Silver
40 cards per game.
:::Gold
30 cards per game.
:::Estate
Put 8 in the Supply in a game with two players.

View File

@ -23,6 +23,15 @@
23 Mine Dominion Action $5 Trash a Treasure card from your hand. Gain a Treasure card costing up to 3 Coins more; put it into your hand.
24 Witch Dominion Action - Attack $5 +2 Cards, Each other player gains a Curse card.
25 Adventurer Dominion Action $6 Reveal cards from your deck until you reveal 2 Treasure cards. Put those Treasure cards in your hand and discard the other revealed cards.
26 Copper Dominion Treasure $0 Worth 1 Coin.
27 Silver Dominion Treasure $3 Worth 2 Coins.
28 Gold Dominion Treasure $6 Worth 3 Coins.
29 Curse Dominion Curse $0 -1 <VP>
30 Estate Dominion Victory $2 1 <VP>
31 Duchy Dominion Victory $5 3 <VP>
32 Province Dominion Victory $8 6 <VP>
33 Trash Dominion Action $0 Pile of trash.
1 Courtyard Intrigue Action $2 +3 Card, Put a card from your hand on top of your deck.
2 Pawn Intrigue Action $2 Choose two: +1 Card, +1 Action, +1 Buy, +1 Coin. (The choices must be different.).
3 Secret Chamber Intrigue Action - Reaction $2 Discard any number of cards. +1 Coin per card discarded. - When another player plays an Attack card, you may reveal this from your hand. If you do, +2 cards, then put 2 cards from your hand on top of your deck.
@ -49,6 +58,15 @@
24 Harem Intrigue Treasure - Victory $6 Worth 2 Coins, 2 <VP>
25 Nobles Intrigue Action - Victory $6 2 <VP>
Choose one: +3 Cards, or +2 Actions.
26 Copper Intrigue Treasure $0 Worth 1 Coin.
27 Silver Intrigue Treasure $3 Worth 2 Coins.
28 Gold Intrigue Treasure $6 Worth 3 Coins.
29 Curse Intrigue Curse $0 -1 <VP>
30 Estate Intrigue Victory $2 1 <VP>
31 Duchy Intrigue Victory $5 3 <VP>
32 Province Intrigue Victory $8 6 <VP>
33 Trash Intrigue Action $0 Pile of trash.
1 Embargo Seaside Action $2 +2 Coins, Trash this card. Put an Embargo token on top of a Supply pile. - When a player buys a card, he gains a Curse card per Embargo token on that pile.
2 Haven Seaside Action - Duration $2 +1 Card, +1 Action, Set aside a card from your hand face down. At the start of your next turn, put it into your hand.
3 Lighthouse Seaside Action - Duration $2 +1 Action, Now and at the start of your next turn: +1 Coin. - While this is in play, when another player plays an Attack card, it doesn't affect you.
@ -76,6 +94,7 @@ At the start of your next turn, +1 Card.
24 Tactician Seaside Action - Duration $5 Discard your hand. If you discarded any cards this way, then at the start of your next turn, +5 Cards, +1 Buy, and +1 Action.
25 Treasury Seaside Action $5 +1 Card, +1 Action, +1 Coin, When you discard this from play, if you didn't buy a Victory card this turn, you may put this on top of your deck.
26 Wharf Seaside Action - Duration $5 Now and at the start of your next turn: +2 Cards, +1 Buy.
1 Transmute Alchemy Action $0 1P Trash a card from your hand. If it is an...
Action card, gain a Duchy
Treasure card, gain a Transmute
@ -179,6 +198,7 @@ When you play this, it`s worth 1 Coin per Treasure card you have in play (counti
During your Buy phase, this costs 2 Coins less per Action card you have in play, but not less than 0 Coins.
26 Platinum Prosperity Treasure $9 Worth 5 Coins.
27 Colony Prosperity Victory $11 10 <VP>.
1 Black Market Promo Action $3 +2 Coins, Reveal the top 3 cards of the Black Market deck. You may buy one of them immediately. Put the unbought cards on the bottom of the Black Market deck in any order.
(Before the game, make a Black Market deck out of one copy of each Kingdom card not in the supply.).
2 Envoy Promo Action $4 Reveal the top 5 cards of your deck. The player to your left chooses one for you to discard. Draw the rest.
@ -187,21 +207,20 @@ During your Buy phase, this costs 2 Coins less per Action card you have in play,
+2 Actions
At the start of Clean-up, if you have this and no more than one other Action card in play, you may put this on top of your deck.
5 Governor Promo Action $5 +1 Action
Choose one; you get the version in parentheses: Each player gets +1 (+3) Cards; or each player gains a Silver (Gold); or each player may trash a card from his hand and gain a card costing exactly 1 Coin (2 Coins) more.
1 Copper Base Treasure $0 Worth 1 Coin.
2 Curse Base Curse $0 -1 <VP>
3 Estate Base Victory $2 1 <VP>
4 Silver Base Treasure $3 Worth 2 Coins.
5 Duchy Base Victory $5 3 <VP>
6 Gold Base Treasure $6 Worth 3 Coins.
7 Province Base Victory $8 6 <VP>
8 Potion Base Treasure $4 Worth 1 Potion.
9 Platinum Base Treasure $9 Worth 5 Coins.
2 Silver Base Treasure $3 Worth 2 Coins.
3 Gold Base Treasure $6 Worth 3 Coins.
4 Platinum Base Treasure $9 Worth 5 Coins.
5 Potion Base Treasure $4 Worth 1 Potion.
6 Curse Base Curse $0 -1 <VP>
7 Estate Base Victory $2 1 <VP>
8 Duchy Base Victory $5 3 <VP>
9 Province Base Victory $8 6 <VP>
10 Colony Base Victory $11 10 <VP>
11 Trash Base Action $0 Pile of trash.
1 Bag of Gold Cornucopia Action - Prize $0 +1 Action
Gain a Gold, putting it on top of your deck.
(This is not in the Supply.)
@ -248,6 +267,7 @@ Reveal your hand. Reveal cards from your deck until you reveal a card that isn
17 Jester Cornucopia Action - Attack $5 +2 Coins
Each other player discards the top card of his deck. If its a Victory card he gains a Curse. Otherwise he gains a copy of the discarded card or you do, your choice.
18 Fairgrounds Cornucopia Victory $6 Worth 2 <VP> for every 5 differently named cards in your deck (rounded down)
1 Crossroads Hinterlands Action $2 Reveal your hand.
+1 Card per Victory card revealed. If this is the first time you played a Crossroads this turn, +3 Actions.
2 Duchess Hinterlands Action $2 +2 Coins
@ -328,6 +348,7 @@ When you gain this, gain a card costing less than this.
26 Farmland Hinterlands Victory $6 2 <VP>
----------
When you buy this, trash a card from your hand. Gain a card costing exactly 2 Coins more than the trashed card.
1 Ruins Dark Ages Action - Ruins $0 Abandoned Mine: +1 Coin
Ruined Library: +1 Card
Ruined Marked: :1 Buy
@ -460,7 +481,8 @@ If its the named card, put it into your hand.
Necropolis: +2 Actions
Overgrown Estate: 0 <VP>; when you trash this, +1 Card.
43 Urchin / Mercenary Dark Ages Extras Action $3 Urchin: When you play this, you draw a card and get +1 Action, then each other player discards down to 4 cards in hand. Players who already have 4 or fewer cards in hand do not do anything. While Urchin is in play, when you play another Attack card, before resolving it, you may trash the Urchin. If you do, you gain a Mercenary. If there are no Mercenaries left you do not gain one. If you play the same Urchin twice in one turn, such as via Procession, that does not let you trash it for a Mercenary. If you play two different Urchins however, playing the second one will let you trash the first one.
44 Hermit / Madman Dark Ages Action $3 Hermit: When you play this, look through your discard pile, and then you may choose to trash a card that is not a Treasure, from either your hand or your discard pile. You do not have to trash a card and cannot trash Treasures. A card with multiple types, one of which is Treasure (such as Harem from Intrigue), is a Treasure. After trashing or not, you gain a card costing up to 3 Coins. The card you gain comes from the Supply and is put into your discard pile. Gaining a card is mandatory if it is possible. Then, when you discard Hermit from play - normally, in Clean-up, after playing it in your Action phase - if you did not buy any cards this turn, you trash Hermit and gain a Madman. It does not matter whether or not you gained cards other ways, only whether or not you bought a card. If there are no Madman cards left, you do not gain one. If Hermit is not discarded from play during Clean-up - for example, if you put it on your deck with Scheme (from Hinterlands) - then the ability that trashes it will not trigger.
44 Hermit / Madman Dark Ages Extras Action $3 Hermit: When you play this, look through your discard pile, and then you may choose to trash a card that is not a Treasure, from either your hand or your discard pile. You do not have to trash a card and cannot trash Treasures. A card with multiple types, one of which is Treasure (such as Harem from Intrigue), is a Treasure. After trashing or not, you gain a card costing up to 3 Coins. The card you gain comes from the Supply and is put into your discard pile. Gaining a card is mandatory if it is possible. Then, when you discard Hermit from play - normally, in Clean-up, after playing it in your Action phase - if you did not buy any cards this turn, you trash Hermit and gain a Madman. It does not matter whether or not you gained cards other ways, only whether or not you bought a card. If there are no Madman cards left, you do not gain one. If Hermit is not discarded from play during Clean-up - for example, if you put it on your deck with Scheme (from Hinterlands) - then the ability that trashes it will not trigger.
1 Advisor Guilds Action $4 +1 Action
Reveal the top 3 cards of your deck. The player to your left chooses one of them. Discard that card. Put the other cards into your hand.
2 Baker Guilds Action $5 +1 Card

View File

@ -1,3 +1,4 @@
#!python
import re
from optparse import OptionParser
import os.path
@ -9,6 +10,7 @@ from reportlab.platypus import Paragraph
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfbase import pdfmetrics
from reportlab.lib.enums import TA_JUSTIFY
def split(l,n):
i = 0
@ -36,6 +38,20 @@ class Card:
def toString(self):
return self.name + ' ' + self.cardset + ' ' + '-'.join(self.types) + ' ' + `self.cost` + ' ' + self.description + ' ' + self.extra
def isExpansion(self):
return self.getType().getTypeNames() == ('Expansion',)
def setImage(self):
setImage = DominionTabs.setImages.get(self.cardset, None)
if not setImage:
setImage = DominionTabs.promoImages.get(self.name.lower(), None)
if setImage == None and self.cardset != 'base' and not self.isExpansion():
print 'warning, no set image for set "%s" card "%s"' % (self.cardset, self.name)
DominionTabs.setImages[self.cardset] = 0
DominionTabs.promoImages[self.name.lower()] = 0
return setImage
class CardType:
def __init__(self, typeNames, tabImageFile, tabTextHeightOffset=0, tabCostHeightOffset=-1):
self.typeNames = typeNames
@ -183,6 +199,31 @@ class DominionTabs:
self.canvas.restoreState()
def drawCost(self, card, x, y, costOffset=-1):
# base width is 16 (for image) + 2 (1 pt border on each side)
width = 18
costHeight = y + costOffset
coinHeight = costHeight - 5
potHeight = y - 3
potSize = 11
self.canvas.drawImage(os.path.join(self.filedir,'images','coin_small.png'),x,coinHeight,16,16,preserveAspectRatio=True,mask='auto')
if card.potcost:
self.canvas.drawImage(os.path.join(self.filedir,'images','potion.png'),x+17,potHeight,potSize,potSize,preserveAspectRatio=True,mask=[255,255,255,255,255,255])
width += potSize
self.canvas.setFont('MinionPro-Bold',12)
cost = str(card.cost)
if 'Prize' in card.types:
cost += '*'
self.canvas.drawCentredString(x+8,costHeight,cost)
return width
def drawSetIcon(self, setImage, x, y):
# set image
self.canvas.drawImage(os.path.join(self.filedir,'images',setImage), x, y, 14, 12, mask='auto')
@classmethod
def nameWidth(self, name, fontSize):
w = 0
@ -197,8 +238,7 @@ class DominionTabs:
def drawTab(self, card, rightSide):
#draw tab flap
self.canvas.saveState()
isExpansionIntro = card.getType().getTypeNames() == ('Expansion',)
if isExpansionIntro:
if card.isExpansion():
self.canvas.translate(self.tabWidth/2-self.tabLabelWidth/2,
self.tabHeight-self.tabLabelHeight)
elif not rightSide:
@ -210,51 +250,35 @@ class DominionTabs:
textWidth = self.tabLabelWidth - 6 # allow for 3 pt border on each side
textHeight = self.tabLabelHeight/2-7+card.getType().getTabTextHeightOffset()
# draw banner
self.canvas.drawImage(os.path.join(self.filedir,'images',card.getType().getNoCoinTabImageFile()),1,0,
self.tabLabelWidth-2,self.tabLabelHeight-1,
preserveAspectRatio=False,anchor='n',mask='auto')
if not isExpansionIntro:
textInset = 22
costHeight = textHeight + card.getType().getTabCostHeightOffset()
potHeight = 3 + card.getType().getTabTextHeightOffset()
potSize = 11
self.canvas.drawImage(os.path.join(self.filedir,'images','coin_small.png'),4,costHeight-5,16,16,preserveAspectRatio=True,mask='auto')
if card.potcost:
self.canvas.drawImage(os.path.join(self.filedir,'images','potion.png'),21,potHeight,potSize,potSize,preserveAspectRatio=True,mask=[255,255,255,255,255,255])
textInset += potSize
setImageHeight = potHeight
self.canvas.setFont('MinionPro-Bold',12)
cost = str(card.cost)
if 'Prize' in card.types:
cost += '*'
costWidthOffset = 12
self.canvas.drawCentredString(costWidthOffset,costHeight,cost)
# draw cost
if not card.isExpansion():
if 'tab' in self.options.cost:
textInset = 4
textInset += self.drawCost(card, textInset, textHeight,
card.getType().getTabCostHeightOffset())
else:
textInset = 6
else:
textInset = 13
# draw set image
setImage = card.setImage()
if setImage and 'tab' in self.options.set_icon:
setImageHeight = 3 + card.getType().getTabTextHeightOffset()
#set image
setImage = DominionTabs.setImages.get(card.cardset, None)
if not setImage:
setImage = DominionTabs.promoImages.get(card.name.lower(), None)
self.drawSetIcon(setImage, self.tabLabelWidth-20,
setImageHeight)
textInsetRight = 20
else:
# always need to offset from right edge, to make sure it stays on
# banner
textInsetRight = 6
if setImage:
self.canvas.drawImage(os.path.join(self.filedir,'images',setImage), self.tabLabelWidth-20, setImageHeight, 14, 12, mask='auto')
textInsetRight = 20
elif setImage == None and card.cardset != 'base' and card.getType().getTypeNames() != ('Expansion',):
print 'warning, no set image for set "%s" card "%s"' % (card.cardset, card.name)
DominionTabs.setImages[card.cardset] = 0
DominionTabs.promoImages[card.name.lower()] = 0
# draw name
fontSize = 12
name = card.name.upper()
@ -263,7 +287,7 @@ class DominionTabs:
width = self.nameWidth(name, fontSize)
while width > textWidth and fontSize > 8:
fontSize -= 1
fontSize -= .01
#print 'decreasing font size for tab of',name,'now',fontSize
width = self.nameWidth(name, fontSize)
tooLong = width > textWidth
@ -286,15 +310,17 @@ class DominionTabs:
else:
h -= h/2
words = line.split()
if rightSide or not self.options.edge_align_name:
w = textInset
name_parts = line.split()
def drawWordPiece(text, fontSize):
self.canvas.setFont('MinionPro-Regular',fontSize)
if text != ' ':
self.canvas.drawString(w,h,text)
return pdfmetrics.stringWidth(text,'MinionPro-Regular',fontSize)
for word in name_parts:
for i, word in enumerate(words):
if i != 0:
w += drawWordPiece(' ', fontSize)
w += drawWordPiece(word[0], fontSize)
w += drawWordPiece(word[1:], fontSize-2)
else:
@ -303,43 +329,76 @@ class DominionTabs:
# space between text + set symbol
w = self.tabLabelWidth - textInsetRight - 3
name_parts = reversed(line.split())
words.reverse()
def drawWordPiece(text, fontSize):
self.canvas.setFont('MinionPro-Regular',fontSize)
if text != ' ':
self.canvas.drawRightString(w,h,text)
return -pdfmetrics.stringWidth(text,'MinionPro-Regular',fontSize)
for word in name_parts:
for i, word in enumerate(words):
w += drawWordPiece(word[1:], fontSize-2)
w += drawWordPiece(word[0], fontSize)
if i != len(words) - 1:
w += drawWordPiece(' ', fontSize)
self.canvas.restoreState()
def drawText(self, card, useExtra=False):
usedHeight = 0
totalHeight = self.tabHeight - self.tabLabelHeight
drewTopIcon = False
if 'body-top' in self.options.cost and not card.isExpansion():
self.drawCost(card, cm/4.0, totalHeight - 0.5*cm)
drewTopIcon = True
if 'body-top' in self.options.set_icon and not card.isExpansion():
setImage = card.setImage()
if setImage:
self.drawSetIcon(setImage, self.tabWidth-16,
totalHeight-0.5*cm-3)
drewTopIcon = True
if drewTopIcon:
usedHeight += 15
#draw text
if useExtra and card.extra:
descriptions = (card.extra,)
else:
descriptions = re.split("\n",card.description)
height = 0
for d in descriptions:
s = getSampleStyleSheet()['BodyText']
s.fontName = "Times-Roman"
s.alignment = TA_JUSTIFY
textHorizontalMargin = .5*cm
textVerticalMargin = .3*cm
textBoxWidth = self.tabWidth - 2*textHorizontalMargin
textBoxHeight = totalHeight - usedHeight - 2*textVerticalMargin
spacerHeight = 0.2*cm
minSpacerHeight = 0.05*cm
while True:
paragraphs = []
# this accounts for the spacers we insert between paragraphs
h = (len(descriptions) - 1) * spacerHeight
for d in descriptions:
dmod = self.add_inline_images(d,s.fontSize)
p = Paragraph(dmod,s)
textHeight = self.tabHeight - self.tabLabelHeight + 0.2*cm
textWidth = self.tabWidth - cm
h += p.wrap(textBoxWidth, textBoxHeight)[1]
paragraphs.append(p)
w,h = p.wrap(textWidth,textHeight)
while h > textHeight:
if h <= textBoxHeight or s.fontSize <= 1 or s.leading <= 1:
break
else:
s.fontSize -= 1
s.leading -= 1
#print 'decreasing fontsize on description for',card.name,'now',s.fontSize
dmod = self.add_inline_images(d,s.fontSize)
p = Paragraph(dmod,s)
w,h = p.wrap(textWidth,textHeight)
p.drawOn(self.canvas,cm/2.0,textHeight-height-h-0.5*cm)
height += h + 0.2*cm
spacerHeight = max(spacerHeight - 1, minSpacerHeight)
h = totalHeight - usedHeight - textVerticalMargin
for p in paragraphs:
h -= p.height
p.drawOn(self.canvas, textHorizontalMargin, h)
h -= spacerHeight
def drawDivider(self,card,x,y,useExtra=False):
#figure out whether the tab should go on the right side or not
@ -534,10 +593,14 @@ class DominionTabs:
self.canvas.restoreState()
self.canvas.showPage()
@staticmethod
def parse_opts(argstring):
LOCATION_CHOICES = ["tab", "body-top", "hide"]
@classmethod
def parse_opts(cls, argstring):
parser = OptionParser()
parser.add_option("--back_offset",type="int",dest="back_offset",default=0,
parser.add_option("--back_offset",type="float",dest="back_offset",default=0,
help="Points to offset the back page to the right; needed for some printers")
parser.add_option("--orientation",type="choice",choices=["horizontal","vertical"],dest="orientation",default="horizontal",
help="horizontal or vertical, default:horizontal")
@ -554,11 +617,25 @@ class DominionTabs:
help="force all label tabs to be on the same side"
" (this will be forced on if there is an uneven"
" number of cards horizontally across the page)")
parser.add_option("--edge-align-name",action="store_true",
parser.add_option("--edge_align_name",action="store_true",
help="align the card name to the outside edge of the"
" tab, so that when using tabs on alternating sides,"
" the name is less likely to be hidden by the tab"
" in front; ignored if samesidelabels is on")
parser.add_option("--cost",action="append",type="choice",
choices=cls.LOCATION_CHOICES, default=[],
help="where to display the card cost; may be set to"
" 'hide' to indicate it should not be displayed, or"
" given multiple times to show it in multiple"
" places; valid values are: %s; defaults to 'tab'"
% ", ".join("'%s'" % x for x in cls.LOCATION_CHOICES))
parser.add_option("--set_icon",action="append",type="choice",
choices=cls.LOCATION_CHOICES, default=[],
help="where to display the set icon; may be set to"
" 'hide' to indicate it should not be displayed, or"
" given multiple times to show it in multiple"
" places; valid values are: %s; defaults to 'tab'"
% ", ".join("'%s'" % x for x in cls.LOCATION_CHOICES))
parser.add_option("--expansions",action="append",type="string",
help="subset of dominion expansions to produce tabs for")
parser.add_option("--cropmarks",action="store_true",dest="cropmarks",
@ -575,8 +652,17 @@ class DominionTabs:
help="sort order for the cards, whether by expansion or globally alphabetical")
parser.add_option("--expansion_dividers", action="store_true", dest="expansion_dividers",
help="add dividers describing each expansion set")
parser.add_option("--base_cards_with_expansion", action="store_true",
help='print the base cards as part of the expansion; ie, a divider for "Silver"'
'will be printed as both a "Dominion" card and as an "Intrigue" card; if this'
'option is not given, all base cards are placed in their own "Base" expansion')
return parser.parse_args(argstring)
options, args = parser.parse_args(argstring)
if not options.cost:
options.cost = ['tab']
if not options.set_icon:
options.set_icon = ['tab']
return options, args
def main(self,argstring):
options,args = DominionTabs.parse_opts(argstring)
@ -726,13 +812,35 @@ class DominionTabs:
cards = self.read_card_defs(os.path.join(self.filedir,"dominion_cards.txt"))
self.read_card_extras(os.path.join(self.filedir,"dominion_card_extras.txt"),cards)
baseCards = [card.name for card in cards if card.cardset.lower() == 'base']
def isBaseExpansionCard(card):
return card.cardset.lower() != 'base' and card.name in baseCards
if self.options.base_cards_with_expansion:
cards = [card for card in cards if card.cardset.lower() != 'base']
else:
cards = [card for card in cards if not isBaseExpansionCard(card)]
if self.options.expansions:
self.options.expansions = [o.lower() for o in self.options.expansions]
cards=[c for c in cards if c.cardset in self.options.expansions]
filteredCards = []
knownExpansions = set()
for c in cards:
knownExpansions.add(c.cardset)
if c.cardset in self.options.expansions:
filteredCards.append(c)
unknownExpansions = set(self.options.expansions) - knownExpansions
if unknownExpansions:
print "Error - unknown expansion(s): %s" % ", ".join(unknownExpansions)
return
cards = filteredCards
if options.expansion_dividers:
cardnamesByExpansion = {}
for c in cards:
if isBaseExpansionCard(c):
continue
cardnamesByExpansion.setdefault(c.cardset,[]).append(c.name.strip())
for exp,names in cardnamesByExpansion.iteritems():
c = Card(exp, exp, ("Expansion",), None, ' | '.join(sorted(names)))
@ -743,10 +851,21 @@ class DominionTabs:
out = yaml.dump(cards)
open('cards.yaml','w').write(out)
# When sorting cards, want to always put "base" cards after all
# kingdom cards, and order the base cards in a set order - the
# order they are listed in the database (ie, all normal treasures
# by worth, then potion, then all normal VP cards by worth, then
# trash)
def baseIndex(name):
try:
return baseCards.index(name)
except Exception:
return -1
if options.order == "global":
sortKey = lambda x: x.name
sortKey = lambda x: (int(x.isExpansion()), baseIndex(x.name),x.name)
else:
sortKey = lambda x: (x.cardset,x.name)
sortKey = lambda x: (x.cardset,int(x.isExpansion()),baseIndex(x.name),x.name)
cards.sort(key=sortKey)
if not f: