1
0
Fork 0
mirror of https://github.com/shlomif/PySolFC.git synced 2025-04-05 00:02:29 -04:00

Version 7 of the cardset format with subtype and joker support. (#330)

This commit is contained in:
Joe R 2023-08-11 20:30:29 -04:00 committed by GitHub
parent 9237c30df4
commit 13a29b34ea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 187 additions and 79 deletions

View file

@ -8,7 +8,7 @@ config.txt template
------------------- -------------------
.... ....
PySolFC solitaire cardset;$A;$FMT;$B;$C;$D,$E;$F PySolFC solitaire cardset;$A;$FMT;$B;$C;$D,$E;$F;$G;$H
<internal_name>;<cardset_name> <internal_name>;<cardset_name>
X Y D X Y D
XOFF YOFF SXOFF SYOFF XOFF YOFF SXOFF SYOFF
@ -21,7 +21,7 @@ Line 1
*$A:* The cardset version number that belongs to the number of fields divided through ";" on the first line (e.g. `.gif;1;78;8,1016` -> `$A=4`) *$A:* The cardset version number that belongs to the number of fields divided through ";" on the first line (e.g. `.gif;1;78;8,1016` -> `$A=4`)
( *WARNING:* For Mahjongg, $A must always be 6 and the $F field must be included in the line; however, you can put `0` in `$F` if you wish, in that case. ) ( *WARNING:* For Mahjongg, $A must always be 6 or 7 and the $F field must be included in the line; however, you can put `0` in `$F` if you wish, in that case. )
( *NOTE:* $D and $E are comma separated and count for one field ) ( *NOTE:* $D and $E are comma separated and count for one field )
@ -112,6 +112,9 @@ Cardsets Origins:
*$F:* The Year the cardset was created (in the range 1000 to 2299) *$F:* The Year the cardset was created (in the range 1000 to 2299)
*$G:* The subtype of the cardset. Usually 0 - for French type cardsets, a value of 1 is used if there are jokers.
*$H:* Whether the cardset is a 3D Mahjongg cardset - 1 if it is, 0 if it isn't. For cardsets with a version less than 7, version 6 cardsets treat this value as 1, and older version cardsets treat it as 0.
Line 2 Line 2
------ ------

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 363 B

View file

@ -1,6 +1,6 @@
<h1>Cardset Customization Tutorial</h1> <h1>Cardset Customization Tutorial</h1>
<h2>config.txt template</h2> <h2>config.txt template</h2>
<pre>PySolFC solitaire cardset;$A;$FMT;$B;$C;$D,$E;$F <pre>PySolFC solitaire cardset;$A;$FMT;$B;$C;$D,$E;$F;$G;$H
&lt;internal_name&gt;;&lt;cardset_name&gt; &lt;internal_name&gt;;&lt;cardset_name&gt;
X Y D X Y D
XOFF YOFF SXOFF SYOFF XOFF YOFF SXOFF SYOFF
@ -9,7 +9,7 @@ back01.ext;back02.ext;back03.ext</pre>
<h2>Line 1</h2> <h2>Line 1</h2>
<p><b>$A:</b> The cardset version number that belongs to the number <p><b>$A:</b> The cardset version number that belongs to the number
of fields divided through ";" on the first line (e.g. <code>.gif;1;78;8,1016</code> &#8594; <code>$A=4</code>)</p> of fields divided through ";" on the first line (e.g. <code>.gif;1;78;8,1016</code> &#8594; <code>$A=4</code>)</p>
<p>(<b>WARNING:</b> For Mahjongg, $A must always be 6 and the $F <p>(<b>WARNING:</b> For Mahjongg, $A must always be 6 or 7 and the $F
field must be included in the line; however, you can put <code>0</code> in <code>$F</code> if you wish, in that case.)</p> field must be included in the line; however, you can put <code>0</code> in <code>$F</code> if you wish, in that case.)</p>
<p>(<b>NOTE:</b> $D and $E are comma separated and count for one <p>(<b>NOTE:</b> $D and $E are comma separated and count for one
field)</p> field)</p>
@ -220,6 +220,11 @@ back01.ext;back02.ext;back03.ext</pre>
</ul> </ul>
<p><b>$F:</b> The Year the cardset was created (in the range 1000 <p><b>$F:</b> The Year the cardset was created (in the range 1000
to 2299)</p> to 2299)</p>
<p><b>$G:</b> The subtype of the cardset. Usually 0 - for French type
cardsets, a value of 1 is used if there are jokers.</p>
<p><b>$H:</b> Whether the cardset is a 3D Mahjongg cardset - 1 if it is, 0
if it isn't. For cardsets with a version less than 7, version 6 cardsets
treat this value as 1, and older version cardsets treat it as 0.</p>
<h2>Line 2</h2> <h2>Line 2</h2>
<p><code>&lt;internal_name&gt;</code>: A name for PySolFC to identify your <p><code>&lt;internal_name&gt;</code>: A name for PySolFC to identify your
cardset (without spaces)</p> cardset (without spaces)</p>

View file

@ -143,8 +143,7 @@ all the cards in the foundation pile(s).</p>
<dd> <dd>
<p>A deck of cards consisting of a STANDARD DECK and two jokers <p>A deck of cards consisting of a STANDARD DECK and two jokers
making a total of 54 cards. Currently, joker decks are not making a total of 54 cards.</p>
used in PySol.</p>
</dd> </dd>
<dt><b>OPEN</b></dt> <dt><b>OPEN</b></dt>

View file

@ -0,0 +1,14 @@
<h1>Thieves</h1>
<p>
Golf type. 1 joker deck. No redeal.
<h3>Object</h3>
<p>
Move all cards to the waste stack.
<h3>Quick Description</h3>
<p>
Like <a href="golf.html">Golf</a>,
but with two jokers. Jokers are wild, any card
can be played on a joker, and a joker can be played
on any card.

View file

@ -652,22 +652,25 @@ class Application:
self.images.setNegative(self.opt.negative_bottom) self.images.setNegative(self.opt.negative_bottom)
self.subsampled_images.setNegative(self.opt.negative_bottom) self.subsampled_images.setNegative(self.opt.negative_bottom)
if update & 1: if update & 1:
self.opt.cardset[0] = (cs.name, cs.backname) self.opt.cardset[0][0] = (cs.name, cs.backname)
if update & 2: if update & 2:
self.opt.cardset[cs.si.type] = (cs.name, cs.backname) self.opt.cardset[cs.si.type][cs.si.subtype] = (cs.name,
cs.backname)
gi = self.getGameInfo(id) gi = self.getGameInfo(id)
if gi: if gi:
if update & 256: if update & 256:
try: try:
del self.opt.cardset[(1, gi.id)] del self.opt.cardset[(1, gi.id)][gi.subcategory]
except KeyError: except KeyError:
pass pass
t = self.checkCompatibleCardsetType(gi, cs) t = self.checkCompatibleCardsetType(gi, cs)
if not t[1]: if not t[1]:
if update & 4: if update & 4:
self.opt.cardset[gi.category] = (cs.name, cs.backname) self.opt.cardset[gi.category][gi.subcategory] = \
(cs.name, cs.backname)
if update & 8: if update & 8:
self.opt.cardset[(1, gi.id)] = (cs.name, cs.backname) self.opt.cardset[(1, gi.id)][gi.subcategory] = \
(cs.name, cs.backname)
# from pprint import pprint; pprint(self.opt.cardset) # from pprint import pprint; pprint(self.opt.cardset)
def loadCardset(self, cs, id=0, update=7, progress=None, def loadCardset(self, cs, id=0, update=7, progress=None,
@ -685,14 +688,16 @@ class Application:
# key: Cardset.type # key: Cardset.type
# value: (Cardset.ident, Images, SubsampledImages) # value: (Cardset.ident, Images, SubsampledImages)
c = self.cardsets_cache.get(cs.type) c = self.cardsets_cache.get(cs.type)
if c and c[0] == cs.ident: if c:
# print 'load from cache', c c2 = c.get(cs.subtype)
self.images, self.subsampled_images = c[1], c[2] if c2 and c2[0] == cs.ident:
if not tocache: # print 'load from cache', c
self.updateCardset(id, update=update) self.images, self.subsampled_images = c2[1], c2[2]
if self.menubar is not None: if not tocache:
self.menubar.updateBackgroundImagesMenu() self.updateCardset(id, update=update)
return 1 if self.menubar is not None:
self.menubar.updateBackgroundImagesMenu()
return 1
# #
if progress is None and not noprogress: if progress is None and not noprogress:
self.wm_save_state() self.wm_save_state()
@ -718,9 +723,13 @@ class Application:
# if self.opt.save_cardsets: # if self.opt.save_cardsets:
c = self.cardsets_cache.get(cs.type) c = self.cardsets_cache.get(cs.type)
if c: if c:
# c[1].destruct() c2 = c.get(cs.subtype)
destruct(c[1]) if c2:
self.cardsets_cache[cs.type] = (cs.ident, images, simages) # c2[1].destruct()
destruct(c2[1])
self.cardsets_cache[cs.type] = {}
self.cardsets_cache[cs.type][cs.subtype] = (cs.ident, images,
simages)
if not tocache: if not tocache:
# elif self.images is not None: # elif self.images is not None:
# # self.images.destruct() # # self.images.destruct()
@ -757,7 +766,9 @@ class Application:
assert gi is not None assert gi is not None
assert cs is not None assert cs is not None
gc = gi.category gc = gi.category
gs = gi.subcategory
cs_type = cs.si.type cs_type = cs.si.type
cs_subtype = cs.si.subtype
t0, t1 = None, None t0, t1 = None, None
if gc == GI.GC_FRENCH: if gc == GI.GC_FRENCH:
t0 = "French" t0 = "French"
@ -765,6 +776,9 @@ class Application:
# CSI.TYPE_TAROCK, # CSI.TYPE_TAROCK,
): ):
t1 = t0 t1 = t0
if (cs_subtype == CSI.SUBTYPE_NONE
and gs == CSI.SUBTYPE_JOKER_DECK):
t1 = t0
elif gc == GI.GC_HANAFUDA: elif gc == GI.GC_HANAFUDA:
t0 = "Hanafuda" t0 = "Hanafuda"
if cs_type not in (CSI.TYPE_HANAFUDA,): if cs_type not in (CSI.TYPE_HANAFUDA,):
@ -823,14 +837,17 @@ class Application:
# try by gameid / category # try by gameid / category
for key, flag in (((1, gi.id), 8), (gi.category, 4)): for key, flag in (((1, gi.id), 8), (gi.category, 4)):
c = self.opt.cardset.get(key) c = self.opt.cardset.get(key)
if not c or len(c) != 2: c2 = None
if c:
c2 = c.get(gi.subcategory)
if not c2 or len(c2) != 2:
continue continue
cs = self.cardset_manager.getByName(c[0]) cs = self.cardset_manager.getByName(c2[0])
if not cs: if not cs:
continue continue
t = self.checkCompatibleCardsetType(gi, cs) t = self.checkCompatibleCardsetType(gi, cs)
if not t[1]: if not t[1]:
cs.updateCardback(backname=c[1]) cs.updateCardback(backname=c2[1])
return cs, flag, t return cs, flag, t
# ask # ask
return None, 0, t return None, 0, t

View file

@ -100,6 +100,20 @@ def parse_cardset_config(lines_list):
except ValueError: except ValueError:
_perr(1, 6, 'not integer') _perr(1, 6, 'not integer')
return None return None
if cs.version >= 7:
if len(fields) < 9:
_perr(1, msg='not enough fields')
return None
try:
cs.subtype = int(fields[7])
except ValueError:
_perr(1, 7, 'not integer')
return None
try:
cs.mahjongg3d = bool(fields[8])
except ValueError:
_perr(1, 8, 'not boolean')
return None
if len(cs.ext) < 2 or cs.ext[0] != ".": if len(cs.ext) < 2 or cs.ext[0] != ".":
_perr(1, msg='specifies an invalid file extension') _perr(1, msg='specifies an invalid file extension')
return None return None

View file

@ -59,6 +59,10 @@ class GI:
NUM_CATEGORIES = CSI.TYPE_MATCHING NUM_CATEGORIES = CSI.TYPE_MATCHING
# game subcategory
GS_NONE = CSI.SUBTYPE_NONE
GS_JOKER_DECK = CSI.SUBTYPE_JOKER_DECK
# game type # game type
GT_1DECK_TYPE = 0 GT_1DECK_TYPE = 0
GT_2DECK_TYPE = 1 GT_2DECK_TYPE = 1
@ -341,7 +345,7 @@ class GI:
# Gnome AisleRiot 2.2.0 (we have 65 out of 70 games) # Gnome AisleRiot 2.2.0 (we have 65 out of 70 games)
# Gnome AisleRiot 3.22.7 # Gnome AisleRiot 3.22.7
# still missing: # still missing:
# Hamilton, Labyrinth, Thieves, Treize, Valentine, Wall # Hamilton, Labyrinth, Treize, Valentine, Wall
("Gnome AisleRiot", ( ("Gnome AisleRiot", (
1, 2, 8, 9, 11, 12, 13, 19, 24, 27, 29, 31, 33, 34, 35, 36, 1, 2, 8, 9, 11, 12, 13, 19, 24, 27, 29, 31, 33, 34, 35, 36,
38, 40, 41, 42, 43, 45, 48, 58, 65, 67, 89, 91, 92, 93, 94, 38, 40, 41, 42, 43, 45, 48, 58, 65, 67, 89, 91, 92, 93, 94,
@ -349,7 +353,7 @@ class GI:
146, 147, 148, 200, 201, 206, 224, 225, 229, 230, 233, 257, 146, 147, 148, 200, 201, 206, 224, 225, 229, 230, 233, 257,
258, 277, 280, 281, 282, 283, 284, 334, 384, 479, 495, 551, 258, 277, 280, 281, 282, 283, 284, 334, 384, 479, 495, 551,
552, 553, 572, 593, 674, 700, 715, 716, 737, 772, 810, 819, 552, 553, 572, 593, 674, 700, 715, 716, 737, 772, 810, 819,
824, 829, 859, 874, 22231, 824, 829, 859, 874, 906, 22231,
)), )),
# Hoyle Card Games # Hoyle Card Games
@ -560,7 +564,8 @@ class GI:
('fc-2.15', tuple(range(827, 855)) + tuple(range(22400, 22407))), ('fc-2.15', tuple(range(827, 855)) + tuple(range(22400, 22407))),
('fc-2.20', tuple(range(855, 897))), ('fc-2.20', tuple(range(855, 897))),
('fc-2.21', tuple(range(897, 900)) + tuple(range(11014, 11017)) + ('fc-2.21', tuple(range(897, 900)) + tuple(range(11014, 11017)) +
tuple(range(13160, 13163)) + (16682,)) tuple(range(13160, 13163)) + (16682,)),
('dev', tuple(range(906, 907))),
) )
# deprecated - the correct way is to or a GI.GT_XXX flag # deprecated - the correct way is to or a GI.GT_XXX flag
@ -608,7 +613,7 @@ class GameInfo(Struct):
game_type, decks, redeals, game_type, decks, redeals,
skill_level=None, skill_level=None,
# keyword arguments: # keyword arguments:
si={}, category=0, si={}, category=0, subcategory=GI.GS_NONE,
short_name=None, altnames=(), short_name=None, altnames=(),
suits=list(range(4)), ranks=list(range(13)), trumps=(), suits=list(range(4)), ranks=list(range(13)), trumps=(),
rules_filename=None, rules_filename=None,
@ -692,7 +697,8 @@ class GameInfo(Struct):
name=name, short_name=short_name, name=name, short_name=short_name,
altnames=tuple(altnames), en_name=en_name, altnames=tuple(altnames), en_name=en_name,
decks=decks, redeals=redeals, ncards=ncards, decks=decks, redeals=redeals, ncards=ncards,
category=category, skill_level=skill_level, category=category, subcategory=subcategory,
skill_level=skill_level,
suits=tuple(suits), ranks=tuple(ranks), suits=tuple(suits), ranks=tuple(ranks),
trumps=tuple(trumps), trumps=tuple(trumps),
si=gi_si, rules_filename=rules_filename) si=gi_si, rules_filename=rules_filename)

View file

@ -107,6 +107,9 @@ class Golf_Waste(WasteStack):
return True return True
if not WasteStack.acceptsCards(self, from_stack, cards): if not WasteStack.acceptsCards(self, from_stack, cards):
return False return False
# if there are jokers, they're wild
if self.cards[-1].suit == 4 or cards[0].suit == 4:
return True
# check cards # check cards
r1, r2 = self.cards[-1].rank, cards[0].rank r1, r2 = self.cards[-1].rank, cards[0].rank
if self.game.getStrictness() == 1: if self.game.getStrictness() == 1:
@ -217,6 +220,14 @@ class DoubleGolf(Golf):
Golf.startGame(self, 7) Golf.startGame(self, 7)
# ************************************************************************
# * Thieves
# ************************************************************************
class Thieves(Golf):
pass
# ************************************************************************ # ************************************************************************
# * # *
# ************************************************************************ # ************************************************************************
@ -1491,3 +1502,6 @@ registerGame(GameInfo(891, AllInARowII, "All in a Row II",
GI.GT_GOLF | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL)) GI.GT_GOLF | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL))
registerGame(GameInfo(892, DoublePutt, "Double Putt", registerGame(GameInfo(892, DoublePutt, "Double Putt",
GI.GT_GOLF, 2, 0, GI.SL_BALANCED)) GI.GT_GOLF, 2, 0, GI.SL_BALANCED))
registerGame(GameInfo(906, Thieves, "Thieves",
GI.GT_GOLF, 1, 0, GI.SL_BALANCED,
subcategory=GI.GS_JOKER_DECK, trumps=list(range(2))))

View file

@ -383,7 +383,7 @@ class AbstractMahjonggGame(Game):
# dx, dy = 2, -2 # dx, dy = 2, -2
# dx, dy = 3, -3 # dx, dy = 3, -3
cs = self.app.images.cs cs = self.app.images.cs
if cs.version >= 6: if cs.version == 6 or cs.mahjongg3d:
dx = l.XOFFSET dx = l.XOFFSET
dy = -l.YOFFSET dy = -l.YOFFSET
d_x = cs.SHADOW_XOFFSET d_x = cs.SHADOW_XOFFSET

View file

@ -256,7 +256,7 @@ class Shisen_RowStack(Mahjongg_RowStack):
x0, y0 = (game.XMARGIN + game.center_offset[0], x0, y0 = (game.XMARGIN + game.center_offset[0],
game.YMARGIN + game.center_offset[1]) game.YMARGIN + game.center_offset[1])
cardw, cardh = images.CARDW, images.CARDH cardw, cardh = images.CARDW, images.CARDH
if cs.version >= 6: if cs.version == 6 or cs.mahjongg3d:
cardw -= cs.SHADOW_XOFFSET cardw -= cs.SHADOW_XOFFSET
cardh -= cs.SHADOW_YOFFSET cardh -= cs.SHADOW_YOFFSET
coords = [] coords = []
@ -314,7 +314,7 @@ class AbstractShisenGame(AbstractMahjonggGame):
# dx, dy = 3, -3 # dx, dy = 3, -3
cs = self.app.images.cs cs = self.app.images.cs
if cs.version >= 6: if cs.version == 6 or cs.mahjongg3d:
dx = l.XOFFSET dx = l.XOFFSET
dy = -l.YOFFSET dy = -l.YOFFSET
d_x = cs.SHADOW_XOFFSET d_x = cs.SHADOW_XOFFSET

View file

@ -316,7 +316,7 @@ Please check your %(app)s installation.
# init cardsets # init cardsets
app.initCardsets() app.initCardsets()
cardset = None cardset = None
c = app.opt.cardset.get(0) c = app.opt.cardset.get(0).get(0)
if c: if c:
cardset = app.cardset_manager.getByName(c[0]) cardset = app.cardset_manager.getByName(c[0])
if cardset and c[1]: if cardset and c[1]:

View file

@ -192,6 +192,7 @@ highlight_piles = float(0.2, 9.9)
[cardsets] [cardsets]
0 = string_list(min=2, max=2) 0 = string_list(min=2, max=2)
1 = string_list(min=2, max=2) 1 = string_list(min=2, max=2)
1_1 = string_list(min=2, max=2)
2 = string_list(min=2, max=2) 2 = string_list(min=2, max=2)
3 = string_list(min=2, max=2) 3 = string_list(min=2, max=2)
4 = string_list(min=2, max=2) 4 = string_list(min=2, max=2)
@ -546,34 +547,36 @@ class Options:
# c = 'Dondorf' # c = 'Dondorf'
if USE_PIL: if USE_PIL:
self.cardset = { self.cardset = {
0: ("Neo", ""), 0: {0: ("Neo", "")},
CSI.TYPE_FRENCH: ("Neo", ""), CSI.TYPE_FRENCH: {0: ("Neo", ""), 1: ("Neo", "")},
CSI.TYPE_HANAFUDA: ("Louie Mantia Hanafuda", ""), CSI.TYPE_HANAFUDA: {0: ("Louie Mantia Hanafuda", "")},
CSI.TYPE_MAHJONGG: ("Uni Mahjongg", ""), CSI.TYPE_MAHJONGG: {0: ("Uni Mahjongg", "")},
CSI.TYPE_TAROCK: ("Neo Tarock", ""), CSI.TYPE_TAROCK: {0: ("Neo Tarock", "")},
CSI.TYPE_HEXADECK: ("Neo Hex", ""), CSI.TYPE_HEXADECK: {0: ("Neo Hex", "")},
CSI.TYPE_MUGHAL_GANJIFA: ("Mughal Ganjifa XL", ""), CSI.TYPE_MUGHAL_GANJIFA: {0: ("Mughal Ganjifa XL", "")},
# CSI.TYPE_NAVAGRAHA_GANJIFA: ("Navagraha Ganjifa", ""), # CSI.TYPE_NAVAGRAHA_GANJIFA: {0: ("Navagraha Ganjifa", "")},
CSI.TYPE_NAVAGRAHA_GANJIFA: ("Dashavatara Ganjifa XL", ""), CSI.TYPE_NAVAGRAHA_GANJIFA:
CSI.TYPE_DASHAVATARA_GANJIFA: ("Dashavatara Ganjifa XL", ""), {0: ("Dashavatara Ganjifa XL", "")},
CSI.TYPE_TRUMP_ONLY: ("Next Matrix", ""), CSI.TYPE_DASHAVATARA_GANJIFA:
CSI.TYPE_MATCHING: ("Neo", "") {0: ("Dashavatara Ganjifa XL", "")},
CSI.TYPE_TRUMP_ONLY: {0: ("Next Matrix", "")},
CSI.TYPE_MATCHING: {0: ("Neo", "")}
} }
else: else:
self.cardset = { self.cardset = {
# game_type: (cardset_name, back_file) # game_type: (cardset_name, back_file)
0: (c, ""), 0: {0: (c, "")},
CSI.TYPE_FRENCH: (c, ""), CSI.TYPE_FRENCH: {0: (c, ""), 1: (c, "")},
CSI.TYPE_HANAFUDA: ("Kintengu", ""), CSI.TYPE_HANAFUDA: {0: ("Kintengu", "")},
CSI.TYPE_MAHJONGG: ("Crystal Mahjongg", ""), CSI.TYPE_MAHJONGG: {0: ("Crystal Mahjongg", "")},
CSI.TYPE_TAROCK: ("Vienna 2K", ""), CSI.TYPE_TAROCK: {0: ("Vienna 2K", "")},
CSI.TYPE_HEXADECK: ("Hex A Deck", ""), CSI.TYPE_HEXADECK: {0: ("Hex A Deck", "")},
CSI.TYPE_MUGHAL_GANJIFA: ("Mughal Ganjifa", ""), CSI.TYPE_MUGHAL_GANJIFA: {0: ("Mughal Ganjifa", "")},
# CSI.TYPE_NAVAGRAHA_GANJIFA: ("Navagraha Ganjifa", ""), # CSI.TYPE_NAVAGRAHA_GANJIFA: {0: ("Navagraha Ganjifa", "")},
CSI.TYPE_NAVAGRAHA_GANJIFA: ("Dashavatara Ganjifa", ""), CSI.TYPE_NAVAGRAHA_GANJIFA: {0: ("Dashavatara Ganjifa", "")},
CSI.TYPE_DASHAVATARA_GANJIFA: ("Dashavatara Ganjifa", ""), CSI.TYPE_DASHAVATARA_GANJIFA: {0: ("Dashavatara Ganjifa", "")},
CSI.TYPE_TRUMP_ONLY: ("Matrix", ""), CSI.TYPE_TRUMP_ONLY: {0: ("Matrix", "")},
CSI.TYPE_MATCHING: (c, ""), CSI.TYPE_MATCHING: {0: (c, "")}
} }
# not changeable options # not changeable options
@ -635,7 +638,11 @@ class Options:
# cardsets # cardsets
for key, val in self.cardset.items(): for key, val in self.cardset.items():
config['cardsets'][str(key)] = val for key2, val2 in val.items():
if key2 > 0:
config['cardsets'][str(key) + "_" + str(key2)] = val2
else:
config['cardsets'][str(key)] = val2
for key in ('scale_cards', 'scale_x', 'scale_y', for key in ('scale_cards', 'scale_x', 'scale_y',
'auto_scale', 'spread_stacks', 'auto_scale', 'spread_stacks',
'preserve_aspect_ratio', 'resampling'): 'preserve_aspect_ratio', 'resampling'):
@ -802,12 +809,17 @@ class Options:
# cardsets # cardsets
for key in self.cardset: for key in self.cardset:
val = self._getOption('cardsets', str(key), 'list') for key2 in self.cardset[key]:
if val is not None: if key2 > 0:
try: val = self._getOption('cardsets',
self.cardset[int(key)] = val str(key) + "_" + str(key2), 'list')
except Exception: else:
traceback.print_exc() val = self._getOption('cardsets', str(key), 'list')
if val is not None:
try:
self.cardset[int(key)][int(key2)] = val
except Exception:
traceback.print_exc()
for key, t in (('scale_cards', 'bool'), for key, t in (('scale_cards', 'bool'),
('scale_x', 'float'), ('scale_x', 'float'),
('scale_y', 'float'), ('scale_y', 'float'),

View file

@ -416,14 +416,19 @@ class SelectGameDialogWithPreview(MfxDialog):
# #
c = self.app.cardsets_cache.get(gi.category) c = self.app.cardsets_cache.get(gi.category)
if not c: c2 = None
if c:
c2 = c.get(gi.subcategory)
if not c2:
cardset = self.app.cardset_manager.getByName( cardset = self.app.cardset_manager.getByName(
self.app.opt.cardset[gi.category][0]) self.app.opt.cardset[gi.category][gi.subcategory][0])
self.app.loadCardset(cardset, id=gi.category, self.app.loadCardset(cardset, id=gi.category,
tocache=True, noprogress=True) tocache=True, noprogress=True)
c = self.app.cardsets_cache.get(gi.category) c = self.app.cardsets_cache.get(gi.category)
if c: if c:
self.preview_app.images = c[2] c2 = c.get(gi.subcategory)
if c2:
self.preview_app.images = c2[2]
else: else:
self.preview_app.images = self.app.subsampled_images self.preview_app.images = self.app.subsampled_images

View file

@ -182,6 +182,10 @@ class CSI:
TYPE_TRUMP_ONLY = 9 TYPE_TRUMP_ONLY = 9
TYPE_MATCHING = 10 TYPE_MATCHING = 10
# cardset subtypes
SUBTYPE_NONE = 0
SUBTYPE_JOKER_DECK = 1
TYPE = { TYPE = {
1: _("French type (52 cards)"), 1: _("French type (52 cards)"),
2: _("Hanafuda type (48 cards)"), 2: _("Hanafuda type (48 cards)"),
@ -351,6 +355,8 @@ class CardsetConfig(Struct):
ncards=-1, ncards=-1,
styles=[], styles=[],
year=0, year=0,
subtype=0,
mahjongg3d=False,
# line[1] # line[1]
ident="", ident="",
name="", name="",
@ -380,7 +386,8 @@ class Cardset(Resource):
kw = KwStruct(config.__dict__, **kw) kw = KwStruct(config.__dict__, **kw)
# si is the SelectionInfo struct that will be queried by # si is the SelectionInfo struct that will be queried by
# the "select cardset" dialogs. It can be freely modified. # the "select cardset" dialogs. It can be freely modified.
si = Struct(type=0, size=0, styles=[], nationalities=[], dates=[]) si = Struct(type=0, subtype=0, size=0, styles=[],
nationalities=[], dates=[])
kw = KwStruct( kw = KwStruct(
kw, kw,
# essentials # essentials
@ -452,11 +459,13 @@ class CardsetManager(ResourceManager):
if s not in CSI.TYPE: if s not in CSI.TYPE:
return 0 return 0
cs.si.type = s cs.si.type = s
cs.si.subtype = cs.subtype
cs.suits = CSI.TYPE_SUITS[s] cs.suits = CSI.TYPE_SUITS[s]
cs.ranks = CSI.TYPE_RANKS[s] cs.ranks = CSI.TYPE_RANKS[s]
cs.trumps = CSI.TYPE_TRUMPS[s] cs.trumps = CSI.TYPE_TRUMPS[s]
if s == CSI.TYPE_FRENCH: if s == CSI.TYPE_FRENCH:
pass if cs.subtype == 1:
cs.trumps = list(range(2))
elif s == CSI.TYPE_HANAFUDA: elif s == CSI.TYPE_HANAFUDA:
cs.nbottoms = 15 cs.nbottoms = 15
elif s == CSI.TYPE_TAROCK: elif s == CSI.TYPE_TAROCK:

View file

@ -734,14 +734,19 @@ class SelectGameDialogWithPreview(SelectGameDialog):
# #
c = self.app.cardsets_cache.get(gi.category) c = self.app.cardsets_cache.get(gi.category)
if not c: c2 = None
if c:
c2 = c.get(gi.subcategory)
if not c2:
cardset = self.app.cardset_manager.getByName( cardset = self.app.cardset_manager.getByName(
self.app.opt.cardset[gi.category][0]) self.app.opt.cardset[gi.category][gi.subcategory][0])
self.app.loadCardset(cardset, id=gi.category, self.app.loadCardset(cardset, id=gi.category,
tocache=True, noprogress=True) tocache=True, noprogress=True)
c = self.app.cardsets_cache.get(gi.category) c = self.app.cardsets_cache.get(gi.category)
if c: if c:
self.preview_app.images = c[2] c2 = c.get(gi.subcategory)
if c2:
self.preview_app.images = c2[2]
else: else:
self.preview_app.images = self.app.subsampled_images self.preview_app.images = self.app.subsampled_images

View file

@ -509,14 +509,19 @@ class SelectGameDialogWithPreview(SelectGameDialog):
# #
c = self.app.cardsets_cache.get(gi.category) c = self.app.cardsets_cache.get(gi.category)
if not c: c2 = None
if c:
c2 = c.get(gi.subcategory)
if not c2:
cardset = self.app.cardset_manager.getByName( cardset = self.app.cardset_manager.getByName(
self.app.opt.cardset[gi.category][0]) self.app.opt.cardset[gi.category][gi.subcategory][0])
self.app.loadCardset(cardset, id=gi.category, self.app.loadCardset(cardset, id=gi.category,
tocache=True, noprogress=True) tocache=True, noprogress=True)
c = self.app.cardsets_cache.get(gi.category) c = self.app.cardsets_cache.get(gi.category)
if c: if c:
self.preview_app.images = c[2] c2 = c.get(gi.subcategory)
if c2:
self.preview_app.images = c2[2]
else: else:
self.preview_app.images = self.app.subsampled_images self.preview_app.images = self.app.subsampled_images