Beispiel #1
0
 def wm_withdraw(self):
     if self.intro.progress:
         self.intro.progress.destroy()
         destruct(self.intro.progress)
         self.intro.progress = None
     if self.top:
         wm_withdraw(self.top)
         self.top.busyUpdate()
Beispiel #2
0
 def _leave(self, *event):
     after_cancel(self.timer)
     after_cancel(self.cancel_timer)
     self.timer = self.cancel_timer = None
     if self.tooltip:
         self.label.destroy()
         destruct(self.label)
         self.label = None
         self.tooltip.destroy()
         destruct(self.tooltip)
         self.tooltip = None
         MfxTooltip.last_leave_time = time.time()
Beispiel #3
0
 def _leave(self, *event):
     after_cancel(self.timer)
     after_cancel(self.cancel_timer)
     self.timer = self.cancel_timer = None
     if self.tooltip:
         self.label.destroy()
         destruct(self.label)
         self.label = None
         self.tooltip.destroy()
         destruct(self.tooltip)
         self.tooltip = None
         MfxTooltip.last_leave_time = time.time()
Beispiel #4
0
 def freeGame(self):
     # disconnect from game
     self.menubar.connectGame(None)
     self.toolbar.connectGame(None)
     # clean up the canvas
     self.canvas.deleteAllItems()
     self.canvas.update_idletasks()
     # destruct the game
     if self.game:
         self.game.destruct()
         destruct(self.game)
     self.game = None
     self.top.connectApp(None)
Beispiel #5
0
 def _load_held_or_saved_game(self, tmpgame):
     """docstring for _load_held_or_saved_game"""
     if self.opt.game_holded > 0 and not self.nextgame.loadedgame:
         game = None
         try:
             game = tmpgame._loadGame(self.fn.holdgame, self)
         except Exception:
             traceback.print_exc()
             game = None
         if game:
             if game.id == self.opt.game_holded and game.gstats.holded:
                 game.gstats.loaded = game.gstats.loaded - 1
                 game.gstats.holded = 0
                 self.nextgame.loadedgame = game
             else:
                 # not a holded game
                 game.destruct()
                 destruct(game)
Beispiel #6
0
 def deletePreview(self, destroy=0):
     self.preview_key = -1
     # clean up the canvas
     if self.preview:
         unbind_destroy(self.preview.canvas)
         self.preview.canvas.deleteAllItems()
         if destroy:
             self.preview.canvas.delete("all")
     #
     #for l in self.info_labels.values():
     #    l.config(text='')
     # destruct the game
     if self.preview_game:
         self.preview_game.endGame()
         self.preview_game.destruct()
         destruct(self.preview_game)
     self.preview_game = None
     # destruct the app
     if destroy:
         if self.preview_app:
             destruct(self.preview_app)
         self.preview_app = None
Beispiel #7
0
 def deletePreview(self, destroy=0):
     self.preview_key = -1
     # clean up the canvas
     if self.preview:
         unbind_destroy(self.preview.canvas)
         self.preview.canvas.deleteAllItems()
         if destroy:
             self.preview.canvas.delete("all")
     #
     # for l in self.info_labels.values():
     #    l.config(text='')
     # destruct the game
     if self.preview_game:
         self.preview_game.endGame()
         self.preview_game.destruct()
         destruct(self.preview_game)
     self.preview_game = None
     # destruct the app
     if destroy:
         if self.preview_app:
             destruct(self.preview_app)
         self.preview_app = None
Beispiel #8
0
 def __destructClones(self):
     for s in self.__clones:
         s.__class__ = self.AClonedStack  # restore orignal class
         destruct(s)
     self.__clones = []
Beispiel #9
0
 def __destructClones(self):
     for s in self.__clones:
         s.__class__ = self.AClonedStack     # restore orignal class
         destruct(s)
     self.__clones = []
Beispiel #10
0
 def loadCardset(self,
                 cs,
                 id=0,
                 update=7,
                 progress=None,
                 tocache=False,
                 noprogress=False):
     # print 'loadCardset', cs.ident
     r = 0
     if cs is None or cs.error:
         return 0
     if cs is self.cardset:
         if not tocache:
             self.updateCardset(id, update=update)
         return 1
     # cache carsets
     # self.cardsets_cache:
     #   key: Cardset.type
     #   value: (Cardset.ident, Images, SubsampledImages)
     c = self.cardsets_cache.get(cs.type)
     if c and c[0] == cs.ident:
         # print 'load from cache', c
         self.images, self.subsampled_images = c[1], c[2]
         if not tocache:
             self.updateCardset(id, update=update)
             if self.menubar is not None:
                 self.menubar.updateBackgroundImagesMenu()
         return 1
     #
     if progress is None and not noprogress:
         self.wm_save_state()
         self.wm_withdraw()
         title = _("Loading cardset %s...") % cs.name
         color = self.opt.colors['table']
         if self.tabletile_index > 0:
             color = "#008200"
         progress = PysolProgressBar(self,
                                     self.top,
                                     title=title,
                                     color=color,
                                     images=self.progress_images)
     images = Images(self.dataloader, cs)
     try:
         if not images.load(app=self, progress=progress):
             raise Exception("Invalid or damaged cardset")
         simages = SubsampledImages(images)
         if tocache:
             simages.setNegative(self.opt.negative_bottom)
         # The save cardsets option is deprecated, and its existence
         # directly conflicts with the ability to allow previews of
         # other cardset types.
         # if self.opt.save_cardsets:
         c = self.cardsets_cache.get(cs.type)
         if c:
             # c[1].destruct()
             destruct(c[1])
         self.cardsets_cache[cs.type] = (cs.ident, images, simages)
         if not tocache:
             # elif self.images is not None:
             #    # self.images.destruct()
             #    destruct(self.images)
             #
             if self.cardset:
                 if self.cardset.ident != cs.ident:
                     if self.cardset.type == cs.type:
                         # clear saved games geometry
                         self.opt.games_geometry = {}
             # update
             self.images = images
             self.subsampled_images = simages
             self.updateCardset(id, update=update)
         r = 1
     except (Exception, TclError, UnpicklingError) as ex:
         traceback.print_exc()
         cs.error = 1
         # restore settings
         self.nextgame.cardset = self.cardset
         if self.cardset:
             self.cardset_manager.setSelected(self.cardset.index)
         # images.destruct()
         destruct(images)
         MfxExceptionDialog(self.top,
                            ex,
                            title=_("Cardset load error"),
                            text=_("Error while loading cardset"))
     self.intro.progress = progress
     if r and not tocache and self.menubar is not None:
         self.menubar.updateBackgroundImagesMenu()
     return r
Beispiel #11
0
 def runGame(self, id_, random=None):
     self.top.connectApp(self)
     # create game instance
     g = self.getGameClass(id_)
     if g is None:
         id_ = 2  # start Klondike as default game
         random = None
         g = self.getGameClass(id_)
         if g is None:
             # start first available game
             id_ = self.gdb.getGamesIdSortedByName()[0]
             g = self.getGameClass(id_)
     gi = self.getGameInfo(id_)
     assert gi is not None and gi.id == id_
     self.game = self.constructGame(id_)
     self.gdb.setSelected(id_)
     self.game.busy = 1
     # create stacks and layout
     self.game.create(self)
     # connect with game
     self.menubar.connectGame(self.game)
     if self.toolbar:  # ~
         self.toolbar.connectGame(self.game)
     self.game.updateStatus(player=self.opt.player)
     # update "Recent games" menubar entry
     if id_ in self.opt.recent_gameid:
         self.opt.recent_gameid.remove(id_)
     self.opt.recent_gameid.insert(0, id_)
     del self.opt.recent_gameid[self.opt.num_recent_games:]
     self.menubar.updateRecentGamesMenu(self.opt.recent_gameid)
     self.menubar.updateFavoriteGamesMenu()
     # hide/show "Shuffle" button
     self.toolbar.config(
         'shuffle', self.opt.toolbar_vars['shuffle']
         and self.game.canShuffle())
     # delete intro progress bar
     if self.intro.progress:
         self.intro.progress.destroy()
         destruct(self.intro.progress)
         self.intro.progress = None
     # prepare game
     autoplay = 0
     if self.nextgame.loadedgame is not None:
         self.stats.gameid_balance = 0
         self.game.restoreGame(self.nextgame.loadedgame)
         destruct(self.nextgame.loadedgame)
     elif self.nextgame.bookmark is not None:
         self.game.restoreGameFromBookmark(self.nextgame.bookmark)
     else:
         self.stats.gameid_balance = 0
         self.game.newGame(random=random, autoplay=0)
         autoplay = 1
     self.nextgame.loadedgame = None
     self.nextgame.bookmark = None
     # splash screen
     if self.opt.splashscreen and self.splashscreen > 0:
         status = help_about(self, timeout=20000, sound=0)
         if status == 2:  # timeout - start a demo
             if autoplay:
                 self.nextgame.startdemo = 1
     self.splashscreen = 0
     # start demo/autoplay
     if self.nextgame.startdemo:
         self.nextgame.startdemo = 0
         self.game.startDemo()
         self.game.createDemoInfoText()
     elif autoplay:
         self.game.autoPlay()
         self.game.stats.player_moves = 0
     # enter the Tk mainloop
     self.game.busy = 0
     self.top.mainloop()
Beispiel #12
0
    def mainproc(self):
        # copy startup options
        self.startup_opt = self.opt.copy()
        # try to load statistics
        try:
            self.loadStatistics()
        except Exception:
            traceback.print_exc()
            pass
        # startup information
        if self.getGameClass(self.opt.last_gameid):
            self.nextgame.id = self.opt.last_gameid
        # load a holded or saved game
        tmpgame = self.constructGame(self.gdb.getGamesIdSortedByName()[0])
        self._load_held_or_saved_game(tmpgame)
        if not self.nextgame.loadedgame:
            if self.commandline.loadgame:
                try:
                    self.nextgame.loadedgame = tmpgame._loadGame(
                        self.commandline.loadgame, self)
                    self.nextgame.loadedgame.gstats.holded = 0
                except Exception:
                    traceback.print_exc()
                    self.nextgame.loadedgame = None
            elif self.commandline.game is not None:
                gameid = self.gdb.getGameByName(self.commandline.game)
                if gameid is None:
                    print_err(
                        _("can't find game: %(game)s") %
                        {'game': self.commandline.game})
                    sys.exit(-1)
                else:
                    self.nextgame.id = gameid
                    deal = self.commandline.deal
                    self.nextgame.random = \
                        None if deal is None else construct_random(deal)
            elif self.commandline.gameid is not None:
                self.nextgame.id, self.nextgame.random = \
                    self.commandline.gameid, None
        self.opt.game_holded = 0
        tmpgame.destruct()
        destruct(tmpgame)
        tmpgame = None
        #
        # widgets
        #
        # create the menubar
        if self.intro.progress:
            self.intro.progress.update(step=1)
        self.menubar = PysolMenubar(self,
                                    self.top,
                                    progress=self.intro.progress)
        # create the statusbar(s)
        self.statusbar = PysolStatusbar(self.top)
        self.statusbar.show(self.opt.statusbar)
        self.statusbar.config('gamenumber', self.opt.statusbar_game_number)
        self.statusbar.config('stuck', self.opt.statusbar_stuck)
        self.helpbar = HelpStatusbar(self.top)
        self.helpbar.show(self.opt.helpbar)
        # create the canvas
        self.scrolled_canvas = MfxScrolledCanvas(self.top, propagate=True)
        self.canvas = self.scrolled_canvas.canvas
        padx, pady = TkSettings.canvas_padding
        self.scrolled_canvas.grid(row=1,
                                  column=1,
                                  sticky='nsew',
                                  padx=padx,
                                  pady=pady)
        self.top.grid_columnconfigure(1, weight=1)
        self.top.grid_rowconfigure(1, weight=1)
        self.setTile(self.tabletile_index, force=True)
        # create the toolbar
        dirname = self.getToolbarImagesDir()
        self.toolbar = PysolToolbar(self.top,
                                    self.menubar,
                                    dir=dirname,
                                    size=self.opt.toolbar_size,
                                    relief=self.opt.toolbar_relief,
                                    compound=self.opt.toolbar_compound)
        self.toolbar.show(self.opt.toolbar)
        if TOOLKIT == 'tk':
            for w, v in self.opt.toolbar_vars.items():
                self.toolbar.config(w, v)
        #
        if self.intro.progress:
            self.intro.progress.update(step=1)
        #

        if TOOLKIT == 'kivy':
            self.gproc = self.gameproc()
            self.gproc.send(None)
        return self._main_loop()
Beispiel #13
0
 def loadCardset(self, cs, id=0, update=7, progress=None):
     # print 'loadCardset', cs.ident
     r = 0
     if cs is None or cs.error:
         return 0
     if cs is self.cardset:
         self.updateCardset(id, update=update)
         return 1
     # cache carsets
     # self.cardsets_cache:
     #   key: Cardset.type
     #   value: (Cardset.ident, Images, SubsampledImages)
     c = self.cardsets_cache.get(cs.type)
     if c and c[0] == cs.ident:
         # print 'load from cache', c
         self.images, self.subsampled_images = c[1], c[2]
         self.updateCardset(id, update=update)
         if self.menubar is not None:
             self.menubar.updateBackgroundImagesMenu()
         return 1
     #
     if progress is None:
         self.wm_save_state()
         self.wm_withdraw()
         title = _("Loading %s %s...") % (CARDSET, cs.name)
         color = self.opt.colors['table']
         if self.tabletile_index > 0:
             color = "#008200"
         progress = PysolProgressBar(self,
                                     self.top,
                                     title=title,
                                     color=color,
                                     images=self.progress_images)
     images = Images(self.dataloader, cs)
     try:
         if not images.load(app=self, progress=progress):
             raise Exception("Invalid or damaged " + CARDSET)
         simages = SubsampledImages(images)
         if self.opt.save_cardsets:
             c = self.cardsets_cache.get(cs.type)
             if c:
                 # c[1].destruct()
                 destruct(c[1])
             self.cardsets_cache[cs.type] = (cs.ident, images, simages)
         elif self.images is not None:
             # self.images.destruct()
             destruct(self.images)
         #
         if self.cardset:
             if self.cardset.ident != cs.ident:
                 if self.cardset.type == cs.type:
                     # clear saved games geometry
                     self.opt.games_geometry = {}
         # update
         self.images = images
         self.subsampled_images = simages
         self.updateCardset(id, update=update)
         r = 1
     except (Exception, TclError, UnpicklingError) as ex:
         traceback.print_exc()
         cs.error = 1
         # restore settings
         self.nextgame.cardset = self.cardset
         if self.cardset:
             self.cardset_manager.setSelected(self.cardset.index)
         # images.destruct()
         destruct(images)
         MfxExceptionDialog(self.top,
                            ex,
                            title=CARDSET + _(" load error"),
                            text=_("Error while loading ") + CARDSET)
     self.intro.progress = progress
     if r and self.menubar is not None:
         self.menubar.updateBackgroundImagesMenu()
     return r
    def _undumpGame(self, p):
        #
        err_txt = _("Invalid or damaged %s save file") % PACKAGE
        #
        def pload(t=None, p=p):
            obj = p.load()
            if isinstance(t, type):
                assert isinstance(obj, t), err_txt
            return obj
        def validate(v, txt):
            if not v:
                raise UnpicklingError(txt)
        #
        package = pload(str)
        validate(package == PACKAGE, err_txt)
        version = pload(str)
        #validate(isinstance(version, str) and len(version) <= 20, err_txt)
        version_tuple = pload(tuple)
        validate(version_tuple >= (1,0), _('''\
Cannot load games saved with
%s version %s''') % (PACKAGE, version))
        game_version = 1
        bookmark = pload(int)
        validate(0 <= bookmark <= 2, err_txt)
        game_version = pload(int)
        validate(game_version > 0, err_txt)
        #
        id = pload(int)
        validate(id > 0, err_txt)
        if id not in GI.PROTECTED_GAMES:
           game = self.constructGame(id)
           if game:
               if not game.canLoadGame(version_tuple, game_version):
                   destruct(game)
                   game = None
        validate(game is not None, _('''\
Cannot load this game from version %s
as the game rules have changed
in the current implementation.''') % version)
        game.version = version
        game.version_tuple = version_tuple
        #
        initial_seed = pload(long)
        if initial_seed <= 32000:
            game.random = LCRandom31(initial_seed)
        else:
            game.random = PysolRandom(initial_seed)
        state = pload()
        game.random.setstate(state)
        #if not hasattr(game.random, "origin"):
        #    game.random.origin = game.random.ORIGIN_UNKNOWN
        game.loadinfo.stacks = []
        game.loadinfo.ncards = 0
        nstacks = pload(int)
        validate(1 <= nstacks, err_txt)
        for i in range(nstacks):
            stack = []
            ncards = pload(int)
            validate(0 <= ncards <= 1024, err_txt)
            for j in range(ncards):
                card_id = pload(int)
                face_up = pload(int)
                stack.append((card_id, face_up))
            game.loadinfo.stacks.append(stack)
            game.loadinfo.ncards = game.loadinfo.ncards + ncards
        validate(game.loadinfo.ncards == game.gameinfo.ncards, err_txt)
        game.loadinfo.talon_round = pload()
        game.finished = pload()
        if 0 <= bookmark <= 1:
            saveinfo = pload(Struct)
            game.saveinfo.__dict__.update(saveinfo.__dict__)
            gsaveinfo = pload(Struct)
            game.gsaveinfo.__dict__.update(gsaveinfo.__dict__)
        moves = pload(Struct)
        game.moves.__dict__.update(moves.__dict__)
        snapshots = pload(list)
        game.snapshots = snapshots
        if 0 <= bookmark <= 1:
            gstats = pload(Struct)
            game.gstats.__dict__.update(gstats.__dict__)
            stats = pload(Struct)
            game.stats.__dict__.update(stats.__dict__)
        game._loadGameHook(p)
        dummy = pload(str)
        validate(dummy == "EOF", err_txt)
        if bookmark == 2:
            # copy back all variables that are not saved
            game.stats = self.stats
            game.gstats = self.gstats
            game.saveinfo = self.saveinfo
            game.gsaveinfo = self.gsaveinfo
        return game
Beispiel #15
0
    def mainproc(self):
        # copy startup options
        self.startup_opt = self.opt.copy()
        # try to load statistics
        try:
            self.loadStatistics()
        except Exception:
            traceback.print_exc()
            pass
        # startup information
        if self.getGameClass(self.opt.last_gameid):
            self.nextgame.id = self.opt.last_gameid
        # load a holded or saved game
        id = self.gdb.getGamesIdSortedByName()[0]
        tmpgame = self.constructGame(id)
        if self.opt.game_holded > 0 and not self.nextgame.loadedgame:
            game = None
            try:
                game = tmpgame._loadGame(self.fn.holdgame, self)
            except Exception:
                traceback.print_exc()
                game = None
            if game:
                if game.id == self.opt.game_holded and game.gstats.holded:
                    game.gstats.loaded = game.gstats.loaded - 1
                    game.gstats.holded = 0
                    self.nextgame.loadedgame = game
                else:
                    # not a holded game
                    game.destruct()
                    destruct(game)
            game = None
        if not self.nextgame.loadedgame:
            if self.commandline.loadgame:
                try:
                    self.nextgame.loadedgame = tmpgame._loadGame(
                        self.commandline.loadgame, self)
                    self.nextgame.loadedgame.gstats.holded = 0
                except Exception:
                    traceback.print_exc()
                    self.nextgame.loadedgame = None
            elif self.commandline.game is not None:
                gameid = self.gdb.getGameByName(self.commandline.game)
                if gameid is None:
                    print_err(_("can't find game: ") + self.commandline.game)
                    sys.exit(-1)
                else:
                    self.nextgame.id = gameid
                    deal = self.commandline.deal
                    self.nextgame.random = \
                        None if deal is None else constructRandom(deal)
            elif self.commandline.gameid is not None:
                self.nextgame.id, self.nextgame.random = \
                    self.commandline.gameid, None
        self.opt.game_holded = 0
        tmpgame.destruct()
        destruct(tmpgame)
        tmpgame = None
        #
        # widgets
        #
        # create the menubar
        if self.intro.progress:
            self.intro.progress.update(step=1)
        self.menubar = PysolMenubar(self,
                                    self.top,
                                    progress=self.intro.progress)
        # create the statusbar(s)
        self.statusbar = PysolStatusbar(self.top)
        self.statusbar.show(self.opt.statusbar)
        self.statusbar.config('gamenumber', self.opt.statusbar_game_number)
        self.statusbar.config('stuck', self.opt.statusbar_stuck)
        self.helpbar = HelpStatusbar(self.top)
        self.helpbar.show(self.opt.helpbar)
        # create the canvas
        self.scrolled_canvas = MfxScrolledCanvas(self.top, propagate=True)
        self.canvas = self.scrolled_canvas.canvas
        padx, pady = TkSettings.canvas_padding
        self.scrolled_canvas.grid(row=1,
                                  column=1,
                                  sticky='nsew',
                                  padx=padx,
                                  pady=pady)
        self.top.grid_columnconfigure(1, weight=1)
        self.top.grid_rowconfigure(1, weight=1)
        self.setTile(self.tabletile_index, force=True)
        # create the toolbar
        dir = self.getToolbarImagesDir()
        self.toolbar = PysolToolbar(self.top,
                                    self.menubar,
                                    dir=dir,
                                    size=self.opt.toolbar_size,
                                    relief=self.opt.toolbar_relief,
                                    compound=self.opt.toolbar_compound)
        self.toolbar.show(self.opt.toolbar)
        if TOOLKIT == 'tk':
            for w, v in self.opt.toolbar_vars.items():
                self.toolbar.config(w, v)
        #
        if self.intro.progress:
            self.intro.progress.update(step=1)
        #

        if TOOLKIT == 'kivy':
            self.gproc = self.gameproc()
            self.gproc.send(None)

        try:
            # this is the mainloop
            while 1:
                assert self.cardset is not None
                id_, random = self.nextgame.id, self.nextgame.random
                self.nextgame.id, self.nextgame.random = 0, None
                try:
                    if TOOLKIT == 'kivy':
                        self.gproc.send((id_, random))
                        logging.info('App: sent for game to start')
                        yield
                        logging.info('App: game proc stopped')
                    else:
                        self.runGame(id_, random)
                except Exception:
                    # try Klondike if current game fails
                    if id_ == 2:
                        raise  # internal error?
                    if DEBUG:
                        raise
                    traceback.print_exc()
                    self.nextgame.id = 2
                    self.freeGame()
                    continue
                if self.nextgame.holdgame:
                    assert self.nextgame.id <= 0
                    try:
                        self.game.gstats.holded = 1
                        self.game._saveGame(self.fn.holdgame)
                        self.opt.game_holded = self.game.id
                    except Exception:
                        traceback.print_exc()
                        pass
                self.wm_save_state()
                # save game geometry
                geom = (self.canvas.winfo_width(), self.canvas.winfo_height())
                if self.opt.save_games_geometry and not self.opt.wm_maximized:
                    self.opt.games_geometry[self.game.id] = geom
                self.opt.game_geometry = geom
                self.freeGame()
                #
                if self.nextgame.id <= 0:
                    break
                # load new cardset
                if self.nextgame.cardset is not self.cardset:
                    self.loadCardset(self.nextgame.cardset,
                                     id=self.nextgame.id,
                                     update=7 + 256)
                else:
                    self.requestCompatibleCardsetType(self.nextgame.id)

        except Exception:
            traceback.print_exc()
            pass

        finally:
            # hide main window
            self.wm_withdraw()
            #
            destroy_help_html()
            destroy_find_card_dialog()
            destroy_solver_dialog()
            # update options
            self.opt.last_gameid = id_
            # save options
            try:
                self.saveOptions()
            except Exception:
                traceback.print_exc()
                pass
            # save statistics
            try:
                self.saveStatistics()
            except Exception:
                traceback.print_exc()
                pass
            # shut down audio
            try:
                self.audio.destroy()
            except Exception:
                traceback.print_exc()
                pass
            if TOOLKIT == 'kivy':
                self.top.quit()
                while True:
                    logging.info('App: mainloop end position')
                    yield
Beispiel #16
0
    def _undumpGame(self, p):
        #
        err_txt = _("Invalid or damaged %s save file") % PACKAGE

        #
        def pload(t=None, p=p):
            obj = p.load()
            if isinstance(t, type):
                assert isinstance(obj, t), err_txt
            return obj

        def validate(v, txt):
            if not v:
                raise UnpicklingError(txt)

        #
        package = pload(str)
        validate(package == PACKAGE, err_txt)
        version = pload(str)
        #validate(isinstance(version, str) and len(version) <= 20, err_txt)
        version_tuple = pload(tuple)
        validate(
            version_tuple >= (1, 0),
            _('''\
Cannot load games saved with
%s version %s''') % (PACKAGE, version))
        game_version = 1
        bookmark = pload(int)
        validate(0 <= bookmark <= 2, err_txt)
        game_version = pload(int)
        validate(game_version > 0, err_txt)
        #
        id = pload(int)
        validate(id > 0, err_txt)
        if id not in GI.PROTECTED_GAMES:
            game = self.constructGame(id)
            if game:
                if not game.canLoadGame(version_tuple, game_version):
                    destruct(game)
                    game = None
        validate(
            game is not None,
            _('''\
Cannot load this game from version %s
as the game rules have changed
in the current implementation.''') % version)
        game.version = version
        game.version_tuple = version_tuple
        #
        initial_seed = pload(long)
        if initial_seed <= 32000:
            game.random = LCRandom31(initial_seed)
        else:
            game.random = PysolRandom(initial_seed)
        state = pload()
        game.random.setstate(state)
        #if not hasattr(game.random, "origin"):
        #    game.random.origin = game.random.ORIGIN_UNKNOWN
        game.loadinfo.stacks = []
        game.loadinfo.ncards = 0
        nstacks = pload(int)
        validate(1 <= nstacks, err_txt)
        for i in range(nstacks):
            stack = []
            ncards = pload(int)
            validate(0 <= ncards <= 1024, err_txt)
            for j in range(ncards):
                card_id = pload(int)
                face_up = pload(int)
                stack.append((card_id, face_up))
            game.loadinfo.stacks.append(stack)
            game.loadinfo.ncards = game.loadinfo.ncards + ncards
        validate(game.loadinfo.ncards == game.gameinfo.ncards, err_txt)
        game.loadinfo.talon_round = pload()
        game.finished = pload()
        if 0 <= bookmark <= 1:
            saveinfo = pload(Struct)
            game.saveinfo.__dict__.update(saveinfo.__dict__)
            gsaveinfo = pload(Struct)
            game.gsaveinfo.__dict__.update(gsaveinfo.__dict__)
        moves = pload(Struct)
        game.moves.__dict__.update(moves.__dict__)
        snapshots = pload(list)
        game.snapshots = snapshots
        if 0 <= bookmark <= 1:
            gstats = pload(Struct)
            game.gstats.__dict__.update(gstats.__dict__)
            stats = pload(Struct)
            game.stats.__dict__.update(stats.__dict__)
        game._loadGameHook(p)
        dummy = pload(str)
        validate(dummy == "EOF", err_txt)
        if bookmark == 2:
            # copy back all variables that are not saved
            game.stats = self.stats
            game.gstats = self.gstats
            game.saveinfo = self.saveinfo
            game.gsaveinfo = self.gsaveinfo
        return game