def handle_interfaces_mismatch(): """ Handle cases when AI and universe generation interfaces mismatch. """ try: import freeorion as fo universe = fo.get_universe() empire_of_first_ai = fo.get_empire(2) galaxy_data = fo.get_galaxy_setup_data() return fo, universe, empire_of_first_ai, galaxy_data except ImportError: pass try: import freeOrionAIInterface as fo universe = fo.getUniverse() empire_of_first_ai = fo.getEmpire(2) galaxy_data = fo.getGalaxySetupData() return fo, universe, empire_of_first_ai, galaxy_data except ImportError: pass
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
def inspect_universe_generation_interface(*args, **kwargs): import freeorion as fo tech = fo.getTech('LRN_NASCENT_AI') universe = fo.get_universe() empire = fo.get_empire(1) rules = fo.getGameRules() ship_hull = fo.getShipHull('SH_XENTRONIUM') species = fo.getSpecies('SP_ABADDONI') generate_stub( fo, instances=[ fo.getFieldType('FLD_ION_STORM'), fo.getBuildingType('BLD_SHIPYARD_BASE'), ship_hull, ship_hull.slots, fo.getShipPart('SR_WEAPON_1_1'), fo.getSpecial('MODERATE_TECH_NATIVES_SPECIAL'), species, fo.diplomaticMessage(1, 2, fo.diplomaticMessageType.acceptPeaceProposal), rules, tech, tech.unlockedItems, universe, universe.effectAccounting, universe.buildingIDs, fo.get_galaxy_setup_data(), empire, empire.colour, empire.productionQueue, empire.researchQueue, ], classes_to_ignore=( 'IntBoolMap', 'IntDblMap', 'IntFltMap', 'IntIntMap', 'IntPairVec', 'IntSetSet', 'MeterTypeAccountingInfoVecMap', 'MeterTypeMeterMap', 'MeterTypeStringPair', 'MonsterFleetPlan', 'PairIntInt_IntMap', 'RuleValueStringStringPair', 'ShipPartMeterMap', 'VisibilityIntMap', 'AccountingInfoVec', 'IntSet', 'StringSet', 'StringVec', ), path=".", dump=False, )
def log_species_summary(): num_empires = sum(empire_species.values()) num_species = len(fo.get_playable_species()) exp_count = num_empires // num_species print "Empire Starting Species Summary for %d Empires and %d playable species" % ( num_empires, num_species) print "Approximately %d to %d empires expected per species" % (max( 0, exp_count - 1), exp_count + 1) print "%-16s : # -- %%" % ("species") for species, count in empire_species.items(): if count: print "%-16s : %3d -- %5.1f%%" % (species, count, 100.0 * count / num_empires) print inverse_native_chance = fo.native_frequency( fo.get_galaxy_setup_data().nativeFrequency) native_chance = 1.0 / (1e-5 + inverse_native_chance) print "Natives Placement Summary (native frequency: %.1f%%)" % ( inverse_native_chance and (100 * native_chance)) # 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_potential_planet_total = sum( potential_native_planet_summary.values()) for species in species_summary: if species_summary[species] > 0: settleable_planets = 0 expectation_tally = 0.0 for p_type in natives.planet_types_for_natives[species]: settleable_planets += potential_native_planet_summary[p_type] expectation_tally += native_chance * 100.0 * potential_native_planet_summary[ p_type] / (1E-10 + len(natives.natives_for_planet_type[p_type])) expectation = expectation_tally / (1E-10 + settleable_planets) print "Settled natives %18s on %3d planets -- %5.1f%% of total and %5.1f%% vs %5.1f%% (actual vs expected) of %s planets" % \ (species, species_summary[species], 100.0 * species_summary[species] / (1E-10 + native_potential_planet_total), 100.0 * species_summary[species] / (1E-10 + settleable_planets), expectation, [str(p_t) for p_t in natives.planet_types_for_natives[species]]) print native_settled_planet_total = sum(settled_native_planet_summary.values()) print "Planet Type Summary for Native Planets (native frequency: %.1f%%)" % ( inverse_native_chance and (100 * native_chance)) print "%19s : %-s" % ("Potential (% of tot)", "Settled (% of potential)") print "%-13s %5d : %5d" % ("Totals", native_potential_planet_total, native_settled_planet_total) for planet_type, planet_count in potential_native_planet_summary.items(): settled_planet_count = settled_native_planet_summary.get( planet_type, 0) potential_percent = 100.0 * planet_count / ( 1E-10 + native_potential_planet_total) settled_percent = 100.0 * settled_planet_count / (1E-10 + planet_count) print "%-12s %5.1f%% : %5.1f%%" % (planet_type.name, potential_percent, settled_percent)
def log_monsters_summary(): print "Space Monsters Placement Summary" for monster, counter in monsters_summary: if counter > 0: print "Placed space monster", monster, counter, "times" print inverse_monster_chance = fo.monster_frequency(fo.get_galaxy_setup_data().monsterFrequency) monster_chance = 1.0 / (1e-5 + inverse_monster_chance) # the following loop depends on name mapping done in monsters.py print "Tracked Monster and Nest Summary (base monster freq: %4.1f%%)" % (100 * monster_chance) print "%-18s | %8s | %8s | %8s | %12s | %s" %\ ("Monster", "chance", "# tried", "# placed", "# valid sys locs", "# valid nest planet locs") for monster in tracked_monsters_summary: print "%-18s | %5.2f | %4d | %4d | %4d | %4d" % (monster, tracked_monsters_chance[monster], tracked_monsters_tries[monster], tracked_monsters_summary[monster], tracked_monsters_location_summary[monster], tracked_nest_location_summary[monster])
def log_monsters_summary(): print "Space Monsters Placement Summary" for monster, counter in monsters_summary: if counter > 0: print "Placed space monster", monster, counter, "times" print inverse_monster_chance = fo.monster_frequency( fo.get_galaxy_setup_data().monsterFrequency) monster_chance = 1.0 / (1e-5 + inverse_monster_chance) # the following loop depends on name mapping done in monsters.py print "Tracked Monster and Nest Summary (base monster freq: %4.1f%%)" % ( 100 * monster_chance) print "%-18s | %8s | %8s | %8s | %12s | %s" %\ ("Monster", "chance", "# tried", "# placed", "# valid sys locs", "# valid nest planet locs") for monster in tracked_monsters_summary: print "%-18s | %5.2f | %4d | %4d | %4d | %4d" % ( monster, tracked_monsters_chance[monster], tracked_monsters_tries[monster], tracked_monsters_summary[monster], tracked_monsters_location_summary[monster], tracked_nest_location_summary[monster])
def log_species_summary(): num_empires = sum(empire_species.values()) num_species = len(fo.get_playable_species()) exp_count = num_empires // num_species print "Empire Starting Species Summary for %d Empires and %d playable species" % (num_empires, num_species) print "Approximately %d to %d empires expected per species" % (max(0, exp_count - 1), exp_count + 1) print "%-16s : # -- %%" % ("species") for species, count in empire_species.items(): if count: print "%-16s : %3d -- %5.1f%%" % (species, count, 100.0 * count / num_empires) print inverse_native_chance = fo.native_frequency(fo.get_galaxy_setup_data().nativeFrequency) native_chance = 1.0 / (1e-5 + inverse_native_chance) print "Natives Placement Summary (native frequency: %.1f%%)" % (inverse_native_chance and (100 * native_chance)) # 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_potential_planet_total = sum(potential_native_planet_summary.values()) for species in species_summary: if species_summary[species] > 0: settleable_planets = 0 expectation_tally = 0.0 for p_type in natives.planet_types_for_natives[species]: settleable_planets += potential_native_planet_summary[p_type] expectation_tally += native_chance * 100.0 * potential_native_planet_summary[p_type] / (1E-10 + len(natives.natives_for_planet_type[p_type])) expectation = expectation_tally / (1E-10 + settleable_planets) print "Settled natives %18s on %3d planets -- %5.1f%% of total and %5.1f%% vs %5.1f%% (actual vs expected) of %s planets" % \ (species, species_summary[species], 100.0 * species_summary[species] / (1E-10 + native_potential_planet_total), 100.0 * species_summary[species] / (1E-10 + settleable_planets), expectation, [str(p_t) for p_t in natives.planet_types_for_natives[species]]) print native_settled_planet_total = sum(settled_native_planet_summary.values()) print "Planet Type Summary for Native Planets (native frequency: %.1f%%)" % (inverse_native_chance and (100 * native_chance)) print "%19s : %-s" % ("Potential (% of tot)", "Settled (% of potential)") print "%-13s %5d : %5d" % ("Totals", native_potential_planet_total, native_settled_planet_total) for planet_type, planet_count in potential_native_planet_summary.items(): settled_planet_count = settled_native_planet_summary.get(planet_type, 0) potential_percent = 100.0 * planet_count / (1E-10 + native_potential_planet_total) settled_percent = 100.0 * settled_planet_count / (1E-10 + planet_count) print "%-12s %5.1f%% : %5.1f%%" % (planet_type.name, potential_percent, settled_percent)
def inspect_universe_generation_interface(*args, **kwargs): import freeorion as fo tech = fo.getTech('LRN_ARTIF_MINDS') universe = fo.get_universe() empire = fo.get_empire(1) rules = fo.getGameRules() hull_type = fo.getHullType('SH_XENTRONIUM') species = fo.getSpecies('SP_ABADDONI') inspect( fo, instances=[ fo.getFieldType('FLD_ION_STORM'), fo.getBuildingType('BLD_SHIPYARD_BASE'), hull_type, hull_type.slots, fo.getPartType('SR_WEAPON_1_1'), fo.getSpecial('MODERATE_TECH_NATIVES_SPECIAL'), species, fo.diplomaticMessage(1, 2, fo.diplomaticMessageType.acceptPeaceProposal), rules, tech, tech.unlockedItems, rules.getRulesAsStrings, universe, universe.effectAccounting, universe.buildingIDs, fo.get_galaxy_setup_data(), empire, empire.colour, empire.productionQueue, empire.researchQueue, ], classes_to_ignore=( 'IntBoolMap', 'IntDblMap', 'IntFltMap', 'IntIntMap', 'IntPairVec', 'IntSetSet', 'MeterTypeAccountingInfoVecMap', 'MeterTypeMeterMap', 'MeterTypeStringPair', 'MonsterFleetPlan', 'PairIntInt_IntMap', 'RuleValueStringStringPair', 'ShipPartMeterMap', 'VisibilityIntMap', 'AccountingInfoVec', 'IntSet', 'StringSet', 'StringVec', ), path=".", )
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
def inspect_universe_generation(): """ Inspect function for universe generation interface. We have no way to run it without modifying of game code. To generate interface put call before return section of universe_generation.universe_generator.create_universe function """ import freeorion as fo techs = fo.techs() universe = fo.get_universe() planet_ids = universe.planetIDs system_ids = universe.systemIDs system = universe.getSystem(system_ids[0]) building_ids = universe.buildingIDs building = universe.getBuilding(building_ids[0]) empire_ids = fo.get_all_empires() empire = fo.get_empire(empire_ids[0]) fields_ids = universe.fieldIDs field = universe.getField(fields_ids[0]) fleets_ids = universe.fleetIDs fleet = universe.getFleet(fleets_ids[0]) tech = fo.getTech(techs[0]) unlocked_items = tech.unlockedItems ship = universe.getShip(list(fleet.shipIDs)[0]) # meter = ship.getMeter(fo.meterType.maxFuel) design = ship.design universe_object = universe.getObject(universe.systemIDs[0]) # fo.getHullType ? species = None special = None planets = [universe.getPlanet(pid) for pid in planet_ids] for planet in planets: species_name = planet.speciesName if species_name: species = fo.getSpecies(species_name) specials = list(planet.specials) if specials: special = fo.getSpecial(specials[0]) inspect( fo, instances=[ fo.get_galaxy_setup_data(), universe, planet_ids, universe.getPlanet(planet_ids[0]), system, techs, tech, tech.unlockedTechs, building, fo.getBuildingType(building.buildingTypeName), empire, field, fo.getFieldType(field.fieldTypeName), fleet, ship, # meter, design, fleet.shipIDs, # int set wtf? universe_object, system.starlanesWormholes, empire.systemSupplyRanges, empire.supplyProjections(), empire.obstructedStarlanes(), empire.planetsWithWastedPP, unlocked_items, species, special ], classes_to_ignore=( 'FleetPlan', 'GGColor', 'MonsterFleetPlan', 'PlayerSetupData', 'ShipPartMeterMap', 'ShipSlotVec', 'VisibilityIntMap', 'diplomaticMessage', 'diplomaticStatusUpdate', 'meter', ), path='') # fo.sys_get_star_type(system), # fo.planet_get_size(pid), # fo.planet_get_type(planet), # fo.species_get_planet_environment(species, planet_type), # fo.species_preferred_focus(species), # fo.getBuildingType(string) # fo.getFieldType(string) # fo.getHullType(string) # fo.getShipPart(string) # fo.getShipDesign(number) # fo.getSpecial(string) # fo.getSpecies(string) # fo.getTech(string) # fo.getTechCategories(obj) # fo.get_empire(number) # fo.planet_get_species(number) # fo.techsInCategory(string) exit(1)
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
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
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
def add_planets_to_vicinity(vicinity, num_planets): """ Adds the specified number of planets to the specified systems. """ print "Adding", num_planets, "planets to the following systems:", vicinity gsd = fo.get_galaxy_setup_data() # get galaxy setup data, we will need that later # 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 while star_type not in star_types_real: star_type = pick_star_type(gsd.age) # 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
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
def add_planets_to_vicinity(vicinity, num_planets): """ Adds the specified number of planets to the specified systems. """ print "Adding", num_planets, "planets to the following systems:", vicinity gsd = fo.get_galaxy_setup_data( ) # get galaxy setup data, we will need that later # 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 while star_type not in star_types_real: star_type = pick_star_type(gsd.age) # 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
def inspect_universe_generation(): """ Inspect function for universe generation interface. We have no way to run it without modifying of game code. To generate interface put call before return section of universe_generation.universe_generator.create_universe function """ import freeorion as fo techs = fo.techs() universe = fo.get_universe() planet_ids = universe.planetIDs system_ids = universe.systemIDs system = universe.getSystem(system_ids[0]) building_ids = universe.buildingIDs building = universe.getBuilding(building_ids[0]) empire_ids = fo.get_all_empires() empire = fo.get_empire(empire_ids[0]) fields_ids = universe.fieldIDs field = universe.getField(fields_ids[0]) fleets_ids = universe.fleetIDs fleet = universe.getFleet(fleets_ids[0]) tech = fo.getTech(techs[0]) unlocked_items = tech.unlockedItems ship = universe.getShip(list(fleet.shipIDs)[0]) # meter = ship.getMeter(fo.meterType.maxFuel) design = ship.design universe_object = universe.getObject(universe.systemIDs[0]) # fo.getHullType ? species = None special = None planets = [universe.getPlanet(pid) for pid in planet_ids] for planet in planets: species_name = planet.speciesName if species_name: species = fo.getSpecies(species_name) specials = list(planet.specials) if specials: special = fo.getSpecial(specials[0]) inspect( fo, instances=[ fo.get_galaxy_setup_data(), universe, planet_ids, universe.getPlanet(planet_ids[0]), system, techs, tech, tech.unlockedTechs, building, fo.getBuildingType(building.buildingTypeName), empire, field, fo.getFieldType(field.fieldTypeName), fleet, ship, # meter, design, fleet.shipIDs, # int set wtf? universe_object, system.starlanesWormholes, empire.systemSupplyRanges, empire.supplyProjections(), empire.obstructedStarlanes(), empire.planetsWithWastedPP, unlocked_items, species, special ], classes_to_ignore=( 'FleetPlan', 'GGColor', 'MonsterFleetPlan', 'PlayerSetupData', 'ShipPartMeterMap', 'ShipSlotVec', 'VisibilityIntMap', 'diplomaticMessage', 'diplomaticStatusUpdate', 'meter', ), path='' ) # fo.sys_get_star_type(system), # fo.planet_get_size(pid), # fo.planet_get_type(planet), # fo.species_get_planet_environment(species, planet_type), # fo.species_preferred_focus(species), # fo.getBuildingType(string) # fo.getFieldType(string) # fo.getHullType(string) # fo.getPartType(string) # fo.getShipDesign(number) # fo.getSpecial(string) # fo.getSpecies(string) # fo.getTech(string) # fo.getTechCategories(obj) # fo.get_empire(number) # fo.planet_get_species(number) # fo.techsInCategory(string) exit(1)
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(gsd.seed) 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()) # set game uid empire_names = [] for psd in psd_map.values(): empire_names.append(psd.empire_name) empire_names.sort() for i, v in enumerate(empire_names): empire_names[i] = v.capitalize()[:2] fo.get_galaxy_setup_data().gameUID = "".join(empire_names) + str(random.randint(0, 999)).zfill(3) print "Game UID %s" % fo.get_galaxy_setup_data().gameUID # 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