def _check_abort_mission(self, fleet_order: AIFleetOrder): """checks if current mission (targeting a planet) should be aborted""" planet_stealthed = False target_is_planet = fleet_order.target and isinstance( fleet_order.target, TargetPlanet) planet = None if target_is_planet: planet = fleet_order.target.get_object() # Check visibility prediction, but if somehow still have current visibility, don't # abort the mission yet if not EspionageAI.colony_detectable_by_empire( planet.id, empire=fo.empireID()): if get_partial_visibility_turn(planet.id) == fo.currentTurn(): debug( "EspionageAI predicts planet id %d to be stealthed" % planet.id + ", but somehow have current visibity anyway, so won't trigger mission abort" ) else: debug( "EspionageAI predicts we can no longer detect %s, will abort mission" % fleet_order.target) planet_stealthed = True if target_is_planet and not planet_stealthed: # TBD use fleet_order.is_valid or add fleet_order.should_abort if isinstance(fleet_order, OrderColonize): if planet.initialMeterValue(fo.meterType.population) == 0 and ( planet.ownedBy(fo.empireID()) or planet.unowned): return False elif isinstance(fleet_order, OrderOutpost): if planet.unowned: return False elif isinstance(fleet_order, OrderInvade): if planet.owner == fo.getEmpire().empireID: debug( f"Abandoning invasion for {planet}, it already belongs to us" ) return True if planet.currentMeterValue(fo.meterType.maxShield): military_support_fleets = MilitaryAI.get_military_fleets_with_target_system( planet.systemID) if not military_support_fleets: # Maybe try again later... debug( f"Abandoning Invasion mission for {planet} because target has nonzero max shields " f"and there is no military fleet assigned to secure the target system." ) return True return False else: return False # canceling fleet orders debug(" %s" % fleet_order) debug( "Fleet %d had a target planet that is no longer valid for this mission; aborting." % self.fleet.id) FleetUtilsAI.split_fleet(self.fleet.id) return True
def __split_new_fleets(self): """Split any new fleets. This function is supposed to be called once at the beginning of the turn. Splitting the auto generated fleets at game start or those created by recently built ships allows the AI to assign correct roles to all ships. """ # TODO: check length of fleets for losses or do in AIstate.__cleanRoles universe = fo.getUniverse() known_fleets = self.get_fleet_roles_map() self.newlySplitFleets.clear() fleets_to_split = [fleet_id for fleet_id in FleetUtilsAI.get_empire_fleet_ids() if fleet_id not in known_fleets] if fleets_to_split: print "Trying to split %d new fleets" % len(fleets_to_split) for fleet_id in fleets_to_split: fleet = universe.getFleet(fleet_id) if not fleet: warn("Trying to split fleet %d but seemingly does not exist" % fleet_id) continue fleet_len = len(fleet.shipIDs) if fleet_len == 1: continue new_fleets = FleetUtilsAI.split_fleet(fleet_id) print "Split fleet %d with %d ships into %d new fleets:" % (fleet_id, fleet_len, len(new_fleets))
def __split_new_fleets(self): """Split any new fleets. This function is supposed to be called once at the beginning of the turn. Splitting the auto generated fleets at game start or those created by recently built ships allows the AI to assign correct roles to all ships. """ # TODO: check length of fleets for losses or do in AIstate.__cleanRoles universe = fo.getUniverse() known_fleets = self.get_fleet_roles_map() self.newlySplitFleets.clear() fleets_to_split = [fleet_id for fleet_id in FleetUtilsAI.get_empire_fleet_ids() if fleet_id not in known_fleets] if fleets_to_split: debug("Trying to split %d new fleets" % len(fleets_to_split)) for fleet_id in fleets_to_split: fleet = universe.getFleet(fleet_id) if not fleet: warn("Trying to split fleet %d but seemingly does not exist" % fleet_id) continue fleet_len = len(fleet.shipIDs) if fleet_len == 1: continue new_fleets = FleetUtilsAI.split_fleet(fleet_id) debug("Split fleet %d with %d ships into %d new fleets:" % (fleet_id, fleet_len, len(new_fleets)))
def _check_abort_mission(self, fleet_order): """ checks if current mission (targeting a planet) should be aborted""" planet_stealthed = False target_is_planet = fleet_order.target and isinstance( fleet_order.target, TargetPlanet) planet = None if target_is_planet: planet = fleet_order.target.get_object() # Check visibility prediction, but if somehow still have current visibility, don't # abort the mission yet if not EspionageAI.colony_detectable_by_empire( planet.id, empire=fo.empireID()): if get_partial_visibility_turn(planet.id) == fo.currentTurn(): debug( "EspionageAI predicts planet id %d to be stealthed" % planet.id + ", but somehow have current visibity anyway, so won't trigger mission abort" ) else: debug( "EspionageAI predicts we can no longer detect %s, will abort mission" % fleet_order.target) planet_stealthed = True if target_is_planet and not planet_stealthed: if isinstance(fleet_order, OrderColonize): if (planet.initialMeterValue(fo.meterType.population) == 0 and (planet.ownedBy(fo.empireID()) or planet.unowned)): return False elif isinstance(fleet_order, OrderOutpost): if planet.unowned: return False elif isinstance(fleet_order, OrderInvade): # TODO add substantive abort check return False else: return False # canceling fleet orders debug(" %s" % fleet_order) debug( "Fleet %d had a target planet that is no longer valid for this mission; aborting." % self.fleet.id) self.clear_fleet_orders() self.clear_target() FleetUtilsAI.split_fleet(self.fleet.id) return True
def split_new_fleets(self): """Split any new fleets (at new game creation, can have unplanned mix of ship roles).""" universe = fo.getUniverse() mission_table = Table( [ Text('Fleet'), Text('Mission'), Text('Ships'), Float('Rating'), Float('Troops'), Text('Target') ], table_name="Turn %d: Fleet Mission Review from Last Turn" % fo.currentTurn()) for fleet_id, mission in self.get_fleet_missions_map().items(): fleet = universe.getFleet(fleet_id) if not fleet: continue if not mission: mission_table.add_row([fleet]) else: mission_table.add_row([ fleet, mission.type or "None", len(fleet.shipIDs), CombatRatingsAI.get_fleet_rating(fleet_id), FleetUtilsAI.count_troops_in_fleet(fleet_id), mission.target or "-" ]) mission_table.print_table() # TODO: check length of fleets for losses or do in AIstat.__cleanRoles known_fleets = self.get_fleet_roles_map() self.newlySplitFleets.clear() fleets_to_split = [ fleet_id for fleet_id in FleetUtilsAI.get_empire_fleet_ids() if fleet_id not in known_fleets ] if fleets_to_split: print "Splitting new fleets" for fleet_id in fleets_to_split: fleet = universe.getFleet(fleet_id) if not fleet: print >> sys.stderr, "After splitting fleet: resulting fleet ID %d appears to not exist" % fleet_id continue fleet_len = len(list(fleet.shipIDs)) if fleet_len == 1: continue new_fleets = FleetUtilsAI.split_fleet( fleet_id) # try splitting fleet print "\t from splitting fleet ID %4d with %d ships, got %d new fleets:" % ( fleet_id, fleet_len, len(new_fleets))
def _check_abort_mission(self, fleet_order): """ checks if current mission (targeting a planet) should be aborted""" if fleet_order.target and isinstance(fleet_order.target, Planet): planet = fleet_order.target.get_object() if isinstance(fleet_order, OrderColonize): if planet.currentMeterValue(fo.meterType.population) == 0 and (planet.ownedBy(fo.empireID()) or planet.unowned): return False elif isinstance(fleet_order, OrderOutpost): if planet.unowned: return False elif isinstance(fleet_order, OrderInvade): # TODO add substantive abort check return False else: return False # canceling fleet orders print " %s" % fleet_order print "Fleet %d had a target planet that is no longer valid for this mission; aborting." % self.fleet.id self.clear_fleet_orders() self.clear_target() FleetUtilsAI.split_fleet(self.fleet.id) return True
def _check_abort_mission(self, fleet_order): """ checks if current mission (targeting a planet) should be aborted""" planet = fo.getUniverse().getPlanet(fleet_order.get_target_target().target_id) if planet: order_type = fleet_order.get_fleet_order_type() if order_type == AIFleetOrderType.ORDER_COLONISE: if planet.currentMeterValue(fo.meterType.population) == 0 and (planet.ownedBy(fo.empireID()) or planet.unowned): return False elif order_type == AIFleetOrderType.ORDER_OUTPOST: if planet.unowned: return False elif order_type == AIFleetOrderType.ORDER_INVADE: #TODO add substantive abort check return False else: return False # canceling fleet orders print " %s" % fleet_order print "Fleet %d had a target planet that is no longer valid for this mission; aborting." % self.target_id self.clear_fleet_orders() self.clear_targets(([-1] + self.get_mission_types()[:1])[-1]) FleetUtilsAI.split_fleet(self.target_id) return True
def _check_abort_mission(self, fleet_order): """ checks if current mission (targeting a planet) should be aborted""" planet = fo.getUniverse().getPlanet(fleet_order.target.target_id) if planet: order_type = fleet_order.order_type if order_type == AIFleetOrderType.ORDER_COLONISE: if planet.currentMeterValue(fo.meterType.population) == 0 and (planet.ownedBy(fo.empireID()) or planet.unowned): return False elif order_type == AIFleetOrderType.ORDER_OUTPOST: if planet.unowned: return False elif order_type == AIFleetOrderType.ORDER_INVADE: #TODO add substantive abort check return False else: return False # canceling fleet orders print " %s" % fleet_order print "Fleet %d had a target planet that is no longer valid for this mission; aborting." % self.target_id self.clear_fleet_orders() self.clear_targets(([-1] + self.get_mission_types()[:1])[-1]) FleetUtilsAI.split_fleet(self.target_id) return True
def _check_abort_mission(self, fleet_order): """ checks if current mission (targeting a planet) should be aborted""" planet_stealthed = False target_is_planet = fleet_order.target and isinstance(fleet_order.target, TargetPlanet) planet = None if target_is_planet: planet = fleet_order.target.get_object() # Check visibility prediction, but if somehow still have current visibility, don't # abort the mission yet if not EspionageAI.colony_detectable_by_empire(planet.id, empire=fo.empireID()): if get_partial_visibility_turn(planet.id) == fo.currentTurn(): debug("EspionageAI predicts planet id %d to be stealthed" % planet.id + ", but somehow have current visibity anyway, so won't trigger mission abort") else: debug("EspionageAI predicts we can no longer detect %s, will abort mission" % fleet_order.target) planet_stealthed = True if target_is_planet and not planet_stealthed: if isinstance(fleet_order, OrderColonize): if (planet.initialMeterValue(fo.meterType.population) == 0 and (planet.ownedBy(fo.empireID()) or planet.unowned)): return False elif isinstance(fleet_order, OrderOutpost): if planet.unowned: return False elif isinstance(fleet_order, OrderInvade): # TODO add substantive abort check return False else: return False # canceling fleet orders debug(" %s" % fleet_order) debug("Fleet %d had a target planet that is no longer valid for this mission; aborting." % self.fleet.id) self.clear_fleet_orders() self.clear_target() FleetUtilsAI.split_fleet(self.fleet.id) return True
def _check_abort_mission(self, fleet_order): """ checks if current mission (targeting a planet) should be aborted""" if fleet_order.target and isinstance(fleet_order.target, Planet): planet = fleet_order.target.get_object() if isinstance(fleet_order, OrderColonize): if (planet.initialMeterValue(fo.meterType.population) == 0 and (planet.ownedBy(fo.empireID()) or planet.unowned)): return False elif isinstance(fleet_order, OrderOutpost): if planet.unowned: return False elif isinstance(fleet_order, OrderInvade): # TODO add substantive abort check return False else: return False # canceling fleet orders print " %s" % fleet_order print "Fleet %d had a target planet that is no longer valid for this mission; aborting." % self.fleet.id self.clear_fleet_orders() self.clear_target() FleetUtilsAI.split_fleet(self.fleet.id) return True
def split_new_fleets(self): """Split any new fleets (at new game creation, can have unplanned mix of ship roles).""" universe = fo.getUniverse() mission_table = Table([Text('Fleet'), Text('Mission'), Text('Ships'), Float('Rating'), Float('Troops'), Text('Target')], table_name="Turn %d: Fleet Mission Review from Last Turn" % fo.currentTurn()) for fleet_id, mission in self.get_fleet_missions_map().items(): fleet = universe.getFleet(fleet_id) if not fleet: continue if not mission: mission_table.add_row([fleet]) else: mission_table.add_row([ fleet, mission.type or "None", len(fleet.shipIDs), CombatRatingsAI.get_fleet_rating(fleet_id), FleetUtilsAI.count_troops_in_fleet(fleet_id), mission.target or "-" ]) mission_table.print_table() # TODO: check length of fleets for losses or do in AIstat.__cleanRoles known_fleets = self.get_fleet_roles_map() self.newlySplitFleets.clear() fleets_to_split = [fleet_id for fleet_id in FleetUtilsAI.get_empire_fleet_ids() if fleet_id not in known_fleets] if fleets_to_split: print "Splitting new fleets" for fleet_id in fleets_to_split: fleet = universe.getFleet(fleet_id) if not fleet: print >> sys.stderr, "After splitting fleet: resulting fleet ID %d appears to not exist" % fleet_id continue fleet_len = len(list(fleet.shipIDs)) if fleet_len == 1: continue new_fleets = FleetUtilsAI.split_fleet(fleet_id) # try splitting fleet print "\t from splitting fleet ID %4d with %d ships, got %d new fleets:" % (fleet_id, fleet_len, len(new_fleets))
def issue_fleet_orders(self): """issues AIFleetOrders which can be issued in system and moves to next one if is possible""" # TODO: priority order_completed = True debug( "\nChecking orders for fleet %s (on turn %d), with mission type %s" % (self.fleet.get_object(), fo.currentTurn(), self.type or 'No mission')) if MissionType.INVASION == self.type: self._check_retarget_invasion() just_issued_move_order = False last_move_target_id = INVALID_ID # Note: the following abort check somewhat assumes only one major mission type for fleet_order in self.orders: if (isinstance(fleet_order, (OrderColonize, OrderOutpost, OrderInvade)) and self._check_abort_mission(fleet_order)): return aistate = get_aistate() for fleet_order in self.orders: if just_issued_move_order and self.fleet.get_object( ).systemID != last_move_target_id: # having just issued a move order, we will normally stop issuing orders this turn, except that if there # are consecutive move orders we will consider moving through the first destination rather than stopping # Without the below noinspection directive, PyCharm is concerned about the 2nd part of the test # noinspection PyTypeChecker if (not isinstance(fleet_order, OrderMove) or self.need_to_pause_movement(last_move_target_id, fleet_order)): break debug("Checking order: %s" % fleet_order) self.check_mergers(context=str(fleet_order)) if fleet_order.can_issue_order(verbose=False): if isinstance( fleet_order, OrderMove ) and order_completed: # only move if all other orders completed debug("Issuing fleet order %s" % fleet_order) fleet_order.issue_order() just_issued_move_order = True last_move_target_id = fleet_order.target.id elif not isinstance(fleet_order, OrderMove): debug("Issuing fleet order %s" % fleet_order) fleet_order.issue_order() else: debug( "NOT issuing (even though can_issue) fleet order %s" % fleet_order) debug("Order issued: %s" % fleet_order.order_issued) if not fleet_order.executed: order_completed = False else: # check that we're not held up by a Big Monster if fleet_order.order_issued: # A previously issued order that wasn't instantly executed must have had cirumstances change so that # the order can't currently be reissued (or perhaps simply a savegame has been reloaded on the same # turn the order was issued). if not fleet_order.executed: order_completed = False # Go on to the next order. continue debug("CAN'T issue fleet order %s" % fleet_order) if isinstance(fleet_order, OrderMove): this_system_id = fleet_order.target.id this_status = aistate.systemStatus.setdefault( this_system_id, {}) threat_threshold = fo.currentTurn( ) * MilitaryAI.cur_best_mil_ship_rating() / 4.0 if this_status.get('monsterThreat', 0) > threat_threshold: # if this move order is not this mil fleet's final destination, and blocked by Big Monster, # release and hope for more effective reassignment if (self.type not in (MissionType.MILITARY, MissionType.SECURE) or fleet_order != self.orders[-1]): debug( "Aborting mission due to being blocked by Big Monster at system %d, threat %d" % (this_system_id, aistate.systemStatus[this_system_id] ['monsterThreat'])) debug("Full set of orders were:") for this_order in self.orders: debug(" - %s" % this_order) self.clear_fleet_orders() self.clear_target() return break # do not order the next order until this one is finished. else: # went through entire order list if order_completed: debug("Final order is completed") orders = self.orders last_order = orders[-1] if orders else None universe = fo.getUniverse() if last_order and isinstance(last_order, OrderColonize): planet = universe.getPlanet(last_order.target.id) sys_partial_vis_turn = get_partial_visibility_turn( planet.systemID) planet_partial_vis_turn = get_partial_visibility_turn( planet.id) if (planet_partial_vis_turn == sys_partial_vis_turn and not planet.initialMeterValue( fo.meterType.population)): warn( "Fleet %d has tentatively completed its " "colonize mission but will wait to confirm population." % self.fleet.id) debug(" Order details are %s" % last_order) debug( " Order is valid: %s; issued: %s; executed: %s" % (last_order.is_valid(), last_order.order_issued, last_order.executed)) if not last_order.is_valid(): source_target = last_order.fleet target_target = last_order.target debug( " source target validity: %s; target target validity: %s " % (bool(source_target), bool(target_target))) return # colonize order must not have completed yet clear_all = True last_sys_target = INVALID_ID if last_order and isinstance(last_order, OrderMilitary): last_sys_target = last_order.target.id # not doing this until decide a way to release from a SECURE mission # if (MissionType.SECURE == self.type) or secure_targets = set(AIstate.colonyTargetedSystemIDs + AIstate.outpostTargetedSystemIDs + AIstate.invasionTargetedSystemIDs) if last_sys_target in secure_targets: # consider a secure mission if last_sys_target in AIstate.colonyTargetedSystemIDs: secure_type = "Colony" elif last_sys_target in AIstate.outpostTargetedSystemIDs: secure_type = "Outpost" elif last_sys_target in AIstate.invasionTargetedSystemIDs: secure_type = "Invasion" else: secure_type = "Unidentified" debug( "Fleet %d has completed initial stage of its mission " "to secure system %d (targeted for %s), " "may release a portion of ships" % (self.fleet.id, last_sys_target, secure_type)) clear_all = False fleet_id = self.fleet.id if clear_all: if orders: debug( "Fleet %d has completed its mission; clearing all orders and targets." % self.fleet.id) debug("Full set of orders were:") for this_order in orders: debug("\t\t %s" % this_order) self.clear_fleet_orders() self.clear_target() if aistate.get_fleet_role(fleet_id) in ( MissionType.MILITARY, MissionType.SECURE): allocations = MilitaryAI.get_military_fleets( mil_fleets_ids=[fleet_id], try_reset=False, thisround="Fleet %d Reassignment" % fleet_id) if allocations: MilitaryAI.assign_military_fleets_to_systems( use_fleet_id_list=[fleet_id], allocations=allocations) else: # no orders debug("No Current Orders") else: # TODO: evaluate releasing a smaller portion or none of the ships system_status = aistate.systemStatus.setdefault( last_sys_target, {}) new_fleets = [] threat_present = system_status.get( 'totalThreat', 0) + system_status.get( 'neighborThreat', 0) > 0 target_system = universe.getSystem(last_sys_target) if not threat_present and target_system: for pid in target_system.planetIDs: planet = universe.getPlanet(pid) if (planet and planet.owner != fo.empireID() and planet.currentMeterValue( fo.meterType.maxDefense) > 0): threat_present = True break if not threat_present: debug( "No current threat in target system; releasing a portion of ships." ) # at least first stage of current task is done; # release extra ships for potential other deployments new_fleets = FleetUtilsAI.split_fleet(self.fleet.id) else: debug( "Threat remains in target system; NOT releasing any ships." ) new_military_fleets = [] for fleet_id in new_fleets: if aistate.get_fleet_role( fleet_id) in COMBAT_MISSION_TYPES: new_military_fleets.append(fleet_id) allocations = [] if new_military_fleets: allocations = MilitaryAI.get_military_fleets( mil_fleets_ids=new_military_fleets, try_reset=False, thisround="Fleet Reassignment %s" % new_military_fleets) if allocations: MilitaryAI.assign_military_fleets_to_systems( use_fleet_id_list=new_military_fleets, allocations=allocations)
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_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_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 issue_fleet_orders(self): """issues AIFleetOrders which can be issued in system and moves to next one if is possible""" # TODO: priority order_completed = True debug("\nChecking orders for fleet %s (on turn %d), with mission type %s and target %s", self.fleet.get_object(), fo.currentTurn(), self.type or 'No mission', self.target or 'No Target') if MissionType.INVASION == self.type: self._check_retarget_invasion() just_issued_move_order = False last_move_target_id = INVALID_ID # Note: the following abort check somewhat assumes only one major mission type for fleet_order in self.orders: if (isinstance(fleet_order, (OrderColonize, OrderOutpost, OrderInvade)) and self._check_abort_mission(fleet_order)): return aistate = get_aistate() for fleet_order in self.orders: if just_issued_move_order and self.fleet.get_object().systemID != last_move_target_id: # having just issued a move order, we will normally stop issuing orders this turn, except that if there # are consecutive move orders we will consider moving through the first destination rather than stopping # Without the below noinspection directive, PyCharm is concerned about the 2nd part of the test # noinspection PyTypeChecker if (not isinstance(fleet_order, OrderMove) or self.need_to_pause_movement(last_move_target_id, fleet_order)): break debug("Checking order: %s" % fleet_order) self.check_mergers(context=str(fleet_order)) if fleet_order.can_issue_order(verbose=False): # only move if all other orders completed if isinstance(fleet_order, OrderMove) and order_completed: debug("Issuing fleet order %s" % fleet_order) fleet_order.issue_order() just_issued_move_order = True last_move_target_id = fleet_order.target.id elif not isinstance(fleet_order, OrderMove): debug("Issuing fleet order %s" % fleet_order) fleet_order.issue_order() else: debug("NOT issuing (even though can_issue) fleet order %s" % fleet_order) status_words = tuple(["not", ""][_s] for _s in [fleet_order.order_issued, fleet_order.executed]) debug("Order %s issued and %s fully executed." % status_words) if not fleet_order.executed: order_completed = False else: # check that we're not held up by a Big Monster if fleet_order.order_issued: # A previously issued order that wasn't instantly executed must have had cirumstances change so that # the order can't currently be reissued (or perhaps simply a savegame has been reloaded on the same # turn the order was issued). if not fleet_order.executed: order_completed = False # Go on to the next order. continue debug("CAN'T issue fleet order %s because:" % fleet_order) fleet_order.can_issue_order(verbose=True) if isinstance(fleet_order, OrderMove): this_system_id = fleet_order.target.id this_status = aistate.systemStatus.setdefault(this_system_id, {}) threat_threshold = fo.currentTurn() * MilitaryAI.cur_best_mil_ship_rating() / 4.0 if this_status.get('monsterThreat', 0) > threat_threshold: # if this move order is not this mil fleet's final destination, and blocked by Big Monster, # release and hope for more effective reassignment if (self.type not in (MissionType.MILITARY, MissionType.SECURE) or fleet_order != self.orders[-1]): debug("Aborting mission due to being blocked by Big Monster at system %d, threat %d" % ( this_system_id, aistate.systemStatus[this_system_id]['monsterThreat'])) debug("Full set of orders were:") for this_order in self.orders: debug(" - %s" % this_order) self.clear_fleet_orders() self.clear_target() return break # do not order the next order until this one is finished. else: # went through entire order list if order_completed: debug("Final order is completed") orders = self.orders last_order = orders[-1] if orders else None universe = fo.getUniverse() if last_order and isinstance(last_order, OrderColonize): planet = universe.getPlanet(last_order.target.id) sys_partial_vis_turn = get_partial_visibility_turn(planet.systemID) planet_partial_vis_turn = get_partial_visibility_turn(planet.id) if (planet_partial_vis_turn == sys_partial_vis_turn and not planet.initialMeterValue(fo.meterType.population)): warn("Fleet %d has tentatively completed its " "colonize mission but will wait to confirm population." % self.fleet.id) debug(" Order details are %s" % last_order) debug(" Order is valid: %s; issued: %s; executed: %s" % ( last_order.is_valid(), last_order.order_issued, last_order.executed)) if not last_order.is_valid(): source_target = last_order.fleet target_target = last_order.target debug(" source target validity: %s; target target validity: %s " % ( bool(source_target), bool(target_target))) return # colonize order must not have completed yet clear_all = True last_sys_target = INVALID_ID if last_order and isinstance(last_order, OrderMilitary): last_sys_target = last_order.target.id # not doing this until decide a way to release from a SECURE mission # if (MissionType.SECURE == self.type) or secure_targets = set(AIstate.colonyTargetedSystemIDs + AIstate.outpostTargetedSystemIDs + AIstate.invasionTargetedSystemIDs) if last_sys_target in secure_targets: # consider a secure mission if last_sys_target in AIstate.colonyTargetedSystemIDs: secure_type = "Colony" elif last_sys_target in AIstate.outpostTargetedSystemIDs: secure_type = "Outpost" elif last_sys_target in AIstate.invasionTargetedSystemIDs: secure_type = "Invasion" else: secure_type = "Unidentified" debug("Fleet %d has completed initial stage of its mission " "to secure system %d (targeted for %s), " "may release a portion of ships" % (self.fleet.id, last_sys_target, secure_type)) clear_all = False # for PROTECT_REGION missions, only release fleet if no more threat if self.type == MissionType.PROTECT_REGION: # use military logic code below to determine if can release # any or even all of the ships. clear_all = False last_sys_target = self.target.id debug("Check if PROTECT_REGION mission with target %d is finished.", last_sys_target) fleet_id = self.fleet.id if clear_all: if orders: debug("Fleet %d has completed its mission; clearing all orders and targets." % self.fleet.id) debug("Full set of orders were:") for this_order in orders: debug("\t\t %s" % this_order) self.clear_fleet_orders() self.clear_target() if aistate.get_fleet_role(fleet_id) in (MissionType.MILITARY, MissionType.SECURE): allocations = MilitaryAI.get_military_fleets(mil_fleets_ids=[fleet_id], try_reset=False, thisround="Fleet %d Reassignment" % fleet_id) if allocations: MilitaryAI.assign_military_fleets_to_systems(use_fleet_id_list=[fleet_id], allocations=allocations) else: # no orders debug("No Current Orders") else: potential_threat = CombatRatingsAI.combine_ratings( MilitaryAI.get_system_local_threat(last_sys_target), MilitaryAI.get_system_neighbor_threat(last_sys_target) ) threat_present = potential_threat > 0 debug("Fleet threat present? %s", threat_present) target_system = universe.getSystem(last_sys_target) if not threat_present and target_system: for pid in target_system.planetIDs: planet = universe.getPlanet(pid) if (planet and planet.owner != fo.empireID() and planet.currentMeterValue(fo.meterType.maxDefense) > 0): debug("Found local planetary threat: %s", planet) threat_present = True break if not threat_present: debug("No current threat in target system; releasing a portion of ships.") # at least first stage of current task is done; # release extra ships for potential other deployments new_fleets = FleetUtilsAI.split_fleet(self.fleet.id) if self.type == MissionType.PROTECT_REGION: self.clear_fleet_orders() self.clear_target() new_fleets.append(self.fleet.id) else: debug("Threat remains in target system; Considering to release some ships.") new_fleets = [] fleet_portion_to_remain = self._portion_of_fleet_needed_here() if fleet_portion_to_remain > 1: debug("Can not release fleet yet due to large threat.") elif fleet_portion_to_remain > 0: debug("Not all ships are needed here - considering releasing a few") fleet_remaining_rating = CombatRatingsAI.get_fleet_rating(fleet_id) fleet_min_rating = fleet_portion_to_remain * fleet_remaining_rating debug("Starting rating: %.1f, Target rating: %.1f", fleet_remaining_rating, fleet_min_rating) allowance = CombatRatingsAI.rating_needed(fleet_remaining_rating, fleet_min_rating) debug("May release ships with total rating of %.1f", allowance) ship_ids = list(self.fleet.get_object().shipIDs) for ship_id in ship_ids: ship_rating = CombatRatingsAI.get_ship_rating(ship_id) debug("Considering to release ship %d with rating %.1f", ship_id, ship_rating) if ship_rating > allowance: debug("Remaining rating insufficient. Not released.") continue debug("Splitting from fleet.") new_fleet_id = FleetUtilsAI.split_ship_from_fleet(fleet_id, ship_id) if assertion_fails(new_fleet_id and new_fleet_id != INVALID_ID): break new_fleets.append(new_fleet_id) fleet_remaining_rating = CombatRatingsAI.rating_difference( fleet_remaining_rating, ship_rating) allowance = CombatRatingsAI.rating_difference( fleet_remaining_rating, fleet_min_rating) debug("Remaining fleet rating: %.1f - Allowance: %.1f", fleet_remaining_rating, allowance) if new_fleets: aistate.get_fleet_role(fleet_id, force_new=True) aistate.update_fleet_rating(fleet_id) aistate.ensure_have_fleet_missions(new_fleets) else: debug("Planetary defenses are deemed sufficient. Release fleet.") new_fleets = FleetUtilsAI.split_fleet(self.fleet.id) new_military_fleets = [] for fleet_id in new_fleets: if aistate.get_fleet_role(fleet_id) in COMBAT_MISSION_TYPES: new_military_fleets.append(fleet_id) allocations = [] if new_military_fleets: allocations = MilitaryAI.get_military_fleets( mil_fleets_ids=new_military_fleets, try_reset=False, thisround="Fleet Reassignment %s" % new_military_fleets ) if allocations: MilitaryAI.assign_military_fleets_to_systems(use_fleet_id_list=new_military_fleets, allocations=allocations)
def issue_fleet_orders(self): """issues AIFleetOrders which can be issued in system and moves to next one if is possible""" # TODO: priority order_completed = True print print "Checking orders for fleet %s (on turn %d), with mission type %s" % (self.fleet.get_object(), fo.currentTurn(), self.type or 'No mission') if MissionType.INVASION == self.type: self._check_retarget_invasion() for fleet_order in self.orders: print "Checking order: %s" % fleet_order if isinstance(fleet_order, (OrderColonize, OrderOutpost, OrderInvade)): # TODO: invasion? if self._check_abort_mission(fleet_order): print "Aborting fleet order %s" % fleet_order return self.check_mergers(context=str(fleet_order)) if fleet_order.can_issue_order(verbose=False): if isinstance(fleet_order, OrderMove) and order_completed: # only move if all other orders completed print "Issuing fleet order %s" % fleet_order fleet_order.issue_order() elif not isinstance(fleet_order, OrderMove): print "Issuing fleet order %s" % fleet_order fleet_order.issue_order() else: print "NOT issuing (even though can_issue) fleet order %s" % fleet_order print "Order issued: %s" % fleet_order.order_issued if not fleet_order.order_issued: order_completed = False else: # check that we're not held up by a Big Monster if fleet_order.order_issued: # It's unclear why we'd really get to this spot, but it has been observed to happen, perhaps due to # game being reloaded after code changes. # Go on to the next order. continue print "CAN'T issue fleet order %s" % fleet_order if isinstance(fleet_order, OrderMove): this_system_id = fleet_order.target.id this_status = foAI.foAIstate.systemStatus.setdefault(this_system_id, {}) if this_status.get('monsterThreat', 0) > fo.currentTurn() * MilitaryAI.cur_best_mil_ship_rating() / 4.0: if (self.type not in (MissionType.MILITARY, MissionType.SECURE) or fleet_order != self.orders[-1] # if this move order is not this mil fleet's final destination, and blocked by Big Monster, release and hope for more effective reassignment ): print "Aborting mission due to being blocked by Big Monster at system %d, threat %d" % (this_system_id, foAI.foAIstate.systemStatus[this_system_id]['monsterThreat']) print "Full set of orders were:" for this_order in self.orders: print " - %s" % this_order self.clear_fleet_orders() self.clear_target() return # moving to another system stops issuing all orders in system where fleet is # move order is also the last order in system if isinstance(fleet_order, OrderMove): fleet = self.fleet.get_object() if fleet.systemID != fleet_order.target.id: break else: # went through entire order list if order_completed: print "Final order is completed" orders = self.orders last_order = orders[-1] if orders else None universe = fo.getUniverse() if last_order and isinstance(last_order, OrderColonize): planet = universe.getPlanet(last_order.target.id) sys_partial_vis_turn = universe.getVisibilityTurnsMap(planet.systemID, fo.empireID()).get(fo.visibility.partial, -9999) planet_partial_vis_turn = universe.getVisibilityTurnsMap(planet.id, fo.empireID()).get(fo.visibility.partial, -9999) if planet_partial_vis_turn == sys_partial_vis_turn and not planet.currentMeterValue(fo.meterType.population): print "Potential Error: Fleet %d has tentatively completed its colonize mission but will wait to confirm population." % self.fleet.id print " Order details are %s" % last_order print " Order is valid: %s; issued: %s; executed: %s" % (last_order.is_valid(), last_order.order_issued, last_order.executed) if not last_order.is_valid(): source_target = last_order.fleet target_target = last_order.target print " source target validity: %s; target target validity: %s " % (bool(source_target), bool(target_target)) return # colonize order must not have completed yet clear_all = True last_sys_target = -1 if last_order and isinstance(last_order, OrderMilitary): last_sys_target = last_order.target.id # if (MissionType.SECURE == self.type) or # not doing this until decide a way to release from a SECURE mission secure_targets = set(AIstate.colonyTargetedSystemIDs + AIstate.outpostTargetedSystemIDs + AIstate.invasionTargetedSystemIDs + AIstate.blockadeTargetedSystemIDs) if last_sys_target in secure_targets: # consider a secure mission if last_sys_target in AIstate.colonyTargetedSystemIDs: secure_type = "Colony" elif last_sys_target in AIstate.outpostTargetedSystemIDs: secure_type = "Outpost" elif last_sys_target in AIstate.invasionTargetedSystemIDs: secure_type = "Invasion" elif last_sys_target in AIstate.blockadeTargetedSystemIDs: secure_type = "Blockade" else: secure_type = "Unidentified" print "Fleet %d has completed initial stage of its mission to secure system %d (targeted for %s), may release a portion of ships" % (self.fleet.id, last_sys_target, secure_type) clear_all = False fleet_id = self.fleet.id if clear_all: if orders: print "Fleet %d has completed its mission; clearing all orders and targets." % self.fleet.id print "Full set of orders were:" for this_order in orders: print "\t\t %s" % this_order self.clear_fleet_orders() self.clear_target() if foAI.foAIstate.get_fleet_role(fleet_id) in (MissionType.MILITARY, MissionType.SECURE): allocations = MilitaryAI.get_military_fleets(mil_fleets_ids=[fleet_id], try_reset=False, thisround="Fleet %d Reassignment" % fleet_id) if allocations: MilitaryAI.assign_military_fleets_to_systems(use_fleet_id_list=[fleet_id], allocations=allocations) else: # no orders print "No Current Orders" else: # TODO: evaluate releasing a smaller portion or none of the ships system_status = foAI.foAIstate.systemStatus.setdefault(last_sys_target, {}) new_fleets = [] threat_present = (system_status.get('totalThreat', 0) != 0) or (system_status.get('neighborThreat', 0) != 0) target_system = universe.getSystem(last_sys_target) if not threat_present and target_system: for pid in target_system.planetIDs: planet = universe.getPlanet(pid) if planet and planet.owner != fo.empireID() and planet.currentMeterValue(fo.meterType.maxDefense) > 0: threat_present = True break if not threat_present: print "No current threat in target system; releasing a portion of ships." new_fleets = FleetUtilsAI.split_fleet(self.fleet.id) # at least first stage of current task is done; release extra ships for potential other deployments else: print "Threat remains in target system; NOT releasing any ships." new_military_fleets = [] for fleet_id in new_fleets: if foAI.foAIstate.get_fleet_role(fleet_id) in COMBAT_MISSION_TYPES: new_military_fleets.append(fleet_id) allocations = [] if new_military_fleets: allocations = MilitaryAI.get_military_fleets(mil_fleets_ids=new_military_fleets, try_reset=False, thisround="Fleet Reassignment %s" % new_military_fleets) if allocations: MilitaryAI.assign_military_fleets_to_systems(use_fleet_id_list=new_military_fleets, allocations=allocations)
def issue_fleet_orders(self): """issues AIFleetOrders which can be issued in system and moves to next one if is possible""" # TODO: priority order_completed = True print print "Checking orders for fleet %s (on turn %d), with mission type %s" % ( self.fleet.get_object(), fo.currentTurn(), self.type or 'No mission') if MissionType.INVASION == self.type: self._check_retarget_invasion() for fleet_order in self.orders: print "Checking order: %s" % fleet_order if isinstance( fleet_order, (OrderColonize, OrderOutpost, OrderInvade)): # TODO: invasion? if self._check_abort_mission(fleet_order): print "Aborting fleet order %s" % fleet_order return self.check_mergers(context=str(fleet_order)) if fleet_order.can_issue_order(verbose=False): if isinstance( fleet_order, OrderMove ) and order_completed: # only move if all other orders completed print "Issuing fleet order %s" % fleet_order fleet_order.issue_order() elif not isinstance(fleet_order, OrderMove): print "Issuing fleet order %s" % fleet_order fleet_order.issue_order() else: print "NOT issuing (even though can_issue) fleet order %s" % fleet_order print "Order issued: %s" % fleet_order.order_issued if not fleet_order.order_issued: order_completed = False else: # check that we're not held up by a Big Monster if fleet_order.order_issued: # It's unclear why we'd really get to this spot, but it has been observed to happen, perhaps due to # game being reloaded after code changes. # Go on to the next order. continue print "CAN'T issue fleet order %s" % fleet_order if isinstance(fleet_order, OrderMove): this_system_id = fleet_order.target.id this_status = foAI.foAIstate.systemStatus.setdefault( this_system_id, {}) if this_status.get('monsterThreat', 0) > fo.currentTurn( ) * MilitaryAI.cur_best_mil_ship_rating() / 4.0: if (self.type not in ( MissionType.MILITARY, MissionType.SECURE ) or fleet_order != self.orders[ -1] # if this move order is not this mil fleet's final destination, and blocked by Big Monster, release and hope for more effective reassignment ): print "Aborting mission due to being blocked by Big Monster at system %d, threat %d" % ( this_system_id, foAI.foAIstate. systemStatus[this_system_id]['monsterThreat']) print "Full set of orders were:" for this_order in self.orders: print " - %s" % this_order self.clear_fleet_orders() self.clear_target() return # moving to another system stops issuing all orders in system where fleet is # move order is also the last order in system if isinstance(fleet_order, OrderMove): fleet = self.fleet.get_object() if fleet.systemID != fleet_order.target.id: break else: # went through entire order list if order_completed: print "Final order is completed" orders = self.orders last_order = orders[-1] if orders else None universe = fo.getUniverse() if last_order and isinstance(last_order, OrderColonize): planet = universe.getPlanet(last_order.target.id) sys_partial_vis_turn = universe.getVisibilityTurnsMap( planet.systemID, fo.empireID()).get(fo.visibility.partial, -9999) planet_partial_vis_turn = universe.getVisibilityTurnsMap( planet.id, fo.empireID()).get(fo.visibility.partial, -9999) if planet_partial_vis_turn == sys_partial_vis_turn and not planet.currentMeterValue( fo.meterType.population): print "Potential Error: Fleet %d has tentatively completed its colonize mission but will wait to confirm population." % self.fleet.id print " Order details are %s" % last_order print " Order is valid: %s; issued: %s; executed: %s" % ( last_order.is_valid(), last_order.order_issued, last_order.executed) if not last_order.is_valid(): source_target = last_order.fleet target_target = last_order.target print " source target validity: %s; target target validity: %s " % ( bool(source_target), bool(target_target)) return # colonize order must not have completed yet clear_all = True last_sys_target = -1 if last_order and isinstance(last_order, OrderMilitary): last_sys_target = last_order.target.id # if (MissionType.SECURE == self.type) or # not doing this until decide a way to release from a SECURE mission secure_targets = set(AIstate.colonyTargetedSystemIDs + AIstate.outpostTargetedSystemIDs + AIstate.invasionTargetedSystemIDs + AIstate.blockadeTargetedSystemIDs) if last_sys_target in secure_targets: # consider a secure mission if last_sys_target in AIstate.colonyTargetedSystemIDs: secure_type = "Colony" elif last_sys_target in AIstate.outpostTargetedSystemIDs: secure_type = "Outpost" elif last_sys_target in AIstate.invasionTargetedSystemIDs: secure_type = "Invasion" elif last_sys_target in AIstate.blockadeTargetedSystemIDs: secure_type = "Blockade" else: secure_type = "Unidentified" print "Fleet %d has completed initial stage of its mission to secure system %d (targeted for %s), may release a portion of ships" % ( self.fleet.id, last_sys_target, secure_type) clear_all = False fleet_id = self.fleet.id if clear_all: if orders: print "Fleet %d has completed its mission; clearing all orders and targets." % self.fleet.id print "Full set of orders were:" for this_order in orders: print "\t\t %s" % this_order self.clear_fleet_orders() self.clear_target() if foAI.foAIstate.get_fleet_role(fleet_id) in ( MissionType.MILITARY, MissionType.SECURE): allocations = MilitaryAI.get_military_fleets( mil_fleets_ids=[fleet_id], try_reset=False, thisround="Fleet %d Reassignment" % fleet_id) if allocations: MilitaryAI.assign_military_fleets_to_systems( use_fleet_id_list=[fleet_id], allocations=allocations) else: # no orders print "No Current Orders" else: # TODO: evaluate releasing a smaller portion or none of the ships system_status = foAI.foAIstate.systemStatus.setdefault( last_sys_target, {}) new_fleets = [] threat_present = (system_status.get('totalThreat', 0) != 0) or (system_status.get( 'neighborThreat', 0) != 0) target_system = universe.getSystem(last_sys_target) if not threat_present and target_system: for pid in target_system.planetIDs: planet = universe.getPlanet(pid) if planet and planet.owner != fo.empireID( ) and planet.currentMeterValue( fo.meterType.maxDefense) > 0: threat_present = True break if not threat_present: print "No current threat in target system; releasing a portion of ships." new_fleets = FleetUtilsAI.split_fleet( self.fleet.id ) # at least first stage of current task is done; release extra ships for potential other deployments else: print "Threat remains in target system; NOT releasing any ships." new_military_fleets = [] for fleet_id in new_fleets: if foAI.foAIstate.get_fleet_role( fleet_id) in COMBAT_MISSION_TYPES: new_military_fleets.append(fleet_id) allocations = [] if new_military_fleets: allocations = MilitaryAI.get_military_fleets( mil_fleets_ids=new_military_fleets, try_reset=False, thisround="Fleet Reassignment %s" % new_military_fleets) if allocations: MilitaryAI.assign_military_fleets_to_systems( use_fleet_id_list=new_military_fleets, allocations=allocations)
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 issue_fleet_orders(self): """issues AIFleetOrders which can be issued in system and moves to next one if is possible""" # TODO: priority order_completed = True print print "Checking orders for fleet %s (on turn %d), with mission type %s" % ( self.fleet.get_object(), fo.currentTurn(), self.type or 'No mission') if MissionType.INVASION == self.type: self._check_retarget_invasion() just_issued_move_order = False last_move_target_id = INVALID_ID # Note: the following abort check somewhat assumes only one major mission type for fleet_order in self.orders: if (isinstance(fleet_order, (OrderColonize, OrderOutpost, OrderInvade)) and self._check_abort_mission(fleet_order)): return for fleet_order in self.orders: if just_issued_move_order and self.fleet.get_object().systemID != last_move_target_id: # having just issued a move order, we will normally stop issuing orders this turn, except that if there # are consecutive move orders we will consider moving through the first destination rather than stopping # Without the below noinspection directive, PyCharm is concerned about the 2nd part of the test # noinspection PyTypeChecker if (not isinstance(fleet_order, OrderMove) or self.need_to_pause_movement(last_move_target_id, fleet_order)): break print "Checking order: %s" % fleet_order self.check_mergers(context=str(fleet_order)) if fleet_order.can_issue_order(verbose=False): if isinstance(fleet_order, OrderMove) and order_completed: # only move if all other orders completed print "Issuing fleet order %s" % fleet_order fleet_order.issue_order() just_issued_move_order = True last_move_target_id = fleet_order.target.id elif not isinstance(fleet_order, OrderMove): print "Issuing fleet order %s" % fleet_order fleet_order.issue_order() else: print "NOT issuing (even though can_issue) fleet order %s" % fleet_order print "Order issued: %s" % fleet_order.order_issued if not fleet_order.executed: order_completed = False else: # check that we're not held up by a Big Monster if fleet_order.order_issued: # A previously issued order that wasn't instantly executed must have had cirumstances change so that # the order can't currently be reissued (or perhaps simply a savegame has been reloaded on the same # turn the order was issued). if not fleet_order.executed: order_completed = False # Go on to the next order. continue print "CAN'T issue fleet order %s" % fleet_order if isinstance(fleet_order, OrderMove): this_system_id = fleet_order.target.id this_status = foAI.foAIstate.systemStatus.setdefault(this_system_id, {}) threat_threshold = fo.currentTurn() * MilitaryAI.cur_best_mil_ship_rating() / 4.0 if this_status.get('monsterThreat', 0) > threat_threshold: # if this move order is not this mil fleet's final destination, and blocked by Big Monster, # release and hope for more effective reassignment if (self.type not in (MissionType.MILITARY, MissionType.SECURE) or fleet_order != self.orders[-1]): print "Aborting mission due to being blocked by Big Monster at system %d, threat %d" % ( this_system_id, foAI.foAIstate.systemStatus[this_system_id]['monsterThreat']) print "Full set of orders were:" for this_order in self.orders: print " - %s" % this_order self.clear_fleet_orders() self.clear_target() return break # do not order the next order until this one is finished. else: # went through entire order list if order_completed: print "Final order is completed" orders = self.orders last_order = orders[-1] if orders else None universe = fo.getUniverse() if last_order and isinstance(last_order, OrderColonize): planet = universe.getPlanet(last_order.target.id) sys_partial_vis_turn = get_partial_visibility_turn(planet.systemID) planet_partial_vis_turn = get_partial_visibility_turn(planet.id) if (planet_partial_vis_turn == sys_partial_vis_turn and not planet.initialMeterValue(fo.meterType.population)): warn("Fleet %d has tentatively completed its " "colonize mission but will wait to confirm population." % self.fleet.id) print " Order details are %s" % last_order print " Order is valid: %s; issued: %s; executed: %s" % ( last_order.is_valid(), last_order.order_issued, last_order.executed) if not last_order.is_valid(): source_target = last_order.fleet target_target = last_order.target print " source target validity: %s; target target validity: %s " % ( bool(source_target), bool(target_target)) return # colonize order must not have completed yet clear_all = True last_sys_target = INVALID_ID if last_order and isinstance(last_order, OrderMilitary): last_sys_target = last_order.target.id # not doing this until decide a way to release from a SECURE mission # if (MissionType.SECURE == self.type) or secure_targets = set(AIstate.colonyTargetedSystemIDs + AIstate.outpostTargetedSystemIDs + AIstate.invasionTargetedSystemIDs) if last_sys_target in secure_targets: # consider a secure mission if last_sys_target in AIstate.colonyTargetedSystemIDs: secure_type = "Colony" elif last_sys_target in AIstate.outpostTargetedSystemIDs: secure_type = "Outpost" elif last_sys_target in AIstate.invasionTargetedSystemIDs: secure_type = "Invasion" else: secure_type = "Unidentified" print ("Fleet %d has completed initial stage of its mission " "to secure system %d (targeted for %s), " "may release a portion of ships" % (self.fleet.id, last_sys_target, secure_type)) clear_all = False fleet_id = self.fleet.id if clear_all: if orders: print "Fleet %d has completed its mission; clearing all orders and targets." % self.fleet.id print "Full set of orders were:" for this_order in orders: print "\t\t %s" % this_order self.clear_fleet_orders() self.clear_target() if foAI.foAIstate.get_fleet_role(fleet_id) in (MissionType.MILITARY, MissionType.SECURE): allocations = MilitaryAI.get_military_fleets(mil_fleets_ids=[fleet_id], try_reset=False, thisround="Fleet %d Reassignment" % fleet_id) if allocations: MilitaryAI.assign_military_fleets_to_systems(use_fleet_id_list=[fleet_id], allocations=allocations) else: # no orders print "No Current Orders" else: # TODO: evaluate releasing a smaller portion or none of the ships system_status = foAI.foAIstate.systemStatus.setdefault(last_sys_target, {}) new_fleets = [] threat_present = system_status.get('totalThreat', 0) + system_status.get('neighborThreat', 0) > 0 target_system = universe.getSystem(last_sys_target) if not threat_present and target_system: for pid in target_system.planetIDs: planet = universe.getPlanet(pid) if (planet and planet.owner != fo.empireID() and planet.currentMeterValue(fo.meterType.maxDefense) > 0): threat_present = True break if not threat_present: print "No current threat in target system; releasing a portion of ships." # at least first stage of current task is done; # release extra ships for potential other deployments new_fleets = FleetUtilsAI.split_fleet(self.fleet.id) else: print "Threat remains in target system; NOT releasing any ships." new_military_fleets = [] for fleet_id in new_fleets: if foAI.foAIstate.get_fleet_role(fleet_id) in COMBAT_MISSION_TYPES: new_military_fleets.append(fleet_id) allocations = [] if new_military_fleets: allocations = MilitaryAI.get_military_fleets( mil_fleets_ids=new_military_fleets, try_reset=False, thisround="Fleet Reassignment %s" % new_military_fleets ) if allocations: MilitaryAI.assign_military_fleets_to_systems(use_fleet_id_list=new_military_fleets, allocations=allocations)
def issue_fleet_orders(self): """issues AIFleetOrders which can be issued in system and moves to next one if is possible""" # TODO: priority order_completed = True print "--------------" print "Checking orders for fleet %d (on turn %d)" % (self.target_id, fo.currentTurn()) print "\t Full Orders are:" for this_orders in self.orders: print "\t\t %s" % this_orders print "/t/t------" if AIFleetMissionType.FLEET_MISSION_INVASION in self.get_mission_types(): self._check_retarget_invasion() for fleet_order in self.orders: print " checking Order: %s" % fleet_order order_type = fleet_order.get_fleet_order_type() if order_type in [AIFleetOrderType.ORDER_COLONISE, AIFleetOrderType.ORDER_OUTPOST, AIFleetOrderType.ORDER_INVADE]: # TODO: invasion? if self._check_abort_mission(fleet_order): return self.check_mergers(context=str(fleet_order)) if fleet_order.can_issue_order(verbose=True): if order_type == AIFleetOrderType.ORDER_MOVE and order_completed: # only move if all other orders completed fleet_order.issue_order() elif order_type not in [AIFleetOrderType.ORDER_MOVE, AIFleetOrderType.ORDER_DEFEND]: fleet_order.issue_order() if not fleet_order.is_execution_completed(): order_completed = False else: # check that we're not held up by a Big Monster if order_type == AIFleetOrderType.ORDER_MOVE: this_system_id = fleet_order.get_target_target().target_id this_status = foAI.foAIstate.systemStatus.setdefault(this_system_id, {}) if this_status.get('monsterThreat', 0) > fo.currentTurn() * ProductionAI.curBestMilShipRating()/4.0: first_mission = self.get_mission_types()[0] if self.get_mission_types() else AIFleetMissionType.FLEET_MISSION_INVALID if (first_mission not in (AIFleetMissionType.FLEET_MISSION_ATTACK, AIFleetMissionType.FLEET_MISSION_MILITARY, AIFleetMissionType.FLEET_MISSION_HIT_AND_RUN, AIFleetMissionType.FLEET_MISSION_SECURE, ) or fleet_order != self.orders[-1] # if this move order is not this mil fleet's final destination, and blocked by Big Monster, release and hope for more effective reassignment ): print "Aborting mission due to being blocked by Big Monster at system %d, threat %d"%(this_system_id, foAI.foAIstate.systemStatus[this_system_id]['monsterThreat']) print "Full set of orders were:" for this_orders in self.orders: print "\t\t %s" % this_orders self.clear_fleet_orders() self.clear_targets(([-1] + self.get_mission_types()[:1])[-1]) return # moving to another system stops issuing all orders in system where fleet is # move order is also the last order in system if order_type == AIFleetOrderType.ORDER_MOVE: fleet = fo.getUniverse().getFleet(self.target_id) if fleet.systemID != fleet_order.get_target_target().target_id: break else: # went through entire order list if order_completed: orders = self.orders last_order = orders[-1] if orders else None universe = fo.getUniverse() if last_order and last_order.get_fleet_order_type() == AIFleetOrderType.ORDER_COLONISE: planet = universe.getPlanet(last_order.get_target_target().target_id) sys_partial_vis_turn = dict_from_map(universe.getVisibilityTurnsMap(planet.systemID, fo.empireID())).get(fo.visibility.partial, -9999) planet_partial_vis_turn = dict_from_map(universe.getVisibilityTurnsMap(planet.id, fo.empireID())).get(fo.visibility.partial, -9999) if planet_partial_vis_turn == sys_partial_vis_turn and not planet.currentMeterValue(fo.meterType.population): print "Potential Error: Fleet %d has tentatively completed its colonize mission but will wait to confirm population." % self.target_id print " Order details are %s" % last_order print " Order is valid: %s ; is Executed : %s; is execution completed: %s " % (last_order.is_valid(), last_order.isExecuted(), last_order.isExecutionCompleted()) if not last_order.is_valid(): source_target = last_order.get_source_target() target_target = last_order.get_target_target() print " source target validity: %s; target target validity: %s " % (source_target.valid, target_target.valid) if EnumsAI.AITargetType.TARGET_SHIP == source_target.target_type: ship_id = source_target.target_id ship = universe.getShip(ship_id) if not ship: print "Ship id %d not a valid ship id" % ship_id print " source target Ship (%d), species %s, can%s colonize" % (ship_id, ship.speciesName, ["not", ""][ship.canColonize]) return # colonize order must not have completed yet clearAll = True last_sys_target = -1 if last_order and last_order.get_fleet_order_type() == AIFleetOrderType.ORDER_MILITARY: last_sys_target = last_order.get_target_target().target_id # if (AIFleetMissionType.FLEET_MISSION_SECURE in self.get_mission_types()) or # not doing this until decide a way to release from a SECURE mission secure_targets = set(AIstate.colonyTargetedSystemIDs + AIstate.outpostTargetedSystemIDs + AIstate.invasionTargetedSystemIDs + AIstate.blockadeTargetedSystemIDs) if last_sys_target in secure_targets: # consider a secure mission if last_sys_target in AIstate.colonyTargetedSystemIDs: secure_type = "Colony" elif last_sys_target in AIstate.outpostTargetedSystemIDs: secure_type = "Outpost" elif last_sys_target in AIstate.invasionTargetedSystemIDs: secure_type = "Invasion" elif last_sys_target in AIstate.blockadeTargetedSystemIDs: secure_type = "Blockade" else: secure_type = "Unidentified" print "Fleet %d has completed initial stage of its mission to secure system %d (targeted for %s), may release a portion of ships" % (self.target_id, last_sys_target, secure_type) clearAll = False fleet_id = self.target_id if clearAll: if orders: print "Fleet %d has completed its mission; clearing all orders and targets." % self.target_id print "Full set of orders were:" for this_orders in orders: print "\t\t %s" % this_orders self.clear_fleet_orders() self.clear_targets(([-1] + self.get_mission_types()[:1])[-1]) if foAI.foAIstate.get_fleet_role(fleet_id) in (AIFleetMissionType.FLEET_MISSION_MILITARY, AIFleetMissionType.FLEET_MISSION_ATTACK, AIFleetMissionType.FLEET_MISSION_DEFEND, AIFleetMissionType.FLEET_MISSION_HIT_AND_RUN, AIFleetMissionType.FLEET_MISSION_SECURE): allocations = MilitaryAI.get_military_fleets(milFleetIDs=[fleet_id], tryReset=False, thisround="Fleet %d Reassignment" % fleet_id) if allocations: MilitaryAI.assign_military_fleets_to_systems(useFleetIDList=[fleet_id], allocations=allocations) else: # no orders print "No Current Orders" else: #TODO: evaluate releasing a smaller portion or none of the ships system_status = foAI.foAIstate.systemStatus.setdefault(last_sys_target, {}) new_fleets = [] threat_present = (system_status.get('totalThreat', 0) != 0) or (system_status.get('neighborThreat', 0) != 0) target_system = universe.getSystem(last_sys_target) if not threat_present and target_system: for pid in target_system.planetIDs: planet = universe.getPlanet(pid) if planet and planet.owner != fo.empireID() and planet.currentMeterValue(fo.meterType.maxDefense) > 0: threat_present = True break if not threat_present: print "No current threat in target system; releasing a portion of ships." new_fleets = FleetUtilsAI.split_fleet(self.target_id) # at least first stage of current task is done; release extra ships for potential other deployments else: print "Threat remains in target system; NOT releasing any ships." new_military_fleets = [] for fleet_id in new_fleets: if foAI.foAIstate.get_fleet_role(fleet_id) in (AIFleetMissionType.FLEET_MISSION_MILITARY, AIFleetMissionType.FLEET_MISSION_ATTACK, AIFleetMissionType.FLEET_MISSION_DEFEND, AIFleetMissionType.FLEET_MISSION_HIT_AND_RUN, AIFleetMissionType.FLEET_MISSION_SECURE): new_military_fleets.append(fleet_id) allocations = [] if new_military_fleets: allocations = MilitaryAI.get_military_fleets(milFleetIDs=new_military_fleets, tryReset=False, thisround="Fleet Reassignment %s" % new_military_fleets) if allocations: MilitaryAI.assign_military_fleets_to_systems(useFleetIDList=new_military_fleets, allocations=allocations)
def issue_fleet_orders(self): """issues AIFleetOrders which can be issued in system and moves to next one if is possible""" # TODO: priority order_completed = True debug("\nChecking orders for fleet %s (on turn %d), with mission type %s and target %s", self.fleet.get_object(), fo.currentTurn(), self.type or 'No mission', self.target or 'No Target') if MissionType.INVASION == self.type: self._check_retarget_invasion() just_issued_move_order = False last_move_target_id = INVALID_ID # Note: the following abort check somewhat assumes only one major mission type for fleet_order in self.orders: if (isinstance(fleet_order, (OrderColonize, OrderOutpost, OrderInvade)) and self._check_abort_mission(fleet_order)): return aistate = get_aistate() for fleet_order in self.orders: if just_issued_move_order and self.fleet.get_object().systemID != last_move_target_id: # having just issued a move order, we will normally stop issuing orders this turn, except that if there # are consecutive move orders we will consider moving through the first destination rather than stopping # Without the below noinspection directive, PyCharm is concerned about the 2nd part of the test # noinspection PyTypeChecker if (not isinstance(fleet_order, OrderMove) or self.need_to_pause_movement(last_move_target_id, fleet_order)): break debug("Checking order: %s" % fleet_order) self.check_mergers(context=str(fleet_order)) if fleet_order.can_issue_order(verbose=False): # only move if all other orders completed if isinstance(fleet_order, OrderMove) and order_completed: debug("Issuing fleet order %s" % fleet_order) fleet_order.issue_order() just_issued_move_order = True last_move_target_id = fleet_order.target.id elif not isinstance(fleet_order, OrderMove): debug("Issuing fleet order %s" % fleet_order) fleet_order.issue_order() else: debug("NOT issuing (even though can_issue) fleet order %s" % fleet_order) status_words = tuple(["not", ""][_s] for _s in [fleet_order.order_issued, fleet_order.executed]) debug("Order %s issued and %s fully executed." % status_words) if not fleet_order.executed: order_completed = False else: # check that we're not held up by a Big Monster if fleet_order.order_issued: # A previously issued order that wasn't instantly executed must have had cirumstances change so that # the order can't currently be reissued (or perhaps simply a savegame has been reloaded on the same # turn the order was issued). if not fleet_order.executed: order_completed = False # Go on to the next order. continue debug("CAN'T issue fleet order %s because:" % fleet_order) fleet_order.can_issue_order(verbose=True) if isinstance(fleet_order, OrderMove): this_system_id = fleet_order.target.id this_status = aistate.systemStatus.setdefault(this_system_id, {}) threat_threshold = fo.currentTurn() * MilitaryAI.cur_best_mil_ship_rating() / 4.0 if this_status.get('monsterThreat', 0) > threat_threshold: # if this move order is not this mil fleet's final destination, and blocked by Big Monster, # release and hope for more effective reassignment if (self.type not in (MissionType.MILITARY, MissionType.SECURE) or fleet_order != self.orders[-1]): debug("Aborting mission due to being blocked by Big Monster at system %d, threat %d" % ( this_system_id, aistate.systemStatus[this_system_id]['monsterThreat'])) debug("Full set of orders were:") for this_order in self.orders: debug(" - %s" % this_order) self.clear_fleet_orders() self.clear_target() return break # do not order the next order until this one is finished. else: # went through entire order list if order_completed: debug("Final order is completed") orders = self.orders last_order = orders[-1] if orders else None universe = fo.getUniverse() if last_order and isinstance(last_order, OrderColonize): planet = universe.getPlanet(last_order.target.id) sys_partial_vis_turn = get_partial_visibility_turn(planet.systemID) planet_partial_vis_turn = get_partial_visibility_turn(planet.id) if (planet_partial_vis_turn == sys_partial_vis_turn and not planet.initialMeterValue(fo.meterType.population)): warning("Fleet %s has tentatively completed its " "colonize mission but will wait to confirm population.", self.fleet) debug(" Order details are %s" % last_order) debug(" Order is valid: %s; issued: %s; executed: %s" % ( last_order.is_valid(), last_order.order_issued, last_order.executed)) if not last_order.is_valid(): source_target = last_order.fleet target_target = last_order.target debug(" source target validity: %s; target target validity: %s " % ( bool(source_target), bool(target_target))) return # colonize order must not have completed yet clear_all = True last_sys_target = INVALID_ID if last_order and isinstance(last_order, OrderMilitary): last_sys_target = last_order.target.id # not doing this until decide a way to release from a SECURE mission # if (MissionType.SECURE == self.type) or secure_targets = set(AIstate.colonyTargetedSystemIDs + AIstate.outpostTargetedSystemIDs + AIstate.invasionTargetedSystemIDs) if last_sys_target in secure_targets: # consider a secure mission if last_sys_target in AIstate.colonyTargetedSystemIDs: secure_type = "Colony" elif last_sys_target in AIstate.outpostTargetedSystemIDs: secure_type = "Outpost" elif last_sys_target in AIstate.invasionTargetedSystemIDs: secure_type = "Invasion" else: secure_type = "Unidentified" debug("Fleet %d has completed initial stage of its mission " "to secure system %d (targeted for %s), " "may release a portion of ships" % (self.fleet.id, last_sys_target, secure_type)) clear_all = False # for PROTECT_REGION missions, only release fleet if no more threat if self.type == MissionType.PROTECT_REGION: # use military logic code below to determine if can release # any or even all of the ships. clear_all = False last_sys_target = self.target.id debug("Check if PROTECT_REGION mission with target %d is finished.", last_sys_target) fleet_id = self.fleet.id if clear_all: if orders: debug("Fleet %d has completed its mission; clearing all orders and targets." % self.fleet.id) debug("Full set of orders were:") for this_order in orders: debug("\t\t %s" % this_order) self.clear_fleet_orders() self.clear_target() if aistate.get_fleet_role(fleet_id) in (MissionType.MILITARY, MissionType.SECURE): allocations = MilitaryAI.get_military_fleets(mil_fleets_ids=[fleet_id], try_reset=False, thisround="Fleet %d Reassignment" % fleet_id) if allocations: MilitaryAI.assign_military_fleets_to_systems(use_fleet_id_list=[fleet_id], allocations=allocations) else: # no orders debug("No Current Orders") else: potential_threat = combine_ratings( MilitaryAI.get_system_local_threat(last_sys_target), MilitaryAI.get_system_neighbor_threat(last_sys_target) ) threat_present = potential_threat > 0 debug("Fleet threat present? %s", threat_present) target_system = universe.getSystem(last_sys_target) if not threat_present and target_system: for pid in target_system.planetIDs: planet = universe.getPlanet(pid) if (planet and planet.owner != fo.empireID() and planet.currentMeterValue(fo.meterType.maxDefense) > 0): debug("Found local planetary threat: %s", planet) threat_present = True break if not threat_present: debug("No current threat in target system; releasing a portion of ships.") # at least first stage of current task is done; # release extra ships for potential other deployments new_fleets = FleetUtilsAI.split_fleet(self.fleet.id) if self.type == MissionType.PROTECT_REGION: self.clear_fleet_orders() self.clear_target() new_fleets.append(self.fleet.id) else: debug("Threat remains in target system; Considering to release some ships.") new_fleets = [] fleet_portion_to_remain = self._portion_of_fleet_needed_here() if fleet_portion_to_remain >= 1: debug("Can not release fleet yet due to large threat.") elif fleet_portion_to_remain > 0: debug("Not all ships are needed here - considering releasing a few") # TODO: Rate against specific enemy threat cause fleet_remaining_rating = CombatRatingsAI.get_fleet_rating(fleet_id) fleet_min_rating = fleet_portion_to_remain * fleet_remaining_rating debug("Starting rating: %.1f, Target rating: %.1f", fleet_remaining_rating, fleet_min_rating) allowance = CombatRatingsAI.rating_needed(fleet_remaining_rating, fleet_min_rating) debug("May release ships with total rating of %.1f", allowance) ship_ids = list(self.fleet.get_object().shipIDs) for ship_id in ship_ids: ship_rating = CombatRatingsAI.get_ship_rating(ship_id) debug("Considering to release ship %d with rating %.1f", ship_id, ship_rating) if ship_rating > allowance: debug("Remaining rating insufficient. Not released.") continue debug("Splitting from fleet.") new_fleet_id = FleetUtilsAI.split_ship_from_fleet(fleet_id, ship_id) if assertion_fails(new_fleet_id and new_fleet_id != INVALID_ID): break new_fleets.append(new_fleet_id) fleet_remaining_rating = CombatRatingsAI.rating_difference( fleet_remaining_rating, ship_rating) allowance = CombatRatingsAI.rating_difference( fleet_remaining_rating, fleet_min_rating) debug("Remaining fleet rating: %.1f - Allowance: %.1f", fleet_remaining_rating, allowance) if new_fleets: aistate.get_fleet_role(fleet_id, force_new=True) aistate.update_fleet_rating(fleet_id) aistate.ensure_have_fleet_missions(new_fleets) else: debug("Planetary defenses are deemed sufficient. Release fleet.") new_fleets = FleetUtilsAI.split_fleet(self.fleet.id) new_military_fleets = [] for fleet_id in new_fleets: if aistate.get_fleet_role(fleet_id) in COMBAT_MISSION_TYPES: new_military_fleets.append(fleet_id) allocations = [] if new_military_fleets: allocations = MilitaryAI.get_military_fleets( mil_fleets_ids=new_military_fleets, try_reset=False, thisround="Fleet Reassignment %s" % new_military_fleets ) if allocations: MilitaryAI.assign_military_fleets_to_systems(use_fleet_id_list=new_military_fleets, allocations=allocations)
def issue_fleet_orders(self): """issues AIFleetOrders which can be issued in system and moves to next one if is possible""" # TODO: priority order_completed = True print "--------------" print "Checking orders for fleet %d (on turn %d), with mission types %s" % ( self.target_id, fo.currentTurn(), [AIFleetMissionType.name(mt) for mt in self.get_mission_types()]) print "\t Full Orders are:" for this_order in self.orders: print "\t\t| %s" % this_order print "/t/t------" if AIFleetMissionType.FLEET_MISSION_INVASION in self.get_mission_types( ): self._check_retarget_invasion() for fleet_order in self.orders: print "\t| checking Order: %s" % fleet_order order_type = fleet_order.order_type if order_type in [ AIFleetOrderType.ORDER_COLONISE, AIFleetOrderType.ORDER_OUTPOST, AIFleetOrderType.ORDER_INVADE ]: # TODO: invasion? if self._check_abort_mission(fleet_order): print "\t\t| Aborting fleet order %s" % fleet_order return self.check_mergers(context=str(fleet_order)) if fleet_order.can_issue_order(verbose=True): if order_type == AIFleetOrderType.ORDER_MOVE and order_completed: # only move if all other orders completed print "\t\t| issuing fleet order %s" % fleet_order fleet_order.issue_order() elif order_type not in [ AIFleetOrderType.ORDER_MOVE, AIFleetOrderType.ORDER_DEFEND ]: print "\t\t| issuing fleet order %s" % fleet_order fleet_order.issue_order() else: print "\t\t| NOT issuing (even though can_issue) fleet order %s" % fleet_order print "\t\t| order status-- execution completed: %s" % fleet_order.execution_completed if not fleet_order.execution_completed: order_completed = False else: # check that we're not held up by a Big Monster print "\t\t| CAN'T issue fleet order %s" % fleet_order if order_type == AIFleetOrderType.ORDER_MOVE: this_system_id = fleet_order.target.target_id this_status = foAI.foAIstate.systemStatus.setdefault( this_system_id, {}) if this_status.get('monsterThreat', 0) > fo.currentTurn( ) * ProductionAI.cur_best_mil_ship_rating() / 4.0: first_mission = self.get_mission_types( )[0] if self.get_mission_types( ) else AIFleetMissionType.FLEET_MISSION_INVALID if (first_mission not in ( AIFleetMissionType.FLEET_MISSION_ATTACK, AIFleetMissionType.FLEET_MISSION_MILITARY, AIFleetMissionType.FLEET_MISSION_HIT_AND_RUN, AIFleetMissionType.FLEET_MISSION_SECURE, ) or fleet_order != self.orders[ -1] # if this move order is not this mil fleet's final destination, and blocked by Big Monster, release and hope for more effective reassignment ): print "Aborting mission due to being blocked by Big Monster at system %d, threat %d" % ( this_system_id, foAI.foAIstate. systemStatus[this_system_id]['monsterThreat']) print "Full set of orders were:" for this_order in self.orders: print "\t\t %s" % this_order self.clear_fleet_orders() self.clear_targets( ([-1] + self.get_mission_types()[:1])[-1]) return # moving to another system stops issuing all orders in system where fleet is # move order is also the last order in system if order_type == AIFleetOrderType.ORDER_MOVE: fleet = fo.getUniverse().getFleet(self.target_id) if fleet.systemID != fleet_order.target.target_id: break else: # went through entire order list if order_completed: print "\t| Final order is completed" orders = self.orders last_order = orders[-1] if orders else None universe = fo.getUniverse() if last_order and last_order.order_type == AIFleetOrderType.ORDER_COLONISE: planet = universe.getPlanet(last_order.target.target_id) sys_partial_vis_turn = universe.getVisibilityTurnsMap( planet.systemID, fo.empireID()).get(fo.visibility.partial, -9999) planet_partial_vis_turn = universe.getVisibilityTurnsMap( planet.id, fo.empireID()).get(fo.visibility.partial, -9999) if planet_partial_vis_turn == sys_partial_vis_turn and not planet.currentMeterValue( fo.meterType.population): print "Potential Error: Fleet %d has tentatively completed its colonize mission but will wait to confirm population." % self.target_id print " Order details are %s" % last_order print " Order is valid: %s ; is Executed : %s; is execution completed: %s " % ( last_order.is_valid(), last_order.isExecuted(), last_order.isExecutionCompleted()) if not last_order.is_valid(): source_target = last_order.fleet target_target = last_order.target print " source target validity: %s; target target validity: %s " % ( source_target.valid, target_target.valid) if EnumsAI.TargetType.TARGET_SHIP == source_target.target_type: ship_id = source_target.target_id ship = universe.getShip(ship_id) if not ship: print "Ship id %d not a valid ship id" % ship_id print " source target Ship (%d), species %s, can%s colonize" % ( ship_id, ship.speciesName, ["not", ""][ship.canColonize]) return # colonize order must not have completed yet clearAll = True last_sys_target = -1 if last_order and last_order.order_type == AIFleetOrderType.ORDER_MILITARY: last_sys_target = last_order.target.target_id # if (AIFleetMissionType.FLEET_MISSION_SECURE in self.get_mission_types()) or # not doing this until decide a way to release from a SECURE mission secure_targets = set(AIstate.colonyTargetedSystemIDs + AIstate.outpostTargetedSystemIDs + AIstate.invasionTargetedSystemIDs + AIstate.blockadeTargetedSystemIDs) if last_sys_target in secure_targets: # consider a secure mission if last_sys_target in AIstate.colonyTargetedSystemIDs: secure_type = "Colony" elif last_sys_target in AIstate.outpostTargetedSystemIDs: secure_type = "Outpost" elif last_sys_target in AIstate.invasionTargetedSystemIDs: secure_type = "Invasion" elif last_sys_target in AIstate.blockadeTargetedSystemIDs: secure_type = "Blockade" else: secure_type = "Unidentified" print "Fleet %d has completed initial stage of its mission to secure system %d (targeted for %s), may release a portion of ships" % ( self.target_id, last_sys_target, secure_type) clearAll = False fleet_id = self.target_id if clearAll: if orders: print "Fleet %d has completed its mission; clearing all orders and targets." % self.target_id print "Full set of orders were:" for this_order in orders: print "\t\t %s" % this_order self.clear_fleet_orders() self.clear_targets( ([-1] + self.get_mission_types()[:1])[-1]) if foAI.foAIstate.get_fleet_role(fleet_id) in ( AIFleetMissionType.FLEET_MISSION_MILITARY, AIFleetMissionType.FLEET_MISSION_ATTACK, AIFleetMissionType.FLEET_MISSION_DEFEND, AIFleetMissionType.FLEET_MISSION_HIT_AND_RUN, AIFleetMissionType.FLEET_MISSION_SECURE): allocations = MilitaryAI.get_military_fleets( milFleetIDs=[fleet_id], tryReset=False, thisround="Fleet %d Reassignment" % fleet_id) if allocations: MilitaryAI.assign_military_fleets_to_systems( useFleetIDList=[fleet_id], allocations=allocations) else: # no orders print "No Current Orders" else: #TODO: evaluate releasing a smaller portion or none of the ships system_status = foAI.foAIstate.systemStatus.setdefault( last_sys_target, {}) new_fleets = [] threat_present = (system_status.get('totalThreat', 0) != 0) or (system_status.get( 'neighborThreat', 0) != 0) target_system = universe.getSystem(last_sys_target) if not threat_present and target_system: for pid in target_system.planetIDs: planet = universe.getPlanet(pid) if planet and planet.owner != fo.empireID( ) and planet.currentMeterValue( fo.meterType.maxDefense) > 0: threat_present = True break if not threat_present: print "No current threat in target system; releasing a portion of ships." new_fleets = FleetUtilsAI.split_fleet( self.target_id ) # at least first stage of current task is done; release extra ships for potential other deployments else: print "Threat remains in target system; NOT releasing any ships." new_military_fleets = [] for fleet_id in new_fleets: if foAI.foAIstate.get_fleet_role( fleet_id) in COMBAT_MISSION_TYPES: new_military_fleets.append(fleet_id) allocations = [] if new_military_fleets: allocations = MilitaryAI.get_military_fleets( milFleetIDs=new_military_fleets, tryReset=False, thisround="Fleet Reassignment %s" % new_military_fleets) if allocations: MilitaryAI.assign_military_fleets_to_systems( useFleetIDList=new_military_fleets, allocations=allocations)