def calculateInvasionPriority(): "calculates the demand for troop ships by opponent planets" global allottedInvasionTargets troopsPerPod=2 empire=fo.getEmpire() if foAI.foAIstate.aggression==fo.aggression.beginner and fo.currentTurn()<150: return 0 allottedInvasionTargets = 1+ int(fo.currentTurn()/25) totalVal= sum( [pscore for pid, pscore, trp in AIstate.invasionTargets[:allottedInvasionTargets] ] ) troopsNeeded= sum( [(trp+4) for pid, pscore, trp in AIstate.invasionTargets[:allottedInvasionTargets] ] ) if totalVal == 0: return 0 opponentTroopPods = int(troopsNeeded/troopsPerPod) productionQueue = empire.productionQueue queuedTroopPods=0 for queue_index in range(0, len(productionQueue)): element=productionQueue[queue_index] if element.buildType == EnumsAI.AIEmpireProductionTypes.BT_SHIP: if foAI.foAIstate.getShipRole(element.designID) in [ EnumsAI.AIShipRoleType.SHIP_ROLE_MILITARY_INVASION, EnumsAI.AIShipRoleType.SHIP_ROLE_BASE_INVASION] : design = fo.getShipDesign(element.designID) queuedTroopPods += element.remaining*element.blocksize * list(design.parts).count("GT_TROOP_POD") bestShip, bestDesign, buildChoices = ProductionAI.getBestShipInfo( EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_INVASION) if bestDesign: troopsPerBestShip = troopsPerPod*( list(bestDesign.parts).count("GT_TROOP_POD") ) else: troopsPerBestShip=troopsPerPod #may actually not have any troopers available, but this num will do for now #don't cound troop bases here since if through misplanning cannot be used where made, cannot be redeployed #troopFleetIDs = FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_INVASION) + FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION) troopFleetIDs = FleetUtilsAI.getEmpireFleetIDsByRole(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) numTroopPods = sum([ FleetUtilsAI.countPartsFleetwide(fleetID, ["GT_TROOP_POD"]) for fleetID in troopFleetIDs]) troopShipsNeeded = math.ceil((opponentTroopPods - (numTroopPods+ queuedTroopPods ))/troopsPerBestShip) #invasionPriority = max( 10+ 200*max(0, troopShipsNeeded ) , int(0.1* totalVal) ) invasionPriority = 30+ 150*max(0, troopShipsNeeded ) if invasionPriority < 0: return 0 if foAI.foAIstate.aggression==fo.aggression.beginner: return 0.5* invasionPriority else: return invasionPriority
def sendInvasionFleets(invasionFleetIDs, evaluatedPlanets, missionType): "sends a list of invasion fleets to a list of planet_value_pairs" universe=fo.getUniverse() invasionPool = invasionFleetIDs[:] #need to make a copy bestShip, bestDesign, buildChoices = ProductionAI.getBestShipInfo( EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_INVASION) if bestDesign: troopsPerBestShip = 2*( list(bestDesign.parts).count("GT_TROOP_POD") ) else: troopsPerBestShip=5 #may actually not have any troopers available, but this num will do for now #sortedTargets=sorted( [ ( pscore-ptroops/2 , pID, pscore, ptroops) for pID, pscore, ptroops in evaluatedPlanets ] , reverse=True) invasionPool=set(invasionPool) for pID, pscore, ptroops in evaluatedPlanets: # if not invasionPool: return planet=universe.getPlanet(pID) if not planet: continue sysID = planet.systemID foundFleets = [] podsNeeded= math.ceil( (ptroops+0.05)/2.0) foundStats={} minStats= {'rating':0, 'troopPods':podsNeeded} targetStats={'rating':10,'troopPods':podsNeeded+1} theseFleets = FleetUtilsAI.getFleetsForMission(1, targetStats , minStats, foundStats, "", systemsToCheck=[sysID], systemsChecked=[], fleetPoolSet=invasionPool, fleetList=foundFleets, verbose=False) if theseFleets == []: if not FleetUtilsAI.statsMeetReqs(foundStats, minStats): print "Insufficient invasion troop allocation for system %d ( %s ) -- requested %s , found %s"%(sysID, universe.getSystem(sysID).name, minStats, foundStats) invasionPool.update( foundFleets ) continue else: theseFleets = foundFleets aiTarget = AITarget.AITarget(EnumsAI.AITargetType.TARGET_PLANET, pID) print "assigning invasion fleets %s to target %s"%(theseFleets, aiTarget) for fleetID in theseFleets: fleet=universe.getFleet(fleetID) aiFleetMission = foAI.foAIstate.getAIFleetMission(fleetID) aiFleetMission.clearAIFleetOrders() aiFleetMission.clearAITargets( (aiFleetMission.getAIMissionTypes() + [-1])[0] ) aiFleetMission.addAITarget(missionType, aiTarget)
def send_invasion_fleets(invasionFleetIDs, evaluatedPlanets, missionType): """sends a list of invasion fleets to a list of planet_value_pairs""" universe=fo.getUniverse() invasionPool = invasionFleetIDs[:] #need to make a copy bestShip, bestDesign, buildChoices = ProductionAI.getBestShipInfo( EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_INVASION) if bestDesign: troopsPerBestShip = 2*( list(bestDesign.parts).count("GT_TROOP_POD") ) else: troopsPerBestShip=5 #may actually not have any troopers available, but this num will do for now #sortedTargets=sorted( [ ( pscore-ptroops/2 , pID, pscore, ptroops) for pID, pscore, ptroops in evaluatedPlanets ] , reverse=True) invasionPool=set(invasionPool) for pID, pscore, ptroops in evaluatedPlanets: # if not invasionPool: return planet=universe.getPlanet(pID) if not planet: continue sysID = planet.systemID foundFleets = [] podsNeeded= math.ceil( (ptroops+0.05)/2.0) foundStats={} minStats= {'rating':0, 'troopPods':podsNeeded} targetStats={'rating':10,'troopPods':podsNeeded+1} theseFleets = FleetUtilsAI.get_fleets_for_mission(1, targetStats , minStats, foundStats, "", systems_to_check=[sysID], systems_checked=[], fleet_pool_set=invasionPool, fleet_list=foundFleets, verbose=False) if not theseFleets: if not FleetUtilsAI.stats_meet_reqs(foundStats, minStats): print "Insufficient invasion troop allocation for system %d ( %s ) -- requested %s , found %s"%(sysID, universe.getSystem(sysID).name, minStats, foundStats) invasionPool.update( foundFleets ) continue else: theseFleets = foundFleets aiTarget = AITarget.AITarget(EnumsAI.TargetType.TARGET_PLANET, pID) print "assigning invasion fleets %s to target %s"%(theseFleets, aiTarget) for fleetID in theseFleets: fleet=universe.getFleet(fleetID) aiFleetMission = foAI.foAIstate.get_fleet_mission(fleetID) aiFleetMission.clear_fleet_orders() aiFleetMission.clear_targets( (aiFleetMission.get_mission_types() + [-1])[0] ) aiFleetMission.add_target(missionType, aiTarget)
def get_invasion_fleets(): invasion_timer.start("gathering initial info") all_invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) AIstate.invasionFleetIDs = FleetUtilsAI.extract_fleet_ids_without_mission_types(all_invasion_fleet_ids) # get suppliable planets universe = fo.getUniverse() empire = fo.getEmpire() empire_id = empire.empireID capital_id = PlanetUtilsAI.get_capital() homeworld=None if capital_id: homeworld = universe.getPlanet(capital_id) if homeworld: home_system_id = homeworld.systemID else: home_system_id = -1 fleet_suppliable_system_ids = empire.fleetSupplyableSystemIDs fleet_suppliable_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(fleet_suppliable_system_ids) prime_invadable_system_ids = set(ColonisationAI.annexable_system_ids) prime_invadable_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(prime_invadable_system_ids) visible_system_ids = foAI.foAIstate.visInteriorSystemIDs.keys() + foAI.foAIstate. visBorderSystemIDs.keys() if home_system_id != -1: accessible_system_ids = [sys_id for sys_id in visible_system_ids if (sys_id != -1) and universe.systemsConnected(sys_id, home_system_id, empire_id)] else: print "Invasion Warning: this empire has no identifiable homeworld, will therefor treat all visible planets as accessible." accessible_system_ids = visible_system_ids # TODO: check if any troop ships still owned, use their system as home system acessible_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(accessible_system_ids) print "Accessible Systems: ", ", ".join(PlanetUtilsAI.sys_name_ids(accessible_system_ids)) print all_owned_planet_ids = PlanetUtilsAI.get_all_owned_planet_ids(acessible_planet_ids) # need these for unpopulated outposts all_populated_planets = PlanetUtilsAI.get_populated_planet_ids(acessible_planet_ids) # need this for natives print "All Visible and accessible Populated PlanetIDs (including this empire's): ", ", ".join(PlanetUtilsAI.planet_name_ids(all_populated_planets)) print print "Prime Invadable Target Systems: ", ", ".join(PlanetUtilsAI.sys_name_ids(prime_invadable_system_ids)) print empire_owned_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs) invadable_planet_ids = set(prime_invadable_planet_ids).intersection(set(all_owned_planet_ids).union(all_populated_planets) - set(empire_owned_planet_ids)) print "Prime Invadable PlanetIDs: ", ", ".join(PlanetUtilsAI.planet_name_ids(invadable_planet_ids)) print print "Current Invasion Targeted SystemIDs: ", ", ".join(PlanetUtilsAI.sys_name_ids(AIstate.invasionTargetedSystemIDs)) invasion_targeted_planet_ids = get_invasion_targeted_planet_ids(universe.planetIDs, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) invasion_targeted_planet_ids.extend(get_invasion_targeted_planet_ids(universe.planetIDs, EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION)) all_invasion_targeted_system_ids = set(PlanetUtilsAI.get_systems(invasion_targeted_planet_ids)) print "Current Invasion Targeted PlanetIDs: ", ", ".join(PlanetUtilsAI.planet_name_ids(invasion_targeted_planet_ids)) invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) if not invasion_fleet_ids: print "Available Invasion Fleets: 0" else: print "Invasion FleetIDs: %s" % FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) num_invasion_fleets = len(FleetUtilsAI.extract_fleet_ids_without_mission_types(invasion_fleet_ids)) print "Invasion Fleets Without Missions: %s" % num_invasion_fleets invasion_timer.start("planning troop base production") # only do base invasions if aggression is typical or above reserved_troop_base_targets = [] if foAI.foAIstate.aggression > fo.aggression.typical: available_pp = {} for el in empire.planetsWithAvailablePP: # keys are sets of ints; data is doubles avail_pp = el.data() for pid in el.key(): available_pp[pid] = avail_pp for pid in invadable_planet_ids: # TODO: reorganize planet = universe.getPlanet(pid) if not planet: continue sys_id = planet.systemID sys_partial_vis_turn = universe.getVisibilityTurnsMap(planet.systemID, empire_id).get(fo.visibility.partial, -9999) planet_partial_vis_turn = universe.getVisibilityTurnsMap(pid, empire_id).get(fo.visibility.partial, -9999) if planet_partial_vis_turn < sys_partial_vis_turn: continue for pid2 in ColonisationAI.empire_species_systems.get(sys_id, {}).get('pids', []): if available_pp.get(pid2, 0) < 2: # TODO: improve troop base PP sufficiency determination break planet2 = universe.getPlanet(pid2) if not planet2: continue if pid not in foAI.foAIstate.qualifyingTroopBaseTargets and planet2.speciesName in ColonisationAI.empire_ship_builders: foAI.foAIstate.qualifyingTroopBaseTargets.setdefault(pid, [pid2, -1]) break for pid in list(foAI.foAIstate.qualifyingTroopBaseTargets): planet = universe.getPlanet(pid) # TODO: also check that still have a colony in this system that can make troops if planet and planet.owner == empire_id: del foAI.foAIstate.qualifyingTroopBaseTargets[pid] secure_ai_fleet_missions = foAI.foAIstate.get_fleet_missions_with_any_mission_types([EnumsAI.AIFleetMissionType.FLEET_MISSION_SECURE]) for pid in (set(foAI.foAIstate.qualifyingTroopBaseTargets.keys()) - set(invasion_targeted_planet_ids)): # TODO: consider overriding standard invasion mission planet = universe.getPlanet(pid) if foAI.foAIstate.qualifyingTroopBaseTargets[pid][1] != -1: reserved_troop_base_targets.append(pid) if planet: all_invasion_targeted_system_ids.add(planet.systemID) continue # already building for here sys_id = planet.systemID this_sys_status = foAI.foAIstate.systemStatus.get(sys_id, {}) if (planet.currentMeterValue(fo.meterType.shield) > 0 and this_sys_status.get('myFleetRating', 0) < 0.8 * this_sys_status.get('totalThreat', 0)): continue loc = foAI.foAIstate.qualifyingTroopBaseTargets[pid][0] this_score, p_troops = evaluate_invasion_planet(pid, empire, secure_ai_fleet_missions, False) best_ship, col_design, build_choices = ProductionAI.getBestShipInfo(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_ORBITAL_INVASION, loc) if not best_ship: continue n_bases = math.ceil((p_troops+1) / 2) # TODO: reconsider this +1 safety factor retval = fo.issueEnqueueShipProductionOrder(best_ship, loc) print "Enqueueing %d Troop Bases at %s for %s" % (n_bases, PlanetUtilsAI.planet_name_ids([loc]), PlanetUtilsAI.planet_name_ids([pid])) if retval != 0: all_invasion_targeted_system_ids.add(planet.systemID) reserved_troop_base_targets.append(pid) foAI.foAIstate.qualifyingTroopBaseTargets[pid][1] = loc fo.issueChangeProductionQuantityOrder(empire.productionQueue.size - 1, 1, int(n_bases)) fo.issueRequeueProductionOrder(empire.productionQueue.size - 1, 0) invasion_timer.start("evaluating target planets") # TODO: check if any invasion_targeted_planet_ids need more troops assigned evaluated_planet_ids = list(set(invadable_planet_ids) - set(invasion_targeted_planet_ids) - set(reserved_troop_base_targets)) print "Evaluating potential invasions, PlanetIDs: %s" % evaluated_planet_ids evaluated_planets = assign_invasion_values(evaluated_planet_ids, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, fleet_suppliable_planet_ids, empire) sorted_planets = [(pid, pscore % 10000, ptroops) for pid, (pscore, ptroops) in evaluated_planets.items()] sorted_planets.sort(key=lambda x: x[1], reverse=True) sorted_planets = [(pid, pscore % 10000, ptroops) for pid, pscore, ptroops in sorted_planets] print if sorted_planets: print "Invadable planets:\n%-6s | %-6s | %-16s | %-16s | Troops" % ('ID', 'Score', 'Name', 'Race') for pid, pscore, ptroops in sorted_planets: planet = universe.getPlanet(pid) if planet: print "%6d | %6d | %16s | %16s | %d" % (pid, pscore, planet.name, planet.speciesName, ptroops) else: print "%6d | %6d | Error: invalid planet ID" % (pid, pscore) else: print "No Invadable planets identified" sorted_planets = filter(lambda x: x[1] > 0, sorted_planets) # export opponent planets for other AI modules AIstate.opponentPlanetIDs = [pid for pid, _, _ in sorted_planets] AIstate.invasionTargets = sorted_planets # export invasion targeted systems for other AI modules AIstate.invasionTargetedSystemIDs = list(all_invasion_targeted_system_ids) invasion_timer.stop(section_name="evaluating %d target planets" % (len(evaluated_planet_ids))) invasion_timer.end()
def get_invasion_fleets(): invasion_timer.start("gathering initial info") all_invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) AIstate.invasionFleetIDs = FleetUtilsAI.extract_fleet_ids_without_mission_types(all_invasion_fleet_ids) # get suppliable planets universe = fo.getUniverse() empire = fo.getEmpire() empire_id = empire.empireID capital_id = PlanetUtilsAI.get_capital() homeworld=None if capital_id: homeworld = universe.getPlanet(capital_id) if homeworld: home_system_id = homeworld.systemID else: home_system_id = -1 fleet_suppliable_system_ids = empire.fleetSupplyableSystemIDs fleet_suppliable_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(fleet_suppliable_system_ids) prime_invadable_system_ids = set(ColonisationAI.annexable_system_ids) prime_invadable_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(prime_invadable_system_ids) visible_system_ids = foAI.foAIstate.visInteriorSystemIDs.keys() + foAI.foAIstate. visBorderSystemIDs.keys() if home_system_id != -1: accessible_system_ids = [sys_id for sys_id in visible_system_ids if (sys_id != -1) and universe.systemsConnected(sys_id, home_system_id, empire_id)] else: print "Invasion Warning: this empire has no identifiable homeworld, will therefor treat all visible planets as accessible." accessible_system_ids = visible_system_ids # TODO: check if any troop ships still owned, use their system as home system acessible_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(accessible_system_ids) print "Accessible Systems: ", ", ".join(PlanetUtilsAI.sys_name_ids(accessible_system_ids)) print all_owned_planet_ids = PlanetUtilsAI.get_all_owned_planet_ids(acessible_planet_ids) # need these for unpopulated outposts all_populated_planets = PlanetUtilsAI.get_populated_planet_ids(acessible_planet_ids) # need this for natives print "All Visible and accessible Populated PlanetIDs (including this empire's): ", ", ".join(PlanetUtilsAI.planet_name_ids(all_populated_planets)) print print "Prime Invadable Target Systems: ", ", ".join(PlanetUtilsAI.sys_name_ids(prime_invadable_system_ids)) print empire_owned_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs) invadable_planet_ids = set(prime_invadable_planet_ids).intersection(set(all_owned_planet_ids).union(all_populated_planets) - set(empire_owned_planet_ids)) print "Prime Invadable PlanetIDs: ", ", ".join(PlanetUtilsAI.planet_name_ids(invadable_planet_ids)) print print "Current Invasion Targeted SystemIDs: ", ", ".join(PlanetUtilsAI.sys_name_ids(AIstate.invasionTargetedSystemIDs)) invasion_targeted_planet_ids = get_invasion_targeted_planet_ids(universe.planetIDs, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) invasion_targeted_planet_ids.extend(get_invasion_targeted_planet_ids(universe.planetIDs, EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION)) all_invasion_targeted_system_ids = set(PlanetUtilsAI.get_systems(invasion_targeted_planet_ids)) print "Current Invasion Targeted PlanetIDs: ", ", ".join(PlanetUtilsAI.planet_name_ids(invasion_targeted_planet_ids)) invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) if not invasion_fleet_ids: print "Available Invasion Fleets: 0" else: print "Invasion FleetIDs: %s" % FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) num_invasion_fleets = len(FleetUtilsAI.extract_fleet_ids_without_mission_types(invasion_fleet_ids)) print "Invasion Fleets Without Missions: %s" % num_invasion_fleets invasion_timer.start("planning troop base production") # only do base invasions if aggression is typical or above reserved_troop_base_targets = [] if foAI.foAIstate.aggression > fo.aggression.typical: available_pp = {} for el in empire.planetsWithAvailablePP: # keys are sets of ints; data is doubles avail_pp = el.data() for pid in el.key(): available_pp[pid] = avail_pp for pid in invadable_planet_ids: # TODO: reorganize planet = universe.getPlanet(pid) if not planet: continue sys_id = planet.systemID sys_partial_vis_turn = universe.getVisibilityTurnsMap(planet.systemID, empire_id).get(fo.visibility.partial, -9999) planet_partial_vis_turn = universe.getVisibilityTurnsMap(pid, empire_id).get(fo.visibility.partial, -9999) if planet_partial_vis_turn < sys_partial_vis_turn: continue for pid2 in ColonisationAI.empire_species_systems.get(sys_id, {}).get('pids', []): if available_pp.get(pid2, 0) < 2: # TODO: improve troop base PP sufficiency determination break planet2 = universe.getPlanet(pid2) if not planet2: continue if pid not in foAI.foAIstate.qualifyingTroopBaseTargets and planet2.speciesName in ColonisationAI.empire_ship_builders: foAI.foAIstate.qualifyingTroopBaseTargets.setdefault(pid, [pid2, -1]) break for pid in list(foAI.foAIstate.qualifyingTroopBaseTargets): planet = universe.getPlanet(pid) # TODO: also check that still have a colony in this system that can make troops if planet and planet.owner == empire_id: del foAI.foAIstate.qualifyingTroopBaseTargets[pid] secure_ai_fleet_missions = foAI.foAIstate.get_fleet_missions_with_any_mission_types([EnumsAI.AIFleetMissionType.FLEET_MISSION_SECURE]) for pid in (set(foAI.foAIstate.qualifyingTroopBaseTargets.keys()) - set(invasion_targeted_planet_ids)): # TODO: consider overriding standard invasion mission planet = universe.getPlanet(pid) if foAI.foAIstate.qualifyingTroopBaseTargets[pid][1] != -1: reserved_troop_base_targets.append(pid) if planet: all_invasion_targeted_system_ids.add(planet.systemID) continue # already building for here sys_id = planet.systemID this_sys_status = foAI.foAIstate.systemStatus.get(sys_id, {}) if (planet.currentMeterValue(fo.meterType.shield) > 0 and this_sys_status.get('myFleetRating', 0) < 0.8 * this_sys_status.get('totalThreat', 0)): continue loc = foAI.foAIstate.qualifyingTroopBaseTargets[pid][0] best_base_trooper_here = ProductionAI.getBestShipInfo(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_ORBITAL_INVASION, loc)[1] if best_base_trooper_here == None: # shouldn't be possible at this point, but just to be safe continue # TODO: have TroopShipDesigner give the expected number of troops including species effects troops_per_ship = best_base_trooper_here.troopCapacity if not troops_per_ship: continue this_score, p_troops = evaluate_invasion_planet(pid, empire, secure_ai_fleet_missions, False) best_ship, col_design, build_choices = ProductionAI.getBestShipInfo(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_ORBITAL_INVASION, loc) if not best_ship: continue n_bases = math.ceil((p_troops+1) / troops_per_ship) # TODO: reconsider this +1 safety factor print "Invasion base planning, need %d troops at %d pership, will build %d ships." % ((p_troops+1), troops_per_ship, n_bases) retval = fo.issueEnqueueShipProductionOrder(best_ship, loc) print "Enqueueing %d Troop Bases at %s for %s" % (n_bases, PlanetUtilsAI.planet_name_ids([loc]), PlanetUtilsAI.planet_name_ids([pid])) if retval != 0: all_invasion_targeted_system_ids.add(planet.systemID) reserved_troop_base_targets.append(pid) foAI.foAIstate.qualifyingTroopBaseTargets[pid][1] = loc fo.issueChangeProductionQuantityOrder(empire.productionQueue.size - 1, 1, int(n_bases)) fo.issueRequeueProductionOrder(empire.productionQueue.size - 1, 0) invasion_timer.start("evaluating target planets") # TODO: check if any invasion_targeted_planet_ids need more troops assigned evaluated_planet_ids = list(set(invadable_planet_ids) - set(invasion_targeted_planet_ids) - set(reserved_troop_base_targets)) print "Evaluating potential invasions, PlanetIDs: %s" % evaluated_planet_ids evaluated_planets = assign_invasion_values(evaluated_planet_ids, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, fleet_suppliable_planet_ids, empire) sorted_planets = [(pid, pscore % 10000, ptroops) for pid, (pscore, ptroops) in evaluated_planets.items()] sorted_planets.sort(key=lambda x: x[1], reverse=True) sorted_planets = [(pid, pscore % 10000, ptroops) for pid, pscore, ptroops in sorted_planets] print if sorted_planets: print "Invadable planets:\n%-6s | %-6s | %-16s | %-16s | Troops" % ('ID', 'Score', 'Name', 'Race') for pid, pscore, ptroops in sorted_planets: planet = universe.getPlanet(pid) if planet: print "%6d | %6d | %16s | %16s | %d" % (pid, pscore, planet.name, planet.speciesName, ptroops) else: print "%6d | %6d | Error: invalid planet ID" % (pid, pscore) else: print "No Invadable planets identified" sorted_planets = filter(lambda x: x[1] > 0, sorted_planets) # export opponent planets for other AI modules AIstate.opponentPlanetIDs = [pid for pid, _, _ in sorted_planets] AIstate.invasionTargets = sorted_planets # export invasion targeted systems for other AI modules AIstate.invasionTargetedSystemIDs = list(all_invasion_targeted_system_ids) invasion_timer.stop(section_name="evaluating %d target planets" % (len(evaluated_planet_ids))) invasion_timer.end()
def calculateInvasionPriority(): """calculates the demand for troop ships by opponent planets""" global allottedInvasionTargets if foAI.foAIstate.aggression <= fo.aggression.turtle: return 0 empire = fo.getEmpire() enemies_sighted = foAI.foAIstate.misc.get("enemies_sighted", {}) multiplier = 1 num_colonies = len(list(AIstate.popCtrIDs)) if num_colonies > colony_growth_barrier: return 0.0 if len(foAI.foAIstate.colonisablePlanetIDs) > 0: best_colony_score = max(2, foAI.foAIstate.colonisablePlanetIDs.items()[0][1][0]) else: best_colony_score = 2 if foAI.foAIstate.aggression == fo.aggression.beginner and fo.currentTurn() < 150: return 0 allottedInvasionTargets = 1 + int(fo.currentTurn() / 25) total_val = 0 troops_needed = 0 for pid, pscore, trp in AIstate.invasionTargets[:allottedInvasionTargets]: if pscore > best_colony_score: multiplier += 1 total_val += 2 * pscore else: total_val += pscore troops_needed += trp + 4 # ToDo: This seems like it could be improved by some dynamic calculation of buffer if total_val == 0: return 0 production_queue = empire.productionQueue queued_troop_capacity = 0 for queue_index in range(0, len(production_queue)): element = production_queue[queue_index] if element.buildType == EnumsAI.AIEmpireProductionTypes.BT_SHIP: if foAI.foAIstate.get_ship_role(element.designID) in [ EnumsAI.AIShipRoleType.SHIP_ROLE_MILITARY_INVASION, EnumsAI.AIShipRoleType.SHIP_ROLE_BASE_INVASION, ]: design = fo.getShipDesign(element.designID) queued_troop_capacity += element.remaining * element.blocksize * design.troopCapacity _, best_design, _ = ProductionAI.getBestShipInfo(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_INVASION) if best_design: troops_per_best_ship = best_design.troopCapacity else: return 1e-6 # if we can not build troop ships, we don't want to build (non-existing) invasion ships # don't count troop bases hereas these cannot be redeployed after misplaning # troopFleetIDs = FleetUtilsAI.get_empire_fleet_ids_by_role(AIFleetMissionType.FLEET_MISSION_INVASION)\ # + FleetUtilsAI.get_empire_fleet_ids_by_role(AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION) troop_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) total_troop_capacity = sum([FleetUtilsAI.count_troops_in_fleet(fid) for fid in troop_fleet_ids]) troop_ships_needed = math.ceil( (troops_needed - (total_troop_capacity + queued_troop_capacity)) / troops_per_best_ship ) # invasion_priority = max( 10+ 200*max(0, troop_ships_needed ) , int(0.1* total_val) ) invasion_priority = multiplier * (30 + 150 * max(0, troop_ships_needed)) if not ColonisationAI.colony_status.get("colonies_under_attack", []): if not ColonisationAI.colony_status.get("colonies_under_threat", []): invasion_priority *= 2.0 else: invasion_priority *= 1.5 if not enemies_sighted: invasion_priority *= 1.5 if invasion_priority < 0: return 0 if foAI.foAIstate.aggression == fo.aggression.beginner: return 0.5 * invasion_priority else: return invasion_priority
def getInvasionFleets(): "get invasion fleets" times=[] tasks = [] times.append( time() ) tasks.append("init") allInvasionFleetIDs = FleetUtilsAI.getEmpireFleetIDsByRole(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) AIstate.invasionFleetIDs = FleetUtilsAI.extractFleetIDsWithoutMissionTypes(allInvasionFleetIDs) # get supplyable planets universe = fo.getUniverse() empire = fo.getEmpire() empireID = empire.empireID capitalID = PlanetUtilsAI.getCapital() #capitalID = empire.capitalID homeworld=None if capitalID: homeworld = universe.getPlanet(capitalID) if homeworld: homeSystemID = homeworld.systemID else: speciesName = "" homeworldName=" no remaining homeworld " homeSystemID = -1 fleetSupplyableSystemIDs = empire.fleetSupplyableSystemIDs fleetSupplyablePlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(fleetSupplyableSystemIDs) primeInvadableSystemIDs = set(ColonisationAI.annexableSystemIDs) primeInvadablePlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(primeInvadableSystemIDs) # get competitor planets exploredSystemIDs = empire.exploredSystemIDs exploredPlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(exploredSystemIDs) visibleSystemIDs = foAI.foAIstate.visInteriorSystemIDs.keys() + foAI.foAIstate. visBorderSystemIDs.keys() visiblePlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(visibleSystemIDs) if homeSystemID != -1: accessibleSystemIDs = [sysID for sysID in visibleSystemIDs if (sysID != -1 ) and universe.systemsConnected(sysID, homeSystemID, empireID) ] else: print "Invasion Warning: this empire has no identifiable homeworld, will therefor treat all visible planets as accessible." accessibleSystemIDs = visibleSystemIDs #TODO: check if any troop ships still owned, use their system as home system acessiblePlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(accessibleSystemIDs) print "Accessible Systems: " + str(PlanetUtilsAI.sysNameIDs(accessibleSystemIDs)) print #allOwnedPlanetIDs = PlanetUtilsAI.getAllOwnedPlanetIDs(exploredPlanetIDs) allOwnedPlanetIDs = PlanetUtilsAI.getAllOwnedPlanetIDs(acessiblePlanetIDs)#need these for unpopulated outposts # print "All Owned and Populated PlanetIDs: " + str(allOwnedPlanetIDs) allPopulatedPlanets=PlanetUtilsAI.getPopulatedPlanetIDs(acessiblePlanetIDs)#need this for natives print "All Visible and accessible Populated PlanetIDs (including this empire's): " + str(PlanetUtilsAI.planetNameIDs(allPopulatedPlanets)) print print "Prime Invadable Target Systems: " + str(PlanetUtilsAI.sysNameIDs(primeInvadableSystemIDs)) print empireOwnedPlanetIDs = PlanetUtilsAI.getOwnedPlanetsByEmpire(universe.planetIDs, empireID) # print "Empire Owned PlanetIDs: " + str(empireOwnedPlanetIDs) invadablePlanetIDs = set(primeInvadablePlanetIDs).intersection(set(allOwnedPlanetIDs).union(allPopulatedPlanets) - set(empireOwnedPlanetIDs)) print "Prime Invadable PlanetIDs: " + str(PlanetUtilsAI.planetNameIDs(invadablePlanetIDs)) print "" print "Current Invasion Targeted SystemIDs: " + str(PlanetUtilsAI.sysNameIDs(AIstate.invasionTargetedSystemIDs)) invasionTargetedPlanetIDs = getInvasionTargetedPlanetIDs(universe.planetIDs, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, empireID) invasionTargetedPlanetIDs.extend( getInvasionTargetedPlanetIDs(universe.planetIDs, EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION, empireID)) allInvasionTargetedSystemIDs = set(PlanetUtilsAI.getSystems(invasionTargetedPlanetIDs)) print "Current Invasion Targeted PlanetIDs: " + str(PlanetUtilsAI.planetNameIDs(invasionTargetedPlanetIDs)) invasionFleetIDs = FleetUtilsAI.getEmpireFleetIDsByRole(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) if not invasionFleetIDs: print "Available Invasion Fleets: 0" else: print "Invasion FleetIDs: " + str(FleetUtilsAI.getEmpireFleetIDsByRole(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION)) numInvasionFleets = len(FleetUtilsAI.extractFleetIDsWithoutMissionTypes(invasionFleetIDs)) print "Invasion Fleets Without Missions: " + str(numInvasionFleets) times.append( time() ) tasks.append( "gathering initial info" ) availablePP = {} for el in empire.planetsWithAvailablePP: #keys are sets of ints; data is doubles avail_pp = el.data() for pid in el.key(): availablePP[pid] = avail_pp if len (invadablePlanetIDs) > 0: #print "Evaluating Troop Bases (SpaceInvaders) for %s"%(invadablePlanetIDs) pass for pid in invadablePlanetIDs: #TODO: reorganize planet = universe.getPlanet(pid) if not planet: continue sysID = planet.systemID sysPartialVisTurn = dictFromMap(universe.getVisibilityTurnsMap(planet.systemID, empireID)).get(fo.visibility.partial, -9999) planetPartialVisTurn = dictFromMap(universe.getVisibilityTurnsMap(pid, empireID)).get(fo.visibility.partial, -9999) if (planetPartialVisTurn < sysPartialVisTurn): #print "rejecting %s due to stealth"%planet.name continue for pid2 in ColonisationAI.empireSpeciesSystems.get(sysID, {}).get('pids', []): if availablePP.get(pid2, 0) < 2: #TODO: improve troop base PP sufficiency determination #print "rejecting %s due to insufficient avail PP"%planet.name break planet2 = universe.getPlanet(pid2) if not planet2: continue if (pid not in foAI.foAIstate.qualifyingTroopBaseTargets) and (planet2.speciesName in ColonisationAI.empireShipBuilders): #print "Adding %s to Troop Bases (SpaceInvaders) potential target list, from %s"%(planet.name, planet2.name) foAI.foAIstate.qualifyingTroopBaseTargets.setdefault(pid, [pid2, -1]) break for pid in list(foAI.foAIstate.qualifyingTroopBaseTargets): planet = universe.getPlanet(pid) if planet and planet.owner == empireID: del foAI.foAIstate.qualifyingTroopBaseTargets[pid] reserved_troop_base_targets = [] secureAIFleetMissions = foAI.foAIstate.getAIFleetMissionsWithAnyMissionTypes([EnumsAI.AIFleetMissionType.FLEET_MISSION_SECURE]) #print "considering possible troop bases at %s" % (foAI.foAIstate.qualifyingTroopBaseTargets.keys()) for pid in (set(foAI.foAIstate.qualifyingTroopBaseTargets.keys()) - set(invasionTargetedPlanetIDs)): #TODO: consider overriding standard invasion mission planet = universe.getPlanet(pid) if foAI.foAIstate.qualifyingTroopBaseTargets[pid][1] != -1: reserved_troop_base_targets.append(pid) if planet: allInvasionTargetedSystemIDs.add( planet.systemID ) continue #already building for here loc = foAI.foAIstate.qualifyingTroopBaseTargets[pid][0] this_score, p_troops = evaluateInvasionPlanet(pid, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, fleetSupplyablePlanetIDs, empire, secureAIFleetMissions, False) if (planet.currentMeterValue(fo.meterType.shield)) > 0: continue bestShip, colDesign, buildChoices = ProductionAI.getBestShipInfo(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_ORBITAL_INVASION, loc) if not bestShip: #print "Error: no troop base can be built at ", PlanetUtilsAI.planetNameIDs([loc]) continue #print "selecting ", PlanetUtilsAI.planetNameIDs([loc]), " to build Orbital troop bases" n_bases = math.ceil((p_troops+1) / 2)#TODO: reconsider this +1 safety factor retval = fo.issueEnqueueShipProductionOrder(bestShip, loc) print "Enqueueing %d Troop Bases at %s for %s"%( n_bases, PlanetUtilsAI.planetNameIDs([loc]), PlanetUtilsAI.planetNameIDs([pid])) if retval !=0: allInvasionTargetedSystemIDs.add( planet.systemID ) reserved_troop_base_targets.append(pid) foAI.foAIstate.qualifyingTroopBaseTargets[pid][1] = loc fo.issueChangeProductionQuantityOrder(empire.productionQueue.size -1, 1, int(n_bases)) res=fo.issueRequeueProductionOrder(empire.productionQueue.size -1, 0) times.append( time() ) tasks.append( "planning troop base production" ) #TODO: check if any invasionTargetedPlanetIDs need more troops assigned evaluatedPlanetIDs = list(set(invadablePlanetIDs) - set(invasionTargetedPlanetIDs) - set(reserved_troop_base_targets) ) print "Evaluating potential invasions, PlanetIDs: " + str(evaluatedPlanetIDs) evaluatedPlanets = assignInvasionValues(evaluatedPlanetIDs, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, fleetSupplyablePlanetIDs, empire) sortedPlanets = [(pid, pscore, ptroops) for (pid, (pscore, ptroops)) in evaluatedPlanets.items() ] sortedPlanets.sort(lambda x, y: cmp(x[1], y[1]), reverse=True) sortedPlanets = [(pid, pscore%10000, ptroops) for (pid, pscore, ptroops) in sortedPlanets ] times.append( time() ) tasks.append( "evaluating %d target planets"%(len(evaluatedPlanetIDs)) ) print "" if sortedPlanets: print "Invadable planets\nIDs, ID | Score | Name | Race | Troops" for pid, pscore, ptroops in sortedPlanets: planet = universe.getPlanet(pid) if planet: print "%6d | %6d | %16s | %16s | %d"%(pid, pscore, planet.name, planet.speciesName, ptroops) else: print "%6d | %6d | Error: invalid planet ID"%(pid, pscore) else: print "No Invadable planets identified" sortedPlanets = [(pid, pscore, ptroops) for (pid, pscore, ptroops) in sortedPlanets if pscore > 0] # export opponent planets for other AI modules AIstate.opponentPlanetIDs = [pid for pid, pscore, trp in sortedPlanets] AIstate.invasionTargets = sortedPlanets # export invasion targeted systems for other AI modules AIstate.invasionTargetedSystemIDs = list(allInvasionTargetedSystemIDs) times.append( time() ) tasks.append( "total processing" ) for t_index in range(1, len(times)-1): print "getInvasionFleets(): %40s took %d msec"%(tasks[t_index], int(1000*(times[t_index]-times[t_index-1]))) print "getInvasionFleets(): %40s took %d msec"%(tasks[-1], int(1000*(times[-1]-times[0])))
def calculateInvasionPriority(): """calculates the demand for troop ships by opponent planets""" global allottedInvasionTargets if foAI.foAIstate.aggression <= fo.aggression.turtle: return 0 troopsPerPod=2 empire=fo.getEmpire() enemies_sighted = foAI.foAIstate.misc.get('enemies_sighted',{}) multiplier = 1 num_colonies = len( list(AIstate.popCtrIDs) ) if num_colonies > colonyGrowthBarrier: return 0.0 if len(foAI.foAIstate.colonisablePlanetIDs) > 0: bestColonyScore = max( 2, foAI.foAIstate.colonisablePlanetIDs[0][1][0] ) else: bestColonyScore = 2 if foAI.foAIstate.aggression==fo.aggression.beginner and fo.currentTurn()<150: return 0 allottedInvasionTargets = 1+ int(fo.currentTurn()/25) totalVal = 0 troopsNeeded = 0 for pid, pscore, trp in AIstate.invasionTargets[:allottedInvasionTargets]: if pscore > bestColonyScore: multiplier += 1 totalVal += 2 * pscore else: totalVal += pscore troopsNeeded += trp+4 if totalVal == 0: return 0 opponentTroopPods = int(troopsNeeded/troopsPerPod) productionQueue = empire.productionQueue queuedTroopPods=0 for queue_index in range(0, len(productionQueue)): element=productionQueue[queue_index] if element.buildType == EnumsAI.AIEmpireProductionTypes.BT_SHIP: if foAI.foAIstate.get_ship_role(element.designID) in [ EnumsAI.AIShipRoleType.SHIP_ROLE_MILITARY_INVASION, EnumsAI.AIShipRoleType.SHIP_ROLE_BASE_INVASION] : design = fo.getShipDesign(element.designID) queuedTroopPods += element.remaining*element.blocksize * list(design.parts).count("GT_TROOP_POD") bestShip, bestDesign, buildChoices = ProductionAI.getBestShipInfo( EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_INVASION) if bestDesign: troopsPerBestShip = troopsPerPod*( list(bestDesign.parts).count("GT_TROOP_POD") ) else: troopsPerBestShip=troopsPerPod #may actually not have any troopers available, but this num will do for now #don't cound troop bases here since if through misplanning cannot be used where made, cannot be redeployed #troopFleetIDs = FleetUtilsAI.get_empire_fleet_ids_by_role(AIFleetMissionType.FLEET_MISSION_INVASION) + FleetUtilsAI.get_empire_fleet_ids_by_role(AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION) troopFleetIDs = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) numTroopPods = sum([ FleetUtilsAI.count_parts_fleetwide(fleetID, ["GT_TROOP_POD"]) for fleetID in troopFleetIDs]) troopShipsNeeded = math.ceil((opponentTroopPods - (numTroopPods+ queuedTroopPods ))/troopsPerBestShip) #invasionPriority = max( 10+ 200*max(0, troopShipsNeeded ) , int(0.1* totalVal) ) invasionPriority = multiplier * (30+ 150*max(0, troopShipsNeeded )) if not ColonisationAI.colony_status.get('colonies_under_attack', []): if not ColonisationAI.colony_status.get('colonies_under_threat', []): invasionPriority *= 2.0 else: invasionPriority *= 1.5 if not enemies_sighted: invasionPriority *= 1.5 if invasionPriority < 0: return 0 if foAI.foAIstate.aggression==fo.aggression.beginner: return 0.5* invasionPriority else: return invasionPriority
def get_invasion_fleets(): """get invasion fleets""" invasion_timer.start("gathering initial info") all_invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) AIstate.invasionFleetIDs = FleetUtilsAI.extract_fleet_ids_without_mission_types(all_invasion_fleet_ids) # get supplyable planets universe = fo.getUniverse() empire = fo.getEmpire() empire_id = empire.empireID capital_id = PlanetUtilsAI.get_capital() homeworld=None if capital_id: homeworld = universe.getPlanet(capital_id) if homeworld: home_system_id = homeworld.systemID else: home_system_id = -1 fleet_supplyable_system_ids = empire.fleetSupplyableSystemIDs fleet_supplyable_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(fleet_supplyable_system_ids) prime_invadable_system_ids = set(ColonisationAI.annexableSystemIDs) prime_invadable_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(prime_invadable_system_ids) visible_system_ids = foAI.foAIstate.visInteriorSystemIDs.keys() + foAI.foAIstate. visBorderSystemIDs.keys() if home_system_id != -1: accessible_system_ids = [sys_id for sys_id in visible_system_ids if (sys_id != -1 ) and universe.systemsConnected(sys_id, home_system_id, empire_id) ] else: print "Invasion Warning: this empire has no identifiable homeworld, will therefor treat all visible planets as accessible." accessible_system_ids = visible_system_ids #TODO: check if any troop ships still owned, use their system as home system acessible_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(accessible_system_ids) print "Accessible Systems: ", ", ".join(PlanetUtilsAI.sys_name_ids(accessible_system_ids)) print #all_owned_planet_ids = PlanetUtilsAI.get_all_owned_planet_ids(exploredPlanetIDs) all_owned_planet_ids = PlanetUtilsAI.get_all_owned_planet_ids(acessible_planet_ids)#need these for unpopulated outposts # print "All Owned and Populated PlanetIDs: " + str(all_owned_planet_ids) all_populated_planets = PlanetUtilsAI.get_populated_planet_ids(acessible_planet_ids)#need this for natives print "All Visible and accessible Populated PlanetIDs (including this empire's): ", ", ".join(PlanetUtilsAI.planet_name_ids(all_populated_planets )) print print "Prime Invadable Target Systems: ", ", ".join(PlanetUtilsAI.sys_name_ids(prime_invadable_system_ids)) print empire_owned_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs) # print "Empire Owned PlanetIDs: " + str(empire_owned_planet_ids) invadable_planet_ids = set(prime_invadable_planet_ids).intersection(set(all_owned_planet_ids).union(all_populated_planets ) - set(empire_owned_planet_ids)) print "Prime Invadable PlanetIDs: ", ", ".join(PlanetUtilsAI.planet_name_ids(invadable_planet_ids)) print print "Current Invasion Targeted SystemIDs: ", ", ".join(PlanetUtilsAI.sys_name_ids(AIstate.invasionTargetedSystemIDs)) invasion_targeted_planet_ids = get_invasion_targeted_planet_ids(universe.planetIDs, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, empire_id) invasion_targeted_planet_ids.extend( get_invasion_targeted_planet_ids(universe.planetIDs, EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION, empire_id)) all_invasion_targeted_system_ids = set(PlanetUtilsAI.get_systems(invasion_targeted_planet_ids)) print "Current Invasion Targeted PlanetIDs: ", ", ".join(PlanetUtilsAI.planet_name_ids(invasion_targeted_planet_ids)) invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) if not invasion_fleet_ids: print "Available Invasion Fleets: 0" else: print "Invasion FleetIDs: " + str(FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION)) num_invasion_fleets = len(FleetUtilsAI.extract_fleet_ids_without_mission_types(invasion_fleet_ids)) print "Invasion Fleets Without Missions: " + str(num_invasion_fleets) invasion_timer.start("planning troop base production") # only do base invasions if aggression is typical or above reserved_troop_base_targets = [] if foAI.foAIstate.aggression > fo.aggression.typical: available_pp = {} for el in empire.planetsWithAvailablePP: #keys are sets of ints; data is doubles avail_pp = el.data() for pid in el.key(): available_pp[pid] = avail_pp if len (invadable_planet_ids) > 0: #print "Evaluating Troop Bases (SpaceInvaders) for %s"%(invadable_planet_ids) pass for pid in invadable_planet_ids: #TODO: reorganize planet = universe.getPlanet(pid) if not planet: continue sys_id = planet.systemID sys_partial_vis_turn = dict_from_map(universe.getVisibilityTurnsMap(planet.systemID, empire_id)).get(fo.visibility.partial, -9999) planet_partial_vis_turn = dict_from_map(universe.getVisibilityTurnsMap(pid, empire_id)).get(fo.visibility.partial, -9999) if planet_partial_vis_turn < sys_partial_vis_turn: #print "rejecting %s due to stealth"%planet.name continue for pid2 in ColonisationAI.empireSpeciesSystems.get(sys_id, {}).get('pids', []): if available_pp.get(pid2, 0) < 2: #TODO: improve troop base PP sufficiency determination #print "rejecting %s due to insufficient avail PP"%planet.name break planet2 = universe.getPlanet(pid2) if not planet2: continue if (pid not in foAI.foAIstate.qualifyingTroopBaseTargets) and (planet2.speciesName in ColonisationAI.empireShipBuilders): #print "Adding %s to Troop Bases (SpaceInvaders) potential target list, from %s"%(planet.name, planet2.name) foAI.foAIstate.qualifyingTroopBaseTargets.setdefault(pid, [pid2, -1]) break for pid in list(foAI.foAIstate.qualifyingTroopBaseTargets): planet = universe.getPlanet(pid) #TODO: also check that still have a colony in this system that can make troops if planet and planet.owner == empire_id: del foAI.foAIstate.qualifyingTroopBaseTargets[pid] secureAIFleetMissions = foAI.foAIstate.get_fleet_missions_with_any_mission_types([EnumsAI.AIFleetMissionType.FLEET_MISSION_SECURE]) #print "considering possible troop bases at %s" % (foAI.foAIstate.qualifyingTroopBaseTargets.keys()) for pid in (set(foAI.foAIstate.qualifyingTroopBaseTargets.keys()) - set(invasion_targeted_planet_ids)): #TODO: consider overriding standard invasion mission planet = universe.getPlanet(pid) if foAI.foAIstate.qualifyingTroopBaseTargets[pid][1] != -1: reserved_troop_base_targets.append(pid) if planet: all_invasion_targeted_system_ids.add( planet.systemID ) continue #already building for here sys_id = planet.systemID this_sys_status = foAI.foAIstate.systemStatus.get( sys_id, {} ) if ((planet.currentMeterValue(fo.meterType.shield) > 0) and (this_sys_status.get('myFleetRating', 0) < (0.8 * this_sys_status.get('totalThreat', 0)))): continue loc = foAI.foAIstate.qualifyingTroopBaseTargets[pid][0] this_score, p_troops = evaluate_invasion_planet(pid, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, fleet_supplyable_planet_ids, empire, secureAIFleetMissions, False) bestShip, colDesign, buildChoices = ProductionAI.getBestShipInfo(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_ORBITAL_INVASION, loc) if not bestShip: #print "Error: no troop base can be built at ", PlanetUtilsAI.planet_name_ids([loc]) continue #print "selecting ", PlanetUtilsAI.planet_name_ids([loc]), " to build Orbital troop bases" n_bases = math.ceil((p_troops+1) / 2)#TODO: reconsider this +1 safety factor retval = fo.issueEnqueueShipProductionOrder(bestShip, loc) print "Enqueueing %d Troop Bases at %s for %s"%( n_bases, PlanetUtilsAI.planet_name_ids([loc]), PlanetUtilsAI.planet_name_ids([pid])) if retval !=0: all_invasion_targeted_system_ids.add( planet.systemID ) reserved_troop_base_targets.append(pid) foAI.foAIstate.qualifyingTroopBaseTargets[pid][1] = loc fo.issueChangeProductionQuantityOrder(empire.productionQueue.size -1, 1, int(n_bases)) res=fo.issueRequeueProductionOrder(empire.productionQueue.size -1, 0) invasion_timer.start("evaluating target planets") #TODO: check if any invasion_targeted_planet_ids need more troops assigned evaluatedPlanetIDs = list(set(invadable_planet_ids) - set(invasion_targeted_planet_ids) - set(reserved_troop_base_targets) ) print "Evaluating potential invasions, PlanetIDs: " + str(evaluatedPlanetIDs) evaluatedPlanets = assign_invasion_values(evaluatedPlanetIDs, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, fleet_supplyable_planet_ids, empire) sortedPlanets = [(pid, pscore, ptroops) for (pid, (pscore, ptroops)) in evaluatedPlanets.items() ] sortedPlanets.sort(lambda x, y: cmp(x[1], y[1]), reverse=True) sortedPlanets = [(pid, pscore%10000, ptroops) for (pid, pscore, ptroops) in sortedPlanets ] print if sortedPlanets: print "Invadable planets\nIDs, ID | Score | Name | Race | Troops" for pid, pscore, ptroops in sortedPlanets: planet = universe.getPlanet(pid) if planet: print "%6d | %6d | %16s | %16s | %d"%(pid, pscore, planet.name, planet.speciesName, ptroops) else: print "%6d | %6d | Error: invalid planet ID"%(pid, pscore) else: print "No Invadable planets identified" sortedPlanets = [(pid, pscore, ptroops) for (pid, pscore, ptroops) in sortedPlanets if pscore > 0] # export opponent planets for other AI modules AIstate.opponentPlanetIDs = [pid for pid, pscore, trp in sortedPlanets] AIstate.invasionTargets = sortedPlanets # export invasion targeted systems for other AI modules AIstate.invasionTargetedSystemIDs = list(all_invasion_targeted_system_ids) invasion_timer.stop(section_name="evaluating %d target planets" % (len(evaluatedPlanetIDs))) invasion_timer.end()
def calculateInvasionPriority(): """calculates the demand for troop ships by opponent planets""" global allottedInvasionTargets if foAI.foAIstate.aggression <= fo.aggression.turtle: return 0 empire = fo.getEmpire() enemies_sighted = foAI.foAIstate.misc.get('enemies_sighted', {}) multiplier = 1 num_colonies = len(list(AIstate.popCtrIDs)) if num_colonies > colony_growth_barrier: return 0.0 if len(foAI.foAIstate.colonisablePlanetIDs) > 0: best_colony_score = max(2, foAI.foAIstate.colonisablePlanetIDs.items()[0][1][0]) else: best_colony_score = 2 if foAI.foAIstate.aggression == fo.aggression.beginner and fo.currentTurn() < 150: return 0 allottedInvasionTargets = 1 + int(fo.currentTurn()/25) total_val = 0 troops_needed = 0 for pid, pscore, trp in AIstate.invasionTargets[:allottedInvasionTargets]: if pscore > best_colony_score: multiplier += 1 total_val += 2 * pscore else: total_val += pscore troops_needed += trp+4 # ToDo: This seems like it could be improved by some dynamic calculation of buffer if total_val == 0: return 0 production_queue = empire.productionQueue queued_troop_capacity = 0 for queue_index in range(0, len(production_queue)): element = production_queue[queue_index] if element.buildType == EnumsAI.AIEmpireProductionTypes.BT_SHIP: if foAI.foAIstate.get_ship_role(element.designID) in [EnumsAI.AIShipRoleType.SHIP_ROLE_MILITARY_INVASION, EnumsAI.AIShipRoleType.SHIP_ROLE_BASE_INVASION]: design = fo.getShipDesign(element.designID) queued_troop_capacity += element.remaining * element.blocksize * design.troopCapacity _, best_design, _ = ProductionAI.getBestShipInfo(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_INVASION) if best_design: troops_per_best_ship = best_design.troopCapacity else: return 1e-6 # if we can not build troop ships, we don't want to build (non-existing) invasion ships # don't count troop bases hereas these cannot be redeployed after misplaning # troopFleetIDs = FleetUtilsAI.get_empire_fleet_ids_by_role(AIFleetMissionType.FLEET_MISSION_INVASION)\ # + FleetUtilsAI.get_empire_fleet_ids_by_role(AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION) troop_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) total_troop_capacity = sum([FleetUtilsAI.count_troops_in_fleet(fid) for fid in troop_fleet_ids]) troop_ships_needed = \ math.ceil((troops_needed - (total_troop_capacity+queued_troop_capacity)) / troops_per_best_ship) # invasion_priority = max( 10+ 200*max(0, troop_ships_needed ) , int(0.1* total_val) ) invasion_priority = multiplier * (30 + 150*max(0, troop_ships_needed)) if not ColonisationAI.colony_status.get('colonies_under_attack', []): if not ColonisationAI.colony_status.get('colonies_under_threat', []): invasion_priority *= 2.0 else: invasion_priority *= 1.5 if not enemies_sighted: invasion_priority *= 1.5 if invasion_priority < 0: return 0 if foAI.foAIstate.aggression == fo.aggression.beginner: return 0.5 * invasion_priority else: return invasion_priority
def calculateInvasionPriority(): """calculates the demand for troop ships by opponent planets""" global allottedInvasionTargets if foAI.foAIstate.aggression <= fo.aggression.turtle: return 0 troopsPerPod = 2 empire = fo.getEmpire() enemies_sighted = foAI.foAIstate.misc.get('enemies_sighted', {}) multiplier = 1 num_colonies = len(list(AIstate.popCtrIDs)) if num_colonies > colonyGrowthBarrier: return 0.0 if len(foAI.foAIstate.colonisablePlanetIDs) > 0: bestColonyScore = max( 2, foAI.foAIstate.colonisablePlanetIDs.items()[0][1][0]) else: bestColonyScore = 2 if foAI.foAIstate.aggression == fo.aggression.beginner and fo.currentTurn( ) < 150: return 0 allottedInvasionTargets = 1 + int(fo.currentTurn() / 25) totalVal = 0 troopsNeeded = 0 for pid, pscore, trp in AIstate.invasionTargets[:allottedInvasionTargets]: if pscore > bestColonyScore: multiplier += 1 totalVal += 2 * pscore else: totalVal += pscore troopsNeeded += trp + 4 if totalVal == 0: return 0 opponentTroopPods = int(troopsNeeded / troopsPerPod) productionQueue = empire.productionQueue queuedTroopPods = 0 for queue_index in range(0, len(productionQueue)): element = productionQueue[queue_index] if element.buildType == EnumsAI.AIEmpireProductionTypes.BT_SHIP: if foAI.foAIstate.get_ship_role(element.designID) in [ EnumsAI.AIShipRoleType.SHIP_ROLE_MILITARY_INVASION, EnumsAI.AIShipRoleType.SHIP_ROLE_BASE_INVASION ]: design = fo.getShipDesign(element.designID) queuedTroopPods += element.remaining * element.blocksize * list( design.parts).count("GT_TROOP_POD") bestShip, bestDesign, buildChoices = ProductionAI.getBestShipInfo( EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_INVASION) if bestDesign: troopsPerBestShip = troopsPerPod * (list( bestDesign.parts).count("GT_TROOP_POD")) else: troopsPerBestShip = troopsPerPod #may actually not have any troopers available, but this num will do for now #don't cound troop bases here since if through misplanning cannot be used where made, cannot be redeployed #troopFleetIDs = FleetUtilsAI.get_empire_fleet_ids_by_role(AIFleetMissionType.FLEET_MISSION_INVASION) + FleetUtilsAI.get_empire_fleet_ids_by_role(AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION) troopFleetIDs = FleetUtilsAI.get_empire_fleet_ids_by_role( EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) numTroopPods = sum([ FleetUtilsAI.count_parts_fleetwide(fleetID, ["GT_TROOP_POD"]) for fleetID in troopFleetIDs ]) troopShipsNeeded = math.ceil( (opponentTroopPods - (numTroopPods + queuedTroopPods)) / troopsPerBestShip) #invasionPriority = max( 10+ 200*max(0, troopShipsNeeded ) , int(0.1* totalVal) ) invasionPriority = multiplier * (30 + 150 * max(0, troopShipsNeeded)) if not ColonisationAI.colony_status.get('colonies_under_attack', []): if not ColonisationAI.colony_status.get('colonies_under_threat', []): invasionPriority *= 2.0 else: invasionPriority *= 1.5 if not enemies_sighted: invasionPriority *= 1.5 if invasionPriority < 0: return 0 if foAI.foAIstate.aggression == fo.aggression.beginner: return 0.5 * invasionPriority else: return invasionPriority