#!/usr/bin/env python # -*- mode: python; coding: utf-8; -*- # --------------------------------------------------------------------------- # # Copyright (C) 1998-2003 Markus Franz Xaver Johannes Oberhumer # Copyright (C) 2003 Mt. Hood Playing Card Co. # Copyright (C) 2005-2009 Skomoroh # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # --------------------------------------------------------------------------- from pysollib.game import Game from pysollib.gamedb import GI, GameInfo, registerGame from pysollib.hint import CautiousDefaultHint from pysollib.layout import Layout from pysollib.mfxutil import kwdefault from pysollib.mygettext import _ from pysollib.stack import \ AC_FoundationStack, \ AC_RowStack, \ OpenStack, \ SS_FoundationStack, \ Stack, \ StackWrapper, \ WasteStack, \ WasteTalonStack from pysollib.util import KING, NO_RANK class Terrace_Talon(WasteTalonStack): def canDealCards(self): if self.game.getState() == 0: return False return WasteTalonStack.canDealCards(self) class Terrace_AC_Foundation(AC_FoundationStack): def __init__(self, x, y, game, suit, **cap): kwdefault(cap, mod=13, min_cards=1, max_move=0) AC_FoundationStack.__init__(self, x, y, game, suit, **cap) def acceptsCards(self, from_stack, cards): if self.game.getState() == 0: if len(cards) != 1 or not cards[0].face_up: return False if cards[0].suit != self.cap.base_suit: return False return from_stack in self.game.s.rows return AC_FoundationStack.acceptsCards(self, from_stack, cards) def getBaseCard(self): if self.game.getState() == 0: return _('Base card - %s.') % _('any card') return AC_FoundationStack.getBaseCard(self) class Terrace_SS_Foundation(SS_FoundationStack): def __init__(self, x, y, game, suit, **cap): kwdefault(cap, mod=13, min_cards=1, max_move=0) SS_FoundationStack.__init__(self, x, y, game, suit, **cap) def acceptsCards(self, from_stack, cards): if self.game.getState() == 0: if len(cards) != 1 or not cards[0].face_up: return False if cards[0].suit != self.cap.base_suit: return False return from_stack in self.game.s.rows return SS_FoundationStack.acceptsCards(self, from_stack, cards) def getBaseCard(self): if self.game.getState() == 0: return _('Base card - %s.') % _('any card') return SS_FoundationStack.getBaseCard(self) class Terrace_RowStack(AC_RowStack): def __init__(self, x, y, game, **cap): kwdefault(cap, mod=13, max_move=1) AC_RowStack.__init__(self, x, y, game, **cap) def acceptsCards(self, from_stack, cards): if self.game.getState() == 0: return False if from_stack in self.game.s.reserves: return False return AC_RowStack.acceptsCards(self, from_stack, cards) def moveMove(self, ncards, to_stack, frames=-1, shadow=-1): state = self.game.getState() if state > 0: AC_RowStack.moveMove( self, ncards, to_stack, frames=frames, shadow=shadow) return assert to_stack in self.game.s.foundations assert ncards == 1 assert not self.game.s.waste.cards self.game.moveMove( ncards, self, to_stack, frames=frames, shadow=shadow) for s in self.game.s.foundations: s.cap.base_rank = to_stack.cards[0].rank freerows = [s for s in self.game.s.rows if not s.cards] self.game.s.talon.dealRow(rows=freerows, sound=True) self.game.s.talon.dealCards() # deal first card to WasteStack getBottomImage = Stack._getReserveBottomImage # ************************************************************************ # * Terrace # ************************************************************************ class Terrace(Game): Talon_Class = Terrace_Talon Foundation_Class = Terrace_AC_Foundation RowStack_Class = Terrace_RowStack ReserveStack_Class = OpenStack Hint_Class = CautiousDefaultHint INITIAL_RESERVE_CARDS = 11 # # game layout # def createGame(self, rows=9, max_rounds=1, num_deal=1, playcards=16): # create layout l, s = Layout(self), self.s # set window # (piles up to 16 cards are playable in default window size) decks = self.gameinfo.decks maxrows = max(rows, decks*4+1) w1, w2 = (maxrows - decks*4)*l.XS//2, (maxrows - rows)*l.XS//2 h = max(3*l.YS, playcards*l.YOFFSET) self.setSize(l.XM + maxrows*l.XS + l.XM, l.YM + 3*l.YS + h) # extra settings self.base_rank = None # create stacks x, y = l.XM + w1, l.YM s.talon = self.Talon_Class( x, y, self, max_rounds=max_rounds, num_deal=num_deal) l.createText(s.talon, "sw") x = x + l.XS s.waste = WasteStack(x, y, self) l.createText(s.waste, "se", text_format="%D") x = x + 2*l.XS stack = self.ReserveStack_Class(x, y, self) stack.CARD_XOFFSET = l.XOFFSET l.createText(stack, "sw") s.reserves.append(stack) x, y = l.XM + w1, y + l.YS for i in range(4): for j in range(decks): s.foundations.append(self.Foundation_Class(x, y, self, suit=i)) x = x + l.XS x, y = l.XM + w2, y + l.YS for i in range(rows): s.rows.append(self.RowStack_Class(x, y, self)) x = x + l.XS # define stack-groups l.defaultStackGroups() # # game extras # def getState(self): for s in self.s.foundations: if s.cards: return 1 return 0 # # game overrides # def startGame(self, nrows=4): self.startDealSample() for i in range(self.INITIAL_RESERVE_CARDS): self.s.talon.dealRow(rows=self.s.reserves) self.s.talon.dealRow(rows=self.s.rows[:nrows]) def fillStack(self, stack): if not stack.cards: old_state = self.enterState(self.S_FILL) if stack is self.s.waste and self.s.talon.cards: self.s.talon.dealCards() elif stack in self.s.rows and self.s.waste.cards: self.s.waste.moveMove(1, stack) self.leaveState(old_state) def _restoreGameHook(self, game): for s in self.s.foundations: s.cap.base_rank = game.loadinfo.base_rank def _loadGameHook(self, p): self.loadinfo.addattr(base_rank=p.load()) def _saveGameHook(self, p): base_rank = NO_RANK for s in self.s.foundations: if s.cards: base_rank = s.cards[0].rank break p.dump(base_rank) shallHighlightMatch = Game._shallHighlightMatch_ACW # ************************************************************************ # * Queen of Italy # ************************************************************************ class QueenOfItaly(Terrace): Foundation_Class = StackWrapper(Terrace_AC_Foundation, max_move=1) def fillStack(self, stack): pass # ************************************************************************ # * General's Patience # ************************************************************************ class GeneralsPatience(Terrace): Foundation_Class = Terrace_SS_Foundation INITIAL_RESERVE_CARDS = 13 # ************************************************************************ # * Blondes and Brunettes # * Falling Star # * Wood # ************************************************************************ class BlondesAndBrunettes(Terrace): INITIAL_RESERVE_CARDS = 10 def startGame(self): self.startDealSample() for i in range(self.INITIAL_RESERVE_CARDS): self.s.talon.dealRow(rows=self.s.reserves) self.s.talon.dealRow() # deal base_card to Foundations c = self.s.talon.getCard() for s in self.s.foundations: s.cap.base_rank = c.rank self.s.talon.dealRow(rows=(self.s.foundations[2*c.suit],)) self.s.talon.dealCards() # deal first card to WasteStack def getState(self): return 1 class FallingStar(BlondesAndBrunettes): INITIAL_RESERVE_CARDS = 11 class Wood_RowStack(AC_RowStack): def acceptsCards(self, from_stack, cards): if not AC_RowStack.acceptsCards(self, from_stack, cards): return False if not self.cards: return from_stack is self.game.s.waste return from_stack not in self.game.s.reserves class Wood(BlondesAndBrunettes): RowStack_Class = StackWrapper(Wood_RowStack, mod=13, max_move=1) def fillStack(self, stack): pass # ************************************************************************ # * Signora # ************************************************************************ class Signora(Terrace): def startGame(self): Terrace.startGame(self, nrows=9) # ************************************************************************ # * Madame # ************************************************************************ class Madame(Terrace): INITIAL_RESERVE_CARDS = 15 def createGame(self): Terrace.createGame(self, rows=10, playcards=20) def startGame(self): Terrace.startGame(self, nrows=10) # ************************************************************************ # * Mamy Susan # ************************************************************************ class MamySusan_RowStack(AC_RowStack): def acceptsCards(self, from_stack, cards): if from_stack in self.game.s.reserves: return False return AC_RowStack.acceptsCards(self, from_stack, cards) class MamySusan(Terrace): Talon_Class = WasteTalonStack Foundation_Class = StackWrapper(SS_FoundationStack, max_move=0) RowStack_Class = StackWrapper(MamySusan_RowStack, max_move=1) def createGame(self): Terrace.createGame(self, rows=10) def startGame(self, nrows=4): for i in range(6): self.s.talon.dealRow(rows=self.s.reserves, flip=0, frames=0) self.flipMove(self.s.reserves[0]) self._startDealNumRowsAndDealRowAndCards(3) def fillStack(self, stack): pass def _restoreGameHook(self, game): pass def _loadGameHook(self, p): pass def _saveGameHook(self, p): pass # ************************************************************************ # * Bastille Day # ************************************************************************ class BastilleDay_BastilleStack(Stack): def clickHandler(self, event): return self.dealCards(sound=True) def rightclickHandler(self, event): return self.clickHandler(event) def canDealCards(self): if self.game.s.reserves[-1].cards: return 0 < len(self.cards) < 12 return len(self.cards) > 0 def dealCards(self, sound=False): if not self.canDealCards(): return 0 old_state = self.game.enterState(self.game.S_DEAL) if sound and not self.game.demo: self.game.playSample("dealwaste") self.game.flipAndMoveMove(self, self.game.s.reserves[-1]) self.game.leaveState(old_state) self.game.finishMove() return 1 def getHelp(self): return '' # FIXME class BastilleDay(Game): def createGame(self, rows=9, max_rounds=1, num_deal=1, playcards=16): l, s = Layout(self), self.s self.setSize(l.XM+8*l.XS, l.YM+3*l.YS+12*l.YOFFSET+l.TEXT_HEIGHT) x, y = l.XM, l.YM s.talon = WasteTalonStack(x, y, self, max_rounds=1) l.createText(s.talon, 's') x += l.XS s.waste = WasteStack(x, y, self) l.createText(s.waste, 's') x += 2*l.XS stack = BastilleDay_BastilleStack(x, y, self) s.reserves.append(stack) l.createText(stack, 's') x += l.XS stack = OpenStack(x, y, self) stack.CARD_XOFFSET = l.XOFFSET l.createText(stack, 's') s.reserves.append(stack) x, y = l.XM, l.YM+l.YS+l.TEXT_HEIGHT for i in range(8): s.foundations.append(SS_FoundationStack(x, y, self, suit=i % 4)) x = x + l.XS x, y = l.XM, l.YM+2*l.YS+l.TEXT_HEIGHT for i in range(8): s.rows.append(AC_RowStack(x, y, self)) x = x + l.XS l.defaultStackGroups() def _shuffleHook(self, cards): # move Kings to top cards = self._shuffleHookMoveToTop( cards, lambda c: (c.rank == KING, None)) # move any 4 cards to top cards = cards[4:]+cards[:4] return cards def startGame(self, nrows=4): for i in range(12): # deal to Bastille self.s.talon.dealRow(flip=0, rows=[self.s.reserves[0]], frames=0) for i in range(9): self.s.talon.dealRow(rows=[self.s.reserves[-1]], frames=0) for i in range(3): self.s.talon.dealRow(flip=0, frames=0) self.startDealSample() self.s.talon.dealRow() self.s.talon.dealCards() def dealCards(self, sound=True): # for demo-mode if self.demo: r = self.s.reserves[0] if r.canDealCards(): # self.demo.last_deal = [] # don't check last deal return r.dealCards(sound=sound) return Game.dealCards(self, sound=sound) shallHighlightMatch = Game._shallHighlightMatch_AC # register the game registerGame(GameInfo(135, Terrace, "Terrace", GI.GT_TERRACE, 2, 0, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(136, GeneralsPatience, "General's Patience", GI.GT_TERRACE, 2, 0, GI.SL_MOSTLY_LUCK)) registerGame(GameInfo(137, BlondesAndBrunettes, "Blondes and Brunettes", GI.GT_TERRACE, 2, 0, GI.SL_MOSTLY_LUCK)) registerGame(GameInfo(138, FallingStar, "Falling Star", GI.GT_TERRACE, 2, 0, GI.SL_MOSTLY_LUCK)) registerGame(GameInfo(431, QueenOfItaly, "Queen of Italy", GI.GT_TERRACE, 2, 0, GI.SL_BALANCED)) registerGame(GameInfo(499, Signora, "Signora", GI.GT_TERRACE, 2, 0, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(500, Madame, "Madame", GI.GT_TERRACE, 3, 0, GI.SL_MOSTLY_SKILL)) registerGame(GameInfo(533, MamySusan, "Mamy Susan", GI.GT_TERRACE, 2, 0, GI.SL_BALANCED)) registerGame(GameInfo(582, Wood, "Wood", GI.GT_TERRACE, 2, 0, GI.SL_BALANCED)) registerGame(GameInfo(637, BastilleDay, "Bastille Day", GI.GT_TERRACE, 2, 0, GI.SL_BALANCED))