From 9773eee2d6e35d3376a8bb629ff3ef5ca8af7fbf Mon Sep 17 00:00:00 2001 From: Joe R <joeraz5@verizon.net> Date: Mon, 3 Mar 2025 21:28:35 -0500 Subject: [PATCH] Add Wizard's Storeroom game --- html-src/rules/bigstoreroom.html | 13 ++++ html-src/rules/wizardsstoreroom.html | 23 +++++++ pysollib/gamedb.py | 3 +- pysollib/games/special/hexadeck.py | 95 +++++++++++++++++++++++++++- 4 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 html-src/rules/bigstoreroom.html create mode 100644 html-src/rules/wizardsstoreroom.html diff --git a/html-src/rules/bigstoreroom.html b/html-src/rules/bigstoreroom.html new file mode 100644 index 00000000..b30a091f --- /dev/null +++ b/html-src/rules/bigstoreroom.html @@ -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. + diff --git a/html-src/rules/wizardsstoreroom.html b/html-src/rules/wizardsstoreroom.html new file mode 100644 index 00000000..3c6f32a7 --- /dev/null +++ b/html-src/rules/wizardsstoreroom.html @@ -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. diff --git a/pysollib/gamedb.py b/pysollib/gamedb.py index 0af79e36..893dbbb8 100644 --- a/pysollib/gamedb.py +++ b/pysollib/gamedb.py @@ -595,7 +595,8 @@ class GI: tuple(range(22353, 22361))), ('fc-3.1', tuple(range(961, 971))), ('dev', tuple(range(971, 978)) + tuple(range(5419, 5421)) + - tuple(range(18005, 18007)) + (44, 526,)), + tuple(range(16683, 16685)) + tuple(range(18005, 18007)) + + (44, 526,)), ) # deprecated - the correct way is to or a GI.GT_XXX flag diff --git a/pysollib/games/special/hexadeck.py b/pysollib/games/special/hexadeck.py index 8e573dca..cac77f0c 100644 --- a/pysollib/games/special/hexadeck.py +++ b/pysollib/games/special/hexadeck.py @@ -62,7 +62,8 @@ class HexATrump_Foundation(HexADeck_FoundationStack): def acceptsCards(self, from_stack, cards): if not self.basicAcceptsCards(from_stack, cards): 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: return 0 return 1 @@ -93,11 +94,12 @@ class Merlins_Foundation(AbstractFoundationStack): 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, dir=-1) OpenStack.__init__(self, x, y, game, **cap) - self.CARD_YOFFSET = yoffset + if yoffset is not None: + self.CARD_YOFFSET = yoffset def isRankSequence(self, cards, dir=None): if not dir: @@ -1600,6 +1602,89 @@ class MagicMontana(Montana): 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) + # ************************************************************************ # * # ************************************************************************ @@ -1646,4 +1731,8 @@ 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(16682, MagicMontana, 'Magic Montana', GI.GT_HEXADECK | GI.GT_OPEN, 1, 2, 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) del r