コード例 #1
0
ファイル: buildable.py プロジェクト: aviler/unknown-horizons
	def check_build(cls, session, point, rotation=45, check_settlement=True, ship=None, issuer=None):
		"""Check if a building is buildable here.
		All tiles, that the building occupies are checked.
		@param point: Point instance, coords
		@param rotation: prefered rotation of building
		@param check_settlement: whether to check for a settlement (for settlementless buildings)
		@param ship: ship instance if building from ship
		@return instance of _BuildPosition"""
		# for non-quadratic buildings, we have to switch width and height depending on the rotation
		if rotation == 45 or rotation == 225:
			position = Rect.init_from_topleft_and_size(point.x, point.y, cls.size[0], cls.size[1])
		else:
			position = Rect.init_from_topleft_and_size(point.x, point.y, cls.size[1], cls.size[0])

		buildable = True
		problem = None
		tearset = []
		try:
			island = cls._check_island(session, position)
			# TODO: if the rotation changes here for non-quadratic buildings, wrong results will be returned
			rotation = cls._check_rotation(session, position, rotation)
			tearset = cls._check_buildings(session, position, island=island)
			cls._check_units(session, position)
			if check_settlement:
				cls._check_settlement(session, position, ship=ship, issuer=issuer)
		except _NotBuildableError as e:
			buildable = False
			problem = (e.errortype, BuildableErrorTypes.text[ e.errortype ])

		return _BuildPosition(position, rotation, tearset, buildable, problem=problem)
コード例 #2
0
ファイル: buildable.py プロジェクト: aviler/unknown-horizons
	def check_build(cls, session, point, rotation=45, check_settlement=True, ship=None, issuer=None):
		# for non-quadratic buildings, we have to switch width and height depending on the rotation
		if rotation == 45 or rotation == 225:
			position = Rect.init_from_topleft_and_size(point.x, point.y, cls.size[0], cls.size[1])
		else:
			position = Rect.init_from_topleft_and_size(point.x, point.y, cls.size[1], cls.size[0])

		buildable = True
		tearset = []
		return _BuildPosition(position, rotation, tearset, buildable)
コード例 #3
0
	def testRadiusCoords(self):
		area = Rect.init_from_topleft_and_size(0, 0, 100, 100)
		tree = TileQuadTree(area)
		tree2 = TileQuadTree(area)
		tree2_check = lambda coord : coord[0] % 2 == 0 and coord[0] % 3 == 0 and coord[1] % 5 == 0
		for coord in area.tuple_iter():
			tree.add_tile( _FakeTile(coord[0], coord[1] ) )
			if tree2_check(coord):
				tree2.add_tile( _FakeTile(coord[0], coord[1]) )

		def get_diff_msg(l1, l2):
			msg = 'unequal at radius '+ str(radius)
			msg += '\nl1: ' + str(l1)
			msg += '\nl2: ' + str(l2)
			diff1 = [ i for i in l1 if i not in l2 ]
			diff2 = [ i for i in l2 if i not in l1 ]
			msg += '\ndiff1: ' + str(diff1)
			msg += '\ndiff2: ' + str(diff2)
			return msg
		def do_test(center, radius):
			l1 = []
			for tile in tree.get_radius_tiles(center, radius):
				l1.append((tile.x, tile.y))
			l2 = []
			tree.visit_radius_tiles(center, radius, lambda x : l2.append((x.x, x.y)))
			l1.sort()
			l2.sort()
			l3 = sorted(center.get_radius_coordinates(radius, include_self=True))
			self.assertEqual(l1, l3, get_diff_msg(l1, l3))
			self.assertEqual(l1, l2, get_diff_msg(l1, l2))
		def do_test2(center, radius):
			l1 = []
			for tile in tree2.get_radius_tiles(center, radius):
				l1.append((tile.x, tile.y))
			l2 = []
			tree2.visit_radius_tiles(center, radius, lambda x : l2.append((x.x, x.y)))
			l1.sort()
			l2.sort()
			l3 = [ x for x in sorted(center.get_radius_coordinates(radius, include_self=True)) if tree2_check(x)]
			self.assertEqual(l1, l3, get_diff_msg(l1, l3))
			self.assertEqual(l1, l2, get_diff_msg(l1, l2))


		center = Rect.init_from_topleft_and_size(20, 20, 0, 0)
		center2 = Rect.init_from_topleft_and_size(20, 20, 3, 3)
		center3 = Rect.init_from_topleft_and_size(20, 20, 5, 2)

		print 'checking for correctness'
		for radius in xrange(0,15):
			do_test(center, radius)
			do_test(center2, radius)
			do_test(center3, radius)
			do_test2(center, radius)
			do_test2(center2, radius)
			do_test2(center3, radius)
コード例 #4
0
	def get_loading_area(cls, building_id, rotation, pos):
		if building_id == BUILDINGS.MOUNTAIN or building_id == BUILDINGS.IRON_MINE:
			if rotation == 45:
				return Rect.init_from_topleft_and_size(pos.origin.x, pos.origin.y + 1, 1, 3)
			elif rotation == 135:
				return Rect.init_from_topleft_and_size(pos.origin.x + 1, pos.origin.y + pos.height - 1, 3, 1)
			elif rotation == 225:
				return Rect.init_from_topleft_and_size(pos.origin.x + pos.width -1, pos.origin.y + 1, 1, 3)
			elif rotation == 315:
				return Rect.init_from_topleft_and_size(pos.origin.x + 1, pos.origin.y, 3, 1)
			assert False
		else:
			return pos
コード例 #5
0
	def testRect(self):
		r1 = Rect(Point(0,0), 1, 1)
		r2 = Rect(0, 0, 1 ,1)
		r3 = Rect(Point(2, 2), 1, 1)
		self.assertEqual(r1, r2)
		self.assertTrue(r1 == r2)
		self.assertFalse(r1.contains(Point(-1,-1)))
		self.assertTrue(r2.contains(Point(0,0)))
		self.assertTrue(r2.contains(Point(1,1)))
		self.assertTrue(r1.intersects(r2))
		self.assertFalse(r1.intersects(r3))
コード例 #6
0
ファイル: island.py プロジェクト: mitfik/unknown-horizons
	def __init(self, origin, filename):
		"""
		Load the actual island from a file
		@param origin: Point
		@param filename: String, filename of island db or random map id
		"""
		self.file = filename
		self.origin = origin

		# check if filename is a random map
		if random_map.is_random_island_id_string(filename):
			# it's a random map id, create this map and load it
			db = random_map.create_random_island(filename)
		else:
			db = DbReader(filename) # Create a new DbReader instance to load the maps file.

		p_x, p_y, width, height = db("SELECT (MIN(x) + ?), (MIN(y) + ?), (1 + MAX(x) - MIN(x)), (1 + MAX(y) - MIN(y)) FROM ground", self.origin.x, self.origin.y)[0]

		# rect for quick checking if a tile isn't on this island
		# NOTE: it contains tiles, that are not on the island!
		self.rect = Rect(Point(p_x, p_y), width, height)

		self.ground_map = {}
		for (rel_x, rel_y, ground_id) in db("SELECT x, y, ground_id FROM ground"): # Load grounds
			ground = Entities.grounds[ground_id](self.session, self.origin.x + rel_x, self.origin.y + rel_y)
			# These are important for pathfinding and building to check if the ground tile
			# is blocked in any way.
			self.ground_map[(ground.x, ground.y)] = ground

		self._init_cache()

		self.settlements = []
		self.wild_animals = []
		self.num_trees = 0

		self.path_nodes = IslandPathNodes(self)

		# define the rectangle with the smallest area that contains every island tile its position
		min_x = min(zip(*self.ground_map.keys())[0])
		max_x = max(zip(*self.ground_map.keys())[0])
		min_y = min(zip(*self.ground_map.keys())[1])
		max_y = max(zip(*self.ground_map.keys())[1])
		self.position = Rect.init_from_borders(min_x, min_y, max_x, max_y)

		# repopulate wild animals every 2 mins if they die out.
		Scheduler().add_new_object(self.check_wild_animal_population, self, Scheduler().get_ticks(120), -1)

		"""TUTORIAL:
コード例 #7
0
    def generate_minimap(cls, size, parameters):
        """Called as subprocess, calculates minimap data and passes it via string via stdout"""
        # called as standalone basically, so init everything we need
        from horizons.main import _create_main_db
        from horizons.entities import Entities
        from horizons.ext.dummy import Dummy

        db = _create_main_db()
        Entities.load_grounds(db, load_now=False)  # create all references
        map_file = SingleplayerMenu._generate_random_map(parameters)
        world = cls._load_raw_world(map_file)
        location = Rect.init_from_topleft_and_size_tuples((0, 0), size)
        minimap = Minimap(
            location,
            session=None,
            view=None,
            world=world,
            targetrenderer=Dummy(),
            imagemanager=Dummy(),
            cam_border=False,
            use_rotation=False,
            preview=True,
        )
        # communicate via stdout
        print minimap.dump_data()
コード例 #8
0
ファイル: minimap.py プロジェクト: perher/unknown-horizons
    def __init__(
        self,
        position,
        session,
        world,
        view,
        targetrenderer,
        imagemanager,
        renderer=None,
        cam_border=True,
        use_rotation=True,
        on_click=None,
        preview=False,
        tooltip=None,
    ):
        """
		@param position: a Rect or a Pychan Icon, where we will draw to
		@param world: World object or fake thereof
		@param view: View object for cam control. Can be None to disable this
		@param renderer: renderer to be used if position isn't an icon
		@param targetrenderer: fife target rendererfor drawing on icons
		@param imagemanager: fife imagemanager for drawing on icons
		@param cam_border: boolean, whether to draw the cam border
		@param use_rotation: boolean, whether to use rotation (it must also be enabled in the settings)
		@param on_click: function taking 1 argument or None for scrolling
		@param preview: flag, whether to only show the map as preview
		@param tooltip: always show this tooltip when cursor hovers over minimap
		"""
        if isinstance(position, Rect):
            self.location = position
            self.renderer = renderer
        else:  # assume icon
            self.location = Rect.init_from_topleft_and_size(0, 0, position.width, position.height)
            self.icon = position
            self.use_overlay_icon(self.icon)
        self.session = session
        self.world = world
        if self.world:
            self._update_world_to_minimap_ratio()
        self.view = view
        self.rotation = 0
        self.fixed_tooltip = tooltip

        if on_click is not None:
            self.on_click = on_click

        self.cam_border = cam_border
        self.use_rotation = use_rotation
        self.preview = preview

        self.location_center = self.location.center()

        self._id = str(self.__class__.__minimap_id_counter.next())  # internal identifier, used for allocating resources

        self._image_size_cache = {}  # internal detail

        self.imagemanager = imagemanager

        self.minimap_image = _MinimapImage(self, targetrenderer)
コード例 #9
0
ファイル: island.py プロジェクト: court-jus/unknown-horizons
    def __init(self, origin, filename):
        """
		Load the actual island from a file
		@param origin: Point
		@param filename: String, filename of island db or random map id
		"""
        self.file = filename
        self.origin = origin

        # check if filename is a random map
        if random_map.is_random_island_id_string(filename):
            # it's a random map id, create this map and load it
            db = random_map.create_random_island(filename)
        else:
            db = DbReader(
                filename
            )  # Create a new DbReader instance to load the maps file.

        p_x, p_y, width, height = db(
            "SELECT (MIN(x) + ?), (MIN(y) + ?), (1 + MAX(x) - MIN(x)), (1 + MAX(y) - MIN(y)) FROM ground",
            self.origin.x, self.origin.y)[0]

        # rect for quick checking if a tile isn't on this island
        # NOTE: it contains tiles, that are not on the island!
        self.rect = Rect(Point(p_x, p_y), width, height)

        self.ground_map = {}
        for (rel_x, rel_y, ground_id
             ) in db("SELECT x, y, ground_id FROM ground"):  # Load grounds
            ground = Entities.grounds[ground_id](self.session,
                                                 self.origin.x + rel_x,
                                                 self.origin.y + rel_y)
            # These are important for pathfinding and building to check if the ground tile
            # is blocked in any way.
            self.ground_map[(ground.x, ground.y)] = ground

        self.settlements = []
        self.wild_animals = []

        self.path_nodes = IslandPathNodes(self)

        # repopulate wild animals every 2 mins if they die out.
        Scheduler().add_new_object(self.check_wild_animal_population, self,
                                   Scheduler().get_ticks(120), -1)
        """TUTORIAL:
コード例 #10
0
 def get_displayed_area(self):
     """Returns the coords of what is displayed on the screen as Rect"""
     coords = self.cam.getLocationRef().getLayerCoordinates()
     cell_dim = self.cam.getCellImageDimensions()
     screen_width_as_coords = (horizons.main.fife.engine_settings.getScreenWidth()/cell_dim.x, \
                               horizons.main.fife.engine_settings.getScreenHeight()/cell_dim.y)
     return Rect.init_from_topleft_and_size(coords.x - (screen_width_as_coords[0]/2), \
                                            coords.y - (screen_width_as_coords[1]/2),
                                            *screen_width_as_coords)
コード例 #11
0
ファイル: view.py プロジェクト: carnivoro/unknown-horizons
	def get_displayed_area(self):
		"""Returns the coords of what is displayed on the screen as Rect"""
		coords = self.cam.getLocationRef().getLayerCoordinates()
		cell_dim = self.cam.getCellImageDimensions()
		screen_width_as_coords = (horizons.main.fife.engine_settings.getScreenWidth()/cell_dim.x, \
		                          horizons.main.fife.engine_settings.getScreenHeight()/cell_dim.y)
		return Rect.init_from_topleft_and_size(coords.x - (screen_width_as_coords[0]/2), \
		                                       coords.y - (screen_width_as_coords[1]/2),
		                                       *screen_width_as_coords)
コード例 #12
0
	def __init(self, deposit_class, mine_empty_msg_shown):
		self.__deposit_class = deposit_class
		self._mine_empty_msg_shown = mine_empty_msg_shown

		# setup loading area
		# TODO: for now we assume that a mine building is 5x5 with a 3x1 entry on 1 side
		#       this needs to be generalised, possibly by defining the loading tiles in the db
		pos = self.position
		if self.rotation == 45:
			self.loading_area = Rect.init_from_topleft_and_size(pos.origin.x, pos.origin.y + 1, 0, 2)
		elif self.rotation == 135:
			self.loading_area = Rect.init_from_topleft_and_size(pos.origin.x + 1, pos.origin.y + pos.height - 1, 2, 0)
		elif self.rotation == 225:
			self.loading_area = Rect.init_from_topleft_and_size(pos.origin.x + pos.width -1, pos.origin.y + 1, 0, 2)
		elif self.rotation == 315:
			self.loading_area = Rect.init_from_topleft_and_size(pos.origin.x + 1, pos.origin.y, 2, 0)
		else:
			assert False
コード例 #13
0
ファイル: island.py プロジェクト: savionok/unknown-horizons
    def __init(self, origin, filename, preview=False):
        """
		Load the actual island from a file
		@param origin: Point
		@param filename: String, filename of island db or random map id
		@param preview: flag, map preview mode
		"""
        self.file = filename
        self.origin = origin
        db = self._get_island_db()

        p_x, p_y, width, height = db(
            "SELECT (MIN(x) + ?), (MIN(y) + ?), (1 + MAX(x) - MIN(x)), (1 + MAX(y) - MIN(y)) FROM ground",
            self.origin.x,
            self.origin.y,
        )[0]

        # rect for quick checking if a tile isn't on this island
        # NOTE: it contains tiles, that are not on the island!
        self.rect = Rect(Point(p_x, p_y), width, height)

        self.ground_map = {}
        for (rel_x, rel_y, ground_id, action_id, rotation) in db(
            "SELECT x, y, ground_id, action_id, rotation FROM ground"
        ):  # Load grounds
            if not preview:  # actual game, need actual tiles
                ground = Entities.grounds[ground_id](self.session, self.origin.x + rel_x, self.origin.y + rel_y)
                ground.act(action_id, rotation)
            else:
                ground = Point(self.origin.x + rel_x, self.origin.y + rel_y)
                ground.classes = tuple()
                ground.settlement = None
                # These are important for pathfinding and building to check if the ground tile
                # is blocked in any way.
            self.ground_map[(ground.x, ground.y)] = ground

        self._init_cache()

        self.settlements = []
        self.wild_animals = []
        self.num_trees = 0

        # define the rectangle with the smallest area that contains every island tile its position
        min_x = min(zip(*self.ground_map.keys())[0])
        max_x = max(zip(*self.ground_map.keys())[0])
        min_y = min(zip(*self.ground_map.keys())[1])
        max_y = max(zip(*self.ground_map.keys())[1])
        self.position = Rect.init_from_borders(min_x, min_y, max_x, max_y)

        if not preview:  # this isn't needed for previews, but it is in actual games
            self.path_nodes = IslandPathNodes(self)

            # repopulate wild animals every 2 mins if they die out.
            Scheduler().add_new_object(self.check_wild_animal_population, self, Scheduler().get_ticks(120), -1)

        """TUTORIAL:
コード例 #14
0
	def handle_lost_area(self, coords_list):
		"""Handle losing the potential land in the given coordinates list."""
		# remove planned fields that are now impossible
		field_size = Entities.buildings[BUILDINGS.POTATO_FIELD_CLASS].size
		removed_list = []
		for coords, (purpose, _) in self.plan.iteritems():
			if purpose in [BUILDING_PURPOSE.POTATO_FIELD, BUILDING_PURPOSE.PASTURE, BUILDING_PURPOSE.SUGARCANE_FIELD]:
				rect = Rect.init_from_topleft_and_size_tuples(coords, field_size)
				for field_coords in rect.tuple_iter():
					if field_coords not in self.land_manager.production:
						removed_list.append(coords)
						break

		for coords in removed_list:
			rect = Rect.init_from_topleft_and_size_tuples(coords, field_size)
			for field_coords in rect.tuple_iter():
				self.plan[field_coords] = (BUILDING_PURPOSE.NONE, None)
		self._refresh_unused_fields()
		super(ProductionBuilder, self).handle_lost_area(coords_list)
コード例 #15
0
	def testInsertFull(self):
		tiles = {}
		for coord in self.default_rect.tuple_iter():
			tiles[coord] = _FakeTile(coord[0], coord[1])
			tree = TileQuadTree(Rect.init_from_topleft_and_size(0,0, 5, 5))

		for coord, tile in tiles.iteritems():
			self.assertEqual( tree.get_tile(*coord), None )
			tree.add_tile(tile)
			self.assertEqual( tree.get_tile(*coord), tile )
コード例 #16
0
	def build_tent(self, coords = None):
		"""Build the next tent (or the specified one if coords is not None)."""
		if not self.tent_queue:
			return BUILD_RESULT.IMPOSSIBLE

		# can_trigger_next_section is used to start building the next section when the old one is done
		# if a tent is built just to extend the area then that can't trigger the next section
		# TODO: handle extension tents nicer than just letting them die
		can_trigger_next_section = False
		if coords is None:
			coords = self.tent_queue[0]
			can_trigger_next_section = True

		ok = True
		x, y = coords
		owned_by_other = False
		size = Entities.buildings[BUILDINGS.RESIDENTIAL_CLASS].size
		for dx in xrange(size[0]):
			for dy in xrange(size[1]):
				coords2 = (x + dx, y + dy)
				if coords2 not in self.settlement.ground_map:
					ok = False
					if self.island.ground_map[coords2].settlement is not None:
						owned_by_other = True

		if ok and not owned_by_other:
			builder = self.make_builder(BUILDINGS.RESIDENTIAL_CLASS, x, y, False)
			if not builder.have_resources():
				return BUILD_RESULT.NEED_RESOURCES
			if not builder.execute():
				self.log.debug('%s unable to build a tent at (%d, %d)', self, x, y)
				return BUILD_RESULT.UNKNOWN_ERROR

		if ok or owned_by_other:
			if self.tent_queue[0] == coords:
				self.tent_queue.popleft()
			else:
				for i in xrange(len(self.tent_queue)):
					if self.tent_queue[i] == coords:
						del self.tent_queue[i]
						break
			if owned_by_other:
				self.log.debug('%s tent position owned by other player at (%d, %d)', self, x, y)
				return BUILD_RESULT.IMPOSSIBLE

		if not ok:
			# need to extends the area, it is not owned by another player
			self.log.debug('%s tent position not owned by the player at (%d, %d), extending settlement area instead', self, x, y)
			return self.extend_settlement(Rect.init_from_topleft_and_size(x, y, size[0], size[1]))

		if not self.roads_built:
			self.build_roads()
		if can_trigger_next_section and self.plan[coords][1][0] > self.current_section:
			self.current_section = self.plan[coords][1][0]
		return BUILD_RESULT.OK
コード例 #17
0
ファイル: minimap.py プロジェクト: lmchawla/unknown-horizons
    def update(self, tup):
        """Recalculate and redraw minimap for real world coord tup
		@param tup: (x, y)"""
        if self.world is None or not self.world.inited:
            return  # don't draw while loading
        minimap_point = self._get_rotated_coords(self._world_coord_to_minimap_coord(tup))
        world_to_minimap = self._get_world_to_minimap_ratio()
        rect = Rect.init_from_topleft_and_size(
            minimap_point[0], minimap_point[1], int(round(1 / world_to_minimap[0])), int(round(1 / world_to_minimap[1]))
        )
        self._recalculate(rect)
コード例 #18
0
    def check_build(cls,
                    session,
                    point,
                    rotation=45,
                    check_settlement=True,
                    ship=None,
                    issuer=None):
        # for non-quadratic buildings, we have to switch width and height depending on the rotation
        if rotation == 45 or rotation == 225:
            position = Rect.init_from_topleft_and_size(point.x, point.y,
                                                       cls.size[0] - 1,
                                                       cls.size[1] - 1)
        else:
            position = Rect.init_from_topleft_and_size(point.x, point.y,
                                                       cls.size[1] - 1,
                                                       cls.size[0] - 1)

        buildable = True
        tearset = []
        return _BuildPosition(position, rotation, tearset, buildable)
コード例 #19
0
	def testRadiusCoordsSpeed(self):
		tree = TileQuadTree(Rect.init_from_topleft_and_size(0, 0, 300, 300) )

		print 'testing speed (may take a while)'
		for x in xrange(0,300):
			if x % 20 == 0: print int((float(x)/300)*100)
			for y in xrange(0,300):
				tree.add_tile(_FakeTile(x, y) )

		center = Rect.init_from_topleft_and_size(144,145,10,10)

		import cProfile as profile
		import tempfile
		#outfilename = tempfile.mkstemp(text = True)[1]
		#print 'profile to ', outfilename
		#profile.runctx( "for i in tree.get_radius_tiles(center, 100): a_app(i)" , globals(), locals(), outfilename)
		def cb(x): pass
		outfilename = tempfile.mkstemp(text = True)[1]
		print 'profile to ', outfilename
		profile.runctx( "tree.visit_radius_tiles(center, 120, cb)" , globals(), locals(), outfilename)
コード例 #20
0
    def update(self, tup):
        """Recalculate and redraw minimap for real world coord tup
		@param tup: (x, y)"""
        if self.world is None or not self.world.inited:
            return  # don't draw while loading
        minimap_point = self._get_rotated_coords(
            self._world_coord_to_minimap_coord(tup))
        world_to_minimap = self._get_world_to_minimap_ratio()
        rect = Rect.init_from_topleft_and_size(minimap_point[0], minimap_point[1], \
                                               int(round(1/world_to_minimap[0])), \
                                               int(round(1/world_to_minimap[1])))
        self._recalculate(rect)
コード例 #21
0
	def load_raw_map(self, savegame_db, preview=False):
		# load islands
		self.islands = []
		for (islandid,) in savegame_db("SELECT rowid + 1000 FROM island"):
			island = Island(savegame_db, islandid, self.session, preview=preview)
			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 = {}

		# big sea water tile class
		if not preview:
			default_grounds = Entities.grounds[int(self.properties.get('default_ground', GROUND.WATER[0]))]

		# extra world size that is added so that the player can't see the "black void"
		border = 30
		fake_tile_class = Entities.grounds[-1]
		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):
				if not preview:
					# we don't need no references, we don't need no mem control
					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)] = fake_tile_class(self.session, x, y)

		# 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
コード例 #22
0
	def testInsert(self):
		tiles = {}
		tiles[(2,2)] = _FakeTile(2, 2)
		tiles[(2,3)] = _FakeTile(2, 3)
		tiles[(3,2)] = _FakeTile(3, 2)
		tiles[(3,3)] = _FakeTile(3, 3)
		tiles[(0,0)] = _FakeTile(0, 0)
		tree = TileQuadTree(Rect.init_from_topleft_and_size(0,0, 5, 5))

		for coord, tile in tiles.iteritems():
			self.assertEqual( tree.get_tile(*coord), None )
			tree.add_tile(tile)
			self.assertEqual( tree.get_tile(*coord), tile )
コード例 #23
0
	def __init_outline(cls):
		"""Save a template outline that surrounds a lumberjack."""
		position = Rect.init_from_topleft_and_size_tuples((0, 0), Entities.buildings[BUILDINGS.LUMBERJACK_CLASS].size)
		moves = [(-1, 0), (0, -1), (0, 1), (1, 0)]
		coords_list = set(position.get_radius_coordinates(Entities.buildings[BUILDINGS.LUMBERJACK_CLASS].radius, True))

		result = set()
		for x, y in coords_list:
			for dx, dy in moves:
				coords = (x + dx, y + dy)
				if coords not in coords_list:
					result.add(coords)
		cls.__template_outline = list(result)
コード例 #24
0
    def check_build(cls,
                    session,
                    point,
                    rotation=45,
                    check_settlement=True,
                    ship=None,
                    issuer=None):
        """Check if a building is buildable here.
		All tiles, that the building occupies are checked.
		@param point: Point instance, coords
		@param rotation: prefered rotation of building
		@param check_settlement: whether to check for a settlement (for settlementless buildings)
		@param ship: ship instance if building from ship
		@return instance of _BuildPosition"""
        # for non-quadratic buildings, we have to switch width and height depending on the rotation
        if rotation == 45 or rotation == 225:
            position = Rect.init_from_topleft_and_size(point.x, point.y,
                                                       cls.size[0] - 1,
                                                       cls.size[1] - 1)
        else:
            position = Rect.init_from_topleft_and_size(point.x, point.y,
                                                       cls.size[1] - 1,
                                                       cls.size[0] - 1)

        buildable = True
        tearset = []
        try:
            cls._check_island(session, position)
            # TODO: if the rotation changes here for non-quadratic buildings, wrong results will be returned
            rotation = cls._check_rotation(session, position, rotation)
            tearset = cls._check_buildings(session, position)
            if check_settlement:
                cls._check_settlement(session,
                                      position,
                                      ship=ship,
                                      issuer=issuer)
        except _NotBuildableError:
            buildable = False
        return _BuildPosition(position, rotation, tearset, buildable)
コード例 #25
0
    def __init(self, deposit_class, mine_empty_msg_shown):
        self.__deposit_class = deposit_class
        self._mine_empty_msg_shown = mine_empty_msg_shown

        # setup loading area
        # TODO: for now we assume that a mine building is 5x5 with a 3x1 entry on 1 side
        #       this needs to be generalised, possibly by defining the loading tiles in the db
        pos = self.position
        if self.rotation == 45:
            self.loading_area = Rect.init_from_topleft_and_size(
                pos.origin.x, pos.origin.y + 1, 0, 2)
        elif self.rotation == 135:
            self.loading_area = Rect.init_from_topleft_and_size(
                pos.origin.x + 1, pos.origin.y + pos.height - 1, 2, 0)
        elif self.rotation == 225:
            self.loading_area = Rect.init_from_topleft_and_size(
                pos.origin.x + pos.width - 1, pos.origin.y + 1, 0, 2)
        elif self.rotation == 315:
            self.loading_area = Rect.init_from_topleft_and_size(
                pos.origin.x + 1, pos.origin.y, 2, 0)
        else:
            assert False
コード例 #26
0
    def check_build_line(cls, session, point1, point2, rotation=45, ship=None):
        possible_builds = []
        area = Rect.init_from_corners(point1, point2)
        # correct placement for large buildings (mouse should be at center of building)
        area.left -= (cls.size[0] - 1) / 2
        area.right -= (cls.size[0] - 1) / 2
        area.top -= (cls.size[1] - 1) / 2
        area.bottom -= (cls.size[1] - 1) / 2

        for x in xrange(area.left, area.right + 1, cls.size[0]):
            for y in xrange(area.top, area.bottom + 1, cls.size[1]):
                possible_builds.append(cls.check_build(session, Point(x, y), rotation=rotation, ship=ship))
        return possible_builds
コード例 #27
0
    def check_build_line(cls, session, point1, point2, rotation=45, ship=None):
        possible_builds = []
        area = Rect.init_from_corners(point1, point2)
        # correct placement for large buildings (mouse should be at center of building)
        area.left -= (cls.size[0] - 1) / 2
        area.right -= (cls.size[0] - 1) / 2
        area.top -= (cls.size[1] - 1) / 2
        area.bottom -= (cls.size[1] - 1) / 2

        for x in xrange(area.left, area.right + 1, cls.size[0]):
            for y in xrange(area.top, area.bottom + 1, cls.size[1]):
                possible_builds.append( \
                  cls.check_build(session, Point(x, y), rotation=rotation, ship=ship) \
                )
        return possible_builds
コード例 #28
0
ファイル: minimap.py プロジェクト: volpino/unknown-horizons
	def _update(self, tup):
		"""Recalculate and redraw minimap for real world coord tup
		@param tup: (x, y)"""
		if self.world is None or not self.world.inited:
			return # don't draw while loading
		minimap_point = self._world_to_minimap( tup, self._get_rotation_setting() )
		world_to_minimap = self._world_to_minimap_ratio
		# TODO: remove this remnant of the old implementation, perhaps by refactoring recalculate()
		minimap_point = (
		  minimap_point[0] + self.location.left,
		  minimap_point[1] + self.location.top,
		)
		rect = Rect.init_from_topleft_and_size(minimap_point[0], minimap_point[1], \
								                           int(round(1/world_to_minimap[0])) + 1, \
								                           int(round(1/world_to_minimap[1])) + 1)
		self._recalculate(rect)
コード例 #29
0
	def _get_possible_building_positions(self, section_coords_set, size):
		"""Return {(x, y): Rect, ...} that contains every size x size potential building location where only the provided coordinates are legal."""
		result = {}
		for (x, y) in sorted(section_coords_set):
			ok = True
			for dx in xrange(size[0]):
				for dy in xrange(size[1]):
					coords = (x + dx, y + dy)
					if coords not in section_coords_set or not self.land_manager.coords_usable(coords):
						ok = False
						break
				if not ok:
					break
			if ok:
				result[(x, y)] = Rect.init_from_topleft_and_size_tuples((x, y), size)
		return result
コード例 #30
0
	def get_job(self):
		jobs = JobList(self, JobList.order_by.random)
		collectable_resources = self.get_needed_resources()

		# iterate over all possible providers and needed resources
		# and save possible job targets
		position_rect = Rect.init_from_topleft_and_size(self.position.x, self.position.y, 0, 0)
		reach = RadiusRect(position_rect, self.walking_range)
		for provider in self.home_island.get_providers_in_range(reach):
			if self.check_possible_job_target(provider):
				for res in collectable_resources:
					job = self.check_possible_job_target_for(provider, res)
					if job is not None:
						jobs.append(job)

		return self.get_best_possible_job(jobs)
コード例 #31
0
ファイル: minimap.py プロジェクト: lmchawla/unknown-horizons
 def _timed_update(self):
     """Regular updates for domains we can't or don't want to keep track of."""
     # update ship dots
     self.renderer.removeAll("minimap_ship")
     for ship in self.world.ship_map.itervalues():
         coord = self._world_coord_to_minimap_coord(ship().position.to_tuple())
         color = ship().owner.color.to_tuple()
         area_to_color = Rect.init_from_topleft_and_size(coord[0], coord[1], 2, 2)
         for tup in area_to_color.tuple_iter():
             try:
                 self.renderer.addPoint("minimap_ship", self.renderernodes[self._get_rotated_coords(tup)], *color)
             except KeyError:
                 # this happens in rare cases, when the ship is at the border of the map,
                 # and since we color an area, that's bigger than a point, it can exceed the
                 # minimap's dimensions.
                 pass
コード例 #32
0
ファイル: shapes.py プロジェクト: carnivoro/unknown-horizons
	def testRect(self):
		r1 = Rect(Point(0,0), 1, 1)
		r2 = Rect(0, 0, 1 ,1)
		r3 = Rect(Point(2, 2), 1, 1)
		self.assertEqual(r1, r2)
		self.assertTrue(r1 == r2)
		self.assertFalse(r1.contains(Point(-1,-1)))
		self.assertTrue(r2.contains(Point(0,0)))
		self.assertTrue(r2.contains(Point(1,1)))
		self.assertTrue(r1.intersects(r2))
		self.assertFalse(r1.intersects(r3))
コード例 #33
0
    def get_job(self):
        jobs = JobList(self, JobList.order_by.random)
        collectable_resources = self.get_needed_resources()

        # iterate over all possible providers and needed resources
        # and save possible job targets
        position_rect = Rect.init_from_topleft_and_size(
            self.position.x, self.position.y, 0, 0)
        reach = RadiusRect(position_rect, self.walking_range)
        for provider in self.home_island.get_providers_in_range(reach):
            if self.check_possible_job_target(provider):
                for res in collectable_resources:
                    job = self.check_possible_job_target_for(provider, res)
                    if job is not None:
                        jobs.append(job)

        return self.get_best_possible_job(jobs)
コード例 #34
0
	def _get_road_to_builder(self, builder):
		"""Return a path from the builder to a building with general collectors (None if impossible)."""
		loading_area = builder.get_loading_area()
		collector_coords = set()
		for building in self.collector_buildings:
			if loading_area.distance(building.position) == 1:
				return []
			if loading_area.distance(building.position) > building.radius:
				continue # the collector building is too far to be useful
			for coords in self.iter_possible_road_coords(building.position, building.position):
				collector_coords.add(coords)

		blocked_coords = set([coords for coords in builder.position.tuple_iter()])
		destination_coords = set(self.iter_possible_road_coords(loading_area, builder.position))
		beacon = Rect.init_from_borders(loading_area.left - 1, loading_area.top - 1, loading_area.right + 1, loading_area.bottom + 1)

		return RoadPlanner()(self.owner.personality_manager.get('RoadPlanner'), collector_coords, \
			destination_coords, beacon, self.get_path_nodes(), blocked_coords = blocked_coords)
コード例 #35
0
    def _handle_farm_removal(self, building):
        """Handle farm removal by removing planned fields and tearing existing ones that can't be serviced by another farm."""
        unused_fields = set()
        farms = self.settlement.get_buildings_by_id(BUILDINGS.FARM_CLASS)
        for coords in building.position.get_radius_coordinates(building.radius):
            if not coords in self.plan:
                continue
            object = self.island.ground_map[coords].object
            if object is None or object.id not in self.field_building_classes:
                continue

            used_by_another_farm = False
            for farm in farms:
                if farm.worldid != building.worldid and object.position.distance(farm.position) <= farm.radius:
                    used_by_another_farm = True
                    break
            if not used_by_another_farm:
                unused_fields.add(object)

                # tear the finished but no longer used fields down
        for unused_field in unused_fields:
            for x, y in unused_field.position.tuple_iter():
                self.register_change(x, y, BUILDING_PURPOSE.NONE, None)
            Tear(unused_field).execute(self.session)

            # remove the planned but never built fields from the plan
        self._refresh_unused_fields()
        for unused_fields_list in self.unused_fields.itervalues():
            for coords in unused_fields_list:
                position = Rect.init_from_topleft_and_size_tuples(
                    coords, Entities.buildings[BUILDINGS.POTATO_FIELD_CLASS].size
                )
                if building.position.distance(position) > building.radius:
                    continue  # it never belonged to the removed building

                used_by_another_farm = False
                for farm in farms:
                    if farm.worldid != building.worldid and position.distance(farm.position) <= farm.radius:
                        used_by_another_farm = True
                        break
                if not used_by_another_farm:
                    for x, y in position.tuple_iter():
                        self.register_change(x, y, BUILDING_PURPOSE.NONE, None)
        self._refresh_unused_fields()
コード例 #36
0
	def _build_extra_road_connection(self, building, collector_building):
		collector_coords = set(coords for coords in self.production_builder.iter_possible_road_coords(collector_building.position, collector_building.position))
		destination_coords = set(coords for coords in self.production_builder.iter_possible_road_coords(building.loading_area, building.position))
		pos = building.loading_area
		beacon = Rect.init_from_borders(pos.left - 1, pos.top - 1, pos.right + 1, pos.bottom + 1)

		path = RoadPlanner()(self.owner.personality_manager.get('RoadPlanner'), collector_coords, \
			destination_coords, beacon, self.production_builder.get_path_nodes())
		if path is None:
			return BUILD_RESULT.IMPOSSIBLE

		cost = self.production_builder.get_road_cost(path)
		for resource_id, amount in cost.iteritems():
			if resource_id == RES.GOLD_ID:
				if self.owner.inventory[resource_id] < amount:
					return BUILD_RESULT.NEED_RESOURCES
			elif self.settlement.inventory[resource_id] < amount:
				return BUILD_RESULT.NEED_RESOURCES
		return BUILD_RESULT.OK if self.production_builder.build_road(path) else BUILD_RESULT.UNKNOWN_ERROR
コード例 #37
0
 def _timed_update(self):
     """Regular updates for domains we can't or don't want to keep track of."""
     # update ship dots
     self.renderer.removeAll("minimap_ship")
     for ship in self.world.ship_map.itervalues():
         coord = self._world_coord_to_minimap_coord(
             ship().position.to_tuple())
         color = ship().owner.color.to_tuple()
         area_to_color = Rect.init_from_topleft_and_size(
             coord[0], coord[1], 2, 2)
         for tup in area_to_color.tuple_iter():
             try:
                 self.renderer.addPoint(
                     "minimap_ship",
                     self.renderernodes[self._get_rotated_coords(tup)],
                     *color)
             except KeyError:
                 # this happens in rare cases, when the ship is at the border of the map,
                 # and since we color an area, that's bigger than a point, it can exceed the
                 # minimap's dimensions.
                 pass
コード例 #38
0
	def __init(self, origin, filename):
		"""
		Load the actual island from a file
		@param origin: Point
		@param filename: String, filename of island db or random map id
		"""
		self.file = filename
		self.origin = origin

		# check if filename is a random map
		if random_map.is_random_island_id_string(filename):
			# it's a random map id, create this map and load it
			db = random_map.create_random_island(filename)
		else:
			db = DbReader(filename) # Create a new DbReader instance to load the maps file.

		p_x, p_y, width, height = db("select (min(x) + ?), (min(y) + ?), (1 + max(x) - min(x)), (1 + max(y) - min(y)) from ground", self.origin.x, self.origin.y)[0]

		# rect for quick checking if a tile isn't on this island
		# NOTE: it contains tiles, that are not on the island!
		self.rect = Rect(Point(p_x, p_y), width, height)

		self.ground_map = {}
		for (rel_x, rel_y, ground_id) in db("select x, y, ground_id from ground"): # Load grounds
			ground = Entities.grounds[ground_id](self.session, self.origin.x + rel_x, self.origin.y + rel_y)
			# These are important for pathfinding and building to check if the ground tile
			# is blocked in any way.
			self.ground_map[(ground.x, ground.y)] = ground

		self.settlements = []
		self.buildings = []
		self.provider_buildings = ProviderHandler()
		self.wild_animals = []

		self.path_nodes = IslandPathNodes(self)

		# repopulate wild animals every 2 mins if they die out.
		Scheduler().add_new_object(self.check_wild_animal_population, self, Scheduler().get_ticks(120), -1)

		"""TUTORIAL:
コード例 #39
0
ファイル: utils.py プロジェクト: aviler/unknown-horizons
def create_map():
	"""
	Create a map with a square island (20x20) at position (20, 20) and return the path
	to the database file.
	"""

	# Create island.
	fd, islandfile = tempfile.mkstemp()
	os.close(fd)

	db = DbReader(islandfile)
	db("CREATE TABLE ground(x INTEGER NOT NULL, y INTEGER NOT NULL, ground_id INTEGER NOT NULL, action_id TEXT NOT NULL, rotation INTEGER NOT NULL)")
	db("CREATE TABLE island_properties(name TEXT PRIMARY KEY NOT NULL, value TEXT NOT NULL)")

	db("BEGIN TRANSACTION")
	tiles = []
	for x, y in Rect.init_from_topleft_and_size(0, 0, 20, 20).tuple_iter():
		if (0 < x < 20) and (0 < y < 20):
			ground = GROUND.DEFAULT_LAND
		else:
			# Add coastline at the borders.
			ground = GROUND.SHALLOW_WATER
		tiles.append([x, y] + list(ground))
	db.execute_many("INSERT INTO ground VALUES(?, ?, ?, ?, ?)", tiles)
	db("COMMIT")

	# Create savegame with the island above.
	fd, savegame = tempfile.mkstemp()
	os.close(fd)

	db = DbReader(savegame)
	read_savegame_template(db)
	db("BEGIN TRANSACTION")
	db("INSERT INTO island (x, y, file) VALUES(?, ?, ?)", 20, 20, islandfile)
	db("COMMIT")

	return savegame
コード例 #40
0
	def extend_settlement_with_tent(self, position):
		"""Build a tent to extend the settlement towards the given position. Return a BUILD_RESULT constant."""
		size = Entities.buildings[BUILDINGS.RESIDENTIAL].size
		min_distance = None
		best_coords = None

		for (x, y) in self.settlement_manager.village_builder.tent_queue:
			ok = True
			for dx in xrange(size[0]):
				for dy in xrange(size[1]):
					if (x + dx, y + dy) not in self.settlement.ground_map:
						ok = False
						break
			if not ok:
				continue

			distance = Rect.init_from_topleft_and_size(x, y, size[0], size[1]).distance(position)
			if min_distance is None or distance < min_distance:
				min_distance = distance
				best_coords = (x, y)

		if min_distance is None:
			return BUILD_RESULT.IMPOSSIBLE
		return self.settlement_manager.village_builder.build_tent(best_coords)
コード例 #41
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"):
            player = None
            # check if player is an ai
            ai_data = self.session.db(
                "SELECT class_package, class_name FROM ai WHERE 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]

        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 = None, None, None, None
        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

        # "unfill" parts that are occupied by island
        # TODO: check if constructing a list of water coords is faster than calling the Ground() so many times
        for island in self.islands:
            for coord in island.ground_map:
                if coord in self.ground_map:
                    del self.ground_map[coord]

        # 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)

        self.water = list(self.ground_map)

        # 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 = 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.append(coord)

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

        # create shiplist, which is currently used for saving ships
        # and having at least one reference to them
        self.ships = []

        if self.session.is_game_loaded():
            # for now, we have one trader in every game, so this is safe:
            trader_id = savegame_db(
                "SELECT rowid FROM player WHERE is_trader = 1")[0][0]
            self.trader = Trader.load(self.session, savegame_db, trader_id)

        # 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.
            self.trader.load_ship_states(savegame_db)

        self.inited = True
        """TUTORIAL:
コード例 #42
0
def generate_map(seed=None):
    """Generates a whole map.
	@param seed: argument passed to random.seed
	@return filename to the sqlite db containing the new map"""
    rand = random.Random(seed)

    filename = tempfile.mkstemp()[1]
    shutil.copyfile(PATHS.SAVEGAME_TEMPLATE, filename)

    db = DbReader(filename)

    island_space = (35, 35)
    island_min_size = (25, 25)
    island_max_size = (28, 28)

    method = rand.randint(0, 1)  # choose map creation method

    if method == 0:
        # generate up to 9 islands
        number_of_islands = 0
        for i in Rect.init_from_topleft_and_size(0, 0, 2, 2):
            if rand.randint(0, 2) != 0:  # 2/3 chance for an island here
                number_of_islands = number_of_islands + 1
                x = int(i.x * island_space[0] * (rand.random() / 6 + 0.90))
                y = int(i.y * island_space[1] * (rand.random() / 6 + 0.90))
                island_seed = rand.randint(-sys.maxint, sys.maxint)
                island_params = {'creation_method': 0, 'seed': island_seed, \
                     'width': rand.randint(island_min_size[0], island_max_size[0]), \
                     'height': rand.randint(island_min_size[1], island_max_size[1])}

                island_string = string.Template(
                    _random_island_id_template).safe_substitute(island_params)

                db("INSERT INTO island (x, y, file) VALUES(?, ?, ?)", x, y,
                   island_string)

        # if there is 1 or 0 islands created, it places 1 large island in the centre
        if number_of_islands == 0:
            x = 20
            y = 20
            island_seed = rand.randint(-sys.maxint, sys.maxint)
            island_params = {'creation_method': 1, 'seed': island_seed, \
                 'width': rand.randint(island_min_size[0] * 2, island_max_size[0] * 2), \
                 'height': rand.randint(island_min_size[1] * 2, island_max_size[1] * 2)}
            island_string = string.Template(
                _random_island_id_template).safe_substitute(island_params)

            db("INSERT INTO island (x, y, file) VALUES(?, ?, ?)", x, y,
               island_string)

        elif number_of_islands == 1:
            db("DELETE FROM island")

            x = 20
            y = 20
            island_seed = rand.randint(-sys.maxint, sys.maxint)
            island_params = {'creation_method': 1, 'seed': island_seed, \
                 'width': rand.randint(island_min_size[0] * 2, island_max_size[0] * 2), \
                 'height': rand.randint(island_min_size[1] * 2, island_max_size[1] * 2)}

            island_string = string.Template(
                _random_island_id_template).safe_substitute(island_params)

            db("INSERT INTO island (x, y, file) VALUES(?, ?, ?)", x, y,
               island_string)

    elif method == 1:
        # places 1 large island in the centre
        x = 20
        y = 20
        island_seed = rand.randint(-sys.maxint, sys.maxint)
        island_params = {'creation_method': 1, 'seed': island_seed, \
             'width': rand.randint(island_min_size[0] * 2, island_max_size[0] * 2), \
             'height': rand.randint(island_min_size[1] * 2, island_max_size[1] * 2)}
        island_string = string.Template(
            _random_island_id_template).safe_substitute(island_params)

        db("INSERT INTO island (x, y, file) VALUES(?, ?, ?)", x, y,
           island_string)

    return filename
コード例 #43
0
def create_random_island(id_string):
    """Creates a random island as sqlite db.
	It is rather primitive; it places shapes on the dict.
	@param id_string: random island id string
	@return: sqlite db reader containing island
	"""
    # NOTE: the tilesystem will be redone soon, so constants indicating grounds are temporary
    # here and will have to be changed anyways.
    match_obj = re.match(_random_island_id_regexp, id_string)
    assert match_obj
    creation_method, width, height, seed = [
        long(i) for i in match_obj.groups()
    ]

    rand = random.Random(seed)

    map_dict = {}

    # creation_method 0 - standard small island for the 3x3 grid
    # creation_method 1 - large island

    # place this number of shapes
    for i in xrange(int(float(width + height) / 2 * 1.5)):
        x = rand.randint(4, width - 4)
        y = rand.randint(4, height - 4)

        # place shape determined by shape_id on (x, y)
        if creation_method == 0:
            shape_id = rand.randint(3, 5)
        elif creation_method == 1:
            shape_id = rand.randint(5, 8)

        if rand.randint(1, 4) == 1:
            # use a rect
            if creation_method == 0:
                for shape_coord in Rect.init_from_topleft_and_size(
                        x - 3, y - 3, 5, 5).tuple_iter():
                    map_dict[shape_coord] = 1
            elif creation_method == 1:
                for shape_coord in Rect.init_from_topleft_and_size(
                        x - 5, y - 5, 8, 8).tuple_iter():
                    map_dict[shape_coord] = 1

        else:
            # use a circle, where radius is determined by shape_id
            for shape_coord in Circle(Point(x, y), shape_id).tuple_iter():
                map_dict[shape_coord] = 1

    # write values to db
    map_db = DbReader(":memory:")
    map_db(
        "CREATE TABLE ground(x INTEGER NOT NULL, y INTEGER NOT NULL, ground_id INTEGER NOT NULL)"
    )
    map_db(
        "CREATE TABLE island_properties(name TEXT PRIMARY KEY NOT NULL, value TEXT NOT NULL)"
    )
    map_db("BEGIN TRANSACTION")

    # assign these characters, if a coastline is found in this offset
    offset_coastline = {'a': (0, -1), 'b': (1, 0), 'c': (0, 1), 'd': (-1, 0)}

    for x, y in map_dict.iterkeys():
        # add a coastline tile for coastline, or default land else
        coastline = ""
        for offset_char in sorted(offset_coastline):
            if (x + offset_coastline[offset_char][0],
                    y + offset_coastline[offset_char][1]) not in map_dict:
                coastline += offset_char

        if coastline:
            # TODO: use coastline tile depending on coastline
            map_db("INSERT INTO ground VALUES(?, ?, ?)", x, y, 49)
        else:
            map_db("INSERT INTO ground VALUES(?, ?, ?)", x, y,
                   GROUND.DEFAULT_LAND)
    map_db("COMMIT")
    return map_db
コード例 #44
0
def create_random_island(id_string):
    """Creates a random island as sqlite db.
	It is rather primitive; it places shapes on the dict.
	@param id_string: random island id string
	@return: sqlite db reader containing island
	"""
    # NOTE: the tilesystem will be redone soon, so constants indicating grounds are temporary
    # here and will have to be changed anyways.
    match_obj = re.match(_random_island_id_regexp, id_string)
    assert match_obj
    creation_method, width, height, seed = [
        long(i) for i in match_obj.groups()
    ]

    rand = random.Random(seed)

    map_dict = {}

    # creation_method 0 - standard small island for the 3x3 grid
    # creation_method 1 - large island

    # place this number of shapes
    for i in xrange(int(float(width + height) / 2 * 1.5)):
        x = rand.randint(8, width - 8)
        y = rand.randint(8, height - 8)

        # place shape determined by shape_id on (x, y)
        if creation_method == 0:
            shape_id = rand.randint(3, 5)
        elif creation_method == 1:
            shape_id = rand.randint(5, 8)

        if rand.randint(1, 4) == 1:
            # use a rect
            if creation_method == 0:
                for shape_coord in Rect.init_from_topleft_and_size(
                        x - 3, y - 3, 5, 5).tuple_iter():
                    map_dict[shape_coord] = True
            elif creation_method == 1:
                for shape_coord in Rect.init_from_topleft_and_size(
                        x - 5, y - 5, 8, 8).tuple_iter():
                    map_dict[shape_coord] = True

        else:
            # use a circle, where radius is determined by shape_id
            for shape_coord in Circle(Point(x, y), shape_id).tuple_iter():
                map_dict[shape_coord] = True

    # write values to db
    map_db = DbReader(":memory:")
    map_db(
        "CREATE TABLE ground(x INTEGER NOT NULL, y INTEGER NOT NULL, ground_id INTEGER NOT NULL)"
    )
    map_db(
        "CREATE TABLE island_properties(name TEXT PRIMARY KEY NOT NULL, value TEXT NOT NULL)"
    )
    map_db("BEGIN TRANSACTION")

    # add grass tiles
    for x, y in map_dict.iterkeys():
        map_db("INSERT INTO ground VALUES(?, ?, ?)", x, y, GROUND.DEFAULT_LAND)

    def fill_tiny_spaces(tile):
        """Fills 1 tile gulfs and straits with the specified tile
		@param tile: ground tile to fill with
		"""

        neighbours = [(-1, 0), (0, -1), (0, 1), (1, 0)]
        corners = [(-1, -1), (-1, 1)]
        knight_moves = [(-2, -1), (-2, 1), (-1, -2), (-1, 2), (1, -2), (1, 2),
                        (2, -1), (2, 1)]
        bad_configs = set([
            0, 1 << 0, 1 << 1, 1 << 2, 1 << 3, (1 << 0) | (1 << 3),
            (1 << 1) | (1 << 2)
        ])

        while True:
            to_fill = {}
            for x, y in map_dict.iterkeys():
                for x_offset, y_offset in neighbours:
                    x2 = x + x_offset
                    y2 = y + y_offset
                    if (x2, y2) in map_dict:
                        continue
                    # (x2, y2) is now a point just off the island

                    neighbours_dirs = 0
                    for i in range(len(neighbours)):
                        x3 = x2 + neighbours[i][0]
                        y3 = y2 + neighbours[i][1]
                        if (x3, y3) not in map_dict:
                            neighbours_dirs |= (1 << i)
                    if neighbours_dirs in bad_configs:
                        # part of a straight 1 tile gulf
                        to_fill[(x2, y2)] = True
                    else:
                        for x_offset, y_offset in corners:
                            x3 = x2 + x_offset
                            y3 = y2 + y_offset
                            x4 = x2 - x_offset
                            y4 = y2 - y_offset
                            if (x3, y3) in map_dict and (x4, y4) in map_dict:
                                # part of a diagonal 1 tile gulf
                                to_fill[(x2, y2)] = True
                                break

                # block 1 tile straits
                for x_offset, y_offset in knight_moves:
                    x2 = x + x_offset
                    y2 = y + y_offset
                    if (x2, y2) not in map_dict:
                        continue
                    if abs(x_offset) == 1:
                        y2 = y + y_offset / 2
                        if (x2, y2) in map_dict or (x, y2) in map_dict:
                            continue
                    else:
                        x2 = x + x_offset / 2
                        if (x2, y2) in map_dict or (x2, y) in map_dict:
                            continue
                    to_fill[(x2, y2)] = True

            if to_fill:
                for x, y in to_fill.iterkeys():
                    map_dict[(x, y)] = tile
                    map_db("INSERT INTO ground VALUES(?, ?, ?)", x, y, tile)
            else:
                break

    # possible movement directions
    all_moves = {
        'sw': (-1, -1),
        'w': (-1, 0),
        'nw': (-1, 1),
        's': (0, -1),
        'n': (0, 1),
        'se': (1, -1),
        'e': (1, 0),
        'ne': (1, 1)
    }

    def get_island_outline():
        """
		@return: the points just off the island as a dict
		"""
        result = {}
        for x, y in map_dict.iterkeys():
            for offset_x, offset_y in all_moves.itervalues():
                coords = (x + offset_x, y + offset_y)
                if coords not in map_dict:
                    result[coords] = True
        return result

    # add grass to sand tiles
    fill_tiny_spaces(GROUND.DEFAULT_LAND)
    outline = get_island_outline()
    for x, y in outline.iterkeys():
        filled = []
        for dir in sorted(all_moves):
            coords = (x + all_moves[dir][1], y + all_moves[dir][0])
            if coords in map_dict:
                filled.append(dir)

        tile = None
        # straight coast or 1 tile U-shaped gulfs
        if filled == ['s', 'se', 'sw'] or filled == ['s']:
            tile = GROUND.SAND_NORTH
        elif filled == ['e', 'ne', 'se'] or filled == ['e']:
            tile = GROUND.SAND_WEST
        elif filled == ['n', 'ne', 'nw'] or filled == ['n']:
            tile = GROUND.SAND_SOUTH
        elif filled == ['nw', 'sw', 'w'] or filled == ['w']:
            tile = GROUND.SAND_EAST
        # slight turn (looks best with straight coast)
        elif filled == ['e', 'se'] or filled == ['e', 'ne']:
            tile = GROUND.SAND_WEST
        elif filled == ['n', 'ne'] or filled == ['n', 'nw']:
            tile = GROUND.SAND_SOUTH
        elif filled == ['nw', 'w'] or filled == ['sw', 'w']:
            tile = GROUND.SAND_EAST
        elif filled == ['s', 'sw'] or filled == ['s', 'se']:
            tile = GROUND.SAND_NORTH
        # sandy corner
        elif filled == ['se']:
            tile = GROUND.SAND_NORTHWEST1
        elif filled == ['ne']:
            tile = GROUND.SAND_SOUTHWEST1
        elif filled == ['nw']:
            tile = GROUND.SAND_SOUTHEAST1
        elif filled == ['sw']:
            tile = GROUND.SAND_NORTHEAST1
        # grassy corner
        elif 3 <= len(filled) <= 5:
            coast_set = set(filled)
            if 'e' in coast_set and 'se' in coast_set and 's' in coast_set:
                tile = GROUND.SAND_NORTHEAST3
            elif 's' in coast_set and 'sw' in coast_set and 'w' in coast_set:
                tile = GROUND.SAND_NORTHWEST3
            elif 'w' in coast_set and 'nw' in coast_set and 'n' in coast_set:
                tile = GROUND.SAND_SOUTHWEST3
            elif 'n' in coast_set and 'ne' in coast_set and 'e' in coast_set:
                tile = GROUND.SAND_SOUTHEAST3

        assert tile
        map_db("INSERT INTO ground VALUES(?, ?, ?)", x, y, tile)

    for coords, type in outline.iteritems():
        map_dict[coords] = type

    # add sand to shallow water tiles
    fill_tiny_spaces(GROUND.SAND)
    outline = get_island_outline()
    for x, y in outline.iterkeys():
        filled = []
        for dir in sorted(all_moves):
            coords = (x + all_moves[dir][1], y + all_moves[dir][0])
            if coords in map_dict:
                filled.append(dir)

        tile = None
        # straight coast or 1 tile U-shaped gulfs
        if filled == ['s', 'se', 'sw'] or filled == ['s']:
            tile = GROUND.COAST_NORTH
        elif filled == ['e', 'ne', 'se'] or filled == ['e']:
            tile = GROUND.COAST_WEST
        elif filled == ['n', 'ne', 'nw'] or filled == ['n']:
            tile = GROUND.COAST_SOUTH
        elif filled == ['nw', 'sw', 'w'] or filled == ['w']:
            tile = GROUND.COAST_EAST
        # slight turn (looks best with straight coast)
        elif filled == ['e', 'se'] or filled == ['e', 'ne']:
            tile = GROUND.COAST_WEST
        elif filled == ['n', 'ne'] or filled == ['n', 'nw']:
            tile = GROUND.COAST_SOUTH
        elif filled == ['nw', 'w'] or filled == ['sw', 'w']:
            tile = GROUND.COAST_EAST
        elif filled == ['s', 'sw'] or filled == ['s', 'se']:
            tile = GROUND.COAST_NORTH
        # mostly wet corner
        elif filled == ['se']:
            tile = GROUND.COAST_NORTHWEST1
        elif filled == ['ne']:
            tile = GROUND.COAST_SOUTHWEST1
        elif filled == ['nw']:
            tile = GROUND.COAST_SOUTHEAST1
        elif filled == ['sw']:
            tile = GROUND.COAST_NORTHEAST1
        # mostly dry corner
        elif 3 <= len(filled) <= 5:
            coast_set = set(filled)
            if 'e' in coast_set and 'se' in coast_set and 's' in coast_set:
                tile = GROUND.COAST_NORTHEAST3
            elif 's' in coast_set and 'sw' in coast_set and 'w' in coast_set:
                tile = GROUND.COAST_NORTHWEST3
            elif 'w' in coast_set and 'nw' in coast_set and 'n' in coast_set:
                tile = GROUND.COAST_SOUTHWEST3
            elif 'n' in coast_set and 'ne' in coast_set and 'e' in coast_set:
                tile = GROUND.COAST_SOUTHEAST3

        assert tile
        map_db("INSERT INTO ground VALUES(?, ?, ?)", x, y, tile)

    for coords, type in outline.iteritems():
        map_dict[coords] = type

    # add shallow water to deep water tiles
    fill_tiny_spaces(GROUND.SHALLOW_WATER)
    outline = get_island_outline()
    for x, y in outline.iterkeys():
        filled = []
        for dir in sorted(all_moves):
            coords = (x + all_moves[dir][1], y + all_moves[dir][0])
            if coords in map_dict:
                filled.append(dir)

        tile = None
        # straight coast or 1 tile U-shaped gulfs
        if filled == ['s', 'se', 'sw'] or filled == ['s']:
            tile = GROUND.DEEP_WATER_NORTH
        elif filled == ['e', 'ne', 'se'] or filled == ['e']:
            tile = GROUND.DEEP_WATER_WEST
        elif filled == ['n', 'ne', 'nw'] or filled == ['n']:
            tile = GROUND.DEEP_WATER_SOUTH
        elif filled == ['nw', 'sw', 'w'] or filled == ['w']:
            tile = GROUND.DEEP_WATER_EAST
        # slight turn (looks best with straight coast)
        elif filled == ['e', 'se'] or filled == ['e', 'ne']:
            tile = GROUND.DEEP_WATER_WEST
        elif filled == ['n', 'ne'] or filled == ['n', 'nw']:
            tile = GROUND.DEEP_WATER_SOUTH
        elif filled == ['nw', 'w'] or filled == ['sw', 'w']:
            tile = GROUND.DEEP_WATER_EAST
        elif filled == ['s', 'sw'] or filled == ['s', 'se']:
            tile = GROUND.DEEP_WATER_NORTH
        # mostly deep corner
        elif filled == ['se']:
            tile = GROUND.DEEP_WATER_NORTHWEST1
        elif filled == ['ne']:
            tile = GROUND.DEEP_WATER_SOUTHWEST1
        elif filled == ['nw']:
            tile = GROUND.DEEP_WATER_SOUTHEAST1
        elif filled == ['sw']:
            tile = GROUND.DEEP_WATER_NORTHEAST1
        # mostly shallow corner
        elif 3 <= len(filled) <= 5:
            coast_set = set(filled)
            if 'e' in coast_set and 'se' in coast_set and 's' in coast_set:
                tile = GROUND.DEEP_WATER_NORTHEAST3
            elif 's' in coast_set and 'sw' in coast_set and 'w' in coast_set:
                tile = GROUND.DEEP_WATER_NORTHWEST3
            elif 'w' in coast_set and 'nw' in coast_set and 'n' in coast_set:
                tile = GROUND.DEEP_WATER_SOUTHWEST3
            elif 'n' in coast_set and 'ne' in coast_set and 'e' in coast_set:
                tile = GROUND.DEEP_WATER_SOUTHEAST3

        assert tile
        map_db("INSERT INTO ground VALUES(?, ?, ?)", x, y, tile)

    map_db("COMMIT")
    return map_db
コード例 #45
0
def create_random_island(id_string):
    """Creates a random island as sqlite db.
	It is rather primitive; it places shapes on the dict.
	The coordinates of tiles will be 0 <= x < width and 0 <= y < height
	@param id_string: random island id string
	@return: sqlite db reader containing island
	"""
    # NOTE: the tilesystem will be redone soon, so constants indicating grounds are temporary
    # here and will have to be changed anyways.
    match_obj = re.match(_random_island_id_regexp, id_string)
    assert match_obj
    creation_method, width, height, seed = [
        long(i) for i in match_obj.groups()
    ]

    rand = random.Random(seed)

    map_set = set()

    # creation_method 0 - standard small island for the 3x3 grid
    # creation_method 1 - large island
    # creation_method 2 - a number of randomly sized and placed islands

    # place this number of shapes
    for i in xrange(15 + width * height / 45):
        # place shape determined by shape_id on (x, y)
        add = True
        rect_chance = 6
        if creation_method == 0:
            shape_id = rand.randint(3, 5)
        elif creation_method == 1:
            shape_id = rand.randint(5, 8)
        elif creation_method == 2:
            shape_id = rand.randint(2, 8)
            rect_chance = 29
            if rand.randint(0, 4) == 0:
                rect_chance = 13
                add = False

        shape = None
        if rand.randint(1, rect_chance) == 1:
            # use a rect
            if add:
                x = rand.randint(8, width - 7)
                y = rand.randint(8, height - 7)
                if creation_method == 0:
                    shape = Rect.init_from_topleft_and_size(x - 3, y - 3, 5, 5)
                elif creation_method == 1:
                    shape = Rect.init_from_topleft_and_size(x - 5, y - 5, 8, 8)
                elif creation_method == 2:
                    shape = Rect.init_from_topleft_and_size(
                        x - 5, y - 5, rand.randint(2, 8), rand.randint(2, 8))
            else:
                x = rand.randint(0, width)
                y = rand.randint(0, height)
                shape = Rect.init_from_topleft_and_size(
                    x - 5, y - 5, rand.randint(2, 8), rand.randint(2, 8))
        else:
            # use a circle, where radius is determined by shape_id
            radius = shape_id
            if not add and rand.randint(0, 6) < 5:
                x = rand.randint(-radius * 3 / 2, width + radius * 3 / 2)
                y = rand.randint(-radius * 3 / 2, height + radius * 3 / 2)
                shape = Circle(Point(x, y), shape_id)
            elif width - radius - 4 >= radius + 3 and height - radius - 4 >= radius + 3:
                x = rand.randint(radius + 3, width - radius - 4)
                y = rand.randint(radius + 3, height - radius - 4)
                shape = Circle(Point(x, y), shape_id)

        if shape:
            for shape_coord in shape.tuple_iter():
                if add:
                    map_set.add(shape_coord)
                elif shape_coord in map_set:
                    map_set.discard(shape_coord)

    # write values to db
    map_db = DbReader(":memory:")
    map_db(
        "CREATE TABLE ground(x INTEGER NOT NULL, y INTEGER NOT NULL, ground_id INTEGER NOT NULL)"
    )
    map_db(
        "CREATE TABLE island_properties(name TEXT PRIMARY KEY NOT NULL, value TEXT NOT NULL)"
    )
    map_db("BEGIN TRANSACTION")

    # add grass tiles
    for x, y in map_set:
        map_db("INSERT INTO ground VALUES(?, ?, ?)", x, y, GROUND.DEFAULT_LAND)

    def fill_tiny_spaces(tile):
        """Fills 1 tile gulfs and straits with the specified tile
		@param tile: ground tile to fill with
		"""

        all_neighbours = [(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1),
                          (1, 0), (1, 1)]
        neighbours = [(-1, 0), (0, -1), (0, 1), (1, 0)]
        corners = [(-1, -1), (-1, 1)]
        knight_moves = [(-2, -1), (-2, 1), (-1, -2), (-1, 2), (1, -2), (1, 2),
                        (2, -1), (2, 1)]
        bad_configs = set([
            0, 1 << 0, 1 << 1, 1 << 2, 1 << 3, (1 << 0) | (1 << 3),
            (1 << 1) | (1 << 2)
        ])

        edge_set = copy.copy(map_set)
        reduce_edge_set = True

        while True:
            to_fill = set()
            to_ignore = set()
            for x, y in edge_set:
                # ignore the tiles with no empty neighbours
                if reduce_edge_set:
                    is_edge = False
                    for x_offset, y_offset in all_neighbours:
                        if (x + x_offset, y + y_offset) not in map_set:
                            is_edge = True
                            break
                    if not is_edge:
                        to_ignore.add((x, y))
                        continue

                for x_offset, y_offset in neighbours:
                    x2 = x + x_offset
                    y2 = y + y_offset
                    if (x2, y2) in map_set:
                        continue
                    # (x2, y2) is now a point just off the island

                    neighbours_dirs = 0
                    for i in xrange(len(neighbours)):
                        x3 = x2 + neighbours[i][0]
                        y3 = y2 + neighbours[i][1]
                        if (x3, y3) not in map_set:
                            neighbours_dirs |= (1 << i)
                    if neighbours_dirs in bad_configs:
                        # part of a straight 1 tile gulf
                        to_fill.add((x2, y2))
                    else:
                        for x_offset, y_offset in corners:
                            x3 = x2 + x_offset
                            y3 = y2 + y_offset
                            x4 = x2 - x_offset
                            y4 = y2 - y_offset
                            if (x3, y3) in map_set and (x4, y4) in map_set:
                                # part of a diagonal 1 tile gulf
                                to_fill.add((x2, y2))
                                break

                # block 1 tile straits
                for x_offset, y_offset in knight_moves:
                    x2 = x + x_offset
                    y2 = y + y_offset
                    if (x2, y2) not in map_set:
                        continue
                    if abs(x_offset) == 1:
                        y2 = y + y_offset / 2
                        if (x2, y2) in map_set or (x, y2) in map_set:
                            continue
                    else:
                        x2 = x + x_offset / 2
                        if (x2, y2) in map_set or (x2, y) in map_set:
                            continue
                    to_fill.add((x2, y2))

                # block diagonal 1 tile straits
                for x_offset, y_offset in corners:
                    x2 = x + x_offset
                    y2 = y + y_offset
                    x3 = x + 2 * x_offset
                    y3 = y + 2 * y_offset
                    if (x2, y2) not in map_set and (x3, y3) in map_set:
                        to_fill.add((x2, y2))
                    elif (x2, y2) in map_set and (x2, y) not in map_set and (
                            x, y2) not in map_set:
                        to_fill.add((x2, y))

            if to_fill:
                for x, y in to_fill:
                    map_set.add((x, y))
                    map_db("INSERT INTO ground VALUES(?, ?, ?)", x, y, tile)

                old_size = len(edge_set)
                edge_set = edge_set.difference(to_ignore).union(to_fill)
                reduce_edge_set = old_size - len(edge_set) > 50
            else:
                break

    # possible movement directions
    all_moves = {
        'sw': (-1, -1),
        'w': (-1, 0),
        'nw': (-1, 1),
        's': (0, -1),
        'n': (0, 1),
        'se': (1, -1),
        'e': (1, 0),
        'ne': (1, 1)
    }

    def get_island_outline():
        """
		@return: the points just off the island as a dict
		"""
        result = set()
        for x, y in map_set:
            for offset_x, offset_y in all_moves.itervalues():
                coords = (x + offset_x, y + offset_y)
                if coords not in map_set:
                    result.add(coords)
        return result

    # add grass to sand tiles
    fill_tiny_spaces(GROUND.DEFAULT_LAND)
    outline = get_island_outline()
    for x, y in outline:
        filled = []
        for dir in sorted(all_moves):
            coords = (x + all_moves[dir][1], y + all_moves[dir][0])
            if coords in map_set:
                filled.append(dir)

        tile = None
        # straight coast or 1 tile U-shaped gulfs
        if filled == ['s', 'se', 'sw'] or filled == ['s']:
            tile = GROUND.SAND_NORTH
        elif filled == ['e', 'ne', 'se'] or filled == ['e']:
            tile = GROUND.SAND_WEST
        elif filled == ['n', 'ne', 'nw'] or filled == ['n']:
            tile = GROUND.SAND_SOUTH
        elif filled == ['nw', 'sw', 'w'] or filled == ['w']:
            tile = GROUND.SAND_EAST
        # slight turn (looks best with straight coast)
        elif filled == ['e', 'se'] or filled == ['e', 'ne']:
            tile = GROUND.SAND_WEST
        elif filled == ['n', 'ne'] or filled == ['n', 'nw']:
            tile = GROUND.SAND_SOUTH
        elif filled == ['nw', 'w'] or filled == ['sw', 'w']:
            tile = GROUND.SAND_EAST
        elif filled == ['s', 'sw'] or filled == ['s', 'se']:
            tile = GROUND.SAND_NORTH
        # sandy corner
        elif filled == ['se']:
            tile = GROUND.SAND_NORTHWEST1
        elif filled == ['ne']:
            tile = GROUND.SAND_SOUTHWEST1
        elif filled == ['nw']:
            tile = GROUND.SAND_SOUTHEAST1
        elif filled == ['sw']:
            tile = GROUND.SAND_NORTHEAST1
        # grassy corner
        elif 3 <= len(filled) <= 5:
            coast_set = set(filled)
            if 'e' in coast_set and 'se' in coast_set and 's' in coast_set:
                tile = GROUND.SAND_NORTHEAST3
            elif 's' in coast_set and 'sw' in coast_set and 'w' in coast_set:
                tile = GROUND.SAND_NORTHWEST3
            elif 'w' in coast_set and 'nw' in coast_set and 'n' in coast_set:
                tile = GROUND.SAND_SOUTHWEST3
            elif 'n' in coast_set and 'ne' in coast_set and 'e' in coast_set:
                tile = GROUND.SAND_SOUTHEAST3

        assert tile
        map_db("INSERT INTO ground VALUES(?, ?, ?)", x, y, tile)
    map_set = map_set.union(outline)

    # add sand to shallow water tiles
    fill_tiny_spaces(GROUND.SAND)
    outline = get_island_outline()
    for x, y in outline:
        filled = []
        for dir in sorted(all_moves):
            coords = (x + all_moves[dir][1], y + all_moves[dir][0])
            if coords in map_set:
                filled.append(dir)

        tile = None
        # straight coast or 1 tile U-shaped gulfs
        if filled == ['s', 'se', 'sw'] or filled == ['s']:
            tile = GROUND.COAST_NORTH
        elif filled == ['e', 'ne', 'se'] or filled == ['e']:
            tile = GROUND.COAST_WEST
        elif filled == ['n', 'ne', 'nw'] or filled == ['n']:
            tile = GROUND.COAST_SOUTH
        elif filled == ['nw', 'sw', 'w'] or filled == ['w']:
            tile = GROUND.COAST_EAST
        # slight turn (looks best with straight coast)
        elif filled == ['e', 'se'] or filled == ['e', 'ne']:
            tile = GROUND.COAST_WEST
        elif filled == ['n', 'ne'] or filled == ['n', 'nw']:
            tile = GROUND.COAST_SOUTH
        elif filled == ['nw', 'w'] or filled == ['sw', 'w']:
            tile = GROUND.COAST_EAST
        elif filled == ['s', 'sw'] or filled == ['s', 'se']:
            tile = GROUND.COAST_NORTH
        # mostly wet corner
        elif filled == ['se']:
            tile = GROUND.COAST_NORTHWEST1
        elif filled == ['ne']:
            tile = GROUND.COAST_SOUTHWEST1
        elif filled == ['nw']:
            tile = GROUND.COAST_SOUTHEAST1
        elif filled == ['sw']:
            tile = GROUND.COAST_NORTHEAST1
        # mostly dry corner
        elif 3 <= len(filled) <= 5:
            coast_set = set(filled)
            if 'e' in coast_set and 'se' in coast_set and 's' in coast_set:
                tile = GROUND.COAST_NORTHEAST3
            elif 's' in coast_set and 'sw' in coast_set and 'w' in coast_set:
                tile = GROUND.COAST_NORTHWEST3
            elif 'w' in coast_set and 'nw' in coast_set and 'n' in coast_set:
                tile = GROUND.COAST_SOUTHWEST3
            elif 'n' in coast_set and 'ne' in coast_set and 'e' in coast_set:
                tile = GROUND.COAST_SOUTHEAST3

        assert tile
        map_db("INSERT INTO ground VALUES(?, ?, ?)", x, y, tile)
    map_set = map_set.union(outline)

    # add shallow water to deep water tiles
    fill_tiny_spaces(GROUND.SHALLOW_WATER)
    outline = get_island_outline()
    for x, y in outline:
        filled = []
        for dir in sorted(all_moves):
            coords = (x + all_moves[dir][1], y + all_moves[dir][0])
            if coords in map_set:
                filled.append(dir)

        tile = None
        # straight coast or 1 tile U-shaped gulfs
        if filled == ['s', 'se', 'sw'] or filled == ['s']:
            tile = GROUND.DEEP_WATER_NORTH
        elif filled == ['e', 'ne', 'se'] or filled == ['e']:
            tile = GROUND.DEEP_WATER_WEST
        elif filled == ['n', 'ne', 'nw'] or filled == ['n']:
            tile = GROUND.DEEP_WATER_SOUTH
        elif filled == ['nw', 'sw', 'w'] or filled == ['w']:
            tile = GROUND.DEEP_WATER_EAST
        # slight turn (looks best with straight coast)
        elif filled == ['e', 'se'] or filled == ['e', 'ne']:
            tile = GROUND.DEEP_WATER_WEST
        elif filled == ['n', 'ne'] or filled == ['n', 'nw']:
            tile = GROUND.DEEP_WATER_SOUTH
        elif filled == ['nw', 'w'] or filled == ['sw', 'w']:
            tile = GROUND.DEEP_WATER_EAST
        elif filled == ['s', 'sw'] or filled == ['s', 'se']:
            tile = GROUND.DEEP_WATER_NORTH
        # mostly deep corner
        elif filled == ['se']:
            tile = GROUND.DEEP_WATER_NORTHWEST1
        elif filled == ['ne']:
            tile = GROUND.DEEP_WATER_SOUTHWEST1
        elif filled == ['nw']:
            tile = GROUND.DEEP_WATER_SOUTHEAST1
        elif filled == ['sw']:
            tile = GROUND.DEEP_WATER_NORTHEAST1
        # mostly shallow corner
        elif 3 <= len(filled) <= 5:
            coast_set = set(filled)
            if 'e' in coast_set and 'se' in coast_set and 's' in coast_set:
                tile = GROUND.DEEP_WATER_NORTHEAST3
            elif 's' in coast_set and 'sw' in coast_set and 'w' in coast_set:
                tile = GROUND.DEEP_WATER_NORTHWEST3
            elif 'w' in coast_set and 'nw' in coast_set and 'n' in coast_set:
                tile = GROUND.DEEP_WATER_SOUTHWEST3
            elif 'n' in coast_set and 'ne' in coast_set and 'e' in coast_set:
                tile = GROUND.DEEP_WATER_SOUTHEAST3

        assert tile
        map_db("INSERT INTO ground VALUES(?, ?, ?)", x, y, tile)

    map_db("COMMIT")
    return map_db
コード例 #46
0
	def __init__(self, session, gui):
		super(IngameGui, self).__init__()
		self.session = session
		self.main_gui = gui
		self.widgets = {}
		self.tabwidgets = {}
		self.settlement = None
		self.resource_source = None
		self.resources_needed, self.resources_usable = {}, {}
		self._old_menu = None

		self.widgets = LazyWidgetsDict(self.styles, center_widgets=False)
		screenwidth = horizons.main.fife.engine_settings.getScreenWidth()

		cityinfo = self.widgets['city_info']
		cityinfo.child_finder = PychanChildFinder(cityinfo)
		cityinfo.position = ( screenwidth/2 - cityinfo.size[0]/2 - 10, 5 )

		self.logbook = LogBook(session)

		# self.widgets['minimap'] is the guichan gui around the actual minimap,
		# which is saved in self.minimap

		minimap = self.widgets['minimap']
		minimap.position = (screenwidth - minimap.size[0] -20, 4)
		minimap.show()

		minimap_rect = Rect.init_from_topleft_and_size(minimap.position[0]+77, 55, 120, 120)
		self.minimap = Minimap(minimap_rect, self.session, \
								           self.session.view.renderer['GenericRenderer'])
		minimap.mapEvents({
			'zoomIn' : self.session.view.zoom_in,
			'zoomOut' : self.session.view.zoom_out,
			'rotateRight' : Callback.ChainedCallbacks(self.session.view.rotate_right, self.minimap.rotate_right),
			'rotateLeft' : Callback.ChainedCallbacks(self.session.view.rotate_left, self.minimap.rotate_left),
			'speedUp' : self.session.speed_up,
			'speedDown' : self.session.speed_down
		})

		minimap_overlay = minimap.findChild(name='minimap_overlay_image')
		self.minimap.use_overlay_icon(minimap_overlay)

		menupanel = self.widgets['menu_panel']
		menupanel.position = (screenwidth - menupanel.size[0] +15, 149)
		menupanel.show()
		menupanel.mapEvents({
			'destroy_tool' : self.session.destroy_tool,
			'build' : self.show_build_menu,
			'helpLink' : self.main_gui.on_help,
			'gameMenuButton' : self.main_gui.show_pause,
			'logbook' : self.logbook.toggle_visibility
		})

		self.widgets['tooltip'].hide()

		for w in ('status','status_extra','status_gold','status_extra_gold'):
			self.widgets[w].child_finder = PychanChildFinder(self.widgets[w])
		self.widgets['status_gold'].show()

		self.message_widget = MessageWidget(self.session, \
								                        cityinfo.position[0] + cityinfo.size[0], 5)

		self.resbar = ResBar(self.session, gui, self.widgets, self.resource_source)

		# map button names to build functions calls with the building id
		building_list = horizons.main.db.get_building_id_buttonname_settlerlvl()
		self.callbacks_build = {}
		for id,button_name,settler_level in building_list:
			if not settler_level in self.callbacks_build:
				self.callbacks_build[settler_level] = {}
			self.callbacks_build[settler_level][button_name] = Callback(self._build, id)
コード例 #47
0
ファイル: island.py プロジェクト: court-jus/unknown-horizons
class Island(BuildingOwner, WorldObject):
    """The Island class represents an Island by keeping a list of all instances on the map,
	that belong to the island. The island variable is also set on every instance that belongs
	to an island, making it easy to determine to which island the instance belongs, when
	selected.
	An Island instance is created at map creation, when all tiles are added to the map.
	@param origin: Point instance - Position of the (0, 0) ground tile.
	@param filename: file from which the island is loaded.

	Each island holds some important attributes:
	* grounds - All grounds that belong to the island are referenced here.
	* grounds_map -  a dictionary that binds tuples of coordinates with a reference to the tile:
	                  { (x, y): tileref, ...}
					  This is important for pathfinding and quick tile fetching.
	* buildings - a list of all Building instances that are present on the island.
	* settlements - a list of all Settlement instances that are present on the island.
	* path_nodes - a special dictionary used by the pather to save paths.

	TUTORIAL:
	Why do we use a separate __init() function, and do not use the __init__() function?
	Simple, if we load the game, the class is not loaded as new instance, so the __init__
	function is not called. Rather the load function is called. So everything that new
	classes and loaded classes share to initialize, comes into the __init() function.
	This is the common way of doing this in Unknown Horizons, so better get used to it :)

	To continue hacking, check out the __init() function now.
	"""
    log = logging.getLogger("world.island")

    def __init__(self, db, islandid, session):
        """
		@param db: db instance with island table
		@param islandid: id of island in that table
		@param session: reference to Session instance
		"""
        super(Island, self).__init__(worldid=islandid)
        self.session = session

        x, y, filename = db(
            "SELECT x, y, file FROM island WHERE rowid = ? - 1000",
            islandid)[0]
        self.__init(Point(x, y), filename)

        # create building indexers
        self.building_indexers = {}
        self.building_indexers[BUILDINGS.TREE_CLASS] = BuildingIndexer(
            WildAnimal.walking_range, self, self.session.random)

        # load settlements
        for (settlement_id, ) in db(
                "SELECT rowid FROM settlement WHERE island = ?", islandid):
            Settlement.load(db, settlement_id, self.session)

        # load buildings
        from horizons.world import load_building
        for (building_worldid, building_typeid) in \
            db("SELECT rowid, type FROM building WHERE location = ?", islandid):
            load_building(self.session, db, building_typeid, building_worldid)

    def __init(self, origin, filename):
        """
		Load the actual island from a file
		@param origin: Point
		@param filename: String, filename of island db or random map id
		"""
        self.file = filename
        self.origin = origin

        # check if filename is a random map
        if random_map.is_random_island_id_string(filename):
            # it's a random map id, create this map and load it
            db = random_map.create_random_island(filename)
        else:
            db = DbReader(
                filename
            )  # Create a new DbReader instance to load the maps file.

        p_x, p_y, width, height = db(
            "SELECT (MIN(x) + ?), (MIN(y) + ?), (1 + MAX(x) - MIN(x)), (1 + MAX(y) - MIN(y)) FROM ground",
            self.origin.x, self.origin.y)[0]

        # rect for quick checking if a tile isn't on this island
        # NOTE: it contains tiles, that are not on the island!
        self.rect = Rect(Point(p_x, p_y), width, height)

        self.ground_map = {}
        for (rel_x, rel_y, ground_id
             ) in db("SELECT x, y, ground_id FROM ground"):  # Load grounds
            ground = Entities.grounds[ground_id](self.session,
                                                 self.origin.x + rel_x,
                                                 self.origin.y + rel_y)
            # These are important for pathfinding and building to check if the ground tile
            # is blocked in any way.
            self.ground_map[(ground.x, ground.y)] = ground

        self.settlements = []
        self.wild_animals = []

        self.path_nodes = IslandPathNodes(self)

        # repopulate wild animals every 2 mins if they die out.
        Scheduler().add_new_object(self.check_wild_animal_population, self,
                                   Scheduler().get_ticks(120), -1)
        """TUTORIAL:
		To continue hacking, you should now take off to the real fun stuff and check out horizons/world/building/__init__.py.
		"""

    def save(self, db):
        super(Island, self).save(db)
        db("INSERT INTO island (rowid, x, y, file) VALUES (? - 1000, ?, ?, ?)",
           self.worldid, self.origin.x, self.origin.y, self.file)
        for settlement in self.settlements:
            settlement.save(db, self.worldid)
        for animal in self.wild_animals:
            animal.save(db)

    def get_coordinates(self):
        """Returns list of coordinates, that are on the island."""
        return self.ground_map.keys()

    def get_tile(self, point):
        """Returns whether a tile is on island or not.
		@param point: Point contains position of the tile.
		@return: tile instance if tile is on island, else None."""
        try:
            return self.ground_map[(point.x, point.y)]
        except KeyError:
            return None

    def get_tile_tuple(self, tup):
        """Overloaded get_tile, takes a tuple as argument"""
        try:
            return self.ground_map[tup]
        except KeyError:
            return None

    def get_tiles_tuple(self, tuples):
        """Same as get_tile, but takes a list of tuples.
		@param tuples: iterable of tuples
		@return: list of tiles"""
        for tup in tuples:
            if tup in self.ground_map:
                yield self.ground_map[tup]

    def get_building(self, point):
        """Returns the building at the point
		@param point: position of the tile to look on
		@return: Building class instance or None if none is found.
		"""
        try:
            return self.ground_map[point.to_tuple()].object
        except KeyError:
            return None

    def get_settlement(self, point):
        """Look for a settlement on a specific tile
		@param point: Point to look on
		@return: Settlement at point, or None"""
        try:
            return self.get_tile(point).settlement
            # some tiles might be none, so we have to catch that error here
        except AttributeError:
            return None

    def get_settlements(self, rect, player=None):
        """Returns the list of settlements for the coordinates describing a rect.
		@param rect: Area to search for settlements
		@return: list of Settlement instances at that position."""
        settlements = set()
        if self.rect.intersects(rect):
            for point in rect:
                try:
                    if player is None or self.get_tile(
                            point).settlement.owner == player:
                        settlements.add(self.get_tile(point).settlement)
                except AttributeError:
                    # some tiles don't have settlements, we don't explicitly check for them cause
                    # its faster this way.
                    pass
            settlements.discard(
                None)  # None values might have been added, we don't want them
        return list(settlements)

    def add_settlement(self, position, radius, player):
        """Adds a settlement to the island at the position x, y with radius as area of influence.
		@param position: Rect describing the position of the new branch office
		@param radius: int radius of the area of influence.
		@param player: int id of the player that owns the settlement"""
        settlement = Settlement(self.session, player)
        self.add_existing_settlement(position, radius, settlement)
        # TODO: Move this to command, this message should not appear while loading
        self.session.ingame_gui.message_widget.add(position.center().x, \
                                                   position.center().y, \
                                                   'NEW_SETTLEMENT', \
                                                   {'player':player.name}, \
                                                   self.session.world.player == player)

        self.session.world.notify_new_settlement()

        return settlement

    def add_existing_settlement(self, position, radius, settlement):
        """Same as add_settlement, but uses settlement from parameter.
		May also be called for extension of an existing settlement by a new building. (this
		is useful for loading, where every loaded building extends the radius of its settlement).
		@param position: Rect"""
        if settlement not in self.settlements:
            self.settlements.append(settlement)
        self.assign_settlement(position, radius, settlement)
        self.session.scenario_eventhandler.check_events(
            CONDITIONS.settlements_num_greater)
        return settlement

    def assign_settlement(self, position, radius, settlement):
        """Assigns the settlement property to tiles within the circle defined by \
		position and radius.
		@param position: Rect
		@param radius:
		@param settlement:
		"""
        for coord in position.get_radius_coordinates(radius,
                                                     include_self=True):
            tile = self.get_tile_tuple(coord)
            if tile is not None:
                if tile.settlement == settlement:
                    continue
                if tile.settlement is None:
                    tile.settlement = settlement
                    settlement.ground_map[coord] = tile
                    self.session.ingame_gui.minimap.update(coord)

                building = tile.object
                # assign buildings on tiles to settlement
                if building is not None and building.settlement is None and \
                   building.island == self: # don't steal from other islands
                    building.settlement = settlement
                    building.owner = settlement.owner
                    settlement.add_building(building)

        #TODO: inherit resources etc

    def add_building(self, building, player):
        """Adds a building to the island at the position x, y with player as the owner.
		@param building: Building class instance of the building that is to be added.
		@param player: int id of the player that owns the settlement"""
        building = super(Island, self).add_building(building, player)
        for building.settlement in self.get_settlements(
                building.position, player):
            self.assign_settlement(building.position, building.radius,
                                   building.settlement)
            break

        if building.settlement is not None:
            building.settlement.add_building(building)
        building.init()
        if building.id in self.building_indexers:
            self.building_indexers[building.id].add(building)

        # Reset the tiles this building was covering
        for point in building.position:
            self.path_nodes.reset_tile_walkability(point.to_tuple())

        return building

    def remove_building(self, building):
        # removal code (before super call)
        if building.settlement is not None:
            building.settlement.remove_building(building)
            assert (building not in building.settlement.buildings)

        super(Island, self).remove_building(building)
        if building.id in self.building_indexers:
            self.building_indexers[building.id].remove(building)

        # Reset the tiles this building was covering (after building has been completely removed)
        for point in building.position:
            self.path_nodes.reset_tile_walkability(point.to_tuple())

    def get_building_index(self, resource_id):
        if resource_id == RES.WILDANIMALFOOD_ID:
            return self.building_indexers[BUILDINGS.TREE_CLASS]
        return None

    def get_surrounding_tiles(self, point, radius=1):
        """Returns tiles around point with specified radius.
		@param point: instance of Point"""
        for position in Circle(point, radius):
            tile = self.get_tile(position)
            if tile is not None:
                yield tile

    def get_tiles_in_radius(self, location, radius, include_self):
        """Returns tiles in radius of location.
		This is a generator.
		@param location: anything that supports get_radius_coordinates (usually Rect).
		@param include_self: bool, whether to include the coordinates in location
		"""
        for coord in location.get_radius_coordinates(radius, include_self):
            try:
                yield self.ground_map[coord]
            except KeyError:
                pass

    def __iter__(self):
        return self.ground_map.iterkeys()

    def check_wild_animal_population(self):
        """Creates a wild animal if they died out."""
        self.log.debug("Checking wild animal population: %s",
                       len(self.wild_animals))
        if len(self.wild_animals) == 0:
            # find a tree where we can place it
            for building in self.buildings:
                if building.id == BUILDINGS.TREE_CLASS:
                    point = building.position.origin
                    Entities.units[UNITS.WILD_ANIMAL_CLASS](
                        self, x=point.x, y=point.y, session=self.session)
                    return
コード例 #48
0
def generate_map(seed=None):
    """Generates a whole map.
	@param seed: argument passed to random.seed
	@return filename to the sqlite db containing the new map"""
    rand = random.Random(seed)

    filename = tempfile.mkstemp()[1]
    shutil.copyfile(PATHS.SAVEGAME_TEMPLATE, filename)

    db = DbReader(filename)

    island_space = (35, 35)
    island_min_size = (25, 25)
    island_max_size = (28, 28)

    method = min(2, rand.randint(
        0, 9))  # choose map creation method with 80% chance for method 2

    if method == 0:
        # generate up to 9 islands
        number_of_islands = 0
        for i in Rect.init_from_topleft_and_size(0, 0, 2, 2):
            if rand.randint(0, 2) != 0:  # 2/3 chance for an island here
                number_of_islands = number_of_islands + 1
                x = int(i.x * island_space[0] * (rand.random() / 6 + 0.90))
                y = int(i.y * island_space[1] * (rand.random() / 6 + 0.90))
                island_seed = rand.randint(-sys.maxint, sys.maxint)
                island_params = {'creation_method': 0, 'seed': island_seed, \
                     'width': rand.randint(island_min_size[0], island_max_size[0]), \
                     'height': rand.randint(island_min_size[1], island_max_size[1])}

                island_string = string.Template(
                    _random_island_id_template).safe_substitute(island_params)

                db("INSERT INTO island (x, y, file) VALUES(?, ?, ?)", x, y,
                   island_string)

        # if there is 1 or 0 islands created, it places 1 large island in the centre
        if number_of_islands == 0:
            x = 20
            y = 20
            island_seed = rand.randint(-sys.maxint, sys.maxint)
            island_params = {'creation_method': 1, 'seed': island_seed, \
                 'width': rand.randint(island_min_size[0] * 2, island_max_size[0] * 2), \
                 'height': rand.randint(island_min_size[1] * 2, island_max_size[1] * 2)}
            island_string = string.Template(
                _random_island_id_template).safe_substitute(island_params)

            db("INSERT INTO island (x, y, file) VALUES(?, ?, ?)", x, y,
               island_string)

        elif number_of_islands == 1:
            db("DELETE FROM island")

            x = 20
            y = 20
            island_seed = rand.randint(-sys.maxint, sys.maxint)
            island_params = {'creation_method': 1, 'seed': island_seed, \
                 'width': rand.randint(island_min_size[0] * 2, island_max_size[0] * 2), \
                 'height': rand.randint(island_min_size[1] * 2, island_max_size[1] * 2)}

            island_string = string.Template(
                _random_island_id_template).safe_substitute(island_params)

            db("INSERT INTO island (x, y, file) VALUES(?, ?, ?)", x, y,
               island_string)

    elif method == 1:
        # places 1 large island in the centre
        x = 20
        y = 20
        island_seed = rand.randint(-sys.maxint, sys.maxint)
        island_params = {'creation_method': 1, 'seed': island_seed, \
             'width': rand.randint(island_min_size[0] * 2, island_max_size[0] * 2), \
             'height': rand.randint(island_min_size[1] * 2, island_max_size[1] * 2)}
        island_string = string.Template(
            _random_island_id_template).safe_substitute(island_params)

        db("INSERT INTO island (x, y, file) VALUES(?, ?, ?)", x, y,
           island_string)
    elif method == 2:
        # tries to fill at most land_coefficient * 100% of the map with land
        map_width = 140
        map_height = 140
        min_island_size = 20
        max_island_size = 65
        max_islands = 20
        min_space = 2
        land_coefficient = max(0.3, min(0.6, rand.gauss(0.45, 0.07)))

        islands = []
        estimated_land = 0
        max_land_amount = map_width * map_height * land_coefficient

        for i in xrange(max_islands):
            size_modifier = 1.1 - 0.2 * estimated_land / float(max_land_amount)
            width = rand.randint(min_island_size - 5, max_island_size)
            width = max(
                min_island_size,
                min(max_island_size, int(round(width * size_modifier))))
            coef = max(0.25, min(4, rand.gauss(1, 0.2)))
            height = max(min_island_size,
                         min(int(round(width * coef)), max_island_size))
            size = width * height
            if estimated_land + size > max_land_amount:
                continue

            for j in xrange(7):
                # try to place the island 7 times
                x = rand.randint(0, map_width - width)
                y = rand.randint(0, map_height - height)

                rect = Rect.init_from_topleft_and_size(x, y, width, height)
                blocked = False
                for existing_island in islands:
                    if rect.distance(existing_island) < min_space:
                        blocked = True
                        break
                if blocked:
                    continue

                island_seed = rand.randint(-sys.maxint, sys.maxint)
                island_params = {'creation_method': 2, 'seed': island_seed, \
                     'width': width, 'height': height}
                island_string = string.Template(
                    _random_island_id_template).safe_substitute(island_params)
                db("INSERT INTO island (x, y, file) VALUES(?, ?, ?)", x, y,
                   island_string)

                islands.append(rect)
                estimated_land += size
                break

    return filename
コード例 #49
0
    def __init__(self, session, gui):
        super(IngameGui, self).__init__()
        self.session = session
        self.main_gui = gui
        self.widgets = {}
        self.tabwidgets = {}
        self.settlement = None
        self.resource_source = None
        self.resources_needed, self.resources_usable = {}, {}
        self._old_menu = None

        self.widgets = LazyWidgetsDict(self.styles, center_widgets=False)

        cityinfo = self.widgets['city_info']
        cityinfo.child_finder = PychanChildFinder(cityinfo)
        cityinfo.position_technique = "center-10:top+5"

        self.logbook = LogBook()
        self.logbook.add_pause_request_listener(
            Callback(self.session.speed_pause))
        self.logbook.add_unpause_request_listener(
            Callback(self.session.speed_unpause))
        self.scenario_chooser = ScenarioChooser(self.session)

        # self.widgets['minimap'] is the guichan gui around the actual minimap,
        # which is saved in self.minimap

        minimap = self.widgets['minimap']
        minimap.position_technique = "right-20:top+4"
        minimap.show()

        minimap_rect = Rect.init_from_topleft_and_size(
            minimap.position[0] + 77, 55, 120, 120)

        self.minimap = Minimap(minimap_rect, self.session, \
                               self.session.view.renderer['GenericRenderer'])
        minimap.mapEvents({
            'zoomIn':
            self.session.view.zoom_in,
            'zoomOut':
            self.session.view.zoom_out,
            'rotateRight':
            Callback.ChainedCallbacks(self.session.view.rotate_right,
                                      self.minimap.rotate_right),
            'rotateLeft':
            Callback.ChainedCallbacks(self.session.view.rotate_left,
                                      self.minimap.rotate_left),
            'speedUp':
            self.session.speed_up,
            'speedDown':
            self.session.speed_down
        })

        minimap_overlay = minimap.findChild(name='minimap_overlay_image')

        self.minimap.use_overlay_icon(minimap_overlay)

        self.widgets['menu_panel'].position_technique = "right+15:top+153"
        self.widgets['menu_panel'].show()
        self.widgets['menu_panel'].mapEvents({
            'destroy_tool':
            self.session.destroy_tool,
            'build':
            self.show_build_menu,
            'helpLink':
            self.main_gui.on_help,
            'gameMenuButton':
            self.main_gui.show_pause,
            'logbook':
            self.logbook.toggle_visibility
        })

        self.widgets['tooltip'].hide()

        self.widgets['status'].child_finder = PychanChildFinder(
            self.widgets['status'])
        self.widgets['status_extra'].child_finder = PychanChildFinder(
            self.widgets['status_extra'])

        self.message_widget = MessageWidget(self.session, \
                                            cityinfo.position[0] + cityinfo.size[0], 5)
        self.widgets['status_gold'].show()
        self.widgets['status_gold'].child_finder = PychanChildFinder(
            self.widgets['status_gold'])
        self.widgets['status_extra_gold'].child_finder = PychanChildFinder(
            self.widgets['status_extra_gold'])

        # map button names to build functions calls with the building id
        callbackWithArguments = pychan.tools.callbackWithArguments
        self.callbacks_build = {}
        for id, button_name, settler_level in horizons.main.db.get_building_id_buttonname_settlerlvl(
        ):
            if not settler_level in self.callbacks_build:
                self.callbacks_build[settler_level] = {}
            self.callbacks_build[settler_level][button_name] = Callback(
                self._build, id)