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

Compare commits

...

42 commits

Author SHA1 Message Date
Joe R
bdd3093a2b Compress tile images 2025-03-30 15:42:45 -04:00
Joe R
c4a62baf79 Add Cribbage Patience II game 2025-03-30 14:04:18 -04:00
Joe R
b1370fce08 Add more alternate names 2025-03-25 19:09:39 -04:00
Joe R
7b85049f7c Add Flamboyant game 2025-03-25 17:42:31 -04:00
Joe R
afc74a86f5 Remove extra paragraph tags to improve documentation formatting 2025-03-23 19:41:21 -04:00
Joe R
50e003e256 Add Ace of Penguins to the compatibility list 2025-03-17 19:44:23 -04:00
Joe R
78de569074 Fix for the total text crashing Ninety-One on Android (#436) 2025-03-17 18:04:38 -04:00
Joe R
a79c81109b Fix binding error in Kivy 2025-03-15 20:11:50 -04:00
Joe R
c14be7b73e Add Wizard's Castle game 2025-03-14 22:09:56 -04:00
Joe R
69c1440b2b Improve display details of cardset info window 2025-03-14 19:21:14 -04:00
Joe R
72386af5e6 Configure highlight matching for more games 2025-03-10 22:02:24 -04:00
Joe R
a57f1eae38 Add Noumea game 2025-03-10 19:47:40 -04:00
Shlomi Fish
6f0c6e00e1
Condition "chdir" in script dir being local. (#434)
So "python3 scripts/linux-install.py" as documented in README will work.
2025-03-09 19:44:55 -04:00
Joe R
512d3ea466 Improve new Mahjongg layouts 2025-03-06 23:13:43 -05:00
Joe R
e7e9f0ff87 Configure topmost dialogs to not stay on top when PySol loses focus 2025-03-06 22:38:13 -05:00
Joe R
9773eee2d6 Add Wizard's Storeroom game 2025-03-03 21:28:35 -05:00
Joe R
015e860557 Fix endgame hints for Crossword 2025-03-03 19:37:54 -05:00
Joe R
04b7eacfcb Fix highlight match logic for Nines/Tens/Elevens 2025-03-01 22:24:17 -05:00
Joe R
52e2ffc58f Add two mahjongg layouts 2025-03-01 16:17:53 -05:00
Joe R
81150b4681 Add Relaxed Cruel game 2025-02-26 19:55:01 -05:00
Joe R
f799093e35 Restore unfinished Thirteen game as Pyramid Thirteen, using correct AisleRiot rules 2025-02-23 22:32:22 -05:00
Joe R
12118d12ed Clean up Scorpion type games 2025-02-23 14:18:08 -05:00
Joe R
fd4a4e1378 Fill in missing translated names 2025-02-20 18:59:01 -05:00
Joe R
63a63fdfd3 Add Louis game 2025-02-20 18:47:21 -05:00
Joe R
ff9cc5e98c Add FAQ to the in-app documentation 2025-02-20 17:26:10 -05:00
Joe R
cadf8b2084 Fix some controls being unselectable by tab 2025-02-18 19:16:04 -05:00
Joe R
f4dec3ed16 Add Ides of March game 2025-02-17 21:24:26 -05:00
Joe R
5c8d5c26b4 Cleanup 2025-02-17 20:49:25 -05:00
Joe R
cb0dd1ec2f Add definition of super move to the glossary 2025-02-13 21:09:17 -05:00
Joe R
dc5ab96c80 Add Families game 2025-02-13 20:55:16 -05:00
Joe R
54a978b4e2 Fix flake8 2025-02-11 21:56:10 -05:00
Joe R
5b9f64a7eb Support alternate names for alternate deck games 2025-02-11 21:39:43 -05:00
Joe R
21c2780e8e Tweak menu text for consistency 2025-02-06 21:56:32 -05:00
Joe R
ed2da8cd46 Restore lost Outback Patience game, with the correct rules 2025-02-06 19:59:16 -05:00
Joe R
054c0f0368 Enable log for demo games 2025-01-28 23:32:15 -05:00
Joe R
487d1c52f3 Use Python 3.13 in AppVeyor 2025-01-28 19:38:23 -05:00
Joe R
6852bb40ff Add Little Ishido game 2025-01-24 21:58:56 -05:00
Joe R
6006e0f4c0 Shift children's games to use tag rather than deprecated list 2025-01-24 20:03:08 -05:00
Joe R
68138c7284 Add Colours game 2025-01-23 18:01:20 -05:00
Joe R
96a06108af Fix flake8 2025-01-20 21:06:13 -05:00
Joe R
ac03fa741d Add Microbe game 2025-01-20 20:18:32 -05:00
Joe R
7cac54b714 Add more alternate names 2025-01-20 19:25:16 -05:00
105 changed files with 1666 additions and 528 deletions

View file

@ -2,7 +2,7 @@
image: Visual Studio 2022 image: Visual Studio 2022
environment: environment:
matrix: matrix:
- PYTHON: "C:\\Python312" - PYTHON: "C:\\Python313"
# Shamelessly taken from https://github.com/plicease/Dist-Zilla-PluginBundle-Author-Plicease/blob/master/.appveyor.yml # Shamelessly taken from https://github.com/plicease/Dist-Zilla-PluginBundle-Author-Plicease/blob/master/.appveyor.yml
# Thanks! # Thanks!
install: install:

BIN
data/tiles/Felt_Blue.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 351 B

After

Width:  |  Height:  |  Size: 350 B

View file

@ -38,42 +38,18 @@ back01.ext;back02.ext;back03.ext</pre>
<p><b>$B:</b> The type of the cardset (see types below)</p> <p><b>$B:</b> The type of the cardset (see types below)</p>
<h3>Cardsets Types:</h3> <h3>Cardsets Types:</h3>
<ul> <ul>
<li> <li>French = 1</li>
<p>French = 1</p> <li>Hanafuda = 2</li>
</li> <li>Tarock = 3</li>
<li> <li>Mahjongg = 4</li>
<p>Hanafuda = 2</p> <li>Hex A Deck = 5</li>
</li> <li>Mughal Ganjifa = 6</li>
<li> <li>Navagraha Ganjiga = 7</li>
<p>Tarock = 3</p> <li>Dashavatara Ganjifa = 8</li>
</li> <li>Trumps Only = 9</li>
<li> <li>Matching = 10</li>
<p>Mahjongg = 4</p> <li>Puzzle = 11</li>
</li> <li>Ishido = 12</li>
<li>
<p>Hex A Deck = 5</p>
</li>
<li>
<p>Mughal Ganjifa = 6</p>
</li>
<li>
<p>Navagraha Ganjiga = 7</p>
</li>
<li>
<p>Dashavatara Ganjifa = 8</p>
</li>
<li>
<p>Trumps Only = 9</p>
</li>
<li>
<p>Matching = 10</p>
</li>
<li>
<p>Puzzle = 11</p>
</li>
<li>
<p>Ishido = 12</p>
</li>
</ul> </ul>
<p><b>$C:</b> The number of cards in the cardset, generally 42, <p><b>$C:</b> The number of cards in the cardset, generally 42,
48, 52, 68, 78, 96 or 120</p> 48, 52, 68, 78, 96 or 120</p>
@ -81,190 +57,70 @@ back01.ext;back02.ext;back03.ext</pre>
or more comma separated values)</p> or more comma separated values)</p>
<h3>Cardsets Styles:</h3> <h3>Cardsets Styles:</h3>
<ul> <ul>
<li> <li>Abstract = 35</li>
<p>Abstract = 35</p> <li>Adult = 1</li>
</li> <li>Animals = 2</li>
<li> <li>Anime = 3</li>
<p>Adult = 1</p> <li>Art = 4</li>
</li> <li>Cartoons = 5</li>
<li> <li>Children = 6</li>
<p>Animals = 2</p> <li>Classic Look = 7</li>
</li> <li>Collectors = 8</li>
<li> <li>Computers = 9</li>
<p>Anime = 3</p> <li>Divination = 36</li>
</li> <li>Engines = 10</li>
<li> <li>Fantasy = 11</li>
<p>Art = 4</p> <li>Four Color = 37</li>
</li> <li>Ganjifa= 30</li>
<li> <li>Hanafuda = 12</li>
<p>Cartoons = 5</p> <li>Hex A Deck = 29</li>
</li> <li>Holiday = 13</li>
<li> <li>Ishido = 34</li>
<p>Children = 6</p> <li>Mahjongg = 28</li>
</li> <li>Matching = 32</li>
<li> <li>Monochrome = 38</li>
<p>Classic Look = 7</p> <li>Movies = 14</li>
</li> <li>Matrix = 31</li>
<li> <li>Music = 15</li>
<p>Collectors = 8</p> <li>Nature = 16</li>
</li> <li>Operating Systems = 17</li>
<li> <li>People = 19</li>
<p>Computers = 9</p> <li>Places = 20</li>
</li> <li>Plain = 21</li>
<li> <li>Products = 22</li>
<p>Divination = 36</p> <li>Puzzle = 33</li>
</li> <li>Round Cardsets = 18</li>
<li> <li>Science Fiction = 23</li>
<p>Engines = 10</p> <li>Sports = 24</li>
</li> <li>Tarock = 27</li>
<li> <li>Vehicles = 25</li>
<p>Fantasy = 11</p> <li>Video Games = 26</li>
</li>
<li>
<p>Four Color = 37</p>
</li>
<li>
<p>Ganjifa= 30</p>
</li>
<li>
<p>Hanafuda = 12</p>
</li>
<li>
<p>Hex A Deck = 29</p>
</li>
<li>
<p>Holiday = 13</p>
</li>
<li>
<p>Ishido = 34</p>
</li>
<li>
<p>Mahjongg = 28</p>
</li>
<li>
<p>Matching = 32</p>
</li>
<li>
<p>Monochrome = 38</p>
</li>
<li>
<p>Movies = 14</p>
</li>
<li>
<p>Matrix = 31</p>
</li>
<li>
<p>Music = 15</p>
</li>
<li>
<p>Nature = 16</p>
</li>
<li>
<p>Operating Systems = 17</p>
</li>
<li>
<p>People = 19</p>
</li>
<li>
<p>Places = 20</p>
</li>
<li>
<p>Plain = 21</p>
</li>
<li>
<p>Products = 22</p>
</li>
<li>
<p>Puzzle = 33</p>
</li>
<li>
<p>Round Cardsets = 18</p>
</li>
<li>
<p>Science Fiction = 23</p>
</li>
<li>
<p>Sports = 24</p>
</li>
<li>
<p>Tarock = 27</p>
</li>
<li>
<p>Vehicles = 25</p>
</li>
<li>
<p>Video Games = 26</p>
</li>
</ul> </ul>
<p><b>$E:</b> The origin (country) of the cardset</p> <p><b>$E:</b> The origin (country) of the cardset</p>
<h3>Cardsets Origins:</h3> <h3>Cardsets Origins:</h3>
<ul> <ul>
<li> <li>Australia = 1021</li>
<p>Australia = 1021</p> <li>Austria = 1001</li>
</li> <li>Belgium = 1019</li>
<li> <li>Canada = 1010</li>
<p>Austria = 1001</p> <li>China = 1011</li>
</li> <li>Czech Republic = 1012</li>
<li> <li>Denmark = 1013</li>
<p>Belgium = 1019</p> <li>England = 1003</li>
</li> <li>France = 1004</li>
<li> <li>Germany = 1006</li>
<p>Canada = 1010</p> <li>Great Britain = 1014</li>
</li> <li>Hungary = 1015</li>
<li> <li>India = 1020</li>
<p>China = 1011</p> <li>Italy = 1005</li>
</li> <li>Japan = 1016</li>
<li> <li>Netherlands = 1002</li>
<p>Czech Republic = 1012</p> <li>Portugal = 1022</li>
</li> <li>Russia = 1007</li>
<li> <li>Spain = 1008</li>
<p>Denmark = 1013</p> <li>Sweden = 1017</li>
</li> <li>Switzerland = 1009</li>
<li> <li>USA = 1018</li>
<p>England = 1003</p>
</li>
<li>
<p>France = 1004</p>
</li>
<li>
<p>Germany = 1006</p>
</li>
<li>
<p>Great Britain = 1014</p>
</li>
<li>
<p>Hungary = 1015</p>
</li>
<li>
<p>India = 1020</p>
</li>
<li>
<p>Italy = 1005</p>
</li>
<li>
<p>Japan = 1016</p>
</li>
<li>
<p>Netherlands = 1002</p>
</li>
<li>
<p>Portugal = 1022</p>
</li>
<li>
<p>Russia = 1007</p>
</li>
<li>
<p>Spain = 1008</p>
</li>
<li>
<p>Sweden = 1017</p>
</li>
<li>
<p>Switzerland = 1009</p>
</li>
<li>
<p>USA = 1018</p>
</li>
</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>
@ -284,31 +140,16 @@ back01.ext;back02.ext;back03.ext</pre>
will be truncated.</p> will be truncated.</p>
<h2>Line 3</h2> <h2>Line 3</h2>
<ul> <ul>
<li> <li><b>X:</b> The cards' width (the card image width)</li>
<p><b>X:</b> The cards' width (the card image width)</p> <li><b>Y:</b> The cards' height (the card image height)</li>
</li> <li><b>D:</b> The color depth (mostly 8)</li>
<li>
<p><b>Y:</b> The cards' height (the card image height)</p>
</li>
<li>
<p><b>D:</b> The color depth (mostly 8)</p>
</li>
</ul> </ul>
<h2>Line 4</h2> <h2>Line 4</h2>
<ul> <ul>
<li> <li><b>XOFF:</b> The horizontal offset of the cards</li>
<p><b>XOFF:</b> The horizontal offset of the cards</p> <li><b>YOFF:</b> The vertical offset of the cards</li>
</li> <li><b>SXOFF:</b> The offset of the horizontal shadow (mostly 7)</li>
<li> <li><b>SYOFF:</b> The offset of the vertical shadow (mostly 7)</li>
<p><b>YOFF:</b> The vertical offset of the cards</p>
</li>
<li>
<p><b>SXOFF:</b> The offset of the horizontal shadow (mostly
7)</p>
</li>
<li>
<p><b>SYOFF:</b> The offset of the vertical shadow (mostly 7)</p>
</li>
</ul> </ul>
<h2>Line 5</h2> <h2>Line 5</h2>
<p><code>back01.ext</code>: The name of the default back image (where <code>ext</code> means the file extension e.g: <code>png</code> or <code>gif</code>.)</p> <p><code>back01.ext</code>: The name of the default back image (where <code>ext</code> means the file extension e.g: <code>png</code> or <code>gif</code>.)</p>
@ -330,7 +171,9 @@ back01.ext;back02.ext;back03.ext</pre>
<a href="https://github.com/shlomif/shlomif-computer-settings/blob/master/shlomif-settings/git/commit-messages/cc0-copyright-disclaimer.txt">CC0/Public Domain/MIT License/GPL terms</a></p> <a href="https://github.com/shlomif/shlomif-computer-settings/blob/master/shlomif-settings/git/commit-messages/cc0-copyright-disclaimer.txt">CC0/Public Domain/MIT License/GPL terms</a></p>
<h3>Credits:</h3> <h3>Credits:</h3>
<p>Credits go to:</p> <p>Credits go to:</p>
<p><a href="mailto:andsa@web.de">Andreas Sauer</a> for clarifying certain <ul>
points<br></p> <li><a href="mailto:andsa@web.de">Andreas Sauer</a> for clarifying certain
<p><a href="https://www.shlomifish.org/">Shlomi Fish</a> for making some points</li>
improvements to this tutorial</p> <li><a href="https://www.shlomifish.org/">Shlomi Fish</a> for making some
improvements to this tutorial</li>
</ul>

64
html-src/faq.html Normal file
View file

@ -0,0 +1,64 @@
<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,6 +46,7 @@ fix_gettext()
files = [ files = [
('credits.html', 'PySol Credits'), ('credits.html', 'PySol Credits'),
('credits_old.html', 'PySol Credits'), ('credits_old.html', 'PySol Credits'),
('faq.html', 'PySol - FAQ'),
('ganjifa.html', 'PySol - General Ganjifa Card Rules'), ('ganjifa.html', 'PySol - General Ganjifa Card Rules'),
('general_rules.html', 'PySol - General Rules'), ('general_rules.html', 'PySol - General Rules'),
('glossary.html', 'PySol - Glossary'), ('glossary.html', 'PySol - Glossary'),

View file

@ -323,6 +323,15 @@ the deck.</p>
Hearts, and Diamonds.</p> Hearts, and Diamonds.</p>
</dd> </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> <dt><b>TABLEAU</b></dt>
<dd> <dd>

View file

@ -55,27 +55,6 @@ 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). The logic involved is not too clever on purpose (i.e. it does not consult the hint system).
</ul> </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> <h2>Some notes about scoring</h2>
<p> <p>
<ul type="disc"> <ul type="disc">

View file

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

View file

@ -1,10 +1,9 @@
<h1>Report a Bug</h1> <h1>Report a Bug</h1>
<p> <p>
Before you report a bug, please verify that you are running Before you report a bug, please verify that you are running
the latest version of PySolFC, and also check the PySolFC site's the latest version of PySolFC. Also, check the
<a href="https://pysolfc.sourceforge.io/faq.html">FAQ page</a>, <a href="faq.html">FAQ</a>, and issues previously reported
and issues previously reported on GitHub, to ensure that the bug on GitHub, to ensure that the bug was not previously reported.
was not previously reported.
<p> <p>
If you found a bug in PySolFC, the best place to report it If you found a bug in PySolFC, the best place to report it
is on GitHub. To do so, create an issue at 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> <h3>Notes</h3>
<p> <p>
Accordion's Revenge is unwinnable if the first or second card is Accordion's Revenge is unwinnable if the first or second card is
declared. As such, PySol will reselect the declared card if it declared. As such, PySol will never select either of those cards as
is chosen. the target.
<p> <p>
The concept of Accordion's Revenge was invented by Mark Masten. The concept of Accordion's Revenge was invented by Mark Masten.

View file

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

View file

@ -0,0 +1,13 @@
<h1>Big Storeroom</h1>
<p>
Hex A Deck type. 2 decks. 1 redeal.
<h3>Object</h3>
<p>
Move all cards to the foundations.
<h3>Rules</h3>
<p>
Like <a href="wizardsstoreroom.html">Wizard's Storeroom</a>
but with two decks and nine piles.

View file

@ -0,0 +1,15 @@
<h1>Colours</h1>
<p>
Numerica type. 1 deck. No redeal.
<h3>Object</h3>
<p>
Move all cards to the foundations.
<h3>Quick Description</h3>
<p>
Like <a href="ladybetty.html">Lady Betty</a>,
but the foundations are built up by same color, and
wrap from king to ace. At the start of the game, a
two through five are dealt to the foundations, in
alternating colors.

View file

@ -4,7 +4,7 @@ Cribbage type. 1 deck. No redeal.
<h3>Object</h3> <h3>Object</h3>
<p> <p>
Deal five cribbage hands to get a total score of 61 points or more. Deal five cribbage hands to get a total score of 80 points or more.
<h3>Rules</h3> <h3>Rules</h3>
<p> <p>
@ -16,7 +16,8 @@ Points are awarded for the 2 Cribbage hands: the remaining four cards, plus
the four cards in the crib. the four cards in the crib.
<p> <p>
After each hand, repeat the process four more times to deal a total of five After each hand, repeat the process four more times to deal a total of five
hands. You win if after all five hands, your score reaches 61 points. hands. You win if after all five hands, your score reaches 80 points.
<h3>Cribbage Scoring</h3> <h3>Cribbage Scoring</h3>
<p> <p>
Cribbage hands are scored as follows - each hand is worth the total value Cribbage hands are scored as follows - each hand is worth the total value

View file

@ -0,0 +1,18 @@
<h1>Cribbage Patience II</h1>
<p>
Cribbage type. 1 deck. No redeal.
<h3>Object</h3>
<p>
Deal four cribbage hands to get a total score of 80 points or more.
<h3>Quick Description</h3>
<p>
Like <a href="cribbagepatience.html">Cribbage Patience</a>,
but two cards are not dealt face-down to the crib. After moving two
cards from the hand to the crib, a second six-card hand is dealt, and
you move two cards from that hand to finish the crib. Then, all
three hands are scored.
<p>
Due to the increased number of cards per hand, only four hands are dealt
per game.

View file

@ -0,0 +1,27 @@
<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

@ -0,0 +1,22 @@
<h1>Flamboyant</h1>
<p>
Fan game type. 1 deck. No redeal.
<h3>Object</h3>
<p>
Move all cards to the foundations.
<h3>Rules</h3>
<p>
The tableau piles are built in seventeen sets of three cards, with
two in the back row face-down, and a third face-up card overlapping
them. The final card is dealt separately.
<p>
The tableau piles are built down by alternate color, with any face-up card
or valid sequence of cards being movable. Once the top card is moved,
the two below it can be flipped face-up and played. Empty piles cannot
be filled, except for the final single card, where a king or sequence of
cards starting with a king can be played.
<p>
Foundations are built up in suit from Ace to King. The game is won
when all cards are moved to the foundations.

View file

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

View file

@ -0,0 +1,12 @@
<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

@ -0,0 +1,12 @@
<h1>Little Ishido</h1>
<p>
Ishido game type. 2 decks. No redeal.
<h3>Object</h3>
<p>
Move all tiles to the playing area.
<h3>Quick Description</h3>
<p>
Like <a href='ishido.html'>Ishido</a>, but with four colors and symbols,
and a 6X8 grid. The initial tiles are placed in the four corners only.

View file

@ -0,0 +1,14 @@
<h1>Little Ishido Relaxed</h1>
<p>
Ishido game type. 2 decks. No redeal.
<h3>Object</h3>
<p>
Move all tiles to the playing area.
<h3>Quick Description</h3>
<p>
Like <a href='ishido.html'>Ishido</a>, but with four colors and symbols,
and a 6X8 grid. The initial tiles are placed in the four corners only.
Also, there are no restrictions when placing a tile next to two or more
other tiles - they just have to match the color or symbol of each.

19
html-src/rules/louis.html Normal file
View file

@ -0,0 +1,19 @@
<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

@ -0,0 +1,27 @@
<h1>Microbe</h1>
<p>
Spider type. 2 decks. No redeal.
<h3>Object</h3>
<p>
Group all the cards in sets of 13 cards in descending sequence
by alternate color from King to Ace and move such sets to the foundations.
<h3>Rules</h3>
<p>
The decks are separated. From one deck, four cards are dealt to each of
eleven tableau piles, with alternating cards face-up and face-down (the
bottom and third from the bottom cards are face-down). The remaining
eight cards from that deck are combined with the other deck to form the
talon.
<p>
Tableau piles are built down by alternate color, and any card or valid
sequence of cards can be moved between tableau piles. Any valid card or
sequence can fill empty piles.
<p>
The object is to group the cards in sets of 13 cards, from King to Ace
in an alternating color sequence. Such groups can be moved to the foundations.
<p>
When there are no moves left, you can deal one card from the talon to
each tableau pile. The game is won if all cards are grouped into sequences
and moved to the foundations.

View file

@ -0,0 +1,27 @@
<h1>Noumea</h1>
<p>
One-Deck game type. 1 decks. 2 redeals.
<h3>Object</h3>
<p>
Move all cards to the foundations.
<h3>Rules</h3>
<p>
The four aces are dealt to the foundations, and 20 cards
are dealt to reserve piles. The reserve piles can hold a
single card and are automatically filled from the waste or
talon when empty.
<p>
There is no building on the tableau piles, so you can
only move cards to the foundations.
<p>
When there are no moves left, you can deal cards three at
a time from the talon, and move them to an appropriate
foundation. Two redeals are allowed, so you can go through
the deck three times. The game is won if all cards are
moved to the foundations.
<h3>Notes</h3>
<p>
<i>Autodrop</i> is disabled for this game.

View file

@ -0,0 +1,12 @@
<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

@ -0,0 +1,22 @@
<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

@ -0,0 +1,12 @@
<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

@ -0,0 +1,13 @@
<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

@ -0,0 +1,15 @@
<h1>Wizard's Castle</h1>
<p>
Hex A Deck type. 1 deck. No redeal.
<h3>Object</h3>
<p>
Move all cards to the foundations.
<h3>Rules</h3>
<p>
Rows build down in rank in alternating color. Wizards are wild,
so any card can be played on one, and a wizard can be played on
any card. Only one card can be moved at a time. Foundations build
up in rank by suit. Any card can be played on an empty row. Cards
can be played from the foundations.

View file

@ -0,0 +1,23 @@
<h1>Wizard's Storeroom</h1>
<p>
Hex A Deck type. 1 deck. 1 redeal.
<h3>Object</h3>
<p>
Move all cards to the foundations.
<h3>Rules</h3>
<p>
The tableau consists of one reserve stack and five row stacks.
Fourteen cards are dealt to the reserve stack and one card each to the
row stacks. When a row stack is emptied it must be filled from the reserve
stack first. When the reserve stack is empty any card can be played on an
empty row stack. Wizards are wild - any card can be played on them, and they
can be played on any card. The Wizards have ranks like the suit cards
corresponding to Ace through Four. If a Wizard is played in it's proper rank
position the row can still be moved, otherwise, the full sequence can't be moved.
The row stacks build down in rank by alternate colors.
<p>
The foundations build up in rank by suit. The Wizards will not move off of the
tableau until all the other cards have been moved to the foundations.
The game is won when all cards are moved to the foundations.

View file

@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: PySol 0.0.1\n" "Project-Id-Version: PySol 0.0.1\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-12-10 10:19-0500\n" "POT-Creation-Date: 2021-12-10 10:19-0500\n"
"PO-Revision-Date: 2024-12-28 19:10-0500\n" "PO-Revision-Date: 2025-03-14 19:16-0400\n"
"Last-Translator: H. Schaekel <Holger.Schaekel@web.de>\n" "Last-Translator: H. Schaekel <Holger.Schaekel@web.de>\n"
"Language-Team: German\n" "Language-Team: German\n"
"Language: de\n" "Language: de\n"
@ -2653,7 +2653,7 @@ msgid "Automatic play"
msgstr "Automatisierung" msgstr "Automatisierung"
#: pysollib/kivy/menubar.py:513 #: pysollib/kivy/menubar.py:513
msgid "Auto face up" msgid "Auto face-up"
msgstr "Automatisch aufdecken" msgstr "Automatisch aufdecken"
#: pysollib/kivy/menubar.py:523 #: pysollib/kivy/menubar.py:523
@ -4189,6 +4189,9 @@ msgstr "Nationalität:"
msgid "Year:" msgid "Year:"
msgstr "Jahr:" msgstr "Jahr:"
msgid "Num. cards:"
msgstr ""
msgid "Compatible with current game" msgid "Compatible with current game"
msgstr "" msgstr ""
@ -4370,6 +4373,9 @@ msgstr "Aktuelle Sitzung"
msgid "Log" msgid "Log"
msgstr "Protokoll" msgstr "Protokoll"
msgid "Demo Log"
msgstr ""
#: pysollib/tile/tkstats.py:523 data/pysolfc.glade:1404 #: pysollib/tile/tkstats.py:523 data/pysolfc.glade:1404
msgid "Full log" msgid "Full log"
msgstr "Volles Protokoll" msgstr "Volles Protokoll"
@ -5171,6 +5177,9 @@ msgstr "Kommentare..."
msgid "Log..." msgid "Log..."
msgstr "" msgstr ""
msgid "Demo log..."
msgstr ""
#: pysollib/ui/tktile/menubar.py:427 #: pysollib/ui/tktile/menubar.py:427
msgid "D&emo statistics..." msgid "D&emo statistics..."
msgstr "D&emo Statistiken..." msgstr "D&emo Statistiken..."

View file

@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: 1.02\n" "Project-Id-Version: 1.02\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-12-10 10:19-0500\n" "POT-Creation-Date: 2021-12-10 10:19-0500\n"
"PO-Revision-Date: 2024-12-28 19:10-0500\n" "PO-Revision-Date: 2025-03-14 19:16-0400\n"
"Last-Translator: Eric Rausch <neelix570@gmail.com>\n" "Last-Translator: Eric Rausch <neelix570@gmail.com>\n"
"Language-Team: French\n" "Language-Team: French\n"
"Language: fr\n" "Language: fr\n"
@ -2694,7 +2694,7 @@ msgid "Automatic play"
msgstr "Jouer auto" msgstr "Jouer auto"
#: pysollib/kivy/menubar.py:513 #: pysollib/kivy/menubar.py:513
msgid "Auto face up" msgid "Auto face-up"
msgstr "Retourner auto" msgstr "Retourner auto"
#: pysollib/kivy/menubar.py:523 #: pysollib/kivy/menubar.py:523
@ -4240,6 +4240,9 @@ msgstr "Origine:"
msgid "Year:" msgid "Year:"
msgstr "Année:" msgstr "Année:"
msgid "Num. cards:"
msgstr ""
msgid "Compatible with current game" msgid "Compatible with current game"
msgstr "" msgstr ""
@ -4421,6 +4424,9 @@ msgstr "Session en cours"
msgid "Log" msgid "Log"
msgstr "Journal" msgstr "Journal"
msgid "Demo Log"
msgstr ""
#: pysollib/tile/tkstats.py:523 data/pysolfc.glade:1404 #: pysollib/tile/tkstats.py:523 data/pysolfc.glade:1404
msgid "Full log" msgid "Full log"
msgstr "Journal complet" msgstr "Journal complet"
@ -5222,6 +5228,9 @@ msgstr "&Commentaires..."
msgid "Log..." msgid "Log..."
msgstr "Journal..." msgstr "Journal..."
msgid "Demo log..."
msgstr ""
#: pysollib/ui/tktile/menubar.py:427 #: pysollib/ui/tktile/menubar.py:427
msgid "D&emo statistics..." msgid "D&emo statistics..."
msgstr "Statistiques d&émo..." msgstr "Statistiques d&émo..."

View file

@ -12,7 +12,7 @@ msgstr ""
"Project-Id-Version: it_pysol\n" "Project-Id-Version: it_pysol\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-12-10 10:19-0500\n" "POT-Creation-Date: 2021-12-10 10:19-0500\n"
"PO-Revision-Date: 2024-12-28 19:11-0500\n" "PO-Revision-Date: 2025-03-14 19:15-0400\n"
"Last-Translator: Giuliano Colla <giuliano.colla@gmail.com>\n" "Last-Translator: Giuliano Colla <giuliano.colla@gmail.com>\n"
"Language-Team: Italiano <it@li.org>\n" "Language-Team: Italiano <it@li.org>\n"
"Language: it\n" "Language: it\n"
@ -2707,7 +2707,7 @@ msgstr "Gioco automatico"
#: pysollib/kivy/menubar.py:513 #: pysollib/kivy/menubar.py:513
#, fuzzy #, fuzzy
msgid "Auto face up" msgid "Auto face-up"
msgstr "Auto &scopri" msgstr "Auto &scopri"
#: pysollib/kivy/menubar.py:523 #: pysollib/kivy/menubar.py:523
@ -4303,6 +4303,9 @@ msgstr "Nazionalità:"
msgid "Year:" msgid "Year:"
msgstr "Anno:" msgstr "Anno:"
msgid "Num. cards:"
msgstr ""
msgid "Compatible with current game" msgid "Compatible with current game"
msgstr "" msgstr ""
@ -4485,6 +4488,9 @@ msgstr "Questa sessione"
msgid "Log" msgid "Log"
msgstr "Log" msgstr "Log"
msgid "Demo Log"
msgstr ""
#: pysollib/tile/tkstats.py:523 data/pysolfc.glade:1404 #: pysollib/tile/tkstats.py:523 data/pysolfc.glade:1404
msgid "Full log" msgid "Full log"
msgstr "Log completo" msgstr "Log completo"
@ -5288,6 +5294,9 @@ msgstr "&Commenti..."
msgid "Log..." msgid "Log..."
msgstr "Log..." msgstr "Log..."
msgid "Demo log..."
msgstr ""
#: pysollib/ui/tktile/menubar.py:427 #: pysollib/ui/tktile/menubar.py:427
msgid "D&emo statistics..." msgid "D&emo statistics..."
msgstr "Statistiche d&emo..." msgstr "Statistiche d&emo..."

View file

@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: PySolFC\n" "Project-Id-Version: PySolFC\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-12-10 10:19-0500\n" "POT-Creation-Date: 2021-12-10 10:19-0500\n"
"PO-Revision-Date: 2024-12-28 19:11-0500\n" "PO-Revision-Date: 2025-03-14 19:15-0400\n"
"Last-Translator: Jerzy Trzeciak <artusek@wp.pl>\n" "Last-Translator: Jerzy Trzeciak <artusek@wp.pl>\n"
"Language-Team: Polish <pl@li.org>\n" "Language-Team: Polish <pl@li.org>\n"
"Language: pl\n" "Language: pl\n"
@ -2707,7 +2707,7 @@ msgid "Automatic play"
msgstr "Gra &automatyczna" msgstr "Gra &automatyczna"
#: pysollib/kivy/menubar.py:513 #: pysollib/kivy/menubar.py:513
msgid "Auto face up" msgid "Auto face-up"
msgstr "Odkrywaj automatycznie" msgstr "Odkrywaj automatycznie"
#: pysollib/kivy/menubar.py:523 #: pysollib/kivy/menubar.py:523
@ -4257,6 +4257,9 @@ msgstr "Narodowość:"
msgid "Year:" msgid "Year:"
msgstr "Rok:" msgstr "Rok:"
msgid "Num. cards:"
msgstr ""
msgid "Compatible with current game" msgid "Compatible with current game"
msgstr "" msgstr ""
@ -4438,6 +4441,9 @@ msgstr "Bieżąca sesja"
msgid "Log" msgid "Log"
msgstr "Log" msgstr "Log"
msgid "Demo Log"
msgstr ""
#: pysollib/tile/tkstats.py:523 data/pysolfc.glade:1404 #: pysollib/tile/tkstats.py:523 data/pysolfc.glade:1404
msgid "Full log" msgid "Full log"
msgstr "Kompletny log" msgstr "Kompletny log"
@ -5242,6 +5248,9 @@ msgstr "Komentarze..."
msgid "Log..." msgid "Log..."
msgstr "Log..." msgstr "Log..."
msgid "Demo log..."
msgstr ""
#: pysollib/ui/tktile/menubar.py:427 #: pysollib/ui/tktile/menubar.py:427
msgid "D&emo statistics..." msgid "D&emo statistics..."
msgstr "D&emo statystyk..." msgstr "D&emo statystyk..."

View file

@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-12-10 10:19-0500\n" "POT-Creation-Date: 2021-12-10 10:19-0500\n"
"PO-Revision-Date: 2024-12-28 19:11-0500\n" "PO-Revision-Date: 2025-03-14 19:15-0400\n"
"Last-Translator: Matheus Knack <mtknack555@gmail.com>\n" "Last-Translator: Matheus Knack <mtknack555@gmail.com>\n"
"Language-Team: \n" "Language-Team: \n"
"Language: pt_BR\n" "Language: pt_BR\n"
@ -2715,7 +2715,7 @@ msgid "Automatic play"
msgstr "Jogar automaticamente" msgstr "Jogar automaticamente"
#: pysollib/kivy/menubar.py:513 #: pysollib/kivy/menubar.py:513
msgid "Auto face up" msgid "Auto face-up"
msgstr "Virar pra cima automaticamente" msgstr "Virar pra cima automaticamente"
#: pysollib/kivy/menubar.py:523 #: pysollib/kivy/menubar.py:523
@ -4263,6 +4263,9 @@ msgstr "Nacionalidade:"
msgid "Year:" msgid "Year:"
msgstr "Ano:" msgstr "Ano:"
msgid "Num. cards:"
msgstr ""
msgid "Compatible with current game" msgid "Compatible with current game"
msgstr "" msgstr ""
@ -4444,6 +4447,9 @@ msgstr "Sessão atual"
msgid "Log" msgid "Log"
msgstr "registro" msgstr "registro"
msgid "Demo Log"
msgstr ""
#: pysollib/tile/tkstats.py:523 data/pysolfc.glade:1404 #: pysollib/tile/tkstats.py:523 data/pysolfc.glade:1404
msgid "Full log" msgid "Full log"
msgstr "Registro completo" msgstr "Registro completo"
@ -5244,6 +5250,9 @@ msgstr "&Comentários..."
msgid "Log..." msgid "Log..."
msgstr "Registro" msgstr "Registro"
msgid "Demo log..."
msgstr ""
#: pysollib/ui/tktile/menubar.py:427 #: pysollib/ui/tktile/menubar.py:427
msgid "D&emo statistics..." msgid "D&emo statistics..."
msgstr "Estatísticas de D&emo..." msgstr "Estatísticas de D&emo..."

View file

@ -2524,7 +2524,7 @@ msgid "Automatic play"
msgstr "" msgstr ""
#: pysollib/kivy/menubar.py:513 #: pysollib/kivy/menubar.py:513
msgid "Auto face up" msgid "Auto face-up"
msgstr "" msgstr ""
#: pysollib/kivy/menubar.py:523 #: pysollib/kivy/menubar.py:523
@ -4045,6 +4045,9 @@ msgstr ""
msgid "Year:" msgid "Year:"
msgstr "" msgstr ""
msgid "Num. cards:"
msgstr ""
msgid "Compatible with current game" msgid "Compatible with current game"
msgstr "" msgstr ""
@ -4224,6 +4227,9 @@ msgstr ""
msgid "Log" msgid "Log"
msgstr "" msgstr ""
msgid "Demo Log"
msgstr ""
#: pysollib/tile/tkstats.py:523 data/pysolfc.glade:1404 #: pysollib/tile/tkstats.py:523 data/pysolfc.glade:1404
msgid "Full log" msgid "Full log"
msgstr "" msgstr ""
@ -4974,6 +4980,9 @@ msgstr ""
msgid "Log..." msgid "Log..."
msgstr "" msgstr ""
msgid "Demo log..."
msgstr ""
#: pysollib/ui/tktile/menubar.py:427 #: pysollib/ui/tktile/menubar.py:427
msgid "D&emo statistics..." msgid "D&emo statistics..."
msgstr "" msgstr ""

View file

@ -7,7 +7,7 @@ msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-12-10 10:19-0500\n" "POT-Creation-Date: 2021-12-10 10:19-0500\n"
"PO-Revision-Date: 2024-12-28 19:12-0500\n" "PO-Revision-Date: 2025-03-14 19:14-0400\n"
"Last-Translator: Skomoroh <skomoroh@gmail.com>\n" "Last-Translator: Skomoroh <skomoroh@gmail.com>\n"
"Language-Team: Russian <ru@li.org>\n" "Language-Team: Russian <ru@li.org>\n"
"Language: ru\n" "Language: ru\n"
@ -2713,7 +2713,7 @@ msgstr "Настройки &автоматической игры"
#: pysollib/kivy/menubar.py:513 #: pysollib/kivy/menubar.py:513
#, fuzzy #, fuzzy
msgid "Auto face up" msgid "Auto face-up"
msgstr "Автоматически &переворачивать" msgstr "Автоматически &переворачивать"
#: pysollib/kivy/menubar.py:523 #: pysollib/kivy/menubar.py:523
@ -4312,6 +4312,9 @@ msgstr "Национальность:"
msgid "Year:" msgid "Year:"
msgstr "Год:" msgstr "Год:"
msgid "Num. cards:"
msgstr ""
msgid "Compatible with current game" msgid "Compatible with current game"
msgstr "" msgstr ""
@ -4494,6 +4497,9 @@ msgstr "Текущая сессия"
msgid "Log" msgid "Log"
msgstr "Лог" msgstr "Лог"
msgid "Demo Log"
msgstr ""
#: pysollib/tile/tkstats.py:523 data/pysolfc.glade:1404 #: pysollib/tile/tkstats.py:523 data/pysolfc.glade:1404
msgid "Full log" msgid "Full log"
msgstr "Полный лог" msgstr "Полный лог"
@ -5311,6 +5317,9 @@ msgstr "&Комментарии..."
msgid "Log..." msgid "Log..."
msgstr "Лог..." msgstr "Лог..."
msgid "Demo log..."
msgstr ""
#: pysollib/ui/tktile/menubar.py:427 #: pysollib/ui/tktile/menubar.py:427
msgid "D&emo statistics..." msgid "D&emo statistics..."
msgstr "Статистика демо..." msgstr "Статистика демо..."

View file

@ -35,7 +35,8 @@ from pysollib.app_stat_result import GameStatResult
from pysollib.app_statistics import Statistics from pysollib.app_statistics import Statistics
from pysollib.cardsetparser import read_cardset_config from pysollib.cardsetparser import read_cardset_config
from pysollib.gamedb import GAME_DB, GI, loadGame from pysollib.gamedb import GAME_DB, GI, loadGame
from pysollib.help import destroy_help_html, help_about, raise_help_html from pysollib.help import (destroy_help_html, help_about, raise_help_html,
unraise_help_html)
from pysollib.images import Images, SubsampledImages from pysollib.images import Images, SubsampledImages
from pysollib.mfxutil import Struct, destruct from pysollib.mfxutil import Struct, destruct
from pysollib.mfxutil import USE_PIL from pysollib.mfxutil import USE_PIL
@ -58,6 +59,9 @@ from pysollib.pysoltk import loadImage, wm_withdraw
from pysollib.pysoltk import raise_find_card_dialog from pysollib.pysoltk import raise_find_card_dialog
from pysollib.pysoltk import raise_full_picture_dialog from pysollib.pysoltk import raise_full_picture_dialog
from pysollib.pysoltk import raise_solver_dialog from pysollib.pysoltk import raise_solver_dialog
from pysollib.pysoltk import unraise_find_card_dialog
from pysollib.pysoltk import unraise_full_picture_dialog
from pysollib.pysoltk import unraise_solver_dialog
from pysollib.resource import CSI, CardsetManager from pysollib.resource import CSI, CardsetManager
from pysollib.resource import Music, MusicManager from pysollib.resource import Music, MusicManager
from pysollib.resource import Sample, SampleManager from pysollib.resource import Sample, SampleManager
@ -525,6 +529,12 @@ class Application:
raise_solver_dialog(self.game) raise_solver_dialog(self.game)
raise_help_html(self.game) raise_help_html(self.game)
def unraiseAll(self):
unraise_find_card_dialog()
unraise_full_picture_dialog()
unraise_solver_dialog()
unraise_help_html()
def loadImages1(self): def loadImages1(self):
# load dialog images # load dialog images
dirname = os.path.join("images", "logos") dirname = os.path.join("images", "logos")

View file

@ -115,11 +115,6 @@ class Statistics:
game.GAME_VERSION) game.GAME_VERSION)
# full log # full log
if status >= 0: if status >= 0:
if player is None:
# demo
ret = self.updateGameStat(player, game, status)
else:
# player
if player not in self.prev_games: if player not in self.prev_games:
self.prev_games[player] = [] self.prev_games[player] = []
self.prev_games[player].append(log) self.prev_games[player].append(log)

View file

@ -589,8 +589,11 @@ class Game(object):
if not self.cards: if not self.cards:
self.cards = self.createCards(progress=self.app.intro.progress) self.cards = self.createCards(progress=self.app.intro.progress)
self.initBindings() self.initBindings()
if TOOLKIT == 'tk':
# self.top.bind('<ButtonPress>', self.top._sleepEvent) # self.top.bind('<ButtonPress>', self.top._sleepEvent)
# self.top.bind('<3>', self.top._sleepEvent) # self.top.bind('<3>', self.top._sleepEvent)
self.top.bind("<FocusOut>", self.top._focusOutEvent)
self.top.bind("<FocusIn>", self.top._focusInEvent)
# update display properties # update display properties
self.canvas.busy = True self.canvas.busy = True
# geometry # geometry

View file

@ -112,7 +112,7 @@ class GI:
# extra flags # extra flags
GT_BETA = 1 << 12 # beta version of game driver GT_BETA = 1 << 12 # beta version of game driver
GT_CHILDREN = 1 << 13 # *not used* GT_CHILDREN = 1 << 13
GT_CONTRIB = 1 << 14 # contributed games under the GNU GPL GT_CONTRIB = 1 << 14 # contributed games under the GNU GPL
GT_HIDDEN = 1 << 15 # not visible in menus, but games can be loaded GT_HIDDEN = 1 << 15 # not visible in menus, but games can be loaded
GT_OPEN = 1 << 16 GT_OPEN = 1 << 16
@ -320,7 +320,6 @@ class GI:
904: 68, # Lexington Harp 904: 68, # Lexington Harp
237: 22231, # Three Peaks 237: 22231, # Three Peaks
297: 631, # Alternation/Alternations 297: 631, # Alternation/Alternations
526: 447, # Australian/Outback Patience
640: 566, # Hypotenuse/Brazilian Patience 640: 566, # Hypotenuse/Brazilian Patience
# Lost Mahjongg Layouts # Lost Mahjongg Layouts
@ -346,6 +345,15 @@ class GI:
# adding it should be a priority. # adding it should be a priority.
GAMES_BY_COMPATIBILITY = ( GAMES_BY_COMPATIBILITY = (
# Ace of Penguins (We have 6 out of 6 card games)
# Non-card games missing:
# - Mastermind
# - Minesweeper (Needs a new cardset type)
# - Pegged layouts (Not all compatible with the PySol engine)
# - Mahjongg/Taipei layouts
("Ace of Penguins", (2, 8, 11, 36, 105, 181, 210, 492,
5401, 22399)),
# Atari ST Patience game v2.13 (we have 10 out of 10 games) # Atari ST Patience game v2.13 (we have 10 out of 10 games)
("Atari ST Patience", (1, 3, 4, 7, 12, 14, 15, 16, 17, 39,)), ("Atari ST Patience", (1, 3, 4, 7, 12, 14, 15, 16, 17, 39,)),
@ -368,12 +376,12 @@ class GI:
# Hamilton, Labyrinth, Treize, Wall # Hamilton, Labyrinth, Treize, 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, 44, 45, 48, 58, 65, 67, 89, 91, 92, 93,
95, 96, 97, 100, 104, 105, 111, 112, 113, 130, 135, 139, 144, 94, 95, 96, 97, 100, 104, 105, 111, 112, 113, 130, 135, 139,
146, 147, 148, 200, 201, 206, 224, 225, 229, 230, 233, 257, 144, 146, 147, 148, 200, 201, 206, 224, 225, 229, 230, 233,
258, 277, 280, 281, 282, 283, 284, 334, 384, 479, 495, 551, 257, 258, 277, 280, 281, 282, 283, 284, 334, 384, 479, 495,
552, 553, 572, 593, 674, 700, 715, 716, 737, 772, 810, 819, 551, 552, 553, 572, 593, 674, 700, 715, 716, 737, 772, 810,
824, 829, 859, 874, 906, 934, 22231, 819, 824, 829, 859, 874, 906, 934, 22231,
)), )),
# Hoyle Card Games # Hoyle Card Games
@ -575,7 +583,7 @@ class GI:
('fc-0.9.0', tuple(range(323, 421))), ('fc-0.9.0', tuple(range(323, 421))),
('fc-0.9.1', tuple(range(421, 441))), ('fc-0.9.1', tuple(range(421, 441))),
('fc-0.9.2', tuple(range(441, 466))), ('fc-0.9.2', tuple(range(441, 466))),
('fc-0.9.3', tuple(range(466, 661))), ('fc-0.9.3', tuple(range(466, 526)) + tuple(range(527, 661))),
('fc-0.9.4', tuple(range(661, 671))), ('fc-0.9.4', tuple(range(661, 671))),
('fc-1.0', tuple(range(671, 711))), ('fc-1.0', tuple(range(671, 711))),
('fc-1.1', tuple(range(711, 759))), ('fc-1.1', tuple(range(711, 759))),
@ -595,12 +603,14 @@ class GI:
tuple(range(19000, 19012)) + tuple(range(22303, 22311)) + tuple(range(19000, 19012)) + tuple(range(22303, 22311)) +
tuple(range(22353, 22361))), tuple(range(22353, 22361))),
('fc-3.1', tuple(range(961, 971))), ('fc-3.1', tuple(range(961, 971))),
('dev', tuple(range(971, 981)) + tuple(range(5419, 5421)) +
tuple(range(16683, 16686)) + tuple(range(18005, 18007)) +
(44, 526, 22399,)),
) )
# deprecated - the correct way is to or a GI.GT_XXX flag # deprecated - the correct way is to or a GI.GT_XXX flag
# in the registerGame() call # in the registerGame() call
_CHILDREN_GAMES = [16, 33, 55, 90, 91, 96, 97, 176, 328, 329, 862, 865, _CHILDREN_GAMES = []
886, 903, ]
_OPEN_GAMES = [] _OPEN_GAMES = []

View file

@ -504,8 +504,8 @@ class MaineCoon(TabbyCat):
# register the game # register the game
registerGame(GameInfo(903, AcesUp, "Aces Up", # was: 52 registerGame(GameInfo(903, AcesUp, "Aces Up", # was: 52
GI.GT_1DECK_TYPE, 1, 0, GI.SL_LUCK, GI.GT_1DECK_TYPE | GI.GT_CHILDREN, 1, 0, GI.SL_LUCK,
altnames=("Aces High", "Drivel"))) altnames=("Aces High", "Drivel", "Discard")))
registerGame(GameInfo(206, Fortunes, "Fortunes", registerGame(GameInfo(206, Fortunes, "Fortunes",
GI.GT_1DECK_TYPE, 1, 0, GI.SL_LUCK)) GI.GT_1DECK_TYPE, 1, 0, GI.SL_LUCK))
registerGame(GameInfo(213, RussianAces, "Russian Aces", registerGame(GameInfo(213, RussianAces, "Russian Aces",
@ -514,7 +514,7 @@ registerGame(GameInfo(130, PerpetualMotion, "Perpetual Motion",
GI.GT_1DECK_TYPE, 1, -1, GI.SL_MOSTLY_LUCK, GI.GT_1DECK_TYPE, 1, -1, GI.SL_MOSTLY_LUCK,
altnames=("First Law", "Narcotic"))) altnames=("First Law", "Narcotic")))
registerGame(GameInfo(353, AcesUp5, "Aces Up 5", registerGame(GameInfo(353, AcesUp5, "Aces Up 5",
GI.GT_1DECK_TYPE, 1, 0, GI.SL_LUCK)) GI.GT_1DECK_TYPE | GI.GT_CHILDREN, 1, 0, GI.SL_LUCK))
registerGame(GameInfo(552, Cover, "Cover", registerGame(GameInfo(552, Cover, "Cover",
GI.GT_1DECK_TYPE, 1, 0, GI.SL_LUCK)) GI.GT_1DECK_TYPE, 1, 0, GI.SL_LUCK))
registerGame(GameInfo(583, FiringSquad, "Firing Squad", registerGame(GameInfo(583, FiringSquad, "Firing Squad",

View file

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

@ -957,7 +957,7 @@ registerGame(GameInfo(831, Siegecraft, "Siegecraft",
GI.SL_MOSTLY_SKILL)) GI.SL_MOSTLY_SKILL))
registerGame(GameInfo(881, Lasker, "Lasker", registerGame(GameInfo(881, Lasker, "Lasker",
GI.GT_BELEAGUERED_CASTLE | GI.GT_OPEN, 1, 0, GI.GT_BELEAGUERED_CASTLE | GI.GT_OPEN, 1, 0,
GI.SL_SKILL)) GI.SL_SKILL, altnames=('Xantia',)))
registerGame(GameInfo(951, Morphy, "Morphy", registerGame(GameInfo(951, Morphy, "Morphy",
GI.GT_BELEAGUERED_CASTLE | GI.GT_OPEN, 1, 0, GI.GT_BELEAGUERED_CASTLE | GI.GT_OPEN, 1, 0,
GI.SL_SKILL)) GI.SL_SKILL))

View file

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

View file

@ -46,6 +46,11 @@ class Crossword_Hint(AbstractHint):
r = rows[i] r = rows[i]
if r.cards: if r.cards:
continue continue
if len(game.s.talon.cards) == 0:
for s in game.s.reserves:
if game.isValidPlay(r.id, s.getCard().rank + 1):
self.addHint(5000, 1, s, r)
continue
if game.isValidPlay(r.id, game.s.talon.getCard().rank + 1): if game.isValidPlay(r.id, game.s.talon.getCard().rank + 1):
# TODO: Check a few moves ahead to get better hints. # TODO: Check a few moves ahead to get better hints.
self.addHint(5000, 1, game.s.talon, r) self.addHint(5000, 1, game.s.talon, r)

View file

@ -105,6 +105,7 @@ class StrictEiffelTower(EiffelTower):
# register the game # register the game
registerGame(GameInfo(16, EiffelTower, "Eiffel Tower", registerGame(GameInfo(16, EiffelTower, "Eiffel Tower",
GI.GT_PAIRING_TYPE, 2, 0, GI.SL_MOSTLY_LUCK)) GI.GT_PAIRING_TYPE | GI.GT_CHILDREN, 2, 0,
GI.SL_MOSTLY_LUCK))
# registerGame(GameInfo(801, StrictEiffelTower, "Strict Eiffel Tower", # registerGame(GameInfo(801, StrictEiffelTower, "Strict Eiffel Tower",
# GI.GT_PAIRING_TYPE, 2, 0)) # GI.GT_PAIRING_TYPE, 2, 0))

View file

@ -776,11 +776,11 @@ registerGame(GameInfo(697, BigBen, "Big Ben",
GI.GT_2DECK_TYPE, 2, 0, GI.SL_BALANCED, GI.GT_2DECK_TYPE, 2, 0, GI.SL_BALANCED,
altnames=("Father Time"))) altnames=("Father Time")))
registerGame(GameInfo(737, Clock, "Clock", registerGame(GameInfo(737, Clock, "Clock",
GI.GT_1DECK_TYPE, 1, 0, GI.SL_LUCK, GI.GT_1DECK_TYPE | GI.GT_CHILDREN, 1, 0, GI.SL_LUCK,
altnames=("Travellers", "Sundial"))) altnames=("Travellers", "Sundial")))
registerGame(GameInfo(827, GermanClock, "German Clock", registerGame(GameInfo(827, GermanClock, "German Clock",
GI.GT_1DECK_TYPE, 1, 1, GI.SL_MOSTLY_LUCK, GI.GT_1DECK_TYPE, 1, 1, GI.SL_MOSTLY_LUCK,
altnames=("Die Uhr",))) altnames=("Die Uhr",)))
registerGame(GameInfo(915, RelaxedClock, "Relaxed Clock", registerGame(GameInfo(915, RelaxedClock, "Relaxed Clock",
GI.GT_1DECK_TYPE | GI.GT_RELAXED, 1, 0, GI.SL_LUCK, GI.GT_1DECK_TYPE | GI.GT_RELAXED | GI.GT_CHILDREN, 1, 0,
altnames=("Watch"))) GI.SL_LUCK, altnames=("Watch")))

View file

@ -1125,7 +1125,8 @@ registerGame(GameInfo(666, TrapdoorSpider, "Trapdoor Spider",
registerGame(GameInfo(712, Leprechaun, "Leprechaun", registerGame(GameInfo(712, Leprechaun, "Leprechaun",
GI.GT_GYPSY | GI.GT_ORIGINAL, 2, 0, GI.SL_MOSTLY_SKILL)) GI.GT_GYPSY | GI.GT_ORIGINAL, 2, 0, GI.SL_MOSTLY_SKILL))
registerGame(GameInfo(718, LockedCards, "Locked Cards", registerGame(GameInfo(718, LockedCards, "Locked Cards",
GI.GT_2DECK_TYPE, 2, 2, GI.SL_BALANCED)) GI.GT_2DECK_TYPE, 2, 2, GI.SL_BALANCED,
altnames=("Prisoners",)))
registerGame(GameInfo(721, Thirty, "Thirty", registerGame(GameInfo(721, Thirty, "Thirty",
GI.GT_1DECK_TYPE | GI.GT_OPEN | GI.GT_STRIPPED, 1, 0, GI.GT_1DECK_TYPE | GI.GT_OPEN | GI.GT_STRIPPED, 1, 0,
GI.SL_MOSTLY_SKILL, ranks=(0, 6, 7, 8, 9, 10, 11, 12))) GI.SL_MOSTLY_SKILL, ranks=(0, 6, 7, 8, 9, 10, 11, 12)))
@ -1133,7 +1134,7 @@ registerGame(GameInfo(725, TopsyTurvyQueens, "Topsy-Turvy Queens",
GI.GT_2DECK_TYPE, 2, 2, GI.SL_BALANCED)) GI.GT_2DECK_TYPE, 2, 2, GI.SL_BALANCED))
registerGame(GameInfo(792, KingsSecrets, "King's Secrets", registerGame(GameInfo(792, KingsSecrets, "King's Secrets",
GI.GT_2DECK_TYPE, 2, 2, GI.SL_BALANCED, GI.GT_2DECK_TYPE, 2, 2, GI.SL_BALANCED,
altnames=('Royal Secrets',))) altnames=('Royal Secrets', "King's Captives")))
registerGame(GameInfo(842, SwissPatience, "Swiss Patience", registerGame(GameInfo(842, SwissPatience, "Swiss Patience",
GI.GT_GYPSY, 1, 0, GI.SL_BALANCED)) GI.GT_GYPSY, 1, 0, GI.SL_BALANCED))
registerGame(GameInfo(890, YeastDough, "Yeast Dough", registerGame(GameInfo(890, YeastDough, "Yeast Dough",

View file

@ -170,5 +170,5 @@ registerGame(GameInfo(774, HitOrMiss, "Hit or Miss",
GI.GT_1DECK_TYPE, 1, VARIABLE_REDEALS, GI.GT_1DECK_TYPE, 1, VARIABLE_REDEALS,
GI.SL_LUCK, altnames=("Roll Call",))) GI.SL_LUCK, altnames=("Roll Call",)))
registerGame(GameInfo(865, HitOrMissUnlimited, "Hit or Miss Unlimited", registerGame(GameInfo(865, HitOrMissUnlimited, "Hit or Miss Unlimited",
GI.GT_1DECK_TYPE, 1, UNLIMITED_REDEALS, GI.GT_1DECK_TYPE | GI.GT_CHILDREN, 1, UNLIMITED_REDEALS,
GI.SL_LUCK)) GI.SL_LUCK))

View file

@ -36,7 +36,7 @@ from pysollib.stack import \
WasteTalonStack, \ WasteTalonStack, \
Yukon_AC_RowStack, \ Yukon_AC_RowStack, \
getNumberOfFreeStacks getNumberOfFreeStacks
from pysollib.util import ANY_RANK, KING from pysollib.util import ANY_RANK, KING, NO_RANK
# ************************************************************************ # ************************************************************************
@ -301,6 +301,96 @@ class Sarlacc(Interlock):
self.s.talon.dealRow(rows=self.s.rows[42:]) self.s.talon.dealRow(rows=self.s.rows[42:])
# ************************************************************************
# * Flamboyant
# ************************************************************************
class Flamboyant_RowStack(Interlock_RowStack):
STEP = ((2,), (1,), (), (2,), (1,), (), (2,), (1,), (),
(2,), (1,), (), (2,), (1,), (), (2,), (1,), (),
(2,), (1,), (), (2,), (1,), (), (2,), (1,), (),
(2,), (1,), (), (2,), (1,), (), (2,), (1,), (),
(2,), (1,), (), (2,), (1,), (), (2,), (1,), (),
(2,), (1,), (), (2,), (1,), ())
class Flamboyant(Interlock):
RowStack_Class = Flamboyant_RowStack
Talon_Class = InitialDealTalonStack
PLAYCARDS = 8
def _createTableauPiece(self, layout, x0, y0):
for i in range(2):
x = x0 + i * layout.XS // 2
y = y0 + i * layout.YS // 4
for j in range(2 - i):
stack = self.RowStack_Class(x, y, self, base_rank=NO_RANK)
self.s.rows.append(stack)
x = x + layout.XS
def createGame(self):
lay, s = Layout(self), self.s
w = (14.5 * lay.XS) + lay.XM
h = (4.2 * lay.YS) + (self.PLAYCARDS * lay.YOFFSET * 3) + lay.YM
self.setSize(w, h)
x, y = lay.XM, lay.YM
# create stacks
for i in range(2):
for i in range(6):
self._createTableauPiece(lay, x, y)
x += (2.25 * lay.XS)
y += (1.4 * lay.YS) + (self.PLAYCARDS * lay.YOFFSET)
x = lay.XM
for i in range(5):
self._createTableauPiece(lay, x, y)
x += (2.25 * lay.XS)
x += (.5 * lay.XS)
self.s.rows.append(AC_RowStack(x, y, self, base_rank=KING))
x, y = lay.XM + (13.5 * lay.XS), lay.YM
for i in range(4):
s.foundations.append(SS_FoundationStack(x, y, self, i))
y += lay.YS
s.talon = InitialDealTalonStack(x, y, self)
lay.defaultStackGroups()
def startGame(self):
self.startDealSample()
backrows = []
frontrows = []
for i, item in enumerate(self.s.rows):
if (i + 1) % 3 == 0 or i >= 51:
frontrows.append(item)
else:
backrows.append(item)
self.s.talon.dealRow(rows=backrows, flip=0, frames=0)
self.s.talon.dealRow(rows=frontrows)
def _getClosestStack(self, cx, cy, stacks, dragstack):
closest, cdist = None, 999999999
# Since we only compare distances,
# we don't bother to take the square root.
for stack in stacks:
# Flamboyant uses different logic to determine back row
# stacks.
backrows = []
frontrows = []
for i, item in enumerate(self.s.rows):
if (i + 1) % 3 == 0:
frontrows.append(item)
else:
backrows.append(item)
if len(stack.cards) == 0 and stack in frontrows:
continue
dist = (stack.x - cx)**2 + (stack.y - cy)**2
if dist < cdist:
closest, cdist = stack, dist
return closest
# register the game # register the game
registerGame(GameInfo(852, Guardian, "Guardian", registerGame(GameInfo(852, Guardian, "Guardian",
GI.GT_KLONDIKE, 1, -1, GI.SL_BALANCED)) GI.GT_KLONDIKE, 1, -1, GI.SL_BALANCED))
@ -310,3 +400,5 @@ registerGame(GameInfo(939, LoveADuck, "Love a Duck",
GI.GT_YUKON | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL)) GI.GT_YUKON | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL))
registerGame(GameInfo(946, Sarlacc, "Sarlacc", registerGame(GameInfo(946, Sarlacc, "Sarlacc",
GI.GT_FREECELL | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL)) GI.GT_FREECELL | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL))
registerGame(GameInfo(979, Flamboyant, "Flamboyant",
GI.GT_FAN_TYPE, 1, 0, GI.SL_BALANCED))

View file

@ -1640,7 +1640,8 @@ registerGame(GameInfo(66, Eastcliff, "Eastcliff",
registerGame(GameInfo(224, Easthaven, "Easthaven", registerGame(GameInfo(224, Easthaven, "Easthaven",
GI.GT_GYPSY, 1, 0, GI.SL_MOSTLY_LUCK)) GI.GT_GYPSY, 1, 0, GI.SL_MOSTLY_LUCK))
registerGame(GameInfo(33, Westcliff, "Westcliff", registerGame(GameInfo(33, Westcliff, "Westcliff",
GI.GT_KLONDIKE, 1, 0, GI.SL_MOSTLY_LUCK)) GI.GT_KLONDIKE | GI.GT_CHILDREN, 1, 0,
GI.SL_MOSTLY_LUCK))
registerGame(GameInfo(225, Westhaven, "Westhaven", registerGame(GameInfo(225, Westhaven, "Westhaven",
GI.GT_GYPSY, 1, 0, GI.SL_BALANCED)) GI.GT_GYPSY, 1, 0, GI.SL_BALANCED))
registerGame(GameInfo(107, PasSeul, "Pas Seul", registerGame(GameInfo(107, PasSeul, "Pas Seul",

View file

@ -407,7 +407,7 @@ class AbstractMahjonggGame(Game):
# width of self.texts.info # width of self.texts.info
# ti_width = Font(self.canvas, font).measure(_('Remaining')) # ti_width = Font(self.canvas, font).measure(_('Remaining'))
ti_width = 80 ti_width = max(80, l.CW)
# set window size # set window size
dxx, dyy = abs(dx) * (max_tl+1), abs(dy) * (max_tl+1) dxx, dyy = abs(dx) * (max_tl+1), abs(dy) * (max_tl+1)

View file

@ -356,6 +356,48 @@ r(5418, "Zigzag", layout="0aabaajaaracahcb" +
"ynvyniyoaypaAehA" + "ynvyniyoaypaAehA" +
"faAgaAmhAnaAoaCa" + "faAgaAmhAnaAoaCa" +
"aCfaCnaCs") "aCfaCnaCs")
r(5419, "Lizard", layout="0aadaafaahaajhbe" +
"hbghbibccaceacga" +
"ciackidjbebaejae" +
"laeqheraesifkbga" +
"agehgfaggagkagmb" +
"grihlaiabifailai" +
"nbirijmojqakaakg" +
"hkhakiokihkjakko" +
"kkvklakmvknakook" +
"ohkpakqhllolmhln" +
"ambamkammamohnlo" +
"nmhnnaokaomaoohp" +
"lopmhpnaqjaqlaqn" +
"hrkorlhrmasjasla" +
"snhtkotlhtmaujau" +
"launhvkovlhvmawi" +
"awkawmhxjpxkhxla" +
"yiaykaymazehzfaz" +
"gozghzhozihzjvzj" +
"ozkhzlvzlozmhzna" +
"zoozohzpazqaAiaA" +
"kaAmbBdiBkbBraCj" +
"aClaDchDdaDehDka" +
"DqhDraDsaEjaElaF" +
"daFraGk")
r(5420, "Candy", layout="0daadaccaebagbai" +
"aakdcbccdbcfbcha" +
"cjcecbeebegaeibg" +
"dbgfaghbieaigakc" +
"akeakgakiamaamcb" +
"mebmgamiamkaoabo" +
"cboebogboiaokopf" +
"aqabqcbqebqgbqia" +
"qkorfasabscbsebs" +
"gbsiaskauaaucbue" +
"bugauiaukawcawea" +
"wgawiayebygaAdbA" +
"fbAhaCcbCebCgcCi" +
"aEbbEdbEfcEhdEja" +
"GabGcbGecGgdGidG" +
"k")
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------

View file

@ -299,6 +299,9 @@ class Quatorze(MonteCarlo):
return (stack1.id // 5 == stack2.id // 5 or return (stack1.id // 5 == stack2.id // 5 or
stack1.id % 5 == stack2.id % 5) stack1.id % 5 == stack2.id % 5)
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return card1.rank + card2.rank == 12
# ************************************************************************ # ************************************************************************
# * Simple Pairs # * Simple Pairs
@ -364,6 +367,10 @@ class BlockTen(SimplePairs):
def isGameWon(self): def isGameWon(self):
return len(self.s.foundations[0].cards) == 48 return len(self.s.foundations[0].cards) == 48
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return (card1.rank + card2.rank == 8 or
(9 < card1.rank == card2.rank > 9))
class SimpleTens(BlockTen): class SimpleTens(BlockTen):
def isGameWon(self): def isGameWon(self):
@ -1108,6 +1115,10 @@ class AcesSquare(MonteCarlo):
return (stack1.id // 4 == stack2.id // 4 or return (stack1.id // 4 == stack2.id // 4 or
stack1.id % 4 == stack2.id % 4) stack1.id % 4 == stack2.id % 4)
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return (card1.suit == card2.suit and
card1.rank != card2.rank != 0)
# register the game # register the game
registerGame(GameInfo(89, MonteCarlo, "Monte Carlo", registerGame(GameInfo(89, MonteCarlo, "Monte Carlo",
@ -1118,15 +1129,16 @@ registerGame(GameInfo(216, MonteCarlo2Decks, "Monte Carlo (2 Decks)",
registerGame(GameInfo(212, Weddings, "Weddings", registerGame(GameInfo(212, Weddings, "Weddings",
GI.GT_PAIRING_TYPE, 1, 0, GI.SL_MOSTLY_LUCK)) GI.GT_PAIRING_TYPE, 1, 0, GI.SL_MOSTLY_LUCK))
registerGame(GameInfo(90, SimpleCarlo, "Simple Carlo", registerGame(GameInfo(90, SimpleCarlo, "Simple Carlo",
GI.GT_PAIRING_TYPE, 1, 0, GI.SL_MOSTLY_LUCK)) GI.GT_PAIRING_TYPE | GI.GT_CHILDREN, 1, 0,
GI.SL_MOSTLY_LUCK))
registerGame(GameInfo(91, SimplePairs, "Simple Pairs", registerGame(GameInfo(91, SimplePairs, "Simple Pairs",
GI.GT_PAIRING_TYPE, 1, 0, GI.SL_LUCK, GI.GT_PAIRING_TYPE | GI.GT_CHILDREN, 1, 0,
altnames=("Jamestown", "Pirate Gold", "Treasure Hunt", GI.SL_LUCK, altnames=("Jamestown", "Pirate Gold",
"Hunter"))) "Treasure Hunt", "Hunter")))
registerGame(GameInfo(92, Neighbour, "Neighbour", registerGame(GameInfo(92, Neighbour, "Neighbour",
GI.GT_PAIRING_TYPE, 1, 0, GI.SL_MOSTLY_LUCK)) GI.GT_PAIRING_TYPE, 1, 0, GI.SL_MOSTLY_LUCK))
registerGame(GameInfo(96, Fourteen, "Fourteen", registerGame(GameInfo(96, Fourteen, "Fourteen",
GI.GT_PAIRING_TYPE | GI.GT_OPEN, 1, 0, GI.GT_PAIRING_TYPE | GI.GT_OPEN | GI.GT_CHILDREN, 1, 0,
GI.SL_MOSTLY_LUCK, altnames=("Fourteen Out", GI.SL_MOSTLY_LUCK, altnames=("Fourteen Out",
"Fourteen Puzzle", "Fourteen Puzzle",
"Take Fourteen"))) "Take Fourteen")))
@ -1137,12 +1149,13 @@ registerGame(GameInfo(152, DerLetzteMonarch, "The Last Monarch",
GI.GT_1DECK_TYPE | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL, GI.GT_1DECK_TYPE | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL,
altnames=("Der letzte Monarch",))) altnames=("Der letzte Monarch",)))
registerGame(GameInfo(328, TheWish, "The Wish", registerGame(GameInfo(328, TheWish, "The Wish",
GI.GT_PAIRING_TYPE | GI.GT_STRIPPED, 1, 0, GI.GT_PAIRING_TYPE | GI.GT_STRIPPED | GI.GT_CHILDREN,
GI.SL_MOSTLY_LUCK, ranks=(0, 6, 7, 8, 9, 10, 11, 12))) 1, 0, GI.SL_MOSTLY_LUCK,
ranks=(0, 6, 7, 8, 9, 10, 11, 12)))
registerGame(GameInfo(329, TheWishOpen, "The Wish (Open)", registerGame(GameInfo(329, TheWishOpen, "The Wish (Open)",
GI.GT_PAIRING_TYPE | GI.GT_OPEN | GI.GT_ORIGINAL | GI.GT_PAIRING_TYPE | GI.GT_OPEN | GI.GT_ORIGINAL |
GI.GT_STRIPPED, 1, 0, GI.SL_MOSTLY_SKILL, GI.GT_STRIPPED | GI.GT_CHILDREN, 1, 0,
ranks=(0, 6, 7, 8, 9, 10, 11, 12), GI.SL_MOSTLY_SKILL, ranks=(0, 6, 7, 8, 9, 10, 11, 12),
rules_filename="thewish.html")) rules_filename="thewish.html"))
registerGame(GameInfo(368, Vertical, "Vertical", registerGame(GameInfo(368, Vertical, "Vertical",
GI.GT_PAIRING_TYPE | GI.GT_OPEN, 1, 0, GI.GT_PAIRING_TYPE | GI.GT_OPEN, 1, 0,
@ -1162,8 +1175,8 @@ registerGame(GameInfo(810, Quatorze, "Quatorze",
registerGame(GameInfo(829, BlockTen, "Block Ten", registerGame(GameInfo(829, BlockTen, "Block Ten",
GI.GT_PAIRING_TYPE, 1, 0, GI.SL_LUCK)) GI.GT_PAIRING_TYPE, 1, 0, GI.SL_LUCK))
registerGame(GameInfo(862, SimpleTens, "Simple Tens", registerGame(GameInfo(862, SimpleTens, "Simple Tens",
GI.GT_PAIRING_TYPE | GI.GT_STRIPPED, 1, 0, GI.SL_LUCK, GI.GT_PAIRING_TYPE | GI.GT_STRIPPED | GI.GT_CHILDREN,
ranks=(0, 1, 2, 3, 4, 5, 6, 7, 8), 1, 0, GI.SL_LUCK, ranks=(0, 1, 2, 3, 4, 5, 6, 7, 8),
altnames=("Add Up Tens",))) altnames=("Add Up Tens",)))
registerGame(GameInfo(867, DoubleFourteen, "Double Fourteen", registerGame(GameInfo(867, DoubleFourteen, "Double Fourteen",
GI.GT_PAIRING_TYPE | GI.GT_OPEN, 2, 0, GI.GT_PAIRING_TYPE | GI.GT_OPEN, 2, 0,

View file

@ -41,6 +41,7 @@ from pysollib.stack import \
RK_FoundationStack, \ RK_FoundationStack, \
RK_RowStack, \ RK_RowStack, \
ReserveStack, \ ReserveStack, \
SC_FoundationStack, \
SS_FoundationStack, \ SS_FoundationStack, \
Stack, \ Stack, \
StackWrapper, \ StackWrapper, \
@ -176,6 +177,7 @@ class Numerica2Decks(Numerica):
# ************************************************************************ # ************************************************************************
# * Lady Betty # * Lady Betty
# * Last Chance # * Last Chance
# * Colours
# ************************************************************************ # ************************************************************************
class LadyBetty(Numerica): class LadyBetty(Numerica):
@ -215,6 +217,40 @@ class LastChance(LadyBetty):
self.s.talon.dealCards() self.s.talon.dealCards()
class Colours(LadyBetty):
Foundation_Class = StackWrapper(SC_FoundationStack, mod=13, suit=ANY_SUIT)
def startGame(self):
self.startDealSample()
self.s.talon.dealRow(rows=self.s.foundations)
self.s.talon.dealCards() # deal first card to WasteStack
def _shuffleHook(self, cards):
# prepare first cards
topcards = [None] * 4
evencolor = -1
oddcolor = -1
for c in cards[:]:
if 0 < c.rank <= 4 and topcards[c.rank - 1] is None:
if c.rank % 2 == 0:
if evencolor != -1 and c.color != evencolor:
continue
if oddcolor != -1 and c.color == oddcolor:
continue
evencolor = c.color
elif c.rank % 2 == 1:
if oddcolor != -1 and c.color != oddcolor:
continue
if evencolor != -1 and c.color == evencolor:
continue
oddcolor = c.color
topcards[c.rank - 1] = c
cards.remove(c)
topcards.reverse()
return cards + topcards
# ************************************************************************ # ************************************************************************
# * Puss in the Corner # * Puss in the Corner
# ************************************************************************ # ************************************************************************
@ -1373,7 +1409,7 @@ class NinetyOne(Game):
def updateText(self): def updateText(self):
if self.preview > 1 or not self.texts.score: if self.preview > 1 or not self.texts.score:
return return
self.texts.score.config(text=self.getTotal()) self.texts.score.config(text=str(self.getTotal()))
def getTotal(self): def getTotal(self):
total = 0 total = 0
@ -1460,3 +1496,5 @@ registerGame(GameInfo(931, TheBogey, "The Bogey",
GI.GT_1DECK_TYPE, 1, -1, GI.SL_BALANCED)) GI.GT_1DECK_TYPE, 1, -1, GI.SL_BALANCED))
registerGame(GameInfo(958, NinetyOne, "Ninety-One", registerGame(GameInfo(958, NinetyOne, "Ninety-One",
GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_SKILL)) GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_SKILL))
registerGame(GameInfo(972, Colours, "Colours",
GI.GT_NUMERICA, 1, 0, GI.SL_BALANCED))

View file

@ -383,51 +383,18 @@ class PyramidDozen(Giza):
# ************************************************************************ # ************************************************************************
# * Thirteen # * Pyramid 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): 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): def startGame(self):
self.startDealSample() self.startDealSample()
@ -616,8 +583,8 @@ class Elevens(Pyramid):
self.leaveState(old_state) self.leaveState(old_state)
def shallHighlightMatch(self, stack1, card1, stack2, card2): def shallHighlightMatch(self, stack1, card1, stack2, card2):
# FIXME return (card1.rank + card2.rank == 9 or
return False (9 < card1.rank != card2.rank > 9))
class ElevensToo(Elevens): class ElevensToo(Elevens):
@ -666,6 +633,11 @@ class SuitElevens(Elevens):
def createGame(self): def createGame(self):
Elevens.createGame(self, rows=3, cols=5) Elevens.createGame(self, rows=3, cols=5)
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return (Elevens.shallHighlightMatch(self, stack1, card1,
stack2, card2)
and card1.suit == card2.suit)
# ************************************************************************ # ************************************************************************
# * Tens # * Tens
@ -698,6 +670,10 @@ class Tens(ElevensToo):
def createGame(self): def createGame(self):
Elevens.createGame(self, rows=2, cols=7, maxpiles=13, reserves=4) Elevens.createGame(self, rows=2, cols=7, maxpiles=13, reserves=4)
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return (card1.rank + card2.rank == 8 or
(8 < card1.rank == card2.rank > 8))
class Nines_RowStack(Elevens_RowStack): class Nines_RowStack(Elevens_RowStack):
ACCEPTED_SUM = 7 ACCEPTED_SUM = 7
@ -742,6 +718,10 @@ class Nines(Tens):
def createGame(self): def createGame(self):
Elevens.createGame(self, rows=3, cols=3, reserves=4) Elevens.createGame(self, rows=3, cols=3, reserves=4)
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return (card1.rank + card2.rank == 7 or
(8 < card1.rank != card2.rank > 8))
# ************************************************************************ # ************************************************************************
# * The Lucky Number # * The Lucky Number
@ -881,6 +861,9 @@ class Fifteens(Elevens):
self._dropReserve() self._dropReserve()
self.leaveState(old_state) self.leaveState(old_state)
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return card1.rank + card2.rank == 13
# ************************************************************************ # ************************************************************************
# * Eighteens # * Eighteens
@ -973,6 +956,9 @@ class Eighteens(Fifteens):
self._dropReserve() self._dropReserve()
self.leaveState(old_state) self.leaveState(old_state)
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return False # How?
# ************************************************************************ # ************************************************************************
# * Neptune # * Neptune
@ -1002,6 +988,10 @@ class Neptune(Thirteens):
def isGameWon(self): def isGameWon(self):
return len(self.s.talon.cards) == 0 return len(self.s.talon.cards) == 0
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return (card1.rank == card2.rank - 1 or
card1.rank == card2.rank + 1)
# ************************************************************************ # ************************************************************************
# * Eight Cards # * Eight Cards
@ -1094,6 +1084,9 @@ class EightCards(Thirteens):
# save vars (for undo/redo) # save vars (for undo/redo)
return [self.draws] return [self.draws]
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return card1.rank + card2.rank == 9
# ************************************************************************ # ************************************************************************
# * Triple Alliance # * Triple Alliance
@ -1422,6 +1415,10 @@ class ElevenTriangle(Apophis):
INVERT = True INVERT = True
MAX_ROUNDS = 1 MAX_ROUNDS = 1
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return (card1.rank + card2.rank == 9 or
(9 < card1.rank == card2.rank > 9))
# ************************************************************************ # ************************************************************************
# * Cheops # * Cheops
@ -1791,6 +1788,8 @@ class Hurricane_Reserve(Hurricane_StackMethods, OpenStack):
class Hurricane(Pyramid): class Hurricane(Pyramid):
Hint_Class = Hurricane_Hint Hint_Class = Hurricane_Hint
RowStack_Class = Hurricane_RowStack
Reserve_Class = Hurricane_Reserve
def createGame(self): def createGame(self):
# create layout # create layout
@ -1808,7 +1807,7 @@ class Hurricane(Pyramid):
(0, 2), (1, 2), (2, 2), (3, 2), (0, 2), (1, 2), (2, 2), (3, 2),
): ):
x, y = layout.XM + 1.5*layout.XS + ww*xx, layout.YM + layout.YS*yy x, y = layout.XM + 1.5*layout.XS + ww*xx, layout.YM + layout.YS*yy
stack = Hurricane_Reserve(x, y, self, max_accept=1) stack = self.Reserve_Class(x, y, self, max_accept=1)
stack.CARD_XOFFSET, stack.CARD_YOFFSET = layout.XOFFSET, 0 stack.CARD_XOFFSET, stack.CARD_YOFFSET = layout.XOFFSET, 0
s.reserves.append(stack) s.reserves.append(stack)
@ -1816,7 +1815,7 @@ class Hurricane(Pyramid):
x = layout.XM + 1.5*layout.XS + layout.XS+2*layout.XOFFSET + d//2 x = layout.XM + 1.5*layout.XS + layout.XS+2*layout.XOFFSET + d//2
y = layout.YM+layout.YS y = layout.YM+layout.YS
for i in range(3): for i in range(3):
stack = Hurricane_RowStack(x, y, self, max_accept=1) stack = self.RowStack_Class(x, y, self, max_accept=1)
s.rows.append(stack) s.rows.append(stack)
x += layout.XS x += layout.XS
@ -1846,6 +1845,45 @@ class Hurricane(Pyramid):
self.s.talon.moveMove(1, stack) self.s.talon.moveMove(1, stack)
self.leaveState(old_state) self.leaveState(old_state)
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return card1.rank + card2.rank == 12
# ************************************************************************
# * 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
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return (card1.rank + card2.rank == 13 or
card1.rank + card2.rank == 0)
# register the game # register the game
registerGame(GameInfo(38, Pyramid, "Pyramid", registerGame(GameInfo(38, Pyramid, "Pyramid",
@ -1854,8 +1892,8 @@ registerGame(GameInfo(193, RelaxedPyramid, "Relaxed Pyramid",
GI.GT_PAIRING_TYPE | GI.GT_RELAXED, 1, 2, GI.GT_PAIRING_TYPE | GI.GT_RELAXED, 1, 2,
GI.SL_MOSTLY_LUCK, GI.SL_MOSTLY_LUCK,
altnames=("Pyramid's Stones", "Pyramid Clear"))) altnames=("Pyramid's Stones", "Pyramid Clear")))
# registerGame(GameInfo(44, Thirteen, "Thirteen", registerGame(GameInfo(44, Thirteen, "Pyramid Thirteen",
# GI.GT_PAIRING_TYPE, 1, 0)) GI.GT_PAIRING_TYPE, 1, 0, GI.SL_MOSTLY_LUCK))
registerGame(GameInfo(592, Giza, "Giza", registerGame(GameInfo(592, Giza, "Giza",
GI.GT_PAIRING_TYPE | GI.GT_OPEN, 1, 0, GI.SL_BALANCED)) GI.GT_PAIRING_TYPE | GI.GT_OPEN, 1, 0, GI.SL_BALANCED))
registerGame(GameInfo(593, Thirteens, "Thirteens", registerGame(GameInfo(593, Thirteens, "Thirteens",
@ -1874,7 +1912,8 @@ registerGame(GameInfo(619, TripleAlliance, "Triple Alliance",
GI.GT_PAIRING_TYPE | GI.GT_OPEN, 1, 0, GI.GT_PAIRING_TYPE | GI.GT_OPEN, 1, 0,
GI.SL_MOSTLY_SKILL, altnames=('Triplets',))) GI.SL_MOSTLY_SKILL, altnames=('Triplets',)))
registerGame(GameInfo(655, Pharaohs, "Pharaohs", registerGame(GameInfo(655, Pharaohs, "Pharaohs",
GI.GT_PAIRING_TYPE | GI.GT_OPEN, 1, 0, GI.SL_BALANCED)) GI.GT_PAIRING_TYPE | GI.GT_OPEN, 1, 0, GI.SL_BALANCED,
altnames=("Three Pharaohs",)))
registerGame(GameInfo(657, Baroness, "Baroness", registerGame(GameInfo(657, Baroness, "Baroness",
GI.GT_PAIRING_TYPE, 1, 0, GI.SL_BALANCED, GI.GT_PAIRING_TYPE, 1, 0, GI.SL_BALANCED,
altnames=('Five Piles',))) altnames=('Five Piles',)))
@ -1895,7 +1934,7 @@ registerGame(GameInfo(699, DoublePyramid, "Double Pyramid",
GI.GT_PAIRING_TYPE, 2, 2, GI.SL_MOSTLY_LUCK)) GI.GT_PAIRING_TYPE, 2, 2, GI.SL_MOSTLY_LUCK))
registerGame(GameInfo(700, Triangle, "Triangle", registerGame(GameInfo(700, Triangle, "Triangle",
GI.GT_PAIRING_TYPE, 1, 2, GI.SL_MOSTLY_LUCK, GI.GT_PAIRING_TYPE, 1, 2, GI.SL_MOSTLY_LUCK,
altnames=('Yield',))) altnames=('Yield', 'Funnel')))
registerGame(GameInfo(701, UpAndDown, "Up and Down", registerGame(GameInfo(701, UpAndDown, "Up and Down",
GI.GT_PAIRING_TYPE | GI.GT_ORIGINAL, 2, 2, GI.GT_PAIRING_TYPE | GI.GT_ORIGINAL, 2, 2,
GI.SL_MOSTLY_LUCK)) GI.SL_MOSTLY_LUCK))
@ -1927,3 +1966,6 @@ registerGame(GameInfo(961, Nines, "Nines",
GI.GT_PAIRING_TYPE, 1, 0, GI.SL_LUCK)) GI.GT_PAIRING_TYPE, 1, 0, GI.SL_LUCK))
registerGame(GameInfo(969, ElevenTriangle, "Eleven Triangle", registerGame(GameInfo(969, ElevenTriangle, "Eleven Triangle",
GI.GT_PAIRING_TYPE, 1, 0, GI.SL_MOSTLY_LUCK)) 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

@ -231,6 +231,58 @@ class Kingdom(RoyalCotillion):
self.s.talon.dealCards() # deal first card to WasteStack self.s.talon.dealCards() # deal first card to WasteStack
# ************************************************************************
# * Noumea
# ************************************************************************
class Noumea(RoyalCotillion):
Foundation_Class = SS_FoundationStack
def createGame(self):
# create layout
l, s = Layout(self), self.s
# set window
self.setSize(l.XM + 5*l.XS, l.YM + 6*l.YS)
# create stacks
x, y, = l.XM + .5 * l.XS, l.YM
for i in range(4):
s.foundations.append(self.Foundation_Class(x, y, self, i))
x += l.XS
x, y, = l.XM, y + l.YS
for j in range(4):
for i in range(5):
s.reserves.append(ReserveStack(x, y, self, max_accept=0))
x += l.XS
x = l.XM
y += l.YS
x, y = l.XM + 1.5 * l.XS, l.YM + 5 * l.YS
s.talon = WasteTalonStack(x, y, self, max_rounds=3, num_deal=3)
l.createText(s.talon, "sw")
x += l.XS
s.waste = WasteStack(x, y, self)
l.createText(s.waste, "se")
# define stack-groups
l.defaultStackGroups()
#
# game overrides
#
def _shuffleHook(self, cards):
# move Aces to top of the Talon (i.e. first cards to be dealt)
return self._shuffleHookMoveToTop(
cards, lambda c: (c.rank == ACE, c.suit))
def startGame(self):
self.s.talon.dealRow(rows=self.s.foundations, frames=0)
self.startDealSample()
self.s.talon.dealRow(rows=self.s.reserves)
self.s.talon.dealCards() # deal first card to WasteStack
# ************************************************************************ # ************************************************************************
# * Alhambra # * Alhambra
# * Granada # * Granada
@ -1573,13 +1625,14 @@ registerGame(GameInfo(54, RoyalCotillion, "Royal Cotillion",
GI.GT_2DECK_TYPE, 2, 0, GI.SL_LUCK, GI.GT_2DECK_TYPE, 2, 0, GI.SL_LUCK,
altnames=("Lords and Ladies",))) altnames=("Lords and Ladies",)))
registerGame(GameInfo(55, OddAndEven, "Odd and Even", registerGame(GameInfo(55, OddAndEven, "Odd and Even",
GI.GT_2DECK_TYPE, 2, 1, GI.SL_LUCK)) GI.GT_2DECK_TYPE | GI.GT_CHILDREN, 2, 1, GI.SL_LUCK))
registerGame(GameInfo(143, Kingdom, "Kingdom", registerGame(GameInfo(143, Kingdom, "Kingdom",
GI.GT_2DECK_TYPE, 2, 0, GI.SL_MOSTLY_LUCK)) GI.GT_2DECK_TYPE, 2, 0, GI.SL_MOSTLY_LUCK))
registerGame(GameInfo(234, Alhambra, "Alhambra", registerGame(GameInfo(234, Alhambra, "Alhambra",
GI.GT_2DECK_TYPE, 2, 2, GI.SL_BALANCED)) GI.GT_2DECK_TYPE, 2, 2, GI.SL_BALANCED))
registerGame(GameInfo(97, Carpet, "Carpet", registerGame(GameInfo(97, Carpet, "Carpet",
GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_LUCK)) GI.GT_1DECK_TYPE | GI.GT_CHILDREN, 1, 0,
GI.SL_MOSTLY_LUCK))
registerGame(GameInfo(391, BritishConstitution, "British Constitution", registerGame(GameInfo(391, BritishConstitution, "British Constitution",
GI.GT_2DECK_TYPE | GI.GT_STRIPPED, 2, 0, GI.SL_BALANCED, GI.GT_2DECK_TYPE | GI.GT_STRIPPED, 2, 0, GI.SL_BALANCED,
ranks=list(range(11)), # without Queens and Kings ranks=list(range(11)), # without Queens and Kings
@ -1623,3 +1676,5 @@ registerGame(GameInfo(943, RosamundsBower, "Rosamund's Bower",
altnames=("Rosamund",))) altnames=("Rosamund",)))
registerGame(GameInfo(952, BigAlhambra, "Big Alhambra", registerGame(GameInfo(952, BigAlhambra, "Big Alhambra",
GI.GT_3DECK_TYPE, 3, 2, GI.SL_BALANCED)) GI.GT_3DECK_TYPE, 3, 2, GI.SL_BALANCED))
registerGame(GameInfo(978, Noumea, "Noumea",
GI.GT_1DECK_TYPE, 1, 2, GI.SL_MOSTLY_LUCK))

View file

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

View file

@ -355,7 +355,7 @@ class CribbagePatience_HandStack(ReserveStack):
def clickHandler(self, event): def clickHandler(self, event):
for s in self.game.s.rows[0:4]: for s in self.game.s.rows[0:4]:
if len(s.cards) == 0: if len(s.cards) == 0 and s.acceptsCards(self, self.cards):
return self.playMoveMove(1, s) return self.playMoveMove(1, s)
return 0 return 0
@ -367,26 +367,32 @@ class CribbagePatience_HandStack(ReserveStack):
def moveMove(self, ncards, to_stack, frames=-1, shadow=-1): def moveMove(self, ncards, to_stack, frames=-1, shadow=-1):
ReserveStack.moveMove(self, ncards, to_stack, frames=frames, ReserveStack.moveMove(self, ncards, to_stack, frames=frames,
shadow=shadow) shadow=shadow)
self.game.dealAdditionalHand()
if self.game.isBoardFull(): if self.game.isBoardFull():
self.game.finalizeHand() self.game.finalizeHand()
class CribbagePatience_CribStack(ReserveStack): class CribbagePatience_CribStack(ReserveStack):
def acceptsCards(self, from_stack, cards): def acceptsCards(self, from_stack, cards):
if from_stack not in self.game.s.rows[4:10]: if from_stack not in self.game.s.rows[4:]:
return False
if self.game.HANDS > 1:
if (len(self.game.s.rows[10].cards) > 0 and
from_stack not in self.game.s.rows[10:]):
return False return False
return ReserveStack.acceptsCards(self, from_stack, cards) return ReserveStack.acceptsCards(self, from_stack, cards)
class CribbagePatience(CribbageShuffle): class CribbagePatience(CribbageShuffle):
WIN_SCORE = 61 WIN_SCORE = 80
HANDS = 1
def createGame(self): def createGame(self):
self.score = 0 self.score = 0
self.isFinalizedHand = False self.isFinalizedHand = False
l, s = Layout(self), self.s l, s = Layout(self), self.s
self.setSize((2 * l.XM) + 8 * l.XS, self.setSize((2 * l.XM) + 8 * l.XS,
l.YM + l.YS + 12 * l.YOFFSET) l.YM + ((self.HANDS + 1) * l.YS))
x, y = self.getInvisibleCoords() x, y = self.getInvisibleCoords()
s.waste = ReserveStack(x, y, self) s.waste = ReserveStack(x, y, self)
x, y = l.XM, l.YM x, y = l.XM, l.YM
@ -398,20 +404,33 @@ class CribbagePatience(CribbageShuffle):
x += l.XS x += l.XS
x, y = l.XM, l.YM + l.YS x, y = l.XM, l.YM + l.YS
s.reserves.append(ReserveStack(x, y, self)) s.reserves.append(ReserveStack(x, y, self))
for i in range(self.HANDS):
x += 2 * l.XS x += 2 * l.XS
for i in range(6): for i in range(6):
s.rows.append(CribbagePatience_HandStack(x, y, self, max_move=1)) s.rows.append(CribbagePatience_HandStack(x, y, self,
max_move=1))
x += l.XS x += l.XS
x, y = l.XM, y + l.YS
# define hands for scoring # define hands for scoring
r = s.rows r = s.rows
if self.HANDS == 1:
self.cribbage_hands = [ self.cribbage_hands = [
r[0:4], r[4:8] r[0:4], r[4:8]
] ]
else:
self.cribbage_hands = [
r[0:4], r[4:8], r[10:14]
]
self.cribbage_hands = list(map(tuple, self.cribbage_hands)) self.cribbage_hands = list(map(tuple, self.cribbage_hands))
if self.preview <= 1: if self.preview <= 1:
for i in (0, 4): if self.HANDS == 2:
scores = (0, 4, 10)
else:
scores = (0, 4)
for i in scores:
tx, ty, ta, tf = l.getTextAttr(s.rows[i], anchor="w") tx, ty, ta, tf = l.getTextAttr(s.rows[i], anchor="w")
t = MfxCanvasText(self.canvas, tx - 8, ty, t = MfxCanvasText(self.canvas, tx - 8, ty,
anchor=ta, anchor=ta,
@ -444,11 +463,12 @@ class CribbagePatience(CribbageShuffle):
def dealHand(self): def dealHand(self):
self.startDealSample() self.startDealSample()
self.saveStateMove(2 | 16)
if self.isFinalizedHand: if self.isFinalizedHand:
for r in reversed(self.s.rows[:8]): for r in reversed(self.s.rows):
if (len(r.cards) > 0):
r.moveMove(1, self.s.waste) r.moveMove(1, self.s.waste)
self.s.reserves[0].moveMove(1, self.s.waste) self.s.reserves[0].moveMove(1, self.s.waste)
self.saveStateMove(2 | 16)
self.isFinalizedHand = False self.isFinalizedHand = False
self.saveStateMove(1 | 16) self.saveStateMove(1 | 16)
@ -456,6 +476,9 @@ class CribbagePatience(CribbageShuffle):
self.s.talon.dealRow(rows=self.s.rows[4:10]) self.s.talon.dealRow(rows=self.s.rows[4:10])
self.stopSamples() self.stopSamples()
def dealAdditionalHand(self):
return
def isBoardFull(self): def isBoardFull(self):
for i in range(8): for i in range(8):
if len(self.s.rows[i].cards) == 0: if len(self.s.rows[i].cards) == 0:
@ -474,7 +497,7 @@ class CribbagePatience(CribbageShuffle):
self.s.talon.flipMove() self.s.talon.flipMove()
self.s.talon.moveMove(1, self.s.reserves[0]) self.s.talon.moveMove(1, self.s.reserves[0])
self.leaveState(old_state) self.leaveState(old_state)
for i in range(2): for i in range(len(self.cribbage_hands)):
value = self.getHandScore(self.cribbage_hands[i]) value = self.getHandScore(self.cribbage_hands[i])
self.texts.list[i].config(text=str(value)) self.texts.list[i].config(text=str(value))
self.score += value self.score += value
@ -485,12 +508,12 @@ class CribbagePatience(CribbageShuffle):
if self.preview > 1: if self.preview > 1:
return return
if self.isBoardFull(): if self.isBoardFull():
for i in range(2): for i in range(len(self.cribbage_hands)):
value = self.getHandScore(self.cribbage_hands[i]) value = self.getHandScore(self.cribbage_hands[i])
self.texts.list[i].config(text=str(value)) self.texts.list[i].config(text=str(value))
else: else:
for i in range(2): for i in range(len(self.cribbage_hands)):
self.texts.list[i].config(text="") self.texts.list[i].config(text="")
# #
t = "" t = ""
@ -499,6 +522,10 @@ class CribbagePatience(CribbageShuffle):
t += _("Total: %d") % self.score t += _("Total: %d") % self.score
self.texts.score.config(text=t) self.texts.score.config(text=t)
def _autoDeal(self, sound=True):
# don't deal a card to the waste if the waste is empty
return 0
def getUpcardStack(self): def getUpcardStack(self):
return self.s.reserves[0] return self.s.reserves[0]
@ -526,6 +553,66 @@ class CribbagePatience(CribbageShuffle):
return [self.score, self.isFinalizedHand] return [self.score, self.isFinalizedHand]
class CribbagePatienceII(CribbagePatience):
WIN_SCORE = 80
HANDS = 2
def startGame(self):
self.score = 0
self.isFinalizedHand = False
self.dealHand()
def fillStack(self, stack):
if not stack.cards:
old_state = self.enterState(self.S_FILL)
hand = self.s.rows[4:10] + self.s.rows[10:16]
if stack in hand:
i = list(hand).index(stack)
if i < len(hand)-1:
from_stack = hand[i+1]
pile = from_stack.getPile()
if pile:
from_stack.moveMove(len(pile), stack)
self.leaveState(old_state)
def dealHand(self):
self.startDealSample()
if self.isFinalizedHand:
for r in reversed(self.s.rows):
if (len(r.cards) > 0):
r.moveMove(1, self.s.waste)
self.s.reserves[0].moveMove(1, self.s.waste)
self.saveStateMove(2 | 16)
self.isFinalizedHand = False
self.saveStateMove(1 | 16)
self.s.talon.dealRow(rows=self.s.rows[4:10])
self.stopSamples()
def dealAdditionalHand(self):
for i in range(2):
if len(self.s.rows[i].cards) == 0:
return
for i in range(2, 4):
if len(self.s.rows[i].cards) > 0:
return
if len(self.s.rows[10].cards) == 0:
self.startDealSample()
self.saveStateMove(2 | 16)
self.s.talon.dealRow(rows=self.s.rows[10:16])
self.saveStateMove(1 | 16)
self.stopSamples()
def isBoardFull(self):
for i in range(8):
if len(self.s.rows[i].cards) == 0:
return False
for i in range(10, 14):
if len(self.s.rows[i].cards) == 0:
return False
return True
# register the game # register the game
registerGame(GameInfo(805, CribbageSquare, "Cribbage Square", registerGame(GameInfo(805, CribbageSquare, "Cribbage Square",
GI.GT_CRIBBAGE_TYPE | GI.GT_SCORE, 1, 0, GI.GT_CRIBBAGE_TYPE | GI.GT_SCORE, 1, 0,
@ -551,3 +638,6 @@ registerGame(GameInfo(809, CribbageShuffle, "Cribbage Shuffle",
registerGame(GameInfo(955, CribbagePatience, "Cribbage Patience", registerGame(GameInfo(955, CribbagePatience, "Cribbage Patience",
GI.GT_CRIBBAGE_TYPE | GI.GT_SCORE, 1, 0, GI.GT_CRIBBAGE_TYPE | GI.GT_SCORE, 1, 0,
GI.SL_MOSTLY_SKILL)) GI.SL_MOSTLY_SKILL))
registerGame(GameInfo(980, CribbagePatienceII, "Cribbage Patience II",
GI.GT_CRIBBAGE_TYPE | GI.GT_SCORE, 1, 0,
GI.SL_MOSTLY_SKILL))

View file

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

View file

@ -62,7 +62,8 @@ class HexATrump_Foundation(HexADeck_FoundationStack):
def acceptsCards(self, from_stack, cards): def acceptsCards(self, from_stack, cards):
if not self.basicAcceptsCards(from_stack, cards): if not self.basicAcceptsCards(from_stack, cards):
return 0 return 0
for s in self.game.s.foundations[:3]: for s in self.game.s.foundations[:((self.game.gameinfo.decks
* 4) - 1)]:
if len(s.cards) != 16: if len(s.cards) != 16:
return 0 return 0
return 1 return 1
@ -93,10 +94,11 @@ class Merlins_Foundation(AbstractFoundationStack):
class HexADeck_OpenStack(OpenStack): class HexADeck_OpenStack(OpenStack):
def __init__(self, x, y, game, yoffset, **cap): def __init__(self, x, y, game, yoffset=None, **cap):
kwdefault(cap, max_move=UNLIMITED_MOVES, max_accept=UNLIMITED_ACCEPTS, kwdefault(cap, max_move=UNLIMITED_MOVES, max_accept=UNLIMITED_ACCEPTS,
dir=-1) dir=-1)
OpenStack.__init__(self, x, y, game, **cap) OpenStack.__init__(self, x, y, game, **cap)
if yoffset is not None:
self.CARD_YOFFSET = yoffset self.CARD_YOFFSET = yoffset
def isRankSequence(self, cards, dir=None): def isRankSequence(self, cards, dir=None):
@ -1498,7 +1500,6 @@ class HexYukon(Game):
shallHighlightMatch = Game._shallHighlightMatch_AC shallHighlightMatch = Game._shallHighlightMatch_AC
# ************************************************************************ # ************************************************************************
# * # *
# ************************************************************************ # ************************************************************************
@ -1600,16 +1601,162 @@ class MagicMontana(Montana):
return True return True
# ************************************************************************
# * Wizard's Storeroom
# ************************************************************************
class WizardsStoreroom(AbstractHexADeckGame):
MAX_ROUNDS = 2
#
# Game layout
#
def createGame(self):
l, s = Layout(self), self.s
# Set window size
decks = self.gameinfo.decks
self.setSize(2*l.XM + (2 + 5*decks)*l.XS, 3*l.YM + 5*l.YS)
yoffset = min(l.YOFFSET, max(10, l.YOFFSET // 2))
# Create talon
x = l.XM
y = l.YM
s.talon = WasteTalonStack(
x, y, self, num_deal=1, max_rounds=self.MAX_ROUNDS)
l.createText(s.talon, "s")
x = x + l.XS
s.waste = WasteStack(x, y, self)
l.createText(s.waste, "s")
# Create foundations
x = x + l.XM + l.XS
for j in range(4):
for i in range(decks):
s.foundations.append(
SS_FoundationStack(x, y, self, j, max_cards=16))
x = x + l.XS
for i in range(decks):
s.foundations.append(
HexATrump_Foundation(x, y, self, 4, max_cards=4))
x = x + l.XS
# Create reserve
x = l.XM
y = l.YM + l.YS + l.TEXT_HEIGHT
s.reserves.append(OpenStack(x, y, self))
s.reserves[0].CARD_YOFFSET = (l.YOFFSET, yoffset)[decks == 2]
# Create rows
x = x + l.XM + l.XS
for i in range(4*decks+1):
s.rows.append(HexAKlon_RowStack(x, y, self))
x = x + l.XS
self.setRegion(s.rows, (-999, y - l.YS, 999999, 999999))
# Define stack groups
l.defaultStackGroups()
#
# Game over rides
#
def startGame(self):
decks = self.gameinfo.decks
self.startDealSample()
for i in range(14 * decks):
self.s.talon.dealRow(rows=self.s.reserves, flip=0, frames=4)
self.s.reserves[0].flipMove()
self.s.talon.dealRow(rows=self.s.rows)
self.s.talon.dealCards() # deal first card to WasteStack
def fillStack(self, stack):
r = self.s.reserves[0]
if not stack.cards and stack in self.s.rows:
if r.cards and stack.acceptsCards(r, r.cards[-1:]):
r.moveMove(1, stack)
if r.canFlipCard():
r.flipMove()
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return ((card1.rank + 1 == card2.rank or
card1.rank - 1 == card2.rank) and
card1.color != card2.color)
# ************************************************************************
# * Wizard's Castle
# ************************************************************************
class WizardsCastle(AbstractHexADeckGame):
Hint_Class = CautiousDefaultHint
#
# Game layout
#
def createGame(self):
l, s = Layout(self), self.s
# Set window size
h = max(5 * l.YS, 20 * l.YOFFSET)
self.setSize(l.XM + 9 * l.XS, l.YM + l.YS + h)
# Create foundations
x = self.width - l.XS
y = l.YM
s.foundations.append(SS_FoundationStack(x, y, self, 4, max_cards=22))
y = y + l.YS
for i in range(4):
s.foundations.append(
SS_FoundationStack(x, y, self, i, max_cards=14))
y = y + l.YS
# Create rows
x = l.XM
y = l.YM
for j in range(2):
for i in range(8):
s.rows.append(
HexAKlon_RowStack(x, y, self, max_move=1, max_accept=1))
x = x + l.XS
x = l.XM
y = y + l.YS * 3
self.setRegion(s.rows, (-999, -999, l.XM + l.XS * 8, 999999))
# Create talon
s.talon = InitialDealTalonStack(l.XM, self.height-l.YS, self)
# Define stack groups
l.defaultStackGroups()
#
# Game over rides
#
def startGame(self):
for i in range(2):
self.s.talon.dealRow(flip=0, frames=0)
self.s.talon.dealRow(flip=0, frames=0)
self.s.talon.dealRow(rows=self.s.rows[:4], flip=0, frames=0)
self._startAndDealRow()
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return (card1.suit == card2.suit and
(card1.rank + 1 == card2.rank or card2.rank + 1 == card1.rank))
# ************************************************************************ # ************************************************************************
# * # *
# ************************************************************************ # ************************************************************************
def r(id, gameclass, name, game_type, decks, redeals, skill_level): def r(id, gameclass, name, game_type, decks, redeals, skill_level,
altnames=()):
game_type = game_type | GI.GT_HEXADECK game_type = game_type | GI.GT_HEXADECK
gi = GameInfo(id, gameclass, name, game_type, decks, redeals, skill_level, gi = GameInfo(id, gameclass, name, game_type, decks, redeals, skill_level,
suits=list(range(4)), ranks=list(range(16)), suits=list(range(4)), ranks=list(range(16)),
trumps=list(range(4))) trumps=list(range(4)), altnames=altnames)
registerGame(gi) registerGame(gi)
return gi return gi
@ -1633,7 +1780,7 @@ r(16674, HiddenPassages, 'Hidden Passages', GI.GT_HEXADECK, 1, 1,
r(16675, CluitjarsLair, 'Cluitjar\'s Lair', GI.GT_HEXADECK, 1, 0, r(16675, CluitjarsLair, 'Cluitjar\'s Lair', GI.GT_HEXADECK, 1, 0,
GI.SL_BALANCED) GI.SL_BALANCED)
r(16676, MerlinsMeander, 'Merlin\'s Meander', GI.GT_HEXADECK, 2, 2, r(16676, MerlinsMeander, 'Merlin\'s Meander', GI.GT_HEXADECK, 2, 2,
GI.SL_BALANCED) GI.SL_BALANCED, altnames=('Merlin\'s Coil'))
r(16677, MagesGame, 'Mage\'s Game', GI.GT_HEXADECK | GI.GT_OPEN, 1, 0, r(16677, MagesGame, 'Mage\'s Game', GI.GT_HEXADECK | GI.GT_OPEN, 1, 0,
GI.SL_BALANCED) GI.SL_BALANCED)
r(16678, Convolution, 'Convolution', GI.GT_HEXADECK | GI.GT_OPEN, 2, 0, r(16678, Convolution, 'Convolution', GI.GT_HEXADECK | GI.GT_OPEN, 2, 0,
@ -1645,4 +1792,10 @@ r(16680, Snakestone, 'Snakestone', GI.GT_HEXADECK | GI.GT_OPEN, 2, 0,
r(16681, HexYukon, 'Hex Yukon', GI.GT_HEXADECK, 1, 0, GI.SL_BALANCED) r(16681, HexYukon, 'Hex Yukon', GI.GT_HEXADECK, 1, 0, GI.SL_BALANCED)
r(16682, MagicMontana, 'Magic Montana', GI.GT_HEXADECK | GI.GT_OPEN, 1, 2, r(16682, MagicMontana, 'Magic Montana', GI.GT_HEXADECK | GI.GT_OPEN, 1, 2,
GI.SL_MOSTLY_SKILL) GI.SL_MOSTLY_SKILL)
r(16683, WizardsStoreroom, "Wizard's Storeroom", GI.GT_HEXADECK, 1, 1,
GI.SL_MOSTLY_SKILL)
r(16684, WizardsStoreroom, "Big Storeroom", GI.GT_HEXADECK, 2, 1,
GI.SL_MOSTLY_SKILL)
r(16685, WizardsCastle, "Wizard's Castle", GI.GT_HEXADECK, 1, 0,
GI.SL_BALANCED)
del r del r

View file

@ -99,6 +99,9 @@ class Ishido(Game):
STRICT_FOUR_WAYS = True STRICT_FOUR_WAYS = True
SCORING = False SCORING = False
COLS = 12
ROWS = 8
# #
# game layout # game layout
# #
@ -115,13 +118,13 @@ class Ishido(Game):
w2 = max(2 * l.XS, x) w2 = max(2 * l.XS, x)
# set window # set window
w, h = w2 + l.XM * 2 + l.CW * 12, l.YM * 2 + l.CH * 8 w, h = w2 + l.XM * 2 + l.CW * self.COLS, l.YM * 2 + l.CH * self.ROWS
self.setSize(w, h) self.setSize(w, h)
# Create rows # Create rows
for j in range(8): for j in range(self.ROWS):
x, y = w2 + l.XM, l.YM + l.CH * j x, y = w2 + l.XM, l.YM + l.CH * j
for i in range(12): for i in range(self.COLS):
s.rows.append(self.RowStack_Class(x, y, self)) s.rows.append(self.RowStack_Class(x, y, self))
x = x + l.CW x = x + l.CW
@ -269,17 +272,17 @@ class Ishido(Game):
def getAdjacent(self, playSpace): def getAdjacent(self, playSpace):
adjacentRows = [] adjacentRows = []
if playSpace % 12 != 11: if playSpace % self.COLS != self.COLS - 1:
adjacentRows.append(self.s.rows[playSpace + 1]) adjacentRows.append(self.s.rows[playSpace + 1])
if playSpace % 12 != 0: if playSpace % self.COLS != 0:
adjacentRows.append(self.s.rows[playSpace - 1]) adjacentRows.append(self.s.rows[playSpace - 1])
if playSpace + 12 < 96: if playSpace + self.COLS < (self.COLS * self.ROWS):
adjacentRows.append(self.s.rows[playSpace + 12]) adjacentRows.append(self.s.rows[playSpace + self.COLS])
if playSpace - 12 > -1: if playSpace - self.COLS > -1:
adjacentRows.append(self.s.rows[playSpace - 12]) adjacentRows.append(self.s.rows[playSpace - self.COLS])
return adjacentRows return adjacentRows
@ -301,10 +304,46 @@ class IshidoScored(Ishido):
SCORING = True SCORING = True
class LittleIshido(Ishido):
ROWS = 6
COLS = 8
def startGame(self):
self.score = 0
self.fourways = 0
self.moveMove(1, self.s.talon, self.s.rows[0], frames=0)
self.s.rows[0].flipMove()
self.moveMove(1, self.s.talon, self.s.rows[7], frames=0)
self.s.rows[7].flipMove()
self.moveMove(1, self.s.talon, self.s.rows[40], frames=0)
self.s.rows[40].flipMove()
self.moveMove(1, self.s.talon, self.s.rows[47], frames=0)
self.s.rows[47].flipMove()
self.s.talon.fillStack()
def _shuffleHook(self, cards):
# prepare first cards
symbols = []
colors = []
topcards = []
for c in cards[:]:
if c.suit not in colors and c.rank not in symbols:
topcards.append(c)
cards.remove(c)
symbols.append(c.rank)
colors.append(c.suit)
if len(colors) >= 4 or len(symbols) >= 4:
break
return cards + topcards
class LittleIshidoRelaxed(LittleIshido):
STRICT_FOUR_WAYS = False
def r(id, gameclass, name, decks, redeals, skill_level, def r(id, gameclass, name, decks, redeals, skill_level,
game_type=GI.GT_ISHIDO): game_type=GI.GT_ISHIDO, colors=6):
gi = GameInfo(id, gameclass, name, game_type, decks, redeals, skill_level, gi = GameInfo(id, gameclass, name, game_type, decks, redeals, skill_level,
ranks=list(range(6)), suits=list(range(6)), ranks=list(range(colors)), suits=list(range(colors)),
category=GI.GC_ISHIDO) category=GI.GC_ISHIDO)
registerGame(gi) registerGame(gi)
return gi return gi
@ -316,3 +355,6 @@ r(18002, FreeIshido, 'Free Ishido', 2, 0, GI.SL_MOSTLY_SKILL)
r(18003, FreeIshidoRelaxed, 'Free Ishido Relaxed', 2, 0, GI.SL_MOSTLY_SKILL) r(18003, FreeIshidoRelaxed, 'Free Ishido Relaxed', 2, 0, GI.SL_MOSTLY_SKILL)
r(18004, IshidoScored, 'Ishido Scored', 2, 0, GI.SL_MOSTLY_SKILL, r(18004, IshidoScored, 'Ishido Scored', 2, 0, GI.SL_MOSTLY_SKILL,
game_type=GI.GT_ISHIDO | GI.GT_SCORE) game_type=GI.GT_ISHIDO | GI.GT_SCORE)
r(18005, LittleIshido, 'Little Ishido', 2, 0, GI.SL_MOSTLY_SKILL, colors=4)
r(18006, LittleIshidoRelaxed, 'Little Ishido Relaxed', 2, 0,
GI.SL_MOSTLY_SKILL, colors=4)

View file

@ -222,6 +222,7 @@ def r(id, short_name, width):
return gi return gi
r(22399, "Lights Out 3x3", 3)
r(22400, "Lights Out 4x4", 4) r(22400, "Lights Out 4x4", 4)
r(22401, "Lights Out 5x5", 5) r(22401, "Lights Out 5x5", 5)
r(22402, "Lights Out 6x6", 6) r(22402, "Lights Out 6x6", 6)

View file

@ -71,7 +71,7 @@ class Memory_RowStack(OpenStack):
def _dropPairMove(self, n, other_stack, frames=-1, shadow=-1): def _dropPairMove(self, n, other_stack, frames=-1, shadow=-1):
game = self.game game = self.game
game.playSample("droppair", priority=200) game.playSample("droppair", priority=200)
game.closed_cards = game.closed_cards - 2 game.closed_cards -= 2
game.score = game.score + 5 game.score = game.score + 5
rightclickHandler = clickHandler rightclickHandler = clickHandler
@ -108,6 +108,7 @@ class Memory24(Game):
# game extras # game extras
self.other_stack = None self.other_stack = None
self.other_stack2 = None
self.closed_cards = -1 self.closed_cards = -1
self.score = 0 self.score = 0
@ -255,7 +256,7 @@ class Concentration_RowStack(Memory_RowStack):
def _dropPairMove(self, n, other_stack, frames=-1, shadow=-1): def _dropPairMove(self, n, other_stack, frames=-1, shadow=-1):
game = self.game game = self.game
game.playSample("droppair", priority=200) game.playSample("droppair", priority=200)
game.closed_cards = game.closed_cards - 2 game.closed_cards -= 2
game.score = game.score + 5 game.score = game.score + 5
# #
old_state = game.enterState(game.S_FILL) old_state = game.enterState(game.S_FILL)
@ -271,6 +272,8 @@ class Concentration(Memory24):
WIN_SCORE = 50 WIN_SCORE = 50
PERFECT_SCORE = 130 # 5 * (13*4)/2 PERFECT_SCORE = 130 # 5 * (13*4)/2
RowStack_Class = Concentration_RowStack
# #
# game layout # game layout
# #
@ -281,6 +284,7 @@ class Concentration(Memory24):
# game extras # game extras
self.other_stack = None self.other_stack = None
self.other_stack2 = None
self.closed_cards = -1 self.closed_cards = -1
self.score = 0 self.score = 0
@ -291,11 +295,12 @@ class Concentration(Memory24):
for i in range(self.ROWS): for i in range(self.ROWS):
for j in range(self.COLUMNS): for j in range(self.COLUMNS):
x, y = l.XM + j*l.XS, l.YM + i*l.YS x, y = l.XM + j*l.XS, l.YM + i*l.YS
s.rows.append(Concentration_RowStack(x, y, self, s.rows.append(self.RowStack_Class(x, y, self,
max_move=0, max_accept=0, max_cards=1)) max_move=0, max_accept=0, max_cards=1))
x, y = l.XM + self.COLUMNS*l.XS//2, self.height - l.YS x, y = l.XM + self.COLUMNS*l.XS//2, self.height - l.YS
s.talon = InitialDealTalonStack(x, y, self) s.talon = InitialDealTalonStack(x, y, self)
l.createText(s.talon, dx=-10, anchor="sw", text_format="%D") l.createText(s.talon, dx=-10, anchor="sw", text_format="%D")
s.internals.append(InvisibleStack(self))
# create text # create text
x, y = l.XM, self.height - l.YM x, y = l.XM, self.height - l.YM
@ -390,14 +395,159 @@ class MemorySequence(Memory24):
return card1.suit == card2.suit and card1.rank == card2.rank + 1 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 # register the game
registerGame(GameInfo(886, Memory16, "Memory 16", registerGame(GameInfo(886, Memory16, "Memory 16",
GI.GT_MEMORY | GI.GT_SCORE, 2, 0, GI.SL_SKILL, GI.GT_MEMORY | GI.GT_SCORE | GI.GT_CHILDREN, 2, 0,
category=GI.GC_MATCHING, GI.SL_SKILL, category=GI.GC_MATCHING,
suits=(), ranks=(), trumps=list(range(8)))) suits=(), ranks=(), trumps=list(range(8))))
registerGame(GameInfo(176, Memory24, "Memory 24", registerGame(GameInfo(176, Memory24, "Memory 24",
GI.GT_MEMORY | GI.GT_SCORE, 2, 0, GI.SL_SKILL, GI.GT_MEMORY | GI.GT_SCORE | GI.GT_CHILDREN, 2, 0,
category=GI.GC_MATCHING, GI.SL_SKILL, category=GI.GC_MATCHING,
suits=(), ranks=(), trumps=list(range(12)))) suits=(), ranks=(), trumps=list(range(12))))
registerGame(GameInfo(219, Memory30, "Memory 30", registerGame(GameInfo(219, Memory30, "Memory 30",
GI.GT_MEMORY | GI.GT_SCORE, 2, 0, GI.SL_SKILL, GI.GT_MEMORY | GI.GT_SCORE, 2, 0, GI.SL_SKILL,
@ -417,3 +567,7 @@ registerGame(GameInfo(178, Concentration, "Concentration",
registerGame(GameInfo(843, MemorySequence, "Memory Sequence", registerGame(GameInfo(843, MemorySequence, "Memory Sequence",
GI.GT_MEMORY | GI.GT_SCORE, 1, 0, GI.SL_SKILL, GI.GT_MEMORY | GI.GT_SCORE, 1, 0, GI.SL_SKILL,
suits=(1,), altnames=('Ace Through King',))) 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,10 +1157,12 @@ class AshtaDikapala(Game):
# * # *
# ************************************************************************ # ************************************************************************
def r(id, gameclass, name, game_type, decks, redeals, skill_level): def r(id, gameclass, name, game_type, decks, redeals, skill_level,
altnames=()):
game_type = game_type | GI.GT_MUGHAL_GANJIFA game_type = game_type | GI.GT_MUGHAL_GANJIFA
gi = GameInfo(id, gameclass, name, game_type, decks, redeals, skill_level, gi = GameInfo(id, gameclass, name, game_type, decks, redeals, skill_level,
suits=list(range(8)), ranks=list(range(12))) suits=list(range(8)), ranks=list(range(12)),
altnames=altnames)
registerGame(gi) registerGame(gi)
return gi return gi
@ -1187,6 +1189,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(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(16003, Makara, 'Makara', GI.GT_MUGHAL_GANJIFA, 1, 0, GI.SL_MOSTLY_SKILL)
r(16004, AshtaDikapala, 'Ashta Dikapala', GI.GT_MUGHAL_GANJIFA, 1, 0, r(16004, AshtaDikapala, 'Ashta Dikapala', GI.GT_MUGHAL_GANJIFA, 1, 0,
GI.SL_BALANCED) GI.SL_BALANCED, altnames=('Eight Guardians'))
del r del r

View file

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

View file

@ -348,15 +348,16 @@ class Scorpion_RowStack(Yukon_SS_RowStack, Spider_RowStack):
class Scorpion(RelaxedSpider): class Scorpion(RelaxedSpider):
Hint_Class = YukonType_Hint Hint_Class = YukonType_Hint
RowStack_Class = StackWrapper(Scorpion_RowStack, base_rank=KING) RowStack_Class = StackWrapper(Scorpion_RowStack, base_rank=KING)
FACEDOWNS = (4, 4, 4, 0, 0, 0)
def createGame(self): def createGame(self):
RelaxedSpider.createGame(self, rows=7, playcards=20) RelaxedSpider.createGame(self, rows=7, playcards=20)
def startGame(self): def startGame(self):
for i in (4, 4, 4, 0, 0, 0): for i in self.FACEDOWNS:
self.s.talon.dealRow(rows=self.s.rows[:i], flip=0, frames=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.s.talon.dealRow(rows=self.s.rows[i:], flip=1, frames=0)
self._startAndDealRow() self._startAndDealRow()
@ -379,46 +380,46 @@ class ScorpionTail(Scorpion):
shallHighlightMatch = Game._shallHighlightMatch_AC shallHighlightMatch = Game._shallHighlightMatch_AC
# ************************************************************************
# * Double Scorpion
# * Triple Scorpion
# ************************************************************************
class DoubleScorpion(Scorpion): class DoubleScorpion(Scorpion):
Talon_Class = InitialDealTalonStack FACEDOWNS = (5, 5, 5, 5, 0, 0, 0, 0, 0)
def createGame(self): def createGame(self):
RelaxedSpider.createGame(self, rows=10, playcards=26, texts=0) 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): class TripleScorpion(Scorpion):
Talon_Class = InitialDealTalonStack Talon_Class = InitialDealTalonStack
FACEDOWNS = (5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0)
def createGame(self): def createGame(self):
RelaxedSpider.createGame(self, rows=13, playcards=30, texts=0) RelaxedSpider.createGame(self, rows=13, playcards=30, texts=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) # * Scorpion II
self.s.talon.dealRow(rows=self.s.rows[i:], flip=1, frames=0) # ************************************************************************
self._startAndDealRow()
class ScorpionII(Scorpion):
FACEDOWNS = (3, 3, 3, 0, 0, 0)
# ************************************************************************ # ************************************************************************
# * Wasp # * Wasp
# * Wasp II
# ************************************************************************ # ************************************************************************
class Wasp(Scorpion): class Wasp(Scorpion):
RowStack_Class = Scorpion_RowStack # anything on an empty space RowStack_Class = Scorpion_RowStack # anything on an empty space
def startGame(self):
for i in (3, 3, 3, 0, 0, 0): class WaspII(ScorpionII):
self.s.talon.dealRow(rows=self.s.rows[:i], flip=0, frames=0) RowStack_Class = Scorpion_RowStack
self.s.talon.dealRow(rows=self.s.rows[i:], flip=1, frames=0)
self._startAndDealRow()
# ************************************************************************ # ************************************************************************
@ -1124,19 +1125,6 @@ class Incompatibility(Spidike):
self._startDealNumRowsAndDealSingleRow(4) 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 # * Tarantula
# ************************************************************************ # ************************************************************************
@ -1158,6 +1146,7 @@ class Tarantula(Spider):
# ************************************************************************ # ************************************************************************
# * Fechter's Game # * Fechter's Game
# * Microbe
# ************************************************************************ # ************************************************************************
class FechtersGame_Talon(TalonStack): class FechtersGame_Talon(TalonStack):
@ -1180,14 +1169,7 @@ class FechtersGame_Talon(TalonStack):
class FechtersGame_RowStack(AC_RowStack): class FechtersGame_RowStack(AC_RowStack):
def canDropCards(self, stacks): canDropCards = BasicRowStack.spiderCanDropCards
if len(self.cards) < 13:
return (None, 0)
cards = self.cards[-13:]
for s in stacks:
if s is not self and s.acceptsCards(self, cards):
return (s, 13)
return (None, 0)
class FechtersGame(RelaxedSpider): class FechtersGame(RelaxedSpider):
@ -1208,6 +1190,17 @@ class FechtersGame(RelaxedSpider):
shallHighlightMatch = Game._shallHighlightMatch_AC shallHighlightMatch = Game._shallHighlightMatch_AC
class Microbe(FechtersGame):
Talon_Class = DealRowTalonStack
RowStack_Class = StackWrapper(FechtersGame_RowStack, base_rank=ANY_RANK)
def createGame(self):
RelaxedSpider.createGame(self, rows=11)
def shuffle(self):
self.shuffleSeparateDecks()
# ************************************************************************ # ************************************************************************
# * Bebop # * Bebop
# ************************************************************************ # ************************************************************************
@ -1663,3 +1656,8 @@ registerGame(GameInfo(870, FairMaids, "Fair Maids",
GI.GT_SPIDER, 1, 0, GI.SL_BALANCED)) GI.GT_SPIDER, 1, 0, GI.SL_BALANCED))
registerGame(GameInfo(917, Astrocyte, "Astrocyte", registerGame(GameInfo(917, Astrocyte, "Astrocyte",
GI.GT_SPIDER, 2, 0, GI.SL_MOSTLY_SKILL)) GI.GT_SPIDER, 2, 0, GI.SL_MOSTLY_SKILL))
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,10 +51,18 @@ class StHelena_Talon(TalonStack):
# move all cards to the Talon and redeal # move all cards to the Talon and redeal
lr = len(self.game.s.rows) lr = len(self.game.s.rows)
num_cards = 0 num_cards = 0
assert len(self.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
for r in self.game.s.rows[::-1]: for r in self.game.s.rows[::-1]:
for i in range(len(r.cards)): for i in range(len(r.cards)):
num_cards = num_cards + 1 num_cards += 1
self.game.moveMove(1, r, self, frames=0) self.game.moveMove(1, r, self, frames=0)
assert len(self.cards) == num_cards assert len(self.cards) == num_cards
if num_cards == 0: # game already finished if num_cards == 0: # game already finished
@ -169,6 +177,32 @@ class BoxKite(StHelena):
shallHighlightMatch = Game._shallHighlightMatch_RKW 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 # * Les Quatre Coins
@ -452,3 +486,5 @@ registerGame(GameInfo(621, RegalFamily, "Regal Family",
registerGame(GameInfo(859, KingsAudience, "King's Audience", registerGame(GameInfo(859, KingsAudience, "King's Audience",
GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_LUCK, GI.GT_1DECK_TYPE, 1, 0, GI.SL_MOSTLY_LUCK,
altnames=("Queen's Audience"))) altnames=("Queen's Audience")))
registerGame(GameInfo(975, Louis, "Louis",
GI.GT_2DECK_TYPE, 2, 2, GI.SL_BALANCED))

View file

@ -472,6 +472,7 @@ class Panopticon(TenAcross):
# ************************************************************************ # ************************************************************************
# * Australian Patience # * Australian Patience
# * Outback Patience
# * Tasmanian Patience # * Tasmanian Patience
# * Canberra # * Canberra
# * Raw Prawn # * Raw Prawn
@ -482,9 +483,9 @@ class AustralianPatience(RussianSolitaire):
RowStack_Class = StackWrapper(Yukon_SS_RowStack, base_rank=KING) RowStack_Class = StackWrapper(Yukon_SS_RowStack, base_rank=KING)
def createGame(self, rows=7, max_rounds=1, num_deal=1): def createGame(self, rows=7, max_rounds=1, num_deal=1, playcards=16):
l, s = Layout(self), self.s l, s = Layout(self), self.s
Layout.klondikeLayout(l, rows=rows, waste=1) Layout.klondikeLayout(l, rows=rows, waste=1, playcards=playcards)
self.setSize(l.size[0], l.size[1]) self.setSize(l.size[0], l.size[1])
s.talon = WasteTalonStack(l.s.talon.x, l.s.talon.y, self, s.talon = WasteTalonStack(l.s.talon.x, l.s.talon.y, self,
max_rounds=max_rounds, num_deal=num_deal) max_rounds=max_rounds, num_deal=num_deal)
@ -500,6 +501,14 @@ class AustralianPatience(RussianSolitaire):
self._startDealNumRowsAndDealRowAndCards(3) 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): class TasmanianPatience(AustralianPatience):
def createGame(self): def createGame(self):
AustralianPatience.createGame(self, max_rounds=-1, num_deal=3) AustralianPatience.createGame(self, max_rounds=-1, num_deal=3)
@ -895,8 +904,7 @@ registerGame(GameInfo(387, Roslin, "Roslin",
GI.GT_YUKON, 1, 0, GI.SL_MOSTLY_SKILL, GI.GT_YUKON, 1, 0, GI.SL_MOSTLY_SKILL,
altnames=("Roslyn",))) altnames=("Roslyn",)))
registerGame(GameInfo(447, AustralianPatience, "Australian Patience", 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", registerGame(GameInfo(450, RawPrawn, "Raw Prawn",
GI.GT_YUKON, 1, 0, GI.SL_BALANCED)) GI.GT_YUKON, 1, 0, GI.SL_BALANCED))
registerGame(GameInfo(456, BimBom, "Bim Bom", registerGame(GameInfo(456, BimBom, "Bim Bom",
@ -906,9 +914,12 @@ registerGame(GameInfo(466, DoubleRussianSolitaire, "Double Russian Solitaire",
registerGame(GameInfo(488, TripleRussianSolitaire, "Triple Russian Solitaire", registerGame(GameInfo(488, TripleRussianSolitaire, "Triple Russian Solitaire",
GI.GT_YUKON, 3, 0, GI.SL_BALANCED)) GI.GT_YUKON, 3, 0, GI.SL_BALANCED))
registerGame(GameInfo(492, Geoffrey, "Geoffrey", registerGame(GameInfo(492, Geoffrey, "Geoffrey",
GI.GT_YUKON, 1, 0, GI.SL_MOSTLY_SKILL)) GI.GT_YUKON, 1, 0, GI.SL_MOSTLY_SKILL,
altnames=('Thornq',)))
registerGame(GameInfo(525, Queensland, "Queensland", registerGame(GameInfo(525, Queensland, "Queensland",
GI.GT_YUKON, 1, 0, GI.SL_BALANCED)) 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", registerGame(GameInfo(530, RussianSpider, "Russian Spider",
GI.GT_SPIDER, 1, 0, GI.SL_BALANCED, GI.GT_SPIDER, 1, 0, GI.SL_BALANCED,
altnames=('Ukrainian Solitaire',))) altnames=('Ukrainian Solitaire',)))
@ -941,4 +952,5 @@ registerGame(GameInfo(942, QuadrupleYukon, "Quadruple Yukon",
registerGame(GameInfo(963, Sevastopol, "Sevastopol", registerGame(GameInfo(963, Sevastopol, "Sevastopol",
GI.GT_SPIDER, 1, 0, GI.SL_BALANCED)) GI.GT_SPIDER, 1, 0, GI.SL_BALANCED))
registerGame(GameInfo(964, RussianCell, "Russian Cell", registerGame(GameInfo(964, RussianCell, "Russian Cell",
GI.GT_YUKON, 1, 0, GI.SL_BALANCED)) GI.GT_YUKON, 1, 0, GI.SL_BALANCED,
altnames=('Finnish Solitaire',)))

View file

@ -175,6 +175,13 @@ def raise_help_html(game):
pass pass
def unraise_help_html():
try:
help_html_viewer.parent.attributes("-topmost", False)
except Exception:
pass
def destroy_help_html(): def destroy_help_html():
try: try:
help_html_viewer.destroy() help_html_viewer.destroy()

View file

@ -73,6 +73,10 @@ def raise_find_card_dialog(game):
pass pass
def unraise_find_card_dialog():
pass
def destroy_find_card_dialog(): def destroy_find_card_dialog():
pass pass
''' '''

View file

@ -112,6 +112,10 @@ def raise_full_picture_dialog(game):
pass pass
def unraise_full_picture_dialog():
pass
def destroy_full_picture_dialog(): def destroy_full_picture_dialog():
pass pass
''' '''

View file

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

View file

@ -50,6 +50,10 @@ def raise_solver_dialog(game):
pass pass
def unraise_solver_dialog():
pass
def destroy_solver_dialog(): def destroy_solver_dialog():
global solver_dialog global solver_dialog
solver_dialog = None solver_dialog = None

View file

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

View file

@ -54,5 +54,9 @@ def raise_find_card_dialog(game):
pass pass
def unraise_find_card_dialog():
pass
def destroy_find_card_dialog(): def destroy_find_card_dialog():
pass pass

View file

@ -50,7 +50,11 @@ def connect_game_full_picture_dialog(game):
pass pass
def raise_find_card_dialog(game): def raise_full_picture_dialog(game):
pass
def unraise_full_picture_dialog():
pass pass

View file

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

View file

@ -34,6 +34,10 @@ def raise_solver_dialog(game):
pass pass
def unraise_solver_dialog():
pass
def destroy_solver_dialog(): def destroy_solver_dialog():
pass pass
# solver_dialog = None # solver_dialog = None

View file

@ -353,7 +353,6 @@ class SelectCardsetDialogWithPreview(MfxDialog):
check = ttk.Checkbutton( check = ttk.Checkbutton(
size_frame, text=_('Auto scaling'), size_frame, text=_('Auto scaling'),
variable=self.auto_scale, variable=self.auto_scale,
takefocus=False,
command=self._updateAutoScale command=self._updateAutoScale
) )
check.grid(row=5, column=0, columnspan=2, sticky='ew', check.grid(row=5, column=0, columnspan=2, sticky='ew',
@ -364,7 +363,6 @@ class SelectCardsetDialogWithPreview(MfxDialog):
self.aspect_check = ttk.Checkbutton( self.aspect_check = ttk.Checkbutton(
size_frame, text=_('Preserve aspect ratio'), size_frame, text=_('Preserve aspect ratio'),
variable=self.preserve_aspect, variable=self.preserve_aspect,
takefocus=False,
# command=self._updateScale # command=self._updateScale
) )
self.aspect_check.grid(row=6, column=0, sticky='ew', self.aspect_check.grid(row=6, column=0, sticky='ew',
@ -664,20 +662,21 @@ class CardsetInfoDialog(MfxDialog):
row += 1 row += 1
styles = nationalities = year = None styles = nationalities = year = None
if cardset.si.styles: if cardset.si.styles:
styles = '\n'.join([CSI.STYLE[i] for i in cardset.si.styles]) styles = '\n'.join(sorted([CSI.STYLE[i]
for i in cardset.si.styles]))
if cardset.si.nationalities: if cardset.si.nationalities:
nationalities = '\n'.join([CSI.NATIONALITY[i] nationalities = '\n'.join(sorted([CSI.NATIONALITY[i]
for i in cardset.si.nationalities]) for i in
cardset.si.nationalities]))
if cardset.year: if cardset.year:
year = str(cardset.year) year = str(cardset.year)
frow = 0 frow = 0
for n, t in ( for n, t in (
# ('Version:', str(cardset.version)),
(_('Type:'), CSI.TYPE[cardset.type]), (_('Type:'), CSI.TYPE[cardset.type]),
(_('Styles:'), styles), (_('Styles:'), styles),
(_('Nationality:'), nationalities), (_('Nationality:'), nationalities),
(_('Year:'), year), (_('Year:'), year),
# (_('Number of cards:'), str(cardset.ncards)), (_('Num. cards:'), str(cardset.ncards)),
(_('Size:'), '%d x %d' % (cardset.CARDW, cardset.CARDH)), (_('Size:'), '%d x %d' % (cardset.CARDW, cardset.CARDH)),
): ):
if t is not None: if t is not None:

View file

@ -95,3 +95,10 @@ def raise_solver_dialog(game):
solver_dialog.top.attributes("-topmost", False) solver_dialog.top.attributes("-topmost", False)
except Exception: except Exception:
pass pass
def unraise_solver_dialog():
try:
solver_dialog.top.attributes("-topmost", False)
except Exception:
pass

View file

@ -109,7 +109,7 @@ class SoundOptionsDialog(MfxDialog):
ttk.Label(frame, text=_('Sample volume:'), anchor='w' ttk.Label(frame, text=_('Sample volume:'), anchor='w'
).grid(row=row, column=0, sticky='ew') ).grid(row=row, column=0, sticky='ew')
w = PysolScale(frame, from_=0, to=128, resolution=1, w = PysolScale(frame, from_=0, to=128, resolution=1,
orient='horizontal', takefocus=0, orient='horizontal',
length="3i", # label=_('Sample volume'), length="3i", # label=_('Sample volume'),
variable=self.sample_volume) variable=self.sample_volume)
w.grid(row=row, column=1, sticky='w', padx=5) 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' ttk.Label(frame, text=_('Music volume:'), anchor='w'
).grid(row=row, column=0, sticky='ew') ).grid(row=row, column=0, sticky='ew')
w = PysolScale(frame, from_=0, to=128, resolution=1, w = PysolScale(frame, from_=0, to=128, resolution=1,
orient='horizontal', takefocus=0, orient='horizontal',
length="3i", # label=_('Music volume'), length="3i", # label=_('Music volume'),
variable=self.music_volume) variable=self.music_volume)
w.grid(row=row, column=1, sticky='w', padx=5) 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') row=row, column=0, sticky='we')
widget = PysolScale(lframe, from_=0.2, to=9.9, value=var.get(), widget = PysolScale(lframe, from_=0.2, to=9.9, value=var.get(),
resolution=0.1, orient='horizontal', resolution=0.1, orient='horizontal',
length="3i", variable=var, takefocus=0) length="3i", variable=var)
widget.grid(row=row, column=1) widget.grid(row=row, column=1)
row += 1 row += 1
# #

View file

@ -377,7 +377,7 @@ class TreeFormatter(PysolStatsFormatter):
return 1 return 1
def writeLog(self, player, prev_games, sort_by='date'): def writeLog(self, player, prev_games, sort_by='date'):
if not player or not prev_games: if not prev_games:
return 0 return 0
num_rows = 0 num_rows = 0
results = self.getLogResults(player, prev_games) results = self.getLogResults(player, prev_games)
@ -520,6 +520,8 @@ class LogDialog(MfxDialog):
kw = self.initKw(kw) kw = self.initKw(kw)
title = _('Log') title = _('Log')
if player is None:
title = _('Demo Log')
MfxDialog.__init__(self, parent, title, kw.resizable, kw.default) MfxDialog.__init__(self, parent, title, kw.resizable, kw.default)
self.top.wm_minsize(400, 200) self.top.wm_minsize(400, 200)

View file

@ -105,8 +105,7 @@ class WizardDialog(MfxDialog):
elif w.widget == 'check': elif w.widget == 'check':
if w.variable is None: if w.variable is None:
w.variable = tkinter.BooleanVar() 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) ch.grid(row=row, column=1, sticky='ew', padx=2, pady=2)
if w.current_value is None: if w.current_value is None:

View file

@ -271,7 +271,6 @@ class SelectCardsetDialogWithPreview(MfxDialog):
check = tkinter.Checkbutton( check = tkinter.Checkbutton(
left_frame, text=_('Auto scaling'), left_frame, text=_('Auto scaling'),
variable=self.auto_scale, variable=self.auto_scale,
takefocus=False,
command=self._updateAutoScale command=self._updateAutoScale
) )
check.grid(row=3, column=0, columnspan=2, sticky='w', check.grid(row=3, column=0, columnspan=2, sticky='w',
@ -282,7 +281,6 @@ class SelectCardsetDialogWithPreview(MfxDialog):
self.aspect_check = tkinter.Checkbutton( self.aspect_check = tkinter.Checkbutton(
left_frame, text=_('Preserve aspect ratio'), left_frame, text=_('Preserve aspect ratio'),
variable=self.preserve_aspect, variable=self.preserve_aspect,
takefocus=False,
# command=self._updateScale # command=self._updateScale
) )
self.aspect_check.grid(row=4, column=0, sticky='w', self.aspect_check.grid(row=4, column=0, sticky='w',
@ -438,20 +436,21 @@ class CardsetInfoDialog(MfxDialog):
padx=0, pady=5, ipadx=5, ipady=5) padx=0, pady=5, ipadx=5, ipady=5)
styles = nationalities = year = None styles = nationalities = year = None
if cardset.si.styles: if cardset.si.styles:
styles = '\n'.join([CSI.STYLE[i] for i in cardset.si.styles]) styles = '\n'.join(sorted([CSI.STYLE[i]
for i in cardset.si.styles]))
if cardset.si.nationalities: if cardset.si.nationalities:
nationalities = '\n'.join([CSI.NATIONALITY[i] nationalities = '\n'.join(sorted([CSI.NATIONALITY[i]
for i in cardset.si.nationalities]) for i in
cardset.si.nationalities]))
if cardset.year: if cardset.year:
year = str(cardset.year) year = str(cardset.year)
row = 0 row = 0
for n, t in ( for n, t in (
# ('Version:', str(cardset.version)),
(_('Type:'), CSI.TYPE[cardset.type]), (_('Type:'), CSI.TYPE[cardset.type]),
(_('Styles:'), styles), (_('Styles:'), styles),
(_('Nationality:'), nationalities), (_('Nationality:'), nationalities),
(_('Year:'), year), (_('Year:'), year),
# (_('Number of cards:'), str(cardset.ncards)), (_('Num. cards:'), str(cardset.ncards)),
(_('Size:'), '%d x %d' % (cardset.CARDW, cardset.CARDH)), (_('Size:'), '%d x %d' % (cardset.CARDW, cardset.CARDH)),
): ):
if t is not None: if t is not None:

View file

@ -109,7 +109,7 @@ class SoundOptionsDialog(MfxDialog):
w = tkinter.Label(frame, text=_('Sample volume:')) w = tkinter.Label(frame, text=_('Sample volume:'))
w.grid(row=row, column=0, sticky='w', padx=5) w.grid(row=row, column=0, sticky='w', padx=5)
w = tkinter.Scale(frame, from_=0, to=128, resolution=1, w = tkinter.Scale(frame, from_=0, to=128, resolution=1,
orient='horizontal', takefocus=0, orient='horizontal',
length="3i", # label=_('Sample volume'), length="3i", # label=_('Sample volume'),
variable=self.sample_volume) variable=self.sample_volume)
w.grid(row=row, column=1, sticky='ew', padx=5) 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 = tkinter.Label(frame, text=_('Music volume:'))
w.grid(row=row, column=0, sticky='w', padx=5) w.grid(row=row, column=0, sticky='w', padx=5)
w = tkinter.Scale(frame, from_=0, to=128, resolution=1, w = tkinter.Scale(frame, from_=0, to=128, resolution=1,
orient='horizontal', takefocus=0, orient='horizontal',
length="3i", # label=_('Music volume'), length="3i", # label=_('Music volume'),
variable=self.music_volume) variable=self.music_volume)
w.grid(row=row, column=1, sticky='ew', padx=5) 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') ).grid(row=row, column=0, sticky='we')
widget = tkinter.Scale(frame, from_=0.2, to=9.9, widget = tkinter.Scale(frame, from_=0.2, to=9.9,
resolution=0.1, orient='horizontal', resolution=0.1, orient='horizontal',
length="3i", variable=var, takefocus=0) length="3i", variable=var)
widget.grid(row=row, column=1) widget.grid(row=row, column=1)
row += 1 row += 1
# #

View file

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

Some files were not shown because too many files have changed in this diff Show more