#!/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 Yukon_Hint from pysollib.layout import Layout from pysollib.stack import \ AC_RowStack, \ BO_RowStack, \ DealReserveRedealTalonStack, \ DealRowRedealTalonStack, \ GroundsForADivorceTalonStack, \ InitialDealTalonStack, \ OpenStack, \ RK_RowStack, \ ReserveStack, \ SC_RowStack, \ SS_RowStack, \ SpiderTalonStack, \ Spider_AC_Foundation, \ Spider_AC_RowStack, \ Spider_BO_Foundation, \ Spider_BO_RowStack, \ Spider_RK_Foundation, \ Spider_SC_Foundation, \ Spider_SC_RowStack, \ Spider_SS_Foundation, \ Spider_SS_RowStack, \ StackWrapper, \ SuperMoveAC_RowStack, \ SuperMoveBO_RowStack, \ SuperMoveRK_RowStack, \ SuperMoveSC_RowStack, \ SuperMoveSS_RowStack, \ UD_AC_RowStack, \ UD_BO_RowStack, \ UD_RK_RowStack, \ UD_SC_RowStack, \ UD_SS_RowStack, \ WasteStack, \ WasteTalonStack, \ Yukon_AC_RowStack, \ Yukon_BO_RowStack, \ Yukon_RK_RowStack, \ Yukon_SC_RowStack, \ Yukon_SS_RowStack from pysollib.util import ACE, ANY_RANK, ANY_SUIT, \ KING, \ UNLIMITED_MOVES from pysollib.wizardutil import WizardWidgets # ************************************************************************ # * # ************************************************************************ def get_settings(ss): s = {} for w in WizardWidgets: if isinstance(w, str): continue if w.var_name in ss: v = ss[w.var_name] else: v = w.default if w.widget == 'menu': v = dict(w.values_map)[v] s[w.var_name] = v return s class CustomGame(Game): def createGame(self): s = get_settings(self.SETTINGS) # from pprint import pprint; pprint(s) # foundations kw = { 'dir': s['found_dir'], 'base_rank': s['found_base_card'], 'mod': 13, } # max_move if s['found_type'] not in (Spider_SS_Foundation, Spider_AC_Foundation, Spider_RK_Foundation, Spider_SC_Foundation, Spider_BO_Foundation,): kw['max_move'] = s['found_max_move'] # suit if s['found_type'] in (Spider_SS_Foundation, Spider_AC_Foundation, Spider_RK_Foundation, Spider_SC_Foundation, Spider_BO_Foundation,): kw['suit'] = ANY_SUIT # fix dir and base_rank for Spider foundations if s['found_type'] in (Spider_SS_Foundation, Spider_AC_Foundation, Spider_RK_Foundation, Spider_SC_Foundation, Spider_BO_Foundation,): kw['dir'] = -kw['dir'] if s['found_base_card'] == KING: kw['base_rank'] = ACE elif s['found_base_card'] == ACE: kw['base_rank'] = KING foundation = StackWrapper(s['found_type'], **kw) # talon kw = { 'max_rounds': s['redeals'], } if s['redeals'] >= 0: kw['max_rounds'] += 1 if s['talon'] is WasteTalonStack: kw['num_deal'] = s['deal_to_waste'] talon = StackWrapper(s['talon'], **kw) # rows kw = { 'base_rank': s['rows_base_card'], 'dir': s['rows_dir'], 'max_move': s['rows_max_move'], } if s['rows_wrap']: kw['mod'] = 13 if s['rows_type'] in (UD_SS_RowStack, UD_AC_RowStack, UD_RK_RowStack, UD_SC_RowStack, UD_BO_RowStack): kw['max_move'] = 1 # Super Move if s['rows_super_move'] and kw['max_move'] == 1: for s1, s2 in ((SS_RowStack, SuperMoveSS_RowStack), (AC_RowStack, SuperMoveAC_RowStack), (RK_RowStack, SuperMoveRK_RowStack), (SC_RowStack, SuperMoveSC_RowStack), (BO_RowStack, SuperMoveBO_RowStack)): if s['rows_type'] is s1: s['rows_type'] = s2 kw['max_move'] = UNLIMITED_MOVES break row = StackWrapper(s['rows_type'], **kw) # layout layout_kw = { 'rows': s['rows_num'], 'reserves': s['reserves_num'], 'waste': False, 'texts': True, } playcards = 0 if s['talon'] is InitialDealTalonStack: layout_kw['texts'] = False playcards = 12 + 52 * s['decks'] / s['rows_num'] else: playcards = 12 + s['deal_face_down'] + s['deal_face_up'] layout_kw['playcards'] = max(16, playcards) if s['talon'] in (DealRowRedealTalonStack, SpiderTalonStack, GroundsForADivorceTalonStack): layout_kw['playcards'] += 2 * s['decks'] # reserves if s['reserves_num']: kw = { 'max_cards': s['reserves_max_accept'], } if s['reserves_max_accept']: layout_kw['reserve_class'] = StackWrapper(ReserveStack, **kw) else: layout_kw['reserve_class'] = StackWrapper(OpenStack, **kw) if s['talon'] is DealReserveRedealTalonStack or \ s['reserves_max_accept'] > 1 or s['deal_to_reserves'] > 1: layout_kw['reserve_texts'] = True # waste if s['talon'] is WasteTalonStack: layout_kw['waste'] = True layout_kw['waste_class'] = WasteStack Layout(self).createGame( layout_method=s['layout'], talon_class=talon, foundation_class=foundation, row_class=row, **layout_kw ) # shuffle if s['talon_shuffle'] and s['talon'] in (WasteTalonStack, DealRowRedealTalonStack): self.s.talon.dealCards = self.s.talon.shuffleAndDealCards # shallHighlightMatch for c, f in ( ((Spider_AC_RowStack, Spider_SS_RowStack, Spider_SC_RowStack, Spider_BO_RowStack), (self._shallHighlightMatch_RK, self._shallHighlightMatch_RKW)), ((AC_RowStack, UD_AC_RowStack, Yukon_AC_RowStack, SuperMoveAC_RowStack), (self._shallHighlightMatch_AC, self._shallHighlightMatch_ACW)), ((SS_RowStack, UD_SS_RowStack, Yukon_SS_RowStack, SuperMoveSS_RowStack), (self._shallHighlightMatch_SS, self._shallHighlightMatch_SSW)), ((RK_RowStack, UD_RK_RowStack, Yukon_RK_RowStack, SuperMoveRK_RowStack), (self._shallHighlightMatch_RK, self._shallHighlightMatch_RKW)), ((SC_RowStack, UD_SC_RowStack, Yukon_SC_RowStack, SuperMoveSC_RowStack), (self._shallHighlightMatch_SC, self._shallHighlightMatch_SCW)), ((BO_RowStack, UD_BO_RowStack, Yukon_SC_RowStack, SuperMoveBO_RowStack), (self._shallHighlightMatch_BO, self._shallHighlightMatch_BOW)), ): if s['rows_type'] in c: if s['rows_wrap']: self.shallHighlightMatch = f[1] else: self.shallHighlightMatch = f[0] break # getQuickPlayScore if s['rows_type'] in (Spider_AC_RowStack, Spider_SS_RowStack, Spider_BO_RowStack, Spider_SC_RowStack,): self.getQuickPlayScore = self._getSpiderQuickPlayScore # canDropCards if s['found_type'] in (Spider_SS_Foundation, Spider_AC_Foundation, Spider_RK_Foundation, Spider_SC_Foundation, Spider_BO_Foundation,): for stack in self.s.rows: stack.canDropCards = stack.spiderCanDropCards # acceptsCards if s['found_base_card'] == ANY_RANK and s['found_equal']: for stack in self.s.foundations: stack.acceptsCards = stack.varyAcceptsCards stack.getBaseCard = stack.varyGetBaseCard # getBottomImage if s['deal_face_down'] + s['deal_face_up'] == 0: for stack in self.s.rows: stack.getBottomImage = stack.getReserveBottomImage # Hint_Class # TODO if s['rows_type'] in (Yukon_SS_RowStack, Yukon_AC_RowStack, Yukon_RK_RowStack, Yukon_SC_RowStack, Yukon_BO_RowStack,): self.Hint_Class = Yukon_Hint def _shuffleHook(self, cards): s = get_settings(self.SETTINGS) if not s['deal_found']: return cards if s['found_type'] in (Spider_SS_Foundation, Spider_AC_Foundation, Spider_RK_Foundation, Spider_SC_Foundation, Spider_BO_Foundation,): return cards base_card = s['found_base_card'] if base_card == ANY_RANK: base_card = cards[0].rank # move base_card to top of the Talon (i.e. first cards to be dealt) return self._shuffleHookMoveToTop( cards, lambda c, rank=base_card: (c.rank == rank, c.suit)) def startGame(self): s = get_settings(self.SETTINGS) anim_frames = -1 def deal(rows, flip, frames, max_cards): if frames == 0: if len(self.s.talon.cards) <= min_cards or \ max_cards <= min_cards: frames = anim_frames self.startDealSample() if max_cards <= 0: return frames, 0 max_cards -= self.s.talon.dealRowAvail(rows=rows, flip=flip, frames=frames) return frames, max_cards frames = 0 if isinstance(self.s.talon, InitialDealTalonStack): max_cards = 52 * s['decks'] else: max_cards = s['deal_max_cards'] min_cards = max(len(self.s.rows), 8) max_rows = s['deal_face_down'] + s['deal_face_up'] \ + s['deal_to_reserves'] if max_rows <= 1: min_cards = max_cards # deal to foundations if s['deal_found']: frames, max_cards = deal(self.s.foundations, True, frames, max_cards) # deal to reserves n = s['deal_to_reserves'] for i in range(n): frames, max_cards = deal(self.s.reserves[:max_cards], True, frames, max_cards) # deal to rows face_down = s['deal_face_down'] max_rows = s['deal_face_down'] + s['deal_face_up'] if s['deal_type'] == 'triangle': # triangle for i in range(1, len(self.s.rows)): if max_rows <= 1: break flip = (face_down <= 0) mc = max_cards - len(self.s.rows) frames, max_cards = deal(self.s.rows[i:i+mc], flip, frames, max_cards) face_down -= 1 max_rows -= 1 elif s['deal_type'] == 'pyramid': # pyramid for i in range(1, len(self.s.rows)): if max_rows <= 1: break flip = (face_down <= 0) mc = max_cards - len(self.s.rows) frames, max_cards = deal(self.s.rows[i:min(i+mc, -i)], flip, frames, max_cards) face_down -= 1 max_rows -= 1 else: # rectangle for i in range(max_rows-1): flip = (face_down <= 0) mc = max_cards - len(self.s.rows) frames, max_cards = deal(self.s.rows[:mc], flip, frames, max_cards) face_down -= 1 if isinstance(self.s.talon, InitialDealTalonStack): while self.s.talon.cards: frames, max_cards = deal(self.s.rows, True, frames, max_cards) else: if max_rows > 0: deal(self.s.rows, True, frames, len(self.s.rows)) # deal to waste if self.s.waste: if frames == 0: self.startDealSample() self.s.talon.dealCards() def registerCustomGame(gameclass): s = get_settings(gameclass.SETTINGS) gameid = gameclass.SETTINGS['gameid'] registerGame(GameInfo(gameid, gameclass, s['name'], GI.GT_CUSTOM | GI.GT_ORIGINAL, s['decks'], s['redeals'], s['skill_level'])) def no_use(): pass