def send_invasion_fleets(fleet_ids, evaluated_planets, mission_type): """sends a list of invasion fleets to a list of planet_value_pairs""" if not fleet_ids: return universe = fo.getUniverse() invasion_fleet_pool = set(fleet_ids) for planet_id, pscore, ptroops in evaluated_planets: if pscore < MIN_INVASION_SCORE: continue planet = universe.getPlanet(planet_id) if not planet: continue sys_id = planet.systemID found_fleets = [] found_stats = {} min_stats = {"troopCapacity": ptroops} target_stats = { "troopCapacity": ptroops + _TROOPS_SAFETY_MARGIN, "target_system": TargetSystem(sys_id), } these_fleets = FleetUtilsAI.get_fleets_for_mission( target_stats, min_stats, found_stats, starting_system=sys_id, fleet_pool_set=invasion_fleet_pool, fleet_list=found_fleets, ) if not these_fleets: if not FleetUtilsAI.stats_meet_reqs(found_stats, min_stats): debug( "Insufficient invasion troop allocation for system %d ( %s ) -- requested %s , found %s" % (sys_id, universe.getSystem(sys_id).name, min_stats, found_stats)) invasion_fleet_pool.update(found_fleets) continue else: these_fleets = found_fleets target = TargetPlanet(planet_id) debug("assigning invasion fleets %s to target %s" % (these_fleets, target)) if target.get_object().currentMeterValue( fo.meterType.maxShield) > 0.0 and not secure_system( sys_id, True): continue aistate = get_aistate() for fleetID in these_fleets: fleet_mission = aistate.get_fleet_mission(fleetID) fleet_mission.clear_fleet_orders() fleet_mission.clear_target() fleet_mission.set_target(mission_type, target) # cannot wait for next turn, else the secure mission may be abandoned if these_fleets and sys_id not in AIstate.invasionTargetedSystemIDs: AIstate.invasionTargetedSystemIDs.append(sys_id)
def get_invasion_targeted_planet_ids(planet_ids, mission_type): invasion_feet_missions = get_aistate().get_fleet_missions_with_any_mission_types([mission_type]) targeted_planets = [] for pid in planet_ids: # add planets that are target of a mission for mission in invasion_feet_missions: target = TargetPlanet(pid) if mission.has_target(mission_type, target): targeted_planets.append(pid) return targeted_planets
def assign_invasion_bases(): """Assign our troop bases to invasion targets.""" universe = fo.getUniverse() all_troopbase_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(MissionType.ORBITAL_INVASION) available_troopbase_fleet_ids = set(FleetUtilsAI.extract_fleet_ids_without_mission_types(all_troopbase_fleet_ids)) aistate = get_aistate() for fid in list(available_troopbase_fleet_ids): if fid not in available_troopbase_fleet_ids: # entry may have been discarded in previous loop iterations continue fleet = universe.getFleet(fid) if not fleet: continue sys_id = fleet.systemID system = universe.getSystem(sys_id) available_planets = set(system.planetIDs).intersection(set(aistate.qualifyingTroopBaseTargets.keys())) debug("Considering Base Troopers in %s, found planets %s and registered targets %s with status %s" % ( system.name, list(system.planetIDs), available_planets, [(pid, aistate.qualifyingTroopBaseTargets[pid]) for pid in available_planets])) targets = [pid for pid in available_planets if aistate.qualifyingTroopBaseTargets[pid][1] != -1] if not targets: debug("Failure: found no valid target for troop base in system %s" % system) continue status = aistate.systemStatus.get(sys_id, {}) local_base_troops = set(status.get('myfleets', [])).intersection(available_troopbase_fleet_ids) target_id = INVALID_ID best_score = -1 target_troops = 0 for pid, (p_score, p_troops) in assign_invasion_values(targets).items(): if p_score > best_score: best_score = p_score target_id = pid target_troops = p_troops if target_id == INVALID_ID: continue local_base_troops.discard(fid) found_fleets = [] troops_needed = max(0, target_troops - FleetUtilsAI.count_troops_in_fleet(fid)) found_stats = {} min_stats = {'rating': 0, 'troopCapacity': troops_needed} target_stats = {'rating': 10, 'troopCapacity': troops_needed + _TROOPS_SAFETY_MARGIN} FleetUtilsAI.get_fleets_for_mission(target_stats, min_stats, found_stats, starting_system=sys_id, fleet_pool_set=local_base_troops, fleet_list=found_fleets) for fid2 in found_fleets: FleetUtilsAI.merge_fleet_a_into_b(fid2, fid) available_troopbase_fleet_ids.discard(fid2) available_troopbase_fleet_ids.discard(fid) aistate.qualifyingTroopBaseTargets[target_id][1] = -1 # TODO: should probably delete target = TargetPlanet(target_id) fleet_mission = aistate.get_fleet_mission(fid) fleet_mission.set_target(MissionType.ORBITAL_INVASION, target)
def send_invasion_fleets(fleet_ids, evaluated_planets, mission_type): """sends a list of invasion fleets to a list of planet_value_pairs""" if not fleet_ids: return universe = fo.getUniverse() invasion_fleet_pool = set(fleet_ids) for planet_id, pscore, ptroops in evaluated_planets: if pscore < MIN_INVASION_SCORE: continue planet = universe.getPlanet(planet_id) if not planet: continue sys_id = planet.systemID found_fleets = [] found_stats = {} min_stats = {"rating": 0, "troopCapacity": ptroops} target_stats = { "rating": 10, "troopCapacity": ptroops + _TROOPS_SAFETY_MARGIN, "target_system": TargetSystem(sys_id), } these_fleets = FleetUtilsAI.get_fleets_for_mission( target_stats, min_stats, found_stats, starting_system=sys_id, fleet_pool_set=invasion_fleet_pool, fleet_list=found_fleets, ) if not these_fleets: if not FleetUtilsAI.stats_meet_reqs(found_stats, min_stats): debug( "Insufficient invasion troop allocation for system %d ( %s ) -- requested %s , found %s" % (sys_id, universe.getSystem(sys_id).name, min_stats, found_stats)) invasion_fleet_pool.update(found_fleets) continue else: these_fleets = found_fleets target = TargetPlanet(planet_id) debug("assigning invasion fleets %s to target %s" % (these_fleets, target)) aistate = get_aistate() for fleetID in these_fleets: fleet_mission = aistate.get_fleet_mission(fleetID) fleet_mission.clear_fleet_orders() fleet_mission.clear_target() fleet_mission.set_target(mission_type, target)
def assign_base(self, fleet_id: int) -> bool: """ Assign an outpost base fleet to execute the plan. It is expected that the fleet consists of only that one outpost base. :return: True on success, False on failure """ if self.base_assigned: warning("Assigned a base to a plan that was already assigned a base to.") return False # give orders to perform the mission target = TargetPlanet(self.target) fleet_mission = get_aistate().get_fleet_mission(fleet_id) fleet_mission.set_target(MissionType.ORBITAL_OUTPOST, target) self.fleet_id = fleet_id return True
def get_targeted_planet_ids(planet_ids: Sequence[PlanetId], mission_type: MissionType) -> List[PlanetId]: """Find the planets that are targets of the specified mission type. :param planet_ids: planets to be queried :param mission_type: :return: Subset of *planet_ids* targeted by *mission_type* """ selected_fleet_missions = get_aistate( ).get_fleet_missions_with_any_mission_types([mission_type]) targeted_planets = [] for planet_id in planet_ids: # add planets that are target of a mission for fleet_mission in selected_fleet_missions: ai_target = TargetPlanet(planet_id) if fleet_mission.has_target(mission_type, ai_target): targeted_planets.append(planet_id) return targeted_planets
def _check_retarget_invasion(self): """checks if an invasion mission should be retargeted""" universe = fo.getUniverse() empire_id = fo.empireID() fleet_id = self.fleet.id fleet = universe.getFleet(fleet_id) if fleet.systemID == INVALID_ID: # next_loc = fleet.nextSystemID return # TODO: still check system = universe.getSystem(fleet.systemID) if not system: return orders = self.orders last_sys_target = INVALID_ID if orders: last_sys_target = orders[-1].target.id if last_sys_target == fleet.systemID: return # TODO: check for best local target open_targets = [] already_targeted = InvasionAI.get_invasion_targeted_planet_ids( system.planetIDs, MissionType.INVASION) aistate = get_aistate() for pid in system.planetIDs: if pid in already_targeted or ( pid in aistate.qualifyingTroopBaseTargets): continue planet = universe.getPlanet(pid) if planet.unowned or (planet.owner == empire_id): continue if (planet.initialMeterValue(fo.meterType.shield)) <= 0: open_targets.append(pid) if not open_targets: return troops_in_fleet = FleetUtilsAI.count_troops_in_fleet(fleet_id) target_id = INVALID_ID best_score = -1 target_troops = 0 # for pid, rating in InvasionAI.assign_invasion_values( open_targets).items(): p_score, p_troops = rating if p_score > best_score: if p_troops >= troops_in_fleet: continue best_score = p_score target_id = pid target_troops = p_troops if target_id == INVALID_ID: return debug("\t Splitting and retargetting fleet %d" % fleet_id) new_fleets = FleetUtilsAI.split_fleet(fleet_id) self.clear_target() # TODO: clear from foAIstate self.clear_fleet_orders() troops_needed = max( 0, target_troops - FleetUtilsAI.count_troops_in_fleet(fleet_id)) min_stats = {'rating': 0, 'troopCapacity': troops_needed} target_stats = {'rating': 10, 'troopCapacity': troops_needed} found_fleets = [] # TODO check if next statement does not mutate any global states and can be removed _ = FleetUtilsAI.get_fleets_for_mission( target_stats, min_stats, {}, starting_system=fleet.systemID, # noqa: F841 fleet_pool_set=set(new_fleets), fleet_list=found_fleets) for fid in found_fleets: FleetUtilsAI.merge_fleet_a_into_b(fid, fleet_id) target = TargetPlanet(target_id) self.set_target(MissionType.INVASION, target) self.generate_fleet_orders()
def send_colony_ships(colony_fleet_ids, evaluated_planets, mission_type): """sends a list of colony ships to a list of planet_value_pairs""" fleet_pool = colony_fleet_ids[:] try_all = False if mission_type == MissionType.OUTPOST: cost = 20 + outpod_pod_cost() else: try_all = True cost = 20 + colony_pod_cost_turns()[1] if fo.currentTurn() < 50: cost *= 0.4 # will be making fast tech progress so value is underestimated elif fo.currentTurn() < 80: cost *= 0.8 # will be making fast-ish tech progress so value is underestimated potential_targets = [ (pid, (score, specName)) for (pid, (score, specName)) in evaluated_planets if score > (0.8 * cost) and score > MINIMUM_COLONY_SCORE ] debug("Colony/outpost ship matching: fleets %s to planets %s" % (fleet_pool, evaluated_planets)) if try_all: debug("Trying best matches to current colony ships") best_scores = dict(evaluated_planets) potential_targets = [] for pid, ratings in _all_colony_opportunities.items(): for rating in ratings: if rating[0] >= 0.75 * best_scores.get(pid, [9999])[0]: potential_targets.append((pid, rating)) potential_targets.sort(key=itemgetter(1), reverse=True) # added a lot of checking because have been getting mysterious exception, after too many recursions to get info fleet_pool = set(fleet_pool) universe = fo.getUniverse() for fid in fleet_pool: fleet = universe.getFleet(fid) if not fleet or fleet.empty: warning("Bad fleet ( ID %d ) given to colonization routine; will be skipped" % fid) fleet_pool.remove(fid) continue report_str = "Fleet ID (%d): %d ships; species: " % (fid, fleet.numShips) for sid in fleet.shipIDs: ship = universe.getShip(sid) if not ship: report_str += "NoShip, " else: report_str += "%s, " % ship.speciesName debug(report_str) debug("") already_targeted = [] # for planetID_value_pair in evaluatedPlanets: aistate = get_aistate() while fleet_pool and potential_targets: target = potential_targets.pop(0) if target in already_targeted: continue planet_id = target[0] if planet_id in already_targeted: continue planet = universe.getPlanet(planet_id) sys_id = planet.systemID if ( aistate.systemStatus.setdefault(sys_id, {}).setdefault("monsterThreat", 0) > 2000 or fo.currentTurn() < 20 and aistate.systemStatus[sys_id]["monsterThreat"] > 200 ): debug( "Skipping colonization of system %s due to Big Monster, threat %d" % (universe.getSystem(sys_id), aistate.systemStatus[sys_id]["monsterThreat"]) ) already_targeted.append(planet_id) continue # make sure not to run into stationary guards if ExplorationAI.system_could_have_unknown_stationary_guard(sys_id): ExplorationAI.request_emergency_exploration(sys_id) continue this_spec = target[1][1] found_fleets = [] try: this_fleet_list = FleetUtilsAI.get_fleets_for_mission( target_stats={}, min_stats={}, cur_stats={}, starting_system=sys_id, species=this_spec, fleet_pool_set=fleet_pool, fleet_list=found_fleets, ) except Exception as e: error(e, exc_info=True) continue if not this_fleet_list: fleet_pool.update(found_fleets) # just to be safe continue # must have no compatible colony/outpost ships fleet_id = this_fleet_list[0] already_targeted.append(planet_id) ai_target = TargetPlanet(planet_id) aistate.get_fleet_mission(fleet_id).set_target(mission_type, ai_target)