Example #1
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)
    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)
Example #3
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)
    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
    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)
Example #6
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)
Example #7
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
Example #8
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)
Example #9
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
Example #10
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
Example #11
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)
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
Example #13
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
Example #14
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