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
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 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()])
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 not starting_species: print "No starting species set for player", player_name, ", picking one randomly" 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: util.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 starting_buildings.txt print "Player", player_name, ": add starting buildings to homeworld" for building in util.load_string_list("../starting_buildings.txt"): fo.create_building(building, homeworld, empire) # unlock starting techs, buildings, hulls, ship parts, etc. # use content file preunlocked_items.txt print "Player", player_name, ": add unlocked items" for item in fo.load_item_spec_list("preunlocked_items.txt"): 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 content file starting_fleets.txt print "Player", player_name, ": add starting fleets" fleet_plans = fo.load_fleet_plan_list("starting_fleets.txt") 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(): util.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(): util.report_error("Python setup empire: couldn't create ship %s for fleet %s" % (ship_design, fleet_plan.name())) return True