def survey_universe(): survey_timer.start("Categorizing Visible Planets") universe = fo.getUniverse() empire_id = fo.empireID() current_turn = fo.currentTurn() # set up / reset various variables; the 'if' is purely for code folding convenience if True: AIstate.empireStars.clear() empire_metabolisms.clear() active_growth_specials.clear() # var setup done aistate = get_aistate() for sys_id in universe.systemIDs: system = universe.getSystem(sys_id) if not system: continue local_ast = False local_gg = False empire_has_qualifying_planet = False if sys_id in AIstate.colonyTargetedSystemIDs: empire_has_qualifying_planet = True for pid in system.planetIDs: planet = universe.getPlanet(pid) if not planet: continue if pid in aistate.colonisablePlanetIDs: empire_has_qualifying_planet = True if planet.size == fo.planetSize.asteroids: local_ast = True elif planet.size == fo.planetSize.gasGiant: local_gg = True spec_name = planet.speciesName this_spec = fo.getSpecies(spec_name) owner_id = planet.owner planet_population = planet.currentMeterValue( fo.meterType.population) buildings_here = [ universe.getBuilding(bldg).buildingTypeName for bldg in planet.buildingIDs ] weapons_grade = "WEAPONS_0.0" if owner_id == empire_id: if planet_population > 0.0 and this_spec: empire_has_qualifying_planet = True for metab in [ tag for tag in this_spec.tags if tag in AIDependencies.metabolismBoostMap ]: empire_metabolisms[metab] = empire_metabolisms.get( metab, 0.0) + planet.habitableSize if this_spec.canProduceShips: pilot_val = rate_piloting_tag(spec_name) if spec_name == "SP_ACIREMA": pilot_val += 1 weapons_grade = "WEAPONS_%.1f" % pilot_val set_pilot_rating_for_planet(pid, pilot_val) yard_here = [] if "BLD_SHIPYARD_BASE" in buildings_here: set_ship_builders(spec_name, pid) yard_here = [pid] if this_spec.canColonize and planet.currentMeterValue( fo.meterType.targetPopulation) >= 3: set_colony_builders(spec_name, yard_here) set_building_locations(weapons_grade, buildings_here, pid) for special in planet.specials: if special_is_nest(special): set_have_nest() if special in AIDependencies.metabolismBoosts: set_growth_special(special, pid) if planet.focus == FocusType.FOCUS_GROWTH: active_growth_specials.setdefault(special, []).append(pid) elif owner_id != -1: if get_partial_visibility_turn( pid ) >= current_turn - 1: # only interested in immediately recent data aistate.misc.setdefault("enemies_sighted", {}).setdefault(current_turn, []).append(pid) if empire_has_qualifying_planet: if local_ast: set_have_asteroids() elif local_gg: set_have_gas_giant() if sys_id in get_owned_planets(): AIstate.empireStars.setdefault(system.starType, []).append(sys_id) sys_status = aistate.systemStatus.setdefault(sys_id, {}) if sys_status.get("fleetThreat", 0) > 0: set_colonies_is_under_attack() if sys_status.get("neighborThreat", 0) > 0: set_colonies_is_under_treat() survey_universe_lock.unlock() survey_timer.stop() # lock must be released before this, since it uses the locked functions _print_empire_species_roster()
def _calculate_military_priority(): """Calculates the demand for military ships by military targeted systems.""" global unmetThreat universe = fo.getUniverse() capital_id = PlanetUtilsAI.get_capital() if capital_id is None or capital_id == INVALID_ID: return 0 # no capitol (not even a capitol-in-the-making), means can't produce any ships have_l1_weaps = (tech_is_complete("SHP_WEAPON_1_4") or (tech_is_complete("SHP_WEAPON_1_3") and tech_is_complete("SHP_MIL_ROBO_CONT")) or tech_is_complete("SHP_WEAPON_2_1") or tech_is_complete("SHP_WEAPON_4_1")) have_l2_weaps = (tech_is_complete("SHP_WEAPON_2_3") or tech_is_complete("SHP_WEAPON_4_1")) aistate = get_aistate() enemies_sighted = aistate.misc.get('enemies_sighted', {}) target_planet_ids = ([ pid for pid, pscore, trp in AIstate.invasionTargets[:allotted_invasion_targets()] ] + [ pid for pid, pscore in list(aistate.colonisablePlanetIDs.items()) [:allottedColonyTargets] ] + [ pid for pid, pscore in list(aistate.colonisableOutpostIDs.items()) [:allottedColonyTargets] ]) my_systems = set(get_owned_planets()) target_systems = set(PlanetUtilsAI.get_systems(target_planet_ids)) cur_ship_rating = ProductionAI.cur_best_military_design_rating() current_turn = fo.currentTurn() ships_needed = 0 defense_ships_needed = 0 ships_needed_allocation = [] for sys_id in my_systems.union(target_systems): status = aistate.systemStatus.get(sys_id, {}) my_rating = status.get('myFleetRating', 0) my_defenses = status.get('mydefenses', {}).get('overall', 0) base_monster_threat = status.get('monsterThreat', 0) # scale monster threat so that in early - mid game big monsters don't over-drive military production monster_threat = base_monster_threat if current_turn > 200: pass elif current_turn > 100: if base_monster_threat >= 2000: monster_threat = 2000 + (current_turn / 100.0 - 1) * (base_monster_threat - 2000) elif current_turn > 30: if base_monster_threat >= 2000: monster_threat = 0 else: if base_monster_threat > 200: monster_threat = 0 if sys_id in my_systems: threat_root = status.get('fleetThreat', 0)**0.5 + 0.8 * status.get( 'max_neighbor_threat', 0)**0.5 + 0.2 * status.get( 'neighborThreat', 0)**0.5 + monster_threat**0.5 + status.get( 'planetThreat', 0)**0.5 else: threat_root = status.get( 'fleetThreat', 0)**0.5 + monster_threat**0.5 + status.get( 'planetThreat', 0)**0.5 ships_needed_here = math.ceil( (max(0, (threat_root - (my_rating**0.5 + my_defenses**0.5)))**2) / cur_ship_rating) ships_needed += ships_needed_here ships_needed_allocation.append( (universe.getSystem(sys_id), ships_needed_here)) if sys_id in my_systems: defense_ships_needed += ships_needed_here part1 = min(1 * fo.currentTurn(), 40) part2 = max(0, int(75 * ships_needed)) military_priority = part1 + part2 if not have_l1_weaps: military_priority /= 2.0 elif not (have_l2_weaps and enemies_sighted): military_priority /= 1.5 fmt_string = "Calculating Military Priority: min(t,40) + max(0,75 * ships_needed) \n\t Priority: %d \t ships_needed: %d \t defense_ships_needed: %d \t curShipRating: %.0f \t l1_weaps: %s \t enemies_sighted: %s" debug(fmt_string % (military_priority, ships_needed, defense_ships_needed, cur_ship_rating, have_l1_weaps, enemies_sighted)) debug("Source of milship demand: %s" % ships_needed_allocation) military_priority *= aistate.character.military_priority_scaling() return max(military_priority, 0)
def _calculate_planet_colonization_rating( planet_id: PlanetId, mission_type: MissionType, species_name: SpeciesName, detail: list, empire_research_list: Sequence, ) -> float: empire = fo.getEmpire() retval = 0 character = get_aistate().character discount_multiplier = character.preferred_discount_multiplier([30.0, 40.0]) species = fo.getSpecies(species_name) species_foci = [] and species and list(species.foci) tag_list = list(species.tags) if species else [] pilot_val = pilot_rating = 0 if species and species.canProduceShips: pilot_val = pilot_rating = rate_piloting_tag(species_name) if pilot_val > best_pilot_rating(): pilot_val *= 2 if pilot_val > 2: retval += discount_multiplier * 5 * pilot_val detail.append("Pilot Val %.1f" % (discount_multiplier * 5 * pilot_val)) if empire.productionPoints < 100: backup_factor = 0.0 else: backup_factor = min(1.0, (empire.productionPoints / 200.0)**2) universe = fo.getUniverse() capital_id = PlanetUtilsAI.get_capital() homeworld = universe.getPlanet(capital_id) planet = universe.getPlanet(planet_id) prospective_invasion_targets = [ pid for pid, pscore, trp in AIstate.invasionTargets[:PriorityAI.allotted_invasion_targets()] if pscore > InvasionAI.MIN_INVASION_SCORE ] if species_name != planet.speciesName and planet.speciesName and mission_type != MissionType.INVASION: return 0 this_sysid = planet.systemID if homeworld: home_system_id = homeworld.systemID eval_system_id = this_sysid if home_system_id != INVALID_ID and eval_system_id != INVALID_ID: least_jumps = universe.jumpDistance(home_system_id, eval_system_id) if least_jumps == -1: # indicates no known path return 0.0 if planet is None: vis_map = universe.getVisibilityTurnsMap(planet_id, empire.empireID) debug("Planet %d object not available; visMap: %s" % (planet_id, vis_map)) return 0 # only count existing presence if not target planet # TODO: consider neighboring sytems for smaller contribution, and bigger contributions for # local colonies versus local outposts locally_owned_planets = [ lpid for lpid in get_owned_planets_in_system(this_sysid) if lpid != planet_id ] planets_with_species = get_inhabited_planets() locally_owned_pop_ctrs = [ lpid for lpid in locally_owned_planets if lpid in planets_with_species ] # triple count pop_ctrs existing_presence = len( locally_owned_planets) + 2 * len(locally_owned_pop_ctrs) system = universe.getSystem(this_sysid) sys_supply = get_system_supply(this_sysid) planet_supply = AIDependencies.supply_by_size.get(planet.size, 0) bld_types = set( universe.getBuilding(bldg).buildingTypeName for bldg in planet.buildingIDs).intersection( AIDependencies.building_supply) planet_supply += sum( AIDependencies.building_supply[bld_type].get(int(psize), 0) for psize in [-1, planet.size] for bld_type in bld_types) supply_specials = set(planet.specials).union(system.specials).intersection( AIDependencies.SUPPLY_MOD_SPECIALS) planet_supply += sum( AIDependencies.SUPPLY_MOD_SPECIALS[_special].get(int(psize), 0) for _special in supply_specials for psize in [-1, planet.size]) ind_tag_mod = AIDependencies.SPECIES_INDUSTRY_MODIFIER.get( get_species_tag_grade(species_name, Tags.INDUSTRY), 1.0) res_tag_mod = AIDependencies.SPECIES_RESEARCH_MODIFIER.get( get_species_tag_grade(species_name, Tags.RESEARCH), 1.0) if species: supply_tag_mod = AIDependencies.SPECIES_SUPPLY_MODIFIER.get( get_species_tag_grade(species_name, Tags.SUPPLY), 1) else: supply_tag_mod = 0 # determine the potential supply provided by owning this planet, and if the planet is currently populated by # the evaluated species, then save this supply value in a cache. # The system supply value can be negative (indicates the respective number of starlane jumps to the closest supplied # system). So if this total planet supply value is non-negative, then the planet would be supply connected (to at # least a portion of the existing empire) if the planet becomes owned by the AI. planet_supply += supply_tag_mod planet_supply = max(planet_supply, 0) # planets can't have negative supply if planet.speciesName == species_name: update_planet_supply(planet_id, planet_supply + sys_supply) threat_factor = _determine_colony_threat_factor(planet_id, species_name, existing_presence) sys_partial_vis_turn = get_partial_visibility_turn(this_sysid) planet_partial_vis_turn = get_partial_visibility_turn(planet_id) if planet_partial_vis_turn < sys_partial_vis_turn: # last time we had partial vis of the system, the planet was stealthed to us # print "Colonization AI couldn't get current info on planet id %d (was stealthed at last sighting)" % planet_id return 0 # TODO: track detection strength, order new scouting when it goes up star_bonus = 0 colony_star_bonus = 0 research_bonus = 0 growth_val = 0 fixed_ind = 0 fixed_res = 0 if system: already_got_this_one = this_sysid in get_owned_planets() # TODO: Should probably consider pilot rating also for Phototropic species if "PHOTOTROPHIC" not in tag_list and pilot_rating >= best_pilot_rating( ): if system.starType == fo.starType.red and tech_is_complete( "LRN_STELLAR_TOMOGRAPHY"): star_bonus += 40 * discount_multiplier # can be used for artif'l black hole and solar hull detail.append( "Red Star for Art Black Hole for solar hull %.1f" % (40 * discount_multiplier)) elif system.starType == fo.starType.blackHole and tech_is_complete( "SHP_FRC_ENRG_COMP"): star_bonus += 100 * discount_multiplier # can be used for solar hull detail.append("Black Hole for solar hull %.1f" % (100 * discount_multiplier)) if tech_is_complete("PRO_SOL_ORB_GEN" ) or "PRO_SOL_ORB_GEN" in empire_research_list[:5]: if system.starType in [fo.starType.blue, fo.starType.white]: if not has_claimed_star(fo.starType.blue, fo.starType.white): star_bonus += 20 * discount_multiplier detail.append("PRO_SOL_ORB_GEN BW %.1f" % (20 * discount_multiplier)) elif not already_got_this_one: # still has extra value as an alternate location for solar generators star_bonus += 10 * discount_multiplier * backup_factor detail.append("PRO_SOL_ORB_GEN BW Backup Location %.1f" % (10 * discount_multiplier * backup_factor)) elif fo.currentTurn() > 100: # lock up this whole system pass # starBonus += 5 # TODO: how much? # detail.append("PRO_SOL_ORB_GEN BW LockingDownSystem %.1f"%5) if system.starType in [fo.starType.yellow, fo.starType.orange]: if not has_claimed_star(fo.starType.blue, fo.starType.white, fo.starType.yellow, fo.starType.orange): star_bonus += 10 * discount_multiplier detail.append("PRO_SOL_ORB_GEN YO %.1f" % (10 * discount_multiplier)) else: pass # starBonus +=2 # still has extra value as an alternate location for solar generators # detail.append("PRO_SOL_ORB_GEN YO Backup %.1f" % 2) if system.starType in [fo.starType.blackHole ] and fo.currentTurn() > 100: if not already_got_this_one: # whether have tech yet or not, assign some base value star_bonus += 10 * discount_multiplier * backup_factor detail.append("Black Hole %.1f" % (10 * discount_multiplier * backup_factor)) else: star_bonus += 5 * discount_multiplier * backup_factor detail.append("Black Hole Backup %.1f" % (5 * discount_multiplier * backup_factor)) if tech_is_complete(AIDependencies.PRO_SOL_ORB_GEN ): # start valuing as soon as PRO_SOL_ORB_GEN done if system.starType == fo.starType.blackHole: # pretty rare planets, good for generator this_val = 0.5 * max(population_with_industry_focus(), 20) * discount_multiplier if not has_claimed_star(fo.starType.blackHole): star_bonus += this_val detail.append("PRO_SINGULAR_GEN %.1f" % this_val) elif not is_system_star_claimed(system): # still has extra value as an alternate location for generators & for blocking enemies generators star_bonus += this_val * backup_factor detail.append("PRO_SINGULAR_GEN Backup %.1f" % (this_val * backup_factor)) elif system.starType == fo.starType.red and not has_claimed_star( fo.starType.blackHole): rfactor = (1.0 + count_claimed_stars(fo.starType.red))**-2 star_bonus += 40 * discount_multiplier * backup_factor * rfactor # can be used for artif'l black hole detail.append( "Red Star for Art Black Hole %.1f" % (40 * discount_multiplier * backup_factor * rfactor)) if tech_is_complete( "PRO_NEUTRONIUM_EXTRACTION" ) or "PRO_NEUTRONIUM_EXTRACTION" in empire_research_list[:8]: if system.starType in [fo.starType.neutron]: if not has_claimed_star(fo.starType.neutron): star_bonus += 80 * discount_multiplier # pretty rare planets, good for armor detail.append("PRO_NEUTRONIUM_EXTRACTION %.1f" % (80 * discount_multiplier)) else: # still has extra value as an alternate location for generators & for bnlocking enemies generators star_bonus += 20 * discount_multiplier * backup_factor detail.append("PRO_NEUTRONIUM_EXTRACTION Backup %.1f" % (20 * discount_multiplier * backup_factor)) if tech_is_complete( "SHP_ENRG_BOUND_MAN" ) or "SHP_ENRG_BOUND_MAN" in empire_research_list[:6]: # TODO: base this on pilot val, and also consider red stars if system.starType in [fo.starType.blackHole, fo.starType.blue]: init_val = 100 * discount_multiplier * (pilot_val or 1) if not has_claimed_star(fo.starType.blackHole, fo.starType.blue): colony_star_bonus += init_val # pretty rare planets, good for energy shipyards detail.append("SHP_ENRG_BOUND_MAN %.1f" % init_val) elif not is_system_star_claimed(system): # still has extra value as an alternate location for energy shipyard colony_star_bonus += 0.5 * init_val * backup_factor detail.append("SHP_ENRG_BOUND_MAN Backup %.1f" % (0.5 * init_val * backup_factor)) retval += star_bonus planet_specials = list(planet.specials) if "ECCENTRIC_ORBIT_SPECIAL" in planet.specials: fixed_res += discount_multiplier * 6 detail.append("ECCENTRIC_ORBIT_SPECIAL %.1f" % (discount_multiplier * 6)) if mission_type == MissionType.OUTPOST or ( mission_type == MissionType.INVASION and not species_name): if "ANCIENT_RUINS_SPECIAL" in planet.specials: # TODO: add value for depleted ancient ruins retval += discount_multiplier * 30 detail.append("Undepleted Ruins %.1f" % discount_multiplier * 30) for special in planet_specials: if "_NEST_" in special: nest_val = get_nest_rating( special, 5.0 ) * discount_multiplier # get an outpost on the nest quick retval += nest_val detail.append("%s %.1f" % (special, nest_val)) elif special == "FORTRESS_SPECIAL": fort_val = 10 * discount_multiplier retval += fort_val detail.append("%s %.1f" % (special, fort_val)) elif special == "HONEYCOMB_SPECIAL": honey_val = 0.3 * (AIDependencies.HONEYCOMB_IND_MULTIPLIER * AIDependencies.INDUSTRY_PER_POP * population_with_industry_focus() * discount_multiplier) retval += honey_val detail.append("%s %.1f" % (special, honey_val)) if planet.size == fo.planetSize.asteroids: ast_val = 0 if system: for pid in system.planetIDs: other_planet = universe.getPlanet(pid) if other_planet.size == fo.planetSize.asteroids: if pid == planet_id: continue elif pid < planet_id and planet.unowned: ast_val = 0 break elif other_planet.speciesName: if other_planet.owner == empire.empireID: ownership_factor = 1.0 elif pid in prospective_invasion_targets: ownership_factor = character.secondary_valuation_factor_for_invasion_targets( ) else: ownership_factor = 0.0 ast_val += ownership_factor * _base_asteroid_mining_val( ) * discount_multiplier retval += ast_val if ast_val > 0: detail.append("AsteroidMining %.1f" % ast_val) ast_val = 0 if tech_is_complete("SHP_ASTEROID_HULLS"): per_ast = 20 elif tech_is_complete("CON_ORBITAL_CON"): per_ast = 5 else: per_ast = 0.1 if system: for pid in system.planetIDs: other_planet = universe.getPlanet(pid) if other_planet.size == fo.planetSize.asteroids: if pid == planet_id: continue elif pid < planet_id and planet.unowned: ast_val = 0 break elif other_planet.speciesName: other_species = fo.getSpecies(other_planet.speciesName) if other_species and other_species.canProduceShips: if other_planet.owner == empire.empireID: ownership_factor = 1.0 elif pid in prospective_invasion_targets: ownership_factor = character.secondary_valuation_factor_for_invasion_targets( ) else: ownership_factor = 0.0 ast_val += ownership_factor * per_ast * discount_multiplier retval += ast_val if ast_val > 0: detail.append("AsteroidShipBuilding %.1f" % ast_val) # We will assume that if any GG in the system is populated, they all will wind up populated; cannot then hope # to build a GGG on a non-populated GG populated_gg_factor = 1.0 per_gg = 0 if planet.size == fo.planetSize.gasGiant: # TODO: Given current industry calc approach, consider bringing this max val down to actual max val of 10 if tech_is_complete("PRO_ORBITAL_GEN"): per_gg = 20 elif tech_is_complete("CON_ORBITAL_CON"): per_gg = 10 if species_name: populated_gg_factor = 0.5 else: per_gg = 5 if system: gg_list = [] orb_gen_val = 0 gg_detail = [] for pid in system.planetIDs: other_planet = universe.getPlanet(pid) if other_planet.size == fo.planetSize.gasGiant: gg_list.append(pid) if other_planet.speciesName: populated_gg_factor = 0.5 if (pid != planet_id and other_planet.owner == empire.empireID and FocusType.FOCUS_INDUSTRY in list(other_planet.availableFoci) + [other_planet.focus]): orb_gen_val += per_gg * discount_multiplier # Note, this reported value may not take into account a later adjustment from a populated gg gg_detail.append("GGG for %s %.1f" % (other_planet.name, discount_multiplier * per_gg * populated_gg_factor)) if planet_id in sorted(gg_list)[:1]: retval += orb_gen_val * populated_gg_factor detail.extend(gg_detail) else: detail.append("Won't GGG") if existing_presence: detail.append("preexisting system colony") retval = (retval + existing_presence * _get_defense_value(species_name)) * 1.5 # Fixme - sys_supply is always <= 0 leading to incorrect supply bonus score supply_val = 0 if sys_supply < 0: if sys_supply + planet_supply >= 0: supply_val += 30 * (planet_supply - max(-3, sys_supply)) else: retval += 30 * (planet_supply + sys_supply) # a penalty elif planet_supply > sys_supply and ( sys_supply < 2): # TODO: check min neighbor supply supply_val += 25 * (planet_supply - sys_supply) detail.append("sys_supply: %d, planet_supply: %d, supply_val: %.0f" % (sys_supply, planet_supply, supply_val)) retval += supply_val if threat_factor < 1.0: threat_factor = _revise_threat_factor(threat_factor, retval, this_sysid, MINIMUM_COLONY_SCORE) retval *= threat_factor detail.append("threat reducing value by %3d %%" % (100 * (1 - threat_factor))) return int(retval) else: # colonization mission if not species: return 0 supply_val = 0 if "ANCIENT_RUINS_SPECIAL" in planet.specials: retval += discount_multiplier * 50 detail.append("Undepleted Ruins %.1f" % discount_multiplier * 50) if "HONEYCOMB_SPECIAL" in planet.specials: honey_val = (AIDependencies.HONEYCOMB_IND_MULTIPLIER * AIDependencies.INDUSTRY_PER_POP * population_with_industry_focus() * discount_multiplier) if FocusType.FOCUS_INDUSTRY not in species_foci: honey_val *= -0.3 # discourage settlement by colonizers not able to use Industry Focus retval += honey_val detail.append("%s %.1f" % ("HONEYCOMB_SPECIAL", honey_val)) # Fixme - sys_supply is always <= 0 leading to incorrect supply bonus score if sys_supply <= 0: if sys_supply + planet_supply >= 0: supply_val = 40 * (planet_supply - max(-3, sys_supply)) else: supply_val = 200 * (planet_supply + sys_supply) # a penalty if species_name == "SP_SLY": # Sly are essentially stuck with lousy supply, so don't penalize for that supply_val = 0 elif planet_supply > sys_supply == 1: # TODO: check min neighbor supply supply_val = 20 * (planet_supply - sys_supply) detail.append("sys_supply: %d, planet_supply: %d, supply_val: %.0f" % (sys_supply, planet_supply, supply_val)) # if AITags != "": # print "Species %s has AITags %s"%(specName, AITags) retval += fixed_res retval += colony_star_bonus asteroid_bonus = 0 gas_giant_bonus = 0 flat_industry = 0 mining_bonus = 0 per_ggg = 10 asteroid_factor = 0.0 gg_factor = 0.0 ast_shipyard_name = "" if system and FocusType.FOCUS_INDUSTRY in species.foci: for pid in system.planetIDs: if pid == planet_id: continue p2 = universe.getPlanet(pid) if p2: if p2.size == fo.planetSize.asteroids: this_factor = 0.0 if p2.owner == empire.empireID: this_factor = 1.0 elif p2.unowned: this_factor = 0.5 elif pid in prospective_invasion_targets: this_factor = character.secondary_valuation_factor_for_invasion_targets( ) if this_factor > asteroid_factor: asteroid_factor = this_factor ast_shipyard_name = p2.name if p2.size == fo.planetSize.gasGiant: if p2.owner == empire.empireID: gg_factor = max(gg_factor, 1.0) elif p2.unowned: gg_factor = max(gg_factor, 0.5) elif pid in prospective_invasion_targets: gg_factor = max( gg_factor, character. secondary_valuation_factor_for_invasion_targets( )) if asteroid_factor > 0.0: if tech_is_complete( "PRO_MICROGRAV_MAN" ) or "PRO_MICROGRAV_MAN" in empire_research_list[:10]: flat_industry += 2 * asteroid_factor # will go into detailed industry projection detail.append("Asteroid mining ~ %.1f" % (5 * asteroid_factor * discount_multiplier)) if tech_is_complete( "SHP_ASTEROID_HULLS" ) or "SHP_ASTEROID_HULLS" in empire_research_list[:11]: if species and species.canProduceShips: asteroid_bonus = 30 * discount_multiplier * pilot_val detail.append("Asteroid ShipBuilding from %s %.1f" % (ast_shipyard_name, discount_multiplier * 30 * pilot_val)) if gg_factor > 0.0: if tech_is_complete( "PRO_ORBITAL_GEN" ) or "PRO_ORBITAL_GEN" in empire_research_list[:5]: flat_industry += per_ggg * gg_factor # will go into detailed industry projection detail.append("GGG ~ %.1f" % (per_ggg * gg_factor * discount_multiplier)) # calculate the maximum population of the species on that planet. if planet.speciesName not in AIDependencies.SPECIES_FIXED_POPULATION: max_pop_size = calc_max_pop(planet, species, detail) else: max_pop_size = AIDependencies.SPECIES_FIXED_POPULATION[ planet.speciesName] detail.append("Fixed max population of %.2f" % max_pop_size) if max_pop_size <= 0: detail.append( "Non-positive population projection for species '%s', so no colonization value" % (species and species.name)) return 0 for special in [ "MINERALS_SPECIAL", "CRYSTALS_SPECIAL", "ELERIUM_SPECIAL" ]: if special in planet_specials: mining_bonus += 1 has_blackhole = has_claimed_star(fo.starType.blackHole) ind_tech_map_flat = AIDependencies.INDUSTRY_EFFECTS_FLAT_NOT_MODIFIED_BY_SPECIES ind_tech_map_before_species_mod = AIDependencies.INDUSTRY_EFFECTS_PER_POP_MODIFIED_BY_SPECIES ind_tech_map_after_species_mod = AIDependencies.INDUSTRY_EFFECTS_PER_POP_NOT_MODIFIED_BY_SPECIES ind_mult = 1 for tech in ind_tech_map_before_species_mod: if tech_is_complete(tech) and ( tech != AIDependencies.PRO_SINGULAR_GEN or has_blackhole): ind_mult += ind_tech_map_before_species_mod[tech] ind_mult = ind_mult * max( ind_tag_mod, 0.5 * (ind_tag_mod + res_tag_mod)) # TODO: report an actual calc for research value for tech in ind_tech_map_after_species_mod: if tech_is_complete(tech) and ( tech != AIDependencies.PRO_SINGULAR_GEN or has_blackhole): ind_mult += ind_tech_map_after_species_mod[tech] max_ind_factor = 0 for tech in ind_tech_map_flat: if tech_is_complete(tech): fixed_ind += discount_multiplier * ind_tech_map_flat[tech] if FocusType.FOCUS_INDUSTRY in species.foci: if "TIDAL_LOCK_SPECIAL" in planet.specials: ind_mult += 1 max_ind_factor += AIDependencies.INDUSTRY_PER_POP * mining_bonus max_ind_factor += AIDependencies.INDUSTRY_PER_POP * ind_mult cur_pop = 1.0 # assume an initial colonization value if planet.speciesName != "": cur_pop = planet.currentMeterValue(fo.meterType.population) elif tech_is_complete("GRO_LIFECYCLE_MAN"): cur_pop = 3.0 cur_industry = planet.currentMeterValue(fo.meterType.industry) ind_val = _project_ind_val(cur_pop, max_pop_size, cur_industry, max_ind_factor, flat_industry, discount_multiplier) detail.append("ind_val %.1f" % ind_val) # used to give preference to closest worlds for special in [ spec for spec in planet_specials if spec in AIDependencies.metabolismBoosts ]: # TODO: also consider potential future benefit re currently unpopulated planets gbonus = (discount_multiplier * AIDependencies.INDUSTRY_PER_POP * ind_mult * empire_metabolisms.get( AIDependencies.metabolismBoosts[special], 0) ) # due to growth applicability to other planets growth_val += gbonus detail.append("Bonus for %s: %.1f" % (special, gbonus)) if FocusType.FOCUS_RESEARCH in species.foci: research_bonus += discount_multiplier * 2 * AIDependencies.RESEARCH_PER_POP * max_pop_size if "ANCIENT_RUINS_SPECIAL" in planet.specials or "ANCIENT_RUINS_DEPLETED_SPECIAL" in planet.specials: research_bonus += discount_multiplier * 2 * AIDependencies.RESEARCH_PER_POP * max_pop_size * 5 detail.append("Ruins Research") if "TEMPORAL_ANOMALY_SPECIAL" in planet.specials: research_bonus += discount_multiplier * 2 * AIDependencies.RESEARCH_PER_POP * max_pop_size * 25 detail.append("Temporal Anomaly Research") if AIDependencies.COMPUTRONIUM_SPECIAL in planet.specials: comp_bonus = (0.5 * AIDependencies.TECH_COST_MULTIPLIER * AIDependencies.RESEARCH_PER_POP * AIDependencies.COMPUTRONIUM_RES_MULTIPLIER * population_with_research_focus() * discount_multiplier) if have_computronium(): comp_bonus *= backup_factor research_bonus += comp_bonus detail.append(AIDependencies.COMPUTRONIUM_SPECIAL) retval += (max(ind_val + asteroid_bonus + gas_giant_bonus, research_bonus, growth_val) + fixed_ind + fixed_res + supply_val) if existing_presence: detail.append("preexisting system colony") retval = (retval + existing_presence * _get_defense_value(species_name)) * 2 if threat_factor < 1.0: threat_factor = _revise_threat_factor(threat_factor, retval, this_sysid, MINIMUM_COLONY_SCORE) retval *= threat_factor detail.append("threat reducing value by %3d %%" % (100 * (1 - threat_factor))) return retval
def assign_military_fleets_to_systems(use_fleet_id_list=None, allocations=None, round=1): # assign military fleets to military theater systems global _military_allocations universe = fo.getUniverse() if allocations is None: allocations = [] doing_main = use_fleet_id_list is None aistate = get_aistate() if doing_main: aistate.misc["ReassignedFleetMissions"] = [] base_defense_ids = FleetUtilsAI.get_empire_fleet_ids_by_role( MissionType.ORBITAL_DEFENSE) unassigned_base_defense_ids = FleetUtilsAI.extract_fleet_ids_without_mission_types( base_defense_ids) for fleet_id in unassigned_base_defense_ids: fleet = universe.getFleet(fleet_id) if not fleet: continue sys_id = fleet.systemID target = TargetSystem(sys_id) fleet_mission = aistate.get_fleet_mission(fleet_id) fleet_mission.clear_fleet_orders() fleet_mission.clear_target() mission_type = MissionType.ORBITAL_DEFENSE fleet_mission.set_target(mission_type, target) all_military_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role( MissionType.MILITARY) if not all_military_fleet_ids: _military_allocations = [] return avail_mil_fleet_ids = list( FleetUtilsAI.extract_fleet_ids_without_mission_types( all_military_fleet_ids)) mil_needing_repair_ids, avail_mil_fleet_ids = avail_mil_needing_repair( avail_mil_fleet_ids) these_allocations = _military_allocations debug("==================================================") debug("Assigning military fleets") debug("---------------------------------") else: avail_mil_fleet_ids = list(use_fleet_id_list) mil_needing_repair_ids, avail_mil_fleet_ids = avail_mil_needing_repair( avail_mil_fleet_ids) these_allocations = allocations # send_for_repair(mil_needing_repair_ids) #currently, let get taken care of by AIFleetMission.generate_fleet_orders() # get systems to defend avail_mil_fleet_ids = set(avail_mil_fleet_ids) for sys_id, alloc, minalloc, rvp, takeAny in these_allocations: if not doing_main and not avail_mil_fleet_ids: break debug("Allocating for: %s", TargetSystem(sys_id)) found_fleets = [] found_stats = {} ensure_return = sys_id not in set(AIstate.colonyTargetedSystemIDs + AIstate.outpostTargetedSystemIDs + AIstate.invasionTargetedSystemIDs) these_fleets = FleetUtilsAI.get_fleets_for_mission( target_stats={ "rating": alloc, "ratingVsPlanets": rvp, "target_system": TargetSystem(sys_id) }, min_stats={ "rating": minalloc, "ratingVsPlanets": rvp, "target_system": TargetSystem(sys_id) }, cur_stats=found_stats, starting_system=sys_id, fleet_pool_set=avail_mil_fleet_ids, fleet_list=found_fleets, ensure_return=ensure_return, ) if not these_fleets: debug("Could not allocate any fleets.") if not found_fleets or not (FleetUtilsAI.stats_meet_reqs( found_stats, {"rating": minalloc}) or takeAny): if doing_main: if _verbose_mil_reporting: debug( "NO available/suitable military allocation for system %d ( %s ) " "-- requested allocation %8d, found available rating %8d in fleets %s" % ( sys_id, universe.getSystem(sys_id).name, minalloc, found_stats.get("rating", 0), found_fleets, )) avail_mil_fleet_ids.update(found_fleets) continue else: these_fleets = found_fleets else: debug("Assigning fleets %s to target %s", these_fleets, TargetSystem(sys_id)) if doing_main and _verbose_mil_reporting: debug("FULL+ military allocation for system %d ( %s )" " -- requested allocation %8d, got %8d with fleets %s" % (sys_id, universe.getSystem(sys_id).name, alloc, found_stats.get("rating", 0), these_fleets)) target = TargetSystem(sys_id) for fleet_id in these_fleets: fo.issueAggressionOrder(fleet_id, True) fleet_mission = aistate.get_fleet_mission(fleet_id) fleet_mission.clear_fleet_orders() fleet_mission.clear_target() if sys_id in set(AIstate.colonyTargetedSystemIDs + AIstate.outpostTargetedSystemIDs + AIstate.invasionTargetedSystemIDs): mission_type = MissionType.SECURE elif get_owned_planets_in_system(sys_id): mission_type = MissionType.PROTECT_REGION else: mission_type = MissionType.MILITARY fleet_mission.set_target(mission_type, target) fleet_mission.generate_fleet_orders() if not doing_main: aistate.misc.setdefault("ReassignedFleetMissions", []).append(fleet_mission) if doing_main: debug("---------------------------------") last_round = 3 last_round_name = "LastRound" if round <= last_round: # check if any fleets remain unassigned all_military_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role( MissionType.MILITARY) avail_mil_fleet_ids = list( FleetUtilsAI.extract_fleet_ids_without_mission_types( all_military_fleet_ids)) allocations = [] round += 1 thisround = "Extras Remaining Round %d" % round if round < last_round else last_round_name if avail_mil_fleet_ids: debug("Round %s - still have available military fleets: %s", thisround, avail_mil_fleet_ids) allocations = get_military_fleets( mil_fleets_ids=avail_mil_fleet_ids, try_reset=False, thisround=thisround) if allocations: assign_military_fleets_to_systems( use_fleet_id_list=avail_mil_fleet_ids, allocations=allocations, round=round) else: # assign remaining fleets to nearest systems to protect. all_military_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role( MissionType.MILITARY) avail_mil_fleet_ids = list( FleetUtilsAI.extract_fleet_ids_without_mission_types( all_military_fleet_ids)) def system_score(_fid, _sys_id): """Helper function to rank systems by priority""" jump_distance = universe.jumpDistance(_fid, _sys_id) if get_system_local_threat(_sys_id): weight = 10 elif get_system_neighbor_threat(_sys_id): weight = 3 elif get_system_jump2_threat(_sys_id): weight = 1 else: weight = 1 / max( 0.5, float( get_distance_to_enemy_supply(_sys_id)))**1.25 return float(weight) / (jump_distance + 1) for fid in avail_mil_fleet_ids: fleet = universe.getFleet(fid) FleetUtilsAI.get_fleet_system(fleet) systems = get_owned_planets().keys() if not systems: continue sys_id = max(systems, key=lambda x: system_score(fid, x)) debug( "Assigning leftover %s to system %d " "- nothing better to do.", fleet, sys_id) fleet_mission = aistate.get_fleet_mission(fid) fleet_mission.clear_fleet_orders() target_system = TargetSystem(sys_id) fleet_mission.set_target(MissionType.PROTECT_REGION, target_system) fleet_mission.generate_fleet_orders()