Esempio n. 1
0
def stitching_positions(p1, p2):
    """
    Returns a list of positions between p1 and p2 between MIN_SYSTEM_SEPARATION and MAX_STARLANE_LENGTH apart
    """
    if 2 * universe_tables.MIN_SYSTEM_SEPARATION >= universe_tables.MAX_STARLANE_LENGTH:
        util.report_error("MAX_STARLANE_LENGTH must be twice MIN_SYSTEM_SEPARATION to "
                          "allow extra positions to be added to enforce MAX_STARLANE_LENGTH")
        return []

    max_dist = universe_tables.MAX_STARLANE_LENGTH
    min_dist = universe_tables.MIN_SYSTEM_SEPARATION
    p1_p2_dist = util.distance(p1, p2)
    if p1_p2_dist < max_dist:
        return []

    # Pick a random point in an 2:1 ratio ellipse and then rotate and slide it in between p1 and p2
    p1_p2_theta = acos((p2[0] - p1[0]) / p1_p2_dist)
    p1_p2_scale = (p1_p2_dist - 2*min_dist) / 2
    p1_p2_translation = ((p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2)

    radius_0space = uniform(0.0, 1.0)
    angle_0space = uniform(0.0, 2.0 * pi)
    rotated_point = (radius_0space * p1_p2_scale * cos(angle_0space + p1_p2_theta),
                     radius_0space * p1_p2_scale * sin(angle_0space + p1_p2_theta))

    p3 = (rotated_point[0] + p1_p2_translation[0], rotated_point[1] + p1_p2_translation[1])

    return [p3] + stitching_positions(p1, p3) + stitching_positions(p2, p3)
Esempio n. 2
0
def calc_planet_size(star_type, orbit, planet_density, galaxy_shape):
    """
    Calculate planet size for a potential new planet based on planet density setup option, star type and orbit number.
    """

    # try to pick a planet size by making a series of "rolls" (1-100)
    # for each planet size, and take the highest modified roll
    planet_size = fo.planetSize.unknown
    try:
        max_roll = 0
        for candidate in planet_sizes_all:
            roll = random.randint(1, 100) \
                + tables.DENSITY_MOD_TO_PLANET_SIZE_DIST[planet_density][candidate] \
                + tables.STAR_TYPE_MOD_TO_PLANET_SIZE_DIST[star_type][candidate] \
                + tables.ORBIT_MOD_TO_PLANET_SIZE_DIST[orbit][candidate] \
                + tables.GALAXY_SHAPE_MOD_TO_PLANET_SIZE_DIST[galaxy_shape][candidate]
            if max_roll < roll:
                max_roll = roll
                planet_size = candidate
    except:
        # in case of an error play it safe and set planet size to invalid
        planet_size = fo.planetSize.unknown
        util.report_error("Python calc_planet_size: Pick planet size failed" + str(sys.exc_info()[1]))

    # if we got an invalid planet size (for whatever reason),
    # just select one randomly from the global tuple based
    # only on the planet density setup option
    if planet_size == fo.planetSize.unknown:
        if random.randint(1, 10) <= planet_density:
            planet_size = random.choice(planet_sizes)
        else:
            planet_size = fo.planetSize.noWorld

    return planet_size
Esempio n. 3
0
    def __distribute(self, dl_info):
        assert isinstance(dl_info, download_info)
        
        util.report_info("Verifying <%s> ..." % dl_info.res_path)

        # Verify distribute source
        if not os.path.isfile(dl_info.store_path):
            util.report_error("File <%s> is not existed. Please check your network state and re-run build script." % dl_info.res_path)

        if fhash.hash_file(dl_info.store_path) != dl_info.tag:
            util.report_error("File <%s> verificaition is failed. Please check your network state and re-run build script." % dl_info.res_path)

        util.report_info("Distributing <%s> ..." % dl_info.res_path)

        # Clean target if file is existed.
        if dl_info.res_type in [RAW_FILE, COMPRESSED_FILE]:
            if os.path.isfile(dl_info.dist_path):
                os.remove(dl_info.dist_path)
        elif dl_info.res_type in [COMPRESSED_FOLDER]:
            if os.path.isdir(dl_info.dist_path):
                shutil.rmtree(dl_info.dist_path)

        dist_parent = os.path.dirname(dl_info.dist_path)
        if dl_info.res_type in [COMPRESSED_FILE, COMPRESSED_FOLDER]:
            self.__decompress(dl_info.store_path, dist_parent)
        else:
            shutil.copy(dl_info.store_path, dist_parent)
Esempio n. 4
0
    def can_place_at(self, system, plan):
        """
        Check if the starlane altering monster fleet ''plan'' can be placed at ''system''
        without disjoining the galaxy map.
        Compute the disjoint set of the galaxy without the starlanes
        from the proposed system.  Return False if there will be more
        connected regions than the number of placed starlane altering
        monsters plus one, otherwise True.
        """
        local_lanes = {(min(system, s), max(system, s)) for s in fo.sys_get_starlanes(system)}

        dsets = DisjointSets()
        for s in self.systems:
            dsets.add(s)

        for lane in self.starlanes:
            if lane in self.removed_lanes or lane in local_lanes:
                continue
            dsets.link(lane[0], lane[1])

        num_contiguous_regions = len(dsets.complete_sets())
        expected_num_contiguous_regions = (len(self.placed) + 2)

        if num_contiguous_regions > expected_num_contiguous_regions:
            return False

        if num_contiguous_regions < expected_num_contiguous_regions:
            report_error("Number of contiguous regions %d is below the expected number "
                         "of contiguous regions %d when placing %d monster %s that can "
                         "break starlanes."
                         % (num_contiguous_regions, expected_num_contiguous_regions,
                            len(self.placed) + 1, plan.name()))
            return False

        return True
Esempio n. 5
0
def pick_star_type(galaxy_age):
    """
    Picks and returns a star type based on universe tables distribution modifiers.
    """

    # try to pick a star type by making a series of "rolls" (1-100)
    # for each star type, and take the highest modified roll
    star_type = fo.starType.unknown
    try:
        max_roll = 0
        for candidate in star_types:
            roll = random.randint(1, 100) \
                + fo.universe_age_mod_to_star_type_dist(galaxy_age, candidate) \
                + fo.base_star_type_dist(candidate)
            if max_roll < roll:
                max_roll = roll
                star_type = candidate
    except:
        # in case of an error play save and set star type to invalid
        star_type = fo.starType.unknown
        util.report_error("Python pick_star_type: Pick star type failed\n" + sys.exc_info()[1])

    # if we got an invalid star type (for whatever reason),
    # just select one randomly from the global tuple
    if star_type == fo.starType.unknown:
        star_type = random.choice(star_types)
    return star_type
Esempio n. 6
0
    def can_place_at(self, system, plan):
        """
        Check if the starlane altering monster fleet ''plan'' can be placed at ''system''
        without disjoining the galaxy map.
        Compute the disjoint set of the galaxy without the starlanes
        from the proposed system.  Return False if there will be more
        connected regions than the number of placed starlane altering
        monsters plus one, otherwise True.
        """
        local_lanes = {(min(system, s), max(system, s)) for s in fo.sys_get_starlanes(system)}

        dsets = DisjointSets()
        for s in self.systems:
            dsets.add(s)

        for lane in self.starlanes:
            if lane in self.removed_lanes or lane in local_lanes:
                continue
            dsets.link(lane[0], lane[1])

        num_contiguous_regions = len(dsets.complete_sets())
        expected_num_contiguous_regions = (len(self.placed) + 2)

        if num_contiguous_regions > expected_num_contiguous_regions:
            return False

        if num_contiguous_regions < expected_num_contiguous_regions:
            report_error("Number of contiguous regions %d is below the expected number "
                         "of contiguous regions %d when placing %d monster %s that can "
                         "break starlanes."
                         % (num_contiguous_regions, expected_num_contiguous_regions,
                            len(self.placed) + 1, plan.name()))
            return False

        return True
Esempio n. 7
0
def stitching_positions(p1, p2):
    """
    Returns a list of positions between p1 and p2 between MIN_SYSTEM_SEPARATION and MAX_STARLANE_LENGTH apart
    """
    if 2 * universe_tables.MIN_SYSTEM_SEPARATION >= universe_tables.MAX_STARLANE_LENGTH:
        util.report_error("MAX_STARLANE_LENGTH must be twice MIN_SYSTEM_SEPARATION to "
                          "allow extra positions to be added to enforce MAX_STARLANE_LENGTH")
        return []

    max_dist = universe_tables.MAX_STARLANE_LENGTH
    min_dist = universe_tables.MIN_SYSTEM_SEPARATION
    p1_p2_dist = util.distance(p1, p2)
    if p1_p2_dist < max_dist:
        return []

    # Pick a random point in an 2:1 ratio ellipse and then rotate and slide it in between p1 and p2
    p1_p2_theta = acos((p2[0] - p1[0]) / p1_p2_dist)
    p1_p2_scale = (p1_p2_dist - 2*min_dist) / 2
    p1_p2_translation = ((p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2)

    radius_0space = uniform(0.0, 1.0)
    angle_0space = uniform(0.0, 2.0 * pi)
    rotated_point = (radius_0space * p1_p2_scale * cos(angle_0space + p1_p2_theta),
                     radius_0space * p1_p2_scale * sin(angle_0space + p1_p2_theta))

    p3 = (rotated_point[0] + p1_p2_translation[0], rotated_point[1] + p1_p2_translation[1])

    return [p3] + stitching_positions(p1, p3) + stitching_positions(p2, p3)
Esempio n. 8
0
def calc_planet_size(star_type, orbit, planet_density, galaxy_shape):
    """
    Calculate planet size for a potential new planet based on planet density setup option, star type and orbit number.
    """
    # try to pick a planet size by making a series of "rolls" (1-100)
    # for each planet size, and take the highest modified roll
    planet_size = fo.planetSize.unknown
    try:
        max_roll = 0
        for size in planet_sizes_all:
            roll = (random.randint(1, 100) + base_chance_of_planet(
                planet_density, galaxy_shape, star_type, orbit, size))
            if max_roll < roll:
                max_roll = roll
                planet_size = size
    except:
        # in case of an error play it safe and set planet size to invalid
        planet_size = fo.planetSize.unknown
        util.report_error("Python calc_planet_size: Pick planet size failed" +
                          str(sys.exc_info()[1]))

    # if we got an invalid planet size (for whatever reason),
    # just select one randomly from the global tuple based
    # only on the planet density setup option
    if planet_size == fo.planetSize.unknown:
        if random.randint(1, 10) <= planet_density:
            planet_size = random.choice(planet_sizes)
        else:
            planet_size = fo.planetSize.noWorld

    return planet_size
Esempio n. 9
0
def generate_fields(systems):
    """
    Generates stationary fields in some randomly chosen empty no star systems.
    """
    # filter out all empty no star systems
    candidates = [
        s for s in systems
        if (fo.sys_get_star_type(s) == fo.starType.noStar) and (
            not fo.sys_get_planets(s))
    ]
    # make sure we have at least one empty no star system, otherwise return without creating any fields
    if not candidates:
        print("...no empty no star systems found, no fields created")
        return
    # pick 10-15% of all empty no star systems to create stationary fields in them, but at least one
    accepted = sample(candidates,
                      max(int(len(candidates) * uniform(0.1, 0.15)), 1))
    for system in accepted:
        # randomly pick a field type
        field_type = choice(["FLD_NEBULA_1", "FLD_NEBULA_2", "FLD_NEBULA_3"])
        # and create the field
        if fo.create_field_in_system(field_type, uniform(40, 120),
                                     system) == fo.invalid_object():
            # create field failed, report an error
            report_error(
                "Python generate_fields: create field %s in system %d failed" %
                (field_type, system))
    print("...fields created in %d systems out of %d empty no star systems" %
          (len(accepted), len(candidates)))
Esempio n. 10
0
def calc_planet_size(star_type, orbit, planet_density, galaxy_shape):
    """
    Calculate planet size for a potential new planet based on planet density setup option, star type and orbit number.
    """

    # try to pick a planet size by making a series of "rolls" (1-100)
    # for each planet size, and take the highest modified roll
    planet_size = fo.planetSize.unknown
    try:
        max_roll = 0
        for candidate in planet_sizes_all:
            roll = random.randint(1, 100) \
                + tables.DENSITY_MOD_TO_PLANET_SIZE_DIST[planet_density][candidate] \
                + tables.STAR_TYPE_MOD_TO_PLANET_SIZE_DIST[star_type][candidate] \
                + tables.ORBIT_MOD_TO_PLANET_SIZE_DIST[orbit][candidate] \
                + tables.GALAXY_SHAPE_MOD_TO_PLANET_SIZE_DIST[galaxy_shape][candidate]
            if max_roll < roll:
                max_roll = roll
                planet_size = candidate
    except:
        # in case of an error play it safe and set planet size to invalid
        planet_size = fo.planetSize.unknown
        util.report_error("Python calc_planet_size: Pick planet size failed" +
                          str(sys.exc_info()[1]))

    # if we got an invalid planet size (for whatever reason),
    # just select one randomly from the global tuple based
    # only on the planet density setup option
    if planet_size == fo.planetSize.unknown:
        if random.randint(1, 10) <= planet_density:
            planet_size = random.choice(planet_sizes)
        else:
            planet_size = fo.planetSize.noWorld

    return planet_size
Esempio n. 11
0
def pick_star_type(galaxy_age):
    """
    Picks and returns a star type based on universe tables distribution modifiers.
    """

    # try to pick a star type by making a series of "rolls" (1-100)
    # for each star type, and take the highest modified roll
    star_type = fo.starType.unknown
    try:
        max_roll = 0
        for candidate in star_types:
            roll = random.randint(1, 100) \
                + fo.universe_age_mod_to_star_type_dist(galaxy_age, candidate) \
                + fo.base_star_type_dist(candidate)
            if max_roll < roll:
                max_roll = roll
                star_type = candidate
    except:
        # in case of an error play save and set star type to invalid
        star_type = fo.starType.unknown
        util.report_error("Python pick_star_type: Pick star type failed\n" +
                          sys.exc_info()[1])

    # if we got an invalid star type (for whatever reason),
    # just select one randomly from the global tuple
    if star_type == fo.starType.unknown:
        star_type = random.choice(star_types)
    return star_type
Esempio n. 12
0
def generate_systems(pos_list, gsd):
    """
    Generates and populates star systems at all positions in specified list.
    """
    sys_list = []
    for position in pos_list:
        star_type = pick_star_type(gsd.age)
        system = fo.create_system(star_type, "", position.x, position.y)
        if system == fo.invalid_object():
            # create system failed, report an error and try to continue with next position
            util.report_error(
                "Python generate_systems: create system at position (%f, %f) failed"
                % (position.x, position.y))
            continue
        sys_list.append(system)
        for orbit in range(fo.sys_get_num_orbits(system)):
            # check for each orbit if a planet shall be created by determining planet size
            planet_size = planets.calc_planet_size(star_type, orbit,
                                                   gsd.planetDensity,
                                                   gsd.shape)
            if planet_size in planets.planet_sizes:
                # ok, we want a planet, determine planet type and generate the planet
                planet_type = planets.calc_planet_type(star_type, orbit,
                                                       planet_size)
                if fo.create_planet(planet_size, planet_type, system, orbit,
                                    "") == fo.invalid_object():
                    # create planet failed, report an error and try to continue with next orbit
                    util.report_error(
                        "Python generate_systems: create planet in system %d failed"
                        % system)
    return sys_list
Esempio n. 13
0
def calc_planet_size(star_type, orbit, planet_density, galaxy_shape):
    """
    Calculate planet size for a potential new planet based on planet density setup option, star type and orbit number.
    """
    # try to pick a planet size by making a series of "rolls" (1-100)
    # for each planet size, and take the highest modified roll
    planet_size = fo.planetSize.unknown
    try:
        max_roll = 0
        for size in planet_sizes_all:
            roll = (random.randint(1, 100)
                    + base_chance_of_planet(planet_density, galaxy_shape, star_type, orbit, size))
            if max_roll < roll:
                max_roll = roll
                planet_size = size
    except:
        # in case of an error play it safe and set planet size to invalid
        planet_size = fo.planetSize.unknown
        util.report_error("Python calc_planet_size: Pick planet size failed" + str(sys.exc_info()[1]))

    # if we got an invalid planet size (for whatever reason),
    # just select one randomly from the global tuple based
    # only on the planet density setup option
    if planet_size == fo.planetSize.unknown:
        if random.randint(1, 10) <= planet_density:
            planet_size = random.choice(planet_sizes)
        else:
            planet_size = fo.planetSize.noWorld

    return planet_size
Esempio n. 14
0
    def report_error(self, resp, status=None):
        """Report an error to StackDriver Error reporting."""
        # don't report specific known failures
        if ('Deadline exceeded while waiting for HTTP response' in resp
                or 'urlfetch.Fetch() took too long' in resp or
                # WordPress Jetpack bugs
                # https://github.com/snarfed/bridgy/issues/161
                '"resp": "invalid_input"' in resp or
                # https://github.com/snarfed/bridgy/issues/750
                '"error": "jetpack_verification_failed"' in resp or
                # https://console.cloud.google.com/errors/CMjIg52NkMLQYA
                'The Jetpack site encountered an error and could not process the API request'
                in resp or
                # Blogger known bug
                # https://github.com/snarfed/bridgy/issues/175
                'bX-2i87au' in resp or
                # Tumblr: transient Disqus error looking up thread
                # https://github.com/snarfed/bridgy/issues/177
                "Invalid argument, 'thread': Unable to find thread" in resp or
                # expected for partially set up tumblr accounts
                "we haven't found your Disqus account" in resp or
                # Twitter 5MB image file size limit
                '"message":"Image file size must be' in resp or
                # Twitter media file number limits
                'Tweet with media must have exactly 1 gif or video' in resp or
                # Facebook image type/size req'ts
                'Missing or invalid image file' in resp or
                "Your photos couldn't be uploaded. Photos should be less than 4 MB"
                in resp or
                # Twitter duplicate publish attempts
                'Status is a duplicate.' in resp
                or 'You have already favorited this status.' in resp
                or 'You have already retweeted this' in resp or
                # Facebook duplicate publish attempts
                'This status update is identical to the last one you posted.'
                in resp or
                # WordPress duplicate comment
                # "error": "Error: 409 HTTP Error 409: Conflict; {\n    \"error\": \"comment_duplicate\",\n    \"message\": \"Duplicate comment detected; it looks as though you&#8217;ve already said that!\"\n}\n"
                'comment_duplicate' in resp):
            return

        subject = '%s %s' % (self.__class__.__name__, '%s %s' %
                             (self.entity.type, self.entity.status)
                             if self.entity else 'failed')
        user = self.source.bridgy_url() if self.source else None
        util.report_error(subject,
                          user=user,
                          http_context=error_reporting.HTTPContext(
                              method=request.method,
                              url=request.url,
                              response_status_code=status,
                              remote_ip=request.remote_addr))
Esempio n. 15
0
def generate_systems(pos_list, gsd):
    """
    Generates and populates star systems at all positions in specified list.
    """
    sys_list = []
    for position in pos_list:
        star_type = pick_star_type(gsd.age)
        system = fo.create_system(star_type, "", position[0], position[1])
        if system == fo.invalid_object():
            # create system failed, report an error and try to continue with next position
            util.report_error(
                "Python generate_systems: create system at position (%f, %f) failed"
                % (position[0], position[1]))
            continue
        sys_list.append(system)

        orbits = list(range(fo.sys_get_num_orbits(system)))

        if not planets.can_have_planets(star_type, orbits, gsd.planet_density,
                                        gsd.shape):
            continue

        # Try to generate planets in each orbit.
        # If after each orbit is tried once there are no planets then
        # keep trying until a single planet is placed.
        # Except for black hole systems, which can be empty.

        at_least_one_planet = False
        random.shuffle(orbits)
        for orbit in orbits:
            if planets.generate_a_planet(system, star_type, orbit,
                                         gsd.planet_density, gsd.shape):
                at_least_one_planet = True

        if at_least_one_planet or can_have_no_planets(star_type):
            continue

        recursion_limit = 1000
        for _, orbit in product(range(recursion_limit), orbits):
            if planets.generate_a_planet(system, star_type, orbit,
                                         gsd.planet_density, gsd.shape):
                break
        else:
            # Intentionally non-modal.  Should be a warning.
            print(
                ("Python generate_systems: place planets in system %d at position (%.2f, %.2f) failed"
                 % (system, position[0], position[1])),
                file=sys.stderr,
            )

    return sys_list
Esempio n. 16
0
def generate_a_planet(system, star_type, orbit, planet_density, galaxy_shape):
    """
    Place a planet in an orbit of a system. Return True on success
    """
    planet_size = calc_planet_size(star_type, orbit, planet_density, galaxy_shape)
    if planet_size not in planet_sizes:
        return False
    # ok, we want a planet, determine planet type and generate the planet
    planet_type = calc_planet_type(star_type, orbit, planet_size)
    if planet_type == fo.planetType.unknown:
        return False
    if fo.create_planet(planet_size, planet_type, system, orbit, "") == fo.invalid_object():
        # create planet failed, report an error
        util.report_error("Python generate_systems: create planet in system %d failed" % system)
        return False
    return True
Esempio n. 17
0
def copy_package_fields(package, pkg):
    fields = [ 
        "activity_period-from", "activity_period-to",
        "activity_count", "country", "filetype", "verified" 
        ]
    for field in fields:
        with report_error(None, None):
            field_name = "package_" + field.replace("-", "_")
            setattr(package, field_name, pkg["extras"][field])
Esempio n. 18
0
def actually_save_file(package_name, orig_url, pkg, runtime_id):
    # `pkg` is a CKAN dataset
    success = False
    directory = app.config['DATA_STORAGE_DIR']

    print "Attempting to fetch package", package_name, "from", orig_url
    url = fixURL(orig_url)
    path = os.path.join(directory, package_name + '.xml')

    success = manage_download(path, url)

    with report_error("  Wrote metadata to DB", 
                      "  Couldn't write metadata to DB"):
        metadata_to_db(pkg, package_name, success, runtime_id)

    with report_error("  Package tested",
                      "  Couldn't test package %s" % package_name):
        dqruntests.start_testing(package_name)
Esempio n. 19
0
def generate_systems(pos_list, gsd):
    """
    Generates and populates star systems at all positions in specified list.
    """
    sys_list = []
    for position in pos_list:
        star_type = pick_star_type(gsd.age)
        system = fo.create_system(star_type, "", position[0], position[1])
        if system == fo.invalid_object():
            # create system failed, report an error and try to continue with next position
            util.report_error("Python generate_systems: create system at position (%f, %f) failed"
                              % (position[0], position[1]))
            continue
        sys_list.append(system)

        orbits = range(fo.sys_get_num_orbits(system))

        if not planets.can_have_planets(star_type, orbits, gsd.planet_density, gsd.shape):
            continue

        # Try to generate planets in each orbit.
        # If after each orbit is tried once there are no planets then
        # keep trying until a single planet is placed.
        # Except for black hole systems, which can be empty.

        at_least_one_planet = False
        random.shuffle(orbits)
        for orbit in orbits:
            if planets.generate_a_planet(system, star_type, orbit, gsd.planet_density, gsd.shape):
                at_least_one_planet = True

        if at_least_one_planet or can_have_no_planets(star_type):
            continue

        recursion_limit = 1000
        for _, orbit in product(range(recursion_limit), orbits):
            if planets.generate_a_planet(system, star_type, orbit, gsd.planet_density, gsd.shape):
                break
        else:
            # Intentionally non-modal.  Should be a warning.
            print >> sys.stderr, ("Python generate_systems: place planets in system %d at position (%.2f, %.2f) failed"
                                  % (system, position[0], position[1]))

    return sys_list
Esempio n. 20
0
def copy_newer( src, dst ):
	if not( os.path.isfile(src) ):
		util.report_error('Error: src parameter of copy_newer is a file path.')
	target = None
	
	if os.path.isdir(dst):
		target = os.path.join( dst, os.path.basename(src) )
	else:
		target = dst
		
	if os.path.exists(target):
		if os.path.getmtime(target) < os.path.getmtime(src):
			os.remove(target)
		
	if not os.path.exists(target):
		shutil.copy2( src, target )
		return True
	else:
		return False
Esempio n. 21
0
def setup_package_group(group):
    with util.report_error(None, "Error saving package_group"):
        # there is a group, so use that group name, or create one

        if group is not None:
            pg = models.PackageGroup.query.filter_by(name=group).first()
            if pg is None:
                pg = create_package_group(group, handle_country=False)
                print "Created new group"
            return pg
Esempio n. 22
0
def generate_fields(systems):
    """
    Generates stationary fields in some randomly chosen empty no star systems.
    """
    # filter out all empty no star systems
    candidates = [s for s in systems if (fo.sys_get_star_type(s) == fo.starType.noStar) and (not fo.sys_get_planets(s))]
    # make sure we have at least one empty no star system, otherwise return without creating any fields
    if not candidates:
        print "...no empty no star systems found, no fields created"
        return
    # pick 10-20% of all empty no star systems to create stationary fields in them, but at least one
    accepted = sample(candidates, max(int(len(candidates) * uniform(0.1, 0.2)), 1))
    for system in accepted:
        # randomly pick a field type
        field_type = choice(["FLD_NEBULA_1", "FLD_NEBULA_2"])
        # and create the field
        if fo.create_field_in_system(field_type, uniform(40, 120), system) == fo.invalid_object():
            # create field failed, report an error
            report_error("Python generate_fields: create field %s in system %d failed" % (field_type, system))
    print "...fields created in %d systems out of %d empty no star systems" % (len(accepted), len(candidates))
Esempio n. 23
0
def generate_a_planet(system, star_type, orbit, planet_density, galaxy_shape):
    """
    Place a planet in an orbit of a system. Return True on success
    """
    planet_size = calc_planet_size(star_type, orbit, planet_density,
                                   galaxy_shape)
    if planet_size not in planet_sizes:
        return False
    # ok, we want a planet, determine planet type and generate the planet
    planet_type = calc_planet_type(star_type, orbit, planet_size)
    if planet_type == fo.planetType.unknown:
        return False
    if fo.create_planet(planet_size, planet_type, system, orbit,
                        "") == fo.invalid_object():
        # create planet failed, report an error
        util.report_error(
            "Python generate_systems: create planet in system %d failed" %
            system)
        return False
    return True
Esempio n. 24
0
def setup_package_group(package, pkg):
    with util.report_error(None, "Error saving package_group"):
        # there is a group, so use that group ID, or create one
        if 'groups' not in pkg:
            print "Warning: package %s has no groups key" % pkg['name']
            return

        group = pkg['organization']["name"]
        pg = models.PackageGroup.query.filter_by(name=group).first()
        if pg is None:
            pg = create_package_group(group, handle_country=False)
        package.package_group = pg.id
Esempio n. 25
0
def boost_version( boost_root ):
	"""
	Get boost version. 
	If it didn't include boost or unknown versioned boost,
	it will return None.
	"""
	version_hpp = os.path.join( boost_root, 'boost', 'version.hpp' )
	try:
		f = open(version_hpp)
	except:
		util.report_error('Cannot find boost/version.hpp. Please specify correct boost directory.')
	if f is None:
		return None
	version_lines = f.readlines()
	f.close()
	for line in version_lines:
		matched = re.match('\s*#\s*define\s+BOOST_VERSION\s+(?P<version>\d+)\s*', line )
		if matched and not matched.groupdict() is None:
			if 'version' in matched.groupdict():
				return version_object( int(matched.group('version')) )
	return None
Esempio n. 26
0
def windows_kit_dirs():
    if systems.current() != systems.win32:
        report_error("Windows Kits only works on windows system.")

    kits = None
    close_key = None

    try:
        import _winreg
        winkit_key = _winreg.OpenKey(
            _winreg.HKEY_LOCAL_MACHINE,
            r"SOFTWARE\Microsoft\Windows Kits\Installed Roots")
        if winkit_key is None:
            return None

        def CloseKey():
            _winreg.CloseKey(winkit_key)

        close_key = CloseKey
        kit_key_names = ["KitsRoot", "KitsRoot81"]
        kits = []
        for kit_key_name in kit_key_names:
            try:
                kit_value = _winreg.QueryValueEx(winkit_key, kit_key_name)[0]
                kits.append(str(kit_value))
            except Exception:
                continue
        if close_key: close_key()
        return kits

    except ImportError as e:
        if close_key: close_key()
        util.report_error(
            "_winreg library is not existed in Python on Win32 platform.")

    except WindowsError as e:
        if close_key: close_key()
        util.report_error(
            'Windows error occurs: "%s" when reading Windows Kits reg.' %
            e.strerror)
Esempio n. 27
0
    def stitch_clusters(self, p1, p2, stitches):
        """
        Stitch the clusters containing ''p1'' and ''p2''
        together with the positions in ''stitches''

        This assumes that the stitching is correctly formed.
        ''p1'' and ''p2'' are the closest positions between
        the clusters and the positions in ''stitches'' are only
        between ''p1'' and ''p2''

        After stitch_clusters there will be one fewer clusters in
        the clusterer, unless there were fewer than two clusters
        to begin with.

        If ''p1'' or ''p2'' are not in clusters then stitch_clusters
        just stitches two random clusters together.  This preserves
        the invariant that stitch_clusters always reduces the number
        of clusters.
        """
        len_dset1 = None
        len_dset2 = None
        for len_dset in self.clusters:
            if p1 in len_dset[1]:
                len_dset1 = len_dset
            if p2 in len_dset[1]:
                len_dset2 = len_dset

        if not len_dset1 or not len_dset2:
            util.report_error(
                "p1 and p2 must be points in disjoint sets of positions")
            if len(self.clusters) < 2:
                return
            len_dset1, len_dset2 = list(self.clusters)[0:2]

        self.clusters.remove(len_dset1)
        self.clusters.remove(len_dset2)
        # Decorate the new cluster with its length to speed sorting
        new_set = len_dset1[1].union(len_dset2[1]).union(frozenset(stitches))
        self.clusters.add((len(new_set), new_set))
Esempio n. 28
0
def compile_home_system_list(num_home_systems, systems):
    """
    Compiles a list with a requested number of home systems.
    """

    # if the list of systems to choose home systems from is empty, report an error and return empty list
    if not systems:
        util.report_error("Python generate_home_system_list: no systems to choose from")
        return []

    # calculate an initial minimal number of jumps that the home systems should be apart,
    # based on the total number of systems to choose from and the requested number of home systems
    min_jumps = max(int(float(len(systems)) / float(num_home_systems * 2)), 5)
    # try to find the home systems, decrease the min jumps until enough systems can be found, or the min jump distance
    # gets reduced to 0 (meaning we don't have enough systems to choose from at all)
    while min_jumps > 0:
        print "Trying to find", num_home_systems, "home systems that are at least", min_jumps, "jumps apart"
        # try to find home systems...
        home_systems = find_systems_with_min_jumps_between(num_home_systems, systems, min_jumps)
        # ...check if we got enough...
        if len(home_systems) >= num_home_systems:
            # ...yes, we got what we need, so let's break out of the loop
            break
        print "Home system min jump conflict: %d systems and %d empires, tried %d min jump and failed"\
              % (len(systems), num_home_systems, min_jumps)
        # ...no, decrease the min jump distance and try again
        min_jumps -= 1

    # check if the loop above delivered a list with enough home systems, or if it exited because the min jump distance
    # has been decreased to 0 without finding enough systems
    # in that case, our galaxy obviously is too crowded, report an error and return an empty list
    if len(home_systems) < num_home_systems:
        util.report_error("Python generate_home_system_list: requested %d homeworlds in a galaxy with %d systems"
                          % (num_home_systems, len(systems)))
        return []

    # make sure all our home systems have a "real" star (that is, a star that is not a neutron star, black hole,
    # or even no star at all) and at least one planet in it
    for home_system in home_systems:
        # if this home system has no "real" star, change star type to a randomly selected "real" star
        if fo.sys_get_star_type(home_system) not in starsystems.star_types_real:
            star_type = random.choice(starsystems.star_types_real)
            print "Home system", home_system, "has star type", fo.sys_get_star_type(home_system),\
                  ", changing that to", star_type
            fo.sys_set_star_type(home_system, star_type)

        # if this home system has no planets, create one in a random orbit
        # we take random values for type and size, as these will be set to suitable values later
        if not fo.sys_get_planets(home_system):
            print "Home system", home_system, "has no planets, adding one"
            planet = fo.create_planet(random.choice(planets.planet_sizes_real),
                                      random.choice(planets.planet_types_real),
                                      home_system, random.randint(0, fo.sys_get_num_orbits(home_system) - 1), "")
            # if we couldn't create the planet, report an error and return an empty list
            if planet == fo.invalid_object():
                util.report_error("Python generate_home_system_list: couldn't create planet in home system")
                return []

    return home_systems
Esempio n. 29
0
    def stitch_clusters(self, p1, p2, stitches):
        """
        Stitch the clusters containing ''p1'' and ''p2''
        together with the positions in ''stitches''

        This assumes that the stitching is correctly formed.
        ''p1'' and ''p2'' are the closest positions between
        the clusters and the positions in ''stitches'' are only
        between ''p1'' and ''p2''

        After stitch_clusters there will be one fewer clusters in
        the clusterer, unless there were fewer than two clusters
        to begin with.

        If ''p1'' or ''p2'' are not in clusters then stitch_clusters
        just stitches two random clusters together.  This preserves
        the invariant that stitch_clusters always reduces the number
        of clusters.
        """
        len_dset1 = None
        len_dset2 = None
        for len_dset in self.clusters:
            if p1 in len_dset[1]:
                len_dset1 = len_dset
            if p2 in len_dset[1]:
                len_dset2 = len_dset

        if not len_dset1 or not len_dset2:
            util.report_error("p1 and p2 must be points in disjoint sets of positions")
            if len(self.clusters) < 2:
                return
            len_dset1, len_dset2 = list(self.clusters)[0:2]

        self.clusters.remove(len_dset1)
        self.clusters.remove(len_dset2)
        # Decorate the new cluster with its length to speed sorting
        new_set = len_dset1[1].union(len_dset2[1]).union(frozenset(stitches))
        self.clusters.add((len(new_set), new_set))
Esempio n. 30
0
def boost_version(boost_root):
    """
	Get boost version. 
	If it didn't include boost or unknown versioned boost,
	it will return None.
	"""
    version_hpp = os.path.join(boost_root, 'boost', 'version.hpp')
    try:
        f = open(version_hpp)
    except:
        util.report_error(
            'Cannot find boost/version.hpp. Please specify correct boost directory.'
        )
    if f is None:
        return None
    version_lines = f.readlines()
    f.close()
    for line in version_lines:
        matched = re.match(
            '\s*#\s*define\s+BOOST_VERSION\s+(?P<version>\d+)\s*', line)
        if matched and not matched.groupdict() is None:
            if 'version' in matched.groupdict():
                return version_object(int(matched.group('version')))
    return None
Esempio n. 31
0
def copy_package_attributes(package, pkg):
    mapping = [
        ("package_ckan_id", "id"),
        ("package_name", "name"),
        ("package_title", "title"),
        ("package_license_id", "license_id"),
        ("package_license", "license"),
        ("package_metadata_created", "metadata_created"),
        ("package_metadata_modified", "metadata_modified"),
        ("package_revision_id", "revision_id")
        ]

    for attr, key in mapping:
        with report_error(None, None):
            setattr(package, attr, pkg[key])
Esempio n. 32
0
def generate_systems(pos_list, gsd):
    """
    Generates and populates star systems at all positions in specified list.
    """
    sys_list = []
    for position in pos_list:
        star_type = pick_star_type(gsd.age)
        system = fo.create_system(star_type, "", position.x, position.y)
        if system == fo.invalid_object():
            # create system failed, report an error and try to continue with next position
            util.report_error("Python generate_systems: create system at position (%f, %f) failed"
                              % (position.x, position.y))
            continue
        sys_list.append(system)
        for orbit in range(0, fo.sys_get_num_orbits(system) - 1):
            # check for each orbit if a planet shall be created by determining planet size
            planet_size = planets.calc_planet_size(star_type, orbit, gsd.planetDensity, gsd.shape)
            if planet_size in planets.planet_sizes:
                # ok, we want a planet, determine planet type and generate the planet
                planet_type = planets.calc_planet_type(star_type, orbit, planet_size)
                if fo.create_planet(planet_size, planet_type, system, orbit, "") == fo.invalid_object():
                    # create planet failed, report an error and try to continue with next orbit
                    util.report_error("Python generate_systems: create planet in system %d failed" % system)
    return sys_list
def actually_save_manual_file(package_name):
    success = False
    directory = app.config['DATA_STORAGE_DIR']

    package = models.Package.query.filter_by(
        package_name=package_name).first()

    url = fixURL(package.source_url)
    path = os.path.join(directory, package_name + '.xml')

    success = manage_download(path, url)

    with db.session.begin():
        package.hash = 'retrieved'
        db.session.add(package)

    with report_error("  Package tested",
                      "  Couldn't test package %s" % package_name):
        dqruntests.start_testing(package_name)
def save_file(package_id, package_name, runtime_id, man_auto):
    if man_auto == 'auto':
        print "Trying to get auto package"
        registry = ckanclient.CkanClient(base_location=CKANurl)
        try:
            pkg = registry.package_entity_get(package_name)
            resources = pkg.get('resources', [])
        except Exception, e:
            print "Couldn't get URL from CKAN for package", package_name, e
            return

        print package_id, package_name, runtime_id
        if resources == []:
            return
        if len(resources) > 1:
            print "WARNING: multiple resources found; attempting to use first"

        url = resources[0]['url']
        print url

        with report_error("Saving %s" % url, None):
            actually_save_file(package_name, url, pkg, runtime_id)
Esempio n. 35
0
def create_universe(psd_map):
    """
    Main universe generation function invoked from C++ code.
    """
    print("Python Universe Generator")

    # fetch universe and player setup data
    gsd = PyGalaxySetupData(fo.get_galaxy_setup_data())
    gsd.dump()
    total_players = len(psd_map)

    # initialize RNG
    h = int_hash(six.ensure_binary(gsd.seed, 'utf-8'))
    print("Using hashed seed", h)
    seed_rng(h)
    seed_pool = [random.random() for _ in range(100)]
    print("Seed pool:", seed_pool)

    # make sure there are enough systems for the given number of players
    print("Universe creation requested with %d systems for %d players" %
          (gsd.size, total_players))
    min_size = total_players * 3
    if min_size > gsd.size:
        gsd.size = min_size
        print(
            "Too few systems for the requested number of players, number of systems adjusted accordingly"
        )
    print("Creating universe with %d systems for %d players" %
          (gsd.size, total_players))

    # calculate star system positions
    seed_rng(seed_pool.pop())
    system_positions = calc_star_system_positions(gsd)
    size = len(system_positions)
    print(gsd.shape,
          "Star system positions calculated, final number of systems:", size)

    # generate and populate systems
    seed_rng(seed_pool.pop())
    systems = generate_systems(system_positions, gsd)
    print(len(systems), "systems generated and populated")

    # generate Starlanes
    seed_rng(seed_pool.pop())
    fo.generate_starlanes(MAX_JUMPS_BETWEEN_SYSTEMS[gsd.starlane_frequency],
                          MAX_STARLANE_LENGTH)
    print("Starlanes generated")

    print("Compile list of home systems...")
    seed_rng(seed_pool.pop())
    home_systems = compile_home_system_list(total_players, systems, gsd)
    if not home_systems:
        err_msg = "Python create_universe: couldn't get any home systems, ABORTING!"
        report_error(err_msg)
        raise Exception(err_msg)
    print("Home systems:", home_systems)

    # set up empires for each player
    seed_rng(seed_pool.pop())
    for empire, psd, home_system in zip(psd_map.keys(), psd_map.values(),
                                        home_systems):
        if not setup_empire(empire, psd.empire_name, home_system,
                            psd.starting_species, psd.player_name):
            report_error(
                "Python create_universe: couldn't set up empire for player %s"
                % psd.player_name)

    # assign names to all star systems and their planets
    # this needs to be done after all systems have been generated and empire home systems have been set, as
    # only after all that is finished star types as well as planet sizes and types are fixed, and the naming
    # process depends on that
    print("Assign star system names")
    seed_rng(seed_pool.pop())
    name_star_systems(systems)
    print("Set planet names")
    for system in systems:
        name_planets(system)

    print("Generating stationary fields in systems")
    seed_rng(seed_pool.pop())
    generate_fields(systems)

    print("Generating Natives")
    seed_rng(seed_pool.pop())
    generate_natives(gsd.native_frequency, systems, home_systems)

    print("Generating Space Monsters")
    seed_rng(seed_pool.pop())
    generate_monsters(gsd.monster_frequency, systems)

    print("Distributing Starting Specials")
    seed_rng(seed_pool.pop())
    distribute_specials(gsd.specials_frequency, fo.get_all_objects())

    # finally, write some statistics to the log file
    print("############################################################")
    print("##             Universe generation statistics             ##")
    print("############################################################")
    universe_statistics.log_planet_count_dist(systems)
    print("############################################################")
    universe_statistics.log_planet_type_summary(systems)
    print("############################################################")
    universe_statistics.log_species_summary(gsd.native_frequency)
    print("############################################################")
    universe_statistics.log_monsters_summary(gsd.monster_frequency)
    print("############################################################")
    universe_statistics.log_specials_summary()
    print("############################################################")
    universe_statistics.log_systems()
    universe_statistics.log_planets()

    if error_list:
        print("Python Universe Generator completed with errors")
        return False
    else:
        print("Python Universe Generator completed successfully")
        return True
Esempio n. 36
0
def generate_monsters(monster_freq, systems):
    """
    Adds space monsters to systems.
    """
    # first, calculate the basic chance for monster generation in a system
    # based on the monster frequency that has been passed
    # get the corresponding value for the specified monster frequency from the universe tables
    basic_chance = universe_tables.MONSTER_FREQUENCY[monster_freq]
    # a value of 0 means no monsters, in this case return immediately
    if basic_chance <= 0:
        return
    print "Default monster spawn chance:", basic_chance
    expectation_tally = 0.0
    actual_tally = 0

    # get all monster fleets that have a spawn rate and limit both > 0 and at least one monster ship design in it
    # (a monster fleet with no monsters in it is pointless) and store them in a list
    fleet_plans = fo.load_monster_fleet_plan_list()

    # create a map where we store a spawn counter for each monster fleet
    # this counter will be set to the spawn limit initially and decreased every time the monster fleet is spawned
    # this map (dict) needs to be separate from the list holding the fleet plans because the order in which items
    # are stored in a dict is undefined (can be different each time), which would result in different distribution
    # even when using the same seed for the RNG
    spawn_limits = {
        fp: fp.spawn_limit()
        for fp in fleet_plans if fp.spawn_rate() > 0.0 and fp.spawn_limit() > 0
        and fp.ship_designs()
    }

    # map nests to monsters for ease of reporting
    nest_name_map = {
        "KRAKEN_NEST_SPECIAL": "SM_KRAKEN_1",
        "SNOWFLAKE_NEST_SPECIAL": "SM_SNOWFLAKE_1",
        "JUGGERNAUT_NEST_SPECIAL": "SM_JUGGERNAUT_1"
    }
    tracked_plan_tries = {name: 0 for name in nest_name_map.values()}
    tracked_plan_counts = {name: 0 for name in nest_name_map.values()}
    tracked_plan_valid_locations = {
        fp: 0
        for fp in fleet_plans if fp.name() in tracked_plan_counts
    }
    tracked_nest_valid_locations = {nest: 0 for nest in nest_name_map}

    if not fleet_plans:
        return

    universe = fo.get_universe()

    # Fleet plans that include ships capable of altering starlanes.
    ## @content_tag{CAN_ALTER_STARLANES} universe_generator special handling for fleets containing a hull design with this tag.
    fleet_can_alter_starlanes = {
        fp
        for fp in fleet_plans if any([
            universe.getGenericShipDesign(design).hull_type.hasTag(
                "CAN_ALTER_STARLANES") for design in fp.ship_designs()
        ])
    }

    # dump a list of all monster fleets meeting these conditions and their properties to the log
    print "Monster fleets available for generation at game start:"
    for fleet_plan in fleet_plans:
        print "...", fleet_plan.name(), ": spawn rate", fleet_plan.spawn_rate(
        ),
        print "/ spawn limit", fleet_plan.spawn_limit(),
        print "/ effective chance", basic_chance * fleet_plan.spawn_rate(),

        if len(systems) < 100:
            # Note: The WithinStarlaneJumps condition in fp.location()
            # is the most time costly function in universe generation
            print "/ can be spawned at", len(
                [s for s in systems if fleet_plan.location(s)]), "systems"
        else:
            print  # to terminate the print line
        if fleet_plan.name() in nest_name_map.values():
            statistics.tracked_monsters_chance[
                fleet_plan.name()] = basic_chance * fleet_plan.spawn_rate()

    # initialize a manager for monsters that can alter the map
    # required to prevent their placement from disjoining the map
    starlane_altering_monsters = StarlaneAlteringMonsters(systems)

    # for each system in the list that has been passed to this function, find a monster fleet that can be spawned at
    # the system and which hasn't already been added too many times, then attempt to add that monster fleet by
    # testing the spawn rate chance
    for system in systems:
        # collect info for tracked monster nest valid locations
        for planet in fo.sys_get_planets(system):
            for nest in tracked_nest_valid_locations:
                # print "\t tracked monster check planet: %d size: %s for nest: %20s  | result: %s"
                # % (planet, fo.planet_get_size(planet), nest, fo.special_location(nest, planet))
                if fo.special_location(nest, planet):
                    tracked_nest_valid_locations[nest] += 1

        # collect info for tracked monster valid locations
        for fp in tracked_plan_valid_locations:
            if fp.location(system):
                tracked_plan_valid_locations[fp] += 1

        # filter out all monster fleets whose location condition allows this system and whose counter hasn't reached 0.
        # Note: The WithinStarlaneJumps condition in fp.location() is
        # the most time costly function in universe generation.
        suitable_fleet_plans = [
            fp for fp in fleet_plans
            if spawn_limits[fp] and fp.location(system) and (
                fp not in fleet_can_alter_starlanes
                or starlane_altering_monsters.can_place_at(system, fp))
        ]
        # if there are no suitable monster fleets for this system, continue with the next
        if not suitable_fleet_plans:
            continue

        # randomly select one monster fleet out of the suitable ones and then test if we want to add it to this system
        # by making a roll against the basic chance multiplied by the spawn rate of this monster fleet
        expectation_tally += basic_chance * sum(
            [fp.spawn_rate()
             for fp in suitable_fleet_plans]) / len(suitable_fleet_plans)
        fleet_plan = random.choice(suitable_fleet_plans)
        if fleet_plan.name() in tracked_plan_tries:
            tracked_plan_tries[fleet_plan.name()] += 1
        if random.random() > basic_chance * fleet_plan.spawn_rate():
            print(
                "\t\t At system %4d rejected monster fleet %s from %d suitable fleets"
                % (system, fleet_plan.name(), len(suitable_fleet_plans)))
            # no, test failed, continue with the next system
            continue
        actual_tally += 1
        if fleet_plan.name() in tracked_plan_counts:
            tracked_plan_counts[fleet_plan.name()] += 1

        # all prerequisites and the test have been met, now spawn this monster fleet in this system
        # create monster fleet
        try:
            if fleet_plan in fleet_can_alter_starlanes:
                starlane_altering_monsters.place(system, fleet_plan)
            else:
                populate_monster_fleet(fleet_plan, system)
            # decrement counter for this monster fleet
            spawn_limits[fleet_plan] -= 1

        except MapGenerationError as e:
            report_error(str(e))
            continue

    print "Actual # monster fleets placed: %d; Total Placement Expectation: %.1f" % (
        actual_tally, expectation_tally)
    # finally, compile some statistics to be dumped to the log later
    statistics.monsters_summary = [(fp.name(), fp.spawn_limit() - counter)
                                   for fp, counter in spawn_limits.iteritems()]
    statistics.tracked_monsters_tries.update(tracked_plan_tries)
    statistics.tracked_monsters_summary.update(tracked_plan_counts)
    statistics.tracked_monsters_location_summary.update([
        (fp.name(), count)
        for fp, count in tracked_plan_valid_locations.iteritems()
    ])
    statistics.tracked_nest_location_summary.update([
        (nest_name_map[nest], count)
        for nest, count in tracked_nest_valid_locations.items()
    ])
Esempio n. 37
0
def create_universe(psd_map):
    """
    Main universe generation function invoked from C++ code.
    """
    print "Python Universe Generator"

    # fetch universe and player setup data
    gsd = fo.get_galaxy_setup_data()
    total_players = len(psd_map)

    # initialize RNG
    seed_rng(gsd.seed)
    seed_pool = [random.random() for _ in range(100)]

    # make sure there are enough systems for the given number of players
    print "Universe creation requested with %d systems for %d players" % (gsd.size, total_players)
    size = max(gsd.size, (total_players * 3))
    if size > gsd.size:
        # gsd.size = size
        print "Too few systems for the requested number of players, number of systems adjusted accordingly"
    print "Creating universe with %d systems for %d players" % (size, total_players)

    # calculate star system positions
    seed_rng(seed_pool.pop())
    system_positions = calc_star_system_positions(gsd.shape, size)
    size = len(system_positions)
    print gsd.shape, "Star system positions calculated, final number of systems:", size

    # generate and populate systems
    seed_rng(seed_pool.pop())
    systems = generate_systems(system_positions, gsd)
    print len(systems), "systems generated and populated"

    # generate Starlanes
    seed_rng(seed_pool.pop())
    fo.generate_starlanes(gsd.starlaneFrequency)
    print "Starlanes generated"

    print "Compile list of home systems..."
    seed_rng(seed_pool.pop())
    home_systems = compile_home_system_list(total_players, systems)
    if not home_systems:
        err_msg = "Python create_universe: couldn't get any home systems, ABORTING!"
        report_error(err_msg)
        raise Exception(err_msg)
    print "Home systems:", home_systems

    # set up empires for each player
    seed_rng(seed_pool.pop())
    for empire, psd, home_system in zip(psd_map.keys(), psd_map.values(), home_systems):
        if not setup_empire(empire, psd.empire_name, home_system, psd.starting_species, psd.player_name):
            report_error("Python create_universe: couldn't set up empire for player %s" % psd.player_name)

    # assign names to all star systems and their planets
    # this needs to be done after all systems have been generated and empire home systems have been set, as
    # only after all that is finished star types as well as planet sizes and types are fixed, and the naming
    # process depends on that
    print "Assign star system names"
    seed_rng(seed_pool.pop())
    name_star_systems(systems)
    print "Set planet names"
    for system in systems:
        name_planets(system)

    print "Generating Natives"
    seed_rng(seed_pool.pop())
    generate_natives(gsd.nativeFrequency, systems, home_systems)

    print "Generating Space Monsters"
    seed_rng(seed_pool.pop())
    generate_monsters(gsd.monsterFrequency, systems)

    print "Distributing Starting Specials"
    seed_rng(seed_pool.pop())
    distribute_specials(gsd.specialsFrequency, fo.get_all_objects())

    # finally, write some statistics to the log file
    print "############################################################"
    print "##             Universe generation statistics             ##"
    print "############################################################"
    statistics.log_planet_count_dist(systems)
    print "############################################################"
    statistics.log_planet_type_summary(systems)
    print "############################################################"
    statistics.log_species_summary()
    print "############################################################"
    statistics.log_monsters_summary()
    print "############################################################"
    statistics.log_specials_summary()
    print "############################################################"

    if error_list:
        print "Python Universe Generator completed with errors"
        return False
    else:
        print "Python Universe Generator completed successfully"
        return True
Esempio n. 38
0
def generate_monsters(monster_freq, systems):
    """
    Adds space monsters to systems.
    """

    # first, calculate the basic chance for monster generation in a system
    # based on the monster frequency that has been passed
    # get the corresponding value for the specified monster frequency from the universe tables
    inverse_monster_chance = fo.monster_frequency(monster_freq)
    # as the value in the universe table is higher for a lower frequency, we have to invert it
    # exception: a value of 0 means no monsters, in this case return immediately
    if inverse_monster_chance <= 0:
        return
    basic_chance = 1.0 / float(inverse_monster_chance)
    print "Default monster spawn chance:", basic_chance
    expectation_tally = 0.0
    actual_tally = 0

    # get all monster fleets that have a spawn rate and limit both > 0 and at least one monster ship design in it
    # (a monster fleet with no monsters in it is pointless) and store them with a spawn counter in a dict
    # this counter will be set to the spawn limit initially and decreased every time the monster fleet is spawned
    fleet_plans = {fp: fp.spawn_limit() for fp in fo.load_monster_fleet_plan_list("space_monster_spawn_fleets.txt")
                   if fp.spawn_rate() > 0.0 and fp.spawn_limit() > 0 and fp.ship_designs()}

    # map nests to monsters for ease of reporting
    nest_name_map = dict(zip(["KRAKEN_NEST_SPECIAL", "SNOWFLAKE_NEST_SPECIAL", "JUGGERNAUT_NEST_SPECIAL"], ["SM_KRAKEN_1", "SM_SNOWFLAKE_1", "SM_JUGGERNAUT_1"]))
    tracked_plan_tries = {name: 0 for name in nest_name_map.values()}
    tracked_plan_counts = {name: 0 for name in nest_name_map.values()}
    tracked_plan_valid_locations = {fp: 0 for fp, limit in fleet_plans.iteritems() if fp.name() in tracked_plan_counts}
    tracked_nest_valid_locations = {nest: 0 for nest in nest_name_map}

    if not fleet_plans:
        return

    # dump a list of all monster fleets meeting these conditions and their properties to the log
    print "Monster fleets available for generation at game start:"
    for fleet_plan in fleet_plans:
        print "...", fleet_plan.name(), ": spawn rate", fleet_plan.spawn_rate(),\
            "/ spawn limit", fleet_plan.spawn_limit(),\
            "/ effective chance", basic_chance * fleet_plan.spawn_rate(),\
            "/ can be spawned at", len([s for s in systems if fleet_plan.location(s)]), "systems"
        if fleet_plan.name() in nest_name_map.values():
            statistics.tracked_monsters_chance[fleet_plan.name()] = basic_chance * fleet_plan.spawn_rate()

    # for each system in the list that has been passed to this function, find a monster fleet that can be spawned at
    # the system and which hasn't already been added too many times, then attempt to add that monster fleet by
    # testing the spawn rate chance
    for system in systems:
        # collect info for tracked monster nest valid locations
        for planet in fo.sys_get_planets(system):
            for nest in tracked_nest_valid_locations:
                #print "\t tracked monster check planet: %d size: %s for nest: %20s  | result: %s" % (planet, fo.planet_get_size(planet), nest, fo.special_location(nest, planet))
                if fo.special_location(nest, planet):
                    tracked_nest_valid_locations[nest] += 1

        # collect info for tracked monster valid locations
        for fp in tracked_plan_valid_locations:
            if fp.location(system):
                tracked_plan_valid_locations[fp] += 1

        # filter out all monster fleets whose location condition allows this system and whose counter hasn't reached 0
        suitable_fleet_plans = [fp for fp, counter in fleet_plans.iteritems() if counter and fp.location(system)]
        # if there are no suitable monster fleets for this system, continue with the next
        if not suitable_fleet_plans:
            continue

        # randomly select one monster fleet out of the suitable ones and then test if we want to add it to this system
        # by making a roll against the basic chance multiplied by the spawn rate of this monster fleet
        expectation_tally += basic_chance * sum([fp.spawn_rate() for fp in suitable_fleet_plans]) / len(suitable_fleet_plans)
        fleet_plan = random.choice(suitable_fleet_plans)
        if fleet_plan.name() in tracked_plan_tries:
            tracked_plan_tries[fleet_plan.name()] += 1
        if random.random() > basic_chance * fleet_plan.spawn_rate():
            print "\t\t At system %4d rejected monster fleet %s from %d suitable fleets" % (system, fleet_plan.name(), len(suitable_fleet_plans))
            # no, test failed, continue with the next system
            continue
        actual_tally += 1
        if fleet_plan.name() in tracked_plan_counts:
            tracked_plan_counts[fleet_plan.name()] += 1

        # all prerequisites and the test have been met, now spawn this monster fleet in this system
        print "Spawn", fleet_plan.name(), "at", fo.get_name(system)
        # decrement counter for this monster fleet
        fleet_plans[fleet_plan] -= 1
        # create monster fleet
        monster_fleet = fo.create_monster_fleet(system)
        # if fleet creation fails, report an error and try to continue with next system
        if monster_fleet == fo.invalid_object():
            util.report_error("Python generate_monsters: unable to create new monster fleet %s" % fleet_plan.name())
            continue
        # add monsters to fleet
        for design in fleet_plan.ship_designs():
            # create monster, if creation fails, report an error and try to continue with the next design
            if fo.create_monster(design, monster_fleet) == fo.invalid_object():
                util.report_error("Python generate_monsters: unable to create monster %s" % design)

    print "Actual # monster fleets placed: %d; Total Placement Expectation: %.1f" % (actual_tally, expectation_tally)
    # finally, compile some statistics to be dumped to the log later
    statistics.monsters_summary = [(fp.name(), fp.spawn_limit() - counter) for fp, counter in fleet_plans.iteritems()]
    statistics.tracked_monsters_tries.update(tracked_plan_tries)
    statistics.tracked_monsters_summary.update(tracked_plan_counts)
    statistics.tracked_monsters_location_summary.update([(fp.name(), count) for fp, count in tracked_plan_valid_locations.iteritems()])
    statistics.tracked_nest_location_summary.update([(nest_name_map[nest], count) for nest, count in tracked_nest_valid_locations.items()])
Esempio n. 39
0
def compile_home_system_list(num_home_systems, systems):
    """
    Compiles a list with a requested number of home systems.
    """
    print "Compile home system list:", num_home_systems, "systems requested"

    # if the list of systems to choose home systems from is empty, report an error and return empty list
    if not systems:
        report_error("Python generate_home_system_list: no systems to choose from")
        return []

    # calculate an initial minimal number of jumps that the home systems should be apart,
    # based on the total number of systems to choose from and the requested number of home systems
    # Don't let min_jumps be larger than 10, because a larger number is really not at all needed and with large
    # galaxies an excessive amount of time can be used in failed attempts
    min_jumps = min(10, max(int(float(len(systems)) / float(num_home_systems * 2)), 5))

    # home systems must have a certain minimum of systems in their near vicinity
    # we will try to select our home systems from systems that match this criteria, if that fails, we will select our
    # home systems from all systems and add the missing number planets to the systems in their vicinity afterwards
    # the minimum planet limit and the jump range that defines the "near vicinity" are controlled by the
    # HS_* option constants in options.py (see there)

    # lets start by filtering out all systems from the pool we got passed into this function that match the criteria
    filtered_pool = [s for s in systems if has_min_planets_in_vicinity(s)]
    print "Filtering out systems that meet the minimum planets in the near vicinity condition yielded",\
        len(filtered_pool), "systems"
    print "Using this as the preferred pool for home system selection"
    # now try to pick the requested number of home systems by calling find_home_systems
    # this function takes two pools, a "complete" pool and one with preferred systems
    # it will try to pick the home systems from the preferred pool first, so pass our filtered pool as preferred pool
    home_systems = find_home_systems(num_home_systems, systems, filtered_pool, min_jumps)

    # check if the selection process delivered a list with enough home systems
    # if not, our galaxy obviously is too crowded, report an error and return an empty list
    if len(home_systems) < num_home_systems:
        report_error("Python generate_home_system_list: requested %d homeworlds in a galaxy with %d systems"
                     % (num_home_systems, len(systems)))
        return []

    # check if we got more home systems than we requested
    if len(home_systems) > num_home_systems:
        # yes: calculate the number of planets in the near vicinity of each system
        # and store that value with each system in a map
        hs_planets_in_vicinity_map = {s: count_planets_in_systems(get_systems_within_jumps(s, HS_VICINITY_RANGE))
                                      for s in home_systems}
        # sort the home systems by the number of planets in their near vicinity using the map
        # now only pick the number of home systems we need, taking those with the highest number of planets
        home_systems = sorted(home_systems, key=hs_planets_in_vicinity_map.get, reverse=True)[:num_home_systems]

    # make sure all our home systems have a "real" star (that is, a star that is not a neutron star, black hole,
    # or even no star at all) and at least one planet in it
    for home_system in home_systems:
        # if this home system has no "real" star, change star type to a randomly selected "real" star
        if fo.sys_get_star_type(home_system) not in star_types_real:
            star_type = random.choice(star_types_real)
            print "Home system", home_system, "has star type", fo.sys_get_star_type(home_system),\
                  ", changing that to", star_type
            fo.sys_set_star_type(home_system, star_type)

        # if this home system has no planets, create one in a random orbit
        # we take random values for type and size, as these will be set to suitable values later
        if not fo.sys_get_planets(home_system):
            print "Home system", home_system, "has no planets, adding one"
            planet = fo.create_planet(random.choice(planet_sizes_real),
                                      random.choice(planet_types_real),
                                      home_system, random.randint(0, fo.sys_get_num_orbits(home_system) - 1), "")
            # if we couldn't create the planet, report an error and return an empty list
            if planet == fo.invalid_object():
                report_error("Python generate_home_system_list: couldn't create planet in home system")
                return []

    # finally, check again if all home systems meet the criteria of having the required minimum number of planets
    # within their near vicinity, if not, add the missing number of planets
    print "Checking if home systems have the required minimum of planets within the near vicinity..."
    for home_system in home_systems:
        # calculate the number of missing planets, and add them if this number is > 0
        systems_in_vicinity = get_systems_within_jumps(home_system, HS_VICINITY_RANGE)
        num_systems_in_vicinity = len(systems_in_vicinity)
        num_planets_in_vicinity = count_planets_in_systems(systems_in_vicinity)
        num_planets_to_add = min_planets_in_vicinity_limit(num_systems_in_vicinity) - num_planets_in_vicinity
        print "Home system", home_system, "has", num_systems_in_vicinity, "systems and", num_planets_in_vicinity,\
            "planets in the near vicinity, required minimum:", min_planets_in_vicinity_limit(num_systems_in_vicinity)
        if num_planets_to_add > 0:
            systems_in_vicinity.remove(home_system)  # don't add planets to the home system, so remove it from the list
            add_planets_to_vicinity(systems_in_vicinity, num_planets_to_add)

    # as we've sorted the home system list before, lets shuffle it to ensure random order and return
    random.shuffle(home_systems)
    return home_systems
Esempio n. 40
0
def setup_empire(empire, empire_name, home_system, starting_species, player_name):
    """
    Sets up various aspects of an empire, like empire name, homeworld, etc.
    """

    # set empire name, if no one is given, pick one randomly
    if not empire_name:
        print "No empire name set for player", player_name, ", picking one randomly"
        empire_name = next(empire_name_generator)
    fo.empire_set_name(empire, empire_name)
    print "Empire name for player", player_name, "is", empire_name

    # check starting species, if no one is given, pick one randomly
    if starting_species == "RANDOM" or not starting_species:
        print "Picking random starting species for player", player_name
        starting_species = next(starting_species_pool)
    print "Starting species for player", player_name, "is", starting_species
    statistics.empire_species[starting_species] += 1

    # pick a planet from the specified home system as homeworld
    planet_list = fo.sys_get_planets(home_system)
    # if the system is empty, report an error and return false, indicating failure
    if not planet_list:
        report_error("Python setup_empire: got home system with no planets")
        return False
    homeworld = random.choice(planet_list)

    # set selected planet as empire homeworld with selected starting species
    fo.empire_set_homeworld(empire, homeworld, starting_species)

    # set homeworld focus
    # check if the preferred focus for the starting species is among
    # the foci available on the homeworld planet
    available_foci = fo.planet_available_foci(homeworld)
    preferred_focus = fo.species_preferred_focus(starting_species)
    if preferred_focus in available_foci:
        # if yes, set the homeworld focus to the preferred focus
        print "Player", player_name, ": setting preferred focus", preferred_focus, "on homeworld"
        fo.planet_set_focus(homeworld, preferred_focus)
    elif len(available_foci) > 0:
        # if no, and there is at least one available focus,
        # just take the first of the list
        if preferred_focus == "":
            print "Player", player_name, ": starting species", starting_species, "has no preferred focus, using",\
                  available_foci[0], "instead"
        else:
            print "Player", player_name, ": preferred focus", preferred_focus, "for starting species",\
                  starting_species, "not available on homeworld, using", available_foci[0], "instead"
        fo.planet_set_focus(homeworld, available_foci[0])
    else:
        # if no focus is available on the homeworld, don't set any focus
        print "Player", player_name, ": no available foci on homeworld for starting species", starting_species

    # give homeworld starting buildings
    # use the list provided in scripting/starting_unlocks/buildings.inf
    print "Player", player_name, ": add starting buildings to homeworld"
    for building in load_string_list(os.path.join(fo.get_resource_dir(), "scripting/starting_unlocks/buildings.inf")):
        fo.create_building(building, homeworld, empire)

    # unlock starting techs, buildings, hulls, ship parts, etc.
    # use default content file
    print "Player", player_name, ": add unlocked items"
    for item in fo.load_item_spec_list():
        fo.empire_unlock_item(empire, item.type, item.name)

    # add premade ship designs to empire
    print "Player", player_name, ": add premade ship designs"
    for ship_design in fo.design_get_premade_list():
        fo.empire_add_ship_design(empire, ship_design)

    # add starting fleets to empire
    # use default content file
    print "Player", player_name, ": add starting fleets"
    fleet_plans = fo.load_fleet_plan_list()
    for fleet_plan in fleet_plans:
        # first, create the fleet
        fleet = fo.create_fleet(fleet_plan.name(), home_system, empire)
        # if the fleet couldn't be created, report an error and try to continue with the next fleet plan
        if fleet == fo.invalid_object():
            report_error("Python setup empire: couldn't create fleet %s" % fleet_plan.name())
            continue
        # second, iterate over the list of ship design names in the fleet plan
        for ship_design in fleet_plan.ship_designs():
            # create a ship in the fleet
            # if the ship couldn't be created, report an error and try to continue with the next ship design
            if fo.create_ship("", ship_design, starting_species, fleet) == fo.invalid_object():
                report_error("Python setup empire: couldn't create ship %s for fleet %s"
                             % (ship_design, fleet_plan.name()))
    return True
Esempio n. 41
0
def generate_monsters(monster_freq, systems):
    """
    Adds space monsters to systems.
    """
    # first, calculate the basic chance for monster generation in a system
    # based on the monster frequency that has been passed
    # get the corresponding value for the specified monster frequency from the universe tables
    basic_chance = universe_tables.MONSTER_FREQUENCY[monster_freq]
    # a value of 0 means no monsters, in this case return immediately
    if basic_chance <= 0:
        return
    print "Default monster spawn chance:", basic_chance
    expectation_tally = 0.0
    actual_tally = 0

    # get all monster fleets that have a spawn rate and limit both > 0 and at least one monster ship design in it
    # (a monster fleet with no monsters in it is pointless) and store them in a list
    fleet_plans = fo.load_monster_fleet_plan_list()

    # create a map where we store a spawn counter for each monster fleet
    # this counter will be set to the spawn limit initially and decreased every time the monster fleet is spawned
    # this map (dict) needs to be separate from the list holding the fleet plans because the order in which items
    # are stored in a dict is undefined (can be different each time), which would result in different distribution
    # even when using the same seed for the RNG
    spawn_limits = {fp: fp.spawn_limit() for fp in fleet_plans
                    if fp.spawn_rate() > 0.0 and fp.spawn_limit() > 0 and fp.ship_designs()}

    # map nests to monsters for ease of reporting
    nest_name_map = {"KRAKEN_NEST_SPECIAL": "SM_KRAKEN_1",
                     "SNOWFLAKE_NEST_SPECIAL": "SM_SNOWFLAKE_1",
                     "JUGGERNAUT_NEST_SPECIAL": "SM_JUGGERNAUT_1"}
    tracked_plan_tries = {name: 0 for name in nest_name_map.values()}
    tracked_plan_counts = {name: 0 for name in nest_name_map.values()}
    tracked_plan_valid_locations = {fp: 0 for fp in fleet_plans if fp.name() in tracked_plan_counts}

    if not fleet_plans:
        return

    universe = fo.get_universe()

    # Fleet plans that include ships capable of altering starlanes.
    # @content_tag{CAN_ALTER_STARLANES} universe_generator special handling
    # for fleets containing a hull design with this tag.
    fleet_can_alter_starlanes = {fp for fp in fleet_plans
                                 if any([universe.getGenericShipDesign(design).hull_type.hasTag("CAN_ALTER_STARLANES")
                                         for design in fp.ship_designs()])}

    # dump a list of all monster fleets meeting these conditions and their properties to the log
    print "Monster fleets available for generation at game start:"
    fp_location_cache = {}
    for fleet_plan in fleet_plans:
        print "...", fleet_plan.name(), ": spawn rate", fleet_plan.spawn_rate(),
        print "/ spawn limit", fleet_plan.spawn_limit(),
        print "/ effective chance", basic_chance * fleet_plan.spawn_rate(),
        fp_location_cache[fleet_plan] = set(fleet_plan.locations(systems))
        print ("/ can be spawned at", len(fp_location_cache[fleet_plan]),
               "of", len(systems), "systems")
        if fleet_plan.name() in nest_name_map.values():
            universe_statistics.tracked_monsters_chance[fleet_plan.name()] = basic_chance * fleet_plan.spawn_rate()

    # initialize a manager for monsters that can alter the map
    # required to prevent their placement from disjoining the map
    starlane_altering_monsters = StarlaneAlteringMonsters(systems)

    # collect info for tracked monster nest valid locations
    planets = [p for s in systems for p in fo.sys_get_planets(s)]
    tracked_nest_valid_locations = {nest: len(fo.special_locations(nest, planets))
                                    for nest in nest_name_map}

    # for each system in the list that has been passed to this function, find a monster fleet that can be spawned at
    # the system and which hasn't already been added too many times, then attempt to add that monster fleet by
    # testing the spawn rate chance
    random.shuffle(systems)
    for system in systems:
        # collect info for tracked monster valid locations
        for fp in tracked_plan_valid_locations:
            if system in fp_location_cache[fp]:
                tracked_plan_valid_locations[fp] += 1

        # filter out all monster fleets whose location condition allows this system and whose counter hasn't reached 0.
        suitable_fleet_plans = [fp for fp in fleet_plans
                                if system in fp_location_cache[fp]
                                and spawn_limits.get(fp, 0)
                                and (fp not in fleet_can_alter_starlanes
                                     or starlane_altering_monsters.can_place_at(system, fp))]
        # if there are no suitable monster fleets for this system, continue with the next
        if not suitable_fleet_plans:
            continue

        # randomly select one monster fleet out of the suitable ones and then test if we want to add it to this system
        # by making a roll against the basic chance multiplied by the spawn rate of this monster fleet
        expectation_tally += basic_chance * sum([fp.spawn_rate()
                                                 for fp in suitable_fleet_plans]) / len(suitable_fleet_plans)
        fleet_plan = random.choice(suitable_fleet_plans)
        if fleet_plan.name() in tracked_plan_tries:
            tracked_plan_tries[fleet_plan.name()] += 1
        if random.random() > basic_chance * fleet_plan.spawn_rate():
            print("\t\t At system %4d rejected monster fleet %s from %d suitable fleets"
                  % (system, fleet_plan.name(), len(suitable_fleet_plans)))
            # no, test failed, continue with the next system
            continue
        actual_tally += 1
        if fleet_plan.name() in tracked_plan_counts:
            tracked_plan_counts[fleet_plan.name()] += 1

        # all prerequisites and the test have been met, now spawn this monster fleet in this system
        # create monster fleet
        try:
            if fleet_plan in fleet_can_alter_starlanes:
                starlane_altering_monsters.place(system, fleet_plan)
            else:
                populate_monster_fleet(fleet_plan, system)
            # decrement counter for this monster fleet
            spawn_limits[fleet_plan] -= 1

        except MapGenerationError as err:
            report_error(str(err))
            continue

    print "Actual # monster fleets placed: %d; Total Placement Expectation: %.1f" % (actual_tally, expectation_tally)
    # finally, compile some statistics to be dumped to the log later
    universe_statistics.monsters_summary = [
        (fp.name(), fp.spawn_limit() - counter) for fp, counter in spawn_limits.iteritems()
    ]
    universe_statistics.tracked_monsters_tries.update(tracked_plan_tries)
    universe_statistics.tracked_monsters_summary.update(tracked_plan_counts)
    universe_statistics.tracked_monsters_location_summary.update(
        (fp.name(), count) for fp, count in tracked_plan_valid_locations.iteritems())
    universe_statistics.tracked_nest_location_summary.update(
        (nest_name_map[nest], count) for nest, count in tracked_nest_valid_locations.items())
Esempio n. 42
0
def setup_empire(empire, empire_name, home_system, starting_species,
                 player_name):
    """
    Sets up various aspects of an empire, like empire name, homeworld, etc.
    """

    # set empire name, if no one is given, pick one randomly
    if not empire_name:
        print "No empire name set for player", player_name, ", picking one randomly"
        empire_name = next(empire_name_generator)
    fo.empire_set_name(empire, empire_name)
    print "Empire name for player", player_name, "is", empire_name

    # check starting species, if no one is given, pick one randomly
    if starting_species == "RANDOM" or not starting_species:
        print "Picking random starting species for player", player_name
        starting_species = next(starting_species_pool)
    print "Starting species for player", player_name, "is", starting_species
    universe_statistics.empire_species[starting_species] += 1

    # pick a planet from the specified home system as homeworld
    planet_list = fo.sys_get_planets(home_system)
    # if the system is empty, report an error and return false, indicating failure
    if not planet_list:
        report_error("Python setup_empire: got home system with no planets")
        return False
    homeworld = random.choice(planet_list)

    # set selected planet as empire homeworld with selected starting species
    fo.empire_set_homeworld(empire, homeworld, starting_species)

    # set homeworld focus
    # check if the preferred focus for the starting species is among
    # the foci available on the homeworld planet
    available_foci = fo.planet_available_foci(homeworld)
    preferred_focus = fo.species_preferred_focus(starting_species)
    if preferred_focus in available_foci:
        # if yes, set the homeworld focus to the preferred focus
        print "Player", player_name, ": setting preferred focus", preferred_focus, "on homeworld"
        fo.planet_set_focus(homeworld, preferred_focus)
    elif len(available_foci) > 0:
        # if no, and there is at least one available focus,
        # just take the first of the list
        if preferred_focus == "":
            print "Player", player_name, ": starting species", starting_species, "has no preferred focus, using",\
                  available_foci[0], "instead"
        else:
            print "Player", player_name, ": preferred focus", preferred_focus, "for starting species",\
                  starting_species, "not available on homeworld, using", available_foci[0], "instead"
        fo.planet_set_focus(homeworld, available_foci[0])
    else:
        # if no focus is available on the homeworld, don't set any focus
        print "Player", player_name, ": no available foci on homeworld for starting species", starting_species

    # give homeworld starting buildings
    print "Player", player_name, ": add starting buildings to homeworld"
    for item in fo.load_starting_buildings():
        fo.create_building(item.name, homeworld, empire)

    # unlock starting techs, buildings, hulls, ship parts, etc.
    # use default content file
    print "Player", player_name, ": add unlocked items"
    for item in fo.load_item_spec_list():
        fo.empire_unlock_item(empire, item.type, item.name)

    # add premade ship designs to empire
    print "Player", player_name, ": add premade ship designs"
    for ship_design in fo.design_get_premade_list():
        fo.empire_add_ship_design(empire, ship_design)

    # add starting fleets to empire
    # use default content file
    print "Player", player_name, ": add starting fleets"
    fleet_plans = fo.load_fleet_plan_list()
    for fleet_plan in fleet_plans:
        # first, create the fleet
        fleet = fo.create_fleet(fleet_plan.name(), home_system, empire)
        # if the fleet couldn't be created, report an error and try to continue with the next fleet plan
        if fleet == fo.invalid_object():
            report_error("Python setup empire: couldn't create fleet %s" %
                         fleet_plan.name())
            continue
        # second, iterate over the list of ship design names in the fleet plan
        for ship_design in fleet_plan.ship_designs():
            # create a ship in the fleet
            # if the ship couldn't be created, report an error and try to continue with the next ship design
            if fo.create_ship("", ship_design, starting_species,
                              fleet) == fo.invalid_object():
                report_error(
                    "Python setup empire: couldn't create ship %s for fleet %s"
                    % (ship_design, fleet_plan.name()))
    return True
Esempio n. 43
0
def add_planets_to_vicinity(vicinity, num_planets, gsd):
    """
    Adds the specified number of planets to the specified systems.
    """
    print "Adding", num_planets, "planets to the following systems:", vicinity

    # first, compile a list containing all the free orbits in the specified systems
    # begin with adding the free orbits of all systems that have a real star (that is, no neutron star, black hole,
    # and not no star), if that isn't enough, also one, by one, add the free orbits of neutron star, black hole and
    # no star systems (in that order) until we have enough free orbits

    # for that, we use this list of tuples
    # the first tuple contains all real star types, the following tuples the neutron, black hole and no star types,
    # so we can iterate over this list and only add the free orbits of systems that match the respective star types
    # each step
    # this way we can prioritize the systems we want to add planets to by star type
    acceptable_star_types_list = [
        star_types_real, (fo.starType.noStar, ), (fo.starType.neutron, ),
        (fo.starType.blackHole, )
    ]

    # store the free orbits as a list of tuples of (system, orbit)
    free_orbits_map = []

    # now, iterate over the list of acceptable star types
    for acceptable_star_types in acceptable_star_types_list:
        # check all systems in the list of systems we got passed into this function
        for system in vicinity:
            # if this system has a star type we want to accept in this step, add its free orbits to our list
            if fo.sys_get_star_type(system) in acceptable_star_types:
                free_orbits_map.extend([
                    (system, orbit) for orbit in fo.sys_free_orbits(system)
                ])
        # check if we got enough free orbits after completing this step
        # we want 4 times as much free orbits as planets we want to add, that means each system shouldn't get more
        # than 2-3 additional planets on average
        if len(free_orbits_map) > (num_planets * 4):
            break

    # if we got less free orbits than planets that should be added, something is wrong
    # in that case abort and log an error
    if len(free_orbits_map) < num_planets:
        report_error(
            "Python add_planets_to_vicinity: less free orbits than planets to add - cancelled"
        )

    print "...free orbits available:", free_orbits_map
    # as we will pop the free orbits from this list afterwards, shuffle it to randomize the order of the orbits
    random.shuffle(free_orbits_map)

    # add the requested number of planets
    while num_planets > 0:
        # get the next free orbit from the list we just compiled
        system, orbit = free_orbits_map.pop()

        # check the star type of the system containing the orbit we got
        star_type = fo.sys_get_star_type(system)
        if star_type in [fo.starType.noStar, fo.starType.blackHole]:
            # if it is a black hole or has no star, change the star type
            # pick a star type, continue until we get a real star
            # don't accept neutron, black hole or no star
            print "...system picked to add a planet has star type", star_type
            while star_type not in star_types_real:
                star_type = pick_star_type(gsd.age)
            print "...change that to", star_type
            fo.sys_set_star_type(system, star_type)

        # pick a planet size, continue until we get a size that matches the HS_ACCEPTABLE_PLANET_SIZES option
        planet_size = fo.planetSize.unknown
        while planet_size not in HS_ACCEPTABLE_PLANET_SIZES:
            planet_size = calc_planet_size(star_type, orbit,
                                           fo.galaxySetupOption.high,
                                           gsd.shape)

        # pick an according planet type
        planet_type = calc_planet_type(star_type, orbit, planet_size)

        # finally, create the planet in the system and orbit we got
        print "...adding", planet_size, planet_type, "planet to system", system
        if fo.create_planet(planet_size, planet_type, system, orbit,
                            "") == fo.invalid_object():
            report_error(
                "Python add_planets_to_vicinity: create planet in system %d failed"
                % system)

        # continue with next planet
        num_planets -= 1
Esempio n. 44
0
 def __decompress(self, source_path, dist_parent):
     try:
         o = subprocess.check_output([self.decompressor.store_path, "x", source_path, '-o%s' % dist_parent])
     except:
         util.report_error("Found error while decompressing <%s>" % source_path)
Esempio n. 45
0
def compile_home_system_list(num_home_systems, systems):
    """
    Compiles a list with a requested number of home systems.
    """
    print "Compile home system list:", num_home_systems, "systems requested"

    # if the list of systems to choose home systems from is empty, report an error and return empty list
    if not systems:
        report_error(
            "Python generate_home_system_list: no systems to choose from")
        return []

    # calculate an initial minimal number of jumps that the home systems should be apart,
    # based on the total number of systems to choose from and the requested number of home systems
    # Don't let min_jumps be larger than 10, because a larger number is really not at all needed and with large
    # galaxies an excessive amount of time can be used in failed attempts
    min_jumps = min(
        10, max(int(float(len(systems)) / float(num_home_systems * 2)), 5))

    # home systems must have a certain minimum of systems in their near vicinity
    # we will try to select our home systems from systems that match this criteria, if that fails, we will select our
    # home systems from all systems and add the missing number planets to the systems in their vicinity afterwards
    # the minimum planet limit and the jump range that defines the "near vicinity" are controlled by the
    # HS_* option constants in options.py (see there)

    # lets start by filtering out all systems from the pool we got passed into this function that match the criteria
    filtered_pool = [s for s in systems if has_min_planets_in_vicinity(s)]
    print "Filtering out systems that meet the minimum planets in the near vicinity condition yielded",\
        len(filtered_pool), "systems"
    print "Using this as the preferred pool for home system selection"
    # now try to pick the requested number of home systems by calling find_home_systems
    # this function takes two pools, a "complete" pool and one with preferred systems
    # it will try to pick the home systems from the preferred pool first, so pass our filtered pool as preferred pool
    home_systems = find_home_systems(num_home_systems, systems, filtered_pool,
                                     min_jumps)

    # check if the selection process delivered a list with enough home systems
    # if not, our galaxy obviously is too crowded, report an error and return an empty list
    if len(home_systems) < num_home_systems:
        report_error(
            "Python generate_home_system_list: requested %d homeworlds in a galaxy with %d systems"
            % (num_home_systems, len(systems)))
        return []

    # check if we got more home systems than we requested
    if len(home_systems) > num_home_systems:
        # yes: calculate the number of planets in the near vicinity of each system
        # and store that value with each system in a map
        hs_planets_in_vicinity_map = {
            s: count_planets_in_systems(
                get_systems_within_jumps(s, HS_VICINITY_RANGE))
            for s in home_systems
        }
        # sort the home systems by the number of planets in their near vicinity using the map
        # now only pick the number of home systems we need, taking those with the highest number of planets
        home_systems = sorted(home_systems,
                              key=hs_planets_in_vicinity_map.get,
                              reverse=True)[:num_home_systems]

    # make sure all our home systems have a "real" star (that is, a star that is not a neutron star, black hole,
    # or even no star at all) and at least one planet in it
    for home_system in home_systems:
        # if this home system has no "real" star, change star type to a randomly selected "real" star
        if fo.sys_get_star_type(home_system) not in star_types_real:
            star_type = random.choice(star_types_real)
            print "Home system", home_system, "has star type", fo.sys_get_star_type(home_system),\
                  ", changing that to", star_type
            fo.sys_set_star_type(home_system, star_type)

        # if this home system has no planets, create one in a random orbit
        # we take random values for type and size, as these will be set to suitable values later
        if not fo.sys_get_planets(home_system):
            print "Home system", home_system, "has no planets, adding one"
            planet = fo.create_planet(
                random.choice(planet_sizes_real),
                random.choice(planet_types_real), home_system,
                random.randint(0,
                               fo.sys_get_num_orbits(home_system) - 1), "")
            # if we couldn't create the planet, report an error and return an empty list
            if planet == fo.invalid_object():
                report_error(
                    "Python generate_home_system_list: couldn't create planet in home system"
                )
                return []

    # finally, check again if all home systems meet the criteria of having the required minimum number of planets
    # within their near vicinity, if not, add the missing number of planets
    print "Checking if home systems have the required minimum of planets within the near vicinity..."
    for home_system in home_systems:
        # calculate the number of missing planets, and add them if this number is > 0
        systems_in_vicinity = get_systems_within_jumps(home_system,
                                                       HS_VICINITY_RANGE)
        num_systems_in_vicinity = len(systems_in_vicinity)
        num_planets_in_vicinity = count_planets_in_systems(systems_in_vicinity)
        num_planets_to_add = min_planets_in_vicinity_limit(
            num_systems_in_vicinity) - num_planets_in_vicinity
        print "Home system", home_system, "has", num_systems_in_vicinity, "systems and", num_planets_in_vicinity,\
            "planets in the near vicinity, required minimum:", min_planets_in_vicinity_limit(num_systems_in_vicinity)
        if num_planets_to_add > 0:
            systems_in_vicinity.remove(
                home_system
            )  # don't add planets to the home system, so remove it from the list
            add_planets_to_vicinity(systems_in_vicinity, num_planets_to_add)

    # as we've sorted the home system list before, lets shuffle it to ensure random order and return
    random.shuffle(home_systems)
    return home_systems
Esempio n. 46
0
        pkg = registry.package_entity_get(package_name)
        resources = pkg.get('resources', [])
    except Exception, e:
        print "Couldn't get URL from CKAN for package", package_name, e
        return

    print package_id, package_name, runtime_id
    if resources == []:
        return
    if len(resources) > 1:
        print "WARNING: multiple resources found; attempting to use first"

    url = resources[0]['url']
    print url

    with report_error("Saving %s" % url, None):
        actually_save_file(package_name, url, pkg, runtime_id)

def dequeue_download(body):
    args = json.loads(body)
    try:
        save_file(args['package_id'],
                  args['package_name'],
                  args['runtime_id'])
    except Exception:
        print sys.exc_info()
        print "Exception!!", e
        print


def callback_fn(ch, method, properties, body):
Esempio n. 47
0
def generate_monsters(monster_freq, systems):
    """
    Adds space monsters to systems.
    """

    # first, calculate the basic chance for monster generation in a system
    # based on the monster frequency that has been passed
    # get the corresponding value for the specified monster frequency from the universe tables
    inverse_monster_chance = fo.monster_frequency(monster_freq)
    # as the value in the universe table is higher for a lower frequency, we have to invert it
    # exception: a value of 0 means no monsters, in this case return immediately
    if inverse_monster_chance <= 0:
        return
    basic_chance = 1.0 / float(inverse_monster_chance)
    print "Default monster spawn chance:", basic_chance
    expectation_tally = 0.0
    actual_tally = 0

    # get all monster fleets that have a spawn rate and limit both > 0 and at least one monster ship design in it
    # (a monster fleet with no monsters in it is pointless) and store them with a spawn counter in a dict
    # this counter will be set to the spawn limit initially and decreased every time the monster fleet is spawned
    fleet_plans = {
        fp: fp.spawn_limit()
        for fp in fo.load_monster_fleet_plan_list(
            "space_monster_spawn_fleets.txt") if fp.spawn_rate() > 0.0
        and fp.spawn_limit() > 0 and fp.ship_designs()
    }

    # map nests to monsters for ease of reporting
    nest_name_map = dict(
        zip([
            "KRAKEN_NEST_SPECIAL", "SNOWFLAKE_NEST_SPECIAL",
            "JUGGERNAUT_NEST_SPECIAL"
        ], ["SM_KRAKEN_1", "SM_SNOWFLAKE_1", "SM_JUGGERNAUT_1"]))
    tracked_plan_tries = {name: 0 for name in nest_name_map.values()}
    tracked_plan_counts = {name: 0 for name in nest_name_map.values()}
    tracked_plan_valid_locations = {
        fp: 0
        for fp, limit in fleet_plans.iteritems()
        if fp.name() in tracked_plan_counts
    }
    tracked_nest_valid_locations = {nest: 0 for nest in nest_name_map}

    if not fleet_plans:
        return

    # dump a list of all monster fleets meeting these conditions and their properties to the log
    print "Monster fleets available for generation at game start:"
    for fleet_plan in fleet_plans:
        print "...", fleet_plan.name(), ": spawn rate", fleet_plan.spawn_rate(
        ),
        print "/ spawn limit", fleet_plan.spawn_limit(),
        print "/ effective chance", basic_chance * fleet_plan.spawn_rate(),
        if len(systems) < 1000:
            print "/ can be spawned at", len(
                [s for s in systems if fleet_plan.location(s)]), "systems"
        else:
            print  # to terminate the print line
        if fleet_plan.name() in nest_name_map.values():
            statistics.tracked_monsters_chance[
                fleet_plan.name()] = basic_chance * fleet_plan.spawn_rate()

    # for each system in the list that has been passed to this function, find a monster fleet that can be spawned at
    # the system and which hasn't already been added too many times, then attempt to add that monster fleet by
    # testing the spawn rate chance
    for system in systems:
        # collect info for tracked monster nest valid locations
        for planet in fo.sys_get_planets(system):
            for nest in tracked_nest_valid_locations:
                #print "\t tracked monster check planet: %d size: %s for nest: %20s  | result: %s" % (planet, fo.planet_get_size(planet), nest, fo.special_location(nest, planet))
                if fo.special_location(nest, planet):
                    tracked_nest_valid_locations[nest] += 1

        # collect info for tracked monster valid locations
        for fp in tracked_plan_valid_locations:
            if fp.location(system):
                tracked_plan_valid_locations[fp] += 1

        # filter out all monster fleets whose location condition allows this system and whose counter hasn't reached 0
        suitable_fleet_plans = [
            fp for fp, counter in fleet_plans.iteritems()
            if counter and fp.location(system)
        ]
        # if there are no suitable monster fleets for this system, continue with the next
        if not suitable_fleet_plans:
            continue

        # randomly select one monster fleet out of the suitable ones and then test if we want to add it to this system
        # by making a roll against the basic chance multiplied by the spawn rate of this monster fleet
        expectation_tally += basic_chance * sum(
            [fp.spawn_rate()
             for fp in suitable_fleet_plans]) / len(suitable_fleet_plans)
        fleet_plan = random.choice(suitable_fleet_plans)
        if fleet_plan.name() in tracked_plan_tries:
            tracked_plan_tries[fleet_plan.name()] += 1
        if random.random() > basic_chance * fleet_plan.spawn_rate():
            print "\t\t At system %4d rejected monster fleet %s from %d suitable fleets" % (
                system, fleet_plan.name(), len(suitable_fleet_plans))
            # no, test failed, continue with the next system
            continue
        actual_tally += 1
        if fleet_plan.name() in tracked_plan_counts:
            tracked_plan_counts[fleet_plan.name()] += 1

        # all prerequisites and the test have been met, now spawn this monster fleet in this system
        print "Spawn", fleet_plan.name(), "at", fo.get_name(system)
        # decrement counter for this monster fleet
        fleet_plans[fleet_plan] -= 1
        # create monster fleet
        monster_fleet = fo.create_monster_fleet(system)
        # if fleet creation fails, report an error and try to continue with next system
        if monster_fleet == fo.invalid_object():
            util.report_error(
                "Python generate_monsters: unable to create new monster fleet %s"
                % fleet_plan.name())
            continue
        # add monsters to fleet
        for design in fleet_plan.ship_designs():
            # create monster, if creation fails, report an error and try to continue with the next design
            if fo.create_monster(design, monster_fleet) == fo.invalid_object():
                util.report_error(
                    "Python generate_monsters: unable to create monster %s" %
                    design)

    print "Actual # monster fleets placed: %d; Total Placement Expectation: %.1f" % (
        actual_tally, expectation_tally)
    # finally, compile some statistics to be dumped to the log later
    statistics.monsters_summary = [(fp.name(), fp.spawn_limit() - counter)
                                   for fp, counter in fleet_plans.iteritems()]
    statistics.tracked_monsters_tries.update(tracked_plan_tries)
    statistics.tracked_monsters_summary.update(tracked_plan_counts)
    statistics.tracked_monsters_location_summary.update([
        (fp.name(), count)
        for fp, count in tracked_plan_valid_locations.iteritems()
    ])
    statistics.tracked_nest_location_summary.update([
        (nest_name_map[nest], count)
        for nest, count in tracked_nest_valid_locations.items()
    ])
Esempio n. 48
0
def add_planets_to_vicinity(vicinity, num_planets, gsd):
    """
    Adds the specified number of planets to the specified systems.
    """
    print "Adding", num_planets, "planets to the following systems:", vicinity

    # first, compile a list containing all the free orbits in the specified systems
    # begin with adding the free orbits of all systems that have a real star (that is, no neutron star, black hole,
    # and not no star), if that isn't enough, also one, by one, add the free orbits of neutron star, black hole and
    # no star systems (in that order) until we have enough free orbits

    # for that, we use this list of tuples
    # the first tuple contains all real star types, the following tuples the neutron, black hole and no star types,
    # so we can iterate over this list and only add the free orbits of systems that match the respective star types
    # each step
    # this way we can prioritize the systems we want to add planets to by star type
    acceptable_star_types_list = [
        star_types_real,
        (fo.starType.noStar,),
        (fo.starType.neutron,),
        (fo.starType.blackHole,)
    ]

    # store the free orbits as a list of tuples of (system, orbit)
    free_orbits_map = []

    # now, iterate over the list of acceptable star types
    for acceptable_star_types in acceptable_star_types_list:
        # check all systems in the list of systems we got passed into this function
        for system in vicinity:
            # if this system has a star type we want to accept in this step, add its free orbits to our list
            if fo.sys_get_star_type(system) in acceptable_star_types:
                free_orbits_map.extend([(system, orbit) for orbit in fo.sys_free_orbits(system)])
        # check if we got enough free orbits after completing this step
        # we want 4 times as much free orbits as planets we want to add, that means each system shouldn't get more
        # than 2-3 additional planets on average
        if len(free_orbits_map) > (num_planets * 4):
            break

    # if we got less free orbits than planets that should be added, something is wrong
    # in that case abort and log an error
    if len(free_orbits_map) < num_planets:
        report_error("Python add_planets_to_vicinity: less free orbits than planets to add - cancelled")

    print "...free orbits available:", free_orbits_map
    # as we will pop the free orbits from this list afterwards, shuffle it to randomize the order of the orbits
    random.shuffle(free_orbits_map)

    # add the requested number of planets
    while num_planets > 0:
        # get the next free orbit from the list we just compiled
        system, orbit = free_orbits_map.pop()

        # check the star type of the system containing the orbit we got
        star_type = fo.sys_get_star_type(system)
        if star_type in [fo.starType.noStar, fo.starType.blackHole]:
            # if it is a black hole or has no star, change the star type
            # pick a star type, continue until we get a real star
            # don't accept neutron, black hole or no star
            print "...system picked to add a planet has star type", star_type
            while star_type not in star_types_real:
                star_type = pick_star_type(gsd.age)
            print "...change that to", star_type
            fo.sys_set_star_type(system, star_type)

        # pick a planet size, continue until we get a size that matches the HS_ACCEPTABLE_PLANET_SIZES option
        planet_size = fo.planetSize.unknown
        while planet_size not in HS_ACCEPTABLE_PLANET_SIZES:
            planet_size = calc_planet_size(star_type, orbit, fo.galaxySetupOption.high, gsd.shape)

        # pick an according planet type
        planet_type = calc_planet_type(star_type, orbit, planet_size)

        # finally, create the planet in the system and orbit we got
        print "...adding", planet_size, planet_type, "planet to system", system
        if fo.create_planet(planet_size, planet_type, system, orbit, "") == fo.invalid_object():
            report_error("Python add_planets_to_vicinity: create planet in system %d failed" % system)

        # continue with next planet
        num_planets -= 1
Esempio n. 49
0
def compile_home_system_list(num_home_systems, systems, gsd):
    """
    Compiles a list with a requested number of home systems.
    """
    print "Compile home system list:", num_home_systems, "systems requested"

    # if the list of systems to choose home systems from is empty, report an error and return empty list
    if not systems:
        report_error(
            "Python generate_home_system_list: no systems to choose from")
        return []

    # calculate an initial minimal number of jumps that the home systems should be apart,
    # based on the total number of systems to choose from and the requested number of home systems
    # don't let min_jumps be either:
    # a.) larger than a defined limit, because an unreasonably large number is really not at all needed,
    #     and with large galaxies an excessive amount of time can be used in failed attempts
    # b.) lower than the minimum jump distance limit that should be considered high priority (see options.py),
    #     otherwise no attempt at all would be made to enforce the other requirements for home systems (see below)
    min_jumps = min(
        HS_MAX_JUMP_DISTANCE_LIMIT,
        max(int(float(len(systems)) / float(num_home_systems * 2)),
            HS_MIN_DISTANCE_PRIORITY_LIMIT))

    # home systems must have a certain minimum of systems and planets in their near vicinity
    # we will try to select our home systems from systems that match this criteria, if that fails, we will select our
    # home systems from all systems and add the missing number planets to the systems in their vicinity afterwards
    # the minimum system and planet limit and the jump range that defines the "near vicinity" are controlled by the
    # HS_* option constants in options.py (see there)

    # we start by building two additional pools of systems: one that contains all systems that match the criteria
    # completely (meets the min systems and planets limit), and one that contains all systems that match the criteria
    # at least partially (meets the min systems limit)
    pool_matching_sys_and_planet_limit = []
    pool_matching_sys_limit = []
    for system in systems:
        systems_in_vicinity = fo.systems_within_jumps_unordered(
            HS_VICINITY_RANGE, [system])
        if len(systems_in_vicinity) >= HS_MIN_SYSTEMS_IN_VICINITY:
            pool_matching_sys_limit.append(system)
            if count_planets_in_systems(
                    systems_in_vicinity) >= min_planets_in_vicinity_limit(
                        len(systems_in_vicinity)):
                pool_matching_sys_and_planet_limit.append(system)
    print(
        len(pool_matching_sys_and_planet_limit),
        "systems meet the min systems and planets in the near vicinity limit")
    print len(pool_matching_sys_limit
              ), "systems meet the min systems in the near vicinity limit"

    # now try to pick the requested number of home systems
    # we will do this by calling find_home_systems, which takes a list of tuples defining the pools from which to pick
    # the home systems; it will use the pools in the order in which they appear in the list, so put better pools first

    # we will make two attempts: the first one with the filtered pools we just created, and tell find_home_systems
    # to start with the min_jumps jumps distance we calculated above, but not to go lower than
    # HS_MIN_DISTANCE_PRIORITY_LIMIT

    print "First attempt: trying to pick home systems from the filtered pools of preferred systems"
    pool_list = [
        # the better pool is of course the one where all systems meet BOTH the min systems and planets limit
        (pool_matching_sys_and_planet_limit,
         "pool of systems that meet both the min systems and planets limit"),
        # next the less preferred pool where all systems at least meets the min systems limit
        # specify 0 as number of requested home systems to pick as much systems as possible
        (pool_matching_sys_limit,
         "pool of systems that meet at least the min systems limit"),
    ]
    home_systems = find_home_systems(num_home_systems, pool_list, min_jumps,
                                     HS_MIN_DISTANCE_PRIORITY_LIMIT)

    # check if the first attempt delivered a list with enough home systems
    # if not, we make our second attempt, this time disregarding the filtered pools and using all systems, starting
    # again with the min_jumps jump distance limit and specifying 0 as number of required home systems to pick as much
    # systems as possible
    if len(home_systems) < num_home_systems:
        print "Second attempt: trying to pick home systems from all systems"
        home_systems = find_home_systems(num_home_systems,
                                         [(systems, "complete pool")],
                                         min_jumps, 1)

    # check if the selection process delivered a list with enough home systems
    # if not, our galaxy obviously is too crowded, report an error and return an empty list
    if len(home_systems) < num_home_systems:
        report_error(
            "Python generate_home_system_list: requested %d homeworlds in a galaxy with %d systems"
            % (num_home_systems, len(systems)))
        return []

    # check if we got more home systems than we requested
    if len(home_systems) > num_home_systems:
        # yes: calculate the number of planets in the near vicinity of each system
        # and store that value with each system in a map
        hs_planets_in_vicinity_map = {
            s: calculate_home_system_merit(s)
            for s in home_systems
        }
        # sort the home systems by the number of planets in their near vicinity using the map
        # now only pick the number of home systems we need, taking those with the highest number of planets
        home_systems = sorted(home_systems,
                              key=hs_planets_in_vicinity_map.get,
                              reverse=True)[:num_home_systems]

    # make sure all our home systems have a "real" star (that is, a star that is not a neutron star, black hole,
    # or even no star at all) and at least one planet in it
    for home_system in home_systems:
        # if this home system has no "real" star, change star type to a randomly selected "real" star
        if fo.sys_get_star_type(home_system) not in star_types_real:
            star_type = random.choice(star_types_real)
            print "Home system", home_system, "has star type", fo.sys_get_star_type(home_system),\
                  ", changing that to", star_type
            fo.sys_set_star_type(home_system, star_type)

        # if this home system has no planets, create one in a random orbit
        # we take random values for type and size, as these will be set to suitable values later
        if not fo.sys_get_planets(home_system):
            print "Home system", home_system, "has no planets, adding one"
            planet = fo.create_planet(
                random.choice(planet_sizes_real),
                random.choice(planet_types_real), home_system,
                random.randint(0,
                               fo.sys_get_num_orbits(home_system) - 1), "")
            # if we couldn't create the planet, report an error and return an empty list
            if planet == fo.invalid_object():
                report_error(
                    "Python generate_home_system_list: couldn't create planet in home system"
                )
                return []

    # finally, check again if all home systems meet the criteria of having the required minimum number of planets
    # within their near vicinity, if not, add the missing number of planets
    print "Checking if home systems have the required minimum of planets within the near vicinity..."
    for home_system in home_systems:
        # calculate the number of missing planets, and add them if this number is > 0
        systems_in_vicinity = fo.systems_within_jumps_unordered(
            HS_VICINITY_RANGE, [home_system])
        num_systems_in_vicinity = len(systems_in_vicinity)
        num_planets_in_vicinity = count_planets_in_systems(systems_in_vicinity)
        num_planets_to_add = min_planets_in_vicinity_limit(
            num_systems_in_vicinity) - num_planets_in_vicinity
        print "Home system", home_system, "has", num_systems_in_vicinity, "systems and", num_planets_in_vicinity,\
            "planets in the near vicinity, required minimum:", min_planets_in_vicinity_limit(num_systems_in_vicinity)
        if num_planets_to_add > 0:
            systems_in_vicinity.remove(
                home_system
            )  # don't add planets to the home system, so remove it from the list
            # sort the systems_in_vicinity before adding, since the C++ engine doesn't guarrantee the same
            # platform independence as python.
            add_planets_to_vicinity(sorted(systems_in_vicinity),
                                    num_planets_to_add, gsd)

    # as we've sorted the home system list before, lets shuffle it to ensure random order and return
    random.shuffle(home_systems)
    return home_systems
Esempio n. 50
0
def compile_home_system_list(num_home_systems, systems, gsd):
    """
    Compiles a list with a requested number of home systems.
    """
    print "Compile home system list:", num_home_systems, "systems requested"

    # if the list of systems to choose home systems from is empty, report an error and return empty list
    if not systems:
        report_error("Python generate_home_system_list: no systems to choose from")
        return []

    # calculate an initial minimal number of jumps that the home systems should be apart,
    # based on the total number of systems to choose from and the requested number of home systems
    # don't let min_jumps be either:
    # a.) larger than a defined limit, because an unreasonably large number is really not at all needed,
    #     and with large galaxies an excessive amount of time can be used in failed attempts
    # b.) lower than the minimum jump distance limit that should be considered high priority (see options.py),
    #     otherwise no attempt at all would be made to enforce the other requirements for home systems (see below)
    min_jumps = min(HS_MAX_JUMP_DISTANCE_LIMIT, max(int(float(len(systems)) / float(num_home_systems * 2)),
                                                    HS_MIN_DISTANCE_PRIORITY_LIMIT))

    # home systems must have a certain minimum of systems and planets in their near vicinity
    # we will try to select our home systems from systems that match this criteria, if that fails, we will select our
    # home systems from all systems and add the missing number planets to the systems in their vicinity afterwards
    # the minimum system and planet limit and the jump range that defines the "near vicinity" are controlled by the
    # HS_* option constants in options.py (see there)

    # we start by building two additional pools of systems: one that contains all systems that match the criteria
    # completely (meets the min systems and planets limit), and one that contains all systems that match the criteria
    # at least partially (meets the min systems limit)
    pool_matching_sys_and_planet_limit = []
    pool_matching_sys_limit = []
    for system in systems:
        systems_in_vicinity = get_systems_within_jumps(system, HS_VICINITY_RANGE)
        if len(systems_in_vicinity) >= HS_MIN_SYSTEMS_IN_VICINITY:
            pool_matching_sys_limit.append(system)
            if count_planets_in_systems(systems_in_vicinity) >= min_planets_in_vicinity_limit(len(systems_in_vicinity)):
                pool_matching_sys_and_planet_limit.append(system)
    print len(pool_matching_sys_and_planet_limit), "systems meet the min systems and planets in the near vicinity limit"
    print len(pool_matching_sys_limit), "systems meet the min systems in the near vicinity limit"

    # now try to pick the requested number of home systems
    # we will do this by calling find_home_systems, which takes a list of tuples defining the pools from which to pick
    # the home systems; it will use the pools in the order in which they appear in the list, so put better pools first

    # we will make two attempts: the first one with the filtered pools we just created, and tell find_home_systems
    # to start with the min_jumps jumps distance we calculated above, but not to go lower than
    # HS_MIN_DISTANCE_PRIORITY_LIMIT

    print "First attempt: trying to pick home systems from the filtered pools of preferred systems"
    pool_list = [
        # the better pool is of course the one where all systems meet BOTH the min systems and planets limit
        (pool_matching_sys_and_planet_limit, "pool of systems that meet both the min systems and planets limit"),
        # next the less preferred pool where all systems at least meets the min systems limit
        # specify 0 as number of requested home systems to pick as much systems as possible
        (pool_matching_sys_limit, "pool of systems that meet at least the min systems limit"),
    ]
    home_systems = find_home_systems(num_home_systems, pool_list, min_jumps, HS_MIN_DISTANCE_PRIORITY_LIMIT)

    # check if the first attempt delivered a list with enough home systems
    # if not, we make our second attempt, this time disregarding the filtered pools and using all systems, starting
    # again with the min_jumps jump distance limit and specifying 0 as number of required home systems to pick as much
    # systems as possible
    if len(home_systems) < num_home_systems:
        print "Second attempt: trying to pick home systems from all systems"
        home_systems = find_home_systems(num_home_systems, [(systems, "complete pool")], min_jumps, 1)

    # check if the selection process delivered a list with enough home systems
    # if not, our galaxy obviously is too crowded, report an error and return an empty list
    if len(home_systems) < num_home_systems:
        report_error("Python generate_home_system_list: requested %d homeworlds in a galaxy with %d systems"
                     % (num_home_systems, len(systems)))
        return []

    # check if we got more home systems than we requested
    if len(home_systems) > num_home_systems:
        # yes: calculate the number of planets in the near vicinity of each system
        # and store that value with each system in a map
        hs_planets_in_vicinity_map = {s: count_planets_in_systems(get_systems_within_jumps(s, HS_VICINITY_RANGE))
                                      for s in home_systems}
        # sort the home systems by the number of planets in their near vicinity using the map
        # now only pick the number of home systems we need, taking those with the highest number of planets
        home_systems = sorted(home_systems, key=hs_planets_in_vicinity_map.get, reverse=True)[:num_home_systems]

    # make sure all our home systems have a "real" star (that is, a star that is not a neutron star, black hole,
    # or even no star at all) and at least one planet in it
    for home_system in home_systems:
        # if this home system has no "real" star, change star type to a randomly selected "real" star
        if fo.sys_get_star_type(home_system) not in star_types_real:
            star_type = random.choice(star_types_real)
            print "Home system", home_system, "has star type", fo.sys_get_star_type(home_system),\
                  ", changing that to", star_type
            fo.sys_set_star_type(home_system, star_type)

        # if this home system has no planets, create one in a random orbit
        # we take random values for type and size, as these will be set to suitable values later
        if not fo.sys_get_planets(home_system):
            print "Home system", home_system, "has no planets, adding one"
            planet = fo.create_planet(random.choice(planet_sizes_real),
                                      random.choice(planet_types_real),
                                      home_system, random.randint(0, fo.sys_get_num_orbits(home_system) - 1), "")
            # if we couldn't create the planet, report an error and return an empty list
            if planet == fo.invalid_object():
                report_error("Python generate_home_system_list: couldn't create planet in home system")
                return []

    # finally, check again if all home systems meet the criteria of having the required minimum number of planets
    # within their near vicinity, if not, add the missing number of planets
    print "Checking if home systems have the required minimum of planets within the near vicinity..."
    for home_system in home_systems:
        # calculate the number of missing planets, and add them if this number is > 0
        systems_in_vicinity = get_systems_within_jumps(home_system, HS_VICINITY_RANGE)
        num_systems_in_vicinity = len(systems_in_vicinity)
        num_planets_in_vicinity = count_planets_in_systems(systems_in_vicinity)
        num_planets_to_add = min_planets_in_vicinity_limit(num_systems_in_vicinity) - num_planets_in_vicinity
        print "Home system", home_system, "has", num_systems_in_vicinity, "systems and", num_planets_in_vicinity,\
            "planets in the near vicinity, required minimum:", min_planets_in_vicinity_limit(num_systems_in_vicinity)
        if num_planets_to_add > 0:
            systems_in_vicinity.remove(home_system)  # don't add planets to the home system, so remove it from the list
            add_planets_to_vicinity(systems_in_vicinity, num_planets_to_add, gsd)

    # as we've sorted the home system list before, lets shuffle it to ensure random order and return
    random.shuffle(home_systems)
    return home_systems
Esempio n. 51
0
def create_universe(psd_map):
    """
    Main universe generation function invoked from C++ code.
    """
    print "Python Universe Generator"

    # fetch universe and player setup data
    gsd = fo.get_galaxy_setup_data()
    total_players = len(psd_map)

    # initialize RNG
    seed_rng(gsd.seed)
    seed_pool = [random.random() for _ in range(100)]

    # make sure there are enough systems for the given number of players
    print "Universe creation requested with %d systems for %d players" % (
        gsd.size, total_players)
    size = max(gsd.size, (total_players * 3))
    if size > gsd.size:
        # gsd.size = size
        print "Too few systems for the requested number of players, number of systems adjusted accordingly"
    print "Creating universe with %d systems for %d players" % (size,
                                                                total_players)

    # calculate star system positions
    seed_rng(seed_pool.pop())
    system_positions = calc_star_system_positions(gsd.shape, size)
    size = len(system_positions)
    print gsd.shape, "Star system positions calculated, final number of systems:", size

    # generate and populate systems
    seed_rng(seed_pool.pop())
    systems = generate_systems(system_positions, gsd)
    print len(systems), "systems generated and populated"

    # generate Starlanes
    seed_rng(seed_pool.pop())
    fo.generate_starlanes(gsd.starlaneFrequency)
    print "Starlanes generated"

    print "Compile list of home systems..."
    seed_rng(seed_pool.pop())
    home_systems = compile_home_system_list(total_players, systems)
    if not home_systems:
        err_msg = "Python create_universe: couldn't get any home systems, ABORTING!"
        report_error(err_msg)
        raise Exception(err_msg)
    print "Home systems:", home_systems

    # set up empires for each player
    seed_rng(seed_pool.pop())
    for empire, psd, home_system in zip(psd_map.keys(), psd_map.values(),
                                        home_systems):
        if not setup_empire(empire, psd.empire_name, home_system,
                            psd.starting_species, psd.player_name):
            report_error(
                "Python create_universe: couldn't set up empire for player %s"
                % psd.player_name)

    # assign names to all star systems and their planets
    # this needs to be done after all systems have been generated and empire home systems have been set, as
    # only after all that is finished star types as well as planet sizes and types are fixed, and the naming
    # process depends on that
    print "Assign star system names"
    seed_rng(seed_pool.pop())
    name_star_systems(systems)
    print "Set planet names"
    for system in systems:
        name_planets(system)

    print "Generating Natives"
    seed_rng(seed_pool.pop())
    generate_natives(gsd.nativeFrequency, systems, home_systems)

    print "Generating Space Monsters"
    seed_rng(seed_pool.pop())
    generate_monsters(gsd.monsterFrequency, systems)

    print "Distributing Starting Specials"
    seed_rng(seed_pool.pop())
    distribute_specials(gsd.specialsFrequency, fo.get_all_objects())

    # finally, write some statistics to the log file
    print "############################################################"
    print "##             Universe generation statistics             ##"
    print "############################################################"
    statistics.log_planet_count_dist(systems)
    print "############################################################"
    statistics.log_planet_type_summary(systems)
    print "############################################################"
    statistics.log_species_summary()
    print "############################################################"
    statistics.log_monsters_summary()
    print "############################################################"
    statistics.log_specials_summary()
    print "############################################################"

    if error_list:
        print "Python Universe Generator completed with errors"
        return False
    else:
        print "Python Universe Generator completed successfully"
        return True
Esempio n. 52
0
def compile_home_system_list(num_home_systems, systems):
    """
    Compiles a list with a requested number of home systems.
    """

    # if the list of systems to choose home systems from is empty, report an error and return empty list
    if not systems:
        util.report_error(
            "Python generate_home_system_list: no systems to choose from")
        return []

    # calculate an initial minimal number of jumps that the home systems should be apart,
    # based on the total number of systems to choose from and the requested number of home systems
    min_jumps = max(int(float(len(systems)) / float(num_home_systems * 2)), 5)
    # try to find the home systems, decrease the min jumps until enough systems can be found, or the min jump distance
    # gets reduced to 0 (meaning we don't have enough systems to choose from at all)
    while min_jumps > 0:
        print "Trying to find", num_home_systems, "home systems that are at least", min_jumps, "jumps apart"
        # try to find home systems...
        home_systems = find_systems_with_min_jumps_between(
            num_home_systems, systems, min_jumps)
        # ...check if we got enough...
        if len(home_systems) >= num_home_systems:
            # ...yes, we got what we need, so let's break out of the loop
            break
        print "Home system min jump conflict: %d systems and %d empires, tried %d min jump and failed"\
              % (len(systems), num_home_systems, min_jumps)
        # ...no, decrease the min jump distance and try again
        min_jumps -= 1

    # check if the loop above delivered a list with enough home systems, or if it exited because the min jump distance
    # has been decreased to 0 without finding enough systems
    # in that case, our galaxy obviously is too crowded, report an error and return an empty list
    if len(home_systems) < num_home_systems:
        util.report_error(
            "Python generate_home_system_list: requested %d homeworlds in a galaxy with %d systems"
            % (num_home_systems, len(systems)))
        return []

    # make sure all our home systems have a "real" star (that is, a star that is not a neutron star, black hole,
    # or even no star at all) and at least one planet in it
    for home_system in home_systems:
        # if this home system has no "real" star, change star type to a randomly selected "real" star
        if fo.sys_get_star_type(
                home_system) not in starsystems.star_types_real:
            star_type = random.choice(starsystems.star_types_real)
            print "Home system", home_system, "has star type", fo.sys_get_star_type(home_system),\
                  ", changing that to", star_type
            fo.sys_set_star_type(home_system, star_type)

        # if this home system has no planets, create one in a random orbit
        # we take random values for type and size, as these will be set to suitable values later
        if not fo.sys_get_planets(home_system):
            print "Home system", home_system, "has no planets, adding one"
            planet = fo.create_planet(
                random.choice(planets.planet_sizes_real),
                random.choice(planets.planet_types_real), home_system,
                random.randint(0,
                               fo.sys_get_num_orbits(home_system) - 1), "")
            # if we couldn't create the planet, report an error and return an empty list
            if planet == fo.invalid_object():
                util.report_error(
                    "Python generate_home_system_list: couldn't create planet in home system"
                )
                return []

    return home_systems