def check_mergers(self, context=""): """ Merge local fleets with same mission into this fleet. :param context: Context of the function call for logging purposes :type context: str """ debug("Considering to merge %s", self.__str__()) if self.type not in MERGEABLE_MISSION_TYPES: debug("Mission type does not allow merging.") return if not self.target: debug("Mission has no valid target - do not merge.") return universe = fo.getUniverse() empire_id = fo.empireID() fleet_id = self.fleet.id main_fleet = universe.getFleet(fleet_id) main_fleet_system_id = main_fleet.systemID if main_fleet_system_id == INVALID_ID: debug("Can't merge: fleet in middle of starlane.") return # only merge PROTECT_REGION if there is any threat near target if self.type == MissionType.PROTECT_REGION: neighbor_systems = universe.getImmediateNeighbors( self.target.id, empire_id) if not any( MilitaryAI.get_system_local_threat(sys_id) for sys_id in neighbor_systems): debug("Not merging PROTECT_REGION fleet - no threat nearby.") return destroyed_list = set(universe.destroyedObjectIDs(empire_id)) aistate = get_aistate() system_status = aistate.systemStatus[main_fleet_system_id] other_fleets_here = [ fid for fid in system_status.get('myFleetsAccessible', []) if fid != fleet_id and fid not in destroyed_list and universe.getFleet(fid).ownedBy(empire_id) ] if not other_fleets_here: debug("No other fleets here") return for fid in other_fleets_here: fleet_mission = aistate.get_fleet_mission(fid) if fleet_mission.type != self.type or fleet_mission.target != self.target: debug("Local candidate %s does not have same mission." % fleet_mission) continue FleetUtilsAI.merge_fleet_a_into_b( fid, fleet_id, context="Order %s of mission %s" % (context, self))
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 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 check_mergers(self, context=""): """ Merge local fleets with same mission into this fleet. :param context: Context of the function call for logging purposes :type context: str """ debug("Considering to merge %s", self.__str__()) if self.type not in MERGEABLE_MISSION_TYPES: debug("Mission type does not allow merging.") return if not self.target: debug("Mission has no valid target - do not merge.") return universe = fo.getUniverse() empire_id = fo.empireID() fleet_id = self.fleet.id main_fleet = universe.getFleet(fleet_id) main_fleet_system_id = main_fleet.systemID if main_fleet_system_id == INVALID_ID: debug("Can't merge: fleet in middle of starlane.") return # only merge PROTECT_REGION if there is any threat near target if self.type == MissionType.PROTECT_REGION: neighbor_systems = universe.getImmediateNeighbors(self.target.id, empire_id) if not any(MilitaryAI.get_system_local_threat(sys_id) for sys_id in neighbor_systems): debug("Not merging PROTECT_REGION fleet - no threat nearby.") return destroyed_list = set(universe.destroyedObjectIDs(empire_id)) aistate = get_aistate() system_status = aistate.systemStatus[main_fleet_system_id] other_fleets_here = [fid for fid in system_status.get('myFleetsAccessible', []) if fid != fleet_id and fid not in destroyed_list and universe.getFleet(fid).ownedBy(empire_id)] if not other_fleets_here: debug("No other fleets here") return for fid in other_fleets_here: fleet_mission = aistate.get_fleet_mission(fid) if fleet_mission.type != self.type or fleet_mission.target != self.target: debug("Local candidate %s does not have same mission." % fleet_mission) continue FleetUtilsAI.merge_fleet_a_into_b(fid, fleet_id, context="Order %s of mission %s" % (context, self))
def check_mergers(self, fleet_id=None, context=""): if fleet_id is None: fleet_id = self.fleet.id if self.type not in (MissionType.MILITARY, MissionType.INVASION, MissionType.ORBITAL_INVASION, MissionType.SECURE, MissionType.ORBITAL_DEFENSE, ): return universe = fo.getUniverse() empire_id = fo.empireID() main_fleet = universe.getFleet(fleet_id) system_id = main_fleet.systemID if system_id == -1: return # can't merge fleets in middle of starlane system_status = foAI.foAIstate.systemStatus[system_id] destroyed_list = list(universe.destroyedObjectIDs(empire_id)) other_fleets_here = [fid for fid in system_status.get('myFleetsAccessible', []) if fid != fleet_id and fid not in destroyed_list and universe.getFleet(fid).ownedBy(empire_id)] if not other_fleets_here: return # nothing of record to merge with if not self.target: m_mt0_id = None else: m_mt0_id = self.target.id # TODO consider establishing an AI strategy & tactics planning document for discussing & planning # high level considerations for issues like fleet merger compatible_roles_map = { MissionType.ORBITAL_DEFENSE: [MissionType.ORBITAL_DEFENSE], MissionType.MILITARY: [MissionType.MILITARY], MissionType.ORBITAL_INVASION: [MissionType.ORBITAL_INVASION], MissionType.INVASION: [MissionType.INVASION], } main_fleet_role = foAI.foAIstate.get_fleet_role(fleet_id) for fid in other_fleets_here: fleet_role = foAI.foAIstate.get_fleet_role(fid) if fleet_role not in compatible_roles_map[main_fleet_role]: # TODO: if fleetRoles such as LongRange start being used, adjust this continue # will only considering subsuming fleets that have a compatible role fleet = universe.getFleet(fid) if not (fleet and (fleet.systemID == system_id)): continue if not (fleet.speed > 0 or main_fleet.speed == 0): # TODO(Cjkjvfnby) Check this condition continue fleet_mission = foAI.foAIstate.get_fleet_mission(fid) do_merge = False need_left = 0 if (main_fleet_role == MissionType.ORBITAL_DEFENSE) or (fleet_role == MissionType.ORBITAL_DEFENSE): if main_fleet_role == fleet_role: do_merge = True elif (main_fleet_role == MissionType.ORBITAL_INVASION) or (fleet_role == MissionType.ORBITAL_INVASION): if main_fleet_role == fleet_role: do_merge = False # TODO: could allow merger if both orb invaders and both same target elif not fleet_mission and (main_fleet.speed > 0) and (fleet.speed > 0): do_merge = True else: if not self.target and (main_fleet.speed > 0 or fleet.speed == 0): # print "\t\t\t ** Considering merging fleetA (id: %4d) into fleet (id %d) and former has no targets, will take it. FleetA mission was %s "%(fid, fleetID, fleet_mission) do_merge = True else: target = fleet_mission.target.id if fleet_mission.target else None if target == m_mt0_id: print "Military fleet %d has same target as %s fleet %d and will (at least temporarily) be merged into the latter" % (fid, fleet_role, fleet_id) do_merge = True # TODO: should probably ensure that fleetA has aggression on now elif main_fleet.speed > 0: neighbors = foAI.foAIstate.systemStatus.get(system_id, {}).get('neighbors', []) if (target == system_id) and m_mt0_id in neighbors: # consider 'borrowing' for work in neighbor system # TODO check condition if self.type in (MissionType.MILITARY, MissionType.SECURE): # continue if self.type == MissionType.SECURE: # actually, currently this is probably the only one of all four that should really be possible in this situation need_left = 1.5 * sum([sysStat.get('fleetThreat', 0) for sysStat in [foAI.foAIstate.systemStatus.get(neighbor, {}) for neighbor in [nid for nid in foAI.foAIstate.systemStatus.get(system_id, {}).get('neighbors', []) if nid != m_mt0_id]]]) fb_rating = foAI.foAIstate.get_rating(fid) if (need_left < fb_rating.get('overall', 0)) and fb_rating.get('nships', 0) > 1: do_merge = True if do_merge: FleetUtilsAI.merge_fleet_a_into_b(fid, fleet_id, need_left, context="Order %s of mission %s" % (context, self)) return
def _check_retarget_invasion(self): """checks if an invasion mission should be retargeted""" universe = fo.getUniverse() empire = fo.getEmpire() empire_id = fo.empireID() fleet_id = self.fleet.id fleet = universe.getFleet(fleet_id) if fleet.systemID == -1: # next_loc = fleet.nextSystemID return # TODO: still check system = universe.getSystem(fleet.systemID) if not system: return orders = self.orders last_sys_target = -1 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) for pid in system.planetIDs: if pid in already_targeted or (pid in foAI.foAIstate.qualifyingTroopBaseTargets): continue planet = universe.getPlanet(pid) if planet.unowned or (planet.owner == empire_id): continue if (planet.currentMeterValue(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 = -1 best_score = -1 target_troops = 0 # for pid, rating in InvasionAI.assign_invasion_values(open_targets, empire).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 == -1: return print "\t AIFleetMission._check_retarget_invasion: 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() # pods_needed = max(0, math.ceil((target_troops - 2 * (FleetUtilsAI.count_parts_fleetwide(fleet_id, ["GT_TROOP_POD"])) + 0.05) / 2.0)) troops_needed = max(0, target_troops - FleetUtilsAI.count_troops_in_fleet(fleet_id)) found_stats = {} 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(1, target_stats, min_stats, found_stats, "", systems_to_check=[fleet.systemID], systems_checked=[], fleet_pool_set=set(new_fleets), fleet_list=found_fleets, verbose=False) for fid in found_fleets: FleetUtilsAI.merge_fleet_a_into_b(fid, fleet_id) target = Planet(target_id) self.add_target(MissionType.INVASION, target) self.generate_fleet_orders()
def check_mergers(self, context=""): """ If possible and reasonable, merge this fleet with others. :param context: Context of the function call for logging purposes :type context: str """ if self.type not in MERGEABLE_MISSION_TYPES: return universe = fo.getUniverse() empire_id = fo.empireID() fleet_id = self.fleet.id main_fleet = universe.getFleet(fleet_id) system_id = main_fleet.systemID if system_id == INVALID_ID: return # can't merge fleets in middle of starlane system_status = foAI.foAIstate.systemStatus[system_id] destroyed_list = list(universe.destroyedObjectIDs(empire_id)) other_fleets_here = [fid for fid in system_status.get('myFleetsAccessible', []) if fid != fleet_id and fid not in destroyed_list and universe.getFleet(fid).ownedBy(empire_id)] if not other_fleets_here: return target_id = self.target.id if self.target else None main_fleet_role = foAI.foAIstate.get_fleet_role(fleet_id) for fid in other_fleets_here: fleet_role = foAI.foAIstate.get_fleet_role(fid) if fleet_role not in COMPATIBLE_ROLES_MAP[main_fleet_role]: continue fleet = universe.getFleet(fid) if not fleet or fleet.systemID != system_id or len(fleet.shipIDs) == 0: continue if not (fleet.speed > 0 or main_fleet.speed == 0): # TODO(Cjkjvfnby) Check this condition continue fleet_mission = foAI.foAIstate.get_fleet_mission(fid) do_merge = False need_left = 0 if (main_fleet_role == MissionType.ORBITAL_DEFENSE) or (fleet_role == MissionType.ORBITAL_DEFENSE): if main_fleet_role == fleet_role: do_merge = True elif (main_fleet_role == MissionType.ORBITAL_INVASION) or (fleet_role == MissionType.ORBITAL_INVASION): if main_fleet_role == fleet_role: do_merge = False # TODO: could allow merger if both orb invaders and both same target elif not fleet_mission and (main_fleet.speed > 0) and (fleet.speed > 0): do_merge = True else: if not self.target and (main_fleet.speed > 0 or fleet.speed == 0): do_merge = True else: target = fleet_mission.target.id if fleet_mission.target else None if target == target_id: print "Military fleet %d has same target as %s fleet %d. Merging." % (fid, fleet_role, fleet_id) do_merge = True # TODO: should probably ensure that fleetA has aggression on now elif main_fleet.speed > 0: neighbors = foAI.foAIstate.systemStatus.get(system_id, {}).get('neighbors', []) if target == system_id and target_id in neighbors and self.type == MissionType.SECURE: # consider 'borrowing' for work in neighbor system # TODO check condition need_left = 1.5 * sum(foAI.foAIstate.systemStatus.get(nid, {}).get('fleetThreat', 0) for nid in neighbors if nid != target_id) fleet_rating = CombatRatingsAI.get_fleet_rating(fid) if need_left < fleet_rating: do_merge = True if do_merge: FleetUtilsAI.merge_fleet_a_into_b(fid, fleet_id, need_left, context="Order %s of mission %s" % (context, self)) return
def assign_invasion_fleets_to_invade(): """Assign fleet targets to invadable planets.""" universe = fo.getUniverse() empire = fo.getEmpire() fleet_suppliable_system_ids = empire.fleetSupplyableSystemIDs fleet_suppliable_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(fleet_suppliable_system_ids) all_troopbase_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType. FLEET_MISSION_ORBITAL_INVASION) available_troopbase_fleet_ids = set(FleetUtilsAI.extract_fleet_ids_without_mission_types(all_troopbase_fleet_ids)) for fid in list(available_troopbase_fleet_ids): if fid not in available_troopbase_fleet_ids: # TODO: I do not see how this check makes sense, maybe remove? 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(foAI.foAIstate.qualifyingTroopBaseTargets.keys())) print "Considering Base Troopers in %s, found planets %s and registered targets %s with status %s" % ( system.name, list(system.planetIDs), available_planets, [(pid, foAI.foAIstate.qualifyingTroopBaseTargets[pid]) for pid in available_planets]) targets = [pid for pid in available_planets if foAI.foAIstate.qualifyingTroopBaseTargets[pid][1] != -1] if not targets: print "Error: found no valid target for troop base in system %s (%d)" % (system.name, sys_id) continue status = foAI.foAIstate.systemStatus.get(sys_id, {}) local_base_troops = set(status.get('myfleets', [])).intersection(available_troopbase_fleet_ids) troop_capacity_tally = 0 for fid2 in local_base_troops: troop_capacity_tally += FleetUtilsAI.count_troops_in_fleet(fid2) target_id = -1 best_score = -1 target_troops = 0 for pid, rating in assign_invasion_values(targets, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, fleet_suppliable_planet_ids, empire).items(): p_score, p_troops = rating if p_score > best_score: best_score = p_score target_id = pid target_troops = p_troops if target_id != -1: 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} FleetUtilsAI.get_fleets_for_mission(1, target_stats, min_stats, found_stats, "", systems_to_check=[sys_id], systems_checked=[], fleet_pool_set=local_base_troops, fleet_list=found_fleets, verbose=False) 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) foAI.foAIstate.qualifyingTroopBaseTargets[target_id][1] = -1 # TODO: should probably delete target = AITarget.AITarget(EnumsAI.TargetType.TARGET_PLANET, target_id) fleet_mission = foAI.foAIstate.get_fleet_mission(fid) fleet_mission.add_target(EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION, target) invasion_fleet_ids = AIstate.invasionFleetIDs send_invasion_fleets(invasion_fleet_ids, AIstate.invasionTargets, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) all_invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) for fid in FleetUtilsAI.extract_fleet_ids_without_mission_types(all_invasion_fleet_ids): this_mission = foAI.foAIstate.get_fleet_mission(fid) this_mission.check_mergers(context="Post-send consolidation of unassigned troops")
def assign_invasion_fleets_to_invade(): # assign fleet targets to invadable planets universe = fo.getUniverse() empire = fo.getEmpire() empireID = empire.empireID fleetSupplyableSystemIDs = empire.fleetSupplyableSystemIDs fleetSupplyablePlanetIDs = PlanetUtilsAI.get_planets_in__systems_ids(fleetSupplyableSystemIDs) allTroopBaseFleetIDs = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION) availTroopBaseFleetIDs = set(FleetUtilsAI.extract_fleet_ids_without_mission_types(allTroopBaseFleetIDs)) for fid in list(availTroopBaseFleetIDs): if fid not in availTroopBaseFleetIDs: continue fleet = universe.getFleet(fid) if not fleet: continue sysID = fleet.systemID system = universe.getSystem(sysID) availPlanets = set(system.planetIDs).intersection(set( foAI.foAIstate.qualifyingTroopBaseTargets.keys())) print "Considering Base Troopers in %s, found planets %s and regtistered targets %s with status %s"%(system.name, list(system.planetIDs), availPlanets, [(pid, foAI.foAIstate.qualifyingTroopBaseTargets[pid]) for pid in availPlanets]) targets = [pid for pid in availPlanets if foAI.foAIstate.qualifyingTroopBaseTargets[pid][1] != -1 ] if not targets: print "Error found no valid target for troop base in system %s (%d)"%(system.name, sysID) continue status=foAI.foAIstate.systemStatus.get( sysID, {} ) local_base_troops = set(status.get('myfleets', [])).intersection(availTroopBaseFleetIDs) troop_pod_tally = 0 for fid2 in local_base_troops: troop_pod_tally += FleetUtilsAI.count_parts_fleetwide(fid2, ["GT_TROOP_POD"]) targetID=-1 bestScore=-1 target_troops = 0 # for pid, rating in assign_invasion_values(targets, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, fleetSupplyablePlanetIDs, empire).items(): p_score, p_troops = rating if p_score>bestScore: if p_troops >= 2*troop_pod_tally: pass #continue bestScore = p_score targetID = pid target_troops = p_troops if targetID != -1: local_base_troops.discard(fid) foundFleets = [] podsNeeded= math.ceil( (target_troops - 2*(FleetUtilsAI.count_parts_fleetwide(fid, ["GT_TROOP_POD"]))+0.05)/2.0) foundStats={} minStats= {'rating':0, 'troopPods':podsNeeded} targetStats={'rating':10,'troopPods':podsNeeded} theseFleets = FleetUtilsAI.get_fleets_for_mission(1, targetStats , minStats, foundStats, "", systems_to_check=[sysID], systems_checked=[], fleet_pool_set=local_base_troops, fleet_list=foundFleets, verbose=False) for fid2 in foundFleets: FleetUtilsAI.merge_fleet_a_into_b(fid2, fid) availTroopBaseFleetIDs.discard(fid2) availTroopBaseFleetIDs.discard(fid) foAI.foAIstate.qualifyingTroopBaseTargets[targetID][1] = -1 #TODO: should probably delete aiTarget = AITarget.AITarget(EnumsAI.TargetType.TARGET_PLANET, targetID) aiFleetMission = foAI.foAIstate.get_fleet_mission(fid) aiFleetMission.add_target(EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION, aiTarget) invasionFleetIDs = AIstate.invasionFleetIDs send_invasion_fleets(invasionFleetIDs, AIstate.invasionTargets, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) allInvasionFleetIDs = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) for fid in FleetUtilsAI.extract_fleet_ids_without_mission_types(allInvasionFleetIDs): thisMission = foAI.foAIstate.get_fleet_mission(fid) thisMission.check_mergers(context="Post-send consolidation of unassigned troops")
def check_mergers(self, context=""): """ If possible and reasonable, merge this fleet with others. :param context: Context of the function call for logging purposes :type context: str """ if self.type not in MERGEABLE_MISSION_TYPES: return universe = fo.getUniverse() empire_id = fo.empireID() fleet_id = self.fleet.id main_fleet = universe.getFleet(fleet_id) system_id = main_fleet.systemID if system_id == INVALID_ID: return # can't merge fleets in middle of starlane aistate = get_aistate() system_status = aistate.systemStatus[system_id] # if a combat mission, and only have final order (so must be at final target), don't try # merging if there is no local threat (it tends to lead to fleet object churn) if self.type in COMBAT_MISSION_TYPES and len( self.orders) == 1 and not system_status.get('totalThreat', 0): return destroyed_list = list(universe.destroyedObjectIDs(empire_id)) other_fleets_here = [ fid for fid in system_status.get('myFleetsAccessible', []) if fid != fleet_id and fid not in destroyed_list and universe.getFleet(fid).ownedBy(empire_id) ] if not other_fleets_here: return target_id = self.target.id if self.target else None main_fleet_role = aistate.get_fleet_role(fleet_id) for fid in other_fleets_here: fleet_role = aistate.get_fleet_role(fid) if fleet_role not in COMPATIBLE_ROLES_MAP[main_fleet_role]: continue fleet = universe.getFleet(fid) if not fleet or fleet.systemID != system_id or len( fleet.shipIDs) == 0: continue if not (fleet.speed > 0 or main_fleet.speed == 0): # TODO(Cjkjvfnby) Check this condition continue fleet_mission = aistate.get_fleet_mission(fid) do_merge = False need_left = 0 if (main_fleet_role == MissionType.ORBITAL_DEFENSE) or ( fleet_role == MissionType.ORBITAL_DEFENSE): if main_fleet_role == fleet_role: do_merge = True elif (main_fleet_role == MissionType.ORBITAL_INVASION) or ( fleet_role == MissionType.ORBITAL_INVASION): if main_fleet_role == fleet_role: do_merge = False # TODO: could allow merger if both orb invaders and both same target elif not fleet_mission and (main_fleet.speed > 0) and (fleet.speed > 0): do_merge = True else: if not self.target and (main_fleet.speed > 0 or fleet.speed == 0): do_merge = True else: target = fleet_mission.target.id if fleet_mission.target else None if target == target_id: info( "Military fleet %d (%d ships) has same target as %s fleet %d (%d ships). Merging former " "into latter." % (fid, fleet.numShips, fleet_role, fleet_id, len(main_fleet.shipIDs))) # TODO: should probably ensure that fleetA has aggression on now do_merge = float(min( main_fleet.speed, fleet.speed)) / max( main_fleet.speed, fleet.speed) >= 0.6 elif main_fleet.speed > 0: neighbors = aistate.systemStatus.get( system_id, {}).get('neighbors', []) if target == system_id and target_id in neighbors and self.type == MissionType.SECURE: # consider 'borrowing' for work in neighbor system # TODO check condition need_left = 1.5 * sum( aistate.systemStatus.get(nid, {}).get( 'fleetThreat', 0) for nid in neighbors if nid != target_id) fleet_rating = CombatRatingsAI.get_fleet_rating( fid) if need_left < fleet_rating: do_merge = True if do_merge: FleetUtilsAI.merge_fleet_a_into_b( fid, fleet_id, need_left, context="Order %s of mission %s" % (context, self)) return
def assign_invasion_fleets_to_invade(): # assign fleet targets to invadable planets universe = fo.getUniverse() empire = fo.getEmpire() empireID = empire.empireID fleetSupplyableSystemIDs = empire.fleetSupplyableSystemIDs fleetSupplyablePlanetIDs = PlanetUtilsAI.get_planets_in__systems_ids(fleetSupplyableSystemIDs) allTroopBaseFleetIDs = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION) availTroopBaseFleetIDs = set(FleetUtilsAI.extract_fleet_ids_without_mission_types(allTroopBaseFleetIDs)) for fid in list(availTroopBaseFleetIDs): if fid not in availTroopBaseFleetIDs: continue fleet = universe.getFleet(fid) if not fleet: continue sysID = fleet.systemID system = universe.getSystem(sysID) availPlanets = set(system.planetIDs).intersection(set( foAI.foAIstate.qualifyingTroopBaseTargets.keys())) print "Considering Base Troopers in %s, found planets %s and regtistered targets %s with status %s"%(system.name, list(system.planetIDs), availPlanets, [(pid, foAI.foAIstate.qualifyingTroopBaseTargets[pid]) for pid in availPlanets]) targets = [pid for pid in availPlanets if foAI.foAIstate.qualifyingTroopBaseTargets[pid][1] != -1 ] if not targets: print "Error found no valid target for troop base in system %s (%d)"%(system.name, sysID) continue status=foAI.foAIstate.systemStatus.get( sysID, {} ) local_base_troops = set(status.get('myfleets', [])).intersection(availTroopBaseFleetIDs) troop_pod_tally = 0 for fid2 in local_base_troops: troop_pod_tally += FleetUtilsAI.count_parts_fleetwide(fid2, ["GT_TROOP_POD"]) targetID=-1 bestScore=-1 target_troops = 0 # for pid, rating in assign_invasion_values(targets, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, fleetSupplyablePlanetIDs, empire).items(): p_score, p_troops = rating if p_score>bestScore: if p_troops >= 2*troop_pod_tally: pass #continue bestScore = p_score targetID = pid target_troops = p_troops if targetID != -1: local_base_troops.discard(fid) foundFleets = [] podsNeeded= math.ceil( (target_troops - 2*(FleetUtilsAI.count_parts_fleetwide(fid, ["GT_TROOP_POD"]))+0.05)/2.0) foundStats={} minStats= {'rating':0, 'troopPods':podsNeeded} targetStats={'rating':10,'troopPods':podsNeeded} theseFleets = FleetUtilsAI.get_fleets_for_mission(1, targetStats , minStats, foundStats, "", systems_to_check=[sysID], systems_checked=[], fleet_pool_set=local_base_troops, fleet_list=foundFleets, verbose=False) for fid2 in foundFleets: FleetUtilsAI.merge_fleet_a_into_b(fid2, fid) availTroopBaseFleetIDs.discard(fid2) availTroopBaseFleetIDs.discard(fid) foAI.foAIstate.qualifyingTroopBaseTargets[targetID][1] = -1 #TODO: should probably delete aiTarget = AITarget.AITarget(EnumsAI.AITargetType.TARGET_PLANET, targetID) aiFleetMission = foAI.foAIstate.get_fleet_mission(fid) aiFleetMission.add_target(EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION, aiTarget) invasionFleetIDs = AIstate.invasionFleetIDs send_invasion_fleets(invasionFleetIDs, AIstate.invasionTargets, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) allInvasionFleetIDs = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) for fid in FleetUtilsAI.extract_fleet_ids_without_mission_types(allInvasionFleetIDs): thisMission = foAI.foAIstate.get_fleet_mission(fid) thisMission.check_mergers(context="Post-send consolidation of unassigned troops")
def check_mergers(self, fleet_id=None, context=""): if fleet_id is None: fleet_id = self.fleet.id if self.type not in ( MissionType.MILITARY, MissionType.INVASION, MissionType.ORBITAL_INVASION, MissionType.SECURE, MissionType.ORBITAL_DEFENSE, ): return universe = fo.getUniverse() empire_id = fo.empireID() main_fleet = universe.getFleet(fleet_id) system_id = main_fleet.systemID if system_id == -1: return # can't merge fleets in middle of starlane system_status = foAI.foAIstate.systemStatus[system_id] destroyed_list = list(universe.destroyedObjectIDs(empire_id)) other_fleets_here = [ fid for fid in system_status.get('myFleetsAccessible', []) if fid != fleet_id and fid not in destroyed_list and universe.getFleet(fid).ownedBy(empire_id) ] if not other_fleets_here: return # nothing of record to merge with if not self.target: m_mt0_id = None else: m_mt0_id = self.target.id # TODO consider establishing an AI strategy & tactics planning document for discussing & planning # high level considerations for issues like fleet merger compatible_roles_map = { MissionType.ORBITAL_DEFENSE: [MissionType.ORBITAL_DEFENSE], MissionType.MILITARY: [MissionType.MILITARY], MissionType.ORBITAL_INVASION: [MissionType.ORBITAL_INVASION], MissionType.INVASION: [MissionType.INVASION], } main_fleet_role = foAI.foAIstate.get_fleet_role(fleet_id) for fid in other_fleets_here: fleet_role = foAI.foAIstate.get_fleet_role(fid) if fleet_role not in compatible_roles_map[ main_fleet_role]: # TODO: if fleetRoles such as LongRange start being used, adjust this continue # will only considering subsuming fleets that have a compatible role fleet = universe.getFleet(fid) if not (fleet and (fleet.systemID == system_id)): continue if not (fleet.speed > 0 or main_fleet.speed == 0): # TODO(Cjkjvfnby) Check this condition continue fleet_mission = foAI.foAIstate.get_fleet_mission(fid) do_merge = False need_left = 0 if (main_fleet_role == MissionType.ORBITAL_DEFENSE) or ( fleet_role == MissionType.ORBITAL_DEFENSE): if main_fleet_role == fleet_role: do_merge = True elif (main_fleet_role == MissionType.ORBITAL_INVASION) or ( fleet_role == MissionType.ORBITAL_INVASION): if main_fleet_role == fleet_role: do_merge = False # TODO: could allow merger if both orb invaders and both same target elif not fleet_mission and (main_fleet.speed > 0) and (fleet.speed > 0): do_merge = True else: if not self.target and (main_fleet.speed > 0 or fleet.speed == 0): # print "\t\t\t ** Considering merging fleetA (id: %4d) into fleet (id %d) and former has no targets, will take it. FleetA mission was %s "%(fid, fleetID, fleet_mission) do_merge = True else: target = fleet_mission.target.id if fleet_mission.target else None if target == m_mt0_id: print "Military fleet %d has same target as %s fleet %d and will (at least temporarily) be merged into the latter" % ( fid, fleet_role, fleet_id) do_merge = True # TODO: should probably ensure that fleetA has aggression on now elif main_fleet.speed > 0: neighbors = foAI.foAIstate.systemStatus.get( system_id, {}).get('neighbors', []) if ( target == system_id ) and m_mt0_id in neighbors: # consider 'borrowing' for work in neighbor system # TODO check condition if self.type in (MissionType.MILITARY, MissionType.SECURE): # continue if self.type == MissionType.SECURE: # actually, currently this is probably the only one of all four that should really be possible in this situation need_left = 1.5 * sum([ sysStat.get('fleetThreat', 0) for sysStat in [ foAI.foAIstate.systemStatus.get( neighbor, {}) for neighbor in [ nid for nid in foAI. foAIstate.systemStatus.get( system_id, {}).get( 'neighbors', []) if nid != m_mt0_id ] ] ]) fb_rating = foAI.foAIstate.get_rating(fid) if (need_left < fb_rating.get( 'overall', 0)) and fb_rating.get( 'nships', 0) > 1: do_merge = True if do_merge: FleetUtilsAI.merge_fleet_a_into_b( fid, fleet_id, need_left, context="Order %s of mission %s" % (context, self)) return
def _check_retarget_invasion(self): """checks if an invasion mission should be retargeted""" universe = fo.getUniverse() empire = fo.getEmpire() empire_id = fo.empireID() fleet_id = self.fleet.id fleet = universe.getFleet(fleet_id) if fleet.systemID == -1: # next_loc = fleet.nextSystemID return # TODO: still check system = universe.getSystem(fleet.systemID) if not system: return orders = self.orders last_sys_target = -1 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) for pid in system.planetIDs: if pid in already_targeted or ( pid in foAI.foAIstate.qualifyingTroopBaseTargets): continue planet = universe.getPlanet(pid) if planet.unowned or (planet.owner == empire_id): continue if (planet.currentMeterValue(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 = -1 best_score = -1 target_troops = 0 # for pid, rating in InvasionAI.assign_invasion_values( open_targets, empire).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 == -1: return print "\t AIFleetMission._check_retarget_invasion: 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() # pods_needed = max(0, math.ceil((target_troops - 2 * (FleetUtilsAI.count_parts_fleetwide(fleet_id, ["GT_TROOP_POD"])) + 0.05) / 2.0)) troops_needed = max( 0, target_troops - FleetUtilsAI.count_troops_in_fleet(fleet_id)) found_stats = {} 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( 1, target_stats, min_stats, found_stats, "", systems_to_check=[fleet.systemID], systems_checked=[], fleet_pool_set=set(new_fleets), fleet_list=found_fleets, verbose=False) for fid in found_fleets: FleetUtilsAI.merge_fleet_a_into_b(fid, fleet_id) target = Planet(target_id) self.add_target(MissionType.INVASION, target) self.generate_fleet_orders()
def check_mergers(self, fleet_id=None, context=""): if fleet_id is None: fleet_id = self.target_id mission_types = self.get_mission_types( ) # normally, currently, should only be one if len(mission_types) != 1: return # if this fleet has multiple mission types, will not subsume other fleets mission_type = mission_types[0] if mission_type not in ( AIFleetMissionType.FLEET_MISSION_ATTACK, AIFleetMissionType.FLEET_MISSION_DEFEND, AIFleetMissionType.FLEET_MISSION_LAST_STAND, AIFleetMissionType.FLEET_MISSION_MILITARY, AIFleetMissionType.FLEET_MISSION_INVASION, AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION, AIFleetMissionType.FLEET_MISSION_SECURE, AIFleetMissionType.FLEET_MISSION_ORBITAL_DEFENSE, ): return universe = fo.getUniverse() empire_id = fo.empireID() main_fleet = universe.getFleet(fleet_id) system_id = main_fleet.systemID if system_id == -1: return # can't merge fleets in middle of starlane system_status = foAI.foAIstate.systemStatus[system_id] destroyed_list = list(universe.destroyedObjectIDs(empire_id)) other_fleets_here = [ fid for fid in system_status.get('myFleetsAccessible', []) if fid != fleet_id and fid not in destroyed_list and universe.getFleet(fid).ownedBy(empire_id) ] if not other_fleets_here: return # nothing of record to merge with targets = self.get_targets(mission_type) if not targets: pass #return #let's let invasion fleets with no target get merged m_MT0_id = None else: m_MT0_id = targets[0].target_id if len(targets) > 1: pass print "\tConsidering merging fleets into fleet %d, but it has multiple targets: %s" % ( fleet_id, str(targets)) # TODO (Cjkjvfnby) check why we cant merge fleet with other missions to each other # TODO consider establishing an AI strategy & tactics planning document for discussing & planning # high level considerations for issues like fleet merger compatibileRolesMap = { EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_DEFENSE: [EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_DEFENSE], EnumsAI.AIFleetMissionType.FLEET_MISSION_MILITARY: [EnumsAI.AIFleetMissionType.FLEET_MISSION_MILITARY], EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION: [EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION], EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION: [EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION], } main_fleet_role = foAI.foAIstate.get_fleet_role(fleet_id) for fid in other_fleets_here: fleet_role = foAI.foAIstate.get_fleet_role(fid) if fleet_role not in compatibileRolesMap[ main_fleet_role]: # TODO: if fleetRoles such as LongRange start being used, adjust this continue # will only considering subsuming fleets that have a compatible role fleet = universe.getFleet(fid) if not (fleet and (fleet.systemID == system_id)): continue if not (fleet.speed > 0 or main_fleet.speed == 0): # TODO(Cjkjvfnby) Check this condition continue fleet_mission = foAI.foAIstate.get_fleet_mission(fid) do_merge = False need_left = 0 if (main_fleet_role == AIFleetMissionType.FLEET_MISSION_ORBITAL_DEFENSE) or ( fleet_role == AIFleetMissionType.FLEET_MISSION_ORBITAL_DEFENSE): if main_fleet_role == fleet_role: do_merge = True elif (main_fleet_role == AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION) or ( fleet_role == AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION): if main_fleet_role == fleet_role: do_merge = False # TODO: could allow merger if both orb invaders and both same target elif not fleet_mission and (main_fleet.speed > 0) and (fleet.speed > 0): do_merge = True else: fleet_mission_type = fleet_mission.get_mission_types( )[0] if fleet_mission.get_mission_types( ) else AIFleetMissionType.FLEET_MISSION_INVALID fleet_targets = fleet_mission.get_targets(fleet_mission_type) if len(fleet_targets) > 1: pass elif not fleet_targets and (main_fleet.speed > 0 or fleet.speed == 0): #print "\t\t\t ** Considering merging fleetA (id: %4d) into fleet (id %d) and former has no targets, will take it. FleetA mission was %s "%(fid, fleetID, fleet_mission) do_merge = True else: target = fleet_targets[0].target_id if target == m_MT0_id: print "Military fleet %d has same target as %s fleet %d and will (at least temporarily) be merged into the latter" % ( fid, EnumsAI.AIShipRoleType.name(fleet_role), fleet_id) do_merge = True # TODO: should probably ensure that fleetA has aggression on now elif main_fleet.speed > 0: neighbors = foAI.foAIstate.systemStatus.get( system_id, {}).get('neighbors', []) if ( target == system_id ) and m_MT0_id in neighbors: # consider 'borrowing' for work in neighbor system # TODO check condition if fleet_mission_type in ( AIFleetMissionType.FLEET_MISSION_ATTACK, AIFleetMissionType.FLEET_MISSION_DEFEND, AIFleetMissionType.FLEET_MISSION_MILITARY, AIFleetMissionType.FLEET_MISSION_SECURE): #continue if fleet_mission_type in ( AIFleetMissionType. FLEET_MISSION_DEFEND, AIFleetMissionType. FLEET_MISSION_SECURE, # actually, currently this is probably the onle one of all four that should really be possibile in this situation ): need_left = 1.5 * sum([ sysStat.get('fleetThreat', 0) for sysStat in [ foAI.foAIstate.systemStatus.get( neighbor, {}) for neighbor in [ nid for nid in foAI. foAIstate.systemStatus.get( system_id, {}).get( 'neighbors', []) if nid != m_MT0_id ] ] ]) fBRating = foAI.foAIstate.get_rating(fid) if (need_left < fBRating.get('overall', 0) ) and fBRating.get('nships', 0) > 1: do_merge = True if do_merge: FleetUtilsAI.merge_fleet_a_into_b( fid, fleet_id, need_left, context="Order %s of mission %s" % (context, self)) return
def check_mergers(self, fleet_id=None, context=""): if fleet_id is None: fleet_id = self.target_id mission_types = self.get_mission_types() # normally, currently, should only be one if len(mission_types) != 1: return # if this fleet has multiple mission types, will not subsume other fleets mission_type = mission_types[0] if mission_type not in (AIFleetMissionType.FLEET_MISSION_ATTACK, AIFleetMissionType.FLEET_MISSION_DEFEND, AIFleetMissionType.FLEET_MISSION_LAST_STAND, AIFleetMissionType.FLEET_MISSION_MILITARY, AIFleetMissionType.FLEET_MISSION_INVASION, AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION, AIFleetMissionType.FLEET_MISSION_SECURE, AIFleetMissionType.FLEET_MISSION_ORBITAL_DEFENSE, ): return universe = fo.getUniverse() empire_id = fo.empireID() main_fleet = universe.getFleet(fleet_id) system_id = main_fleet.systemID if system_id == -1: return # can't merge fleets in middle of starlane system_status = foAI.foAIstate.systemStatus[system_id] destroyed_list = list(universe.destroyedObjectIDs(empire_id)) other_fleets_here = [fid for fid in system_status.get('myFleetsAccessible', []) if fid != fleet_id and fid not in destroyed_list and universe.getFleet(fid).ownedBy(empire_id)] if not other_fleets_here: return # nothing of record to merge with targets = self.get_targets(mission_type) if not targets: pass #return #let's let invasion fleets with no target get merged m_MT0_id = None else: m_MT0_id = targets[0].target_id if len(targets) > 1: pass print "\tConsidering merging fleets into fleet %d, but it has multiple targets: %s" % (fleet_id, str(targets)) # TODO (Cjkjvfnby) check why we cant merge fleet with other missions to each other # TODO consider establishing an AI strategy & tactics planning document for discussing & planning # high level considerations for issues like fleet merger compatibileRolesMap = {EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_DEFENSE: [EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_DEFENSE], EnumsAI.AIFleetMissionType.FLEET_MISSION_MILITARY: [EnumsAI.AIFleetMissionType.FLEET_MISSION_MILITARY], EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION: [EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION], EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION: [EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION], } main_fleet_role = foAI.foAIstate.get_fleet_role(fleet_id) for fid in other_fleets_here: fleet_role = foAI.foAIstate.get_fleet_role(fid) if fleet_role not in compatibileRolesMap[main_fleet_role]: # TODO: if fleetRoles such as LongRange start being used, adjust this continue # will only considering subsuming fleets that have a compatible role fleet = universe.getFleet(fid) if not (fleet and (fleet.systemID == system_id)): continue if not (fleet.speed > 0 or main_fleet.speed == 0): # TODO(Cjkjvfnby) Check this condition continue fleet_mission = foAI.foAIstate.get_fleet_mission(fid) do_merge = False need_left = 0 if (main_fleet_role == AIFleetMissionType.FLEET_MISSION_ORBITAL_DEFENSE) or (fleet_role == AIFleetMissionType.FLEET_MISSION_ORBITAL_DEFENSE): if main_fleet_role == fleet_role: do_merge = True elif (main_fleet_role == AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION) or (fleet_role == AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION): if main_fleet_role == fleet_role: do_merge = False # TODO: could allow merger if both orb invaders and both same target elif not fleet_mission and (main_fleet.speed > 0) and (fleet.speed > 0): do_merge = True else: fleet_mission_type = fleet_mission.get_mission_types()[0] if fleet_mission.get_mission_types() else AIFleetMissionType.FLEET_MISSION_INVALID fleet_targets = fleet_mission.get_targets(fleet_mission_type) if len(fleet_targets) > 1: pass elif not fleet_targets and (main_fleet.speed > 0 or fleet.speed == 0): #print "\t\t\t ** Considering merging fleetA (id: %4d) into fleet (id %d) and former has no targets, will take it. FleetA mission was %s "%(fid, fleetID, fleet_mission) do_merge = True else: target = fleet_targets[0].target_id if target == m_MT0_id: print "Military fleet %d has same target as %s fleet %d and will (at least temporarily) be merged into the latter" % (fid, EnumsAI.AIShipRoleType.name(fleet_role), fleet_id) do_merge = True # TODO: should probably ensure that fleetA has aggression on now elif main_fleet.speed > 0: neighbors = foAI.foAIstate.systemStatus.get(system_id, {}).get('neighbors', []) if (target == system_id) and m_MT0_id in neighbors: # consider 'borrowing' for work in neighbor system # TODO check condition if fleet_mission_type in (AIFleetMissionType.FLEET_MISSION_ATTACK, AIFleetMissionType.FLEET_MISSION_DEFEND, AIFleetMissionType.FLEET_MISSION_MILITARY, AIFleetMissionType.FLEET_MISSION_SECURE): #continue if fleet_mission_type in (AIFleetMissionType.FLEET_MISSION_DEFEND, AIFleetMissionType.FLEET_MISSION_SECURE, # actually, currently this is probably the onle one of all four that should really be possibile in this situation ): need_left = 1.5 * sum([sysStat.get('fleetThreat', 0) for sysStat in [foAI.foAIstate.systemStatus.get(neighbor, {}) for neighbor in [nid for nid in foAI.foAIstate.systemStatus.get(system_id, {}).get('neighbors', []) if nid != m_MT0_id]]]) fBRating = foAI.foAIstate.get_rating(fid) if (need_left < fBRating.get('overall', 0)) and fBRating.get('nships', 0) > 1: do_merge = True if do_merge: FleetUtilsAI.merge_fleet_a_into_b(fid, fleet_id, need_left, context="Order %s of mission %s" % (context, self)) return
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 assign_invasion_fleets_to_invade(): """Assign fleet targets to invadable planets.""" universe = fo.getUniverse() empire = fo.getEmpire() fleet_suppliable_system_ids = empire.fleetSupplyableSystemIDs fleet_suppliable_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(fleet_suppliable_system_ids) all_troopbase_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType. FLEET_MISSION_ORBITAL_INVASION) available_troopbase_fleet_ids = set(FleetUtilsAI.extract_fleet_ids_without_mission_types(all_troopbase_fleet_ids)) for fid in list(available_troopbase_fleet_ids): if fid not in available_troopbase_fleet_ids: # TODO: I do not see how this check makes sense, maybe remove? 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(foAI.foAIstate.qualifyingTroopBaseTargets.keys())) print "Considering Base Troopers in %s, found planets %s and registered targets %s with status %s" % ( system.name, list(system.planetIDs), available_planets, [(pid, foAI.foAIstate.qualifyingTroopBaseTargets[pid]) for pid in available_planets]) targets = [pid for pid in available_planets if foAI.foAIstate.qualifyingTroopBaseTargets[pid][1] != -1] if not targets: print "Error: found no valid target for troop base in system %s (%d)" % (system.name, sys_id) continue status = foAI.foAIstate.systemStatus.get(sys_id, {}) local_base_troops = set(status.get('myfleets', [])).intersection(available_troopbase_fleet_ids) troop_capacity_tally = 0 for fid2 in local_base_troops: troop_capacity_tally += FleetUtilsAI.count_troops_in_fleet(fid2) target_id = -1 best_score = -1 target_troops = 0 for pid, rating in assign_invasion_values(targets, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, fleet_suppliable_planet_ids, empire).items(): p_score, p_troops = rating if p_score > best_score: best_score = p_score target_id = pid target_troops = p_troops if target_id != -1: 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} FleetUtilsAI.get_fleets_for_mission(1, target_stats, min_stats, found_stats, "", systems_to_check=[sys_id], systems_checked=[], fleet_pool_set=local_base_troops, fleet_list=found_fleets, verbose=False) 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) foAI.foAIstate.qualifyingTroopBaseTargets[target_id][1] = -1 # TODO: should probably delete target = AITarget.AITarget(EnumsAI.TargetType.TARGET_PLANET, target_id) fleet_mission = foAI.foAIstate.get_fleet_mission(fid) fleet_mission.add_target(EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION, target) invasion_fleet_ids = AIstate.invasionFleetIDs send_invasion_fleets(invasion_fleet_ids, AIstate.invasionTargets, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) all_invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) for fid in FleetUtilsAI.extract_fleet_ids_without_mission_types(all_invasion_fleet_ids): this_mission = foAI.foAIstate.get_fleet_mission(fid) this_mission.check_mergers(context="Post-send consolidation of unassigned troops")
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 check_mergers(self, context=""): """ If possible and reasonable, merge this fleet with others. :param context: Context of the function call for logging purposes :type context: str """ if self.type not in MERGEABLE_MISSION_TYPES: return universe = fo.getUniverse() empire_id = fo.empireID() fleet_id = self.fleet.id main_fleet = universe.getFleet(fleet_id) system_id = main_fleet.systemID if system_id == -1: return # can't merge fleets in middle of starlane system_status = foAI.foAIstate.systemStatus[system_id] destroyed_list = list(universe.destroyedObjectIDs(empire_id)) other_fleets_here = [ fid for fid in system_status.get('myFleetsAccessible', []) if fid != fleet_id and fid not in destroyed_list and universe.getFleet(fid).ownedBy(empire_id) ] if not other_fleets_here: return target_id = self.target.id if self.target else None main_fleet_role = foAI.foAIstate.get_fleet_role(fleet_id) for fid in other_fleets_here: fleet_role = foAI.foAIstate.get_fleet_role(fid) if fleet_role not in COMPATIBLE_ROLES_MAP[main_fleet_role]: continue fleet = universe.getFleet(fid) if not fleet or fleet.systemID != system_id: continue if not (fleet.speed > 0 or main_fleet.speed == 0): # TODO(Cjkjvfnby) Check this condition continue fleet_mission = foAI.foAIstate.get_fleet_mission(fid) do_merge = False need_left = 0 if (main_fleet_role == MissionType.ORBITAL_DEFENSE) or ( fleet_role == MissionType.ORBITAL_DEFENSE): if main_fleet_role == fleet_role: do_merge = True elif (main_fleet_role == MissionType.ORBITAL_INVASION) or ( fleet_role == MissionType.ORBITAL_INVASION): if main_fleet_role == fleet_role: do_merge = False # TODO: could allow merger if both orb invaders and both same target elif not fleet_mission and (main_fleet.speed > 0) and (fleet.speed > 0): do_merge = True else: if not self.target and (main_fleet.speed > 0 or fleet.speed == 0): do_merge = True else: target = fleet_mission.target.id if fleet_mission.target else None if target == target_id: print "Military fleet %d has same target as %s fleet %d. Merging." % ( fid, fleet_role, fleet_id) do_merge = True # TODO: should probably ensure that fleetA has aggression on now elif main_fleet.speed > 0: neighbors = foAI.foAIstate.systemStatus.get( system_id, {}).get('neighbors', []) if target == system_id and target_id in neighbors and self.type == MissionType.SECURE: # consider 'borrowing' for work in neighbor system # TODO check condition need_left = 1.5 * sum( foAI.foAIstate.systemStatus.get(nid, {}).get( 'fleetThreat', 0) for nid in neighbors if nid != target_id) fb_rating = foAI.foAIstate.get_rating(fid) if (need_left < fb_rating.get('overall', 0) ) and fb_rating.get('nships', 0) > 1: do_merge = True if do_merge: FleetUtilsAI.merge_fleet_a_into_b( fid, fleet_id, need_left, context="Order %s of mission %s" % (context, self)) return