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

+ 9 new game

+ added command-line option `--debug' (undocumented)
- removed `mixer' button in soundoptionsdialog
* small improvements


git-svn-id: https://pysolfc.svn.sourceforge.net/svnroot/pysolfc/PySolFC/trunk@19 39dd0a4e-7c14-0410-91b3-c4f2d318f732
This commit is contained in:
skomoroh 2006-07-14 21:09:12 +00:00
parent 2aa38bdda5
commit 3c25e97e13
11 changed files with 276 additions and 75 deletions

View file

@ -846,8 +846,10 @@ class Application:
def loadImages3(self):
MfxMessageDialog.img = {}
#dir = os.path.join('images', 'dialog', 'default')
dir = os.path.join('images', 'dialog', 'bluecurve')
if os.name == 'posix':
dir = os.path.join('images', 'dialog', 'bluecurve')
else:
dir = os.path.join('images', 'dialog', 'default')
for f in ('error', 'info', 'question', 'warning'):
fn = self.dataloader.findImage(f, dir)
im = loadImage(fn)

View file

@ -60,11 +60,14 @@ class BeleagueredCastleType_Hint(CautiousDefaultHint):
class StreetsAndAlleys(Game):
Hint_Class = BeleagueredCastleType_Hint
Foundation_Class = SS_FoundationStack
RowStack_Class = RK_RowStack
#
# game layout
#
def createGame(self, playcards=13, reserves=0):
def createGame(self, playcards=13, reserves=0, texts=False):
# create layout
l, s = Layout(self), self.s
@ -75,7 +78,8 @@ class StreetsAndAlleys(Game):
x1 = x0 + w + 2*l.XM
x2 = x1 + l.XS + 2*l.XM
x3 = x2 + w + l.XM
self.setSize(x3, l.YM + (4+int(reserves!=0))*l.YS)
h = l.YM + (4+int(reserves!=0))*l.YS + int(texts)*l.TEXT_HEIGHT
self.setSize(x3, h)
# create stacks
y = l.YM
@ -87,12 +91,17 @@ class StreetsAndAlleys(Game):
y += l.YS
x = x1
for i in range(4):
s.foundations.append(SS_FoundationStack(x, y, self, i, max_move=0))
s.foundations.append(self.Foundation_Class(x, y, self, i, max_move=0))
y = y + l.YS
if texts:
tx, ty, ta, tf = l.getTextAttr(None, "ss")
tx, ty = x+tx, y-l.YS+ty
font = self.app.getFont("canvas_default")
self.texts.info = MfxCanvasText(self.canvas, tx, ty, anchor=ta, font=font)
for x in (x0, x2):
y = l.YM+l.YS*int(reserves!=0)
for i in range(4):
stack = RK_RowStack(x, y, self, max_move=1, max_accept=1)
stack = self.RowStack_Class(x, y, self, max_move=1, max_accept=1)
stack.CARD_XOFFSET, stack.CARD_YOFFSET = l.XOFFSET, 0
s.rows.append(stack)
y = y + l.YS
@ -682,6 +691,29 @@ class CastleMount(Lightweight):
return 0
# /***********************************************************************
# // Selective Castle
# ************************************************************************/
class SelectiveCastle_RowStack(RK_RowStack):
def canDropCards(self, stacks):
if self.game.demo:
return RK_RowStack.canDropCards(self, stacks)
for s in self.game.s.foundations:
if s.cards:
return RK_RowStack.canDropCards(self, stacks)
return (None, 0)
class SelectiveCastle(StreetsAndAlleys, Chessboard):
Foundation_Class = Chessboard_Foundation
RowStack_Class = StackWrapper(SelectiveCastle_RowStack, mod=13)
def createGame(self):
StreetsAndAlleys.createGame(self, texts=True)
def updateText(self):
Chessboard.updateText(self)
# register the game
registerGame(GameInfo(146, StreetsAndAlleys, "Streets and Alleys",
@ -716,3 +748,5 @@ registerGame(GameInfo(507, Lightweight, "Lightweight",
GI.GT_BELEAGUERED_CASTLE | GI.GT_OPEN | GI.GT_ORIGINAL, 2, 0, GI.SL_MOSTLY_SKILL))
registerGame(GameInfo(508, CastleMount, "Castle Mount",
GI.GT_BELEAGUERED_CASTLE | GI.GT_OPEN, 3, 0, GI.SL_MOSTLY_SKILL))
registerGame(GameInfo(524, SelectiveCastle, "Selective Castle",
GI.GT_BELEAGUERED_CASTLE | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL))

View file

@ -408,6 +408,7 @@ class EagleWing(Canfield):
# /***********************************************************************
# // Gate
# // Little Gate
# // Doorway
# ************************************************************************/
class Gate(Game):
@ -477,31 +478,35 @@ class Gate(Game):
class LittleGate(Gate):
RowStack_Class = AC_RowStack
ReserveStack_Class = StackWrapper(OpenStack, max_accept=0)
#
# game layout
#
def createGame(self):
def createGame(self, rows=4):
# create layout
l, s = Layout(self), self.s
# set window
w, h = l.XM+7*l.XS, l.YM+2*l.YS+12*l.YOFFSET
max_rows = max(7, rows+3)
w, h = l.XM+max_rows*l.XS, l.YM+2*l.YS+12*l.YOFFSET
self.setSize(w, h)
# create stacks
y = l.YM+l.YS+l.TEXT_HEIGHT
for x in (l.XM, w-l.XS):
stack = OpenStack(x, y, self, max_accept=0)
stack = self.ReserveStack_Class(x, y, self)
stack.CARD_XOFFSET, stack.CARD_YOFFSET = 0, l.YOFFSET
s.reserves.append(stack)
x, y = l.XM+3*l.XS, l.YM
x, y = l.XM+(max_rows-4)*l.XS, l.YM
for i in range(4):
s.foundations.append(SS_FoundationStack(x, y, self, suit=i))
x += l.XS
x, y = int(l.XM+1.5*l.XS), l.YM+l.YS+l.TEXT_HEIGHT
for i in range(4):
s.rows.append(AC_RowStack(x, y, self))
x, y = l.XM+(max_rows-rows)*l.XS/2, l.YM+l.YS+l.TEXT_HEIGHT
for i in range(rows):
s.rows.append(self.RowStack_Class(x, y, self))
x += l.XS
s.talon = WasteTalonStack(l.XM, l.YM, self, max_rounds=1)
l.createText(s.talon, "ss")
@ -511,6 +516,37 @@ class LittleGate(Gate):
# define stack-groups
l.defaultStackGroups()
return l
class Doorway(LittleGate):
Hint_Class = CautiousDefaultHint
RowStack_Class = StackWrapper(RK_RowStack, max_move=1)
ReserveStack_Class = ReserveStack
def createGame(self):
l = LittleGate.createGame(self, rows=5)
tx, ty, ta, tf = l.getTextAttr(self.s.reserves[0], "s")
font = self.app.getFont("canvas_default")
MfxCanvasText(self.canvas, tx, ty, anchor=ta, font=font, text=_('King'))
tx, ty, ta, tf = l.getTextAttr(self.s.reserves[1], "s")
font = self.app.getFont("canvas_default")
MfxCanvasText(self.canvas, tx, ty, anchor=ta, font=font, text=_('Queen'))
self.s.reserves[0].cap.base_rank = KING
self.s.reserves[1].cap.base_rank = QUEEN
def startGame(self):
self.startDealSample()
self.s.talon.dealRow()
self.s.talon.dealCards()
def fillStack(self, stack):
pass
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return abs(card1.rank-card2.rank) == 1
# /***********************************************************************
# // Minerva
@ -728,4 +764,6 @@ registerGame(GameInfo(494, Mystique, "Mystique",
GI.GT_CANFIELD, 1, 0, GI.SL_BALANCED))
registerGame(GameInfo(521, CanfieldRush, "Canfield Rush",
GI.GT_CANFIELD, 1, 2, GI.SL_BALANCED))
registerGame(GameInfo(527, Doorway, "Doorway",
GI.GT_KLONDIKE, 1, 0, GI.SL_BALANCED))

View file

@ -158,6 +158,7 @@ class FortyThieves(Game):
# // Josephine
# // Marie Rose
# // Big Courtyard
# // San Juan Hill
# // rows build down by suit
# ************************************************************************/
@ -249,6 +250,12 @@ class Carnation(Limited):
FortyThieves.createGame(self, rows=16, playcards=20, XCARDS=120)
class SanJuanHill(FortyThieves):
def createGame(self):
FortyThieves.createGame(self, XOFFSET=0)
# /***********************************************************************
# // Deuces
# ************************************************************************/
@ -457,6 +464,7 @@ class Mumbai(Indian):
# // Napoleon's Exile
# // Double Rail
# // Single Rail (1 deck)
# // Final Battle
# // rows build down by rank
# ************************************************************************/
@ -482,6 +490,12 @@ class SingleRail(DoubleRail):
FortyThieves.createGame(self, rows=4, XCARDS=48)
class FinalBattle(DoubleRail):
def createGame(self):
FortyThieves.createGame(self, rows=6)
# /***********************************************************************
# // Octave
# ************************************************************************/
@ -832,3 +846,9 @@ registerGame(GameInfo(506, Express, "Express",
GI.GT_FORTY_THIEVES | GI.GT_ORIGINAL, 3, 0, GI.SL_MOSTLY_SKILL))
registerGame(GameInfo(514, Carnation, "Carnation",
GI.GT_FORTY_THIEVES | GI.GT_ORIGINAL, 4, 0, GI.SL_MOSTLY_SKILL))
registerGame(GameInfo(528, FinalBattle, "Final Battle",
GI.GT_FORTY_THIEVES, 2, 0, GI.SL_BALANCED))
registerGame(GameInfo(529, SanJuanHill, "San Juan Hill",
GI.GT_FORTY_THIEVES, 2, 0, GI.SL_BALANCED))

View file

@ -416,6 +416,8 @@ class Cone_Talon(DealRowTalonStack):
def canDealCards(self):
if not DealRowTalonStack.canDealCards(self):
return False
if len(self.cards) == 4:
return True
for r in self.game.s.rows:
if not r.cards:
return False
@ -425,7 +427,7 @@ class Cone_Talon(DealRowTalonStack):
rows = self.game.s.rows
if len(self.cards) == 4:
rows = self.game.s.reserves
self.dealRowAvail(rows=rows, sound=sound)
return self.dealRowAvail(rows=rows, sound=sound)
class Cone(Gypsy):

View file

@ -839,6 +839,8 @@ class Q_C_(Klondike):
self.fillAll()
return
# waste
if not self.s.waste.cards and self.s.talon.cards:
self.s.talon.dealCards()
if self.fillOne(self.s.waste):
self.fillAll()
@ -1073,6 +1075,19 @@ class Boost(Klondike):
Klondike.createGame(self, rows=4, max_rounds=3)
# /***********************************************************************
# // Gold Rush
# ************************************************************************/
from canfield import CanfieldRush_Talon
class GoldRush(Klondike):
Talon_Class = CanfieldRush_Talon
def createGame(self):
Klondike.createGame(self, max_rounds=3)
# register the game
registerGame(GameInfo(2, Klondike, "Klondike",
GI.GT_KLONDIKE, 1, -1, GI.SL_BALANCED))
@ -1182,4 +1197,6 @@ registerGame(GameInfo(518, Boost, "Boost",
GI.GT_KLONDIKE, 1, 2, GI.SL_BALANCED))
registerGame(GameInfo(522, ArticGarden, "Artic Garden",
GI.GT_RAGLAN, 1, 0, GI.SL_MOSTLY_SKILL))
registerGame(GameInfo(532, GoldRush, "Gold Rush",
GI.GT_KLONDIKE, 1, 2, GI.SL_BALANCED))

View file

@ -54,17 +54,21 @@ class LarasGame_Hint(CautiousDefaultHint):
class LarasGame_Talon(WasteTalonStack):
# Deal a card to each of the RowStacks. Then deal
# cards to the talon. Return number of cards dealt.
def dealRow(self, rows=None, flip=1, reverse=0, frames=-1):
def dealRow(self, rows=None, flip=1, reverse=0, frames=-1, sound=0):
game = self.game
if rows is None:
rows = game.s.rows
old_state = game.enterState(game.S_DEAL)
cards = self.dealToStacks(rows[:game.MAX_ROW], flip, reverse, frames)
if sound and frames and self.game.app.opt.animations:
self.game.startDealSample()
for i in range(game.DEAL_TO_TALON):
if self.cards:
game.moveMove(1, self, game.s.rows[-1], frames=frames)
cards = cards + 1
game.leaveState(old_state)
if sound:
self.game.stopSamples()
return cards
def dealToStacks(self, stacks, flip=1, reverse=0, frames=-1):
@ -102,6 +106,8 @@ class LarasGame_Talon(WasteTalonStack):
def dealCards(self, sound=0):
game = self.game
if sound and self.game.app.opt.animations:
self.game.startDealSample()
for r in game.s.reserves[:20]:
while r.cards:
game.moveMove(1, r, game.s.rows[game.active_row], frames=3, shadow=0)
@ -123,25 +129,26 @@ class LarasGame_Talon(WasteTalonStack):
for i in range(ncards):
game.moveMove(1, game.s.rows[game.active_row],
game.s.reserves[ncards - i], frames=4, shadow=0)
return len(self.cards) or self.canDealCards()
if self.round < self.max_rounds:
num_cards = 0
rows = list(game.s.rows)[:game.MAX_ROW]
rows.reverse()
for r in rows:
while r.cards:
num_cards = num_cards + 1
if r.cards[-1].face_up:
game.flipMove(r)
game.moveMove(1, r, self, frames=0)
assert len(self.cards) == num_cards
if num_cards == 0:
return 0
game.nextRoundMove(self)
game.dealToRows()
num_cards = len(self.cards) or self.canDealCards()
else: # not self.cards
if self.round < self.max_rounds:
ncards = 0
rows = list(game.s.rows)[:game.MAX_ROW]
rows.reverse()
for r in rows:
while r.cards:
ncards += 1
if r.cards[-1].face_up:
game.flipMove(r)
game.moveMove(1, r, self, frames=0)
assert len(self.cards) == ncards
if ncards != 0:
game.nextRoundMove(self)
game.dealToRows()
num_cards = len(self.cards)
if sound:
game.stopSamples()
return len(self.cards)
return num_cards
def canDealCards(self):
if self.game.demo and self.game.moves.index >= 400:
@ -380,7 +387,7 @@ class LarasGame(Game):
assert moves.index == len(moves.history)
moves.current = []
self.updateText()
self.updateStatus(moves=moves.index)
self.updateStatus(moves=(moves.index, self.stats.total_moves))
self.updateMenus()
return 1
@ -404,7 +411,7 @@ class LarasGame(Game):
self.stats.total_moves = self.stats.total_moves + 1
self.hints.list = None
self.updateText()
self.updateStatus(moves = self.moves.index)
self.updateStatus(moves=(self.moves.index, self.stats.total_moves))
self.updateMenus()
def redo(self):
@ -425,7 +432,7 @@ class LarasGame(Game):
self.stats.total_moves = self.stats.total_moves + 1
self.hints.list = None
self.updateText()
self.updateStatus(moves = self.moves.index)
self.updateStatus(moves=(self.moves.index, self.stats.total_moves))
self.updateMenus()
def _restoreGameHook(self, game):

View file

@ -87,7 +87,6 @@ class Yukon(Game):
RowStack_Class = StackWrapper(Yukon_AC_RowStack, base_rank=KING)
Hint_Class = Yukon_Hint
def createGame(self, **layout):
# create layout
l, s = Layout(self), self.s
@ -95,7 +94,7 @@ class Yukon(Game):
apply(self.Layout_Method, (l,), layout)
self.setSize(l.size[0], l.size[1])
# create stacks
s.talon =self.Talon_Class(l.s.talon.x, l.s.talon.y, self)
s.talon = self.Talon_Class(l.s.talon.x, l.s.talon.y, self)
for r in l.s.foundations:
s.foundations.append(self.Foundation_Class(r.x, r.y, self, suit=r.suit,
max_move=0))
@ -538,6 +537,104 @@ class Geoffrey(Yukon):
return card1.suit == card2.suit and abs(card1.rank-card2.rank) == 1
# /***********************************************************************
# // Queensland
# ************************************************************************/
class Queensland(Yukon):
Layout_Method = Layout.klondikeLayout
RowStack_Class = Yukon_SS_RowStack
def createGame(self):
Yukon.createGame(self, waste=0)
def startGame(self):
for i in range(1, len(self.s.rows)):
self.s.talon.dealRow(rows=self.s.rows[i:], flip=0, frames=0)
for i in range(3):
self.s.talon.dealRow(frames=0)
self.startDealSample()
self.s.talon.dealRow()
self.s.talon.dealRowAvail()
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return card1.suit == card2.suit and abs(card1.rank-card2.rank) == 1
# /***********************************************************************
# // Outback Patience
# ************************************************************************/
class OutbackPatience(Yukon):
def createGame(self, max_rounds=-1, num_deal=1, **layout):
l, s = Layout(self), self.s
l.klondikeLayout(rows=7, waste=1, texts=1, playcards=20)
self.setSize(l.size[0], l.size[1])
s.talon = WasteTalonStack(l.s.talon.x, l.s.talon.y, self, max_rounds=1)
s.waste = WasteStack(l.s.waste.x, l.s.waste.y, self)
for r in l.s.foundations:
s.foundations.append(SS_FoundationStack(r.x, r.y, self, suit=r.suit))
for r in l.s.rows:
s.rows.append(Yukon_SS_RowStack(r.x, r.y, self, base_rank=KING))
l.defaultAll()
def startGame(self):
for i in range(3):
self.s.talon.dealRow(frames=0)
self.startDealSample()
self.s.talon.dealRow()
self.s.talon.dealCards()
def shallHighlightMatch(self, stack1, card1, stack2, card2):
return card1.suit == card2.suit and abs(card1.rank-card2.rank) == 1
# /***********************************************************************
# // Russian Spider
# // Double Russian Spider
# ************************************************************************/
class RussianSpider_RowStack(Yukon_SS_RowStack): #Spider_SS_RowStack
def canDropCards(self, stacks):
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 RussianSpider(RussianSolitaire):
RowStack_Class = StackWrapper(RussianSpider_RowStack, base_rank=KING)
Foundation_Class = Spider_SS_Foundation
def createGame(self, rows=7):
# create layout
l, s = Layout(self), self.s
l.yukonLayout(rows=rows, texts=0, playcards=25)
self.setSize(l.size[0], l.size[1])
# create stacks
s.talon = self.Talon_Class(l.s.talon.x, l.s.talon.y, self)
for r in l.s.foundations:
s.foundations.append(self.Foundation_Class(r.x, r.y, self, suit=ANY_SUIT,
max_move=0))
for r in l.s.rows:
s.rows.append(self.RowStack_Class(r.x, r.y, self))
# default
l.defaultAll()
class DoubleRussianSpider(RussianSpider, DoubleRussianSolitaire):
def createGame(self):
RussianSpider.createGame(self, rows=10)
def startGame(self):
DoubleRussianSolitaire.startGame(self)
# register the game
registerGame(GameInfo(19, Yukon, "Yukon",
@ -586,4 +683,11 @@ registerGame(GameInfo(488, TripleRussianSolitaire, "Triple Russian Solitaire",
GI.GT_YUKON, 3, 0, GI.SL_BALANCED))
registerGame(GameInfo(492, Geoffrey, "Geoffrey",
GI.GT_YUKON, 1, 0, GI.SL_MOSTLY_SKILL))
registerGame(GameInfo(525, Queensland, "Queensland",
GI.GT_YUKON, 1, 0, GI.SL_BALANCED))
registerGame(GameInfo(526, OutbackPatience, "Outback Patience",
GI.GT_YUKON, 1, 0, GI.SL_BALANCED))
registerGame(GameInfo(530, RussianSpider, "Russian Spider",
GI.GT_SPIDER, 1, 0, GI.SL_BALANCED))
registerGame(GameInfo(531, DoubleRussianSpider, "Double Russian Spider",
GI.GT_SPIDER | GI.GT_ORIGINAL, 2, 0, GI.SL_BALANCED))

View file

@ -84,27 +84,29 @@ Please check your %s installation.
def parse_option(argv):
prog_name = argv[0]
try:
optlist, args = getopt.getopt(argv[1:], "h",
optlist, args = getopt.getopt(argv[1:], "hD:",
["fg=", "foreground=",
"bg=", "background=",
"fn=", "font=",
"noplugins",
"nosound",
"debug=",
"help"])
except getopt.GetoptError, err:
print _("%s: %s\ntry %s --help for more information") \
% (prog_name, err, prog_name)
return None
opts = {"help": 0,
opts = {"help": False,
"fg": None,
"bg": None,
"fn": None,
"noplugins": 0,
"nosound": 0,
"noplugins": False,
"nosound": False,
"debug": 0,
}
for i in optlist:
if i[0] in ("-h", "--help"):
opts["help"] = 1
opts["help"] = True
elif i[0] in ("--fg", "--foreground"):
opts["fg"] = i[1]
elif i[0] in ("--bg", "--background"):
@ -112,9 +114,11 @@ def parse_option(argv):
elif i[0] in ("--fn", "--font"):
opts["fn"] = i[1]
elif i[0] == "--noplugins":
opts["noplugins"] = 1
opts["noplugins"] = True
elif i[0] == "--nosound":
opts["nosound"] = 1
opts["nosound"] = True
elif i[0] in ("-D", "--debug"):
opts["debug"] = i[1]
if opts["help"]:
print _("""Usage: %s [OPTIONS] [FILE]
@ -173,6 +177,7 @@ def pysol_init(app, args):
wm_command = prog + " " + os.path.abspath(argv0)
if filename:
app.commandline.loadgame = filename
app.debug = int(opts['debug'])
# init games database
import games

View file

@ -43,17 +43,6 @@ if os.name == "nt":
if os.name == "mac":
pass
# sound mixers
MIXERS = ()
if os.name == "nt":
MIXERS = (("sndvol32.exe", None),)
elif os.name == "posix":
MIXERS = (
#("alsamixer", None),
("kmix", None),
("gmix", None),
)
TOP_SIZE = 10
TOP_TITLE = n_("Top 10")

View file

@ -44,7 +44,6 @@ import traceback
from pysollib.mfxutil import destruct, kwdefault, KwStruct, Struct, spawnvp
from pysollib.settings import PACKAGE
from pysollib.pysolaudio import pysolsoundserver
from pysollib.settings import MIXERS
# Toolkit imports
from tkconst import EVENT_HANDLED, EVENT_PROPAGATE
@ -55,7 +54,6 @@ from tkwidget import MfxDialog, MfxMessageDialog
# ************************************************************************/
class SoundOptionsDialog(MfxDialog):
MIXER = ()
def __init__(self, parent, title, app, **kw):
self.app = app
@ -168,17 +166,13 @@ class SoundOptionsDialog(MfxDialog):
self.mainloop(focus, kw.timeout)
def initKw(self, kw):
strings=[_("&OK"), _("&Apply"), _("&Mixer..."), _("&Cancel"),]
if self.MIXER is None:
strings[2] = (_("&Mixer..."), -1)
## if os.name != "nt" and not self.app.debug:
## strings[2] = None
strings=[_("&OK"), _("&Apply"), _("&Cancel"),]
kw = KwStruct(kw,
strings=strings,
default=0,
resizable=1,
padx=10, pady=10,
buttonpadx=1, buttonpady=5,
buttonpadx=10, buttonpady=5,
)
return MfxDialog.initKw(self, kw)
@ -191,17 +185,6 @@ class SoundOptionsDialog(MfxDialog):
for n, t, v in self.samples:
self.app.opt.sound_samples[n] = v.get()
elif button == 2:
for name, args in MIXERS:
try:
f = spawnvp(name, args)
if f:
self.MIXER = (f, args)
return
except:
if traceback: traceback.print_exc()
pass
self.MIXER = None
elif button == 3:
self.app.opt = self.saved_opt
if self.app.audio:
self.app.audio.updateSettings()