Example #1
0
def place_special(specials, obj):
    """
    Place at most a single special.
    Return the number of specials placed.
    """
    # Calculate the conditional probabilities that each special is
    # placed here given that a special will be placed here.
    probs = [fo.special_spawn_rate(sp) for sp in specials]
    total_prob = float(sum(probs))
    if total_prob == 0:
        # This shouldn't happen since special_spawn_rate > 0.0 is checked in distribute_specials()
        return 0
    thresholds = [x / total_prob for x in probs]

    chance = random.random()
    for threshold, special in zip(thresholds, specials):
        if chance > threshold:
            chance -= threshold
            continue

        fo.add_special(obj, special)
        print "Special", special, "added to", fo.get_name(obj)
        universe_statistics.specials_summary[special] += 1

        return 1
    return 0
Example #2
0
def place_special(specials, obj):
    """
    Place at most a single special.
    Return the number of specials placed.
    """
    # Calculate the conditional probabilities that each special is
    # placed here given that a special will be placed here.
    probs = [fo.special_spawn_rate(sp) for sp in specials]
    total_prob = float(sum(probs))
    if total_prob == 0:
        # This shouldn't happen since special_spawn_rate > 0.0 is checked in distribute_specials()
        return 0
    thresholds = [x / total_prob for x in probs]

    chance = random.random()
    for threshold, special in zip(thresholds, specials):
        if chance > threshold:
            chance -= threshold
            continue

        fo.add_special(obj, special)
        print("Special", special, "added to", fo.get_name(obj))
        universe_statistics.specials_summary[special] += 1

        return 1
    return 0
Example #3
0
def execute_turn_events():
    print "Executing turn events for turn", fo.current_turn()

    # creating fields
    systems = fo.get_systems()
    radius = fo.get_universe_width() / 2.0
    if random() < max(0.0003 * radius, 0.03):
        if random() < 0.4:
            field_type = "FLD_MOLECULAR_CLOUD"
            size = 5.0
        else:
            field_type = "FLD_ION_STORM"
            size = 5.0

        x = y = radius
        dist_from_center = 0.0
        while (dist_from_center < radius) or any(hypot(fo.get_x(s) - x, fo.get_y(s) - y) < 50.0 for s in systems):
            angle = random() * 2.0 * pi
            dist_from_center = radius + uniform(min(max(radius * 0.02, 10), 50.0), min(max(radius * 0.05, 20), 100.0))
            x = radius + (dist_from_center * sin(angle))
            y = radius + (dist_from_center * cos(angle))

        print "...creating new", field_type, "field, at distance", dist_from_center, "from center"
        if fo.create_field(field_type, x, y, size) == fo.invalid_object():
            print >> sys.stderr, "Turn events: couldn't create new field"

    # creating monsters
    gsd = fo.get_galaxy_setup_data()
    monster_freq = MONSTER_FREQUENCY[gsd.monsterFrequency]
    # monster freq ranges from 30 (= one monster per 30 systems) to 3 (= one monster per 3 systems)
    # (example: low monsters and 150 Systems results in 150 / 30 * 0.001 = 0.005)
    if monster_freq > 0 and random() < len(systems) / monster_freq * 0.001:
        #only spawn Krill at the moment, other monsters can follow in the future
        if random() < 1:
            monster_type = "SM_KRILL_1"
        else:
            monster_type = "SM_FLOATER"

        # search for systems without planets or fleets
        candidates = [s for s in systems if len(fo.sys_get_planets(s)) <= 0 and len(fo.sys_get_fleets(s)) <= 0]
        if not candidates:
            print >> sys.stderr, "Turn events: unable to find system for monster spawn"
        else:
            system = choice(candidates)
            print "...creating new", monster_type, "at", fo.get_name(system)

            # create monster fleet
            monster_fleet = fo.create_monster_fleet(system)
            # if fleet creation fails, report an error
            if monster_fleet == fo.invalid_object():
                print >> sys.stderr, "Turn events: unable to create new monster fleet"
            else:
                # create monster, if creation fails, report an error
                monster = fo.create_monster(monster_type, monster_fleet)
                if monster == fo.invalid_object():
                    print >> sys.stderr, "Turn events: unable to create monster in fleet"

    return True
Example #4
0
def name_planets(system):
    """
    Sets the names of the planets of the specified system.

    Planet name is system name + planet number (as roman number)
    unless it's an asteroid belt, in that case name is system
    name + 'asteroid belt' (localized).
    """
    # iterate over all planets in the system
    sys_name = fo.get_name(system)
    for planet in fo.sys_get_planets(system):
        name = fo.user_string("NEW_PLANET_NAME")
        name = name.replace("%1%", sys_name)
        name = name.replace("%2%", fo.planet_cardinal_suffix(planet))
        fo.set_name(planet, name)
Example #5
0
def name_planets(system):
    """
    Sets the names of the planets of the specified system.

    Planet name is system name + planet number (as roman number)
    unless it's an asteroid belt, in that case name is system
    name + 'asteroid belt' (localized).
    """
    planet_number = 1
    # iterate over all planets in the system
    for planet in fo.sys_get_planets(system):
        # use different naming methods for "normal" planets and asteroid belts
        if fo.planet_get_type(planet) == fo.planetType.asteroids:
            # get localized text from stringtable
            name = fo.user_string("PL_ASTEROID_BELT_OF_SYSTEM")
            # %1% parameter in the localized string is the system name
            name = name.replace("%1%", fo.get_name(system))
        else:
            # set name to system name + planet number as roman number...
            name = fo.get_name(system) + " " + fo.roman_number(planet_number)
            # ...and increase planet number
            planet_number += 1
        # do the actual renaming
        fo.set_name(planet, name)
Example #6
0
def name_planets(system):
    """
    Sets the names of the planets of the specified system.

    Planet name is system name + planet number (as roman number)
    unless it's an asteroid belt, in that case name is system
    name + 'asteroid belt' (localized).
    """
    planet_number = 1
    # iterate over all planets in the system
    for planet in fo.sys_get_planets(system):
        # use different naming methods for "normal" planets and asteroid belts
        if fo.planet_get_type(planet) == fo.planetType.asteroids:
            # get localized text from stringtable
            name = fo.user_string("PL_ASTEROID_BELT_OF_SYSTEM")
            # %1% parameter in the localized string is the system name
            name = name.replace("%1%", fo.get_name(system))
        else:
            # set name to system name + planet number as roman number...
            name = fo.get_name(system) + " " + fo.roman_number(planet_number)
            # ...and increase planet number
            planet_number += 1
        # do the actual renaming
        fo.set_name(planet, name)
Example #7
0
def name_planets(system):
    """
    Sets the names of the planets of the specified system.

    Planet name is system name + planet number (as roman number)
    unless it's an asteroid belt, in that case name is system
    name + 'asteroid belt' (localized).
    """
    # iterate over all planets in the system
    sys_name = fo.get_name(system)
    for planet in fo.sys_get_planets(system):
        name = fo.user_string("NEW_PLANET_NAME")
        name = name.replace("%1%", sys_name)
        name = name.replace("%2%", fo.planet_cardinal_suffix(planet))
        fo.set_name(planet, name)
Example #8
0
def populate_monster_fleet(fleet_plan, system):
    """
    Create a monster fleet in ''system'' according to ''fleet_plan''
    """

    # create monster fleet
    monster_fleet = fo.create_monster_fleet(system)

    if monster_fleet == fo.invalid_object():
        raise MapGenerationError("Python generate_monsters: unable to create new monster fleet %s" % fleet_plan.name())

    # add monsters to fleet
    for design in fleet_plan.ship_designs():
        if fo.create_monster(design, monster_fleet) == fo.invalid_object():
            raise MapGenerationError("Python generate_monsters: unable to create monster %s" % design)

    print "Spawn", fleet_plan.name(), "at", fo.get_name(system)
Example #9
0
def populate_monster_fleet(fleet_plan, system):
    """
    Create a monster fleet in ''system'' according to ''fleet_plan''
    """

    # create monster fleet
    monster_fleet = fo.create_monster_fleet(system)

    if monster_fleet == fo.invalid_object():
        raise MapGenerationError("Python generate_monsters: unable to create new monster fleet %s"
                                 % fleet_plan.name())

    # add monsters to fleet
    for design in fleet_plan.ship_designs():
        if fo.create_monster(design, monster_fleet) == fo.invalid_object():
            raise MapGenerationError("Python generate_monsters: unable to create monster %s" % design)

    print "Spawn", fleet_plan.name(), "at", fo.get_name(system)
Example #10
0
def generate_natives(native_freq, systems, empire_home_systems):
    """
    Adds non-empire-affiliated native populations to planets.
    """

    # first, calculate the chance for natives on a planet based on the native frequency that has been passed
    # get the corresponding value for the specified natives frequency from the universe tables
    inverse_native_chance = fo.native_frequency(native_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 natives, in this case return immediately
    if inverse_native_chance <= 0:
        return
    native_chance = 1.0 / float(inverse_native_chance)

    # compile a list of planets where natives can be placed
    # select only planets sufficiently far away from player home systems
    native_safe_planets = []  # list of planets safe for natives
    for candidate in systems:
        if not is_too_close_to_empire_home_systems(candidate, empire_home_systems):
            # this system is sufficiently far away from all player homeworlds, so add it's planets to our list
            native_safe_planets += fo.sys_get_planets(candidate)
    print "Number of planets far enough from players for natives to be allowed:", len(native_safe_planets)
    # if there are no "native safe" planets at all, we can stop here
    if not native_safe_planets:
        return

    # get all native species
    native_species = fo.get_native_species()
    print "Species that can be added as natives:"
    print "... " + "\n... ".join(native_species)

    # create a map with a list for each planet type containing the species
    # for which this planet type is a good environment
    # we will need this afterwards when picking natives for a planet
    natives_for_planet_type.clear()  # just to be safe
    natives_for_planet_type.update( {planet_type: [] for planet_type in planets.planet_types} )
    planet_types_for_natives.clear()
    planet_types_for_natives.update( {species: set() for species in native_species} )
    # iterate over all native species we got
    for species in native_species:
        # check the planet environment for all planet types for this species
        for planet_type in planets.planet_types:
            # if this planet type is a good environment for the species, add it to the list for this planet type
            if fo.species_get_planet_environment(species, planet_type) == fo.planetEnvironment.good:
                natives_for_planet_type[planet_type].append(species)
                planet_types_for_natives[species].add(planet_type)

    # randomly add species to planets
    # iterate over the list of "native safe" planets we compiled earlier
    for candidate in native_safe_planets:
        # select a native species to put on this planet
        planet_type = fo.planet_get_type(candidate)
        # check if we have any native species that like this planet type
        if not natives_for_planet_type[planet_type]:
            # no, continue with next planet
            continue
        statistics.potential_native_planet_summary[planet_type] += 1
        # make a "roll" against the chance for natives to determine if we shall place natives on this planet
        if random.random() > native_chance:
            # no, continue with next planet
            continue
        statistics.settled_native_planet_summary[planet_type] += 1

        # randomly pick one of the native species available for this planet type
        natives = random.choice(natives_for_planet_type[planet_type])

        # put the selected natives on the planet
        fo.planet_set_species(candidate, natives)
        # set planet as homeworld for that species
        fo.species_add_homeworld(natives, candidate)
        # set planet focus
        # check if the preferred focus for the native species is among the foci available on this planet
        available_foci = fo.planet_available_foci(candidate)
        preferred_focus = fo.species_preferred_focus(natives)
        if preferred_focus in available_foci:
            # if yes, set the planet focus to the preferred focus
            fo.planet_set_focus(candidate, preferred_focus)
        elif available_foci:
            # if no, and there is at least one available focus, just take the first of the list
            # otherwise don't set any focus
            fo.planet_set_focus(candidate, available_foci[0])
        print "Added native", natives, "to planet", fo.get_name(candidate)

        # increase the statistics counter for this native species, so a species summary can be dumped to the log later
        statistics.species_summary[natives] += 1
Example #11
0
def distribute_specials(specials_freq, universe_objects):
    """
    Adds start-of-game specials to universe objects.
    """

    # get basic chance for occurrence of specials from the universe tables
    # the values there are integers, so we have to divide them by 10,000 to get the actual basic probability value
    basic_chance = float(fo.specials_frequency(specials_freq)) / 10000.0
    if basic_chance <= 0:
        return

    # get a list with all specials that have a spawn rate and limit both > 0 and a location condition defined
    # (no location condition means a special shouldn't get added at game start)
    specials = [
        sp for sp in fo.get_all_specials() if fo.special_spawn_rate(sp) > 0.0
        and fo.special_spawn_limit(sp) > 0 and fo.special_has_location(sp)
    ]
    if not specials:
        return
    # dump a list of all specials meeting that conditions and their properties to the log
    print "Specials available for distribution at game start:"
    for special in specials:
        print "...", special, ": spawn rate", fo.special_spawn_rate(special),\
              "/ spawn limit", fo.special_spawn_limit(special)

    # attempt to apply a special to each universe object in the list that has been passed to this function
    # by finding a special that can be applied to it and hasn't been added too many times, and then attempt
    # to add that special by testing its spawn rate
    repeat_rate = {1: 0.08, 2: 0.05, 3: 0.01, 4: 0.00}
    for univ_obj in universe_objects:
        # for this universe object, find a suitable special
        # start by shuffling our specials list, so each time the specials are considered in a new random order
        random.shuffle(specials)
        num_here = 0

        # then, consider each special until one has been found or we run out of specials
        # (the latter case means that no special is added to this universe object)
        for special in specials:
            # check if the spawn limit for this special has already been reached (that is, if this special
            # has already been added the maximal allowed number of times)
            if statistics.specials_summary[special] >= fo.special_spawn_limit(
                    special):
                # if yes, consider next special
                continue

            # check if this universe object matches the location condition for this special
            # (meaning, if this special can be added to this universe object at all)
            if not fo.special_location(special, univ_obj):
                # if not, consider next special
                continue

            # we have found a special that meets all prerequisites
            # now do the test if we want to add the selected special to this universe object by making a roll against
            # the basic probability multiplied by the spawn rate of the special
            if random.random() > basic_chance * fo.special_spawn_rate(special):
                # no, test failed, break out of the specials loop and continue with the next universe object
                statistics.specials_repeat_dist[num_here] += 1
                break
            num_here += 1

            # all prerequisites and the test have been met, now add this special to this universe object
            fo.add_special(univ_obj, special)
            # increase the statistic counter for this special, so we can keep track of how often it has already
            # been added (needed for the spawn limit test above, and to dump some statistics to the log later)
            statistics.specials_summary[special] += 1
            print "Special", special, "added to", fo.get_name(univ_obj)

            # stop attempting to add specials here?  give a small chance to try more than one special
            if random.random() > repeat_rate.get(num_here, 0.0):
                # sorry, no, break out of the specials loop and continue with the next universe object
                statistics.specials_repeat_dist[num_here] += 1
                break
        else:
            statistics.specials_repeat_dist[num_here] += 1
Example #12
0
def generate_natives(native_freq, systems, empire_home_systems):
    """
    Adds non-empire-affiliated native populations to planets.
    """

    # first, calculate the chance for natives on a planet based on the native frequency that has been passed
    # get the corresponding value for the specified natives frequency from the universe tables
    native_chance = universe_tables.NATIVE_FREQUENCY[native_freq]
    # a value of 0 means no natives, in this case return immediately
    if native_chance <= 0:
        return

    # compile a list of planets where natives can be placed
    # select only planets sufficiently far away from player home systems
    # list of planets safe for natives
    EMPIRE_TO_NATIVE_MIN_DIST = 2
    empire_exclusions = set(
        itertools.chain.from_iterable(
            fo.systems_within_jumps_unordered(EMPIRE_TO_NATIVE_MIN_DIST, [e])
            for e in empire_home_systems))
    native_safe_planets = set(
        itertools.chain.from_iterable([
            fo.sys_get_planets(s) for s in systems
            if s not in empire_exclusions
        ]))

    print(
        "Number of planets far enough from players for natives to be allowed:",
        len(native_safe_planets))
    # if there are no "native safe" planets at all, we can stop here
    if not native_safe_planets:
        return

    # get all native species
    native_species = fo.get_native_species()
    print("Species that can be added as natives:")
    print("... " + "\n... ".join(native_species))

    # create a map with a list for each planet type containing the species
    # for which this planet type is a good environment
    # we will need this afterwards when picking natives for a planet
    natives_for_planet_type.clear()  # just to be safe
    natives_for_planet_type.update(
        {planet_type: []
         for planet_type in planets.planet_types})
    planet_types_for_natives.clear()
    planet_types_for_natives.update(
        {species: set()
         for species in native_species})
    # iterate over all native species we got
    for species in native_species:
        # check the planet environment for all planet types for this species
        for planet_type in planets.planet_types:
            # if this planet type is a good environment for the species, add it to the list for this planet type
            if fo.species_get_planet_environment(
                    species, planet_type) == fo.planetEnvironment.good:
                natives_for_planet_type[planet_type].append(species)
                planet_types_for_natives[species].add(planet_type)

    # randomly add species to planets
    # iterate over the list of "native safe" planets we compiled earlier
    for candidate in native_safe_planets:
        # select a native species to put on this planet
        planet_type = fo.planet_get_type(candidate)
        # check if we have any native species that like this planet type
        if not natives_for_planet_type[planet_type]:
            # no, continue with next planet
            continue
        universe_statistics.potential_native_planet_summary[planet_type] += 1
        # make a "roll" against the chance for natives to determine if we shall place natives on this planet
        if random.random() > native_chance:
            # no, continue with next planet
            continue
        universe_statistics.settled_native_planet_summary[planet_type] += 1

        # randomly pick one of the native species available for this planet type
        natives = random.choice(natives_for_planet_type[planet_type])

        # put the selected natives on the planet
        fo.planet_set_species(candidate, natives)
        # set planet as homeworld for that species
        fo.species_add_homeworld(natives, candidate)
        # set planet focus
        # check if the preferred focus for the native species is among the foci available on this planet
        available_foci = fo.planet_available_foci(candidate)
        preferred_focus = fo.species_preferred_focus(natives)
        if preferred_focus in available_foci:
            # if yes, set the planet focus to the preferred focus
            fo.planet_set_focus(candidate, preferred_focus)
        elif available_foci:
            # if no, and there is at least one available focus, just take the first of the list
            # otherwise don't set any focus
            fo.planet_set_focus(candidate, available_foci[0])
        print("Added native", natives, "to planet", fo.get_name(candidate))

        # increase the statistics counter for this native species, so a species summary can be dumped to the log later
        universe_statistics.species_summary[natives] += 1
Example #13
0
def execute_turn_events():
    print "Executing turn events for turn", fo.current_turn()

    # creating fields
    systems = fo.get_systems()
    radius = fo.get_universe_width() / 2.0
    if random() < max(0.0003 * radius, 0.03):
        if random() < 0.4:
            field_type = "FLD_MOLECULAR_CLOUD"
            size = 5.0
        else:
            field_type = "FLD_ION_STORM"
            size = 5.0

        x = y = radius
        dist_from_center = 0.0
        while (dist_from_center < radius) or any(
                hypot(fo.get_x(s) - x,
                      fo.get_y(s) - y) < 50.0 for s in systems):
            angle = random() * 2.0 * pi
            dist_from_center = radius + uniform(
                min(max(radius * 0.02, 10), 50.0),
                min(max(radius * 0.05, 20), 100.0))
            x = radius + (dist_from_center * sin(angle))
            y = radius + (dist_from_center * cos(angle))

        print "...creating new", field_type, "field, at distance", dist_from_center, "from center"
        if fo.create_field(field_type, x, y, size) == fo.invalid_object():
            print >> sys.stderr, "Turn events: couldn't create new field"

    # creating monsters
    gsd = fo.get_galaxy_setup_data()
    monster_freq = MONSTER_FREQUENCY[gsd.monsterFrequency]
    # monster freq ranges from 1/30 (= one monster per 30 systems) to 1/3 (= one monster per 3 systems)
    # (example: low monsters and 150 Systems results in 150 / 30 * 0.01 = 0.05)
    if monster_freq > 0 and random() < len(systems) * monster_freq * 0.01:
        #only spawn Krill at the moment, other monsters can follow in the future
        if random() < 1:
            monster_type = "SM_KRILL_1"
        else:
            monster_type = "SM_FLOATER"

        # search for systems without planets or fleets
        candidates = [
            s for s in systems if len(fo.sys_get_planets(s)) <= 0
            and len(fo.sys_get_fleets(s)) <= 0
        ]
        if not candidates:
            print >> sys.stderr, "Turn events: unable to find system for monster spawn"
        else:
            system = choice(candidates)
            print "...creating new", monster_type, "at", fo.get_name(system)

            # create monster fleet
            monster_fleet = fo.create_monster_fleet(system)
            # if fleet creation fails, report an error
            if monster_fleet == fo.invalid_object():
                print >> sys.stderr, "Turn events: unable to create new monster fleet"
            else:
                # create monster, if creation fails, report an error
                monster = fo.create_monster(monster_type, monster_fleet)
                if monster == fo.invalid_object():
                    print >> sys.stderr, "Turn events: unable to create monster in fleet"

    return True
Example #14
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()
    ])
Example #15
0
def distribute_specials(specials_freq, universe_objects):
    """
    Adds start-of-game specials to universe objects.
    """

    # get basic chance for occurrence of specials from the universe tables
    # the values there are integers, so we have to divide them by 10,000 to get the actual basic probability value
    basic_chance = float(fo.specials_frequency(specials_freq)) / 10000.0
    if basic_chance <= 0:
        return

    # get a list with all specials that have a spawn rate and limit both > 0 and a location condition defined
    # (no location condition means a special shouldn't get added at game start)
    specials = [sp for sp in fo.get_all_specials() if fo.special_spawn_rate(sp) > 0.0 and
                fo.special_spawn_limit(sp) > 0 and fo.special_has_location(sp)]
    if not specials:
        return
    # dump a list of all specials meeting that conditions and their properties to the log
    print "Specials available for distribution at game start:"
    for special in specials:
        print "...", special, ": spawn rate", fo.special_spawn_rate(special),\
              "/ spawn limit", fo.special_spawn_limit(special)

    # attempt to apply a special to each universe object in the list that has been passed to this function
    # by finding a special that can be applied to it and hasn't been added too many times, and then attempt
    # to add that special by testing its spawn rate
    repeat_rate = {1 : 0.08, 2 : 0.05, 3 : 0.01, 4 : 0.00}
    for univ_obj in universe_objects:
        # for this universe object, find a suitable special
        # start by shuffling our specials list, so each time the specials are considered in a new random order
        random.shuffle(specials)
        num_here = 0

        # then, consider each special until one has been found or we run out of specials
        # (the latter case means that no special is added to this universe object)
        for special in specials:
            # check if the spawn limit for this special has already been reached (that is, if this special
            # has already been added the maximal allowed number of times)
            if statistics.specials_summary[special] >= fo.special_spawn_limit(special):
                # if yes, consider next special
                continue

            # check if this universe object matches the location condition for this special
            # (meaning, if this special can be added to this universe object at all)
            if not fo.special_location(special, univ_obj):
                # if not, consider next special
                continue

            # we have found a special that meets all prerequisites
            # now do the test if we want to add the selected special to this universe object by making a roll against
            # the basic probability multiplied by the spawn rate of the special
            if random.random() > basic_chance * fo.special_spawn_rate(special):
                # no, test failed, break out of the specials loop and continue with the next universe object
                statistics.specials_repeat_dist[num_here] += 1
                break
            num_here += 1

            # all prerequisites and the test have been met, now add this special to this universe object
            fo.add_special(univ_obj, special)
            # increase the statistic counter for this special, so we can keep track of how often it has already
            # been added (needed for the spawn limit test above, and to dump some statistics to the log later)
            statistics.specials_summary[special] += 1
            print "Special", special, "added to", fo.get_name(univ_obj)

            # stop attempting to add specials here?  give a small chance to try more than one special
            if random.random() > repeat_rate.get(num_here, 0.0):
                # sorry, no, break out of the specials loop and continue with the next universe object
                statistics.specials_repeat_dist[num_here] += 1
                break
        else:
                statistics.specials_repeat_dist[num_here] += 1
Example #16
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 = 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 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

    # 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 in fleet_plans if spawn_limits[fp] 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
        spawn_limits[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 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()])
Example #17
0
def execute_turn_events():
    print("Executing turn events for turn", fo.current_turn())

    # creating fields
    systems = fo.get_systems()
    radius = fo.get_universe_width() / 2.0
    field_types = [
        "FLD_MOLECULAR_CLOUD", "FLD_ION_STORM", "FLD_NANITE_SWARM",
        "FLD_METEOR_BLIZZARD", "FLD_VOID_RIFT"
    ]

    if random() < max(0.00015 * radius, 0.03):
        field_type = choice(field_types)
        size = 5.0
        x = y = radius
        dist_from_center = uniform(0.35, 1.0) * radius
        angle = random() * 2.0 * pi
        x = radius + (dist_from_center * sin(angle))
        y = radius + (dist_from_center * cos(angle))

        print("...creating new", field_type, "field, at distance",
              dist_from_center, "from center")
        if fo.create_field(field_type, x, y, size) == fo.invalid_object():
            print("Turn events: couldn't create new field", file=sys.stderr)

    # creating monsters
    gsd = fo.get_galaxy_setup_data()
    monster_freq = MONSTER_FREQUENCY[gsd.monsterFrequency]
    # monster freq ranges from 1/30 (= one monster per 30 systems) to 1/3 (= one monster per 3 systems)
    # (example: low monsters and 150 Systems results in 150 / 30 * 0.01 = 0.05)
    if monster_freq > 0 and random() < len(systems) * monster_freq * 0.01:
        # only spawn Krill at the moment, other monsters can follow in the future
        if random() < 1:
            monster_type = "SM_KRILL_1"
        else:
            monster_type = "SM_FLOATER"

        # search for systems without planets or fleets
        candidates = [
            s for s in systems if len(fo.sys_get_planets(s)) <= 0
            and len(fo.sys_get_fleets(s)) <= 0
        ]
        if not candidates:
            print("Turn events: unable to find system for monster spawn",
                  file=sys.stderr)
        else:
            system = choice(candidates)
            print("...creating new", monster_type, "at", fo.get_name(system))

            # create monster fleet
            monster_fleet = fo.create_monster_fleet(system)
            # if fleet creation fails, report an error
            if monster_fleet == fo.invalid_object():
                print("Turn events: unable to create new monster fleet",
                      file=sys.stderr)
            else:
                # create monster, if creation fails, report an error
                monster = fo.create_monster(monster_type, monster_fleet)
                if monster == fo.invalid_object():
                    print("Turn events: unable to create monster in fleet",
                          file=sys.stderr)

    return True