示例#1
0
	def __init__(self, gui, db, rng_seed=None):
		super(Session, self).__init__()
		self.log.debug("Initing session")
		self.gui = gui # main gui, not ingame gui
		self.db = db # main db for game data (game.sqlite)
		# this saves how often the current game has been saved
		self.savecounter = 0
		self.is_alive = True

		WorldObject.reset()
		NamedObject.reset()
		AIPlayer.clear_caches()

		#game
		self.random = self.create_rng(rng_seed)
		self.timer = self.create_timer()
		Scheduler.create_instance(self.timer)
		self.manager = self.create_manager()
		self.view = View(self, (15, 15))
		Entities.load(self.db)
		self.scenario_eventhandler = ScenarioEventHandler(self) # dummy handler with no events
		self.campaign = {}

		#GUI
		self.gui.session = self
		self.ingame_gui = IngameGui(self, self.gui)
		self.keylistener = IngameKeyListener(self)
		self.coordinates_tooltip = None
		self.display_speed()

		self.selected_instances = set()
		self.selection_groups = [set()] * 10 # List of sets that holds the player assigned unit groups.
示例#2
0
def new_session(mapgen=create_map, rng_seed=RANDOM_SEED, human_player = True, ai_players = 0):
	"""
	Create a new session with a map, add one human player and a trader (it will crash
	otherwise). It returns both session and player to avoid making the function-baed
	tests too verbose.
	"""
	session = SPTestSession(horizons.main.db, rng_seed=rng_seed)
	human_difficulty = DifficultySettings.DEFAULT_LEVEL
	ai_difficulty = DifficultySettings.EASY_LEVEL

	players = []
	if human_player:
		players.append({'id': 1, 'name': 'foobar', 'color': Color[1], 'local': True, 'is_ai': False, 'difficulty': human_difficulty})
	for i in xrange(ai_players):
		id = i + human_player + 1
		players.append({'id': id, 'name': ('AI' + str(i)), 'color': Color[id], 'local': id == 1, 'is_ai': True, 'difficulty': ai_difficulty})

	session.load(mapgen(), players)
	session.world.init_fish_indexer()
	# use different trader id here, so that init_new_world can be called
	# (else there would be a worldid conflict)
	session.world.trader = Trader(session, 99999 + 42, 'Free Trader', Color())

	if ai_players > 0: # currently only ai tests use the ships
		for player in session.world.players:
			point = session.world.get_random_possible_ship_position()
			ship = CreateUnit(player.worldid, UNITS.PLAYER_SHIP_CLASS, point.x, point.y)(issuer=player)
			# give ship basic resources
			for res, amount in session.db("SELECT resource, amount FROM start_resources"):
				ship.inventory.alter(res, amount)
		AIPlayer.load_abstract_buildings(session.db)

	return session, session.world.player
示例#3
0
	def __init__(self, db, rng_seed=None):
		"""
		Unfortunately, right now there is no other way to setup Dummy versions of the GUI,
		View etc., unless we want to patch the references in the session module.
		"""
		super(LivingObject, self).__init__()
		self.gui = Dummy()
		self.db = db
		self.savecounter = 0	# this is a new game.
		self.is_alive = True

		WorldObject.reset()
		NamedObject.reset()
		AIPlayer.clear_caches()

		# Game
		self.current_tick = 0
		self.random = self.create_rng(rng_seed)
		self.timer = self.create_timer()
		Scheduler.create_instance(self.timer)
		ExtScheduler.create_instance(Dummy)
		self.manager = self.create_manager()
		self.view = Dummy()
		self.view.renderer = Dummy()
		Entities.load(self.db)
		self.scenario_eventhandler = Dummy()
		self.campaign = {}
		self.selected_instances = []

		# GUI
		self.gui.session = self
		self.ingame_gui = Dummy()

		GAME_SPEED.TICKS_PER_SECOND = 16
示例#4
0
	def init_new_world(self, trader_enabled, pirate_enabled, natural_resource_multiplier):
		"""
		This should be called if a new map is loaded (not a savegame, a fresh
		map). In other words when it is loaded for the first time.

		NOTE: commands for creating the world objects are executed directly,
		      bypassing the manager
		      This is necessary because else the commands would be transmitted
		      over the wire in network games.

		@return: the coordinates of the players first ship
		"""

		# workaround: the creation of all the objects causes a lot of logging output, we don't need
		#             therefore, reset the levels for now
		loggers_to_silence = { 'world.production' : None }
		for logger_name in loggers_to_silence:
			logger = logging.getLogger(logger_name)
			loggers_to_silence[logger_name] = logger.getEffectiveLevel()
			logger.setLevel( logging.WARN )

		# add a random number of environmental objects
		if natural_resource_multiplier != 0:
			self._add_nature_objects(natural_resource_multiplier)

		# reset loggers, see above
		for logger_name, level in loggers_to_silence.iteritems():
			logging.getLogger(logger_name).setLevel(level)

		# add free trader
		if trader_enabled:
			self.trader = Trader(self.session, 99999, u"Free Trader", Color())

		ret_coords = None
		for player in self.players:
			# Adding ships for the players
			# hack to place the ship on the development map
			point = self.get_random_possible_ship_position()
			# Execute command directly, not via manager, because else it would be transmitted over the
			# network to other players. Those however will do the same thing anyways.
			ship = CreateUnit(player.worldid, UNITS.PLAYER_SHIP, point.x, point.y)(issuer=self.session.world.player)
			# give ship basic resources
			for res, amount in self.session.db("SELECT resource, amount FROM start_resources"):
				ship.get_component(StorageComponent).inventory.alter(res, amount)
			if player is self.player:
				ret_coords = point.to_tuple()

		# 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

		# add a pirate ship
		if pirate_enabled:
			self.pirate = Pirate(self.session, 99998, "Captain Blackbeard", Color())

		# Fire a message for new world creation
		self.session.ingame_gui.message_widget.add(None, None, 'NEW_WORLD')
		assert ret_coords is not None, "Return coords are None. No players loaded?"
		return ret_coords
示例#5
0
	def setup_player(self, id, name, color, clientid, local, is_ai, difficulty_level):
		"""Sets up a new Player instance and adds her to the active world.
		Only used for new games. Loading old players is done in _init().
		@param local: bool, whether the player is the one sitting on front of this machine."""
		inv = self.session.db.get_player_start_res()
		player = None
		if is_ai: # a human controlled AI player
			player = AIPlayer(self.session, id, name, color, clientid, difficulty_level)
		else:
			player = HumanPlayer(self.session, id, name, color, clientid, difficulty_level)
		player.initialize(inv)  # Componentholder init
		if local:
			self.player = player
		self.players.append(player)
示例#6
0
	def setup_player(self, id, name, color, clientid, local, is_ai, difficulty_level):
		"""Sets up a new Player instance and adds her to the active world.
		Only used for new games. Loading old players is done in _init().
		@param local: bool, whether the player is the one sitting on front of this machine."""
		inv = self.session.db.get_player_start_res()
		player = None
		if is_ai: # a human controlled AI player
			player = AIPlayer(self.session, id, name, color, clientid, difficulty_level)
		else:
			player = HumanPlayer(self.session, id, name, color, clientid, difficulty_level)
		player.initialize(inv)  # Componentholder init
		if local:
			self.player = player
		self.players.append(player)
示例#7
0
	def __init__(self, gui, db, rng_seed=None):
		super(Session, self).__init__()
		assert isinstance(gui, Gui)
		assert isinstance(db, horizons.util.uhdbaccessor.UhDbAccessor)
		self.log.debug("Initing session")
		self.gui = gui # main gui, not ingame gui
		self.db = db # main db for game data (game.sql)
		# this saves how often the current game has been saved
		self.savecounter = 0
		self.is_alive = True

		self.message_bus = MessageBus()

		# misc
		WorldObject.reset()
		NamedComponent.reset()
		AIPlayer.clear_caches()

		#game
		self.random = self.create_rng(rng_seed)
		assert isinstance(self.random, Random)
		self.timer = self.create_timer()
		Scheduler.create_instance(self.timer)
		self.manager = self.create_manager()
		self.view = View(self)
		Entities.load(self.db)
		self.scenario_eventhandler = ScenarioEventHandler(self) # dummy handler with no events
		self.campaign = {}

		#GUI
		self.gui.session = self
		self.ingame_gui = IngameGui(self, self.gui)
		self.keylistener = IngameKeyListener(self)
		self.coordinates_tooltip = None
		self.display_speed()
		LastActivePlayerSettlementManager.create_instance(self)


		self.status_icon_manager = StatusIconManager(self)

		self.selected_instances = set()
		self.selection_groups = [set()] * 10 # List of sets that holds the player assigned unit groups.
示例#8
0
	def __init__(self, db, rng_seed=None):
		"""
		Unfortunately, right now there is no other way to setup Dummy versions of the GUI,
		View etc., unless we want to patch the references in the session module.
		"""
		super(LivingObject, self).__init__()
		self.gui = Dummy()
		self.db = db
		self.savecounter = 0	# this is a new game.
		self.is_alive = True

		WorldObject.reset()
		NamedComponent.reset()
		AIPlayer.clear_caches()

		# Game
		self.random = self.create_rng(rng_seed)
		self.timer = self.create_timer()
		Scheduler.create_instance(self.timer)
		ExtScheduler.create_instance(Dummy)
		self.manager = self.create_manager()
		self.view = Dummy()
		self.view.renderer = Dummy()
		Entities.load(self.db)
		self.scenario_eventhandler = Dummy()
		self.campaign = {}

		self.message_bus = MessageBus()
		self.status_icon_manager = StatusIconManager(self)


		# GUI
		self.gui.session = self
		self.ingame_gui = Dummy()
		LastActivePlayerSettlementManager.create_instance(self)

		self.selected_instances = set()
		self.selection_groups = [set()] * 10 # List of sets that holds the player assigned unit groups.

		GAME_SPEED.TICKS_PER_SECOND = 16
示例#9
0
	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] = json.loads(value)
		if not 'disasters_enabled' in self.properties:
			# set on first init
			self.properties['disasters_enabled'] = disasters_enabled

		# create playerlist
		self.players = []
		self.player = None # player sitting in front of this machine
		self.trader = None
		self.pirate = None

		self._load_players(savegame_db, force_player_id)

		# all static data
		LoadingProgress.broadcast(self, 'world_load_map')
		self.load_raw_map(savegame_db)

		# load world buildings (e.g. fish)
		LoadingProgress.broadcast(self, 'world_load_buildings')
		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
		LoadingProgress.broadcast(self, 'world_init_water')
		self.water = dict((tile, 1.0) for tile in self.ground_map)
		self._init_water_bodies()
		self.sea_number = self.water_body[(self.min_x, self.min_y)]
		for island in self.islands:
			island.terrain_cache.create_sea_cache()

		# 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
		self._init_shallow_water_bodies()
		self.shallow_sea_number = self.shallow_water_body[(self.min_x, self.min_y)]

		# 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)
		LoadingProgress.broadcast(self, 'world_load_units')
		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 and pirate command their ships. we have to do this here
			# because ships have to be initialized for this, and they have
			# to exist before ships are loaded.
			if self.trader:
				self.trader.load_ship_states(savegame_db)
			if self.pirate:
				self.pirate.finish_loading(savegame_db)

			# load the AI stuff only when we have AI players
			LoadingProgress.broadcast(self, 'world_setup_ai')
			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)

		LoadingProgress.broadcast(self, 'world_load_stuff')
		self._load_combat(savegame_db)
		self._load_diplomacy(savegame_db)
		self._load_disasters(savegame_db)

		self.inited = True
		"""TUTORIAL:
示例#10
0
    def init_new_world(self, trader_enabled, pirate_enabled,
                       natural_resource_multiplier):
        """
		This should be called if a new map is loaded (not a savegame, a fresh
		map). In other words, when it is loaded for the first time.

		NOTE: commands for creating the world objects are executed directly,
		      bypassing the manager.
		      This is necessary because else the commands would be transmitted
		      over the wire in network games.

		@return: the coordinates of the players first ship
		"""

        # workaround: the creation of all the objects causes a lot of logging output we don't need.
        #             therefore, reset the levels for now
        loggers_to_silence = {'world.production': None}
        for logger_name in loggers_to_silence:
            logger = logging.getLogger(logger_name)
            loggers_to_silence[logger_name] = logger.getEffectiveLevel()
            logger.setLevel(logging.WARN)

        # add a random number of environmental objects
        if natural_resource_multiplier != 0:
            self._add_nature_objects(natural_resource_multiplier)

        # reset loggers, see above
        for logger_name, level in loggers_to_silence.items():
            logging.getLogger(logger_name).setLevel(level)

        # add free trader
        if trader_enabled:
            self.trader = Trader(self.session, 99999, "Free Trader", Color())

        ret_coords = None
        for player in self.players:
            # Adding ships for the players
            # hack to place the ship on the development map
            point = self.get_random_possible_ship_position()
            # Execute command directly, not via manager, because else it would be transmitted over the
            # network to other players. Those however will do the same thing anyways.
            ship = CreateUnit(player.worldid, UNITS.PLAYER_SHIP, point.x,
                              point.y)(issuer=self.session.world.player)
            # give ship basic resources
            for res, amount in self.session.db(
                    "SELECT resource, amount FROM start_resources"):
                ship.get_component(StorageComponent).inventory.alter(
                    res, amount)
            if player is self.player:
                ret_coords = point.to_tuple()

                # HACK: Store starting ship as first unit group, and select it
                def _preselect_player_ship(player_ship):
                    sel_comp = player_ship.get_component(SelectableComponent)
                    sel_comp.select(reset_cam=True)
                    self.session.selected_instances = {player_ship}
                    self.session.ingame_gui.handle_selection_group(1, True)
                    sel_comp.show_menu()

                select_ship = partial(_preselect_player_ship, ship)
                Scheduler().add_new_object(select_ship, ship, run_in=0)

        # 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

        # add a pirate ship
        if pirate_enabled:
            self.pirate = Pirate(self.session, 99998, "Captain Blackbeard",
                                 Color())

        assert ret_coords is not None, "Return coords are None. No players loaded?"
        return ret_coords
示例#11
0
    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] = json.loads(value)
        if 'disasters_enabled' not in self.properties:
            # set on first init
            self.properties['disasters_enabled'] = disasters_enabled

        self._load_players(savegame_db, force_player_id)

        # all static data
        LoadingProgress.broadcast(self, 'world_load_map')
        self.load_raw_map(savegame_db)

        # load world buildings (e.g. fish)
        LoadingProgress.broadcast(self, 'world_load_buildings')
        buildings = savegame_db(
            "SELECT rowid, type FROM building WHERE location = ?",
            self.worldid)
        for (building_worldid, building_typeid) in buildings:
            load_building(self.session, savegame_db, building_typeid,
                          building_worldid)

        # use a dict because it's directly supported by the pathfinding algo
        LoadingProgress.broadcast(self, 'world_init_water')
        self.water = {tile: 1.0 for tile in self.ground_map}
        self._init_water_bodies()
        self.sea_number = self.water_body[(self.min_x, self.min_y)]
        for island in self.islands:
            island.terrain_cache.create_sea_cache()

        # 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.items():
                if 'coastline' in tile.classes or 'constructible' not in tile.classes:
                    self.water_and_coastline[coord] = 1.0
        self._init_shallow_water_bodies()
        self.shallow_sea_number = self.shallow_water_body[(self.min_x,
                                                           self.min_y)]

        # create ship position list. entries: ship_map[(x, y)] = ship
        self.ship_map = {}
        self.ground_unit_map = {}

        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)
        LoadingProgress.broadcast(self, 'world_load_units')
        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 and pirate command their ships. we have to do this here
            # because ships have to be initialized for this, and they have
            # to exist before ships are loaded.
            if self.trader:
                self.trader.load_ship_states(savegame_db)
            if self.pirate:
                self.pirate.finish_loading(savegame_db)

            # load the AI stuff only when we have AI players
            LoadingProgress.broadcast(self, 'world_setup_ai')
            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)

        LoadingProgress.broadcast(self, 'world_load_stuff')
        self._load_combat(savegame_db)
        self._load_diplomacy(savegame_db)
        self._load_disasters(savegame_db)

        self.inited = True
        """TUTORIAL:
示例#12
0
	def _clear_caches(cls):
		"""Clear all data caches in global namespace related to a session"""
		WorldObject.reset()
		NamedComponent.reset()
		AIPlayer.clear_caches()
		SelectableBuildingComponent.reset()
示例#13
0
	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:
示例#14
0
	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:
示例#15
0
	def _clear_caches(self):
		WorldObject.reset()
		NamedComponent.reset()
		AIPlayer.clear_caches()
示例#16
0
 def _clear_caches(cls):
     """Clear all data caches in global namespace related to a session"""
     WorldObject.reset()
     NamedComponent.reset()
     AIPlayer.clear_caches()
     SelectableBuildingComponent.reset()
示例#17
0
	def init_new_world(self, minclay = 2, maxclay = 3, minmountains = 1, maxmountains = 3):
		"""
		This should be called if a new map is loaded (not a savegame, a fresh
		map). In other words when it is loaded for the first time.

		NOTE: commands for creating the world objects are executed directly,
		      bypassing the manager
		      This is necessary because else the commands would be transmitted
		      over the wire in network games.

		@return: Returs the coordinates of the players first ship
		"""
		# workaround: the creation of all the objects causes a lot of logging output, we don't need
		#             therefore, reset the levels for now
		loggers_to_silence = { 'world.production' : None }
		for logger_name in loggers_to_silence:
			logger = logging.getLogger(logger_name)
			loggers_to_silence[logger_name] = logger.getEffectiveLevel()
			logger.setLevel( logging.WARN )

		from horizons.command.building import Build
		from horizons.command.unit import CreateUnit
		# add a random number of environmental objects to the gameworld
		if int(self.properties.get('RandomTrees', 1)) == 1:
			Tree = Entities.buildings[BUILDINGS.TREE_CLASS]
			Clay = Entities.buildings[BUILDINGS.CLAY_DEPOSIT_CLASS]
			Fish = Entities.buildings[BUILDINGS.FISH_DEPOSIT_CLASS]
			Mountain = Entities.buildings[BUILDINGS.MOUNTAIN_CLASS]
			for island in self.islands:
				if maxclay <= minclay:
					minclay = maxclay-1
				if maxmountains <= minmountains:
					minmountains = maxmountains-1
				max_clay_deposits = self.session.random.randint(minclay, maxclay)
				max_mountains = self.session.random.randint(minmountains, maxmountains)
				num_clay_deposits = 0
				num_mountains = 0
				# TODO: fix this sorted()-call. its slow but orderness of dict-loop isn't guaranteed
				for coords, tile in sorted(island.ground_map.iteritems()):
					# add tree to every nth tile
					if self.session.random.randint(0, 2) == 0 and \
					   Tree.check_build(self.session, tile, check_settlement=False):
						building = Build(Tree, coords[0], coords[1], ownerless=True,island=island)(issuer=None)
						building.finish_production_now() # make trees big and fill their inventory
						if self.session.random.randint(0, WILD_ANIMAL.POPUlATION_INIT_RATIO) == 0: # add animal to every nth tree
							CreateUnit(island.worldid, UNITS.WILD_ANIMAL_CLASS, *coords)(issuer=None)
						if self.session.random.random() > WILD_ANIMAL.FOOD_AVAILABLE_ON_START:
							building.inventory.alter(RES.WILDANIMALFOOD_ID, -1)
					elif num_clay_deposits < max_clay_deposits and \
					     self.session.random.randint(0, 40) == 0 and \
					     Clay.check_build(self.session, tile, check_settlement=False):
						num_clay_deposits += 1
						Build(Clay, coords[0], coords[1], ownerless=True, island=island)(issuer=None)
					elif num_mountains < max_mountains and \
					     self.session.random.randint(0, 40) == 0 and \
					     Mountain.check_build(self.session, tile, check_settlement=False):
						num_mountains += 1
						Build(Mountain, coords[0], coords[1], ownerless=True, island=island)(issuer=None)
					if 'coastline' in tile.classes and self.session.random.randint(0, 4) == 0:
						# try to place fish
						# from the current position, go to random directions 2 times
						directions = [ (i, j) for i in xrange(-1, 2) for j in xrange(-1, 2) ]
						for (x_dir, y_dir) in self.session.random.sample(directions, 2):
							# move a random amount in both directions
							coord_to_check = (
							  coords[0] + x_dir * self.session.random.randint(3, 9),
							  coords[1] + y_dir * self.session.random.randint(3, 9),
							)
							# now we have the location, check if we can build here
							if coord_to_check in self.ground_map:
								Build(Fish, coord_to_check[0], coord_to_check[1], ownerless=True, \
								      island=self)(issuer=None)

		# reset loggers, see above
		for logger_name, level in loggers_to_silence.iteritems():
			logging.getLogger(logger_name).setLevel(level)

		# add free trader
		self.trader = Trader(self.session, 99999, u"Free Trader", Color())

		ret_coords = None
		for player in self.players:
			# Adding ships for the players
			# hack to place the ship on the development map
			point = self.get_random_possible_ship_position()
			# Execute command directly, not via manager, because else it would be transmitted over the
			# network to other players. Those however will do the same thing anyways.
			ship = CreateUnit(player.worldid, UNITS.PLAYER_SHIP_CLASS, point.x, point.y)(issuer=self.session.world.player)
			# give ship basic resources
			for res, amount in self.session.db("SELECT resource, amount FROM start_resources"):
				ship.inventory.alter(res, amount)
			if player is self.player:
				ret_coords = point.to_tuple()
		AIPlayer.load_abstract_buildings(self.session.db) # TODO: find a better place for this

		# add a pirate ship
		self.pirate = Pirate(self.session, 99998, "Captain Blackbeard", Color())

		# Fire a message for new world creation
		self.session.ingame_gui.message_widget.add(self.max_x/2, self.max_y/2, 'NEW_WORLD')
		assert ret_coords is not None, "Return coords are None. No players loaded?"
		return ret_coords