Beispiel #1
0
    def issue_order(self):
        if not super(OrderResupply, self).issue_order():
            return
        fleet_id = self.fleet.id
        system_id = self.target.get_system().id
        fleet = self.fleet.get_object()
        if system_id not in [fleet.systemID, fleet.nextSystemID]:
            # if self.order_type == AIFleetOrderType.ORDER_MOVE:
            #     dest_id = system_id
            # else:
            # if self.order_type == AIFleetOrderType.ORDER_REPAIR:
            #     fo.issueAggressionOrder(fleet_id, False)
            start_id = FleetUtilsAI.get_fleet_system(fleet)
            dest_id = MoveUtilsAI.get_safe_path_leg_to_dest(fleet_id, start_id, system_id)
            print "fleet %d with order type(%s) sent to safe leg dest %s and ultimate dest %s" % (
                fleet_id, self.ORDER_NAME,
                PlanetUtilsAI.sys_name_ids([dest_id]),
                PlanetUtilsAI.sys_name_ids([system_id]))
            fo.issueFleetMoveOrder(fleet_id, dest_id)
            print "Order issued: %s fleet: %s target: %s" % (self.ORDER_NAME, self.fleet, self.target)

        if system_id == fleet.systemID:
            if foAI.foAIstate.get_fleet_role(fleet_id) == MissionType.EXPLORATION:
                if system_id in foAI.foAIstate.needsEmergencyExploration:
                    foAI.foAIstate.needsEmergencyExploration.remove(system_id)
            self.order_issued = True
Beispiel #2
0
 def __border_exploration_update(self):
     universe = fo.getUniverse()
     exploration_center = PlanetUtilsAI.get_capital_sys_id()
     # a bad state probably from an old savegame, or else empire has lost (or almost has)
     if exploration_center == INVALID_ID:
         exploration_center = self.__origin_home_system_id
     ExplorationAI.graph_flags.clear()
     if fo.currentTurn() < 50:
         print "-------------------------------------------------"
         print "Border Exploration Update (relative to %s)" % (
             PlanetUtilsAI.sys_name_ids([exploration_center, INVALID_ID])[0])
         print "-------------------------------------------------"
     if self.visBorderSystemIDs == {INVALID_ID}:
         self.visBorderSystemIDs.clear()
         self.visBorderSystemIDs.add(exploration_center)
     for sys_id in list(self.visBorderSystemIDs):  # This set is modified during iteration.
         if fo.currentTurn() < 50:
             print "Considering border system %s" % (PlanetUtilsAI.sys_name_ids([sys_id, INVALID_ID])[0])
         ExplorationAI.follow_vis_system_connections(sys_id, exploration_center)
     newly_explored = ExplorationAI.update_explored_systems()
     nametags = []
     for sys_id in newly_explored:
         newsys = universe.getSystem(sys_id)
         # an explored system *should* always be able to be gotten
         nametags.append("ID:%4d -- %-20s" % (sys_id, (newsys and newsys.name) or "name unknown"))
     if newly_explored:
         print "-------------------------------------------------"
         print "Newly explored systems:\n%s" % "\n".join(nametags)
         print "-------------------------------------------------"
Beispiel #3
0
def get_safe_path_leg_to_dest(fleet_id, start_id, dest_id):
    start_targ = AITarget.AITarget(AITargetType.TARGET_SYSTEM, start_id)
    dest_targ = AITarget.AITarget(AITargetType.TARGET_SYSTEM, dest_id)
    #TODO actually get a safe path
    this_path = can_travel_to_system(fleet_id, start_targ, dest_targ, ensure_return=False)
    path_ids = [targ.target_id for targ in this_path if targ.target_id != start_id] + [start_id]
    start_info = PlanetUtilsAI.sys_name_ids([start_id])
    dest_info = PlanetUtilsAI.sys_name_ids([dest_id])
    path_info = [PlanetUtilsAI.sys_name_ids([sys_id]) for sys_id in path_ids]
    print "Fleet %d requested safe path leg from %s to %s, found path %s" % (fleet_id, start_info, dest_info, path_info)
    return path_ids[0]
Beispiel #4
0
def get_safe_path_leg_to_dest(fleet_id, start_id, dest_id):
    start_targ = universe_object.System(start_id)
    dest_targ = universe_object.System(dest_id)
    # TODO actually get a safe path
    this_path = can_travel_to_system(fleet_id, start_targ, dest_targ, ensure_return=False)
    path_ids = [targ.id for targ in this_path if targ.id != start_id] + [start_id]
    start_info = PlanetUtilsAI.sys_name_ids([start_id])
    dest_info = PlanetUtilsAI.sys_name_ids([dest_id])
    path_info = [PlanetUtilsAI.sys_name_ids([sys_id]) for sys_id in path_ids]
    print "Fleet %d requested safe path leg from %s to %s, found path %s" % (fleet_id, ppstring(start_info), ppstring(dest_info), ppstring(path_info))
    return path_ids[0]
def avail_mil_needing_repair(mil_fleet_ids, split_ships=False, on_mission=False):
    """returns tuple of lists-- ( ids_needing_repair, ids_not )"""
    fleet_buckets = [[], []]
    universe = fo.getUniverse()
    cutoff = [0.70, 0.25][on_mission]
    for fleet_id in mil_fleet_ids:
        fleet = universe.getFleet(fleet_id)
        ship_buckets = [[], []]
        ships_cur_health = [0, 0]
        ships_max_health = [0, 0]
        safely_needed = False
        for ship_id in fleet.shipIDs:
            this_ship = universe.getShip(ship_id)
            cur_struc = this_ship.currentMeterValue(fo.meterType.structure)
            max_struc = this_ship.currentMeterValue(fo.meterType.maxStructure)
            ship_ok = cur_struc >= cutoff * max_struc
            ship_buckets[ship_ok].append(ship_id)
            ships_cur_health[ship_ok] += cur_struc
            ships_max_health[ship_ok] += max_struc
        thisSysID = (fleet.nextSystemID != -1 and fleet.nextSystemID) or fleet.systemID
        fleet_ok = sum(ships_cur_health) >= cutoff * sum(ships_max_health)
        local_status = foAI.foAIstate.systemStatus.get(thisSysID, {})
        my_local_rating = local_status.get("mydefenses", {}).get("overall", 0) + local_status.get("myFleetRating", 0)
        needed_here = local_status.get("totalThreat", 0) > 0  # TODO: assess if remaining other forces are sufficient
        safely_needed = needed_here and my_local_rating > local_status.get(
            "totalThreat", 0
        )  # TODO: improve both assessment prongs
        if not fleet_ok:
            if safely_needed:
                print "Fleet %d at %s needs repair but deemed safely needed to remain for defense" % (
                    fleet_id,
                    ppstring(PlanetUtilsAI.sys_name_ids([fleet.systemID])),
                )
            else:
                if needed_here:
                    print "Fleet %d at %s needed present for combat, but is damaged and deemed unsafe to remain." % (
                        fleet_id,
                        ppstring(PlanetUtilsAI.sys_name_ids([fleet.systemID])),
                    )
                    print "\t my_local_rating: %.1f ; threat: %.1f" % (
                        my_local_rating,
                        local_status.get("totalThreat", 0),
                    )
                print "Selecting fleet %d at %s for repair" % (
                    fleet_id,
                    ppstring(PlanetUtilsAI.sys_name_ids([fleet.systemID])),
                )
        fleet_buckets[fleet_ok or safely_needed].append(fleet_id)
    return fleet_buckets
Beispiel #6
0
    def refresh(self):
        """Turn start AIstate cleanup/refresh."""
        universe = fo.getUniverse()
        # checks exploration border & clears roles/missions of missing fleets & updates fleet locs & threats
        fleetsLostBySystem.clear()
        invasionTargets[:] = []
        exploration_center = PlanetUtilsAI.get_capital_sys_id()
        if exploration_center == -1:  # a bad state probably from an old savegame, or else empire has lost (or almost has)
            exploration_center = self.__origin_home_system_id

        # check if planets in cache is still present. Remove destroyed.
        for system_id, info in sorted(self.systemStatus.items()):
            planet_dict = info.get('planets', {})
            cache_planet_set = set(planet_dict)
            system_planet_set = set(universe.getSystem(system_id).planetIDs)
            diff = cache_planet_set - system_planet_set
            if diff:
                print "Removing destroyed planets from systemStatus for system %s: planets to be removed: %s" % (system_id, sorted(diff))
                for key in diff:
                    del planet_dict[key]

        ExplorationAI.graphFlags.clear()
        if fo.currentTurn() < 50:
            print "-------------------------------------------------"
            print "Border Exploration Update (relative to %s)" % (PlanetUtilsAI.sys_name_ids([exploration_center, -1])[0])
            print "-------------------------------------------------"
        if self.visBorderSystemIDs.keys() == [-1]:
            self.visBorderSystemIDs.clear()
            self.visBorderSystemIDs[exploration_center] = 1
        for sys_id in self.visBorderSystemIDs.keys():  # This dict modified during iteration.
            if fo.currentTurn() < 50:
                print "Considering border system %s" % (PlanetUtilsAI.sys_name_ids([sys_id, -1])[0])
            ExplorationAI.follow_vis_system_connections(sys_id, exploration_center)
        newly_explored = ExplorationAI.update_explored_systems()
        nametags = []
        for sys_id in newly_explored:
            newsys = universe.getSystem(sys_id)
            nametags.append("ID:%4d -- %-20s" % (sys_id, (newsys and newsys.name) or "name unknown"))  # an explored system *should* always be able to be gotten
        if newly_explored:
            print "-------------------------------------------------"
            print "Newly explored systems:\n%s" % "\n".join(nametags)
            print "-------------------------------------------------"
        # cleanup fleet roles
        # self.update_fleet_locs()
        self.__clean_fleet_roles()
        self.__clean_fleet_missions(FleetUtilsAI.get_empire_fleet_ids())
        print "Fleets lost by system: %s" % fleetsLostBySystem
        self.update_system_status()
Beispiel #7
0
def avail_mil_needing_repair(mil_fleet_ids, split_ships=False, on_mission=False):
    """returns tuple of lists-- ( ids_needing_repair, ids_not )"""
    fleet_buckets = [[], []]
    universe = fo.getUniverse()
    cutoff = [0.70, 0.25][ on_mission ]
    for fleet_id in mil_fleet_ids:
        fleet = universe.getFleet(fleet_id)
        ship_buckets = [ [], [] ]
        ships_cur_health = [ 0, 0 ]
        ships_max_health = [ 0, 0 ]
        for ship_id in fleet.shipIDs:
            this_ship = universe.getShip(ship_id)
            cur_struc = this_ship.currentMeterValue(fo.meterType.structure)
            max_struc = this_ship.currentMeterValue(fo.meterType.maxStructure)
            ship_ok = cur_struc >= cutoff * max_struc
            ship_buckets[ship_ok].append( ship_id )
            ships_cur_health[ship_ok] += cur_struc
            ships_max_health[ship_ok] += max_struc
        #TODO: the following is a temp all-or-nothing test
        fleet_ok = ( sum(ships_cur_health) >= cutoff * sum(ships_max_health) )
        if not fleet_ok:
            pass
            print "Selecting fleet %d at %s for repair"%(fleet_id, PlanetUtilsAI.sys_name_ids( [fleet.systemID] ))
        fleet_buckets[fleet_ok].append(fleet_id)
    return fleet_buckets
Beispiel #8
0
def get_repair_fleet_order(fleet_target, current_sys_id):
    """ Returns repair AIFleetOrder to [nearest safe] drydock."""
    # find nearest supplied system
    drydock_sys_id = get_nearest_drydock_system_id(current_sys_id)
    drydock_system_target = AITarget.AITarget(AITargetType.TARGET_SYSTEM, drydock_sys_id)
    print "ordering fleet %d to %s for repair" % (fleet_target.target_id, PlanetUtilsAI.sys_name_ids([drydock_sys_id]))
    # create resupply AIFleetOrder
    return AIFleetOrder.AIFleetOrder(AIFleetOrderType.ORDER_REPAIR, fleet_target, drydock_system_target)
Beispiel #9
0
def get_safe_path_leg_to_dest(fleet_id, start_id, dest_id):
    start_targ = universe_object.System(start_id)
    dest_targ = universe_object.System(dest_id)
    #TODO actually get a safe path
    this_path = can_travel_to_system(fleet_id,
                                     start_targ,
                                     dest_targ,
                                     ensure_return=False)
    path_ids = [targ.id
                for targ in this_path if targ.id != start_id] + [start_id]
    start_info = PlanetUtilsAI.sys_name_ids([start_id])
    dest_info = PlanetUtilsAI.sys_name_ids([dest_id])
    path_info = [PlanetUtilsAI.sys_name_ids([sys_id]) for sys_id in path_ids]
    print "Fleet %d requested safe path leg from %s to %s, found path %s" % (
        fleet_id, ppstring(start_info), ppstring(dest_info),
        ppstring(path_info))
    return path_ids[0]
Beispiel #10
0
def get_safe_path_leg_to_dest(fleet_id, start_id, dest_id):
    start_targ = TargetSystem(start_id)
    dest_targ = TargetSystem(dest_id)
    # TODO actually get a safe path
    this_path = can_travel_to_system(fleet_id, start_targ, dest_targ, ensure_return=False)
    path_ids = [targ.id for targ in this_path if targ.id != start_id] + [start_id]
    universe = fo.getUniverse()
    debug("Fleet %d requested safe path leg from %s to %s, found path %s" % (
        fleet_id, universe.getSystem(start_id), universe.getSystem(dest_id), PlanetUtilsAI.sys_name_ids(path_ids)))
    return path_ids[0]
Beispiel #11
0
    def issue_order(self):
        if not super(OrderRepair, self).issue_order():
            return
        fleet_id = self.fleet.id
        system_id = self.target.get_system().id
        fleet = self.fleet.get_object()
        if system_id not in [fleet.systemID, fleet.nextSystemID]:
            fo.issueAggressionOrder(fleet_id, False)
            start_id = FleetUtilsAI.get_fleet_system(fleet)
            dest_id = MoveUtilsAI.get_safe_path_leg_to_dest(fleet_id, start_id, system_id)
            print "fleet %d with order type(%s) sent to safe leg dest %s and ultimate dest %s" % (
                fleet_id, self.ORDER_NAME, PlanetUtilsAI.sys_name_ids([dest_id]),
                PlanetUtilsAI.sys_name_ids([system_id]))
            fo.issueFleetMoveOrder(fleet_id, dest_id)
            print "Order issued: %s fleet: %s target: %s" % (self.ORDER_NAME, self.fleet, self.target)

        if system_id == fleet.systemID:
            if foAI.foAIstate.get_fleet_role(fleet_id) == MissionType.EXPLORATION:
                if system_id in foAI.foAIstate.needsEmergencyExploration:
                    foAI.foAIstate.needsEmergencyExploration.remove(system_id)
            self.order_issued = True
Beispiel #12
0
    def refresh(self):
        """Turn start AIstate cleanup/refresh."""
        universe = fo.getUniverse()
        # checks exploration border & clears roles/missions of missing fleets & updates fleet locs & threats
        fleetsLostBySystem.clear()
        invasionTargets[:] = []
        exploration_center = PlanetUtilsAI.get_capital_sys_id()
        if exploration_center == INVALID_ID:  # a bad state probably from an old savegame, or else empire has lost (or almost has)
            exploration_center = self.__origin_home_system_id

        for system_id, info in sorted(self.systemStatus.items()):
            self.systemStatus[system_id]['enemy_ship_count'] = 0  # clear now in prep for update_system_status()
        ExplorationAI.graph_flags.clear()
        if fo.currentTurn() < 50:
            print "-------------------------------------------------"
            print "Border Exploration Update (relative to %s)" % (PlanetUtilsAI.sys_name_ids([exploration_center, INVALID_ID])[0])
            print "-------------------------------------------------"
        if self.visBorderSystemIDs == {INVALID_ID}:
            self.visBorderSystemIDs.clear()
            self.visBorderSystemIDs.add(exploration_center)
        for sys_id in list(self.visBorderSystemIDs):  # This set is modified during iteration.
            if fo.currentTurn() < 50:
                print "Considering border system %s" % (PlanetUtilsAI.sys_name_ids([sys_id, INVALID_ID])[0])
            ExplorationAI.follow_vis_system_connections(sys_id, exploration_center)
        newly_explored = ExplorationAI.update_explored_systems()
        nametags = []
        for sys_id in newly_explored:
            newsys = universe.getSystem(sys_id)
            nametags.append("ID:%4d -- %-20s" % (sys_id, (newsys and newsys.name) or "name unknown"))  # an explored system *should* always be able to be gotten
        if newly_explored:
            print "-------------------------------------------------"
            print "Newly explored systems:\n%s" % "\n".join(nametags)
            print "-------------------------------------------------"
        # cleanup fleet roles
        # self.update_fleet_locs()
        self.__clean_fleet_roles()
        self.__clean_fleet_missions(FleetUtilsAI.get_empire_fleet_ids())
        print "Fleets lost by system: %s" % fleetsLostBySystem
        self.update_system_status()
Beispiel #13
0
def get_safe_path_leg_to_dest(fleet_id, start_id, dest_id):
    start_targ = TargetSystem(start_id)
    dest_targ = TargetSystem(dest_id)
    # TODO actually get a safe path
    this_path = can_travel_to_system(fleet_id,
                                     start_targ,
                                     dest_targ,
                                     ensure_return=False)
    path_ids = [targ.id
                for targ in this_path if targ.id != start_id] + [start_id]
    universe = fo.getUniverse()
    debug("Fleet %d requested safe path leg from %s to %s, found path %s" %
          (fleet_id, universe.getSystem(start_id), universe.getSystem(dest_id),
           PlanetUtilsAI.sys_name_ids(path_ids)))
    return path_ids[0]
Beispiel #14
0
def get_repair_fleet_order(fleet_target, current_sys_id):
    """
    Return fleet_orders.OrderRepair for fleet to proceed system with drydock.

    :param fleet_target: fleet that need to be repaired
    :type fleet_target: universe_object.Fleet
    # TODO check if we can remove this id, because fleet already have it.
    :param current_sys_id: current system id
    :type current_sys_id: int
    :return: order to repair
    :rtype fleet_orders.OrderRepair
    """
    # find nearest supplied system
    drydock_sys_id = get_nearest_drydock_system_id(current_sys_id)
    print "ordering fleet %d to %s for repair" % (fleet_target.id, ppstring(PlanetUtilsAI.sys_name_ids([drydock_sys_id])))
    # create resupply AIFleetOrder
    return fleet_orders.OrderRepair(fleet_target, universe_object.System(drydock_sys_id))
Beispiel #15
0
def get_repair_fleet_order(fleet, current_system_id):
    """Return fleet_orders.OrderRepair for fleet to proceed to system with drydock.

    :param fleet: fleet that need to be repaired
    :type fleet: universe_object.Fleet
    # TODO check if we can remove this id, because fleet already have it.
    :param current_system_id: current location of the fleet, next system if currently on starlane.
    :type current_system_id: int
    :return: order to repair
    :rtype fleet_orders.OrderRepair
    """
    # TODO Cover new mechanics where happiness increases repair rate - don't always use nearest system!
    # find nearest drydock system
    drydock_sys_id = get_best_drydock_system_id(current_system_id, fleet.id)
    if drydock_sys_id is None:
        return None

    print "Ordering fleet %s to %s for repair" % (fleet, ppstring(PlanetUtilsAI.sys_name_ids([drydock_sys_id])))
    return fleet_orders.OrderRepair(fleet, universe_object.System(drydock_sys_id))
Beispiel #16
0
def get_repair_fleet_order(fleet_target, current_sys_id):
    """
    Return fleet_orders.OrderRepair for fleet to proceed system with drydock.

    :param fleet_target: fleet that need to be repaired
    :type fleet_target: universe_object.Fleet
    # TODO check if we can remove this id, because fleet already have it.
    :param current_sys_id: current system id
    :type current_sys_id: int
    :return: order to repair
    :rtype fleet_orders.OrderRepair
    """
    # TODO Cover new mechanics where happiness increases repair rate - don't always use nearest system!
    # find nearest supplied system
    drydock_sys_id = get_best_drydock_system_id(current_sys_id, fleet_target.id)
    if drydock_sys_id is None:
        return None
    print "ordering fleet %d to %s for repair" % (fleet_target.id, ppstring(PlanetUtilsAI.sys_name_ids([drydock_sys_id])))
    # create resupply AIFleetOrder
    return fleet_orders.OrderRepair(fleet_target, universe_object.System(drydock_sys_id))
Beispiel #17
0
    def refresh(self):
        """Turn start AIstate cleanup/refresh."""
        universe = fo.getUniverse()
        # checks exploration border & clears roles/missions of missing fleets & updates fleet locs & threats
        fleetsLostBySystem.clear()
        invasionTargets[:] = []
        exploration_center = PlanetUtilsAI.get_capital_sys_id()
        if exploration_center == INVALID_ID:  # a bad state probably from an old savegame, or else empire has lost (or almost has)
            exploration_center = self.__origin_home_system_id

        # check if planets in cache is still present. Remove destroyed.
        for system_id, info in sorted(self.systemStatus.items()):
            self.systemStatus[system_id][
                'enemy_ship_count'] = 0  # clear now in prep for update_system_status()
            planet_dict = info.get('planets', {})
            cache_planet_set = set(planet_dict)
            system_planet_set = set(
                *(sys.planetIDs for sys in [universe.getSystem(system_id)]
                  if sys))
            diff = cache_planet_set - system_planet_set
            if diff:
                print "Removing destroyed planets from systemStatus for system %s: planets to be removed: %s" % (
                    system_id, sorted(diff))
                for key in diff:
                    del planet_dict[key]

        ExplorationAI.graphFlags.clear()
        if fo.currentTurn() < 50:
            print "-------------------------------------------------"
            print "Border Exploration Update (relative to %s)" % (
                PlanetUtilsAI.sys_name_ids([exploration_center, INVALID_ID
                                            ])[0])
            print "-------------------------------------------------"
        if self.visBorderSystemIDs.keys() == [INVALID_ID]:
            self.visBorderSystemIDs.clear()
            self.visBorderSystemIDs[exploration_center] = 1
        for sys_id in self.visBorderSystemIDs.keys(
        ):  # This dict modified during iteration.
            if fo.currentTurn() < 50:
                print "Considering border system %s" % (
                    PlanetUtilsAI.sys_name_ids([sys_id, INVALID_ID])[0])
            ExplorationAI.follow_vis_system_connections(
                sys_id, exploration_center)
        newly_explored = ExplorationAI.update_explored_systems()
        nametags = []
        for sys_id in newly_explored:
            newsys = universe.getSystem(sys_id)
            nametags.append(
                "ID:%4d -- %-20s" %
                (sys_id, (newsys and newsys.name) or "name unknown")
            )  # an explored system *should* always be able to be gotten
        if newly_explored:
            print "-------------------------------------------------"
            print "Newly explored systems:\n%s" % "\n".join(nametags)
            print "-------------------------------------------------"
        # cleanup fleet roles
        # self.update_fleet_locs()
        self.__clean_fleet_roles()
        self.__clean_fleet_missions(FleetUtilsAI.get_empire_fleet_ids())
        print "Fleets lost by system: %s" % fleetsLostBySystem
        self.update_system_status()
Beispiel #18
0
def get_invasion_fleets():
    invasion_timer.start("gathering initial info")
    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empire_id = empire.empireID

    all_invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(
        MissionType.INVASION)
    AIstate.invasionFleetIDs = FleetUtilsAI.extract_fleet_ids_without_mission_types(
        all_invasion_fleet_ids)

    home_system_id = PlanetUtilsAI.get_capital_sys_id()
    visible_system_ids = foAI.foAIstate.visInteriorSystemIDs.keys(
    ) + foAI.foAIstate.visBorderSystemIDs.keys()

    if home_system_id != -1:
        accessible_system_ids = [
            sys_id for sys_id in visible_system_ids if (sys_id != -1)
            and universe.systemsConnected(sys_id, home_system_id, empire_id)
        ]
    else:
        print "Warning: Empire has no identifiable homeworld; will treat all visible planets as accessible."
        accessible_system_ids = visible_system_ids  # TODO: check if any troop ships owned, use their system as home system

    acessible_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(
        accessible_system_ids)
    all_owned_planet_ids = PlanetUtilsAI.get_all_owned_planet_ids(
        acessible_planet_ids)  # includes unpopulated outposts
    all_populated_planets = PlanetUtilsAI.get_populated_planet_ids(
        acessible_planet_ids)  # includes unowned natives
    empire_owned_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(
        universe.planetIDs)
    invadable_planet_ids = set(all_owned_planet_ids).union(
        all_populated_planets) - set(empire_owned_planet_ids)

    invasion_targeted_planet_ids = get_invasion_targeted_planet_ids(
        universe.planetIDs, MissionType.INVASION)
    invasion_targeted_planet_ids.extend(
        get_invasion_targeted_planet_ids(universe.planetIDs,
                                         MissionType.ORBITAL_INVASION))
    all_invasion_targeted_system_ids = set(
        PlanetUtilsAI.get_systems(invasion_targeted_planet_ids))

    invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(
        MissionType.INVASION)
    num_invasion_fleets = len(
        FleetUtilsAI.extract_fleet_ids_without_mission_types(
            invasion_fleet_ids))

    print "Current Invasion Targeted SystemIDs: ", PlanetUtilsAI.sys_name_ids(
        AIstate.invasionTargetedSystemIDs)
    print "Current Invasion Targeted PlanetIDs: ", PlanetUtilsAI.planet_name_ids(
        invasion_targeted_planet_ids)
    print invasion_fleet_ids and "Invasion Fleet IDs: %s" % invasion_fleet_ids or "Available Invasion Fleets: 0"
    print "Invasion Fleets Without Missions: %s" % num_invasion_fleets

    invasion_timer.start("planning troop base production")
    # only do base invasions if aggression is typical or above
    reserved_troop_base_targets = []
    if foAI.foAIstate.aggression > fo.aggression.typical:
        available_pp = {}
        for el in empire.planetsWithAvailablePP:  # keys are sets of ints; data is doubles
            avail_pp = el.data()
            for pid in el.key():
                available_pp[pid] = avail_pp
        for pid in invadable_planet_ids:  # TODO: reorganize
            planet = universe.getPlanet(pid)
            if not planet:
                continue
            sys_id = planet.systemID
            sys_partial_vis_turn = universe.getVisibilityTurnsMap(
                planet.systemID, empire_id).get(fo.visibility.partial, -9999)
            planet_partial_vis_turn = universe.getVisibilityTurnsMap(
                pid, empire_id).get(fo.visibility.partial, -9999)
            if planet_partial_vis_turn < sys_partial_vis_turn:
                continue
            for pid2 in state.get_empire_inhabited_planets_by_system().get(
                    sys_id, []):
                if available_pp.get(
                        pid2, 0
                ) < 2:  # TODO: improve troop base PP sufficiency determination
                    break
                planet2 = universe.getPlanet(pid2)
                if not planet2:
                    continue
                if pid not in foAI.foAIstate.qualifyingTroopBaseTargets and planet2.speciesName in ColonisationAI.empire_ship_builders:
                    foAI.foAIstate.qualifyingTroopBaseTargets.setdefault(
                        pid, [pid2, -1])
                    break

        for pid in list(foAI.foAIstate.qualifyingTroopBaseTargets):
            planet = universe.getPlanet(
                pid
            )  # TODO: also check that still have a colony in this system that can make troops
            if planet and planet.owner == empire_id:
                del foAI.foAIstate.qualifyingTroopBaseTargets[pid]

        secure_ai_fleet_missions = foAI.foAIstate.get_fleet_missions_with_any_mission_types(
            [MissionType.SECURE])
        for pid in (set(foAI.foAIstate.qualifyingTroopBaseTargets.keys()) -
                    set(invasion_targeted_planet_ids)
                    ):  # TODO: consider overriding standard invasion mission
            planet = universe.getPlanet(pid)
            if foAI.foAIstate.qualifyingTroopBaseTargets[pid][1] != -1:
                reserved_troop_base_targets.append(pid)
                if planet:
                    all_invasion_targeted_system_ids.add(planet.systemID)
                continue  # already building for here
            sys_id = planet.systemID
            this_sys_status = foAI.foAIstate.systemStatus.get(sys_id, {})
            if (planet.currentMeterValue(fo.meterType.shield) > 0
                    and this_sys_status.get('myFleetRating', 0) <
                    0.8 * this_sys_status.get('totalThreat', 0)):
                continue
            loc = foAI.foAIstate.qualifyingTroopBaseTargets[pid][0]
            best_base_trooper_here = ProductionAI.get_best_ship_info(
                PriorityType.PRODUCTION_ORBITAL_INVASION, loc)[1]
            loc_planet = universe.getPlanet(loc)
            if best_base_trooper_here is None:  # shouldn't be possible at this point, but just to be safe
                print "Could not find a suitable orbital invasion design at %s" % loc_planet
                continue
            # TODO: have TroopShipDesigner give the expected number of troops including species effects directly
            troops_per_ship = best_base_trooper_here.troopCapacity
            _, _, species_troop_grade = foAI.foAIstate.get_piloting_grades(
                loc_planet.speciesName)
            troops_per_ship = foAI.foAIstate.weight_attack_troops(
                troops_per_ship, species_troop_grade)
            if not troops_per_ship:
                print "The best orbital invasion design at %s seems not to have any troop capacity." % loc_planet
                continue
            this_score, p_troops = evaluate_invasion_planet(
                pid, empire, secure_ai_fleet_missions, False)
            _, col_design, build_choices = ProductionAI.get_best_ship_info(
                PriorityType.PRODUCTION_ORBITAL_INVASION, loc)
            if not col_design:
                continue
            if loc not in build_choices:
                sys.stderr.write(
                    'Best troop design %s can not be produces in at planet with id: %s\d'
                    % (col_design, build_choices))
            n_bases = math.ceil(
                (p_troops + 1) /
                troops_per_ship)  # TODO: reconsider this +1 safety factor
            print "Invasion base planning, need %d troops at %d pership, will build %d ships." % (
                (p_troops + 1), troops_per_ship, n_bases)
            retval = fo.issueEnqueueShipProductionOrder(col_design.id, loc)
            print "Enqueueing %d Troop Bases at %s for %s" % (
                n_bases, PlanetUtilsAI.planet_name_ids(
                    [loc]), PlanetUtilsAI.planet_name_ids([pid]))
            if retval != 0:
                all_invasion_targeted_system_ids.add(planet.systemID)
                reserved_troop_base_targets.append(pid)
                foAI.foAIstate.qualifyingTroopBaseTargets[pid][1] = loc
                fo.issueChangeProductionQuantityOrder(
                    empire.productionQueue.size - 1, 1, int(n_bases))
                fo.issueRequeueProductionOrder(empire.productionQueue.size - 1,
                                               0)

    invasion_timer.start("evaluating target planets")
    # TODO: check if any invasion_targeted_planet_ids need more troops assigned
    evaluated_planet_ids = list(
        set(invadable_planet_ids) - set(invasion_targeted_planet_ids) -
        set(reserved_troop_base_targets))
    evaluated_planets = assign_invasion_values(evaluated_planet_ids, empire)

    sorted_planets = [(pid, pscore % 10000, ptroops)
                      for pid, (pscore, ptroops) in evaluated_planets.items()]
    sorted_planets.sort(key=lambda x: x[1], reverse=True)
    sorted_planets = [(pid, pscore % 10000, ptroops)
                      for pid, pscore, ptroops in sorted_planets]

    invasion_table = Table(
        [Text('Planet'),
         Float('Score'),
         Text('Species'),
         Float('Troops')],
        table_name="Potential Targets for Invasion Turn %d" % fo.currentTurn())

    for pid, pscore, ptroops in sorted_planets:
        planet = universe.getPlanet(pid)
        invasion_table.add_row([
            planet, pscore, planet and planet.speciesName or "unknown", ptroops
        ])
    print
    invasion_table.print_table()

    sorted_planets = filter(lambda x: x[1] > 0, sorted_planets)
    # export opponent planets for other AI modules
    AIstate.opponentPlanetIDs = [pid for pid, _, _ in sorted_planets]
    AIstate.invasionTargets = sorted_planets

    # export invasion targeted systems for other AI modules
    AIstate.invasionTargetedSystemIDs = list(all_invasion_targeted_system_ids)
    invasion_timer.stop(section_name="evaluating %d target planets" %
                        (len(evaluated_planet_ids)))
    invasion_timer.end()
Beispiel #19
0
def get_invasion_fleets():
    invasion_timer.start("gathering initial info")

    all_invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION)
    AIstate.invasionFleetIDs = FleetUtilsAI.extract_fleet_ids_without_mission_types(all_invasion_fleet_ids)

    # get suppliable planets
    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empire_id = empire.empireID
    capital_id = PlanetUtilsAI.get_capital()
    homeworld=None
    if capital_id:
        homeworld = universe.getPlanet(capital_id)
    if homeworld:
        home_system_id = homeworld.systemID
    else:
        home_system_id = -1

    fleet_suppliable_system_ids = empire.fleetSupplyableSystemIDs
    fleet_suppliable_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(fleet_suppliable_system_ids)

    prime_invadable_system_ids = set(ColonisationAI.annexable_system_ids)
    prime_invadable_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(prime_invadable_system_ids)

    visible_system_ids = foAI.foAIstate.visInteriorSystemIDs.keys() + foAI.foAIstate. visBorderSystemIDs.keys()

    if home_system_id != -1:
        accessible_system_ids = [sys_id for sys_id in visible_system_ids if (sys_id != -1) and universe.systemsConnected(sys_id, home_system_id, empire_id)]
    else:
        print "Invasion Warning: this empire has no identifiable homeworld, will therefor treat all visible planets as accessible."
        accessible_system_ids = visible_system_ids  # TODO: check if any troop ships still owned, use their system as home system
    acessible_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(accessible_system_ids)
    print "Accessible Systems: ", ", ".join(PlanetUtilsAI.sys_name_ids(accessible_system_ids))
    print

    all_owned_planet_ids = PlanetUtilsAI.get_all_owned_planet_ids(acessible_planet_ids)  # need these for unpopulated outposts
    all_populated_planets = PlanetUtilsAI.get_populated_planet_ids(acessible_planet_ids)  # need this for natives
    print "All Visible and accessible Populated PlanetIDs (including this empire's): ", ", ".join(PlanetUtilsAI.planet_name_ids(all_populated_planets))
    print
    print "Prime Invadable Target Systems: ", ", ".join(PlanetUtilsAI.sys_name_ids(prime_invadable_system_ids))
    print

    empire_owned_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs)

    invadable_planet_ids = set(prime_invadable_planet_ids).intersection(set(all_owned_planet_ids).union(all_populated_planets) - set(empire_owned_planet_ids))
    print "Prime Invadable PlanetIDs: ", ", ".join(PlanetUtilsAI.planet_name_ids(invadable_planet_ids))

    print
    print "Current Invasion Targeted SystemIDs: ", ", ".join(PlanetUtilsAI.sys_name_ids(AIstate.invasionTargetedSystemIDs))
    invasion_targeted_planet_ids = get_invasion_targeted_planet_ids(universe.planetIDs, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION)
    invasion_targeted_planet_ids.extend(get_invasion_targeted_planet_ids(universe.planetIDs, EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION))
    all_invasion_targeted_system_ids = set(PlanetUtilsAI.get_systems(invasion_targeted_planet_ids))

    print "Current Invasion Targeted PlanetIDs: ", ", ".join(PlanetUtilsAI.planet_name_ids(invasion_targeted_planet_ids))

    invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION)
    if not invasion_fleet_ids:
        print "Available Invasion Fleets: 0"
    else:
        print "Invasion FleetIDs: %s" % FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION)

    num_invasion_fleets = len(FleetUtilsAI.extract_fleet_ids_without_mission_types(invasion_fleet_ids))
    print "Invasion Fleets Without Missions:    %s" % num_invasion_fleets
    
    invasion_timer.start("planning troop base production")
    # only do base invasions if aggression is typical or above
    reserved_troop_base_targets = []
    if foAI.foAIstate.aggression > fo.aggression.typical:
        available_pp = {}
        for el in empire.planetsWithAvailablePP:  # keys are sets of ints; data is doubles
            avail_pp = el.data()
            for pid in el.key():
                available_pp[pid] = avail_pp
        for pid in invadable_planet_ids:  # TODO: reorganize
            planet = universe.getPlanet(pid)
            if not planet: 
                continue
            sys_id = planet.systemID
            sys_partial_vis_turn = universe.getVisibilityTurnsMap(planet.systemID, empire_id).get(fo.visibility.partial, -9999)
            planet_partial_vis_turn = universe.getVisibilityTurnsMap(pid, empire_id).get(fo.visibility.partial, -9999)
            if planet_partial_vis_turn < sys_partial_vis_turn:
                continue
            for pid2 in ColonisationAI.empire_species_systems.get(sys_id,  {}).get('pids', []):
                if available_pp.get(pid2,  0) < 2:  # TODO: improve troop base PP sufficiency determination
                    break
                planet2 = universe.getPlanet(pid2)
                if not planet2: 
                    continue
                if pid not in foAI.foAIstate.qualifyingTroopBaseTargets and planet2.speciesName in ColonisationAI.empire_ship_builders:
                    foAI.foAIstate.qualifyingTroopBaseTargets.setdefault(pid,  [pid2,  -1])
                    break

        for pid in list(foAI.foAIstate.qualifyingTroopBaseTargets):
            planet = universe.getPlanet(pid)  # TODO: also check that still have a colony in this system that can make troops
            if planet and planet.owner == empire_id:
                del foAI.foAIstate.qualifyingTroopBaseTargets[pid]

        secure_ai_fleet_missions = foAI.foAIstate.get_fleet_missions_with_any_mission_types([EnumsAI.AIFleetMissionType.FLEET_MISSION_SECURE])
        for pid in (set(foAI.foAIstate.qualifyingTroopBaseTargets.keys()) - set(invasion_targeted_planet_ids)):  # TODO: consider overriding standard invasion mission
            planet = universe.getPlanet(pid)
            if foAI.foAIstate.qualifyingTroopBaseTargets[pid][1] != -1:
                reserved_troop_base_targets.append(pid)
                if planet:
                    all_invasion_targeted_system_ids.add(planet.systemID)
                continue  # already building for here
            sys_id = planet.systemID
            this_sys_status = foAI.foAIstate.systemStatus.get(sys_id,  {})
            if (planet.currentMeterValue(fo.meterType.shield) > 0 and
                    this_sys_status.get('myFleetRating', 0) < 0.8 * this_sys_status.get('totalThreat', 0)):
                continue
            loc = foAI.foAIstate.qualifyingTroopBaseTargets[pid][0]
            this_score,  p_troops = evaluate_invasion_planet(pid, empire, secure_ai_fleet_missions, False)
            best_ship, col_design, build_choices = ProductionAI.getBestShipInfo(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_ORBITAL_INVASION, loc)
            if not best_ship:
                continue
            n_bases = math.ceil((p_troops+1) / 2)  # TODO: reconsider this +1 safety factor
            retval = fo.issueEnqueueShipProductionOrder(best_ship, loc)
            print "Enqueueing %d Troop Bases at %s for %s" % (n_bases, PlanetUtilsAI.planet_name_ids([loc]), PlanetUtilsAI.planet_name_ids([pid]))
            if retval != 0:
                all_invasion_targeted_system_ids.add(planet.systemID)
                reserved_troop_base_targets.append(pid)
                foAI.foAIstate.qualifyingTroopBaseTargets[pid][1] = loc
                fo.issueChangeProductionQuantityOrder(empire.productionQueue.size - 1, 1, int(n_bases))
                fo.issueRequeueProductionOrder(empire.productionQueue.size - 1, 0)

    invasion_timer.start("evaluating target planets")
    # TODO: check if any invasion_targeted_planet_ids need more troops assigned
    evaluated_planet_ids = list(set(invadable_planet_ids) - set(invasion_targeted_planet_ids) - set(reserved_troop_base_targets))
    print "Evaluating potential invasions, PlanetIDs: %s" % evaluated_planet_ids

    evaluated_planets = assign_invasion_values(evaluated_planet_ids, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, fleet_suppliable_planet_ids, empire)

    sorted_planets = [(pid, pscore % 10000, ptroops) for pid, (pscore, ptroops) in evaluated_planets.items()]
    sorted_planets.sort(key=lambda x: x[1], reverse=True)
    sorted_planets = [(pid, pscore % 10000, ptroops) for pid, pscore, ptroops in sorted_planets]

    print
    if sorted_planets:
        print "Invadable planets:\n%-6s | %-6s | %-16s | %-16s | Troops" % ('ID', 'Score', 'Name', 'Race')
        for pid, pscore, ptroops in sorted_planets:
            planet = universe.getPlanet(pid)
            if planet:
                print "%6d | %6d | %16s | %16s | %d" % (pid, pscore, planet.name, planet.speciesName, ptroops)
            else:
                print "%6d | %6d | Error: invalid planet ID" % (pid, pscore)
    else:
        print "No Invadable planets identified"

    sorted_planets = filter(lambda x: x[1] > 0, sorted_planets)
    # export opponent planets for other AI modules
    AIstate.opponentPlanetIDs = [pid for pid, _, _ in sorted_planets]
    AIstate.invasionTargets = sorted_planets

    # export invasion targeted systems for other AI modules
    AIstate.invasionTargetedSystemIDs = list(all_invasion_targeted_system_ids)
    invasion_timer.stop(section_name="evaluating %d target planets" % (len(evaluated_planet_ids)))
    invasion_timer.end()
Beispiel #20
0
def get_invasion_fleets():
    invasion_timer.start("gathering initial info")

    all_invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION)
    AIstate.invasionFleetIDs = FleetUtilsAI.extract_fleet_ids_without_mission_types(all_invasion_fleet_ids)

    # get suppliable planets
    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empire_id = empire.empireID
    capital_id = PlanetUtilsAI.get_capital()
    homeworld=None
    if capital_id:
        homeworld = universe.getPlanet(capital_id)
    if homeworld:
        home_system_id = homeworld.systemID
    else:
        home_system_id = -1

    fleet_suppliable_system_ids = empire.fleetSupplyableSystemIDs
    fleet_suppliable_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(fleet_suppliable_system_ids)

    prime_invadable_system_ids = set(ColonisationAI.annexable_system_ids)
    prime_invadable_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(prime_invadable_system_ids)

    visible_system_ids = foAI.foAIstate.visInteriorSystemIDs.keys() + foAI.foAIstate. visBorderSystemIDs.keys()

    if home_system_id != -1:
        accessible_system_ids = [sys_id for sys_id in visible_system_ids if (sys_id != -1) and universe.systemsConnected(sys_id, home_system_id, empire_id)]
    else:
        print "Invasion Warning: this empire has no identifiable homeworld, will therefor treat all visible planets as accessible."
        accessible_system_ids = visible_system_ids  # TODO: check if any troop ships still owned, use their system as home system
    acessible_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(accessible_system_ids)
    print "Accessible Systems: ", ", ".join(PlanetUtilsAI.sys_name_ids(accessible_system_ids))
    print

    all_owned_planet_ids = PlanetUtilsAI.get_all_owned_planet_ids(acessible_planet_ids)  # need these for unpopulated outposts
    all_populated_planets = PlanetUtilsAI.get_populated_planet_ids(acessible_planet_ids)  # need this for natives
    print "All Visible and accessible Populated PlanetIDs (including this empire's): ", ", ".join(PlanetUtilsAI.planet_name_ids(all_populated_planets))
    print
    print "Prime Invadable Target Systems: ", ", ".join(PlanetUtilsAI.sys_name_ids(prime_invadable_system_ids))
    print

    empire_owned_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs)

    invadable_planet_ids = set(prime_invadable_planet_ids).intersection(set(all_owned_planet_ids).union(all_populated_planets) - set(empire_owned_planet_ids))
    print "Prime Invadable PlanetIDs: ", ", ".join(PlanetUtilsAI.planet_name_ids(invadable_planet_ids))

    print
    print "Current Invasion Targeted SystemIDs: ", ", ".join(PlanetUtilsAI.sys_name_ids(AIstate.invasionTargetedSystemIDs))
    invasion_targeted_planet_ids = get_invasion_targeted_planet_ids(universe.planetIDs, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION)
    invasion_targeted_planet_ids.extend(get_invasion_targeted_planet_ids(universe.planetIDs, EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION))
    all_invasion_targeted_system_ids = set(PlanetUtilsAI.get_systems(invasion_targeted_planet_ids))

    print "Current Invasion Targeted PlanetIDs: ", ", ".join(PlanetUtilsAI.planet_name_ids(invasion_targeted_planet_ids))

    invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION)
    if not invasion_fleet_ids:
        print "Available Invasion Fleets: 0"
    else:
        print "Invasion FleetIDs: %s" % FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION)

    num_invasion_fleets = len(FleetUtilsAI.extract_fleet_ids_without_mission_types(invasion_fleet_ids))
    print "Invasion Fleets Without Missions:    %s" % num_invasion_fleets
    
    invasion_timer.start("planning troop base production")
    # only do base invasions if aggression is typical or above
    reserved_troop_base_targets = []
    if foAI.foAIstate.aggression > fo.aggression.typical:
        available_pp = {}
        for el in empire.planetsWithAvailablePP:  # keys are sets of ints; data is doubles
            avail_pp = el.data()
            for pid in el.key():
                available_pp[pid] = avail_pp
        for pid in invadable_planet_ids:  # TODO: reorganize
            planet = universe.getPlanet(pid)
            if not planet: 
                continue
            sys_id = planet.systemID
            sys_partial_vis_turn = universe.getVisibilityTurnsMap(planet.systemID, empire_id).get(fo.visibility.partial, -9999)
            planet_partial_vis_turn = universe.getVisibilityTurnsMap(pid, empire_id).get(fo.visibility.partial, -9999)
            if planet_partial_vis_turn < sys_partial_vis_turn:
                continue
            for pid2 in ColonisationAI.empire_species_systems.get(sys_id,  {}).get('pids', []):
                if available_pp.get(pid2,  0) < 2:  # TODO: improve troop base PP sufficiency determination
                    break
                planet2 = universe.getPlanet(pid2)
                if not planet2: 
                    continue
                if pid not in foAI.foAIstate.qualifyingTroopBaseTargets and planet2.speciesName in ColonisationAI.empire_ship_builders:
                    foAI.foAIstate.qualifyingTroopBaseTargets.setdefault(pid,  [pid2,  -1])
                    break

        for pid in list(foAI.foAIstate.qualifyingTroopBaseTargets):
            planet = universe.getPlanet(pid)  # TODO: also check that still have a colony in this system that can make troops
            if planet and planet.owner == empire_id:
                del foAI.foAIstate.qualifyingTroopBaseTargets[pid]

        secure_ai_fleet_missions = foAI.foAIstate.get_fleet_missions_with_any_mission_types([EnumsAI.AIFleetMissionType.FLEET_MISSION_SECURE])
        for pid in (set(foAI.foAIstate.qualifyingTroopBaseTargets.keys()) - set(invasion_targeted_planet_ids)):  # TODO: consider overriding standard invasion mission
            planet = universe.getPlanet(pid)
            if foAI.foAIstate.qualifyingTroopBaseTargets[pid][1] != -1:
                reserved_troop_base_targets.append(pid)
                if planet:
                    all_invasion_targeted_system_ids.add(planet.systemID)
                continue  # already building for here
            sys_id = planet.systemID
            this_sys_status = foAI.foAIstate.systemStatus.get(sys_id,  {})
            if (planet.currentMeterValue(fo.meterType.shield) > 0 and
                    this_sys_status.get('myFleetRating', 0) < 0.8 * this_sys_status.get('totalThreat', 0)):
                continue
            loc = foAI.foAIstate.qualifyingTroopBaseTargets[pid][0]
            best_base_trooper_here = ProductionAI.getBestShipInfo(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_ORBITAL_INVASION, loc)[1]
            if best_base_trooper_here == None:  # shouldn't be possible at this point, but just to be safe
                continue
            # TODO: have TroopShipDesigner give the expected number of troops including species effects
            troops_per_ship = best_base_trooper_here.troopCapacity
            if not troops_per_ship:
                continue
            this_score,  p_troops = evaluate_invasion_planet(pid, empire, secure_ai_fleet_missions, False)
            best_ship, col_design, build_choices = ProductionAI.getBestShipInfo(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_ORBITAL_INVASION, loc)
            if not best_ship:
                continue
            n_bases = math.ceil((p_troops+1) / troops_per_ship)  # TODO: reconsider this +1 safety factor
            print "Invasion base planning, need %d troops at %d pership, will build %d ships." % ((p_troops+1), troops_per_ship, n_bases)
            retval = fo.issueEnqueueShipProductionOrder(best_ship, loc)
            print "Enqueueing %d Troop Bases at %s for %s" % (n_bases, PlanetUtilsAI.planet_name_ids([loc]), PlanetUtilsAI.planet_name_ids([pid]))
            if retval != 0:
                all_invasion_targeted_system_ids.add(planet.systemID)
                reserved_troop_base_targets.append(pid)
                foAI.foAIstate.qualifyingTroopBaseTargets[pid][1] = loc
                fo.issueChangeProductionQuantityOrder(empire.productionQueue.size - 1, 1, int(n_bases))
                fo.issueRequeueProductionOrder(empire.productionQueue.size - 1, 0)

    invasion_timer.start("evaluating target planets")
    # TODO: check if any invasion_targeted_planet_ids need more troops assigned
    evaluated_planet_ids = list(set(invadable_planet_ids) - set(invasion_targeted_planet_ids) - set(reserved_troop_base_targets))
    print "Evaluating potential invasions, PlanetIDs: %s" % evaluated_planet_ids

    evaluated_planets = assign_invasion_values(evaluated_planet_ids, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, fleet_suppliable_planet_ids, empire)

    sorted_planets = [(pid, pscore % 10000, ptroops) for pid, (pscore, ptroops) in evaluated_planets.items()]
    sorted_planets.sort(key=lambda x: x[1], reverse=True)
    sorted_planets = [(pid, pscore % 10000, ptroops) for pid, pscore, ptroops in sorted_planets]

    print
    if sorted_planets:
        print "Invadable planets:\n%-6s | %-6s | %-16s | %-16s | Troops" % ('ID', 'Score', 'Name', 'Race')
        for pid, pscore, ptroops in sorted_planets:
            planet = universe.getPlanet(pid)
            if planet:
                print "%6d | %6d | %16s | %16s | %d" % (pid, pscore, planet.name, planet.speciesName, ptroops)
            else:
                print "%6d | %6d | Error: invalid planet ID" % (pid, pscore)
    else:
        print "No Invadable planets identified"

    sorted_planets = filter(lambda x: x[1] > 0, sorted_planets)
    # export opponent planets for other AI modules
    AIstate.opponentPlanetIDs = [pid for pid, _, _ in sorted_planets]
    AIstate.invasionTargets = sorted_planets

    # export invasion targeted systems for other AI modules
    AIstate.invasionTargetedSystemIDs = list(all_invasion_targeted_system_ids)
    invasion_timer.stop(section_name="evaluating %d target planets" % (len(evaluated_planet_ids)))
    invasion_timer.end()
Beispiel #21
0
def _info_string(path_info):
    return "dist %.1f, path %s" % (path_info.distance,
                                   PlanetUtilsAI.sys_name_ids(path_info.path))
Beispiel #22
0
def get_invasion_fleets():
    """get invasion fleets"""
    invasion_timer.start("gathering initial info")

    all_invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION)
    AIstate.invasionFleetIDs = FleetUtilsAI.extract_fleet_ids_without_mission_types(all_invasion_fleet_ids)

    # get supplyable planets
    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empire_id = empire.empireID
    capital_id = PlanetUtilsAI.get_capital()
    homeworld=None
    if capital_id:
        homeworld = universe.getPlanet(capital_id)
    if homeworld:
        home_system_id = homeworld.systemID
    else:
        home_system_id = -1

    fleet_supplyable_system_ids = empire.fleetSupplyableSystemIDs
    fleet_supplyable_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(fleet_supplyable_system_ids)

    prime_invadable_system_ids = set(ColonisationAI.annexableSystemIDs)
    prime_invadable_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(prime_invadable_system_ids)

    visible_system_ids = foAI.foAIstate.visInteriorSystemIDs.keys() + foAI.foAIstate. visBorderSystemIDs.keys()

    if home_system_id != -1:
        accessible_system_ids = [sys_id for sys_id in visible_system_ids if (sys_id != -1 ) and universe.systemsConnected(sys_id, home_system_id, empire_id) ]
    else:
        print "Invasion Warning: this empire has no identifiable homeworld, will therefor treat all visible planets as accessible."
        accessible_system_ids = visible_system_ids #TODO: check if any troop ships still owned, use their system as home system
    acessible_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(accessible_system_ids)
    print "Accessible Systems: ", ", ".join(PlanetUtilsAI.sys_name_ids(accessible_system_ids))
    print

    #all_owned_planet_ids = PlanetUtilsAI.get_all_owned_planet_ids(exploredPlanetIDs)
    all_owned_planet_ids = PlanetUtilsAI.get_all_owned_planet_ids(acessible_planet_ids)#need these for unpopulated outposts
    # print "All Owned and Populated PlanetIDs: " + str(all_owned_planet_ids)

    all_populated_planets = PlanetUtilsAI.get_populated_planet_ids(acessible_planet_ids)#need this for natives
    print "All Visible and accessible Populated PlanetIDs (including this empire's): ", ", ".join(PlanetUtilsAI.planet_name_ids(all_populated_planets ))
    print
    print "Prime Invadable Target Systems: ", ", ".join(PlanetUtilsAI.sys_name_ids(prime_invadable_system_ids))
    print

    empire_owned_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs)
    # print "Empire Owned PlanetIDs: " + str(empire_owned_planet_ids)

    invadable_planet_ids = set(prime_invadable_planet_ids).intersection(set(all_owned_planet_ids).union(all_populated_planets ) - set(empire_owned_planet_ids))
    print "Prime Invadable PlanetIDs: ", ", ".join(PlanetUtilsAI.planet_name_ids(invadable_planet_ids))

    print
    print "Current Invasion Targeted SystemIDs: ", ", ".join(PlanetUtilsAI.sys_name_ids(AIstate.invasionTargetedSystemIDs))
    invasion_targeted_planet_ids = get_invasion_targeted_planet_ids(universe.planetIDs, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, empire_id)
    invasion_targeted_planet_ids.extend( get_invasion_targeted_planet_ids(universe.planetIDs, EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION, empire_id))
    all_invasion_targeted_system_ids = set(PlanetUtilsAI.get_systems(invasion_targeted_planet_ids))

    print "Current Invasion Targeted PlanetIDs: ", ", ".join(PlanetUtilsAI.planet_name_ids(invasion_targeted_planet_ids))

    invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION)
    if not invasion_fleet_ids:
        print "Available Invasion Fleets: 0"
    else:
        print "Invasion FleetIDs: " + str(FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION))

    num_invasion_fleets = len(FleetUtilsAI.extract_fleet_ids_without_mission_types(invasion_fleet_ids))
    print "Invasion Fleets Without Missions:    " + str(num_invasion_fleets)
    
    invasion_timer.start("planning troop base production")
    # only do base invasions if aggression is typical or above
    reserved_troop_base_targets = []
    if foAI.foAIstate.aggression > fo.aggression.typical:
        available_pp = {}
        for el in  empire.planetsWithAvailablePP:  #keys are sets of ints; data is doubles
            avail_pp = el.data()
            for pid in el.key():
                available_pp[pid] = avail_pp
        if len (invadable_planet_ids) > 0:
            #print "Evaluating Troop Bases (SpaceInvaders) for %s"%(invadable_planet_ids)
            pass
        for pid in invadable_planet_ids: #TODO: reorganize
            planet = universe.getPlanet(pid)
            if not planet: 
                continue
            sys_id = planet.systemID
            sys_partial_vis_turn = dict_from_map(universe.getVisibilityTurnsMap(planet.systemID, empire_id)).get(fo.visibility.partial, -9999)
            planet_partial_vis_turn = dict_from_map(universe.getVisibilityTurnsMap(pid, empire_id)).get(fo.visibility.partial, -9999)
            if planet_partial_vis_turn < sys_partial_vis_turn:
                #print "rejecting %s due to stealth"%planet.name
                continue
            for pid2 in ColonisationAI.empireSpeciesSystems.get(sys_id,  {}).get('pids', []):
                if available_pp.get(pid2,  0) < 2: #TODO: improve troop base PP sufficiency determination
                    #print "rejecting %s due to insufficient avail PP"%planet.name
                    break
                planet2 = universe.getPlanet(pid2)
                if not planet2: 
                    continue
                if (pid not in  foAI.foAIstate.qualifyingTroopBaseTargets) and (planet2.speciesName  in ColonisationAI.empireShipBuilders):
                    #print "Adding %s to Troop Bases (SpaceInvaders) potential target list, from %s"%(planet.name, planet2.name) 
                    foAI.foAIstate.qualifyingTroopBaseTargets.setdefault(pid,  [pid2,  -1])
                    break

        for pid in list(foAI.foAIstate.qualifyingTroopBaseTargets):
            planet = universe.getPlanet(pid) #TODO: also check that still have a colony in this system that can make troops
            if planet and planet.owner == empire_id:
                del foAI.foAIstate.qualifyingTroopBaseTargets[pid]

        secureAIFleetMissions = foAI.foAIstate.get_fleet_missions_with_any_mission_types([EnumsAI.AIFleetMissionType.FLEET_MISSION_SECURE])
        #print "considering possible troop bases at %s" % (foAI.foAIstate.qualifyingTroopBaseTargets.keys())
        for pid in (set(foAI.foAIstate.qualifyingTroopBaseTargets.keys()) - set(invasion_targeted_planet_ids)): #TODO: consider overriding standard invasion mission
            planet = universe.getPlanet(pid)
            if  foAI.foAIstate.qualifyingTroopBaseTargets[pid][1] != -1: 
                reserved_troop_base_targets.append(pid)
                if planet:
                    all_invasion_targeted_system_ids.add( planet.systemID )
                continue  #already building for here
            sys_id = planet.systemID
            this_sys_status = foAI.foAIstate.systemStatus.get( sys_id,  {} )
            if  ((planet.currentMeterValue(fo.meterType.shield) > 0) and 
                        (this_sys_status.get('myFleetRating', 0) < (0.8 * this_sys_status.get('totalThreat', 0)))):
                continue
            loc = foAI.foAIstate.qualifyingTroopBaseTargets[pid][0]
            this_score,  p_troops = evaluate_invasion_planet(pid, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, fleet_supplyable_planet_ids, empire,  secureAIFleetMissions,  False)
            bestShip,  colDesign,  buildChoices = ProductionAI.getBestShipInfo(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_ORBITAL_INVASION,  loc)
            if not bestShip:
                #print "Error: no troop base can be built at ",  PlanetUtilsAI.planet_name_ids([loc])
                continue
            #print "selecting  ",  PlanetUtilsAI.planet_name_ids([loc]),  " to build Orbital troop bases"
            n_bases = math.ceil((p_troops+1) / 2)#TODO: reconsider this +1 safety factor
            retval  = fo.issueEnqueueShipProductionOrder(bestShip, loc)
            print "Enqueueing %d Troop Bases at %s for %s"%( n_bases,  PlanetUtilsAI.planet_name_ids([loc]),  PlanetUtilsAI.planet_name_ids([pid]))
            if retval !=0:
                all_invasion_targeted_system_ids.add( planet.systemID )
                reserved_troop_base_targets.append(pid)
                foAI.foAIstate.qualifyingTroopBaseTargets[pid][1] = loc
                fo.issueChangeProductionQuantityOrder(empire.productionQueue.size -1,  1,  int(n_bases))
                res=fo.issueRequeueProductionOrder(empire.productionQueue.size -1,  0)

    invasion_timer.start("evaluating target planets")
    #TODO: check if any invasion_targeted_planet_ids need more troops assigned
    evaluatedPlanetIDs = list(set(invadable_planet_ids) - set(invasion_targeted_planet_ids) - set(reserved_troop_base_targets) )
    print "Evaluating potential invasions, PlanetIDs: " + str(evaluatedPlanetIDs)

    evaluatedPlanets = assign_invasion_values(evaluatedPlanetIDs, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, fleet_supplyable_planet_ids, empire)

    sortedPlanets = [(pid, pscore, ptroops) for (pid, (pscore, ptroops)) in evaluatedPlanets.items() ]
    sortedPlanets.sort(lambda x, y: cmp(x[1], y[1]), reverse=True)
    sortedPlanets = [(pid, pscore%10000, ptroops) for (pid, pscore, ptroops) in sortedPlanets ]

    print
    if sortedPlanets:
        print "Invadable planets\nIDs, ID | Score | Name | Race | Troops"
        for pid, pscore, ptroops in sortedPlanets:
            planet = universe.getPlanet(pid)
            if planet:
                print "%6d | %6d | %16s | %16s | %d"%(pid, pscore, planet.name, planet.speciesName, ptroops)
            else:
                print "%6d | %6d | Error: invalid planet ID"%(pid, pscore)
    else:
        print "No Invadable planets identified"

    sortedPlanets = [(pid, pscore, ptroops) for (pid, pscore, ptroops) in sortedPlanets if pscore > 0]
    # export opponent planets for other AI modules
    AIstate.opponentPlanetIDs = [pid for pid, pscore, trp in sortedPlanets]
    AIstate.invasionTargets = sortedPlanets

    # export invasion targeted systems for other AI modules
    AIstate.invasionTargetedSystemIDs = list(all_invasion_targeted_system_ids)
    invasion_timer.stop(section_name="evaluating %d target planets" % (len(evaluatedPlanetIDs)))
    invasion_timer.end()
Beispiel #23
0
    def issue_order(self):
        if not super(OrderResupply, self).issue_order():
            return
        fleet_id = self.fleet.id
        system_id = self.target.get_system().id
        fleet = self.fleet.get_object()
        if system_id not in [fleet.systemID, fleet.nextSystemID]:
            # if self.order_type == AIFleetOrderType.ORDER_MOVE:
            #     dest_id = system_id
            # else:
            # if self.order_type == AIFleetOrderType.ORDER_REPAIR:
            #     fo.issueAggressionOrder(fleet_id, False)
            start_id = [fleet.systemID, fleet.nextSystemID][fleet.systemID == INVALID_ID]
            dest_id = MoveUtilsAI.get_safe_path_leg_to_dest(fleet_id, start_id, system_id)
            print "fleet %d with order type(%s) sent to safe leg dest %s and ultimate dest %s" % (fleet_id, self.ORDER_NAME,
                                                                                                  PlanetUtilsAI.sys_name_ids([dest_id]),
                                                                                                  PlanetUtilsAI.sys_name_ids([system_id]))
            fo.issueFleetMoveOrder(fleet_id, dest_id)
            print "Order issued: %s fleet: %s target: %s" % (self.ORDER_NAME, self.fleet, self.target)

        if system_id == fleet.systemID:
            if foAI.foAIstate.get_fleet_role(fleet_id) == MissionType.EXPLORATION:
                if system_id in foAI.foAIstate.needsEmergencyExploration:
                    del foAI.foAIstate.needsEmergencyExploration[foAI.foAIstate.needsEmergencyExploration.index(system_id)]
            self.order_issued = True
Beispiel #24
0
    def issue_order(self):
        if not super(OrderRepair, self).issue_order():
            return
        fleet_id = self.fleet.id
        system_id = self.target.get_system().id
        fleet = self.fleet.get_object()
        if system_id not in [fleet.systemID, fleet.nextSystemID]:
            fo.issueAggressionOrder(fleet_id, False)
            start_id = [fleet.systemID, fleet.nextSystemID][fleet.systemID == INVALID_ID]
            dest_id = MoveUtilsAI.get_safe_path_leg_to_dest(fleet_id, start_id, system_id)
            print "fleet %d with order type(%s) sent to safe leg dest %s and ultimate dest %s" % (fleet_id, self.ORDER_NAME,
                                                                                                  PlanetUtilsAI.sys_name_ids([dest_id]),
                                                                                                  PlanetUtilsAI.sys_name_ids([system_id]))
            fo.issueFleetMoveOrder(fleet_id, dest_id)
            print "Order issued: %s fleet: %s target: %s" % (self.ORDER_NAME, self.fleet, self.target)

        if system_id == fleet.systemID:
            if foAI.foAIstate.get_fleet_role(fleet_id) == MissionType.EXPLORATION:
                if system_id in foAI.foAIstate.needsEmergencyExploration:
                    del foAI.foAIstate.needsEmergencyExploration[foAI.foAIstate.needsEmergencyExploration.index(system_id)]
            self.order_issued = True
Beispiel #25
0
def get_invasion_fleets():
    invasion_timer.start("gathering initial info")
    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empire_id = empire.empireID

    all_invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(MissionType.INVASION)
    AIstate.invasionFleetIDs = FleetUtilsAI.extract_fleet_ids_without_mission_types(all_invasion_fleet_ids)

    home_system_id = PlanetUtilsAI.get_capital_sys_id()
    visible_system_ids = foAI.foAIstate.visInteriorSystemIDs.keys() + foAI.foAIstate. visBorderSystemIDs.keys()

    if home_system_id != -1:
        accessible_system_ids = [sys_id for sys_id in visible_system_ids
                                 if (sys_id != -1) and universe.systemsConnected(sys_id, home_system_id, empire_id)]
    else:
        print "Warning: Empire has no identifiable homeworld; will treat all visible planets as accessible."
        accessible_system_ids = visible_system_ids  # TODO: check if any troop ships owned, use their system as home system

    acessible_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(accessible_system_ids)
    all_owned_planet_ids = PlanetUtilsAI.get_all_owned_planet_ids(acessible_planet_ids)  # includes unpopulated outposts
    all_populated_planets = PlanetUtilsAI.get_populated_planet_ids(acessible_planet_ids)  # includes unowned natives
    empire_owned_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs)
    invadable_planet_ids = set(all_owned_planet_ids).union(all_populated_planets) - set(empire_owned_planet_ids)

    invasion_targeted_planet_ids = get_invasion_targeted_planet_ids(universe.planetIDs, MissionType.INVASION)
    invasion_targeted_planet_ids.extend(get_invasion_targeted_planet_ids(universe.planetIDs, MissionType.ORBITAL_INVASION))
    all_invasion_targeted_system_ids = set(PlanetUtilsAI.get_systems(invasion_targeted_planet_ids))

    invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(MissionType.INVASION)
    num_invasion_fleets = len(FleetUtilsAI.extract_fleet_ids_without_mission_types(invasion_fleet_ids))

    print "Current Invasion Targeted SystemIDs: ", PlanetUtilsAI.sys_name_ids(AIstate.invasionTargetedSystemIDs)
    print "Current Invasion Targeted PlanetIDs: ", PlanetUtilsAI.planet_name_ids(invasion_targeted_planet_ids)
    print invasion_fleet_ids and "Invasion Fleet IDs: %s" % invasion_fleet_ids or "Available Invasion Fleets: 0"
    print "Invasion Fleets Without Missions: %s" % num_invasion_fleets

    invasion_timer.start("planning troop base production")
    # only do base invasions if aggression is typical or above
    reserved_troop_base_targets = []
    if foAI.foAIstate.aggression > fo.aggression.typical:
        available_pp = {}
        for el in empire.planetsWithAvailablePP:  # keys are sets of ints; data is doubles
            avail_pp = el.data()
            for pid in el.key():
                available_pp[pid] = avail_pp
        for pid in invadable_planet_ids:  # TODO: reorganize
            planet = universe.getPlanet(pid)
            if not planet:
                continue
            sys_id = planet.systemID
            sys_partial_vis_turn = universe.getVisibilityTurnsMap(planet.systemID, empire_id).get(fo.visibility.partial, -9999)
            planet_partial_vis_turn = universe.getVisibilityTurnsMap(pid, empire_id).get(fo.visibility.partial, -9999)
            if planet_partial_vis_turn < sys_partial_vis_turn:
                continue
            for pid2 in state.get_empire_inhabited_planets_by_system().get(sys_id, []):
                if available_pp.get(pid2, 0) < 2:  # TODO: improve troop base PP sufficiency determination
                    break
                planet2 = universe.getPlanet(pid2)
                if not planet2:
                    continue
                if pid not in foAI.foAIstate.qualifyingTroopBaseTargets and planet2.speciesName in ColonisationAI.empire_ship_builders:
                    foAI.foAIstate.qualifyingTroopBaseTargets.setdefault(pid, [pid2, -1])
                    break

        for pid in list(foAI.foAIstate.qualifyingTroopBaseTargets):
            planet = universe.getPlanet(pid)  # TODO: also check that still have a colony in this system that can make troops
            if planet and planet.owner == empire_id:
                del foAI.foAIstate.qualifyingTroopBaseTargets[pid]

        secure_ai_fleet_missions = foAI.foAIstate.get_fleet_missions_with_any_mission_types([MissionType.SECURE])
        for pid in (set(foAI.foAIstate.qualifyingTroopBaseTargets.keys()) - set(invasion_targeted_planet_ids)):  # TODO: consider overriding standard invasion mission
            planet = universe.getPlanet(pid)
            if foAI.foAIstate.qualifyingTroopBaseTargets[pid][1] != -1:
                reserved_troop_base_targets.append(pid)
                if planet:
                    all_invasion_targeted_system_ids.add(planet.systemID)
                continue  # already building for here
            sys_id = planet.systemID
            this_sys_status = foAI.foAIstate.systemStatus.get(sys_id, {})
            if (planet.currentMeterValue(fo.meterType.shield) > 0 and
                    this_sys_status.get('myFleetRating', 0) < 0.8 * this_sys_status.get('totalThreat', 0)):
                continue
            loc = foAI.foAIstate.qualifyingTroopBaseTargets[pid][0]
            best_base_trooper_here = ProductionAI.get_best_ship_info(PriorityType.PRODUCTION_ORBITAL_INVASION, loc)[1]
            loc_planet = universe.getPlanet(loc)
            if best_base_trooper_here is None:  # shouldn't be possible at this point, but just to be safe
                print "Could not find a suitable orbital invasion design at %s" % loc_planet
                continue
            # TODO: have TroopShipDesigner give the expected number of troops including species effects directly
            troops_per_ship = best_base_trooper_here.troopCapacity
            species_troop_grade = CombatRatingsAI.get_species_troops_grade(loc_planet.speciesName)
            troops_per_ship = CombatRatingsAI.weight_attack_troops(troops_per_ship, species_troop_grade)
            if not troops_per_ship:
                print "The best orbital invasion design at %s seems not to have any troop capacity." % loc_planet
                continue
            this_score, p_troops = evaluate_invasion_planet(pid, empire, secure_ai_fleet_missions, False)
            _, col_design, build_choices = ProductionAI.get_best_ship_info(PriorityType.PRODUCTION_ORBITAL_INVASION, loc)
            if not col_design:
                continue
            if loc not in build_choices:
                sys.stderr.write(
                    'Best troop design %s can not be produces in at planet with id: %s\d' % (col_design, build_choices)
                )
            n_bases = math.ceil((p_troops + 1) / troops_per_ship)  # TODO: reconsider this +1 safety factor
            print "Invasion base planning, need %d troops at %d pership, will build %d ships." % ((p_troops + 1), troops_per_ship, n_bases)
            retval = fo.issueEnqueueShipProductionOrder(col_design.id, loc)
            print "Enqueueing %d Troop Bases at %s for %s" % (n_bases, PlanetUtilsAI.planet_name_ids([loc]), PlanetUtilsAI.planet_name_ids([pid]))
            if retval != 0:
                all_invasion_targeted_system_ids.add(planet.systemID)
                reserved_troop_base_targets.append(pid)
                foAI.foAIstate.qualifyingTroopBaseTargets[pid][1] = loc
                fo.issueChangeProductionQuantityOrder(empire.productionQueue.size - 1, 1, int(n_bases))
                fo.issueRequeueProductionOrder(empire.productionQueue.size - 1, 0)

    invasion_timer.start("evaluating target planets")
    # TODO: check if any invasion_targeted_planet_ids need more troops assigned
    evaluated_planet_ids = list(set(invadable_planet_ids) - set(invasion_targeted_planet_ids) - set(reserved_troop_base_targets))
    evaluated_planets = assign_invasion_values(evaluated_planet_ids, empire)

    sorted_planets = [(pid, pscore % 10000, ptroops) for pid, (pscore, ptroops) in evaluated_planets.items()]
    sorted_planets.sort(key=lambda x: x[1], reverse=True)
    sorted_planets = [(pid, pscore % 10000, ptroops) for pid, pscore, ptroops in sorted_planets]

    invasion_table = Table([Text('Planet'), Float('Score'), Text('Species'), Float('Troops')],
                           table_name="Potential Targets for Invasion Turn %d" % fo.currentTurn())

    for pid, pscore, ptroops in sorted_planets:
        planet = universe.getPlanet(pid)
        invasion_table.add_row([
            planet,
            pscore,
            planet and planet.speciesName or "unknown",
            ptroops
        ])
    print
    invasion_table.print_table()

    sorted_planets = filter(lambda x: x[1] > 0, sorted_planets)
    # export opponent planets for other AI modules
    AIstate.opponentPlanetIDs = [pid for pid, _, _ in sorted_planets]
    AIstate.invasionTargets = sorted_planets

    # export invasion targeted systems for other AI modules
    AIstate.invasionTargetedSystemIDs = list(all_invasion_targeted_system_ids)
    invasion_timer.stop(section_name="evaluating %d target planets" % (len(evaluated_planet_ids)))
    invasion_timer.end()
Beispiel #26
0
def _info_string(path_info):
    return "dist %.1f, path %s" % (path_info.distance, PlanetUtilsAI.sys_name_ids(path_info.path))
Beispiel #27
0
def get_invasion_fleets():
    invasion_timer.start("gathering initial info")
    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empire_id = fo.empireID()

    home_system_id = PlanetUtilsAI.get_capital_sys_id()
    aistate = get_aistate()
    visible_system_ids = list(aistate.visInteriorSystemIDs) + list(aistate.visBorderSystemIDs)

    if home_system_id != INVALID_ID:
        accessible_system_ids = [sys_id for sys_id in visible_system_ids if
                                 (sys_id != INVALID_ID) and universe.systemsConnected(sys_id, home_system_id,
                                                                                      empire_id)]
    else:
        debug("Empire has no identifiable homeworld; will treat all visible planets as accessible.")
        # TODO: check if any troop ships owned, use their system as home system
        accessible_system_ids = visible_system_ids

    acessible_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(accessible_system_ids)
    all_owned_planet_ids = PlanetUtilsAI.get_all_owned_planet_ids(acessible_planet_ids)  # includes unpopulated outposts
    all_populated_planets = PlanetUtilsAI.get_populated_planet_ids(acessible_planet_ids)  # includes unowned natives
    empire_owned_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs)
    invadable_planet_ids = set(all_owned_planet_ids).union(all_populated_planets) - set(empire_owned_planet_ids)

    invasion_targeted_planet_ids = get_invasion_targeted_planet_ids(universe.planetIDs, MissionType.INVASION)
    invasion_targeted_planet_ids.extend(
        get_invasion_targeted_planet_ids(universe.planetIDs, MissionType.ORBITAL_INVASION))
    all_invasion_targeted_system_ids = set(PlanetUtilsAI.get_systems(invasion_targeted_planet_ids))

    invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(MissionType.INVASION)
    num_invasion_fleets = len(FleetUtilsAI.extract_fleet_ids_without_mission_types(invasion_fleet_ids))

    debug("Current Invasion Targeted SystemIDs: %s" % PlanetUtilsAI.sys_name_ids(AIstate.invasionTargetedSystemIDs))
    debug("Current Invasion Targeted PlanetIDs: %s" % PlanetUtilsAI.planet_string(invasion_targeted_planet_ids))
    debug(invasion_fleet_ids and "Invasion Fleet IDs: %s" % invasion_fleet_ids or "Available Invasion Fleets: 0")
    debug("Invasion Fleets Without Missions: %s" % num_invasion_fleets)

    invasion_timer.start("planning troop base production")
    reserved_troop_base_targets = []
    if aistate.character.may_invade_with_bases():
        available_pp = {}
        for el in empire.planetsWithAvailablePP:  # keys are sets of ints; data is doubles
            avail_pp = el.data()
            for pid in el.key():
                available_pp[pid] = avail_pp
        # For planning base trooper invasion targets we have a two-pass system.  (1) In the first pass we consider all
        # the invasion targets and figure out which ones appear to be suitable for using base troopers against (i.e., we
        # already have a populated planet in the same system that could build base troopers) and we have at least a
        # minimal amount of PP available, and (2) in the second pass we go through the reserved base trooper target list
        # and check to make sure that there does not appear to be too much military action still needed before the
        # target is ready to be invaded, we double check that not too many base troopers would be needed, and if things
        # look clear then we queue up the base troopers on the Production Queue and keep track of where we are building
        # them, and how many; we may also disqualify and remove previously qualified targets (in case, for example,
        # we lost our base trooper source planet since it was first added to list).
        #
        # For planning and tracking base troopers under construction, we use a dictionary store in
        # get_aistate().qualifyingTroopBaseTargets, keyed by the invasion target planet ID.  We only store values
        # for invasion targets that appear likely to be suitable for base trooper use, and store a 2-item list.
        # The first item in this list is the ID of the planet where we expect to build the base troopers, and the second
        # entry initially is set to INVALID_ID (-1).  The presence of this entry in qualifyingTroopBaseTargets
        # flags this target as being reserved as a base-trooper invasion target.
        # In the second pass, if/when we actually start construction, then we modify the record, replacing that second
        # value with the ID of the planet where the troopers are actually being built.  (Right now that is always the
        # same as the source planet originally identified, but we could consider reevaluating that, or use that second
        # value to instead record how many base troopers have been queued, so that on later turns we can assess if the
        # process got delayed & perhaps more troopers need to be queued).
        secure_ai_fleet_missions = aistate.get_fleet_missions_with_any_mission_types([MissionType.SECURE,
                                                                                      MissionType.MILITARY])

        # Pass 1: identify qualifying base troop invasion targets
        for pid in invadable_planet_ids:  # TODO: reorganize
            if pid in aistate.qualifyingTroopBaseTargets:
                continue
            planet = universe.getPlanet(pid)
            if not planet:
                continue
            sys_id = planet.systemID
            sys_partial_vis_turn = get_partial_visibility_turn(sys_id)
            planet_partial_vis_turn = get_partial_visibility_turn(pid)
            if planet_partial_vis_turn < sys_partial_vis_turn:
                continue
            best_base_planet = INVALID_ID
            best_trooper_count = 0
            for pid2 in state.get_empire_planets_by_system(sys_id, include_outposts=False):
                if available_pp.get(pid2, 0) < 2:  # TODO: improve troop base PP sufficiency determination
                    break
                planet2 = universe.getPlanet(pid2)
                if not planet2 or planet2.speciesName not in ColonisationAI.empire_ship_builders:
                    continue
                best_base_trooper_here = \
                    ProductionAI.get_best_ship_info(PriorityType.PRODUCTION_ORBITAL_INVASION, pid2)[1]
                if not best_base_trooper_here:
                    continue
                troops_per_ship = best_base_trooper_here.troopCapacity
                if not troops_per_ship:
                    continue
                species_troop_grade = CombatRatingsAI.get_species_troops_grade(planet2.speciesName)
                troops_per_ship = CombatRatingsAI.weight_attack_troops(troops_per_ship, species_troop_grade)
                if troops_per_ship > best_trooper_count:
                    best_base_planet = pid2
                    best_trooper_count = troops_per_ship
            if best_base_planet != INVALID_ID:
                aistate.qualifyingTroopBaseTargets.setdefault(pid, [best_base_planet, INVALID_ID])

        # Pass 2: for each target previously identified for base troopers, check that still qualifies and
        # check how many base troopers would be needed; if reasonable then queue up the troops and record this in
        # get_aistate().qualifyingTroopBaseTargets
        for pid in aistate.qualifyingTroopBaseTargets.keys():
            planet = universe.getPlanet(pid)
            if planet and planet.owner == empire_id:
                del aistate.qualifyingTroopBaseTargets[pid]
                continue
            if pid in invasion_targeted_planet_ids:  # TODO: consider overriding standard invasion mission
                continue
            if aistate.qualifyingTroopBaseTargets[pid][1] != -1:
                reserved_troop_base_targets.append(pid)
                if planet:
                    all_invasion_targeted_system_ids.add(planet.systemID)
                # TODO: evaluate changes to situation, any more troops needed, etc.
                continue  # already building for here
            _, planet_troops = evaluate_invasion_planet(pid, secure_ai_fleet_missions, True)
            sys_id = planet.systemID
            this_sys_status = aistate.systemStatus.get(sys_id, {})
            troop_tally = 0
            for _fid in this_sys_status.get('myfleets', []):
                troop_tally += FleetUtilsAI.count_troops_in_fleet(_fid)
            if troop_tally > planet_troops:  # base troopers appear unneeded
                del aistate.qualifyingTroopBaseTargets[pid]
                continue
            if (planet.currentMeterValue(fo.meterType.shield) > 0 and
                    (this_sys_status.get('myFleetRating', 0) < 0.8 * this_sys_status.get('totalThreat', 0) or
                     this_sys_status.get('myFleetRatingVsPlanets', 0) < this_sys_status.get('planetThreat', 0))):
                # this system not secured, so ruling out invasion base troops for now
                # don't immediately delete from qualifyingTroopBaseTargets or it will be opened up for regular troops
                continue
            loc = aistate.qualifyingTroopBaseTargets[pid][0]
            best_base_trooper_here = ProductionAI.get_best_ship_info(PriorityType.PRODUCTION_ORBITAL_INVASION, loc)[1]
            loc_planet = universe.getPlanet(loc)
            if best_base_trooper_here is None:  # shouldn't be possible at this point, but just to be safe
                warn("Could not find a suitable orbital invasion design at %s" % loc_planet)
                continue
            # TODO: have TroopShipDesigner give the expected number of troops including species effects directly
            troops_per_ship = best_base_trooper_here.troopCapacity
            species_troop_grade = CombatRatingsAI.get_species_troops_grade(loc_planet.speciesName)
            troops_per_ship = CombatRatingsAI.weight_attack_troops(troops_per_ship, species_troop_grade)
            if not troops_per_ship:
                warn("The best orbital invasion design at %s seems not to have any troop capacity." % loc_planet)
                continue
            _, col_design, build_choices = ProductionAI.get_best_ship_info(PriorityType.PRODUCTION_ORBITAL_INVASION,
                                                                           loc)
            if not col_design:
                continue
            if loc not in build_choices:
                warn('Best troop design %s can not be produced at planet with id: %s\d' % (col_design, build_choices))
                continue
            n_bases = math.ceil((planet_troops + 1) / troops_per_ship)  # TODO: reconsider this +1 safety factor
            # TODO: evaluate cost and time-to-build of best base trooper here versus cost and time-to-build-and-travel
            # for best regular trooper elsewhere
            # For now, we assume what building base troopers is best so long as either (1) we would need no more than
            # MAX_BASE_TROOPERS_POOR_INVADERS base troop ships, or (2) our base troopers have more than 1 trooper per
            # ship and we would need no more than MAX_BASE_TROOPERS_GOOD_INVADERS base troop ships
            if (n_bases > MAX_BASE_TROOPERS_POOR_INVADERS or
                    (troops_per_ship > 1 and n_bases > MAX_BASE_TROOPERS_GOOD_INVADERS)):
                debug("ruling out base invasion troopers for %s due to high number (%d) required." % (planet, n_bases))
                del aistate.qualifyingTroopBaseTargets[pid]
                continue
            debug("Invasion base planning, need %d troops at %d per ship, will build %d ships." % (
                (planet_troops + 1), troops_per_ship, n_bases))
            retval = fo.issueEnqueueShipProductionOrder(col_design.id, loc)
            debug("Enqueueing %d Troop Bases at %s for %s" % (n_bases, PlanetUtilsAI.planet_string(loc),
                                                              PlanetUtilsAI.planet_string(pid)))
            if retval != 0:
                all_invasion_targeted_system_ids.add(planet.systemID)
                reserved_troop_base_targets.append(pid)
                aistate.qualifyingTroopBaseTargets[pid][1] = loc
                fo.issueChangeProductionQuantityOrder(empire.productionQueue.size - 1, 1, int(n_bases))
                fo.issueRequeueProductionOrder(empire.productionQueue.size - 1, 0)

    invasion_timer.start("evaluating target planets")
    # TODO: check if any invasion_targeted_planet_ids need more troops assigned
    evaluated_planet_ids = list(
        set(invadable_planet_ids) - set(invasion_targeted_planet_ids) - set(reserved_troop_base_targets))
    evaluated_planets = assign_invasion_values(evaluated_planet_ids)

    sorted_planets = [(pid, pscore % 10000, ptroops) for pid, (pscore, ptroops) in evaluated_planets.items()]
    sorted_planets.sort(key=lambda x: x[1], reverse=True)
    sorted_planets = [(pid, pscore % 10000, ptroops) for pid, pscore, ptroops in sorted_planets]

    invasion_table = Table([Text('Planet'), Float('Score'), Text('Species'), Float('Troops')],
                           table_name="Potential Targets for Invasion Turn %d" % fo.currentTurn())

    for pid, pscore, ptroops in sorted_planets:
        planet = universe.getPlanet(pid)
        invasion_table.add_row([
            planet,
            pscore,
            planet and planet.speciesName or "unknown",
            ptroops
        ])
    info(invasion_table)

    sorted_planets = filter(lambda x: x[1] > 0, sorted_planets)
    # export opponent planets for other AI modules
    AIstate.opponentPlanetIDs = [pid for pid, __, __ in sorted_planets]
    AIstate.invasionTargets = sorted_planets

    # export invasion targeted systems for other AI modules
    AIstate.invasionTargetedSystemIDs = list(all_invasion_targeted_system_ids)
    invasion_timer.stop(section_name="evaluating %d target planets" % (len(evaluated_planet_ids)))
    invasion_timer.stop_print_and_clear()
    def issue_order(self):
        global dumpTurn
        if not self.can_issue_order():  # appears to be redundant with check in IAFleetMission?
            print "\tcan't issue %s" % self
        else:
            universe = fo.getUniverse()
            self.executed = True
            # outpost
            if AIFleetOrderType.ORDER_OUTPOST == self.order_type:
                planet = universe.getPlanet(self.target.target_id)
                if not planet.unowned:
                    self.execution_completed = True
                    return
                fleet_id = self.fleet.target_id
                ship_id = FleetUtilsAI.get_ship_id_with_role(fleet_id, AIShipRoleType.SHIP_ROLE_CIVILIAN_OUTPOST)
                if ship_id is None:
                    ship_id = FleetUtilsAI.get_ship_id_with_role(fleet_id, AIShipRoleType.SHIP_ROLE_BASE_OUTPOST)
                result = fo.issueColonizeOrder(ship_id, self.target.target_id)
                if not result:
                    self.executed = False
            # colonise
            elif AIFleetOrderType.ORDER_COLONISE == self.order_type:
                fleet_id = self.fleet.target_id
                ship_id = FleetUtilsAI.get_ship_id_with_role(fleet_id, AIShipRoleType.SHIP_ROLE_CIVILIAN_COLONISATION)
                if ship_id is None:
                    ship_id = FleetUtilsAI.get_ship_id_with_role(fleet_id, AIShipRoleType.SHIP_ROLE_BASE_COLONISATION)

                planet_id = self.target.target_id
                planet = universe.getPlanet(planet_id)
                planet_name = planet and planet.name or "apparently invisible"
                result = fo.issueColonizeOrder(ship_id, planet_id)
                print "Ordered colony ship ID %d to colonize %s, got result %d" % (ship_id, planet_name, result)
                if not result:
                    self.executed = False
            # invade
            elif AIFleetOrderType.ORDER_INVADE == self.order_type:
                result = False
                planet_id = self.target.target_id
                planet = universe.getPlanet(planet_id)
                planet_name = planet and planet.name or "invisible"

                fleet_id = self.fleet.target_id
                fleet = fo.getUniverse().getFleet(fleet_id)
                detail_str = ""
                for ship_id in fleet.shipIDs:
                    ship = universe.getShip(ship_id)
                    if foAI.foAIstate.get_ship_role(ship.design.id) in [AIShipRoleType.SHIP_ROLE_MILITARY_INVASION, AIShipRoleType.SHIP_ROLE_BASE_INVASION]:
                        result = fo.issueInvadeOrder(ship_id, planet_id) or result  # will track if at least one invasion troops successfully deployed
                        shields = planet.currentMeterValue(fo.meterType.shield)
                        owner = planet.owner
                        if not result:
                            pstealth = planet.currentMeterValue(fo.meterType.stealth)
                            pop = planet.currentMeterValue(fo.meterType.population)
                            detail_str = " -- planet has %.1f stealth, shields %.1f, %.1f population and is owned by empire %d" % (pstealth, shields, pop, owner)
                        print "Ordered troop ship ID %d to invade %s, got result %d" % (ship_id, planet_name, result), detail_str
                        if not result:
                            if 'needsEmergencyExploration' not in dir(foAI.foAIstate):
                                foAI.foAIstate.needsEmergencyExploration = []
                            if fleet.systemID not in foAI.foAIstate.needsEmergencyExploration:
                                foAI.foAIstate.needsEmergencyExploration.append(fleet.systemID)
                                print "Due to trouble invading, adding system %d to Emergency Exploration List" % fleet.systemID
                                self.executed = False
                            if shields > 0 and owner == -1 and dumpTurn < fo.currentTurn():
                                dumpTurn = fo.currentTurn()
                                print "Universe Dump to debug invasions:"
                                universe.dump()
                            break
                if result:
                    print "Successfully ordered troop ship(s) to invade %s, with detail %s" % (planet_name, detail_str)
            # military
            elif AIFleetOrderType.ORDER_MILITARY == self.order_type:
                fleet_id = self.fleet.target_id
                #fo.issueFleetMoveOrder(fleet_id, self.target.target_id) #moving is already taken care of separately
                target_sys_id = self.target.target_id
                fleet = fo.getUniverse().getFleet(fleet_id)
                system_status = foAI.foAIstate.systemStatus.get(target_sys_id, {})
                if fleet and fleet.systemID == target_sys_id and not (system_status.get('fleetThreat', 0) + system_status.get('planetThreat', 0) + system_status.get('monsterThreat', 0)):
                    self.execution_completed = True

            # move or resupply
            elif self.order_type in [AIFleetOrderType.ORDER_MOVE, AIFleetOrderType.ORDER_REPAIR, AIFleetOrderType.ORDER_RESUPPLY]:
                fleet_id = self.fleet.target_id
                system_id = self.target.target_id
                fleet = fo.getUniverse().getFleet(fleet_id)
                if system_id not in [fleet.systemID, fleet.nextSystemID]:
                    if self.order_type == AIFleetOrderType.ORDER_MOVE:
                        dest_id = system_id
                    else:
                        if self.order_type == AIFleetOrderType.ORDER_REPAIR:
                            fo.issueAggressionOrder(fleet_id, False)
                        start_id = [fleet.systemID, fleet.nextSystemID][fleet.systemID == -1]
                        dest_id = MoveUtilsAI.get_safe_path_leg_to_dest(fleet_id, start_id, system_id)
                        print "fleet %d with order type(%s) sent to safe leg dest %s and ultimate dest %s" % (fleet_id, AIFleetOrderTypeNames.name(self.order_type),
                                                                                                            PlanetUtilsAI.sys_name_ids([dest_id]),
                                                                                                            PlanetUtilsAI.sys_name_ids([system_id]))
                    fo.issueFleetMoveOrder(fleet_id, dest_id)
                if system_id == fleet.systemID:
                    if foAI.foAIstate.get_fleet_role(fleet_id) == AIFleetMissionType.FLEET_MISSION_EXPLORATION:
                        if system_id in foAI.foAIstate.needsEmergencyExploration:
                            del foAI.foAIstate.needsEmergencyExploration[foAI.foAIstate.needsEmergencyExploration.index(system_id)]
                    self.execution_completed = True

            # split fleet
            elif AIFleetOrderType.ORDER_SPLIT_FLEET == self.order_type:
                fleet_id = self.fleet.target_id
                ship_id = self.target.target_id
                fleet = fo.getUniverse().getFleet(fleet_id)
                if ship_id in fleet.shipIDs:
                    fo.issueNewFleetOrder(str(ship_id), ship_id)
                self.execution_completed = True
            # attack
            elif AIFleetOrderType.ORDER_ATTACK == self.order_type:
                fleet_id = self.fleet.target_id
                fo.issueFleetMoveOrder(fleet_id, self.target.get_required_system_ai_targets()[0].target_id)
Beispiel #29
0
def get_invasion_fleets():
    invasion_timer.start("gathering initial info")
    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empire_id = fo.empireID()

    home_system_id = PlanetUtilsAI.get_capital_sys_id()
    aistate = get_aistate()
    visible_system_ids = list(aistate.visInteriorSystemIDs) + list(
        aistate.visBorderSystemIDs)

    if home_system_id != INVALID_ID:
        accessible_system_ids = [
            sys_id for sys_id in visible_system_ids
            if systems_connected(sys_id, home_system_id)
        ]
    else:
        debug(
            "Empire has no identifiable homeworld; will treat all visible planets as accessible."
        )
        # TODO: check if any troop ships owned, use their system as home system
        accessible_system_ids = visible_system_ids

    acessible_planet_ids = PlanetUtilsAI.get_planets_in__systems_ids(
        accessible_system_ids)
    all_owned_planet_ids = PlanetUtilsAI.get_all_owned_planet_ids(
        acessible_planet_ids)  # includes unpopulated outposts
    all_populated_planets = PlanetUtilsAI.get_populated_planet_ids(
        acessible_planet_ids)  # includes unowned natives
    empire_owned_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(
        universe.planetIDs)
    invadable_planet_ids = set(all_owned_planet_ids).union(
        all_populated_planets) - set(empire_owned_planet_ids)

    invasion_targeted_planet_ids = get_invasion_targeted_planet_ids(
        universe.planetIDs, MissionType.INVASION)
    invasion_targeted_planet_ids.extend(
        get_invasion_targeted_planet_ids(universe.planetIDs,
                                         MissionType.ORBITAL_INVASION))
    all_invasion_targeted_system_ids = set(
        PlanetUtilsAI.get_systems(invasion_targeted_planet_ids))

    invasion_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(
        MissionType.INVASION)
    num_invasion_fleets = len(
        FleetUtilsAI.extract_fleet_ids_without_mission_types(
            invasion_fleet_ids))

    debug("Current Invasion Targeted SystemIDs: %s" %
          PlanetUtilsAI.sys_name_ids(AIstate.invasionTargetedSystemIDs))
    debug("Current Invasion Targeted PlanetIDs: %s" %
          PlanetUtilsAI.planet_string(invasion_targeted_planet_ids))
    debug(invasion_fleet_ids and "Invasion Fleet IDs: %s" % invasion_fleet_ids
          or "Available Invasion Fleets: 0")
    debug("Invasion Fleets Without Missions: %s" % num_invasion_fleets)

    invasion_timer.start("planning troop base production")
    reserved_troop_base_targets = []
    if aistate.character.may_invade_with_bases():
        available_pp = {}
        for el in empire.planetsWithAvailablePP:  # keys are sets of ints; data is doubles
            avail_pp = el.data()
            for pid in el.key():
                available_pp[pid] = avail_pp
        # For planning base trooper invasion targets we have a two-pass system.  (1) In the first pass we consider all
        # the invasion targets and figure out which ones appear to be suitable for using base troopers against (i.e., we
        # already have a populated planet in the same system that could build base troopers) and we have at least a
        # minimal amount of PP available, and (2) in the second pass we go through the reserved base trooper target list
        # and check to make sure that there does not appear to be too much military action still needed before the
        # target is ready to be invaded, we double check that not too many base troopers would be needed, and if things
        # look clear then we queue up the base troopers on the Production Queue and keep track of where we are building
        # them, and how many; we may also disqualify and remove previously qualified targets (in case, for example,
        # we lost our base trooper source planet since it was first added to list).
        #
        # For planning and tracking base troopers under construction, we use a dictionary store in
        # get_aistate().qualifyingTroopBaseTargets, keyed by the invasion target planet ID.  We only store values
        # for invasion targets that appear likely to be suitable for base trooper use, and store a 2-item list.
        # The first item in this list is the ID of the planet where we expect to build the base troopers, and the second
        # entry initially is set to INVALID_ID (-1).  The presence of this entry in qualifyingTroopBaseTargets
        # flags this target as being reserved as a base-trooper invasion target.
        # In the second pass, if/when we actually start construction, then we modify the record, replacing that second
        # value with the ID of the planet where the troopers are actually being built.  (Right now that is always the
        # same as the source planet originally identified, but we could consider reevaluating that, or use that second
        # value to instead record how many base troopers have been queued, so that on later turns we can assess if the
        # process got delayed & perhaps more troopers need to be queued).

        # Pass 1: identify qualifying base troop invasion targets
        for pid in invadable_planet_ids:  # TODO: reorganize
            if pid in aistate.qualifyingTroopBaseTargets:
                continue
            planet = universe.getPlanet(pid)
            if not planet:
                continue
            sys_id = planet.systemID
            sys_partial_vis_turn = get_partial_visibility_turn(sys_id)
            planet_partial_vis_turn = get_partial_visibility_turn(pid)
            if planet_partial_vis_turn < sys_partial_vis_turn:
                continue
            best_base_planet = INVALID_ID
            best_trooper_count = 0
            for pid2 in get_colonized_planets_in_system(sys_id):
                if available_pp.get(
                        pid2, 0
                ) < 2:  # TODO: improve troop base PP sufficiency determination
                    break
                planet2 = universe.getPlanet(pid2)
                if not planet2 or not can_build_ship_for_species(
                        planet2.speciesName):
                    continue
                best_base_trooper_here = get_best_ship_info(
                    PriorityType.PRODUCTION_ORBITAL_INVASION, pid2)[1]
                if not best_base_trooper_here:
                    continue
                troops_per_ship = best_base_trooper_here.troopCapacity
                if not troops_per_ship:
                    continue
                species_troop_grade = get_species_tag_grade(
                    planet2.speciesName, Tags.ATTACKTROOPS)
                troops_per_ship = CombatRatingsAI.weight_attack_troops(
                    troops_per_ship, species_troop_grade)
                if troops_per_ship > best_trooper_count:
                    best_base_planet = pid2
                    best_trooper_count = troops_per_ship
            if best_base_planet != INVALID_ID:
                aistate.qualifyingTroopBaseTargets.setdefault(
                    pid, [best_base_planet, INVALID_ID])

        # Pass 2: for each target previously identified for base troopers, check that still qualifies and
        # check how many base troopers would be needed; if reasonable then queue up the troops and record this in
        # get_aistate().qualifyingTroopBaseTargets
        for pid in list(aistate.qualifyingTroopBaseTargets.keys()):
            planet = universe.getPlanet(pid)
            if planet and planet.owner == empire_id:
                del aistate.qualifyingTroopBaseTargets[pid]
                continue
            if pid in invasion_targeted_planet_ids:  # TODO: consider overriding standard invasion mission
                continue
            if aistate.qualifyingTroopBaseTargets[pid][1] != -1:
                reserved_troop_base_targets.append(pid)
                if planet:
                    all_invasion_targeted_system_ids.add(planet.systemID)
                # TODO: evaluate changes to situation, any more troops needed, etc.
                continue  # already building for here
            _, planet_troops = evaluate_invasion_planet(pid)
            sys_id = planet.systemID
            this_sys_status = aistate.systemStatus.get(sys_id, {})
            troop_tally = 0
            for _fid in this_sys_status.get("myfleets", []):
                troop_tally += FleetUtilsAI.count_troops_in_fleet(_fid)
            if troop_tally > planet_troops:  # base troopers appear unneeded
                del aistate.qualifyingTroopBaseTargets[pid]
                continue
            if planet.currentMeterValue(fo.meterType.shield) > 0 and (
                    this_sys_status.get("myFleetRating", 0) <
                    0.8 * this_sys_status.get("totalThreat", 0)
                    or this_sys_status.get("myFleetRatingVsPlanets", 0) <
                    this_sys_status.get("planetThreat", 0)):
                # this system not secured, so ruling out invasion base troops for now
                # don't immediately delete from qualifyingTroopBaseTargets or it will be opened up for regular troops
                continue
            loc = aistate.qualifyingTroopBaseTargets[pid][0]
            best_base_trooper_here = get_best_ship_info(
                PriorityType.PRODUCTION_ORBITAL_INVASION, loc)[1]
            loc_planet = universe.getPlanet(loc)
            if best_base_trooper_here is None:  # shouldn't be possible at this point, but just to be safe
                warning(
                    "Could not find a suitable orbital invasion design at %s" %
                    loc_planet)
                continue
            # TODO: have TroopShipDesigner give the expected number of troops including species effects directly
            troops_per_ship = best_base_trooper_here.troopCapacity
            species_troop_grade = get_species_tag_grade(
                loc_planet.speciesName, Tags.ATTACKTROOPS)
            troops_per_ship = CombatRatingsAI.weight_attack_troops(
                troops_per_ship, species_troop_grade)
            if not troops_per_ship:
                warning(
                    "The best orbital invasion design at %s seems not to have any troop capacity."
                    % loc_planet)
                continue
            _, col_design, build_choices = get_best_ship_info(
                PriorityType.PRODUCTION_ORBITAL_INVASION, loc)
            if not col_design:
                continue
            if loc not in build_choices:
                warning(
                    "Best troop design %s can not be produced at planet with id: %s"
                    % (col_design, build_choices))
                continue
            n_bases = math.ceil(
                (planet_troops + 1) /
                troops_per_ship)  # TODO: reconsider this +1 safety factor
            # TODO: evaluate cost and time-to-build of best base trooper here versus cost and time-to-build-and-travel
            # for best regular trooper elsewhere
            # For now, we assume what building base troopers is best so long as either (1) we would need no more than
            # MAX_BASE_TROOPERS_POOR_INVADERS base troop ships, or (2) our base troopers have more than 1 trooper per
            # ship and we would need no more than MAX_BASE_TROOPERS_GOOD_INVADERS base troop ships
            if n_bases > MAX_BASE_TROOPERS_POOR_INVADERS or (
                    troops_per_ship > 1
                    and n_bases > MAX_BASE_TROOPERS_GOOD_INVADERS):
                debug(
                    "ruling out base invasion troopers for %s due to high number (%d) required."
                    % (planet, n_bases))
                del aistate.qualifyingTroopBaseTargets[pid]
                continue
            debug(
                "Invasion base planning, need %d troops at %d per ship, will build %d ships."
                % ((planet_troops + 1), troops_per_ship, n_bases))
            retval = fo.issueEnqueueShipProductionOrder(col_design.id, loc)
            debug("Enqueueing %d Troop Bases at %s for %s" %
                  (n_bases, PlanetUtilsAI.planet_string(loc),
                   PlanetUtilsAI.planet_string(pid)))
            if retval != 0:
                all_invasion_targeted_system_ids.add(planet.systemID)
                reserved_troop_base_targets.append(pid)
                aistate.qualifyingTroopBaseTargets[pid][1] = loc
                fo.issueChangeProductionQuantityOrder(
                    empire.productionQueue.size - 1, 1, int(n_bases))
                fo.issueRequeueProductionOrder(empire.productionQueue.size - 1,
                                               0)

    invasion_timer.start("evaluating target planets")
    # TODO: check if any invasion_targeted_planet_ids need more troops assigned
    evaluated_planet_ids = list(
        set(invadable_planet_ids) - set(invasion_targeted_planet_ids) -
        set(reserved_troop_base_targets))
    evaluated_planets = assign_invasion_values(evaluated_planet_ids)

    sorted_planets = [(pid, pscore % 10000, ptroops)
                      for pid, (pscore, ptroops) in evaluated_planets.items()]
    sorted_planets.sort(key=lambda x: x[1], reverse=True)
    sorted_planets = [(pid, pscore % 10000, ptroops)
                      for pid, pscore, ptroops in sorted_planets]

    invasion_table = Table(
        Text("Planet"),
        Number("Score"),
        Text("Species"),
        Number("Troops"),
        table_name="Potential Targets for Invasion Turn %d" % fo.currentTurn(),
    )

    for pid, pscore, ptroops in sorted_planets:
        planet = universe.getPlanet(pid)
        invasion_table.add_row(planet, pscore, planet and planet.speciesName
                               or "unknown", ptroops)
    invasion_table.print_table(info)

    sorted_planets = [x for x in sorted_planets if x[1] > 0]
    # export opponent planets for other AI modules
    AIstate.opponentPlanetIDs = [pid for pid, __, __ in sorted_planets]
    AIstate.invasionTargets = sorted_planets

    # export invasion targeted systems for other AI modules
    AIstate.invasionTargetedSystemIDs = list(all_invasion_targeted_system_ids)
    invasion_timer.stop(section_name="evaluating %d target planets" %
                        (len(evaluated_planet_ids)))
    invasion_timer.stop_print_and_clear()
Beispiel #30
0
    def issue_order(self):
        global dumpTurn
        if not self.can_issue_order():  # appears to be redundant with check in IAFleetMission?
            print "\tcan't issue %s" % self
        else:
            universe = fo.getUniverse()
            self.executed = True
            # outpost
            if AIFleetOrderType.ORDER_OUTPOST == self.order_type:
                planet = universe.getPlanet(self.target.target_id)
                if not planet.unowned:
                    self.execution_completed = True
                    return
                fleet_id = self.fleet.target_id
                ship_id = FleetUtilsAI.get_ship_id_with_role(fleet_id, AIShipRoleType.SHIP_ROLE_CIVILIAN_OUTPOST)
                if ship_id is None:
                    ship_id = FleetUtilsAI.get_ship_id_with_role(fleet_id, AIShipRoleType.SHIP_ROLE_BASE_OUTPOST)
                result = fo.issueColonizeOrder(ship_id, self.target.target_id)
                if not result:
                    self.executed = False
            # colonise
            elif AIFleetOrderType.ORDER_COLONISE == self.order_type:
                fleet_id = self.fleet.target_id
                ship_id = FleetUtilsAI.get_ship_id_with_role(fleet_id, AIShipRoleType.SHIP_ROLE_CIVILIAN_COLONISATION)
                if ship_id is None:
                    ship_id = FleetUtilsAI.get_ship_id_with_role(fleet_id, AIShipRoleType.SHIP_ROLE_BASE_COLONISATION)

                planet_id = self.target.target_id
                planet = universe.getPlanet(planet_id)
                planet_name = planet and planet.name or "apparently invisible"
                result = fo.issueColonizeOrder(ship_id, planet_id)
                print "Ordered colony ship ID %d to colonize %s, got result %d" % (ship_id, planet_name, result)
                if not result:
                    self.executed = False
            # invade
            elif AIFleetOrderType.ORDER_INVADE == self.order_type:
                result = False
                planet_id = self.target.target_id
                planet = universe.getPlanet(planet_id)
                planet_name = planet and planet.name or "invisible"

                fleet_id = self.fleet.target_id
                fleet = fo.getUniverse().getFleet(fleet_id)
                detail_str = ""
                for ship_id in fleet.shipIDs:
                    ship = universe.getShip(ship_id)
                    if foAI.foAIstate.get_ship_role(ship.design.id) in [AIShipRoleType.SHIP_ROLE_MILITARY_INVASION, AIShipRoleType.SHIP_ROLE_BASE_INVASION]:
                        result = fo.issueInvadeOrder(ship_id, planet_id) or result  # will track if at least one invasion troops successfully deployed
                        shields = planet.currentMeterValue(fo.meterType.shield)
                        owner = planet.owner
                        if not result:
                            pstealth = planet.currentMeterValue(fo.meterType.stealth)
                            pop = planet.currentMeterValue(fo.meterType.population)
                            detail_str = " -- planet has %.1f stealth, shields %.1f, %.1f population and is owned by empire %d" % (pstealth, shields, pop, owner)
                        print "Ordered troop ship ID %d to invade %s, got result %d" % (ship_id, planet_name, result), detail_str
                        if not result:
                            if 'needsEmergencyExploration' not in dir(foAI.foAIstate):
                                foAI.foAIstate.needsEmergencyExploration = []
                            if fleet.systemID not in foAI.foAIstate.needsEmergencyExploration:
                                foAI.foAIstate.needsEmergencyExploration.append(fleet.systemID)
                                print "Due to trouble invading, adding system %d to Emergency Exploration List" % fleet.systemID
                                self.executed = False
                            if shields > 0 and owner == -1 and dumpTurn < fo.currentTurn():
                                dumpTurn = fo.currentTurn()
                                print "Universe Dump to debug invasions:"
                                universe.dump()
                            break
                if result:
                    print "Successfully ordered troop ship(s) to invade %s, with detail %s" % (planet_name, detail_str)
            # military
            elif AIFleetOrderType.ORDER_MILITARY == self.order_type:
                fleet_id = self.fleet.target_id
                #fo.issueFleetMoveOrder(fleet_id, self.target.target_id) #moving is already taken care of separately
                target_sys_id = self.target.target_id
                fleet = fo.getUniverse().getFleet(fleet_id)
                system_status = foAI.foAIstate.systemStatus.get(target_sys_id, {})
                if fleet and fleet.systemID == target_sys_id and not (system_status.get('fleetThreat', 0) + system_status.get('planetThreat', 0) + system_status.get('monsterThreat', 0)):
                    self.execution_completed = True

            # move or resupply
            elif self.order_type in [AIFleetOrderType.ORDER_MOVE, AIFleetOrderType.ORDER_REPAIR, AIFleetOrderType.ORDER_RESUPPLY]:
                fleet_id = self.fleet.target_id
                system_id = self.target.target_id
                fleet = fo.getUniverse().getFleet(fleet_id)
                if system_id not in [fleet.systemID, fleet.nextSystemID]:
                    if self.order_type == AIFleetOrderType.ORDER_MOVE:
                        dest_id = system_id
                    else:
                        if self.order_type == AIFleetOrderType.ORDER_REPAIR:
                            fo.issueAggressionOrder(fleet_id, False)
                        start_id = [fleet.systemID, fleet.nextSystemID][fleet.systemID == -1]
                        dest_id = MoveUtilsAI.get_safe_path_leg_to_dest(fleet_id, start_id, system_id)
                        print "fleet %d with order type(%s) sent to safe leg dest %s and ultimate dest %s" % (fleet_id, AIFleetOrderTypeNames.name(self.order_type),
                                                                                                            PlanetUtilsAI.sys_name_ids([dest_id]),
                                                                                                            PlanetUtilsAI.sys_name_ids([system_id]))
                    fo.issueFleetMoveOrder(fleet_id, dest_id)
                if system_id == fleet.systemID:
                    if foAI.foAIstate.get_fleet_role(fleet_id) == AIFleetMissionType.FLEET_MISSION_EXPLORATION:
                        if system_id in foAI.foAIstate.needsEmergencyExploration:
                            del foAI.foAIstate.needsEmergencyExploration[foAI.foAIstate.needsEmergencyExploration.index(system_id)]
                    self.execution_completed = True

            # split fleet
            elif AIFleetOrderType.ORDER_SPLIT_FLEET == self.order_type:
                fleet_id = self.fleet.target_id
                ship_id = self.target.target_id
                fleet = fo.getUniverse().getFleet(fleet_id)
                if ship_id in fleet.shipIDs:
                    fo.issueNewFleetOrder(str(ship_id), ship_id)
                self.execution_completed = True
            # attack
            elif AIFleetOrderType.ORDER_ATTACK == self.order_type:
                fleet_id = self.fleet.target_id
                fo.issueFleetMoveOrder(fleet_id, self.target.get_required_system_ai_targets()[0].target_id)