def autosave(self): """Called automatically in an interval""" self.log.debug("Session: autosaving") success = self._do_save(SavegameManager.create_autosave_filename()) if success: SavegameManager.delete_dispensable_savegames(autosaves=True) self.ingame_gui.message_widget.add('AUTOSAVE')
def prepare_multiplayer(game, trader_enabled=True, pirate_enabled=True, natural_resource_multiplier=1): """Starts a multiplayer game server TODO: actual game data parameter passing """ _modules.gui.show_loading_screen() global preloading preload_game_join(preloading) # remove cursor while loading horizons.globals.fife.cursor.set(fife_module.CURSOR_NONE) horizons.globals.fife.engine.pump() horizons.globals.fife.set_cursor_image('default') # destruct old session (right now, without waiting for gc) if _modules.session is not None and _modules.session.is_alive: _modules.session.end() # start new session from horizons.mpsession import MPSession # get random seed for game uuid = game.uuid random = sum([ int(uuid[i : i + 2], 16) for i in range(0, len(uuid), 2) ]) _modules.session = MPSession(horizons.globals.db, NetworkInterface(), rng_seed=random) # NOTE: this data passing is only temporary, maybe use a player class/struct if game.is_savegame: map_file = SavegameManager.get_multiplayersave_map(game.map_name) else: map_file = SavegameManager.get_map(game.map_name) options = StartGameOptions.create_start_multiplayer(map_file, game.get_player_list(), not game.is_savegame) _modules.session.load(options)
def _start_map( map_name, ai_players=0, is_scenario=False, pirate_enabled=True, trader_enabled=True, force_player_id=None, is_map=False, ): """Start a map specified by user @param map_name: name of map or path to map @return: bool, whether loading succeeded""" if is_scenario: savegames = SavegameManager.get_available_scenarios(locales=True) else: savegames = SavegameManager.get_maps() map_file = _find_matching_map(map_name, savegames) if not map_file: return False options = StartGameOptions.create_start_singleplayer( map_file, is_scenario, ai_players, trader_enabled, pirate_enabled, force_player_id, is_map ) start_singleplayer(options) return True
def _start_map(map_name, ai_players=0, human_ai=False, is_scenario=False, campaign=None, pirate_enabled=True, trader_enabled=True, force_player_id=None): """Start a map specified by user @param map_name: name of map or path to map @return: bool, whether loading succeded""" # check for exact/partial matches in map list first maps = SavegameManager.get_available_scenarios() if is_scenario else SavegameManager.get_maps() map_file = None for i in xrange(0, len(maps[1])): # exact match if maps[1][i] == map_name: map_file = maps[0][i] break # check for partial match if maps[1][i].startswith(map_name): if map_file is not None: # multiple matches, collect all for output map_file += u'\n' + maps[0][i] else: map_file = maps[0][i] if map_file is None: # not a map name, check for path to file or fail if os.path.exists(map_name): map_file = map_name else: #xgettext:python-format print u"Error: Cannot find map '{name}'.".format(name=map_name) return False if len(map_file.splitlines()) > 1: print "Error: Found multiple matches:" for match in map_file.splitlines(): print os.path.basename(match) return False load_game(ai_players, human_ai, map_file, is_scenario, campaign=campaign, trader_enabled=trader_enabled, pirate_enabled=pirate_enabled, force_player_id=force_player_id) return True
def autosave(self): """Called automatically in an interval""" self.log.debug("Session: autosaving") # call saving through horizons.main and not directly through session, so that save errors are handled success = self.save(SavegameManager.create_autosave_filename()) if success: SavegameManager.delete_dispensable_savegames(autosaves=True)
def test_delete_game(gui): """Test deleting a savegame.""" _copy_savegame('boatbuilder') _copy_savegame('ai_settlement') assert os.path.exists(SavegameManager.create_filename('boatbuilder')) assert os.path.exists(SavegameManager.create_filename('ai_settlement')) def confirm_deletion(): def close_dialog(): gui.trigger('load_game_window', 'cancelButton') with gui.handler(close_dialog): gui.trigger('popup_window', 'okButton') def func1(): gui.find('savegamelist').select(u'boatbuilder') with gui.handler(confirm_deletion): gui.trigger('load_game_window', 'deleteButton') with gui.handler(func1): gui.trigger('menu', 'load_button') assert not os.path.exists(SavegameManager.create_filename('boatbuilder')) assert os.path.exists(SavegameManager.create_filename('ai_settlement'))
def goal_reached(session, goal_number): """The player reaches a certain goal in the current scenario.""" # TODO : if we want, we could make this work in "scenario" mode # to allow the player to reach goals in scenarios even if # no campaign was has been loaded. if session.campaign: SavegameManager.mark_goal_reached(session.campaign, goal_number)
def _start_map(map_name, is_scenario = False): """Start a map specified by user @return: bool, whether loading succeded""" maps = SavegameManager.get_scenarios() if is_scenario else SavegameManager.get_maps() map_file = None for i in xrange(0, len(maps[1])): # exact match if maps[1][i] == map_name: map_file = maps[0][i] break # check for partial match if maps[1][i].startswith(map_name): if map_file is not None: # multiple matches, collect all for output map_file += u'\n' + maps[0][i] else: map_file = maps[0][i] if map_file is None: print _("Error: Cannot find map \"%s\".") % map_name return False if len(map_file.splitlines()) > 1: print _("Error: Found multiple matches: ") for match in map_file.splitlines(): print os.path.basename(match) return False load_game(map_file, is_scenario) return True
def goal_reached(session, goal_number): """Called when player reached a goal in a scenario""" # TODO : if we want, we could make this work in "scenario" mode # to allow the player to reach goals in scenarios even if # he didn't load the campaign. if session.campaign: SavegameManager.mark_goal_reached(session.campaign, goal_number)
def show(self): # Campaign and scenarios data scenario_list = self._gui.findChild(name="scenario_list") campaign_info = SavegameManager.get_campaign_info( name=self.session.campaign['campaign_name']) available_scenarios = SavegameManager.get_available_scenarios()[ 1] # [0] is the list of xml files, we don't need it scenarios = [ s for s in campaign_info.get('scenario_names', []) if s in available_scenarios ] self._gui.distributeInitialData({'scenario_list': scenarios}) # select the first one self._gui.distributeData({ 'scenario_list': 0, }) def _update_infos(): self.selected_scenario = scenarios[self._gui.collectData( "scenario_list")] data = SavegameManager.get_scenario_info( name=self.selected_scenario) text = [ _("Difficulty: ") + unicode(data.get('difficulty', '')), _("Author: ") + unicode(data.get('author', '')), _("Description: ") + unicode(data.get('description', '')), ] self._gui.findChild( name="scenario_details").text = u"\n".join(text) self._gui.findChild(name="scenario_list").capture(_update_infos) _update_infos() self._gui.show()
def prepare_multiplayer(game, trader_enabled = True, pirate_enabled = True, natural_resource_multiplier = 1): """Starts a multiplayer game server TODO: acctual game data parameter passing """ global fife, preloading, db preload_game_join(preloading) # remove cursor while loading fife.cursor.set(fife_module.CURSOR_NONE) fife.engine.pump() fife.set_cursor_image('default') # hide whatever is displayed before the game starts _modules.gui.hide() # destruct old session (right now, without waiting for gc) if _modules.session is not None and _modules.session.is_alive: _modules.session.end() # start new session from mpsession import MPSession # get random seed for game uuid = game.get_uuid() random = sum([ int(uuid[i : i + 2], 16) for i in range(0, len(uuid), 2) ]) _modules.session = MPSession(_modules.gui, db, NetworkInterface(), rng_seed=random) # NOTE: this data passing is only temporary, maybe use a player class/struct if game.load: map_file = SavegameManager.get_multiplayersave_map( game.get_map_name() ) else: map_file = SavegameManager.get_map( game.get_map_name() ) _modules.session.load(map_file, game.get_player_list(), trader_enabled, pirate_enabled, natural_resource_multiplier)
def sanity_checker(string): try: SavegameManager.create_multiplayersave_filename(string) except RuntimeError: return False else: return True
def test_save_game_override(gui): """Test saving a game.""" _copy_savegame() old_size = os.path.getsize(SavegameManager.create_filename('boatbuilder')) # FIXME escape doesn't work #gui.press_key(gui.Key.ESCAPE) gui.trigger('mainhud/gameMenuButton') def func1(): gui.find('savegamelist').select(u'boatbuilder') # handle "do you want to override file" popup def func2(): gui.trigger('popup_window/okButton') with gui.handler(func2): gui.trigger('load_game_window/okButton') with gui.handler(func1): gui.trigger('menu/button_images/savegameButton') assert os.path.exists(SavegameManager.create_filename('boatbuilder')) new_size = os.path.getsize(SavegameManager.create_filename('boatbuilder')) assert old_size != new_size
def test_save_game_override(gui): """Test saving a game.""" _copy_savegame() old_size = os.path.getsize(SavegameManager.create_filename('boatbuilder')) # FIXME escape doesn't work #gui.press_key(gui.Key.ESCAPE) gui.trigger('mainhud', 'gameMenuButton') def func1(): gui.find('savegamelist').select(u'boatbuilder') # handle "do you want to override file" popup def func2(): gui.trigger('popup_window', 'okButton') with gui.handler(func2): gui.trigger('load_game_window', 'okButton') with gui.handler(func1): gui.trigger('menu', 'savegameButton') assert os.path.exists(SavegameManager.create_filename('boatbuilder')) new_size = os.path.getsize(SavegameManager.create_filename('boatbuilder')) assert old_size != new_size
def test_delete_game(gui): """Test deleting a savegame.""" _copy_savegame('boatbuilder') _copy_savegame('ai_settlement') assert os.path.exists(SavegameManager.create_filename('boatbuilder')) assert os.path.exists(SavegameManager.create_filename('ai_settlement')) def confirm_deletion(): def close_dialog(): gui.trigger('load_game_window/cancelButton') with gui.handler(close_dialog): gui.trigger('popup_window/okButton') def func1(): gui.find('savegamelist').select(u'boatbuilder') with gui.handler(confirm_deletion): gui.trigger('load_game_window/deleteButton') with gui.handler(func1): gui.trigger('menu/load_button') assert not os.path.exists(SavegameManager.create_filename('boatbuilder')) assert os.path.exists(SavegameManager.create_filename('ai_settlement'))
def prepare_multiplayer(game, trader_enabled=True, pirate_enabled=True, natural_resource_multiplier=1): """Starts a multiplayer game server TODO: actual game data parameter passing """ _modules.gui.show_loading_screen() preloader.wait_for_finish() # remove cursor while loading horizons.globals.fife.cursor.set(fife_module.CURSOR_NONE) horizons.globals.fife.engine.pump() horizons.globals.fife.set_cursor_image('default') # destruct old session (right now, without waiting for gc) if _modules.session is not None and _modules.session.is_alive: _modules.session.end() # start new session from horizons.mpsession import MPSession # get random seed for game uuid = game.uuid random = sum([int(uuid[i : i + 2], 16) for i in range(0, len(uuid), 2)]) _modules.session = MPSession(horizons.globals.db, NetworkInterface(), rng_seed=random) # NOTE: this data passing is only temporary, maybe use a player class/struct if game.is_savegame: map_file = SavegameManager.get_multiplayersave_map(game.map_name) else: map_file = SavegameManager.get_map(game.map_name) options = StartGameOptions.create_start_multiplayer(map_file, game.get_player_list(), not game.is_savegame) _modules.session.load(options)
def show(self): # Campaign and scenarios data campaign_info = SavegameManager.get_campaign_info(name = self.session.campaign['campaign_name']) available_scenarios = SavegameManager.get_available_scenarios()[1] # [0] is the list of xml files, we don't need it scenarios = [s for s in campaign_info.get('scenario_names', []) if s in available_scenarios] self._gui.distributeInitialData({'scenario_list' : scenarios}) # select the first one self._gui.distributeData({ 'scenario_list' : 0, }) def _update_infos(): self.selected_scenario = scenarios[self._gui.collectData("scenario_list")] data = SavegameManager.get_scenario_info(name = self.selected_scenario) #xgettext:python-format text = [_("Difficulty: {difficulty}").format(difficulty=data.get('difficulty', '')), _("Author: {author}").format(author=data.get('author', '')), _("Description: {desc}").format(desc=data.get('description', '')), ] self._gui.findChild(name="scenario_details").text = u"\n".join(text) self._gui.findChild(name="scenario_list").mapEvents({ 'scenario_list/action': _update_infos, 'scenario_list/mouseWheelMovedUp' : _update_infos, 'scenario_list/mouseWheelMovedDown' : _update_infos }) _update_infos() self._gui.show()
def _do_save(self, savegame): """Actual save code. @param savegame: absolute path""" assert os.path.isabs(savegame) self.log.debug("Session: Saving to %s", savegame) try: if os.path.exists(savegame): os.unlink(savegame) self.savecounter += 1 db = DbReader(savegame) except IOError as e: # usually invalid filename headline = _("Failed to create savegame file") descr = _("There has been an error while creating your savegame file.") advice = _("This usually means that the savegame name contains unsupported special characters.") self.gui.show_error_popup(headline, descr, advice, unicode(e)) return self.save() # retry with new savegamename entered by the user # this must not happen with quicksave/autosave except ZeroDivisionError as err: # TODO: # this should say WindowsError, but that somehow now leads to a NameError if err.winerror == 5: self.gui.show_error_popup(_("Access is denied"), \ _("The savegame file is probably read-only.")) return self.save() elif err.winerror == 32: self.gui.show_error_popup(_("File used by another process"), \ _("The savegame file is currently used by another program.")) return self.save() raise try: read_savegame_template(db) db("BEGIN") self.world.save(db) #self.manager.save(db) self.view.save(db) self.ingame_gui.save(db) self.scenario_eventhandler.save(db) LastActivePlayerSettlementManager().save(db) for instance in self.selected_instances: db("INSERT INTO selected(`group`, id) VALUES(NULL, ?)", instance.worldid) for group in xrange(len(self.selection_groups)): for instance in self.selection_groups[group]: db("INSERT INTO selected(`group`, id) VALUES(?, ?)", group, instance.worldid) rng_state = json.dumps( self.random.getstate() ) SavegameManager.write_metadata(db, self.savecounter, rng_state) # make sure everything get's written now db("COMMIT") db.close() return True except: print "Save Exception" traceback.print_exc() db.close() # close db before delete os.unlink(savegame) # remove invalid savegamefile return False
def _start_map(map_name, is_scenario=False): """Start a map specified by user @return: bool, whether loading succeded""" maps = SavegameManager.get_scenarios( ) if is_scenario else SavegameManager.get_maps() map_file = None for i in xrange(0, len(maps[1])): # exact match if maps[1][i] == map_name: map_file = maps[0][i] break # check for partial match if maps[1][i].startswith(map_name): if map_file is not None: # multiple matches, collect all for output map_file += u'\n' + maps[0][i] else: map_file = maps[0][i] if map_file is None: print _("Error: Cannot find map \"%s\".") % map_name return False if len(map_file.splitlines()) > 1: print _("Error: Found multiple matches: ") for match in map_file.splitlines(): print os.path.basename(match) return False load_game(map_file, is_scenario) return True
def autosave(self): """Called automatically in an interval""" self.log.debug("Session: autosaving") # call saving through horizons.main and not directly through session, so that save errors are handled success = self.save(SavegameManager.create_autosave_filename()) if success: SavegameManager.delete_dispensable_savegames(autosaves = True)
def show(self): # Campaign and scenarios data scenario_list = self._gui.findChild(name="scenario_list") campaign_info = SavegameManager.get_campaign_info(name=self.session.campaign["campaign_name"]) available_scenarios = SavegameManager.get_available_scenarios()[ 1 ] # [0] is the list of xml files, we don't need it scenarios = [s for s in campaign_info.get("scenario_names", []) if s in available_scenarios] self._gui.distributeInitialData({"scenario_list": scenarios}) # select the first one self._gui.distributeData({"scenario_list": 0}) def _update_infos(): self.selected_scenario = scenarios[self._gui.collectData("scenario_list")] data = SavegameManager.get_scenario_info(name=self.selected_scenario) text = [ _("Difficulty: ") + unicode(data.get("difficulty", "")), _("Author: ") + unicode(data.get("author", "")), _("Description: ") + unicode(data.get("description", "")), ] self._gui.findChild(name="scenario_details").text = u"\n".join(text) self._gui.findChild(name="scenario_list").capture(_update_infos) _update_infos() self._gui.show()
def _do_save(self, savegame): """Actual save code. @param savegame: absolute path""" assert os.path.isabs(savegame) self.log.debug("Session: Saving to %s", savegame) try: if os.path.exists(savegame): os.unlink(savegame) self.savecounter += 1 db = DbReader(savegame) except IOError as e: # usually invalid filename headline = T("Failed to create savegame file") descr = T( "There has been an error while creating your savegame file.") advice = T( "This usually means that the savegame name contains unsupported special characters." ) self.ingame_gui.open_error_popup(headline, descr, advice, unicode(e)) # retry with new savegamename entered by the user # (this must not happen with quicksave/autosave) return self.save() except OSError as e: if e.errno != errno.EACCES: raise self.ingame_gui.open_error_popup( T("Access is denied"), T("The savegame file could be read-only or locked by another process." )) return self.save() try: read_savegame_template(db) db("BEGIN") self.world.save(db) self.view.save(db) self.ingame_gui.save(db) self.scenario_eventhandler.save(db) # Store RNG state rng_state = json.dumps(self.random.getstate()) SavegameManager.write_metadata(db, self.savecounter, rng_state) # Make sure everything gets written now db("COMMIT") db.close() return True except Exception: self.log.error("Save Exception:") traceback.print_exc() # remove invalid savegamefile (but close db connection before deleting) db.close() os.unlink(savegame) return False
def autosave(self): """Called automatically in an interval""" if self.in_editor_mode(): return self.log.debug("Session: autosaving") success = self._do_save(SavegameManager.create_autosave_filename()) if success: SavegameManager.delete_dispensable_savegames(autosaves=True) self.ingame_gui.message_widget.add(point=None, string_id="AUTOSAVE")
def quicksave(self): """Called when user presses the quicksave hotkey""" self.log.debug("Session: quicksaving") # call saving through horizons.main and not directly through session, so that save errors are handled success = self.save(SavegameManager.create_quicksave_filename()) if success: self.ingame_gui.message_widget.add(None, None, 'QUICKSAVE') SavegameManager.delete_dispensable_savegames(quicksaves=True) else: self.gui.show_popup(_('Error'), _('Failed to quicksave.'))
def quicksave(self): """Called when user presses the quicksave hotkey""" self.log.debug("Session: quicksaving") # call saving through horizons.main and not directly through session, so that save errors are handled success = self.save(SavegameManager.create_quicksave_filename()) if success: self.ingame_gui.message_widget.add(None, None, 'QUICKSAVE') SavegameManager.delete_dispensable_savegames(quicksaves = True) else: self.gui.show_popup(_('Error'), _('Failed to quicksave.'))
def save(self, savegamename=None): """Saves a game @param savegamename: string with the full path of the savegame file or None to let user pick one @return: bool, whether save was successfull """ if savegamename is None: savegamename = self.gui.show_select_savegame(mode='save') if savegamename is None: return False # user aborted dialog savegamename = SavegameManager.create_filename(savegamename) savegame = savegamename assert os.path.isabs(savegame) self.log.debug("Session: Saving to %s", savegame) try: if os.path.exists(savegame): os.unlink(savegame) shutil.copyfile(PATHS.SAVEGAME_TEMPLATE, savegame) self.savecounter += 1 db = DbReader(savegame) except IOError: # usually invalid filename self.gui.show_popup(_("Invalid filename"), _("You entered an invalid filename.")) return self.save( ) # retry with new savegamename entered by the user # this must not happen with quicksave/autosave try: db("BEGIN") self.world.save(db) #self.manager.save(db) self.view.save(db) self.ingame_gui.save(db) self.scenario_eventhandler.save(db) for instance in self.selected_instances: db("INSERT INTO selected(`group`, id) VALUES(NULL, ?)", instance.worldid) for group in xrange(len(self.selection_groups)): for instance in self.selection_groups[group]: db("INSERT INTO selected(`group`, id) VALUES(?, ?)", group, instance.worldid) SavegameManager.write_metadata(db, self.savecounter) # make sure everything get's written now db("COMMIT") db.close() return True except: print "Save Exception" traceback.print_exc() db.close() # close db before delete os.unlink(savegame) # remove invalid savegamefile return False
def autosave(self): """Called automatically in an interval""" if self.in_editor_mode(): return self.log.debug("Session: autosaving") success = self._do_save(SavegameManager.create_autosave_filename()) if success: SavegameManager.delete_dispensable_savegames(autosaves=True) self.ingame_gui.message_widget.add(point=None, string_id='AUTOSAVE')
def prepare(self): if self._mode == 'load': self._map_files, self._map_file_display = SavegameManager.get_saves( ) if not self._map_files: self._windows.open_popup( T("No saved games"), T("There are no saved games to load.")) return False elif self._mode == 'save': self._map_files, self._map_file_display = SavegameManager.get_regular_saves( ) elif self._mode == 'editor-save': self._map_files, self._map_file_display = SavegameManager.get_maps( ) self._gui.distributeInitialData( {'savegamelist': self._map_file_display}) if self._mode == 'load': self._gui.distributeData({'savegamelist': 0}) self._cb = self._create_show_savegame_details(self._gui, self._map_files, 'savegamelist') if self._mode in ('save', 'editor-save'): def selected_changed(): """Fills in the name of the savegame in the textbox when selected in the list""" if self._gui.collectData( 'savegamelist' ) == -1: # set blank if nothing is selected self._gui.findChild(name="savegamefile").text = u"" else: savegamefile = self._map_file_display[ self._gui.collectData('savegamelist')] self._gui.distributeData({'savegamefile': savegamefile}) self._cb = Callback.ChainedCallbacks(self._cb, selected_changed) self._cb() # Refresh data on start self._gui.mapEvents({'savegamelist/action': self._cb}) self._gui.findChild(name="savegamelist").capture( self._cb, event_name="keyPressed") self._gui.findChild(name="savegamelist").capture( self.check_double_click, event_name="mousePressed") self.return_events = { OkButton.DEFAULT_NAME: True, CancelButton.DEFAULT_NAME: False, DeleteButton.DEFAULT_NAME: 'delete' } if self._mode in ('save', 'editor-save'): self.return_events['savegamefile'] = True
def _do_save(self, savegame): """Actual save code. @param savegame: absolute path""" assert os.path.isabs(savegame) self.log.debug("Session: Saving to %s", savegame) try: if os.path.exists(savegame): os.unlink(savegame) self.savecounter += 1 db = DbReader(savegame) except IOError as e: # usually invalid filename headline = _("Failed to create savegame file") descr = _("There has been an error while creating your savegame file.") advice = _("This usually means that the savegame name contains unsupported special characters.") self.ingame_gui.show_error_popup(headline, descr, advice, unicode(e)) # retry with new savegamename entered by the user # (this must not happen with quicksave/autosave) return self.save() except OSError as e: if e.errno != errno.EACCES: raise self.ingame_gui.show_error_popup( _("Access is denied"), _("The savegame file could be read-only or locked by another process.") ) return self.save() try: read_savegame_template(db) db("BEGIN") self.world.save(db) self.view.save(db) self.ingame_gui.save(db) self.scenario_eventhandler.save(db) # Store RNG state rng_state = json.dumps(self.random.getstate()) SavegameManager.write_metadata(db, self.savecounter, rng_state) # Make sure everything gets written now db("COMMIT") db.close() return True except Exception: self.log.error("Save Exception:") traceback.print_exc() # remove invalid savegamefile (but close db connection before deleting) db.close() os.unlink(savegame) return False
def save(self, savegamename=None): """Saves a game @param savegamename: string with the full path of the savegame file or None to let user pick one @return: bool, whether save was successfull """ if savegamename is None: savegamename = self.gui.show_select_savegame(mode='save') if savegamename is None: return False # user aborted dialog savegamename = SavegameManager.create_filename(savegamename) savegame = savegamename assert os.path.isabs(savegame) self.log.debug("Session: Saving to %s", savegame) try: if os.path.exists(savegame): os.unlink(savegame) shutil.copyfile(PATHS.SAVEGAME_TEMPLATE, savegame) self.savecounter += 1 db = DbReader(savegame) except IOError: # usually invalid filename self.gui.show_popup(_("Invalid filename"), _("You entered an invalid filename.")) return self.save() # retry with new savegamename entered by the user # this must not happen with quicksave/autosave try: db("BEGIN") self.world.save(db) #self.manager.save(db) self.view.save(db) self.ingame_gui.save(db) self.scenario_eventhandler.save(db) for instance in self.selected_instances: db("INSERT INTO selected(`group`, id) VALUES(NULL, ?)", instance.worldid) for group in xrange(len(self.selection_groups)): for instance in self.selection_groups[group]: db("INSERT INTO selected(`group`, id) VALUES(?, ?)", group, instance.worldid) SavegameManager.write_metadata(db, self.savecounter) # make sure everything get's written now db("COMMIT") db.close() return True except: print "Save Exception" traceback.print_exc() db.close() # close db before delete os.unlink(savegame) # remove invalid savegamefile return False
def quicksave(self): """Called when user presses the quicksave hotkey""" self.log.debug("Session: quicksaving") # call saving through horizons.main and not directly through session, so that save errors are handled success = self._do_save(SavegameManager.create_quicksave_filename()) if success: SavegameManager.delete_dispensable_savegames(quicksaves=True) self.ingame_gui.message_widget.add('QUICKSAVE') else: headline = _("Failed to quicksave.") descr = _("An error happened during quicksave.") + u"\n" + _("Your game has not been saved.") advice = _("If this error happens again, please contact the development team: " "{website}").format(website="http://unknown-horizons.org/support/") self.ingame_gui.open_error_popup(headline, descr, advice)
def quicksave(self): """Called when user presses the quicksave hotkey""" self.log.debug("Session: quicksaving") # call saving through horizons.main and not directly through session, so that save errors are handled success = self._do_save(SavegameManager.create_quicksave_filename()) if success: SavegameManager.delete_dispensable_savegames(quicksaves=True) self.ingame_gui.message_widget.add('QUICKSAVE') else: headline = T("Failed to quicksave.") descr = T("An error happened during quicksave.") + "\n" + T("Your game has not been saved.") advice = T("If this error happens again, please contact the development team: " "{website}").format(website="http://unknown-horizons.org/support/") self.ingame_gui.open_error_popup(headline, descr, advice)
def _start_map(map_name, ai_players=0, human_ai=False, is_scenario=False, campaign=None, pirate_enabled=True, trader_enabled=True, force_player_id=None): """Start a map specified by user @param map_name: name of map or path to map @return: bool, whether loading succeded""" if is_scenario: savegames = SavegameManager.get_available_scenarios(locales=True) else: savegames = SavegameManager.get_maps() map_file = _find_matching_map(map_name, savegames) if not map_file: return False load_game(ai_players, human_ai, map_file, is_scenario, campaign=campaign, trader_enabled=trader_enabled, pirate_enabled=pirate_enabled, force_player_id=force_player_id) return True
def _delete_savegame(self, map_files): """Deletes the selected savegame if the user confirms self._gui has to contain the widget "savegamelist" @param map_files: list of files that corresponds to the entries of 'savegamelist' @return: True if something was deleted, else False """ selected_item = self._gui.collectData("savegamelist") if selected_item == -1 or selected_item >= len(map_files): self._windows.open_popup( T("No file selected"), T("You need to select a savegame to delete.")) return False selected_file = map_files[selected_item] message = T( "Do you really want to delete the savegame '{name}'?").format( name=SavegameManager.get_savegamename_from_filename( selected_file)) if self._windows.open_popup(T("Confirm deletion"), message, show_cancel_button=True): try: os.unlink(selected_file) return True except: self._windows.open_popup(T("Error!"), T("Failed to delete savefile!")) return False else: # player cancelled deletion return False
def show(self): self._aidata.hide() self._files, maps_display = SavegameManager.get_available_scenarios(hide_test_scenarios=True) # get the map files and their display names. display tutorials on top. prefer_tutorial = lambda x: ('tutorial' not in x, x) maps_display.sort(key=prefer_tutorial) self._files.sort(key=prefer_tutorial) self._gui.distributeInitialData({'maplist' : maps_display}) if maps_display: self._gui.distributeData({'maplist': 0}) # add all locales to lang list, select current locale as default and sort lang_list = self._gui.findChild(name="uni_langlist") lang_list.items = self._get_available_languages() cur_locale = horizons.globals.fife.get_locale() if LANGUAGENAMES[cur_locale] in lang_list.items: lang_list.selected = lang_list.items.index(LANGUAGENAMES[cur_locale]) else: lang_list.selected = 0 self._gui.mapEvents({ 'maplist/action': self._update_infos, 'uni_langlist/action': self._update_infos, }) self._update_infos()
def save(self, savegamename=None): """Saves a game @param savegamename: string with the full path of the savegame file or None to let user pick one @return: bool, whether no error happened (user aborting dialog means success) """ if savegamename is None: savegamename = self.gui.show_select_savegame(mode='save') if savegamename is None: return True # user aborted dialog savegamename = SavegameManager.create_filename(savegamename) savegame = savegamename assert os.path.isabs(savegame) self.log.debug("Session: Saving to %s", savegame) try: if os.path.exists(savegame): os.unlink(savegame) shutil.copyfile(PATHS.SAVEGAME_TEMPLATE, savegame) self.savecounter += 1 db = DbReader(savegame) except IOError, e: # usually invalid filename headline = _("Failed to create savegame file") descr = _("There has been an error while creating your savegame file.") advice = _("This usually means that the savegame name contains unsupported special characters.") self.gui.show_error_popup(headline, descr, advice, unicode(e)) return self.save() # retry with new savegamename entered by the user
def save(self, savegamename=None): """Saves a game @param savegamename: string with the full path of the savegame file or None to let user pick one @return: bool, whether no error happened (user aborting dialog means success) """ if savegamename is None: savegamename = self.gui.show_select_savegame(mode='save') if savegamename is None: return True # user aborted dialog savegamename = SavegameManager.create_filename(savegamename) savegame = savegamename assert os.path.isabs(savegame) self.log.debug("Session: Saving to %s", savegame) try: if os.path.exists(savegame): os.unlink(savegame) shutil.copyfile(PATHS.SAVEGAME_TEMPLATE, savegame) self.savecounter += 1 db = DbReader(savegame) except IOError, e: # usually invalid filename headline = _("Failed to create savegame file") descr = _( "There has been an error while creating your savegame file.") advice = _( "This usually means that the savegame name contains unsupported special characters." ) self.gui.show_error_popup(headline, descr, advice, unicode(e)) return self.save( ) # retry with new savegamename entered by the user
def show(self): self._files, self._maps_display = SavegameManager.get_maps() self._gui.distributeInitialData({ 'maplist': self._maps_display, 'playerlimit': range(2, MULTIPLAYER.MAX_PLAYER_COUNT) }) if self._maps_display: # select first entry self._gui.distributeData({ 'maplist': 0, 'playerlimit': 0 }) self._update_infos() self._gui.findChild(name="maplist").mapEvents({ 'maplist/action': self._update_infos }) gamenametextfield = self._gui.findChild(name='gamename') def gamename_clicked(): if gamenametextfield.text == 'Unnamed Game': gamenametextfield.text = "" gamenametextfield.capture(gamename_clicked, event_name='mouseClicked') self._gui.show()
def _load_map(savegamename): """Load a map specified by user @return: bool, whether loading succeded""" saves = SavegameManager.get_saves() map_file = None for i in xrange(0, len(saves[1])): # exact match if saves[1][i] == savegamename: map_file = saves[0][i] break # check for partial match if saves[1][i].startswith(savegamename): if map_file is not None: # multiple matches, collect all for output map_file += u'\n' + saves[0][i] else: map_file = saves[0][i] if map_file is None: print _("Error: Cannot find savegame \"%s\".") % savegamename return False if len(map_file.splitlines()) > 1: print _("Error: Found multiple matches: ") for match in map_file.splitlines(): print os.path.basename(match) return False load_game(map_file) return True
def quicksave(self): self.ingame_gui.open_popup( T("Not possible"), T("Save/load for multiplayer games is not possible yet")) return #TODO disabled for now, see #2151 for details SaveCommand( SavegameManager.create_multiplayer_quicksave_name()).execute(self)
def __create_game(self, load=None, chosen_map=None): """ Actually create a game, join it, and display the lobby. @param load: game data tuple for creating loaded games @param chosen_map: the name of the map to start a new game on (overrides the gui) """ # create the game if load: mapname, gamename = load path = SavegameManager.get_multiplayersave_map(mapname) maxplayers = SavegameAccessor.get_players_num(path) load = SavegameAccessor.get_hash(path) else: mapindex = None if chosen_map is not None: for i, map in enumerate(self.maps_display): if map == chosen_map: mapindex = i break if mapindex is None: mapindex = self.current.collectData('maplist') mapname = self.maps_display[mapindex] maxplayers = self.current.collectData('playerlimit') + 2 # 1 is the first entry gamename = self.current.collectData('gamename') load = None game = NetworkInterface().creategame(mapname, maxplayers, gamename, load) if game is None: return self.__show_gamelobby()
def show(self): self._files, self._maps_display = SavegameManager.get_maps() self._gui.distributeInitialData({ 'maplist': self._maps_display, 'playerlimit': range(2, MULTIPLAYER.MAX_PLAYER_COUNT) }) if self._maps_display: # select first entry self._gui.distributeData({'maplist': 0, 'playerlimit': 0}) self._update_infos() self._gui.findChild(name="maplist").mapEvents( {'maplist/action': self._update_infos}) gamenametextfield = self._gui.findChild(name='gamename') def gamename_clicked(): if gamenametextfield.text == 'Unnamed Game': gamenametextfield.text = "" gamenametextfield.capture(gamename_clicked, event_name='mouseClicked') self._gui.show()
def _update_free_map_infos(self): number_of_players = SavegameManager.get_recommended_number_of_players( self._get_selected_map()) #xgettext:python-format self.current.findChild(name="recommended_number_of_players_lbl").text = \ _("Recommended number of players: {number}").format(number=number_of_players) self.map_preview.update_map(self._get_selected_map())
def _update_infos(): mapindex = self.current.collectData('maplist') mapfile = self.current.files[mapindex] number_of_players = SavegameManager.get_recommended_number_of_players(mapfile) #xgettext:python-format self.current.findChild(name="recommended_number_of_players_lbl").text = \ _("Recommended number of players: {number}").format(number=number_of_players)
def _start_campaign(campaign_name): """Finds the first scenario in this campaign and loads it. @return: bool, whether loading succeded""" if os.path.exists(campaign_name): # a file was specified. In order to make sure everything works properly, # we need to copy the file over to the UH campaign directory. # This is not very clean, but it's safe. if not campaign_name.endswith(".yaml"): print _("Error: campaign filenames have to end in \".yaml\".") return False # check if the user specified a file in the UH campaign dir campaign_basename = os.path.basename( campaign_name ) path_in_campaign_dir = os.path.join(SavegameManager.campaigns_dir, campaign_basename) if not (os.path.exists(path_in_campaign_dir) and \ os.path.samefile(campaign_name, path_in_campaign_dir)): print _("Due to technical reasons, the campaign file will be copied to the UH campaign directory (%s).") % SavegameManager.campaigns_dir + \ "\n" + _("This means that changes in the file you specified will not apply to the game directly.") + \ _("To see the changes, either always start UH with the current arguments or edit the file %s.") % path_in_campaign_dir shutil.copy(campaign_name, SavegameManager.campaigns_dir) # use campaign file name below campaign_name = os.path.splitext( campaign_basename )[0] campaign = SavegameManager.get_campaign_info(name = campaign_name) if not campaign: print _("Error: Cannot find campaign \"%s\".") % campaign_name return False scenarios = [sc.get('level') for sc in campaign.get('scenarios',[])] if not scenarios: return False return _start_map(scenarios[0], 0, False, is_scenario = True, campaign = {'campaign_name': campaign_name, 'scenario_index': 0, 'scenario_name': scenarios[0]})
def show(self): self._aidata.hide() self._scenarios = SavegameManager.get_available_scenarios() # get the map files and their display names. display tutorials on top. self.maps_display = self._scenarios.keys() if not self.maps_display: return prefer_tutorial = lambda x: ('tutorial' not in x, x) self.maps_display.sort(key=prefer_tutorial) self._gui.distributeInitialData({'maplist' : self.maps_display}) self._gui.distributeData({'maplist': 0}) # add all locales to lang list, select current locale as default and sort scenario_langs = list(set(l for s in self._scenarios.values() for l, filename in s)) lang_list = self._gui.findChild(name="uni_langlist") lang_list.items = sorted([LANGUAGENAMES[l] for l in scenario_langs]) cur_locale = horizons.globals.fife.get_locale() if LANGUAGENAMES[cur_locale] in lang_list.items: lang_list.selected = lang_list.items.index(LANGUAGENAMES[cur_locale]) else: lang_list.selected = 0 self._gui.mapEvents({ 'maplist/action': self._update_infos, 'uni_langlist/action': self._update_infos, }) self._update_infos()
def show(self): self._aidata.hide() self._scenarios = SavegameManager.get_available_scenarios() # get the map files and their display names. display tutorials on top. self.maps_display = self._scenarios.keys() if not self.maps_display: return prefer_tutorial = lambda x: ('tutorial' not in x, x) self.maps_display.sort(key=prefer_tutorial) self._gui.distributeInitialData({'maplist': self.maps_display}) self._gui.distributeData({'maplist': 0}) # add all locales to lang list, select current locale as default and sort scenario_langs = list( set(l for s in self._scenarios.values() for l, filename in s)) lang_list = self._gui.findChild(name="uni_langlist") lang_list.items = sorted([LANGUAGENAMES[l] for l in scenario_langs]) cur_locale = horizons.globals.fife.get_locale() if LANGUAGENAMES[cur_locale] in lang_list.items: lang_list.selected = lang_list.items.index( LANGUAGENAMES[cur_locale]) else: lang_list.selected = 0 self._gui.mapEvents({ 'maplist/action': self._update_infos, 'uni_langlist/action': self._update_infos, }) self._update_infos()
def quicksave(self): """Called when user presses the quicksave hotkey""" self.log.debug("Session: quicksaving") # call saving through horizons.main and not directly through session, so that save errors are handled success = self.save(SavegameManager.create_quicksave_filename()) if success: self.ingame_gui.message_widget.add(None, None, 'QUICKSAVE') SavegameManager.delete_dispensable_savegames(quicksaves=True) else: headline = _(u"Failed to quicksave.") descr = _( u"An error happened during quicksave. Your game has not been saved." ) advice = _(u"If this error happens again, please contact the development team:") + \ u"unknown-horizons.org/support/" self.gui.show_error_popup(headline, descr, advice)
def _load_map(savegame, ai_players, human_ai, force_player_id=None): """Load a map specified by user. @param savegame: eiter the displayname of a savegame or a path to a savegame @return: bool, whether loading succeded""" # first check for partial or exact matches in the normal savegame list saves = SavegameManager.get_saves() map_file = None for i in xrange(0, len(saves[1])): # exact match if saves[1][i] == savegame: map_file = saves[0][i] break # check for partial match if saves[1][i].startswith(savegame): if map_file is not None: # multiple matches, collect all for output map_file += u'\n' + saves[0][i] else: map_file = saves[0][i] if map_file is None: # not a savegame, check for path to file or fail if os.path.exists(savegame): map_file = savegame else: #xgettext:python-format print u"Error: Cannot find savegame '{name}'.".format(name=savegame) return False if len(map_file.splitlines()) > 1: print "Error: Found multiple matches:" for match in map_file.splitlines(): print os.path.basename(match) return False load_game(savegame=map_file, force_player_id=force_player_id) return True
def editor_load_map(self): """Show a dialog for the user to select a map to edit.""" old_current = self._switch_current_widget('editor_select_map') self.current.show() map_files, map_file_display = SavegameManager.get_maps() self.current.distributeInitialData({'maplist': map_file_display}) bind = { OkButton.DEFAULT_NAME: True, CancelButton.DEFAULT_NAME: False, } retval = self.show_dialog(self.current, bind) if not retval: # Dialog cancelled self.current = old_current return False selected_map_index = self.current.collectData('maplist') if selected_map_index == -1: # No map selected yet => select first available one self.current.distributeData({'maplist': 0}) self.current = old_current self.show_loading_screen() horizons.main.edit_map(map_files[selected_map_index]) return True
def _start_dev_map(ai_players, human_ai, force_player_id): # start the development map for m in SavegameManager.get_maps()[0]: if 'development' in m: break load_game(ai_players, human_ai, m, force_player_id=force_player_id) return True
def _update_map_infos(self): map_file = self._get_selected_map() number_of_players = SavegameManager.get_recommended_number_of_players(map_file) lbl = self._gui.findChild(name="recommended_number_of_players_lbl") lbl.text = _("Recommended number of players: {number}").format(number=number_of_players) self._update_map_preview(map_file)
def _update_infos(): mapindex = self.current.collectData('maplist') mapfile = self.current.files[mapindex] number_of_players = SavegameManager.get_recommended_number_of_players( mapfile) #xgettext:python-format self.current.findChild(name="recommended_number_of_players_lbl").text = \ _("Recommended number of players: {number}").format(number=number_of_players)
def _init_gui(self): self._gui = load_xml_translated("stringpreviewwidget.xml") self._gui.mapEvents({ 'load' : self.load }) self.scenarios = SavegameManager.get_scenarios() self.listbox = self._gui.findChild(name="scenario_list") self.listbox.items = self.scenarios[1] self.logbook = LogBook()
def _start_map(map_name, ai_players=0, is_scenario=False, pirate_enabled=True, trader_enabled=True, force_player_id=None, is_map=False): """Start a map specified by user @param map_name: name of map or path to map @return: bool, whether loading succeeded""" if is_scenario: map_file = _find_scenario(map_name, SavegameManager.get_available_scenarios(locales=True)) else: map_file = _find_map(map_name, SavegameManager.get_maps()) if not map_file: return False options = StartGameOptions.create_start_singleplayer(map_file, is_scenario, ai_players, trader_enabled, pirate_enabled, force_player_id, is_map) start_singleplayer(options) return True
def edit_map(map_name): """ Start editing the map file specified by the name. @param map_name: name of map or path to map @return: bool, whether loading succeeded """ return _edit_map(_find_map(map_name, SavegameManager.get_maps()))
def __show_load_game(self): ret = self.show_select_savegame(mode='mp_load') if ret is None: # user aborted return path, gamename, gamepassword = ret # get name from path paths, names = SavegameManager.get_multiplayersaves() mapname = names[paths.index(path)] self.__create_game(load=(mapname, gamename, gamepassword))