def save(self, db): """Saves the current game to the specified db. @param db: DbReader object of the db the game is saved to.""" super(World, self).save(db) if isinstance(self.map_name, list): db("INSERT INTO metadata VALUES(?, ?)", 'random_island_sequence', ' '.join(self.map_name)) else: db("INSERT INTO metadata VALUES(?, ?)", 'map_name', self.map_name) for island in self.islands: island.save(db) for player in self.players: player.save(db) if self.trader is not None: self.trader.save(db) if self.pirate is not None: self.pirate.save(db) for unit in self.ships + self.ground_units: unit.save(db) for bullet in self.bullets: bullet.save(db) self.diplomacy.save(db) Weapon.save_attacks(db) self.disaster_manager.save(db)
def save(self, db): """Saves the current game to the specified db. @param db: DbReader object of the db the game is saved to.""" super(World, self).save(db) if isinstance(self.map_name, list): db("INSERT INTO metadata VALUES(?, ?)", 'random_island_sequence', ' '.join(self.map_name)) else: # the map name has to be simplified because the absolute paths won't be transferable between machines simplified_name = self.map_name if self.map_name.startswith(PATHS.USER_MAPS_DIR): simplified_name = 'USER_MAPS_DIR:' + simplified_name[len(PATHS.USER_MAPS_DIR):] db("INSERT INTO metadata VALUES(?, ?)", 'map_name', simplified_name) for island in self.islands: island.save(db) for player in self.players: player.save(db) if self.trader is not None: self.trader.save(db) if self.pirate is not None: self.pirate.save(db) for unit in self.ships + self.ground_units: unit.save(db) for bullet in self.bullets: bullet.save(db) self.diplomacy.save(db) Weapon.save_attacks(db) self.disaster_manager.save(db)
def save(self, db): """Saves the current game to the specified db. @param db: DbReader object of the db the game is saved to.""" super().save(db) if isinstance(self.map_name, list): db("INSERT INTO metadata VALUES(?, ?)", 'random_island_sequence', ' '.join(self.map_name)) else: # the map name has to be simplified because the absolute paths won't be transferable between machines simplified_name = self.map_name if self.map_name.startswith(PATHS.USER_MAPS_DIR): simplified_name = 'USER_MAPS_DIR:' + simplified_name[ len(PATHS.USER_MAPS_DIR):] db("INSERT INTO metadata VALUES(?, ?)", 'map_name', simplified_name) for island in self.islands: island.save(db) for player in self.players: player.save(db) if self.trader is not None: self.trader.save(db) if self.pirate is not None: self.pirate.save(db) for unit in self.ships + self.ground_units: unit.save(db) self.diplomacy.save(db) Weapon.save_attacks(db) self.disaster_manager.save(db)
def _load_combat(self, savegame_db): # load bullets if self.session.is_game_loaded(): for (worldid, sx, sy, dx, dy, speed, img) in savegame_db("SELECT worldid, startx, starty, destx, desty, speed, image FROM bullet"): Bullet(img, Point(sx, sy), Point(dx, dy), speed, self.session, False, worldid) # load ongoing attacks if self.session.is_game_loaded(): Weapon.load_attacks(self.session, savegame_db)
def _load_combat(self, savegame_db): # load bullets if self.session.is_game_loaded(): for (worldid, sx, sy, dx, dy, speed, img) in savegame_db( "SELECT worldid, startx, starty, destx, desty, speed, image FROM bullet" ): Bullet(img, Point(sx, sy), Point(dx, dy), speed, self.session, False, worldid) # load ongoing attacks if self.session.is_game_loaded(): Weapon.load_attacks(self.session, savegame_db)
def load(self, db, worldid): super(WeaponHolder, self).load(db, worldid) self.__init() weapons = db( "SELECT weapon_id, number, remaining_ticks FROM weapon_storage WHERE owner_id = ?", worldid) for weapon_id, number, ticks in weapons: # create weapon and add to storage manually if self.session.db.get_weapon_stackable(weapon_id): weapon = StackableWeapon(self.session, weapon_id) weapon.set_number_of_weapons(number) else: weapon = Weapon(self.session, weapon_id) self._weapon_storage.append(weapon) # if weapon not ready add scheduled call and remove from fireable if ticks: weapon.attack_ready = False Scheduler().add_new_object(weapon.make_attack_ready, weapon, ticks) else: self._fireable.append(weapon) weapon.add_weapon_fired_listener( Callback(self._remove_from_fireable, weapon)) weapon.add_attack_ready_listener( Callback(self._add_to_fireable, weapon)) weapon.add_weapon_fired_listener( self._increase_fired_weapons_number) self.on_storage_modified() # load target after all objects have been loaded Scheduler().add_new_object(Callback(self.load_target, db), self, run_in=0) self.log.debug("%s weapon storage after load: %s", self, self._weapon_storage)
def save(self, db): """Saves the current game to the specified db. @param db: DbReader object of the db the game is saved to.""" super(World, self).save(db) for name, value in self.properties.iteritems(): db("INSERT INTO map_properties (name, value) VALUES (?, ?)", name, json.dumps(value)) for island in self.islands: island.save(db) for player in self.players: player.save(db) if self.trader is not None: self.trader.save(db) if self.pirate is not None: self.pirate.save(db) for unit in self.ships + self.ground_units: unit.save(db) for bullet in self.bullets: bullet.save(db) self.diplomacy.save(db) Weapon.save_attacks(db) self.disaster_manager.save(db)
def add_weapon_to_storage(self, weapon_id): """ adds weapon to storage @param weapon_id : id of the weapon to be added """ self.log.debug("%s add weapon %s", self, weapon_id) #if weapon is stackable, try to stack weapon = None if self.equipped_weapon_number == self.total_number_of_weapons: self.log.debug("%s weapon storage full", self) return False if self.session.db.get_weapon_stackable(weapon_id): stackable = [ w for w in self._weapon_storage if weapon_id == w.weapon_id ] #try to increase the number of weapons for one stackable weapon increased = False for weapon in stackable: try: weapon.increase_number_of_weapons(1) increased = True break except SetStackableWeaponNumberError: continue if not increased: weapon = StackableWeapon(self.session, weapon_id) else: weapon = Weapon(self.session, weapon_id) if weapon: self._weapon_storage.append(weapon) weapon.add_weapon_fired_listener( Callback(self._remove_from_fireable, weapon)) weapon.add_attack_ready_listener( Callback(self._add_to_fireable, weapon)) weapon.add_weapon_fired_listener( self._increase_fired_weapons_number) self._fireable.append(weapon) self.equipped_weapon_number += 1 self.on_storage_modified() # will update the range return True
def _load_combat(self, savegame_db): # load ongoing attacks if self.session.is_game_loaded(): Weapon.load_attacks(self.session, savegame_db)
def _init(self, savegame_db, force_player_id=None, disasters_enabled=True): """ @param savegame_db: Dbreader with loaded savegame database @param force_player_id: the worldid of the selected human player or default if None (debug option) """ """ All essential and non-essential parts of the world are set up here, you don't need to know everything that happens. """ #load properties self.properties = {} for (name, value) in savegame_db("SELECT name, value FROM map_properties"): self.properties[name] = value # create playerlist self.players = [] self.player = None # player sitting in front of this machine self.trader = None self.pirate = None # load player human_players = [] for player_worldid, client_id in savegame_db("SELECT rowid, client_id FROM player WHERE is_trader = 0 and is_pirate = 0 ORDER BY rowid"): player = None # check if player is an ai ai_data = self.session.db("SELECT class_package, class_name FROM ai WHERE client_id = ?", client_id) if len(ai_data) > 0: class_package, class_name = ai_data[0] # import ai class and call load on it module = __import__('horizons.ai.'+class_package, fromlist=[class_name]) ai_class = getattr(module, class_name) player = ai_class.load(self.session, savegame_db, player_worldid) else: # no ai player = HumanPlayer.load(self.session, savegame_db, player_worldid) self.players.append(player) if client_id == horizons.main.fife.get_uh_setting("ClientID"): self.player = player elif client_id is not None and len(ai_data) == 0: # possible human player candidate with different client id human_players.append(player) self.owner_highlight_active = False self.health_visible_for_all_health_instances = False if self.player is None: # we have no human player. # check if there is only one player with an id (i.e. human player) # this would be the case if the savegame originates from a different installation. # if there's more than one of this kind, we can't be sure what to select. # TODO: create interface for selecting player, if we want this if(len(human_players) == 1): # exactly one player, we can quite safely use this one self.player = human_players[0] elif not human_players and self.players: # the first player should be the human-ai hybrid self.player = self.players[0] # set the human player to the forced value (debug option) self.set_forced_player(force_player_id) if self.player is None and self.session.is_game_loaded(): self.log.warning('WARNING: Cannot autoselect a player because there are no \ or multiple candidates.') # all static data self.load_raw_map(savegame_db) # load world buildings (e.g. fish) for (building_worldid, building_typeid) in \ savegame_db("SELECT rowid, type FROM building WHERE location = ?", self.worldid): load_building(self.session, savegame_db, building_typeid, building_worldid) # use a dict because it's directly supported by the pathfinding algo self.water = dict.fromkeys(list(self.ground_map), 1.0) self._init_water_bodies() self.sea_number = self.water_body[(self.min_x, self.min_y)] # assemble list of water and coastline for ship, that can drive through shallow water # NOTE: this is rather a temporary fix to make the fisher be able to move # since there are tile between coastline and deep sea, all non-constructible tiles # are added to this list as well, which will contain a few too many self.water_and_coastline = copy.copy(self.water) for island in self.islands: for coord, tile in island.ground_map.iteritems(): if 'coastline' in tile.classes or 'constructible' not in tile.classes: self.water_and_coastline[coord] = 1.0 # create ship position list. entries: ship_map[(x, y)] = ship self.ship_map = {} self.ground_unit_map = {} # create shiplist, which is currently used for saving ships # and having at least one reference to them self.ships = [] self.ground_units = [] # create bullets list, used for saving bullets in ongoing attacks self.bullets = [] if self.session.is_game_loaded(): # there are 0 or 1 trader AIs so this is safe trader_data = savegame_db("SELECT rowid FROM player WHERE is_trader = 1") if trader_data: self.trader = Trader.load(self.session, savegame_db, trader_data[0][0]) # there are 0 or 1 pirate AIs so this is safe pirate_data = savegame_db("SELECT rowid FROM player WHERE is_pirate = 1") if pirate_data: self.pirate = Pirate.load(self.session, savegame_db, pirate_data[0][0]) # load all units (we do it here cause all buildings are loaded by now) for (worldid, typeid) in savegame_db("SELECT rowid, type FROM unit ORDER BY rowid"): Entities.units[typeid].load(self.session, savegame_db, worldid) if self.session.is_game_loaded(): # let trader command it's ships. we have to do this here cause ships have to be # initialised for this, and trader has to exist before ships are loaded. if self.trader: self.trader.load_ship_states(savegame_db) # let pirate command it's ships. we have to do this here cause ships have to be # initialised for this, and pirate has to exist before ships are loaded. if self.pirate: self.pirate.load_ship_states(savegame_db) # load the AI stuff only when we have AI players if any(isinstance(player, AIPlayer) for player in self.players): AIPlayer.load_abstract_buildings(self.session.db) # TODO: find a better place for this # load the AI players # this has to be done here because otherwise the ships and other objects won't exist for player in self.players: if not isinstance(player, HumanPlayer): player.finish_loading(savegame_db) # load bullets if self.session.is_game_loaded(): for (worldid, sx, sy, dx, dy, speed, img) in savegame_db("SELECT worldid, startx, starty, destx, desty, speed, image FROM bullet"): Bullet(img, Point(sx, sy), Point(dx, dy), speed, self.session, False, worldid) # load ongoing attacks if self.session.is_game_loaded(): Weapon.load_attacks(self.session, savegame_db) # load diplomacy self.diplomacy = Diplomacy() if self.session.is_game_loaded(): self.diplomacy.load(self, savegame_db) # add diplomacy notification listeners def notify_change(caller, old_state, new_state, a, b): player1 = u"%s" % a.name player2 = u"%s" % b.name data = {'player1' : player1, 'player2' : player2} self.session.ingame_gui.message_widget.add( None, None, 'DIPLOMACY_STATUS_'+old_state.upper()+"_"+new_state.upper(), data) self.diplomacy.add_diplomacy_status_changed_listener(notify_change) disasters_disabled_by_properties = 'disasters_enabled' in self.properties and not self.properties['disasters_enabled'] # if savegame or parameter disables disasters, it's disabled (both have to be set to enable to actually enable) disasters_disabled = not disasters_enabled or disasters_disabled_by_properties self.disaster_manager = DisasterManager(self.session, disabled=disasters_disabled) if self.session.is_game_loaded(): self.disaster_manager.load(savegame_db) self.inited = True """TUTORIAL:
def _init(self, savegame_db): """ @param savegame_db: Dbreader with loaded savegame database """ #load properties self.properties = {} for (name, value) in savegame_db("SELECT name, value FROM map_properties"): self.properties[name] = value # create playerlist self.players = [] self.player = None # player sitting in front of this machine self.trader = None self.pirate = None # load player human_players = [] for player_worldid, client_id in savegame_db("SELECT rowid, client_id FROM player WHERE is_trader = 0 and is_pirate = 0 ORDER BY rowid"): player = None # check if player is an ai ai_data = self.session.db("SELECT class_package, class_name FROM ai WHERE client_id = ?", client_id) if len(ai_data) > 0: class_package, class_name = ai_data[0] # import ai class and call load on it module = __import__('horizons.ai.'+class_package, fromlist=[class_name]) ai_class = getattr(module, class_name) player = ai_class.load(self.session, savegame_db, player_worldid) else: # no ai player = HumanPlayer.load(self.session, savegame_db, player_worldid) self.players.append(player) if client_id == horizons.main.fife.get_uh_setting("ClientID"): self.player = player elif client_id is not None and len(ai_data) == 0: # possible human player candidate with different client id human_players.append(player) if self.player is None: # we have no human player. # check if there is only one player with an id (i.e. human player) # this would be the case if the savegame originates from a different installation. # if there's more than one of this kind, we can't be sure what to select. # TODO: create interface for selecting player, if we want this if(len(human_players) == 1): # exactly one player, we can quite safely use this one self.player = human_players[0] elif not human_players and self.players: # the first player should be the human-ai hybrid self.player = self.players[0] if self.player is not None: self.player.inventory.add_change_listener(self.session.ingame_gui.update_gold, \ call_listener_now=True) if self.player is None and self.session.is_game_loaded(): self.log.warning('WARNING: Cannot autoselect a player because there are no \ or multiple candidates.') # load islands self.islands = [] for (islandid,) in savegame_db("SELECT rowid + 1000 FROM island"): island = Island(savegame_db, islandid, self.session) self.islands.append(island) #calculate map dimensions self.min_x, self.min_y, self.max_x, self.max_y = 0, 0, 0, 0 for i in self.islands: self.min_x = i.rect.left if self.min_x is None or i.rect.left < self.min_x else self.min_x self.min_y = i.rect.top if self.min_y is None or i.rect.top < self.min_y else self.min_y self.max_x = i.rect.right if self.max_x is None or i.rect.right > self.max_x else self.max_x self.max_y = i.rect.bottom if self.max_y is None or i.rect.bottom > self.max_y else self.max_y self.min_x -= 10 self.min_y -= 10 self.max_x += 10 self.max_y += 10 self.map_dimensions = Rect.init_from_borders(self.min_x, self.min_y, self.max_x, self.max_y) #add water self.log.debug("Filling world with water...") self.ground_map = {} default_grounds = Entities.grounds[int(self.properties.get('default_ground', GROUND.WATER))] # extra world size that is added so that he player can't see the "black void" border = 30 for x in xrange(self.min_x-border, self.max_x+border, 10): for y in xrange(self.min_y-border, self.max_y+border, 10): ground = default_grounds(self.session, x, y) for x_offset in xrange(0,10): if x+x_offset < self.max_x and x+x_offset>= self.min_x: for y_offset in xrange(0,10): if y+y_offset < self.max_y and y+y_offset >= self.min_y: self.ground_map[(x+x_offset, y+y_offset)] = ground # remove parts that are occupied by islands, create the island map and the full map self.island_map = {} self.full_map = copy.copy(self.ground_map) for island in self.islands: for coords in island.ground_map: if coords in self.ground_map: self.full_map[coords] = island.ground_map[coords] del self.ground_map[coords] self.island_map[coords] = island # load world buildings (e.g. fish) for (building_worldid, building_typeid) in \ savegame_db("SELECT rowid, type FROM building WHERE location = ?", self.worldid): load_building(self.session, savegame_db, building_typeid, building_worldid) # use a dict because it's directly supported by the pathfinding algo self.water = dict.fromkeys(list(self.ground_map), 1.0) self._init_water_bodies() self.sea_number = self.water_body[(self.min_x, self.min_y)] # assemble list of water and coastline for ship, that can drive through shallow water # NOTE: this is rather a temporary fix to make the fisher be able to move # since there are tile between coastline and deep sea, all non-constructible tiles # are added to this list as well, which will contain a few too many self.water_and_coastline = copy.copy(self.water) for island in self.islands: for coord, tile in island.ground_map.iteritems(): if 'coastline' in tile.classes or 'constructible' not in tile.classes: self.water_and_coastline[coord] = 1.0 # create ship position list. entries: ship_map[(x, y)] = ship self.ship_map = {} self.ground_unit_map = {} # create shiplist, which is currently used for saving ships # and having at least one reference to them self.ships = [] self.ground_units = [] # create bullets list, used for saving bullets in ongoing attacks self.bullets = [] if self.session.is_game_loaded(): # there are 0 or 1 trader AIs so this is safe trader_data = savegame_db("SELECT rowid FROM player WHERE is_trader = 1") if trader_data: self.trader = Trader.load(self.session, savegame_db, trader_data[0][0]) # there are 0 or 1 pirate AIs so this is safe pirate_data = savegame_db("SELECT rowid FROM player WHERE is_pirate = 1") if pirate_data: self.pirate = Pirate.load(self.session, savegame_db, pirate_data[0][0]) # load all units (we do it here cause all buildings are loaded by now) for (worldid, typeid) in savegame_db("SELECT rowid, type FROM unit ORDER BY rowid"): Entities.units[typeid].load(self.session, savegame_db, worldid) if self.session.is_game_loaded(): # let trader command it's ships. we have to do this here cause ships have to be # initialised for this, and trader has to exist before ships are loaded. if self.trader: self.trader.load_ship_states(savegame_db) # let pirate command it's ships. we have to do this here cause ships have to be # initialised for this, and pirate has to exist before ships are loaded. if self.pirate: self.pirate.load_ship_states(savegame_db) # load the AI players # this has to be done here because otherwise the ships and other objects won't exist AIPlayer.load_abstract_buildings(self.session.db) # TODO: find a better place for this for player in self.players: if not isinstance(player, HumanPlayer): player.finish_loading(savegame_db) # load bullets if self.session.is_game_loaded(): for (worldid, sx, sy, dx, dy, speed, img) in savegame_db("SELECT worldid, startx, starty, destx, desty, speed, image FROM bullet"): Bullet(img, Point(sx, sy), Point(dx, dy), speed, self.session, False, worldid) # load ongoing attacks if self.session.is_game_loaded(): Weapon.load_attacks(self.session, savegame_db) # load diplomacy self.diplomacy = Diplomacy() if self.session.is_game_loaded(): self.diplomacy.load(self, savegame_db) # add diplomacy notification listeners def notify_change(caller, change_type, a, b): player1 = a.name player2 = b.name #check if status really changed, if so update status string if change_type == 'friend': status = 'friends' elif change_type == 'enemy': status = 'enemies' else: status = 'neutral' self.session.ingame_gui.message_widget.add(self.max_x/2, self.max_y/2, 'DIPLOMACY_STATUS_CHANGED', {'player1' : player1, 'player2' : player2, 'status' : status}) self.diplomacy.add_diplomacy_status_changed_listener(notify_change) self.inited = True """TUTORIAL: