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

Compare commits

..

4 commits

Author SHA1 Message Date
Shlomi Fish
6bc5b53995 test presence of a <move/> element
add a testcase for the XML output
2025-02-01 13:52:43 +02:00
Shlomi Fish
dd42ac10ea test presence of a <move/> element
add a testcase for the XML output
2025-01-31 09:05:30 +02:00
Shlomi Fish
d6ca6d226b add a testcase for the XML output 2025-01-31 08:39:36 +02:00
Shlomi Fish
e4e2e99031 [Wip] kpatience xml exporting (Jan 2025 try) 2025-01-31 08:39:36 +02:00
49 changed files with 177 additions and 561 deletions

View file

@ -1,64 +0,0 @@
<h1>FAQ</h1>
<h2>The animation is too slow...</h2>
<p>
Unfortunately the Tcl/Tk toolkit lacks a sprite concept, so
there is a lot of (invisible double-buffered) redraw going on
when dragging cards around.
<p>
Disabling <i>Card shadow</i>, <i>Shade legal moves</i>,
background table tiles and sound will somewhat improve the display speed.
<h2>The table tiles look strange</h2>
<p>
Background table tiles should only be enabled when using
a true-color video mode - otherwise they may look bad
because of dithering.
<p>
BTW, you can add your own background tiles by copying the images
to the main <i>data/tiles</i> or your home <i>~/.PySolFC/tiles</i> directory.
<!-- They must be in GIF or PPM format. -->
<h2>My antivirus app says the Windows installer contains a virus.</h2>
<p>
We have been asked about the fact that some anti viruses, including those
on <a href="https://www.virustotal.com/">VirusTotal</a>, have identified the Microsoft
Windows downloads as containing malware. What we know is that they are generated from
the <a href="https://en.wikipedia.org/wiki/Free_and_open-source_software">open source</a>
source code by <a href="https://www.appveyor.com/">AppVeyor</a>, are checked using
VirusTotal before they are uploaded, and at that point were considered to be malware clean.
<p>
However, as time passes, they seem to accumulate classifyings as containing malware
in what appears to be <a href="https://en.wikipedia.org/wiki/False_positives_and_false_negatives">false positives</a>. So we believe the downloads are nonetheless safe and free of
malware.
<p>
Furthermore, note that we believe that many anti-malware applications are harmful
by themselves, and that they are all an incomplete (non-)solution to an
issue that does not exist in <a href="https://en.wikipedia.org/wiki/Linux#Desktop">Linux</a> and the <a href="https://en.wikipedia.org/wiki/List_of_BSD_operating_systems">BSDs operating systems</a>.
<p>
For more information, see:
<ol>
<li><a href="https://sourceforge.net/p/pysolfc/discussion/503709/thread/d841b6a1/">Forum discussion</a></li>
<li><a href="http://linuxmafia.com/~rick/faq/">Viruses on Linux</a></li>
<li><a href="https://www.mail-archive.com/wikimedia-l@lists.wikimedia.org/msg30001.html">Discussion about anti-viruses.</a></li>
</ol>
<h2>I received an error that there is no module named "formatter".</h2>
<p>
This error occurs if you're trying to run an older version of PySolFC
with Python 3.10. If you are using Python 3.10 or later, please upgrade your
version of PySolFC to 2.14.0 or later - older versions are not compatible with
Python 3.10.
<p>
If you are getting your copy from your Linux distribution's package manager,
please contact the people who maintain the packages for your distribution.
You can always get the latest version from the PySolFC website or from
Flathub.
<h2>It won't let me deal more cards in Spider.</h2>
<p>
When playing Spider, you are not allowed to deal more cards if there are any
empty piles. If there aren't enough cards left to put one in each pile, the
game is lost. Part of the game is planning ahead when to deal more cards to
avoid this situation.
<p>
If you want a variation without this rule, you can play Relaxed Spider instead.

View file

@ -46,7 +46,6 @@ fix_gettext()
files = [
('credits.html', 'PySol Credits'),
('credits_old.html', 'PySol Credits'),
('faq.html', 'PySol - FAQ'),
('ganjifa.html', 'PySol - General Ganjifa Card Rules'),
('general_rules.html', 'PySol - General Rules'),
('glossary.html', 'PySol - Glossary'),

View file

@ -323,15 +323,6 @@ the deck.</p>
Hearts, and Diamonds.</p>
</dd>
<dt><b>SUPER MOVE</b></dt>
<dd>
<p>A special move where you move a sequence of cards at once, in a game
that does not normally allow it. However, if there are enough open
reserves and empty stacks to perform the move by moving cards between
them one at a time, you can make it as a single move as a shortcut.</p>
</dd>
<dt><b>TABLEAU</b></dt>
<dd>

View file

@ -55,6 +55,27 @@ disable certain features as they would be trivial otherwise.
The logic involved is not too clever on purpose (i.e. it does not consult the hint system).
</ul>
<h2>The animation is too slow...</h2>
<p>
Unfortunately the Tcl/Tk toolkit lacks a sprite concept, so
there is a lot of (invisible double-buffered) redraw going on
when dragging cards around.
<p>
Disabling <i>Card shadow</i>, <i>Shade legal moves</i>,
background table tiles and sound will somewhat improve the display speed.
<h2>The table tiles look strange</h2>
<p>
Background table tiles should only be enabled when using
a true-color video mode - otherwise they may look bad
because of dithering.
<p>
BTW, you can add your own background tiles by copying the images
to the main <i>data/tiles</i> or your home <i>~/.PySolFC/tiles</i> directory.
<!-- They must be in GIF or PPM format. -->
<h2>Some notes about scoring</h2>
<p>
<ul type="disc">

View file

@ -19,10 +19,9 @@
<li> <a href="cardset_customization.html">Cardset Customization</a>
<li> <a href="plugins.html">Plugins</a>
</ul>
<h2>About</h2>
<h2>Misc</h2>
<ul>
<li> <a href="news.html">What's new?</a>
<li> <a href="faq.html">FAQ</a>
<li> <a href="report_bug.html">Report a Bug</a>
<li> <a href="license.html">PySol license terms</a>
<li> <a href="credits.html">PySol credits</a>

View file

@ -1,9 +1,10 @@
<h1>Report a Bug</h1>
<p>
Before you report a bug, please verify that you are running
the latest version of PySolFC. Also, check the
<a href="faq.html">FAQ</a>, and issues previously reported
on GitHub, to ensure that the bug was not previously reported.
the latest version of PySolFC, and also check the PySolFC site's
<a href="https://pysolfc.sourceforge.io/faq.html">FAQ page</a>,
and issues previously reported on GitHub, to ensure that the bug
was not previously reported.
<p>
If you found a bug in PySolFC, the best place to report it
is on GitHub. To do so, create an issue at

View file

@ -15,7 +15,7 @@ This card must be the last remaining card in order to win the game.
<h3>Notes</h3>
<p>
Accordion's Revenge is unwinnable if the first or second card is
declared. As such, PySol will never select either of those cards as
the target.
declared. As such, PySol will reselect the declared card if it
is chosen.
<p>
The concept of Accordion's Revenge was invented by Mark Masten.

View file

@ -1,4 +1,4 @@
<h1>Big Braid (Der gro&szlig;e Zopf)</h1>
<h1>Big Braid</h1>
<p>
Napoleon type. 3 decks. 2 redeals.

View file

@ -1,27 +0,0 @@
<h1>Families</h1>
<p>
Memory game type. 32 cards. No redeal.
<h3>Object</h3>
<p>
Remove all groups of jack-queen-king of the same suit.
<h3>Rules</h3>
<p>
Families is played with eight sets of Jack, Queen, and King - two of
each suit, along with six black jokers and two red jokers.
<p>
Flip three cards. If you flip a sequence of Jack, Queen, and King of
the same suit, the cards are removed. If not, they are flipped face-down.
<p>
If a red joker is flipped, all of the remaining unmatched cards that were
not flipped are reshuffled and redealt (after you've flipped all three
cards).
<p>
If a pair of black jokers is flipped, the game is lost. If all eight
sequences are removed before this happens, the game is won.
<h3>Notes</h3>
<p>
<i>Undo</i>, <i>Bookmarks</i>, <i>Autodrop</i> and <i>Quickplay</i>
are disabled for this game.

View file

@ -1,6 +1,6 @@
<h1>Hurricane</h1>
<p>
Pairing type. 1 deck. No redeal.
Pairing game type. 1 deck. No redeal.
<h3>Object</h3>
<p>

View file

@ -1,12 +0,0 @@
<h1>Ides of March</h1>
<p>
Pairing type. 1 deck. No redeal.
<h3>Object</h3>
<p>
Move all cards to the single foundation.
<h3>Quick Description</h3>
<p>
Like <a href="hurricane.html">Hurricane</a>,
but remove pairs whose ranks total 15, or pairs of aces.

View file

@ -1,19 +0,0 @@
<h1>Louis</h1>
<p>
Two-Deck game type. 2 decks. 2 redeals.
<h3>Object</h3>
<p>
Move all the cards to the foundations.
<h3>Quick Description</h3>
<p>
Like <a href="sthelena.html">St. Helena</a>,
but at the start of the game, a card is dealt to each of the
twelve tableau piles. During this round, an empty tableau pile
will be immediately filled from the talon. When no moves are left,
the rest of the deck can be dealt.
<p>
Also, there are no restrictions as to which tableau piles
cards can be moved to foundations from, and tableau piles are
built up or down by same suit.

View file

@ -1,12 +0,0 @@
<h1>Outback Patience</h1>
<p>
Yukon type. 2 decks. No redeal.
<h3>Object</h3>
<p>
Move all cards to the foundations.
<h3>Quick Description</h3>
<p>
Like <a href="austalianpatience.html">Australian Patience</a>,
but with two decks, and eight piles of seven cards each.

View file

@ -1,22 +0,0 @@
<h1>Pyramid Thirteen</h1>
<p>
Pairing game type. 1 deck. No redeal.
<h3>Object</h3>
<p>
Move all cards to the single foundation.
<h3>Quick Description</h3>
<p>
Like <a href="pyramid.html">Pyramid</a>, but all but the
front row of the pyramid are dealt face-down, and no redeals
are allowed.
<h3>Notes</h3>
<p>
This difficult variant of Pyramid is based on the Gnome AisleRiot
rules. It is called "Thirteen" there, but renamed Pyramid Thirteen
here to avoid confusion with the game
<a href="thirteens.html">Thirteens</a>.
<p>
<i>Quickplay</i> is disabled for this game.

View file

@ -1,12 +0,0 @@
<h1>Relaxed Cruel</h1>
<p>
Baker's Dozen type. 1 deck. Unlimited redeals.
<h3>Object</h3>
<p>
Move all cards to the foundations.
<h3>Quick Description</h3>
<p>
Just like <a href="cruel.html">Cruel</a>,
but the number of cards you can move as a sequence is not restricted.

View file

@ -1,13 +0,0 @@
<h1>Wasp II</h1>
<p>
Spider type. 1 deck. No redeal.
<h3>Object</h3>
<p>
Move all cards to the foundations.
<h3>Quick Description</h3>
<p>
Like <a href="wasp.html">Wasp</a>,
but only three of the tableau piles contain
face-down cards (similar to <a href="scorpionii.html">Scorpion II</a>).

View file

@ -2653,7 +2653,7 @@ msgid "Automatic play"
msgstr "Automatisierung"
#: pysollib/kivy/menubar.py:513
msgid "Auto face-up"
msgid "Auto face up"
msgstr "Automatisch aufdecken"
#: pysollib/kivy/menubar.py:523
@ -5174,7 +5174,7 @@ msgstr "Kommentare..."
msgid "Log..."
msgstr ""
msgid "Demo log..."
msgid "Demo Log..."
msgstr ""
#: pysollib/ui/tktile/menubar.py:427

View file

@ -2694,7 +2694,7 @@ msgid "Automatic play"
msgstr "Jouer auto"
#: pysollib/kivy/menubar.py:513
msgid "Auto face-up"
msgid "Auto face up"
msgstr "Retourner auto"
#: pysollib/kivy/menubar.py:523
@ -5225,7 +5225,7 @@ msgstr "&Commentaires..."
msgid "Log..."
msgstr "Journal..."
msgid "Demo log..."
msgid "Demo Log..."
msgstr ""
#: pysollib/ui/tktile/menubar.py:427

View file

@ -2707,7 +2707,7 @@ msgstr "Gioco automatico"
#: pysollib/kivy/menubar.py:513
#, fuzzy
msgid "Auto face-up"
msgid "Auto face up"
msgstr "Auto &scopri"
#: pysollib/kivy/menubar.py:523
@ -5291,7 +5291,7 @@ msgstr "&Commenti..."
msgid "Log..."
msgstr "Log..."
msgid "Demo log..."
msgid "Demo Log..."
msgstr ""
#: pysollib/ui/tktile/menubar.py:427

View file

@ -2707,7 +2707,7 @@ msgid "Automatic play"
msgstr "Gra &automatyczna"
#: pysollib/kivy/menubar.py:513
msgid "Auto face-up"
msgid "Auto face up"
msgstr "Odkrywaj automatycznie"
#: pysollib/kivy/menubar.py:523
@ -5245,7 +5245,7 @@ msgstr "Komentarze..."
msgid "Log..."
msgstr "Log..."
msgid "Demo log..."
msgid "Demo Log..."
msgstr ""
#: pysollib/ui/tktile/menubar.py:427

View file

@ -2715,7 +2715,7 @@ msgid "Automatic play"
msgstr "Jogar automaticamente"
#: pysollib/kivy/menubar.py:513
msgid "Auto face-up"
msgid "Auto face up"
msgstr "Virar pra cima automaticamente"
#: pysollib/kivy/menubar.py:523
@ -5247,7 +5247,7 @@ msgstr "&Comentários..."
msgid "Log..."
msgstr "Registro"
msgid "Demo log..."
msgid "Demo Log..."
msgstr ""
#: pysollib/ui/tktile/menubar.py:427

View file

@ -2524,7 +2524,7 @@ msgid "Automatic play"
msgstr ""
#: pysollib/kivy/menubar.py:513
msgid "Auto face-up"
msgid "Auto face up"
msgstr ""
#: pysollib/kivy/menubar.py:523
@ -4977,7 +4977,7 @@ msgstr ""
msgid "Log..."
msgstr ""
msgid "Demo log..."
msgid "Demo Log..."
msgstr ""
#: pysollib/ui/tktile/menubar.py:427

View file

@ -2713,7 +2713,7 @@ msgstr "Настройки &автоматической игры"
#: pysollib/kivy/menubar.py:513
#, fuzzy
msgid "Auto face-up"
msgid "Auto face up"
msgstr "Автоматически &переворачивать"
#: pysollib/kivy/menubar.py:523
@ -5314,7 +5314,7 @@ msgstr "&Комментарии..."
msgid "Log..."
msgstr "Лог..."
msgid "Demo log..."
msgid "Demo Log..."
msgstr ""
#: pysollib/ui/tktile/menubar.py:427

View file

@ -112,7 +112,7 @@ class GI:
# extra flags
GT_BETA = 1 << 12 # beta version of game driver
GT_CHILDREN = 1 << 13
GT_CHILDREN = 1 << 13 # *not used*
GT_CONTRIB = 1 << 14 # contributed games under the GNU GPL
GT_HIDDEN = 1 << 15 # not visible in menus, but games can be loaded
GT_OPEN = 1 << 16
@ -320,6 +320,7 @@ class GI:
904: 68, # Lexington Harp
237: 22231, # Three Peaks
297: 631, # Alternation/Alternations
526: 447, # Australian/Outback Patience
640: 566, # Hypotenuse/Brazilian Patience
# Lost Mahjongg Layouts
@ -367,12 +368,12 @@ class GI:
# Hamilton, Labyrinth, Treize, Wall
("Gnome AisleRiot", (
1, 2, 8, 9, 11, 12, 13, 19, 24, 27, 29, 31, 33, 34, 35, 36,
38, 40, 41, 42, 43, 44, 45, 48, 58, 65, 67, 89, 91, 92, 93,
94, 95, 96, 97, 100, 104, 105, 111, 112, 113, 130, 135, 139,
144, 146, 147, 148, 200, 201, 206, 224, 225, 229, 230, 233,
257, 258, 277, 280, 281, 282, 283, 284, 334, 384, 479, 495,
551, 552, 553, 572, 593, 674, 700, 715, 716, 737, 772, 810,
819, 824, 829, 859, 874, 906, 934, 22231,
38, 40, 41, 42, 43, 45, 48, 58, 65, 67, 89, 91, 92, 93, 94,
95, 96, 97, 100, 104, 105, 111, 112, 113, 130, 135, 139, 144,
146, 147, 148, 200, 201, 206, 224, 225, 229, 230, 233, 257,
258, 277, 280, 281, 282, 283, 284, 334, 384, 479, 495, 551,
552, 553, 572, 593, 674, 700, 715, 716, 737, 772, 810, 819,
824, 829, 859, 874, 906, 934, 22231,
)),
# Hoyle Card Games
@ -574,7 +575,7 @@ class GI:
('fc-0.9.0', tuple(range(323, 421))),
('fc-0.9.1', tuple(range(421, 441))),
('fc-0.9.2', tuple(range(441, 466))),
('fc-0.9.3', tuple(range(466, 526)) + tuple(range(527, 661))),
('fc-0.9.3', tuple(range(466, 661))),
('fc-0.9.4', tuple(range(661, 671))),
('fc-1.0', tuple(range(671, 711))),
('fc-1.1', tuple(range(711, 759))),
@ -594,8 +595,7 @@ class GI:
tuple(range(19000, 19012)) + tuple(range(22303, 22311)) +
tuple(range(22353, 22361))),
('fc-3.1', tuple(range(961, 971))),
('dev', tuple(range(971, 978)) + tuple(range(18005, 18007)) +
(44, 526,)),
('dev', tuple(range(971, 973)) + tuple(range(18005, 18007))),
)
# deprecated - the correct way is to or a GI.GT_XXX flag

View file

@ -225,7 +225,6 @@ class Vineyard(CastlesInSpain):
# ************************************************************************
# * Cruel
# * Relaxed Cruel
# * Unusual
# ************************************************************************
@ -311,10 +310,6 @@ class Cruel(CastlesInSpain):
shallHighlightMatch = Game._shallHighlightMatch_SS
class RelaxedCruel(Cruel):
RowStack_Class = StackWrapper(SS_RowStack, base_rank=NO_RANK)
class Unusual(Cruel):
def createGame(self):
@ -458,6 +453,3 @@ registerGame(GameInfo(876, Vineyard, "Vineyard",
GI.SL_MOSTLY_SKILL))
registerGame(GameInfo(907, Martha, "Stewart",
GI.GT_BAKERS_DOZEN, 1, 0, GI.SL_BALANCED))
registerGame(GameInfo(977, RelaxedCruel, "Relaxed Cruel",
GI.GT_BAKERS_DOZEN | GI.GT_OPEN | GI.GT_RELAXED, 1, -1,
GI.SL_BALANCED))

View file

@ -646,8 +646,7 @@ registerGame(GameInfo(376, Backbone, "Backbone",
registerGame(GameInfo(377, BackbonePlus, "Backbone +",
GI.GT_NAPOLEON, 2, 0, GI.SL_BALANCED))
registerGame(GameInfo(510, BigBraid, "Big Braid",
GI.GT_NAPOLEON | GI.GT_ORIGINAL, 3, 2, GI.SL_BALANCED,
altnames=("Der grose Zopf",)))
GI.GT_NAPOLEON | GI.GT_ORIGINAL, 3, 2, GI.SL_BALANCED))
registerGame(GameInfo(694, Casket, "Casket",
GI.GT_2DECK_TYPE, 2, 0, GI.SL_BALANCED))
registerGame(GameInfo(717, Well, "Well",

View file

@ -383,18 +383,51 @@ class PyramidDozen(Giza):
# ************************************************************************
# * Pyramid Thirteen
# * Thirteen
# * FIXME: UNFINISHED
# * (this doesn't work yet as 2 cards of the Waste should be playable)
# ************************************************************************
# Previous comments suggest there would need to be two waste piles. This
# is not true. Based on AisleRiot's rules, the two waste cards can only
# be played with each other, which is the same as how PySol's traditional
# version works. So the remaining AisleRiot differences are captured
# in "Pyramid Thirteen", renamed from "Thirteen" to avoid confusion with
# "Thirteens"
class Thirteen(Pyramid):
Talon_Class = StackWrapper(Pyramid_Talon, max_rounds=1, max_accept=1)
#
# game layout
#
def createGame(self):
# create layout
layout, s = Layout(self), self.s
# set window
self.setSize(7*layout.XS+layout.XM, 5*layout.YS+layout.YM)
# create stacks
for i in range(7):
x = layout.XM + (6-i) * layout.XS // 2
y = layout.YM + layout.YS + i * layout.YS // 2
for j in range(i+1):
s.rows.append(Pyramid_RowStack(x, y, self))
x = x + layout.XS
x, y = layout.XM, layout.YM
s.talon = WasteTalonStack(x, y, self, max_rounds=1)
layout.createText(s.talon, "s")
x = x + layout.XS
s.waste = Pyramid_Waste(x, y, self, max_accept=1)
layout.createText(s.waste, "s")
s.waste.CARD_XOFFSET = 14
x, y = self.width - layout.XS, layout.YM
s.foundations.append(Pyramid_Foundation(x, y, self,
suit=ANY_SUIT, dir=0, base_rank=ANY_RANK,
max_move=0, max_cards=52))
# define stack-groups
self.sg.talonstacks = [s.talon] + [s.waste]
self.sg.openstacks = s.rows + self.sg.talonstacks
self.sg.dropstacks = s.rows + self.sg.talonstacks
#
# game overrides
#
def startGame(self):
self.startDealSample()
@ -1758,8 +1791,6 @@ class Hurricane_Reserve(Hurricane_StackMethods, OpenStack):
class Hurricane(Pyramid):
Hint_Class = Hurricane_Hint
RowStack_Class = Hurricane_RowStack
Reserve_Class = Hurricane_Reserve
def createGame(self):
# create layout
@ -1777,7 +1808,7 @@ class Hurricane(Pyramid):
(0, 2), (1, 2), (2, 2), (3, 2),
):
x, y = layout.XM + 1.5*layout.XS + ww*xx, layout.YM + layout.YS*yy
stack = self.Reserve_Class(x, y, self, max_accept=1)
stack = Hurricane_Reserve(x, y, self, max_accept=1)
stack.CARD_XOFFSET, stack.CARD_YOFFSET = layout.XOFFSET, 0
s.reserves.append(stack)
@ -1785,7 +1816,7 @@ class Hurricane(Pyramid):
x = layout.XM + 1.5*layout.XS + layout.XS+2*layout.XOFFSET + d//2
y = layout.YM+layout.YS
for i in range(3):
stack = self.RowStack_Class(x, y, self, max_accept=1)
stack = Hurricane_RowStack(x, y, self, max_accept=1)
s.rows.append(stack)
x += layout.XS
@ -1816,38 +1847,6 @@ class Hurricane(Pyramid):
self.leaveState(old_state)
# ************************************************************************
# * Ides of March
# ************************************************************************
class IdesOfMarch_StackMethods(Pyramid_StackMethods):
def acceptsCards(self, from_stack, cards):
if from_stack is self:
return False
if len(cards) != 1:
return False
if not self.cards:
return False
c1 = self.cards[-1]
c2 = cards[0]
return (c1.face_up and c2.face_up and
(c1.rank + c2.rank == 13 or c1.rank + c2.rank == 0))
class IdesOfMarch_RowStack(IdesOfMarch_StackMethods, BasicRowStack):
pass
class IdesOfMarch_Reserve(IdesOfMarch_StackMethods, OpenStack):
pass
class IdesOfMarch(Hurricane):
RowStack_Class = IdesOfMarch_RowStack
Reserve_Class = IdesOfMarch_Reserve
# register the game
registerGame(GameInfo(38, Pyramid, "Pyramid",
GI.GT_PAIRING_TYPE, 1, 2, GI.SL_MOSTLY_LUCK))
@ -1855,8 +1854,8 @@ registerGame(GameInfo(193, RelaxedPyramid, "Relaxed Pyramid",
GI.GT_PAIRING_TYPE | GI.GT_RELAXED, 1, 2,
GI.SL_MOSTLY_LUCK,
altnames=("Pyramid's Stones", "Pyramid Clear")))
registerGame(GameInfo(44, Thirteen, "Pyramid Thirteen",
GI.GT_PAIRING_TYPE, 1, 0, GI.SL_MOSTLY_LUCK))
# registerGame(GameInfo(44, Thirteen, "Thirteen",
# GI.GT_PAIRING_TYPE, 1, 0))
registerGame(GameInfo(592, Giza, "Giza",
GI.GT_PAIRING_TYPE | GI.GT_OPEN, 1, 0, GI.SL_BALANCED))
registerGame(GameInfo(593, Thirteens, "Thirteens",
@ -1928,6 +1927,3 @@ registerGame(GameInfo(961, Nines, "Nines",
GI.GT_PAIRING_TYPE, 1, 0, GI.SL_LUCK))
registerGame(GameInfo(969, ElevenTriangle, "Eleven Triangle",
GI.GT_PAIRING_TYPE, 1, 0, GI.SL_MOSTLY_LUCK))
registerGame(GameInfo(974, IdesOfMarch, "Ides of March",
GI.GT_PAIRING_TYPE, 1, 0, GI.SL_MOSTLY_LUCK,
altnames=("XV",)))

View file

@ -291,8 +291,7 @@ class Maze(Game):
# register the game
registerGame(GameInfo(118, SiebenBisAs, "Sieben bis As",
GI.GT_MONTANA | GI.GT_OPEN | GI.GT_STRIPPED, 1, 0,
GI.SL_MOSTLY_SKILL, ranks=(0, 6, 7, 8, 9, 10, 11, 12),
altnames=("Seven to Ace",)))
GI.SL_MOSTLY_SKILL, ranks=(0, 6, 7, 8, 9, 10, 11, 12)))
registerGame(GameInfo(144, Maze, "Maze",
GI.GT_MONTANA | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL,
si={"ncards": 48}))

View file

@ -1266,12 +1266,10 @@ class Dashavatara(Game):
# *
# ***********************************************************************/
def r(id, gameclass, name, game_type, decks, redeals, skill_level,
altnames=()):
def r(id, gameclass, name, game_type, decks, redeals, skill_level):
game_type = game_type | GI.GT_DASHAVATARA_GANJIFA
gi = GameInfo(id, gameclass, name, game_type, decks, redeals, skill_level,
suits=list(range(10)), ranks=list(range(12)),
altnames=altnames)
suits=list(range(10)), ranks=list(range(12)))
registerGame(gi)
return gi

View file

@ -1605,12 +1605,11 @@ class MagicMontana(Montana):
# ************************************************************************
def r(id, gameclass, name, game_type, decks, redeals, skill_level,
altnames=()):
def r(id, gameclass, name, game_type, decks, redeals, skill_level):
game_type = game_type | GI.GT_HEXADECK
gi = GameInfo(id, gameclass, name, game_type, decks, redeals, skill_level,
suits=list(range(4)), ranks=list(range(16)),
trumps=list(range(4)), altnames=altnames)
trumps=list(range(4)))
registerGame(gi)
return gi
@ -1634,7 +1633,7 @@ r(16674, HiddenPassages, 'Hidden Passages', GI.GT_HEXADECK, 1, 1,
r(16675, CluitjarsLair, 'Cluitjar\'s Lair', GI.GT_HEXADECK, 1, 0,
GI.SL_BALANCED)
r(16676, MerlinsMeander, 'Merlin\'s Meander', GI.GT_HEXADECK, 2, 2,
GI.SL_BALANCED, altnames=('Merlin\'s Coil'))
GI.SL_BALANCED)
r(16677, MagesGame, 'Mage\'s Game', GI.GT_HEXADECK | GI.GT_OPEN, 1, 0,
GI.SL_BALANCED)
r(16678, Convolution, 'Convolution', GI.GT_HEXADECK | GI.GT_OPEN, 2, 0,

View file

@ -71,7 +71,7 @@ class Memory_RowStack(OpenStack):
def _dropPairMove(self, n, other_stack, frames=-1, shadow=-1):
game = self.game
game.playSample("droppair", priority=200)
game.closed_cards -= 2
game.closed_cards = game.closed_cards - 2
game.score = game.score + 5
rightclickHandler = clickHandler
@ -108,7 +108,6 @@ class Memory24(Game):
# game extras
self.other_stack = None
self.other_stack2 = None
self.closed_cards = -1
self.score = 0
@ -256,7 +255,7 @@ class Concentration_RowStack(Memory_RowStack):
def _dropPairMove(self, n, other_stack, frames=-1, shadow=-1):
game = self.game
game.playSample("droppair", priority=200)
game.closed_cards -= 2
game.closed_cards = game.closed_cards - 2
game.score = game.score + 5
#
old_state = game.enterState(game.S_FILL)
@ -272,8 +271,6 @@ class Concentration(Memory24):
WIN_SCORE = 50
PERFECT_SCORE = 130 # 5 * (13*4)/2
RowStack_Class = Concentration_RowStack
#
# game layout
#
@ -284,7 +281,6 @@ class Concentration(Memory24):
# game extras
self.other_stack = None
self.other_stack2 = None
self.closed_cards = -1
self.score = 0
@ -295,12 +291,11 @@ class Concentration(Memory24):
for i in range(self.ROWS):
for j in range(self.COLUMNS):
x, y = l.XM + j*l.XS, l.YM + i*l.YS
s.rows.append(self.RowStack_Class(x, y, self,
s.rows.append(Concentration_RowStack(x, y, self,
max_move=0, max_accept=0, max_cards=1))
x, y = l.XM + self.COLUMNS*l.XS//2, self.height - l.YS
s.talon = InitialDealTalonStack(x, y, self)
l.createText(s.talon, dx=-10, anchor="sw", text_format="%D")
s.internals.append(InvisibleStack(self))
# create text
x, y = l.XM, self.height - l.YM
@ -395,151 +390,6 @@ class MemorySequence(Memory24):
return card1.suit == card2.suit and card1.rank == card2.rank + 1
# ************************************************************************
# * Families
# ************************************************************************
class Families_RowStack(Memory_RowStack):
def clickHandler(self, event):
game = self.game
if (game.score == -1):
return 1
if len(self.cards) != 1 or self.cards[-1].face_up:
return 1
if game.other_stack is None:
game.playSample("flip", priority=5)
self.flipMove()
game.other_stack = self
elif game.other_stack2 is None:
game.playSample("flip", priority=5)
self.flipMove()
game.other_stack2 = self
else:
assert len(game.other_stack.cards) == 1 and \
game.other_stack.cards[-1].face_up
c1, c2, c3 = self, game.other_stack, game.other_stack2
self.flipMove()
if not self.game.handleMatch(c1, c2, c3):
game.playSample("flip", priority=5)
game.updateStatus(moves=game.moves.index+1) # update moves now
game.updateText()
game.canvas.update_idletasks()
game.sleep(0.5)
game.other_stack.flipMove()
game.canvas.update_idletasks()
game.sleep(0.2)
game.other_stack2.flipMove()
game.canvas.update_idletasks()
game.sleep(0.2)
self.flipMove()
game.other_stack = None
game.other_stack2 = None
self.game.finishMove()
self.game.checkForWin()
return 1
class Families(Concentration):
Hint_Class = None
COLUMNS = 8
ROWS = 4
RowStack_Class = Families_RowStack
def updateText(self):
pass
def _restoreGameHook(self, game):
if game.loadinfo.other_stack_id >= 0:
self.other_stack = self.allstacks[game.loadinfo.other_stack_id]
else:
self.other_stack = None
if game.loadinfo.other_stack2_id >= 0:
self.other_stack2 = self.allstacks[game.loadinfo.other_stack2_id]
else:
self.other_stack2 = None
self.closed_cards = game.loadinfo.closed_cards
self.score = game.loadinfo.score
def handleMatch(self, stack1, stack2, stack3):
card1 = stack1.cards[-1]
card2 = stack2.cards[-1]
card3 = stack3.cards[-1]
if (card1.suit == card2.suit and card2.suit == card3.suit and
card1.rank != card2.rank and card2.rank != card3.rank and
card1.rank != card3.rank):
self.playSample("droppair", priority=200)
self.closed_cards -= 3
#
old_state = self.enterState(self.S_FILL)
f = self.s.talon
self.moveMove(1, stack1, f)
self.moveMove(1, stack2, f)
self.moveMove(1, stack3, f)
self.leaveState(old_state)
return True
else:
redjokers = 0
blackjokers = 0
if card1.suit == 4 and card1.rank == 0:
blackjokers += 1
if card2.suit == 4 and card2.rank == 0:
blackjokers += 1
if card3.suit == 4 and card3.rank == 0:
blackjokers += 1
if card1.suit == 4 and card1.rank == 1:
redjokers += 1
if card2.suit == 4 and card2.rank == 1:
redjokers += 1
if card3.suit == 4 and card3.rank == 1:
redjokers += 1
if blackjokers > 1:
self.score = -1
return True
if redjokers > 0:
self.reshuffle()
def reshuffle(self):
old_state = self.enterState(self.S_FILL)
stacks = ()
for r in self.s.rows:
if r.cards and not r.cards[-1].face_up:
stacks += (r,)
self.moveMove(len(r.cards), r, self.s.internals[0],
frames=0)
self.shuffleStackMove(self.s.internals[0])
self.startDealSample()
for r in stacks:
self.moveMove(1, self.s.internals[0], r)
self.stopSamples()
self.leaveState(old_state)
def isGameWon(self):
return self.closed_cards == 8 and self.score > -1
def getStuck(self):
return self.score == -1
def _loadGameHook(self, p):
self.loadinfo.addattr(other_stack_id=p.load())
self.loadinfo.addattr(other_stack2_id=p.load())
self.loadinfo.addattr(closed_cards=p.load())
self.loadinfo.addattr(score=p.load())
def _saveGameHook(self, p):
if self.other_stack:
p.dump(self.other_stack.id)
else:
p.dump(-1)
if self.other_stack2:
p.dump(self.other_stack2.id)
else:
p.dump(-1)
p.dump(self.closed_cards)
p.dump(self.score)
# register the game
registerGame(GameInfo(886, Memory16, "Memory 16",
GI.GT_MEMORY | GI.GT_SCORE | GI.GT_CHILDREN, 2, 0,
@ -567,7 +417,3 @@ registerGame(GameInfo(178, Concentration, "Concentration",
registerGame(GameInfo(843, MemorySequence, "Memory Sequence",
GI.GT_MEMORY | GI.GT_SCORE, 1, 0, GI.SL_SKILL,
suits=(1,), altnames=('Ace Through King',)))
registerGame(GameInfo(973, Families, "Families",
GI.GT_MEMORY, 2, 0, GI.SL_MOSTLY_SKILL,
ranks=(10, 11, 12), subcategory=GI.GS_JOKER_DECK,
trumps=(0, 0, 0, 1)))

View file

@ -1157,12 +1157,10 @@ class AshtaDikapala(Game):
# *
# ************************************************************************
def r(id, gameclass, name, game_type, decks, redeals, skill_level,
altnames=()):
def r(id, gameclass, name, game_type, decks, redeals, skill_level):
game_type = game_type | GI.GT_MUGHAL_GANJIFA
gi = GameInfo(id, gameclass, name, game_type, decks, redeals, skill_level,
suits=list(range(8)), ranks=list(range(12)),
altnames=altnames)
suits=list(range(8)), ranks=list(range(12)))
registerGame(gi)
return gi
@ -1189,6 +1187,6 @@ r(16001, Danda, 'Danda', GI.GT_MUGHAL_GANJIFA, 1, 0, GI.SL_MOSTLY_SKILL)
r(16002, Khadga, 'Khadga', GI.GT_MUGHAL_GANJIFA, 1, 0, GI.SL_MOSTLY_SKILL)
r(16003, Makara, 'Makara', GI.GT_MUGHAL_GANJIFA, 1, 0, GI.SL_MOSTLY_SKILL)
r(16004, AshtaDikapala, 'Ashta Dikapala', GI.GT_MUGHAL_GANJIFA, 1, 0,
GI.SL_BALANCED, altnames=('Eight Guardians'))
GI.SL_BALANCED)
del r

View file

@ -501,11 +501,11 @@ class TrumpsRow(Montana):
# ************************************************************************
def r(id, gameclass, name, game_type, decks, redeals, skill_level,
numcards=78, altnames=()):
numcards=78):
game_type = game_type | GI.GT_TAROCK | GI.GT_CONTRIB | GI.GT_ORIGINAL
gi = GameInfo(id, gameclass, name, game_type, decks, redeals, skill_level,
ranks=list(range(14)), trumps=list(range(22)),
altnames=altnames, si={"ncards": numcards})
si={"ncards": numcards})
registerGame(gi)
return gi
@ -519,8 +519,7 @@ r(13166, Serpent, 'Serpent', GI.GT_TAROCK | GI.GT_OPEN, 2, 0,
GI.SL_MOSTLY_SKILL)
r(13167, Rambling, 'Rambling', GI.GT_TAROCK | GI.GT_OPEN, 2, 0,
GI.SL_MOSTLY_SKILL)
r(13168, FoolsUp, "Fool's Up", GI.GT_TAROCK, 1, 0, GI.SL_LUCK,
altnames=('Solitairot'))
r(13168, FoolsUp, "Fool's Up", GI.GT_TAROCK, 1, 0, GI.SL_LUCK)
r(13169, TrumpsRow, "Trumps Row", GI.GT_TAROCK, 1, 4, GI.SL_MOSTLY_SKILL,
numcards=73)
r(22232, LeGrandeTeton, 'Le Grande Teton', GI.GT_TAROCK, 1, 0, GI.SL_BALANCED)

View file

@ -348,16 +348,15 @@ class Scorpion_RowStack(Yukon_SS_RowStack, Spider_RowStack):
class Scorpion(RelaxedSpider):
Hint_Class = YukonType_Hint
RowStack_Class = StackWrapper(Scorpion_RowStack, base_rank=KING)
FACEDOWNS = (4, 4, 4, 0, 0, 0)
def createGame(self):
RelaxedSpider.createGame(self, rows=7, playcards=20)
def startGame(self):
for i in self.FACEDOWNS:
for i in (4, 4, 4, 0, 0, 0):
self.s.talon.dealRow(rows=self.s.rows[:i], flip=0, frames=0)
self.s.talon.dealRow(rows=self.s.rows[i:], flip=1, frames=0)
self._startAndDealRow()
@ -380,46 +379,46 @@ class ScorpionTail(Scorpion):
shallHighlightMatch = Game._shallHighlightMatch_AC
# ************************************************************************
# * Double Scorpion
# * Triple Scorpion
# ************************************************************************
class DoubleScorpion(Scorpion):
FACEDOWNS = (5, 5, 5, 5, 0, 0, 0, 0, 0)
Talon_Class = InitialDealTalonStack
def createGame(self):
RelaxedSpider.createGame(self, rows=10, playcards=26, texts=0)
def startGame(self):
for i in (5, 5, 5, 5, 0, 0, 0, 0, 0):
self.s.talon.dealRow(rows=self.s.rows[:i], flip=0, frames=0)
self.s.talon.dealRow(rows=self.s.rows[i:], flip=1, frames=0)
self.startDealSample()
self.s.talon.dealRow()
self.s.talon.dealRowAvail()
class TripleScorpion(Scorpion):
Talon_Class = InitialDealTalonStack
FACEDOWNS = (5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0)
def createGame(self):
RelaxedSpider.createGame(self, rows=13, playcards=30, texts=0)
# ************************************************************************
# * Scorpion II
# ************************************************************************
class ScorpionII(Scorpion):
FACEDOWNS = (3, 3, 3, 0, 0, 0)
def startGame(self):
for i in (5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0):
self.s.talon.dealRow(rows=self.s.rows[:i], flip=0, frames=0)
self.s.talon.dealRow(rows=self.s.rows[i:], flip=1, frames=0)
self._startAndDealRow()
# ************************************************************************
# * Wasp
# * Wasp II
# ************************************************************************
class Wasp(Scorpion):
RowStack_Class = Scorpion_RowStack # anything on an empty space
class WaspII(ScorpionII):
RowStack_Class = Scorpion_RowStack
def startGame(self):
for i in (3, 3, 3, 0, 0, 0):
self.s.talon.dealRow(rows=self.s.rows[:i], flip=0, frames=0)
self.s.talon.dealRow(rows=self.s.rows[i:], flip=1, frames=0)
self._startAndDealRow()
# ************************************************************************
@ -1125,6 +1124,19 @@ class Incompatibility(Spidike):
self._startDealNumRowsAndDealSingleRow(4)
# ************************************************************************
# * Scorpion II
# ************************************************************************
class ScorpionII(Scorpion):
def startGame(self):
for i in (3, 3, 3, 0, 0, 0):
self.s.talon.dealRow(rows=self.s.rows[:i], flip=0, frames=0)
self.s.talon.dealRow(rows=self.s.rows[i:], flip=1, frames=0)
self._startAndDealRow()
# ************************************************************************
# * Tarantula
# ************************************************************************
@ -1659,5 +1671,3 @@ registerGame(GameInfo(917, Astrocyte, "Astrocyte",
registerGame(GameInfo(971, Microbe, "Microbe",
GI.GT_SPIDER | GI.GT_SEPARATE_DECKS, 2, 0,
GI.SL_MOSTLY_SKILL))
registerGame(GameInfo(976, WaspII, "Wasp II",
GI.GT_SPIDER, 1, 0, GI.SL_MOSTLY_SKILL))

View file

@ -51,18 +51,10 @@ class StHelena_Talon(TalonStack):
# move all cards to the Talon and redeal
lr = len(self.game.s.rows)
num_cards = 0
if len(self.cards) > 0:
num_cards = len(self.cards)
self.game.startDealSample()
for i in range(lr):
k = min(lr, len(self.cards))
for j in range(k):
self.game.flipAndMoveMove(self, self.game.s.rows[j], 4)
self.game.stopSamples()
return num_cards
assert len(self.cards) == 0
for r in self.game.s.rows[::-1]:
for i in range(len(r.cards)):
num_cards += 1
num_cards = num_cards + 1
self.game.moveMove(1, r, self, frames=0)
assert len(self.cards) == num_cards
if num_cards == 0: # game already finished
@ -177,32 +169,6 @@ class BoxKite(StHelena):
shallHighlightMatch = Game._shallHighlightMatch_RKW
# ************************************************************************
# * Louis
# ************************************************************************
class Louis(StHelena):
Foundation_Class = SS_FoundationStack
RowStack_Class = StackWrapper(UD_SS_RowStack, base_rank=NO_RANK, mod=13)
shallHighlightMatch = Game._shallHighlightMatch_RKW
def startGame(self):
self.startDealSample()
self.s.talon.dealRow(self.s.foundations)
self.s.talon.dealRow()
def _shuffleHook(self, cards):
return self._shuffleHookMoveToTop(
cards, lambda c: (c.deck == 0 and c.rank in (0, 12),
(-c.rank, c.suit)), 8)
def fillStack(self, stack):
if (self.s.talon.cards and stack in self.s.rows
and len(stack.cards) == 0):
self.s.talon.dealRow(rows=[stack])
# ************************************************************************
# * Les Quatre Coins
@ -486,5 +452,3 @@ registerGame(GameInfo(621, RegalFamily, "Regal Family",
registerGame(GameInfo(859, KingsAudience, "King's Audience",
GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_LUCK,
altnames=("Queen's Audience")))
registerGame(GameInfo(975, Louis, "Louis",
GI.GT_2DECK_TYPE, 2, 2, GI.SL_BALANCED))

View file

@ -472,7 +472,6 @@ class Panopticon(TenAcross):
# ************************************************************************
# * Australian Patience
# * Outback Patience
# * Tasmanian Patience
# * Canberra
# * Raw Prawn
@ -483,9 +482,9 @@ class AustralianPatience(RussianSolitaire):
RowStack_Class = StackWrapper(Yukon_SS_RowStack, base_rank=KING)
def createGame(self, rows=7, max_rounds=1, num_deal=1, playcards=16):
def createGame(self, rows=7, max_rounds=1, num_deal=1):
l, s = Layout(self), self.s
Layout.klondikeLayout(l, rows=rows, waste=1, playcards=playcards)
Layout.klondikeLayout(l, rows=rows, waste=1)
self.setSize(l.size[0], l.size[1])
s.talon = WasteTalonStack(l.s.talon.x, l.s.talon.y, self,
max_rounds=max_rounds, num_deal=num_deal)
@ -501,14 +500,6 @@ class AustralianPatience(RussianSolitaire):
self._startDealNumRowsAndDealRowAndCards(3)
class OutbackPatience(AustralianPatience):
def createGame(self):
AustralianPatience.createGame(self, rows=8, playcards=25)
def startGame(self):
self._startDealNumRowsAndDealRowAndCards(6)
class TasmanianPatience(AustralianPatience):
def createGame(self):
AustralianPatience.createGame(self, max_rounds=-1, num_deal=3)
@ -904,7 +895,8 @@ registerGame(GameInfo(387, Roslin, "Roslin",
GI.GT_YUKON, 1, 0, GI.SL_MOSTLY_SKILL,
altnames=("Roslyn",)))
registerGame(GameInfo(447, AustralianPatience, "Australian Patience",
GI.GT_YUKON, 1, 0, GI.SL_BALANCED))
GI.GT_YUKON, 1, 0, GI.SL_BALANCED,
altnames=('Outback Patience',)))
registerGame(GameInfo(450, RawPrawn, "Raw Prawn",
GI.GT_YUKON, 1, 0, GI.SL_BALANCED))
registerGame(GameInfo(456, BimBom, "Bim Bom",
@ -917,8 +909,6 @@ registerGame(GameInfo(492, Geoffrey, "Geoffrey",
GI.GT_YUKON, 1, 0, GI.SL_MOSTLY_SKILL))
registerGame(GameInfo(525, Queensland, "Queensland",
GI.GT_YUKON, 1, 0, GI.SL_BALANCED))
registerGame(GameInfo(526, OutbackPatience, "Outback Patience",
GI.GT_YUKON, 2, 0, GI.SL_BALANCED))
registerGame(GameInfo(530, RussianSpider, "Russian Spider",
GI.GT_SPIDER, 1, 0, GI.SL_BALANCED,
altnames=('Ukrainian Solitaire',)))

View file

@ -571,7 +571,7 @@ class LOptionsMenuGenerator(LTreeGenerator):
LTreeNode(text=_('Automatic play')))
if rg:
self.addCheckNode(tv, rg,
_('Auto face-up'),
_('Auto face up'),
self.menubar.tkopt.autofaceup,
self.menubar.mOptAutoFaceUp)

View file

@ -456,7 +456,7 @@ class AShuffleStackMove(AtomicMove):
def redo(self, game):
stack = game.allstacks[self.stack_id]
# paranoia
assert stack is game.s.talon or stack in game.s.internals
assert stack is game.s.talon
# shuffle (see random)
game.random.setstate(self.state)
seq = stack.cards

View file

@ -259,7 +259,7 @@ class PysolMenubarTk:
]
for label, action, opt_name, update_game in (
('A&uto drop', 'optautodrop', 'autodrop', False),
('Auto &face-up', '', 'autofaceup', False),
('Auto &face up', '', 'autofaceup', False),
('Auto &deal', '', 'autodeal', False),
('&Quick play', '', 'quickplay', False),
('Enable &undo', '', 'undo', False),

View file

@ -353,6 +353,7 @@ class SelectCardsetDialogWithPreview(MfxDialog):
check = ttk.Checkbutton(
size_frame, text=_('Auto scaling'),
variable=self.auto_scale,
takefocus=False,
command=self._updateAutoScale
)
check.grid(row=5, column=0, columnspan=2, sticky='ew',
@ -363,6 +364,7 @@ class SelectCardsetDialogWithPreview(MfxDialog):
self.aspect_check = ttk.Checkbutton(
size_frame, text=_('Preserve aspect ratio'),
variable=self.preserve_aspect,
takefocus=False,
# command=self._updateScale
)
self.aspect_check.grid(row=6, column=0, sticky='ew',

View file

@ -109,7 +109,7 @@ class SoundOptionsDialog(MfxDialog):
ttk.Label(frame, text=_('Sample volume:'), anchor='w'
).grid(row=row, column=0, sticky='ew')
w = PysolScale(frame, from_=0, to=128, resolution=1,
orient='horizontal',
orient='horizontal', takefocus=0,
length="3i", # label=_('Sample volume'),
variable=self.sample_volume)
w.grid(row=row, column=1, sticky='w', padx=5)
@ -122,7 +122,7 @@ class SoundOptionsDialog(MfxDialog):
ttk.Label(frame, text=_('Music volume:'), anchor='w'
).grid(row=row, column=0, sticky='ew')
w = PysolScale(frame, from_=0, to=128, resolution=1,
orient='horizontal',
orient='horizontal', takefocus=0,
length="3i", # label=_('Music volume'),
variable=self.music_volume)
w.grid(row=row, column=1, sticky='w', padx=5)

View file

@ -72,7 +72,7 @@ class TimeoutsDialog(MfxDialog):
row=row, column=0, sticky='we')
widget = PysolScale(lframe, from_=0.2, to=9.9, value=var.get(),
resolution=0.1, orient='horizontal',
length="3i", variable=var)
length="3i", variable=var, takefocus=0)
widget.grid(row=row, column=1)
row += 1
#

View file

@ -105,7 +105,8 @@ class WizardDialog(MfxDialog):
elif w.widget == 'check':
if w.variable is None:
w.variable = tkinter.BooleanVar()
ch = ttk.Checkbutton(frame, variable=w.variable)
ch = ttk.Checkbutton(frame, variable=w.variable,
takefocus=False)
ch.grid(row=row, column=1, sticky='ew', padx=2, pady=2)
if w.current_value is None:

View file

@ -271,6 +271,7 @@ class SelectCardsetDialogWithPreview(MfxDialog):
check = tkinter.Checkbutton(
left_frame, text=_('Auto scaling'),
variable=self.auto_scale,
takefocus=False,
command=self._updateAutoScale
)
check.grid(row=3, column=0, columnspan=2, sticky='w',
@ -281,6 +282,7 @@ class SelectCardsetDialogWithPreview(MfxDialog):
self.aspect_check = tkinter.Checkbutton(
left_frame, text=_('Preserve aspect ratio'),
variable=self.preserve_aspect,
takefocus=False,
# command=self._updateScale
)
self.aspect_check.grid(row=4, column=0, sticky='w',

View file

@ -109,7 +109,7 @@ class SoundOptionsDialog(MfxDialog):
w = tkinter.Label(frame, text=_('Sample volume:'))
w.grid(row=row, column=0, sticky='w', padx=5)
w = tkinter.Scale(frame, from_=0, to=128, resolution=1,
orient='horizontal',
orient='horizontal', takefocus=0,
length="3i", # label=_('Sample volume'),
variable=self.sample_volume)
w.grid(row=row, column=1, sticky='ew', padx=5)
@ -117,7 +117,7 @@ class SoundOptionsDialog(MfxDialog):
w = tkinter.Label(frame, text=_('Music volume:'))
w.grid(row=row, column=0, sticky='w', padx=5)
w = tkinter.Scale(frame, from_=0, to=128, resolution=1,
orient='horizontal',
orient='horizontal', takefocus=0,
length="3i", # label=_('Music volume'),
variable=self.music_volume)
w.grid(row=row, column=1, sticky='ew', padx=5)

View file

@ -71,7 +71,7 @@ class TimeoutsDialog(MfxDialog):
).grid(row=row, column=0, sticky='we')
widget = tkinter.Scale(frame, from_=0.2, to=9.9,
resolution=0.1, orient='horizontal',
length="3i", variable=var)
length="3i", variable=var, takefocus=0)
widget.grid(row=row, column=1)
row += 1
#

View file

@ -94,7 +94,7 @@ class WizardDialog(MfxDialog):
if w.variable is None:
w.variable = tkinter.BooleanVar()
ch = tkinter.Checkbutton(frame, variable=w.variable,
anchor='w')
takefocus=False, anchor='w')
ch.grid(row=row, column=1, sticky='ew', padx=2, pady=2)
if w.current_value is None:

View file

@ -614,15 +614,14 @@ class PysolMenubarTkCommon:
menu.add_command(
label=n_("&Statistics..."),
command=self.mPlayerStats, accelerator=m+"T")
menu.add_command(
label=n_("Log..."),
command=lambda: self.mPlayerStats(mode=103))
menu.add_separator()
menu.add_command(
label=n_("D&emo statistics..."),
command=lambda: self.mPlayerStats(mode=1101))
menu.add_command(
label=n_("Demo log..."),
label=n_("Log..."),
command=lambda: self.mPlayerStats(mode=103))
menu.add_command(
label=n_("Demo Log..."),
command=lambda: self.mPlayerStats(mode=1103))
menu.add_separator()
menu.add_command(
@ -667,7 +666,7 @@ class PysolMenubarTkCommon:
command=self.mOptPlayerOptions, accelerator=m+'P')
submenu = MfxMenu(menu, label=n_("&Automatic play"))
submenu.add_checkbutton(
label=n_("Auto &face-up"), variable=self.tkopt.autofaceup,
label=n_("Auto &face up"), variable=self.tkopt.autofaceup,
command=self.mOptAutoFaceUp)
submenu.add_checkbutton(
label=n_("A&uto drop"), variable=self.tkopt.autodrop,

View file

@ -65,14 +65,6 @@ class ImportFileTests(unittest.TestCase):
'''<state><move pile="store0" position="0">'''
'''<card id="[0-9]+" rank="four"'''
''' suit="clubs" turn="face-up"></card>'''
'''<card id="[0-9]+" rank="two"'''
''' suit="clubs" turn="face-up"></card>'''
'''<card id="[0-9]+" rank="nine"'''
''' suit="clubs" turn="face-up"></card>'''
'''<card id="[0-9]+" rank="eight"'''
''' suit="clubs" turn="face-up"></card>'''
'''<card id="[0-9]+" rank="queen"'''
''' suit="spades" turn="face-up"></card>'''
),
blurb='xml import worked')