def _is_valid_fleet_mission_target(self, mission_type: MissionType, target: Target): if not target: return False if mission_type == MissionType.EXPLORATION: if isinstance(target, TargetSystem): empire = fo.getEmpire() if not empire.hasExploredSystem(target.id): return True elif mission_type in [ MissionType.OUTPOST, MissionType.ORBITAL_OUTPOST ]: fleet = self.fleet.get_object() if not fleet.hasOutpostShips: return False if isinstance(target, TargetPlanet): planet = target.get_object() if planet.unowned: return True elif mission_type == MissionType.COLONISATION: fleet = self.fleet.get_object() if not fleet.hasColonyShips: return False if isinstance(target, TargetPlanet): planet = target.get_object() population = planet.initialMeterValue(fo.meterType.population) if planet.unowned or (planet.owner == fleet.owner and population == 0): return True elif mission_type in [ MissionType.INVASION, MissionType.ORBITAL_INVASION ]: fleet = self.fleet.get_object() if not fleet.hasTroopShips: return False if isinstance(target, TargetPlanet): planet = target.get_object() # TODO remove latter portion of next check in light of invasion retargeting, or else correct logic if not planet.unowned or planet.owner != fleet.owner: return True elif mission_type in [ MissionType.MILITARY, MissionType.SECURE, MissionType.ORBITAL_DEFENSE, MissionType.PROTECT_REGION, ]: if isinstance(target, TargetSystem): return True # TODO: implement other mission types return False
def trooper_move_reqs_met(invasion_target: Target, order: OrderMove, verbose: bool) -> bool: """ Indicates whether or not move requirements specific to invasion troopers are met for the provided mission and order. :param verbose: whether to print verbose decision details """ # Don't advance outside of our fleet-supply zone unless the target either has no shields at all or there # is already a military fleet assigned to secure the target, and don't take final jump unless the planet is # (to the AI's knowledge) down to zero shields. Additional checks will also be done by the later # generic movement code invasion_planet = invasion_target.get_object() invasion_system = invasion_target.get_system() supplied_systems = fo.getEmpire().fleetSupplyableSystemIDs # if about to leave supply lines if order.target.id not in supplied_systems or fo.getUniverse( ).jumpDistance(order.fleet.id, invasion_system.id) < 5: if invasion_planet.currentMeterValue(fo.meterType.maxShield): military_support_fleets = MilitaryAI.get_military_fleets_with_target_system( invasion_system.id) if not military_support_fleets: if verbose: debug( "trooper_move_reqs_met() holding Invasion fleet %d before leaving supply " "because target (%s) has nonzero max shields and there is not yet a military fleet " "assigned to secure the target system." % (order.fleet.id, invasion_planet)) return False # if there is a threat in the enemy system, do give military ships at least 1 turn to clear it delay_to_move_troops = 1 if MilitaryAI.get_system_local_threat( order.target.id) else 0 def eta(fleet_id): return FleetUtilsAI.calculate_estimated_time_of_arrival( fleet_id, invasion_system.id) eta_this_fleet = eta(order.fleet.id) if all(((eta_this_fleet - delay_to_move_troops) <= eta(fid) and eta(fid)) for fid in military_support_fleets): if verbose: debug( "trooper_move_reqs_met() holding Invasion fleet %d before leaving supply " "because target (%s) has nonzero max shields and no assigned military fleet would arrive" "at least %d turn earlier than the invasion fleet" % (order.fleet.id, invasion_planet, delay_to_move_troops)) return False if verbose: debug( "trooper_move_reqs_met() allowing Invasion fleet %d to leave supply " "because target (%s) has zero max shields or there is a military fleet assigned to secure " "the target system which will arrive at least 1 turn before the invasion fleet.", order.fleet.id, invasion_planet) return True