def _get_production_bonus_unmodified(planet: fo.planet, stability: float) -> float: """ Calculate bonus production per population which we would get independent of the species production skill. """ specials_bonus = sum( # growth.macros: STANDARD_INDUSTRY_BOOST AIDependencies.INDUSTRY_PER_POP for s in planet.specials if s in AIDependencies.industry_boost_specials_unmodified ) # TBD: check connections? bonuses = [ Bonus( bool(BuildingType.SOL_ORB_GEN.built_or_queued_at()), # TBD: check star type get_named_real("BLD_SOL_ORB_GEN_MIN_STABILITY"), get_named_real("BLD_SOL_ORB_GEN_BRIGHT_TARGET_INDUSTRY_PERPOP"), ), Bonus( have_honeycomb(), 0.0, get_named_real("HONEYCOMB_TARGET_INDUSTRY_PERPOP"), ), # TBD: Collective Thought Network? Ignored for now, AI doesn't know how to handle it. # It shouldn't make a big difference for selecting which planets to colonise anyway. ] return specials_bonus + sum(bonus.get_bonus(stability) for bonus in bonuses)
def _get_asteroid_and_ggg_value(planet: fo.planet, stability: float) -> float: """ Calculate an estimate of the bonus we may get from asteroids (microgravity) and gas giant generators. """ universe = fo.getUniverse() system = universe.getSystem(planet.systemID) ast_min_stability = get_named_real("PRO_MICROGRAV_MAN_MIN_STABILITY") count_asteroids = ast_min_stability <= stability and tech_soon_available(AIDependencies.PRO_MICROGRAV_MAN, 5) ggg_min_stability = get_named_real("BLD_GAS_GIANT_GEN_MIN_STABILITY") count_ggg = ggg_min_stability <= stability and tech_soon_available(AIDependencies.PRO_ORBITAL_GEN, 5) asteroid_value = 0.0 ggg_value = 0.0 for pid in system.planetIDs: p2 = universe.getPlanet(pid) if p2: if count_asteroids and p2.size == fo.planetSize.asteroids: full_bonus = get_named_real("PRO_MICROGRAV_MAN_TARGET_INDUSTRY_FLAT") if p2.owner == fo.empireID or pid == planet.id: asteroid_value = full_bonus elif p2.unowned: asteroid_value = max(asteroid_value, 0.5 * full_bonus) # TODO prospective_invasion_targets? if count_ggg: ggg_value = max(ggg_value, _ggg_value(planet, p2)) debug_rating( f"_get_asteroid_and_ggg_value amin={ast_min_stability:.1f}->{count_asteroids:.1f}, " f"gmin={ggg_min_stability:.1f}->{count_ggg:.1f}, aval={asteroid_value:.1f}, gval={ggg_value:.1f}" ) return asteroid_value + ggg_value
def _get_policy_multiplier(stability) -> float: # if fo.getEmpire().policyAdopted("TECHNOCRACY") and stability >= get_named_real("PLC_TECHNOCRACY_MIN_STABILITY"): # return 1.0 + get_named_real("PLC_TECHNOCRACY_TARGET_RESEARCH_PERCENT") if fo.getEmpire().policyAdopted( "TECHNOCRACY" ) and stability >= get_named_real("PLC_TECHNOCRACY_MIN_STABILITY"): return 1.0 + get_named_real("PLC_TECHNOCRACY_TARGET_RESEARCH_PERCENT") return 1.0
def _get_production_bonus_mod_by_policy(stability: float) -> float: """ Calculate bonus production per population which we would get independent of the species production skill, but still affected by industrialism. """ # TBD: check connections? bonuses = [ Bonus( bool(BuildingType.BLACK_HOLE_POW_GEN.built_or_queued_at()), get_named_real("BLD_BLACK_HOLE_POW_GEN_MIN_STABILITY"), get_named_real("BLD_BLACK_HOLE_POW_GEN_TARGET_INDUSTRY_PERPOP"), ), ] return sum(bonus.get_bonus(stability) for bonus in bonuses)
def _get_modified_research_bonuses(planet: fo.planet) -> List[Bonus]: """ Get list of per-population bonuses which are added before multiplication with the species skill value. """ # use fo.getEmpire().researchQueue directly here to simplify caching this function specials = planet.specials return [ Bonus( AIDependencies.ANCIENT_RUINS_SPECIAL in specials or AIDependencies.ANCIENT_RUINS_SPECIAL2 in specials, get_named_real("ANCIENT_RUINS_MIN_STABILITY"), get_named_real("ANCIENT_RUINS_TARGET_RESEARCH_PERPOP"), ), Bonus( fo.getEmpire().policyAdopted("PLC_DIVERSITY"), get_named_real("PLC_DIVERSITY_MIN_STABILITY"), (len(get_empire_planets_by_species()) - get_named_int("PLC_DIVERSITY_THRESHOLD")) * get_named_real("PLC_DIVERSITY_SCALING"), ), Bonus( tech_soon_available("GRO_ENERGY_META", 3), get_named_real("GRO_ENERGY_META_MIN_STABILITY"), get_named_real("GRO_ENERGY_META_TARGET_RESEARCH_PERPOP"), ), Bonus( bool(BuildingType.ENCLAVE_VOID.built_or_queued_at()), get_named_real("BLD_ENCLAVE_VOID_MIN_STABILITY"), get_named_real("BLD_ENCLAVE_VOID_TARGET_RESEARCH_PERPOP"), ), ]
def _get_production_flat(planet: fo.planet, stability: float) -> float: """ Calculate population independent production bonus. """ value = _get_asteroid_and_ggg_value(planet, stability) # this is a rather expensive one, so consider it only if it is on top of the list if tech_soon_available(AIDependencies.PRO_AUTO_2, 1): value += get_named_real("PRO_SENTIENT_AUTO_TARGET_INDUSTRY_FLAT") return value
def _get_research_bonus_unmodified(planet: fo.planet, stability: float): """ Calculate bonus research per population which we would get independent of the species research skill. """ bonuses = [ Bonus( fo.getEmpire().policyAdopted("PLC_ALGORITHMIC_RESEARCH"), get_named_real("LRN_ALGO_RESEARCH_MIN_STABILITY"), get_named_real( "LRN_ALGO_RESEARCH_TARGET_RESEARCH_PERCONSTRUCTION"), ), Bonus( tech_soon_available("LRN_DISTRIB_THOUGHT", 3), get_named_real("LRN_DISTRIB_THOUGHT_MIN_STABILITY"), _get_distributed_thought_bonus(planet.systemID), ), # TODO: distributed thought and collective thought ] return sum(bonus.get_bonus(stability) for bonus in bonuses)
def _ggg_value(planet: fo.planet, p2: fo.planet) -> float: """ Check if p2 not planet and is a gas giant. If determines a value for the potential GGG on p2. """ if p2.id != planet.id and p2.size == fo.planetSize.gasGiant: ggg_colony_flat = get_named_real("BLD_GAS_GIANT_GEN_COLONY_TARGET_INDUSTRY_FLAT") ggg_outpost_flat = get_named_real("BLD_GAS_GIANT_GEN_OUTPOST_TARGET_INDUSTRY_FLAT") # species living on a GG do not like a GGG, so we ignore the planet itself here if p2.owner == fo.empireID(): if not p2.speciesName: return ggg_outpost_flat if p2.id in BuildingType.GAS_GIANT_GEN.built_or_queued_at(): return ggg_colony_flat else: return 0.4 * ggg_colony_flat # we could build one, but inhabitants won't like it if p2.unowned: return 0.5 * ggg_colony_flat # unowned means we could probably get it easily # TODO prospective_invasion_targets? # So far we do not consider owned gas giant for planets here return 0.0
def _get_distributed_thought_bonus(system_id: SystemId) -> float: universe = fo.getUniverse() max_distance = max( (universe.linearDistance(system_id, p.systemID) for p in get_empire_populated_planets() if p.focus == FocusType.FOCUS_RESEARCH), default=0.0, ) # TBD? This could also affect other planets... return get_named_real( "DISTRIB_THOUGH_RESEARCH_SCALING") * max_distance**0.5
def _get_stellar_tomography_bonus(system_id: SystemId) -> float: universe = fo.getUniverse() system = universe.getSystem(system_id) if system.starType == fo.starType.blackHole: factor = get_named_real( "LRN_STELLAR_TOMO_BLACK_TARGET_RESEARCH_PERPLANET") elif system.starType == fo.starType.neutron: factor = get_named_real( "LRN_STELLAR_TOMO_NEUTRON_TARGET_RESEARCH_PERPLANET") else: factor = get_named_real( "LRN_STELLAR_TOMO_NORMAL_STAR_TARGET_RESEARCH_PERPLANET") def is_our_researcher(pid): planet = universe.getPlanet(pid) return planet.focus == FocusType.FOCUS_RESEARCH and planet.owner == fo.empireID( ) num_researcher = sum(1 for pid in system.planetIDs if is_our_researcher(pid)) # if we add another planet with research focus, all will profit. (n+1)^2 - n^2 = 2n + 1 return (num_researcher * 2 + 1) * factor
def _get_modified_industry_bonuses() -> List[Bonus]: """ Get list of per-population bonuses which are added before multiplication with the species skill value. """ # TBD check connection!? have_center = bool(BuildingType.INDUSTRY_CENTER.built_or_queued_at()) centre_bonus1 = get_named_real("BLD_INDUSTRY_CENTER_1_TARGET_INDUSTRY_PERPOP") centre_bonus2 = get_named_real("BLD_INDUSTRY_CENTER_2_TARGET_INDUSTRY_PERPOP") centre_bonus3 = get_named_real("BLD_INDUSTRY_CENTER_3_TARGET_INDUSTRY_PERPOP") return [ Bonus( tech_soon_available("PRO_FUSION_GEN", 3), get_named_real("PRO_FUSION_GEN_MIN_STABILITY"), get_named_real("PRO_FUSION_GEN_TARGET_INDUSTRY_PERPOP"), ), Bonus( tech_soon_available("GRO_ENERGY_META", 3), get_named_real("GRO_ENERGY_META_MIN_STABILITY"), get_named_real("GRO_ENERGY_META_TARGET_INDUSTRY_PERPOP"), ), # special case: these are not cumulative Bonus( have_center and tech_soon_available("PRO_INDUSTRY_CENTER_III", 1), # expensive research get_named_real("BLD_INDUSTRY_CENTER_3_MIN_STABILITY"), centre_bonus3 - centre_bonus2, ), Bonus( have_center and tech_soon_available("PRO_INDUSTRY_CENTER_II", 2), get_named_real("BLD_INDUSTRY_CENTER_2_MIN_STABILITY"), centre_bonus2 - centre_bonus1, ), Bonus( # normally we have the tech when we have the building, but we could have conquered one have_center and tech_soon_available("PRO_INDUSTRY_CENTER_II", 3), get_named_real("BLD_INDUSTRY_CENTER_1_MIN_STABILITY"), centre_bonus1, ), ]
def _get_modified_by_policy_research_bonuses(stability: float) -> List[Bonus]: return [ Bonus( tech_soon_available("LRN_QUANT_NET", 3), get_named_real("LRN_QUANT_NET_MIN_STABILITY"), get_named_real("LRN_QUANT_NET_TARGET_RESEARCH_PERPOP"), ), # TBD check connection, _empire_resources should collect a list of systems or planets Bonus( have_computronium(), get_named_real("COMPUTRONIUM_MIN_STABILITY"), get_named_real("COMPUTRONIUM_TARGET_RESEARCH_PERPOP"), ), Bonus( fo.getEmpire().policyAdopted("PLC_LIBERTY"), get_named_real("PLC_LIBERTY_MIN_STABILITY"), (min(stability, get_named_real("PLC_LIBERTY_MAX_STABILITY")) - get_named_real("PLC_LIBERTY_MIN_STABILITY")) * get_named_real("PLC_LIBERTY_RESEARCH_BONUS_SCALING"), ), ]
def _get_policy_multiplier(stability) -> float: if fo.getEmpire().policyAdopted("INDUSTRIALISM") and stability >= get_named_real("PLC_INDUSTRIALISM_MIN_STABILITY"): return 1.0 + get_named_real("PLC_INDUSTRIALISM_TARGET_INDUSTRY_PERCENT") return 1.0