예제 #1
0
def calculatePriorities():
    "calculates the priorities of the AI player"
    print("calculating priorities")
    foAI.foAIstate.setPriority(AIPriorityType.PRIORITY_RESOURCE_RESEARCH, calculateResearchPriority())
    ColonisationAI.getColonyFleets() # sets foAI.foAIstate.colonisablePlanetIDs and foAI.foAIstate.outpostPlanetIDs
    InvasionAI.getInvasionFleets() # sets AIstate.invasionFleetIDs, AIstate.opponentPlanetIDs, and AIstate.invasionTargetedPlanetIDs
    MilitaryAI.getMilitaryFleets() # sets AIstate.militaryFleetIDs and AIstate.militaryTargetedSystemIDs

    foAI.foAIstate.setPriority(AIPriorityType.PRIORITY_RESOURCE_PRODUCTION, calculateIndustryPriority())
    foAI.foAIstate.setPriority(AIPriorityType.PRIORITY_RESOURCE_TRADE, 0)
    foAI.foAIstate.setPriority(AIPriorityType.PRIORITY_RESOURCE_CONSTRUCTION, 0)

    foAI.foAIstate.setPriority(AIPriorityType.PRIORITY_PRODUCTION_EXPLORATION, calculateExplorationPriority())
    foAI.foAIstate.setPriority(AIPriorityType.PRIORITY_PRODUCTION_OUTPOST, calculateOutpostPriority())
    foAI.foAIstate.setPriority(AIPriorityType.PRIORITY_PRODUCTION_COLONISATION, calculateColonisationPriority())
    foAI.foAIstate.setPriority(AIPriorityType.PRIORITY_PRODUCTION_INVASION, calculateInvasionPriority())
    foAI.foAIstate.setPriority(AIPriorityType.PRIORITY_PRODUCTION_MILITARY, calculateMilitaryPriority())
    foAI.foAIstate.setPriority(AIPriorityType.PRIORITY_PRODUCTION_BUILDINGS, 25)

    foAI.foAIstate.setPriority(AIPriorityType.PRIORITY_RESEARCH_LEARNING, calculateLearningPriority())
    foAI.foAIstate.setPriority(AIPriorityType.PRIORITY_RESEARCH_GROWTH, calculateGrowthPriority())
    foAI.foAIstate.setPriority(AIPriorityType.PRIORITY_RESEARCH_PRODUCTION, calculateTechsProductionPriority())
    foAI.foAIstate.setPriority(AIPriorityType.PRIORITY_RESEARCH_CONSTRUCTION, calculateConstructionPriority())
    foAI.foAIstate.setPriority(AIPriorityType.PRIORITY_RESEARCH_ECONOMICS, 0)
    foAI.foAIstate.setPriority(AIPriorityType.PRIORITY_RESEARCH_SHIPS, calculateShipsPriority())
    foAI.foAIstate.setPriority(AIPriorityType.PRIORITY_RESEARCH_DEFENSE, 0)
예제 #2
0
def generateOrders():
    print ("Genearting Orders")
    universe = fo.getUniverse()
    empire = fo.getEmpire()
    planetID = empire.capitalID
    planet = universe.getPlanet(planetID)
    print "EmpireID:    " + str(empire.empireID) + " Name: " + empire.name + " Turn: " + str(fo.currentTurn())
    print "CapitalID: " + str(planetID) + " Name: " + planet.name + " Species: " + planet.speciesName 

    # turn cleanup
    splitFleet()

    identifyShipDesigns()
    identifyFleetsRoles()
    foAIstate.clean(ExplorationAI.getHomeSystemID(), FleetUtilsAI.getEmpireFleetIDs())
    # ...missions
    # ...demands/priorities

    print("Calling AI Modules")

    # call AI modules
    PriorityAI.calculatePriorities()
    ExplorationAI.assignScoutsToExploreSystems()
    ColonisationAI.assignColonyFleetsToColonise()
    InvasionAI.assignInvasionFleetsToInvade()
    MilitaryAI.assignMilitaryFleetsToSystems()
    FleetUtilsAI.generateAIFleetOrdersForAIFleetMissions()
    FleetUtilsAI.issueAIFleetOrdersForAIFleetMissions()
    ResearchAI.generateResearchOrders()
    ProductionAI.generateProductionOrders()
    ResourcesAI.generateResourcesOrders()    

    foAIstate.afterTurnCleanup()
    fo.doneTurn()
예제 #3
0
def trooper_move_reqs_met(main_fleet_mission, order, verbose):
    """
    Indicates whether or not move requirements specific to invasion troopers are met for the provided mission and order.
    :type main_fleet_mission: AIFleetMission.AIFleetMission
    :type order: OrderMove
    :param verbose: whether to print verbose decision details
    :type verbose: bool
    :rtype: bool
    """
    # Don't advance outside of our fleet-supply zone unless the target either has no shields at all or there
    # is already a military fleet assigned to secure the target, and don't take final jump unless the planet is
    # (to the AI's knowledge) down to zero shields.  Additional checks will also be done by the later
    # generic movement code
    invasion_target = main_fleet_mission.target
    invasion_planet = invasion_target.get_object()
    invasion_system = invasion_target.get_system()
    supplied_systems = fo.getEmpire().fleetSupplyableSystemIDs
    # if about to leave supply lines
    if order.target.id not in supplied_systems or fo.getUniverse(
    ).jumpDistance(order.fleet.id, invasion_system.id) < 5:
        if invasion_planet.currentMeterValue(fo.meterType.maxShield):
            military_support_fleets = MilitaryAI.get_military_fleets_with_target_system(
                invasion_system.id)
            if not military_support_fleets:
                if verbose:
                    debug(
                        "trooper_move_reqs_met() holding Invasion fleet %d before leaving supply "
                        "because target (%s) has nonzero max shields and there is not yet a military fleet "
                        "assigned to secure the target system." %
                        (order.fleet.id, invasion_planet))
                return False

            # if there is a threat in the enemy system, do give military ships at least 1 turn to clear it
            delay_to_move_troops = 1 if MilitaryAI.get_system_local_threat(
                order.target.id) else 0

            def eta(fleet_id):
                return FleetUtilsAI.calculate_estimated_time_of_arrival(
                    fleet_id, invasion_system.id)

            eta_this_fleet = eta(order.fleet.id)
            if all(((eta_this_fleet -
                     delay_to_move_troops) <= eta(fid) and eta(fid))
                   for fid in military_support_fleets):
                if verbose:
                    debug(
                        "trooper_move_reqs_met() holding Invasion fleet %d before leaving supply "
                        "because target (%s) has nonzero max shields and no assigned military fleet would arrive"
                        "at least %d turn earlier than the invasion fleet" %
                        (order.fleet.id, invasion_planet,
                         delay_to_move_troops))
                return False

        if verbose:
            debug(
                "trooper_move_reqs_met() allowing Invasion fleet %d to leave supply "
                "because target (%s) has zero max shields or there is a military fleet assigned to secure "
                "the target system which will arrive at least 1 turn before the invasion fleet.",
                order.fleet.id, invasion_planet)
    return True
예제 #4
0
    def _portion_of_fleet_needed_here(self):
        """Calculate the portion of the fleet needed in target system considering enemy forces."""
        # TODO check rating against planets
        if assertion_fails(self.type in COMBAT_MISSION_TYPES, msg=str(self)):
            return 0
        if assertion_fails(self.target and self.target.id != INVALID_ID, msg=str(self)):
            return 0
        system_id = self.target.id
        aistate = get_aistate()
        local_defenses = MilitaryAI.get_my_defense_rating_in_system(system_id)
        potential_threat = CombatRatingsAI.combine_ratings(
            MilitaryAI.get_system_local_threat(system_id),
            MilitaryAI.get_system_neighbor_threat(system_id)
        )
        universe = fo.getUniverse()
        system = universe.getSystem(system_id)

        # tally planetary defenses
        total_defense = total_shields = 0
        for planet_id in system.planetIDs:
            planet = universe.getPlanet(planet_id)
            total_defense += planet.currentMeterValue(fo.meterType.defense)
            total_shields += planet.currentMeterValue(fo.meterType.shield)
        planetary_ratings = total_defense * (total_shields + total_defense)
        potential_threat += planetary_ratings  # TODO: rewrite to return min rating vs planets as well

        # consider safety factor just once here rather than everywhere below
        safety_factor = aistate.character.military_safety_factor()
        potential_threat *= safety_factor

        fleet_rating = CombatRatingsAI.get_fleet_rating(self.fleet.id)
        return CombatRatingsAI.rating_needed(potential_threat, local_defenses) / float(fleet_rating)
예제 #5
0
def calculatePriorities():
    "calculates the priorities of the AI player"
    print("checking statuses")
    # Industry, Research, Colony, Invasion, Military
    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_RESOURCE_PRODUCTION, 50) # let this one stay fixed & just adjust Research
    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_RESOURCE_RESEARCH, calculateResearchPriority())
    ColonisationAI.getColonyFleets() # sets foAI.foAIstate.colonisablePlanetIDs and foAI.foAIstate.outpostPlanetIDs  and many other values used by other modules
    InvasionAI.getInvasionFleets() # sets AIstate.invasionFleetIDs, AIstate.opponentPlanetIDs, and AIstate.invasionTargetedPlanetIDs
    MilitaryAI.getMilitaryFleets() # sets AIstate.militaryFleetIDs and AIstate.militaryTargetedSystemIDs

    print("calculating priorities")
    calculateIndustryPriority()#purely for reporting purposes

    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_RESOURCE_TRADE, 0)
    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_RESOURCE_CONSTRUCTION, 0)

    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_EXPLORATION, calculateExplorationPriority())
    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_OUTPOST, calculateOutpostPriority())
    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_COLONISATION, calculateColonisationPriority())
    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_INVASION, calculateInvasionPriority())
    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_MILITARY, calculateMilitaryPriority())
    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_BUILDINGS, 25)

    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_RESEARCH_LEARNING, calculateLearningPriority())
    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_RESEARCH_GROWTH, calculateGrowthPriority())
    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_RESEARCH_PRODUCTION, calculateTechsProductionPriority())
    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_RESEARCH_CONSTRUCTION, calculateConstructionPriority())
    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_RESEARCH_ECONOMICS, 0)
    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_RESEARCH_SHIPS, calculateShipsPriority())
    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_RESEARCH_DEFENSE, 0)
예제 #6
0
def calculate_priorities():
    """Calculates the priorities of the AI player."""
    debug("\n=== Preparing to Calculate Priorities ===")
    prioritiees_timer.start("setting Production Priority")
    aistate = get_aistate()
    # let this one stay fixed & just adjust Research and Influence
    aistate.set_priority(PriorityType.RESOURCE_PRODUCTION, 50)
    # RESOURCE_INFLUENCE priority is calculated in PolicyAI

    debug("\n*** Calculating Research Priority ***\n")
    prioritiees_timer.start("setting Research Priority")
    aistate.set_priority(
        PriorityType.RESOURCE_RESEARCH,
        _calculate_research_priority())  # TODO: do univ _survey before this

    debug("\n*** Updating Colonization Status ***\n")
    prioritiees_timer.start("Evaluating Colonization Status")
    ColonisationAI.get_colony_fleets(
    )  # sets aistate.colonisablePlanetIDs and many other values used by other modules

    debug("\n*** Updating Invasion Status ***\n")
    prioritiees_timer.start("Evaluating Invasion Status")
    InvasionAI.get_invasion_fleets(
    )  # sets AIstate.opponentPlanetIDs, and AIstate.invasionTargetedPlanetIDs

    debug("\n*** Updating Military Status ***\n")
    prioritiees_timer.start("Evaluating Military Status")
    MilitaryAI.get_military_fleets()

    debug("\n** Calculating Production Priorities ***\n")
    prioritiees_timer.start("reporting Production Priority")
    _calculate_industry_priority()  # purely for reporting purposes
    prioritiees_timer.start("setting Exploration Priority")

    aistate.set_priority(PriorityType.RESOURCE_TRADE, 0)
    aistate.set_priority(PriorityType.RESOURCE_CONSTRUCTION, 0)

    aistate.set_priority(PriorityType.PRODUCTION_EXPLORATION,
                         _calculate_exploration_priority())
    prioritiees_timer.start("setting Colony Priority")
    aistate.set_priority(PriorityType.PRODUCTION_COLONISATION,
                         _calculate_colonisation_priority())
    prioritiees_timer.start("setting Outpost Priority")
    aistate.set_priority(PriorityType.PRODUCTION_OUTPOST,
                         _calculate_outpost_priority())
    prioritiees_timer.start("setting Invasion Priority")
    aistate.set_priority(PriorityType.PRODUCTION_INVASION,
                         _calculate_invasion_priority())
    prioritiees_timer.start("setting Military Priority")
    aistate.set_priority(PriorityType.PRODUCTION_MILITARY,
                         _calculate_military_priority())
    prioritiees_timer.start("setting other priorities")
    aistate.set_priority(PriorityType.PRODUCTION_BUILDINGS, 25)

    prioritiees_timer.stop_print_and_clear()
예제 #7
0
def calculate_priorities():
    """Calculates the priorities of the AI player."""
    print "\n", 10 * "=", "Preparing to Calculate Priorities", 10 * "="
    prioritiees_timer.start('setting Production Priority')
    foAI.foAIstate.set_priority(PriorityType.RESOURCE_PRODUCTION, 50)  # let this one stay fixed & just adjust Research

    print "\n*** Calculating Research Priority ***\n"
    prioritiees_timer.start('setting Research Priority')
    foAI.foAIstate.set_priority(PriorityType.RESOURCE_RESEARCH, _calculate_research_priority())  # TODO: do univ _survey before this

    print "\n*** Updating Colonization Status ***\n"
    prioritiees_timer.start('Evaluating Colonization Status')
    ColonisationAI.get_colony_fleets()  # sets foAI.foAIstate.colonisablePlanetIDs and foAI.foAIstate.outpostPlanetIDs and many other values used by other modules

    print "\n*** Updating Invasion Status ***\n"
    prioritiees_timer.start('Evaluating Invasion Status')
    InvasionAI.get_invasion_fleets()  # sets AIstate.invasionFleetIDs, AIstate.opponentPlanetIDs, and AIstate.invasionTargetedPlanetIDs

    print "\n*** Updating Military Status ***\n"
    prioritiees_timer.start('Evaluating Military Status')
    MilitaryAI.get_military_fleets()

    print("\n** Calculating Production Priorities ***\n")
    prioritiees_timer.start('reporting Production Priority')
    _calculate_industry_priority()  # purely for reporting purposes
    prioritiees_timer.start('setting Exploration Priority')

    foAI.foAIstate.set_priority(PriorityType.RESOURCE_TRADE, 0)
    foAI.foAIstate.set_priority(PriorityType.RESOURCE_CONSTRUCTION, 0)

    foAI.foAIstate.set_priority(PriorityType.PRODUCTION_EXPLORATION, _calculate_exploration_priority())
    prioritiees_timer.start('setting Colony Priority')
    foAI.foAIstate.set_priority(PriorityType.PRODUCTION_COLONISATION, _calculate_colonisation_priority())
    prioritiees_timer.start('setting Outpost Priority')
    foAI.foAIstate.set_priority(PriorityType.PRODUCTION_OUTPOST, _calculate_outpost_priority())
    prioritiees_timer.start('setting Invasion Priority')
    foAI.foAIstate.set_priority(PriorityType.PRODUCTION_INVASION, _calculate_invasion_priority())
    prioritiees_timer.start('setting Military Priority')
    foAI.foAIstate.set_priority(PriorityType.PRODUCTION_MILITARY, _calculate_military_priority())
    prioritiees_timer.start('setting other priorities')
    foAI.foAIstate.set_priority(PriorityType.PRODUCTION_BUILDINGS, 25)

    foAI.foAIstate.set_priority(PriorityType.RESEARCH_LEARNING, _calculate_learning_priority())
    foAI.foAIstate.set_priority(PriorityType.RESEARCH_GROWTH, _calculate_growth_priority())
    foAI.foAIstate.set_priority(PriorityType.RESEARCH_PRODUCTION, _calculate_techs_production_priority())
    foAI.foAIstate.set_priority(PriorityType.RESEARCH_CONSTRUCTION, _calculate_construction_priority())
    foAI.foAIstate.set_priority(PriorityType.RESEARCH_ECONOMICS, 0)
    foAI.foAIstate.set_priority(PriorityType.RESEARCH_SHIPS, _calculate_ships_priority())
    foAI.foAIstate.set_priority(PriorityType.RESEARCH_DEFENSE, 0)
    prioritiees_timer.stop_print_and_clear()
예제 #8
0
def trooper_move_reqs_met(main_fleet_mission, order, verbose):
    """
    Indicates whether or not move requirements specific to invasion troopers are met for the provided mission and order.
    :type main_fleet_mission: AIFleetMission.AIFleetMission
    :type order: OrderMove
    :param verbose: whether to print verbose decision details
    :type verbose: bool
    :rtype: bool
    """
    # Don't advance outside of our fleet-supply zone unless the target either has no shields at all or there
    # is already a military fleet assigned to secure the target, and don't take final jump unless the planet is
    # (to the AI's knowledge) down to zero shields.  Additional checks will also be done by the later
    # generic movement code
    invasion_target = main_fleet_mission.target
    invasion_planet = invasion_target.get_object()
    invasion_system = invasion_target.get_system()
    supplied_systems = fo.getEmpire().fleetSupplyableSystemIDs
    # if about to leave supply lines
    if order.target.id not in supplied_systems or fo.getUniverse().jumpDistance(order.fleet.id, invasion_system.id) < 5:
        if invasion_planet.currentMeterValue(fo.meterType.maxShield):
            military_support_fleets = MilitaryAI.get_military_fleets_with_target_system(invasion_system.id)
            if not military_support_fleets:
                if verbose:
                    print ("trooper_move_reqs_met() holding Invasion fleet %d before leaving supply "
                           "because target (%s) has nonzero max shields and there is not yet a military fleet "
                           "assigned to secure the target system.") % (order.fleet.id, invasion_planet)
                return False

            # if there is a threat in the enemy system, do give military ships at least 1 turn to clear it
            delay_to_move_troops = 1 if MilitaryAI.get_system_local_threat(order.target.id) else 0

            def eta(fleet_id):
                return FleetUtilsAI.calculate_estimated_time_of_arrival(fleet_id, invasion_system.id)

            eta_this_fleet = eta(order.fleet.id)
            if all(((eta_this_fleet - delay_to_move_troops) <= eta(fid) and eta(fid))
                   for fid in military_support_fleets):
                if verbose:
                    print ("trooper_move_reqs_met() holding Invasion fleet %d before leaving supply "
                           "because target (%s) has nonzero max shields and no assigned military fleet would arrive"
                           "at least %d turn earlier than the invasion fleet") % (
                                order.fleet.id, invasion_planet, delay_to_move_troops)
                return False

        if verbose:
            print ("trooper_move_reqs_met() allowing Invasion fleet %d to leave supply "
                   "because target (%s) has zero max shields or there is a military fleet assigned to secure "
                   "the target system which will arrive at least 1 turn before the invasion fleet.") % (order.fleet.id,
                                                                                                        invasion_planet)
    return True
예제 #9
0
def calculate_priorities():
    """calculates the priorities of the AI player"""
    print ("checking statuses")
    # Industry, Research, Colony, Invasion, Military

    prioritiees_timer.start("setting Production Priority")
    foAI.foAIstate.set_priority(
        EnumsAI.AIPriorityType.PRIORITY_RESOURCE_PRODUCTION, 50
    )  # let this one stay fixed & just adjust Research
    prioritiees_timer.start("setting Research Priority")
    foAI.foAIstate.set_priority(
        EnumsAI.AIPriorityType.PRIORITY_RESOURCE_RESEARCH, calculateResearchPriority()
    )  # TODO: do univ _survey before this
    prioritiees_timer.start("Evaluating Colonization Status")

    ColonisationAI.get_colony_fleets()  # sets foAI.foAIstate.colonisablePlanetIDs and foAI.foAIstate.outpostPlanetIDs and many other values used by other modules
    prioritiees_timer.start("Evaluating Invasion Status")
    InvasionAI.get_invasion_fleets()  # sets AIstate.invasionFleetIDs, AIstate.opponentPlanetIDs, and AIstate.invasionTargetedPlanetIDs
    prioritiees_timer.start("Evaluating Military Status")
    MilitaryAI.get_military_fleets()  # sets AIstate.militaryFleetIDs and AIstate.militaryTargetedSystemIDs
    prioritiees_timer.start("reporting Production Priority")
    print ("calculating priorities")
    calculateIndustryPriority()  # purely for reporting purposes
    prioritiees_timer.start("setting Exploration Priority")

    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_RESOURCE_TRADE, 0)
    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_RESOURCE_CONSTRUCTION, 0)

    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_EXPLORATION, calculateExplorationPriority())
    prioritiees_timer.start("setting Colony Priority")
    foAI.foAIstate.set_priority(
        EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_COLONISATION, calculateColonisationPriority()
    )
    prioritiees_timer.start("setting Outpost Priority")
    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_OUTPOST, calculateOutpostPriority())
    prioritiees_timer.start("setting Invasion Priority")
    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_INVASION, calculateInvasionPriority())
    prioritiees_timer.start("setting Military Priority")
    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_MILITARY, calculateMilitaryPriority())
    prioritiees_timer.start("setting other priorities")
    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_BUILDINGS, 25)

    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_RESEARCH_LEARNING, calculateLearningPriority())
    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_RESEARCH_GROWTH, calculateGrowthPriority())
    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_RESEARCH_PRODUCTION, calculateTechsProductionPriority())
    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_RESEARCH_CONSTRUCTION, calculateConstructionPriority())
    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_RESEARCH_ECONOMICS, 0)
    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_RESEARCH_SHIPS, calculateShipsPriority())
    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_RESEARCH_DEFENSE, 0)
    prioritiees_timer.end()
예제 #10
0
    def _need_repair(self):
        """
        Check if fleet need repair. Check if fleet HP is less of cutoff.
        TODO make more clever implementation.
        """
        repair_limit = 0.70

        universe = fo.getUniverse()
        fleet_id = self.target_id
        # if combat fleet, use military repair check
        if foAI.foAIstate.get_fleet_role(fleet_id) in COMBAT_MISSION_TYPES:
            return fleet_id in MilitaryAI.avail_mil_needing_repair([fleet_id],
                                                                   False,
                                                                   True)[0]
        fleet = universe.getFleet(fleet_id)
        ships_cur_health = 0
        ships_max_health = 0

        for ship_id in fleet.shipIDs:
            this_ship = universe.getShip(ship_id)
            ships_cur_health += this_ship.currentMeterValue(
                fo.meterType.structure)
            ships_max_health += this_ship.currentMeterValue(
                fo.meterType.maxStructure)
        return ships_cur_health >= repair_limit * ships_max_health
예제 #11
0
    def _need_repair(self, repair_limit=0.70):
        """Check if fleet needs to be repaired.

         If the fleet is already at a system where it can be repaired, stay there until fully repaired.
         Otherwise, repair if fleet health is below specified *repair_limit*.
         For military fleets, there is a special evaluation called, cf. *MilitaryAI.avail_mil_needing_repair()*

         :param repair_limit: percentage of health below which the fleet is sent to repair
         :type repair_limit: float
         :return: True if fleet needs repair
         :rtype: bool
        """
        # TODO: More complex evaluation if fleet needs repair (consider self-repair, distance, threat, mission...)
        fleet_id = self.fleet.id
        # if we are already at a system where we can repair, make sure we use it...
        system = self.fleet.get_system()
        # TODO starlane obstruction is not considered in the next call
        nearest_dock = MoveUtilsAI.get_best_drydock_system_id(system.id, fleet_id)
        if nearest_dock == system.id:
            repair_limit = 0.99
        # if combat fleet, use military repair check
        if get_aistate().get_fleet_role(fleet_id) in COMBAT_MISSION_TYPES:
            return fleet_id in MilitaryAI.avail_mil_needing_repair([fleet_id], on_mission=bool(self.orders),
                                                                   repair_limit=repair_limit)[0]
        # TODO: Allow to split fleet to send only damaged ships to repair
        ships_cur_health, ships_max_health = FleetUtilsAI.get_current_and_max_structure(fleet_id)
        return ships_cur_health < repair_limit * ships_max_health
예제 #12
0
    def can_issue_order(self, verbose=False):
        if not super(OrderMove, self).can_issue_order(verbose=verbose):
            return False
        # TODO: figure out better way to have invasions (& possibly colonizations) require visibility on target without needing visibility of all intermediate systems
        # if False and main_mission_type not in [AIFleetMissionType.FLEET_MISSION_ATTACK,  # TODO: consider this later
        #                                      AIFleetMissionType.FLEET_MISSION_MILITARY,
        #                                      AIFleetMissionType.FLEET_MISSION_SECURE,
        #                                      AIFleetMissionType.FLEET_MISSION_HIT_AND_RUN,
        #                                      AIFleetMissionType.FLEET_MISSION_EXPLORATION]:
        #     if not universe.getVisibility(target_id, foAI.foAIstate.empireID) >= fo.visibility.partial:
        #         #if not target_id in interior systems
        #         foAI.foAIstate.needsEmergencyExploration.append(fleet.systemID)
        #         return False
        system_id = self.fleet.get_system().id
        if system_id == self.target.get_system().id:
            return True  # TODO: already there, but could consider retreating

        fleet_rating = foAI.foAIstate.get_rating(self.fleet.id).get('overall', 0)
        target_sys_status = foAI.foAIstate.systemStatus.get(self.target.id, {})
        f_threat = target_sys_status.get('fleetThreat', 0)
        m_threat = target_sys_status.get('monsterThreat', 0)
        p_threat = target_sys_status.get('planetThreat', 0)
        threat = f_threat + m_threat + p_threat
        safety_factor = MilitaryAI.get_safety_factor()
        universe = fo.getUniverse()
        if fleet_rating >= safety_factor * threat:
            return True
        elif not p_threat and self.target.id in fo.getEmpire().supplyUnobstructedSystems:
                    return True
        else:
            sys1 = universe.getSystem(system_id)
            sys1_name = sys1 and sys1.name or "unknown"
            targ1 = self.target.get_system()
            targ1_name = (targ1 and targ1.get_object().name) or "unknown"
            # following line was poor because AIstate.militaryFleetIDs only covers fleets without current missions
            # my_other_fleet_rating = sum([foAI.foAIstate.fleetStatus.get(fleet_id, {}).get('rating', 0) for fleet_id in foAI.foAIstate.militaryFleetIDs if ( foAI.foAIstate.fleetStatus.get(fleet_id, {}).get('sysID', -1) == thisSystemID ) ])
            # myOtherFleetsRatings = [foAI.foAIstate.fleetStatus.get(fid, {}).get('rating', {}) for fid in foAI.foAIstate.systemStatus.get(target_id, {}).get('myfleets', [])]
            # my_other_fleet_rating = sum([foAI.foAIstate.fleetStatus.get(fid, {}).get('rating', 0) for fid in foAI.foAIstate.systemStatus.get( target_id, {}).get('myfleets', []) ])
            my_other_fleet_rating = foAI.foAIstate.systemStatus.get(self.target.id, {}).get('myFleetRating', 0)  # TODO: adjust calc for any departing fleets
            is_military = foAI.foAIstate.get_fleet_role(self.fleet.id) == AIFleetMissionType.FLEET_MISSION_MILITARY
            if ((my_other_fleet_rating > 3 * safety_factor * threat) or
                        (is_military and my_other_fleet_rating + fleet_rating > safety_factor * threat) or
                        (is_military and my_other_fleet_rating + fleet_rating > 0.8 * safety_factor * threat and fleet_rating > 0.2 * threat)):
                if verbose:
                    print "\tAdvancing fleet %d (rating %d) at system %d (%s) into system %d (%s) with threat %d because of sufficient empire fleet strength already at destination" % (
                        self.fleet.id, fleet_rating, system_id, sys1_name, self.target.id, targ1_name, threat)
                return True
            elif threat == p_threat and not self.fleet.get_object().aggressive and not my_other_fleet_rating and not target_sys_status.get('localEnemyFleetIDs', [-1]):
                if verbose:
                    print ("\tAdvancing fleet %d (rating %d) at system %d (%s) into system %d (%s) with planet threat %d because nonaggressive" +
                           " and no other fleets present to trigger combat") % (self.fleet.id, fleet_rating, system_id, sys1_name, self.target.id, targ1_name, threat)
                return True
            else:
                if verbose:
                    print "\tHolding fleet %d (rating %d) at system %d (%s) before travelling to system %d (%s) with threat %d" % (self.fleet.id, fleet_rating, system_id, sys1_name, self.target.id, targ1_name, threat)
                needs_vis = foAI.foAIstate.misc.setdefault('needs_vis', [])
                if self.target.id not in needs_vis:
                    needs_vis.append(self.target.id)
                return False
        return True
예제 #13
0
def _revise_threat_factor(
    threat_factor: float,
    planet_value: float,
    system_id: int,
    min_planet_value: float = MINIMUM_COLONY_SCORE,
) -> float:
    """
    Check if the threat_factor should be made less severe.

    If the AI does have enough total military to secure this system, and the target has more than minimal value,
    don't let the threat_factor discount the adjusted value below min_planet_value +1, so that if there are no
    other targets the AI could still pursue this one.  Otherwise, scoring pressure from
    MilitaryAI.get_preferred_max_military_portion_for_single_battle might prevent the AI from pursuing a heavily
    defended but still obtainable target even if it has no softer locations available.

    :param threat_factor: the base threat factor
    :param planet_value: the planet score
    :param system_id: the system ID of subject planet
    :param min_planet_value: a floor planet value if the AI has enough military to secure the system
    :return: the (potentially) revised threat_factor
    """

    # the default value below for fleetThreat shouldn't come in to play, but is just to be absolutely sure we don't
    # send colony ships into some system for which we have not evaluated fleetThreat
    system_status = get_aistate().systemStatus.get(system_id, {})
    system_fleet_treat = system_status.get("fleetThreat", 1000)
    # TODO: consider taking area threat into account here.  Arguments can be made both ways, see discussion in PR2069
    sys_total_threat = system_fleet_treat + system_status.get(
        "monsterThreat", 0) + system_status.get("planetThreat", 0)
    if (MilitaryAI.get_concentrated_tot_mil_rating() >
            sys_total_threat) and (planet_value > 2 * min_planet_value):
        threat_factor = max(threat_factor,
                            (min_planet_value + 1) / planet_value)
    return threat_factor
예제 #14
0
def _calculate_exploration_priority():
    """Calculates the demand for scouts by unexplored systems."""
    empire = fo.getEmpire()
    num_unexplored_systems = len(ExplorationAI.borderUnexploredSystemIDs)
    num_scouts = sum([foAI.foAIstate.fleetStatus.get(fid, {}).get('nships', 0) for fid in FleetUtilsAI.get_empire_fleet_ids_by_role(
        MissionType.EXPLORATION)])
    production_queue = empire.productionQueue
    queued_scout_ships = 0
    for queue_index in range(0, len(production_queue)):
        element = production_queue[queue_index]
        if element.buildType == EmpireProductionTypes.BT_SHIP:
            if foAI.foAIstate.get_ship_role(element.designID) == ShipRoleType.CIVILIAN_EXPLORATION:
                queued_scout_ships += element.remaining * element.blocksize

    mil_ships = MilitaryAI.get_num_military_ships()
    # intent of the following calc is essentially
    # new_scouts_needed = min(need_cap_A, need_cap_B, base_need) - already_got_or_queued
    # where need_cap_A is to help prevent scouting needs from swamping military needs, and
    # need_cap_B is to help regulate investment into scouting while the empire is small.
    # These caps could perhaps instead be tied more directly to military priority and
    # total empire production.
    desired_number_of_scouts = int(min(4 + mil_ships/5, 4 + fo.currentTurn()/50.0, 2 + num_unexplored_systems**0.5))
    scouts_needed = max(0, desired_number_of_scouts - (num_scouts + queued_scout_ships))
    exploration_priority = int(40 * scouts_needed)

    print
    print "Number of Scouts: %s" % num_scouts
    print "Number of Unexplored systems: %s" % num_unexplored_systems
    print "Military size: %s" % mil_ships
    print "Priority for scouts: %s" % exploration_priority

    return exploration_priority
예제 #15
0
파일: AIstate.py 프로젝트: Vezzra/freeorion
    def get_fleet_role(self, fleet_id, force_new=False):
        """Returns fleet role by ID."""

        if not force_new and fleet_id in self.__fleetRoleByID:
            return self.__fleetRoleByID[fleet_id]
        else:
            role = FleetUtilsAI.assess_fleet_role(fleet_id)
            self.__fleetRoleByID[fleet_id] = role
            make_aggressive = False
            if role in [MissionType.COLONISATION,
                        MissionType.OUTPOST,
                        MissionType.ORBITAL_INVASION,
                        MissionType.ORBITAL_OUTPOST
                        ]:
                pass
            elif role in [MissionType.EXPLORATION,
                          MissionType.INVASION
                          ]:
                this_rating = self.get_rating(fleet_id)  # Done!
                n_ships = self.fleetStatus.get(fleet_id, {}).get('nships', 1)  # entry sould exist due to above line
                if float(this_rating) / n_ships >= 0.5 * MilitaryAI.cur_best_mil_ship_rating():
                    make_aggressive = True
            else:
                make_aggressive = True
            fo.issueAggressionOrder(fleet_id, make_aggressive)
            return role
예제 #16
0
def _calculate_exploration_priority():
    """Calculates the demand for scouts by unexplored systems."""
    empire = fo.getEmpire()
    num_unexplored_systems = len(ExplorationAI.border_unexplored_system_ids)
    num_scouts = sum([foAI.foAIstate.fleetStatus.get(fid, {}).get('nships', 0) for fid in FleetUtilsAI.get_empire_fleet_ids_by_role(
        MissionType.EXPLORATION)])
    production_queue = empire.productionQueue
    queued_scout_ships = 0
    for queue_index in range(0, len(production_queue)):
        element = production_queue[queue_index]
        if element.buildType == EmpireProductionTypes.BT_SHIP:
            if foAI.foAIstate.get_ship_role(element.designID) == ShipRoleType.CIVILIAN_EXPLORATION:
                queued_scout_ships += element.remaining * element.blocksize

    mil_ships = MilitaryAI.get_num_military_ships()
    # intent of the following calc is essentially
    # new_scouts_needed = min(need_cap_A, need_cap_B, base_need) - already_got_or_queued
    # where need_cap_A is to help prevent scouting needs from swamping military needs, and
    # need_cap_B is to help regulate investment into scouting while the empire is small.
    # These caps could perhaps instead be tied more directly to military priority and
    # total empire production.
    desired_number_of_scouts = int(min(4 + mil_ships/5, 4 + fo.currentTurn()/50.0, 2 + num_unexplored_systems**0.5))
    scouts_needed = max(0, desired_number_of_scouts - (num_scouts + queued_scout_ships))
    exploration_priority = int(40 * scouts_needed)

    print
    print "Number of Scouts: %s" % num_scouts
    print "Number of Unexplored systems: %s" % num_unexplored_systems
    print "Military size: %s" % mil_ships
    print "Priority for scouts: %s" % exploration_priority

    return exploration_priority
예제 #17
0
    def get_fleet_role(self, fleet_id, force_new=False):
        """Returns fleet role by ID."""

        if not force_new and fleet_id in self.__fleetRoleByID:
            return self.__fleetRoleByID[fleet_id]
        else:
            role = FleetUtilsAI.assess_fleet_role(fleet_id)
            self.__fleetRoleByID[fleet_id] = role
            make_aggressive = False
            if role in [MissionType.COLONISATION,
                        MissionType.OUTPOST,
                        MissionType.ORBITAL_INVASION,
                        MissionType.ORBITAL_OUTPOST
                        ]:
                pass
            elif role in [MissionType.EXPLORATION,
                          MissionType.INVASION
                          ]:
                this_rating = self.get_rating(fleet_id)  # Done!
                n_ships = self.fleetStatus.get(fleet_id, {}).get('nships', 1)  # entry sould exist due to above line
                if float(this_rating) / n_ships >= 0.5 * MilitaryAI.cur_best_mil_ship_rating():
                    make_aggressive = True
            else:
                make_aggressive = True
            fo.issueAggressionOrder(fleet_id, make_aggressive)
            return role
예제 #18
0
    def _need_repair(self, repair_limit=0.70):
        """Check if fleet needs to be repaired.

         If the fleet is already at a system where it can be repaired, stay there until fully repaired.
         Otherwise, repair if fleet health is below specified *repair_limit*.
         For military fleets, there is a special evaluation called, cf. *MilitaryAI.avail_mil_needing_repair()*

         :param repair_limit: percentage of health below which the fleet is sent to repair
         :type repair_limit: float
         :return: True if fleet needs repair
         :rtype: bool
        """
        # TODO: More complex evaluation if fleet needs repair (consider self-repair, distance, threat, mission...)
        fleet_id = self.fleet.id
        # if we are already at a system where we can repair, make sure we use it...
        system = self.fleet.get_system()
        # TODO starlane obstruction is not considered in the next call
        nearest_dock = MoveUtilsAI.get_best_drydock_system_id(
            system.id, fleet_id)
        if nearest_dock == system.id:
            repair_limit = 0.99
        # if combat fleet, use military repair check
        if get_aistate().get_fleet_role(fleet_id) in COMBAT_MISSION_TYPES:
            return fleet_id in MilitaryAI.avail_mil_needing_repair(
                [fleet_id],
                on_mission=bool(self.orders),
                repair_limit=repair_limit)[0]
        # TODO: Allow to split fleet to send only damaged ships to repair
        ships_cur_health, ships_max_health = FleetUtilsAI.get_current_and_max_structure(
            fleet_id)
        return ships_cur_health < repair_limit * ships_max_health
예제 #19
0
    def _check_abort_mission(self, fleet_order: AIFleetOrder):
        """checks if current mission (targeting a planet) should be aborted"""
        planet_stealthed = False
        target_is_planet = fleet_order.target and isinstance(
            fleet_order.target, TargetPlanet)
        planet = None
        if target_is_planet:
            planet = fleet_order.target.get_object()
            # Check visibility prediction, but if somehow still have current visibility, don't
            # abort the mission yet
            if not EspionageAI.colony_detectable_by_empire(
                    planet.id, empire=fo.empireID()):
                if get_partial_visibility_turn(planet.id) == fo.currentTurn():
                    debug(
                        "EspionageAI predicts planet id %d to be stealthed" %
                        planet.id +
                        ", but somehow have current visibity anyway, so won't trigger mission abort"
                    )
                else:
                    debug(
                        "EspionageAI predicts we can no longer detect %s, will abort mission"
                        % fleet_order.target)
                    planet_stealthed = True
        if target_is_planet and not planet_stealthed:
            # TBD use fleet_order.is_valid or add fleet_order.should_abort
            if isinstance(fleet_order, OrderColonize):
                if planet.initialMeterValue(fo.meterType.population) == 0 and (
                        planet.ownedBy(fo.empireID()) or planet.unowned):
                    return False
            elif isinstance(fleet_order, OrderOutpost):
                if planet.unowned:
                    return False
            elif isinstance(fleet_order, OrderInvade):
                if planet.owner == fo.getEmpire().empireID:
                    debug(
                        f"Abandoning invasion for {planet}, it already belongs to us"
                    )
                    return True
                if planet.currentMeterValue(fo.meterType.maxShield):
                    military_support_fleets = MilitaryAI.get_military_fleets_with_target_system(
                        planet.systemID)
                    if not military_support_fleets:
                        # Maybe try again later...
                        debug(
                            f"Abandoning Invasion mission for {planet} because target has nonzero max shields "
                            f"and there is no military fleet assigned to secure the target system."
                        )
                        return True
                return False
            else:
                return False

        # canceling fleet orders
        debug("   %s" % fleet_order)
        debug(
            "Fleet %d had a target planet that is no longer valid for this mission; aborting."
            % self.fleet.id)
        FleetUtilsAI.split_fleet(self.fleet.id)
        return True
예제 #20
0
    def check_mergers(self, context=""):
        """
        Merge local fleets with same mission into this fleet.

        :param context: Context of the function call for logging purposes
        :type context: str
        """
        debug("Considering to merge %s", self.__str__())
        if self.type not in MERGEABLE_MISSION_TYPES:
            debug("Mission type does not allow merging.")
            return

        if not self.target:
            debug("Mission has no valid target - do not merge.")
            return

        universe = fo.getUniverse()
        empire_id = fo.empireID()

        fleet_id = self.fleet.id
        main_fleet = universe.getFleet(fleet_id)
        main_fleet_system_id = main_fleet.systemID
        if main_fleet_system_id == INVALID_ID:
            debug("Can't merge: fleet in middle of starlane.")
            return

        # only merge PROTECT_REGION if there is any threat near target
        if self.type == MissionType.PROTECT_REGION:
            neighbor_systems = universe.getImmediateNeighbors(
                self.target.id, empire_id)
            if not any(
                    MilitaryAI.get_system_local_threat(sys_id)
                    for sys_id in neighbor_systems):
                debug("Not merging PROTECT_REGION fleet - no threat nearby.")
                return

        destroyed_list = set(universe.destroyedObjectIDs(empire_id))
        aistate = get_aistate()
        system_status = aistate.systemStatus[main_fleet_system_id]
        other_fleets_here = [
            fid for fid in system_status.get('myFleetsAccessible', [])
            if fid != fleet_id and fid not in destroyed_list
            and universe.getFleet(fid).ownedBy(empire_id)
        ]
        if not other_fleets_here:
            debug("No other fleets here")
            return

        for fid in other_fleets_here:
            fleet_mission = aistate.get_fleet_mission(fid)
            if fleet_mission.type != self.type or fleet_mission.target != self.target:
                debug("Local candidate %s does not have same mission." %
                      fleet_mission)
                continue
            FleetUtilsAI.merge_fleet_a_into_b(
                fid,
                fleet_id,
                context="Order %s of mission %s" % (context, self))
예제 #21
0
def calculate_priorities():
    """calculates the priorities of the AI player"""
    print("checking statuses")
    # Industry, Research, Colony, Invasion, Military

    prioritiees_timer.start('setting Production Priority')
    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_RESOURCE_PRODUCTION, 50) # let this one stay fixed & just adjust Research
    prioritiees_timer.start('setting Research Priority')
    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_RESOURCE_RESEARCH, calculateResearchPriority()) #TODO: do univ _survey before this
    prioritiees_timer.start('Evaluating Colonization Status')

    ColonisationAI.get_colony_fleets() # sets foAI.foAIstate.colonisablePlanetIDs and foAI.foAIstate.outpostPlanetIDs and many other values used by other modules
    prioritiees_timer.start('Evaluating Invasion Status')
    InvasionAI.get_invasion_fleets() # sets AIstate.invasionFleetIDs, AIstate.opponentPlanetIDs, and AIstate.invasionTargetedPlanetIDs
    prioritiees_timer.start('Evaluating Military Status')
    MilitaryAI.get_military_fleets() # sets AIstate.militaryFleetIDs and AIstate.militaryTargetedSystemIDs
    prioritiees_timer.start('reporting Production Priority')
    print("calculating priorities")
    calculateIndustryPriority()#purely for reporting purposes
    prioritiees_timer.start('setting Exploration Priority')

    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_RESOURCE_TRADE, 0)
    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_RESOURCE_CONSTRUCTION, 0)

    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_EXPLORATION, calculateExplorationPriority())
    prioritiees_timer.start('setting Colony Priority')
    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_COLONISATION, calculateColonisationPriority())
    prioritiees_timer.start('setting Outpost Priority')
    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_OUTPOST, calculateOutpostPriority())
    prioritiees_timer.start('setting Invasion Priority')
    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_INVASION, calculateInvasionPriority())
    prioritiees_timer.start('setting Military Priority')
    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_MILITARY, calculateMilitaryPriority())
    prioritiees_timer.start('setting other priorities')
    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_BUILDINGS, 25)

    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_RESEARCH_LEARNING, calculateLearningPriority())
    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_RESEARCH_GROWTH, calculateGrowthPriority())
    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_RESEARCH_PRODUCTION, calculateTechsProductionPriority())
    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_RESEARCH_CONSTRUCTION, calculateConstructionPriority())
    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_RESEARCH_ECONOMICS, 0)
    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_RESEARCH_SHIPS, calculateShipsPriority())
    foAI.foAIstate.set_priority(EnumsAI.AIPriorityType.PRIORITY_RESEARCH_DEFENSE, 0)
    prioritiees_timer.end()
예제 #22
0
def calculate_priorities():
    """Calculates the priorities of the AI player."""
    print "\n", 10 * "=", "Preparing to Calculate Priorities", 10 * "="
    prioritiees_timer.start('setting Production Priority')
    foAI.foAIstate.set_priority(PriorityType.RESOURCE_PRODUCTION, 50)  # let this one stay fixed & just adjust Research

    print "\n*** Calculating Research Priority ***\n"
    prioritiees_timer.start('setting Research Priority')
    foAI.foAIstate.set_priority(PriorityType.RESOURCE_RESEARCH, _calculate_research_priority())  # TODO: do univ _survey before this

    print "\n*** Updating Colonization Status ***\n"
    prioritiees_timer.start('Evaluating Colonization Status')
    ColonisationAI.get_colony_fleets()  # sets foAI.foAIstate.colonisablePlanetIDs and many other values used by other modules

    print "\n*** Updating Invasion Status ***\n"
    prioritiees_timer.start('Evaluating Invasion Status')
    InvasionAI.get_invasion_fleets()  # sets AIstate.opponentPlanetIDs, and AIstate.invasionTargetedPlanetIDs

    print "\n*** Updating Military Status ***\n"
    prioritiees_timer.start('Evaluating Military Status')
    MilitaryAI.get_military_fleets()

    print("\n** Calculating Production Priorities ***\n")
    prioritiees_timer.start('reporting Production Priority')
    _calculate_industry_priority()  # purely for reporting purposes
    prioritiees_timer.start('setting Exploration Priority')

    foAI.foAIstate.set_priority(PriorityType.RESOURCE_TRADE, 0)
    foAI.foAIstate.set_priority(PriorityType.RESOURCE_CONSTRUCTION, 0)

    foAI.foAIstate.set_priority(PriorityType.PRODUCTION_EXPLORATION, _calculate_exploration_priority())
    prioritiees_timer.start('setting Colony Priority')
    foAI.foAIstate.set_priority(PriorityType.PRODUCTION_COLONISATION, _calculate_colonisation_priority())
    prioritiees_timer.start('setting Outpost Priority')
    foAI.foAIstate.set_priority(PriorityType.PRODUCTION_OUTPOST, _calculate_outpost_priority())
    prioritiees_timer.start('setting Invasion Priority')
    foAI.foAIstate.set_priority(PriorityType.PRODUCTION_INVASION, _calculate_invasion_priority())
    prioritiees_timer.start('setting Military Priority')
    foAI.foAIstate.set_priority(PriorityType.PRODUCTION_MILITARY, _calculate_military_priority())
    prioritiees_timer.start('setting other priorities')
    foAI.foAIstate.set_priority(PriorityType.PRODUCTION_BUILDINGS, 25)

    prioritiees_timer.stop_print_and_clear()
예제 #23
0
def _determine_colony_threat_factor(planet_id, spec_name, existing_presence):
    universe = fo.getUniverse()
    planet = universe.getPlanet(planet_id)
    if not planet:  # should have been checked previously, but belt-and-suspenders
        error("Can't retrieve planet ID %d" % planet_id)
        return 0
    sys_status = get_aistate().systemStatus.get(planet.systemID, {})
    cur_best_mil_ship_rating = max(MilitaryAI.cur_best_mil_ship_rating(),
                                   0.001)
    local_defenses = sys_status.get("all_local_defenses", 0)
    local_threat = sys_status.get("fleetThreat", 0) + sys_status.get(
        "monsterThreat", 0)
    neighbor_threat = sys_status.get("neighborThreat", 0)
    jump2_threat = 0.6 * max(
        0,
        sys_status.get("jump2_threat", 0) -
        sys_status.get("my_neighbor_rating", 0))
    area_threat = neighbor_threat + jump2_threat
    area_threat *= 2.0 / (
        existing_presence + 2
    )  # once we have a foothold be less scared off by area threats
    # TODO: evaluate detectability by specific source of area threat, also consider if the subject AI already has
    # researched techs that would grant a stealth bonus
    local_enemies = sys_status.get("enemies_nearly_supplied", [])
    # could more conservatively base detection on get_aistate().misc.get("observed_empires")
    if not EspionageAI.colony_detectable_by_empire(
            planet_id, spec_name, empire=local_enemies, default_result=True):
        area_threat *= 0.05
    net_threat = max(0, local_threat + area_threat - local_defenses)
    # even if our military has lost all warships, rate planets as if we have at least one
    reference_rating = max(
        cur_best_mil_ship_rating,
        MilitaryAI.get_preferred_max_military_portion_for_single_battle() *
        MilitaryAI.get_concentrated_tot_mil_rating(),
    )
    threat_factor = min(1.0, reference_rating / (net_threat + 0.001))**2
    if threat_factor < 0.5:
        mil_ref_string = "Military rating reference: %.1f" % reference_rating
        debug(
            "Significant threat discounting %2d%% at %s, local defense: %.1f, local threat %.1f, area threat %.1f"
            % (100 * (1 - threat_factor), planet.name, local_defenses,
               local_threat, area_threat) + mil_ref_string)
    return threat_factor
예제 #24
0
    def check_mergers(self, context=""):
        """
        Merge local fleets with same mission into this fleet.

        :param context: Context of the function call for logging purposes
        :type context: str
        """
        debug("Considering to merge %s", self.__str__())
        if self.type not in MERGEABLE_MISSION_TYPES:
            debug("Mission type does not allow merging.")
            return

        if not self.target:
            debug("Mission has no valid target - do not merge.")
            return

        universe = fo.getUniverse()
        empire_id = fo.empireID()

        fleet_id = self.fleet.id
        main_fleet = universe.getFleet(fleet_id)
        main_fleet_system_id = main_fleet.systemID
        if main_fleet_system_id == INVALID_ID:
            debug("Can't merge: fleet in middle of starlane.")
            return

        # only merge PROTECT_REGION if there is any threat near target
        if self.type == MissionType.PROTECT_REGION:
            neighbor_systems = universe.getImmediateNeighbors(self.target.id, empire_id)
            if not any(MilitaryAI.get_system_local_threat(sys_id)
                       for sys_id in neighbor_systems):
                debug("Not merging PROTECT_REGION fleet - no threat nearby.")
                return

        destroyed_list = set(universe.destroyedObjectIDs(empire_id))
        aistate = get_aistate()
        system_status = aistate.systemStatus[main_fleet_system_id]
        other_fleets_here = [fid for fid in system_status.get('myFleetsAccessible', []) if fid != fleet_id and
                             fid not in destroyed_list and universe.getFleet(fid).ownedBy(empire_id)]
        if not other_fleets_here:
            debug("No other fleets here")
            return

        for fid in other_fleets_here:
            fleet_mission = aistate.get_fleet_mission(fid)
            if fleet_mission.type != self.type or fleet_mission.target != self.target:
                debug("Local candidate %s does not have same mission." % fleet_mission)
                continue
            FleetUtilsAI.merge_fleet_a_into_b(fid, fleet_id, context="Order %s of mission %s" % (context, self))
예제 #25
0
    def _need_repair(self):
        """
        Check if fleet need repair. Check if fleet HP is less of cutoff.
        TODO make more clever implementation.
        """
        repair_limit = 0.70

        universe = fo.getUniverse()
        fleet_id = self.fleet.id
        # if combat fleet, use military repair check
        if foAI.foAIstate.get_fleet_role(fleet_id) in COMBAT_MISSION_TYPES:
            return fleet_id in MilitaryAI.avail_mil_needing_repair([fleet_id], False, bool(self.orders))[0]
        fleet = universe.getFleet(fleet_id)
        ships_cur_health = 0
        ships_max_health = 0

        for ship_id in fleet.shipIDs:
            this_ship = universe.getShip(ship_id)
            ships_cur_health += this_ship.currentMeterValue(fo.meterType.structure)
            ships_max_health += this_ship.currentMeterValue(fo.meterType.maxStructure)
        return ships_cur_health < repair_limit * ships_max_health
예제 #26
0
def evaluate_invasion_planet(planet_id, secure_fleet_missions, verbose=True):
    """Return the invasion value (score, troops) of a planet."""
    detail = []
    building_values = {"BLD_IMPERIAL_PALACE": 1000,
                       "BLD_CULTURE_ARCHIVES": 1000,
                       "BLD_AUTO_HISTORY_ANALYSER": 100,
                       "BLD_SHIPYARD_BASE": 100,
                       "BLD_SHIPYARD_ORG_ORB_INC": 200,
                       "BLD_SHIPYARD_ORG_XENO_FAC": 200,
                       "BLD_SHIPYARD_ORG_CELL_GRO_CHAMB": 200,
                       "BLD_SHIPYARD_CON_NANOROBO": 300,
                       "BLD_SHIPYARD_CON_GEOINT": 400,
                       "BLD_SHIPYARD_CON_ADV_ENGINE": 1000,
                       "BLD_SHIPYARD_AST": 300,
                       "BLD_SHIPYARD_AST_REF": 1000,
                       "BLD_SHIPYARD_ENRG_SOLAR": 1500,
                       "BLD_INDUSTRY_CENTER": 500,
                       "BLD_GAS_GIANT_GEN": 200,
                       "BLD_SOL_ORB_GEN": 800,
                       "BLD_BLACK_HOLE_POW_GEN": 2000,
                       "BLD_ENCLAVE_VOID": 500,
                       "BLD_NEUTRONIUM_EXTRACTOR": 2000,
                       "BLD_NEUTRONIUM_SYNTH": 2000,
                       "BLD_NEUTRONIUM_FORGE": 1000,
                       "BLD_CONC_CAMP": 100,
                       "BLD_BIOTERROR_PROJECTOR": 1000,
                       "BLD_SHIPYARD_ENRG_COMP": 3000,
                       }
    # TODO: add more factors, as used for colonization
    universe = fo.getUniverse()
    empire_id = fo.empireID()
    max_jumps = 8
    planet = universe.getPlanet(planet_id)
    if planet is None:  # TODO: exclude planets with stealth higher than empireDetection
        print "invasion AI couldn't access any info for planet id %d" % planet_id
        return [0, 0]

    sys_partial_vis_turn = get_partial_visibility_turn(planet.systemID)
    planet_partial_vis_turn = get_partial_visibility_turn(planet_id)

    if planet_partial_vis_turn < sys_partial_vis_turn:
        print "invasion AI couldn't get current info on planet id %d (was stealthed at last sighting)" % planet_id
        # TODO: track detection strength, order new scouting when it goes up
        return [0, 0]  # last time we had partial vis of the system, the planet was stealthed to us

    species_name = planet.speciesName
    species = fo.getSpecies(species_name)
    if not species or AIDependencies.TAG_DESTROYED_ON_CONQUEST in species.tags:
        # this call iterates over this Empire's available species with which it could colonize after an invasion
        planet_eval = ColonisationAI.assign_colonisation_values([planet_id], MissionType.INVASION, None, detail)
        pop_val = max(0.75 * planet_eval.get(planet_id, [0])[0],
                      ColonisationAI.evaluate_planet(planet_id, MissionType.OUTPOST, None, detail))
    else:
        pop_val = ColonisationAI.evaluate_planet(planet_id, MissionType.INVASION, species_name, detail)

    bld_tally = 0
    for bldType in [universe.getBuilding(bldg).buildingTypeName for bldg in planet.buildingIDs]:
        bval = building_values.get(bldType, 50)
        bld_tally += bval
        detail.append("%s: %d" % (bldType, bval))

    tech_tally = 0
    for unlocked_tech in AIDependencies.SPECIES_TECH_UNLOCKS.get(species_name, []):
        if not tech_is_complete(unlocked_tech):
            rp_cost = fo.getTech(unlocked_tech).researchCost(empire_id)
            tech_tally += rp_cost * 4
            detail.append("%s: %d" % (unlocked_tech, rp_cost * 4))

    p_sys_id = planet.systemID
    capitol_id = PlanetUtilsAI.get_capital()
    least_jumps_path = []
    clear_path = True
    if capitol_id:
        homeworld = universe.getPlanet(capitol_id)
        if homeworld:
            home_system_id = homeworld.systemID
            eval_system_id = planet.systemID
            if (home_system_id != INVALID_ID) and (eval_system_id != INVALID_ID):
                least_jumps_path = list(universe.leastJumpsPath(home_system_id, eval_system_id, empire_id))
                max_jumps = len(least_jumps_path)
    system_status = foAI.foAIstate.systemStatus.get(p_sys_id, {})
    system_fleet_treat = system_status.get('fleetThreat', 1000)
    system_monster_threat = system_status.get('monsterThreat', 0)
    sys_total_threat = system_fleet_treat + system_monster_threat + system_status.get('planetThreat', 0)
    max_path_threat = system_fleet_treat
    mil_ship_rating = MilitaryAI.cur_best_mil_ship_rating()
    for path_sys_id in least_jumps_path:
        path_leg_status = foAI.foAIstate.systemStatus.get(path_sys_id, {})
        path_leg_threat = path_leg_status.get('fleetThreat', 1000) + path_leg_status.get('monsterThreat', 0)
        if path_leg_threat > 0.5 * mil_ship_rating:
            clear_path = False
            if path_leg_threat > max_path_threat:
                max_path_threat = path_leg_threat

    pop = planet.currentMeterValue(fo.meterType.population)
    target_pop = planet.currentMeterValue(fo.meterType.targetPopulation)
    troops = planet.currentMeterValue(fo.meterType.troops)
    max_troops = planet.currentMeterValue(fo.meterType.maxTroops)
    # TODO: refactor troop determination into function for use in mid-mission updates and also consider defender techs
    max_troops += AIDependencies.TROOPS_PER_POP * (target_pop - pop)

    this_system = universe.getSystem(p_sys_id)
    secure_targets = [p_sys_id] + list(this_system.planetIDs)
    system_secured = False
    for mission in secure_fleet_missions:
        if system_secured:
            break
        secure_fleet_id = mission.fleet.id
        s_fleet = universe.getFleet(secure_fleet_id)
        if not s_fleet or s_fleet.systemID != p_sys_id:
            continue
        if mission.type == MissionType.SECURE:
            target_obj = mission.target.get_object()
            if target_obj is not None and target_obj.id in secure_targets:
                system_secured = True
                break
    system_secured = system_secured and system_status.get('myFleetRating', 0)

    if verbose:
        print ("Invasion eval of %s\n"
               " - maxShields: %.1f\n"
               " - sysFleetThreat: %.1f\n"
               " - sysMonsterThreat: %.1f") % (
            planet, planet.currentMeterValue(fo.meterType.maxShield), system_fleet_treat,
            system_monster_threat)
    supply_val = 0
    enemy_val = 0
    if planet.owner != -1:  # value in taking this away from an enemy
        enemy_val = 20 * (planet.currentMeterValue(fo.meterType.targetIndustry) +
                          2*planet.currentMeterValue(fo.meterType.targetResearch))
    if p_sys_id in ColonisationAI.annexable_system_ids:  # TODO: extend to rings
        supply_val = 100
    elif p_sys_id in state.get_systems_by_supply_tier(-1):
        supply_val = 200
    elif p_sys_id in state.get_systems_by_supply_tier(-2):
        supply_val = 300
    elif p_sys_id in state.get_systems_by_supply_tier(-3):
        supply_val = 400
    if max_path_threat > 0.5 * mil_ship_rating:
        if max_path_threat < 3 * mil_ship_rating:
            supply_val *= 0.5
        else:
            supply_val *= 0.2

    # devalue invasions that would require too much military force
    threat_factor = min(1, 0.2*MilitaryAI.get_tot_mil_rating()/(sys_total_threat+0.001))**2

    design_id, _, locs = ProductionAI.get_best_ship_info(PriorityType.PRODUCTION_INVASION)
    if not locs or not universe.getPlanet(locs[0]):
        # We are in trouble anyway, so just calculate whatever approximation...
        build_time = 4
        planned_troops = troops if system_secured else min(troops + max_jumps + build_time, max_troops)
        planned_troops += .01  # we must attack with more troops than there are defenders
        troop_cost = math.ceil((planned_troops+_TROOPS_SAFETY_MARGIN) / 6.0) * 20 * FleetUtilsAI.get_fleet_upkeep()
    else:
        loc = locs[0]
        species_here = universe.getPlanet(loc).speciesName
        design = fo.getShipDesign(design_id)
        cost_per_ship = design.productionCost(empire_id, loc)
        build_time = design.productionTime(empire_id, loc)
        troops_per_ship = CombatRatingsAI.weight_attack_troops(design.troopCapacity,
                                                               CombatRatingsAI.get_species_troops_grade(species_here))
        planned_troops = troops if system_secured else min(troops + max_jumps + build_time, max_troops)
        planned_troops += .01  # we must attack with more troops than there are defenders
        ships_needed = math.ceil((planned_troops+_TROOPS_SAFETY_MARGIN) / float(troops_per_ship))
        troop_cost = ships_needed * cost_per_ship  # fleet upkeep is already included in query from server

    # apply some bias to expensive operations
    normalized_cost = float(troop_cost) / max(fo.getEmpire().productionPoints, 1)
    normalized_cost = max(1., normalized_cost)
    cost_score = (normalized_cost**2 / 50.0) * troop_cost

    base_score = pop_val + supply_val + bld_tally + tech_tally + enemy_val - cost_score
    planet_score = retaliation_risk_factor(planet.owner) * threat_factor * max(0, base_score)
    if clear_path:
        planet_score *= 1.5
    if verbose:
        print (' - planet score: %.2f\n'
               ' - troop score: %.2f\n'
               ' - projected troop cost: %.1f\n'
               ' - threat factor: %s\n'
               ' - planet detail: %s\n'
               ' - popval: %.1f\n'
               ' - supplyval: %.1f\n'
               ' - bldval: %s\n'
               ' - enemyval: %s') % (planet_score, planned_troops, troop_cost,
                                     threat_factor, detail, pop_val, supply_val, bld_tally, enemy_val)
    return [planet_score, planned_troops]
예제 #27
0
    def issue_fleet_orders(self):
        """issues AIFleetOrders which can be issued in system and moves to next one if is possible"""
        # TODO: priority
        order_completed = True
        print
        print "Checking orders for fleet %s (on turn %d), with mission type %s" % (
            self.fleet.get_object(), fo.currentTurn(), self.type
            or 'No mission')
        if MissionType.INVASION == self.type:
            self._check_retarget_invasion()
        for fleet_order in self.orders:
            print "Checking order: %s" % fleet_order
            if isinstance(
                    fleet_order,
                (OrderColonize, OrderOutpost, OrderInvade)):  # TODO: invasion?
                if self._check_abort_mission(fleet_order):
                    print "Aborting fleet order %s" % fleet_order
                    return
            self.check_mergers(context=str(fleet_order))
            if fleet_order.can_issue_order(verbose=False):
                if isinstance(
                        fleet_order, OrderMove
                ) and order_completed:  # only move if all other orders completed
                    print "Issuing fleet order %s" % fleet_order
                    fleet_order.issue_order()
                elif not isinstance(fleet_order, OrderMove):
                    print "Issuing fleet order %s" % fleet_order
                    fleet_order.issue_order()
                else:
                    print "NOT issuing (even though can_issue) fleet order %s" % fleet_order
                print "Order issued: %s" % fleet_order.order_issued
                if not fleet_order.order_issued:
                    order_completed = False
            else:  # check that we're not held up by a Big Monster
                if fleet_order.order_issued:
                    # It's unclear why we'd really get to this spot, but it has been observed to happen, perhaps due to
                    # game being reloaded after code changes.
                    # Go on to the next order.
                    continue
                print "CAN'T issue fleet order %s" % fleet_order
                if isinstance(fleet_order, OrderMove):
                    this_system_id = fleet_order.target.id
                    this_status = foAI.foAIstate.systemStatus.setdefault(
                        this_system_id, {})
                    if this_status.get('monsterThreat', 0) > fo.currentTurn(
                    ) * MilitaryAI.cur_best_mil_ship_rating() / 4.0:
                        if (self.type not in (
                                MissionType.MILITARY, MissionType.SECURE
                        ) or fleet_order != self.orders[
                                -1]  # if this move order is not this mil fleet's final destination, and blocked by Big Monster, release and hope for more effective reassignment
                            ):
                            print "Aborting mission due to being blocked by Big Monster at system %d, threat %d" % (
                                this_system_id, foAI.foAIstate.
                                systemStatus[this_system_id]['monsterThreat'])
                            print "Full set of orders were:"
                            for this_order in self.orders:
                                print " - %s" % this_order
                            self.clear_fleet_orders()
                            self.clear_target()
                            return
            # moving to another system stops issuing all orders in system where fleet is
            # move order is also the last order in system
            if isinstance(fleet_order, OrderMove):
                fleet = self.fleet.get_object()
                if fleet.systemID != fleet_order.target.id:
                    break
        else:  # went through entire order list
            if order_completed:
                print "Final order is completed"
                orders = self.orders
                last_order = orders[-1] if orders else None
                universe = fo.getUniverse()

                if last_order and isinstance(last_order, OrderColonize):
                    planet = universe.getPlanet(last_order.target.id)
                    sys_partial_vis_turn = universe.getVisibilityTurnsMap(
                        planet.systemID,
                        fo.empireID()).get(fo.visibility.partial, -9999)
                    planet_partial_vis_turn = universe.getVisibilityTurnsMap(
                        planet.id, fo.empireID()).get(fo.visibility.partial,
                                                      -9999)
                    if planet_partial_vis_turn == sys_partial_vis_turn and not planet.currentMeterValue(
                            fo.meterType.population):
                        print "Potential Error: Fleet %d has tentatively completed its colonize mission but will wait to confirm population." % self.fleet.id
                        print "    Order details are %s" % last_order
                        print "    Order is valid: %s; issued: %s; executed: %s" % (
                            last_order.is_valid(), last_order.order_issued,
                            last_order.executed)
                        if not last_order.is_valid():
                            source_target = last_order.fleet
                            target_target = last_order.target
                            print "        source target validity: %s; target target validity: %s " % (
                                bool(source_target), bool(target_target))
                        return  # colonize order must not have completed yet
                clear_all = True
                last_sys_target = -1
                if last_order and isinstance(last_order, OrderMilitary):
                    last_sys_target = last_order.target.id
                    # if (MissionType.SECURE == self.type) or # not doing this until decide a way to release from a SECURE mission
                    secure_targets = set(AIstate.colonyTargetedSystemIDs +
                                         AIstate.outpostTargetedSystemIDs +
                                         AIstate.invasionTargetedSystemIDs +
                                         AIstate.blockadeTargetedSystemIDs)
                    if last_sys_target in secure_targets:  # consider a secure mission
                        if last_sys_target in AIstate.colonyTargetedSystemIDs:
                            secure_type = "Colony"
                        elif last_sys_target in AIstate.outpostTargetedSystemIDs:
                            secure_type = "Outpost"
                        elif last_sys_target in AIstate.invasionTargetedSystemIDs:
                            secure_type = "Invasion"
                        elif last_sys_target in AIstate.blockadeTargetedSystemIDs:
                            secure_type = "Blockade"
                        else:
                            secure_type = "Unidentified"
                        print "Fleet %d has completed initial stage of its mission to secure system %d (targeted for %s), may release a portion of ships" % (
                            self.fleet.id, last_sys_target, secure_type)
                        clear_all = False
                fleet_id = self.fleet.id
                if clear_all:
                    if orders:
                        print "Fleet %d has completed its mission; clearing all orders and targets." % self.fleet.id
                        print "Full set of orders were:"
                        for this_order in orders:
                            print "\t\t %s" % this_order
                        self.clear_fleet_orders()
                        self.clear_target()
                        if foAI.foAIstate.get_fleet_role(fleet_id) in (
                                MissionType.MILITARY, MissionType.SECURE):
                            allocations = MilitaryAI.get_military_fleets(
                                mil_fleets_ids=[fleet_id],
                                try_reset=False,
                                thisround="Fleet %d Reassignment" % fleet_id)
                            if allocations:
                                MilitaryAI.assign_military_fleets_to_systems(
                                    use_fleet_id_list=[fleet_id],
                                    allocations=allocations)
                    else:  # no orders
                        print "No Current Orders"
                else:
                    # TODO: evaluate releasing a smaller portion or none of the ships
                    system_status = foAI.foAIstate.systemStatus.setdefault(
                        last_sys_target, {})
                    new_fleets = []
                    threat_present = (system_status.get('totalThreat', 0) !=
                                      0) or (system_status.get(
                                          'neighborThreat', 0) != 0)
                    target_system = universe.getSystem(last_sys_target)
                    if not threat_present and target_system:
                        for pid in target_system.planetIDs:
                            planet = universe.getPlanet(pid)
                            if planet and planet.owner != fo.empireID(
                            ) and planet.currentMeterValue(
                                    fo.meterType.maxDefense) > 0:
                                threat_present = True
                                break
                    if not threat_present:
                        print "No current threat in target system; releasing a portion of ships."
                        new_fleets = FleetUtilsAI.split_fleet(
                            self.fleet.id
                        )  # at least first stage of current task is done; release extra ships for potential other deployments
                    else:
                        print "Threat remains in target system; NOT releasing any ships."
                    new_military_fleets = []
                    for fleet_id in new_fleets:
                        if foAI.foAIstate.get_fleet_role(
                                fleet_id) in COMBAT_MISSION_TYPES:
                            new_military_fleets.append(fleet_id)
                    allocations = []
                    if new_military_fleets:
                        allocations = MilitaryAI.get_military_fleets(
                            mil_fleets_ids=new_military_fleets,
                            try_reset=False,
                            thisround="Fleet Reassignment %s" %
                            new_military_fleets)
                    if allocations:
                        MilitaryAI.assign_military_fleets_to_systems(
                            use_fleet_id_list=new_military_fleets,
                            allocations=allocations)
예제 #28
0
    def can_issue_order(self, verbose=False):
        if not super(OrderMove, self).can_issue_order(verbose=verbose):
            return False
        # TODO: figure out better way to have invasions (& possibly colonizations) require visibility on target without needing visibility of all intermediate systems
        # if False and main_mission_type not in [MissionType.ATTACK,  # TODO: consider this later
        #                                        MissionType.MILITARY,
        #                                        MissionType.SECURE,
        #                                        MissionType.HIT_AND_RUN,
        #                                        MissionType.EXPLORATION]:
        #     if not universe.getVisibility(target_id, foAI.foAIstate.empireID) >= fo.visibility.partial:
        #         #if not target_id in interior systems
        #         foAI.foAIstate.needsEmergencyExploration.append(fleet.systemID)
        #         return False
        system_id = self.fleet.get_system().id
        if system_id == self.target.get_system().id:
            return True  # TODO: already there, but could consider retreating

        fleet_rating = foAI.foAIstate.get_rating(self.fleet.id).get(
            'overall', 0)
        target_sys_status = foAI.foAIstate.systemStatus.get(self.target.id, {})
        f_threat = target_sys_status.get('fleetThreat', 0)
        m_threat = target_sys_status.get('monsterThreat', 0)
        p_threat = target_sys_status.get('planetThreat', 0)
        threat = f_threat + m_threat + p_threat
        safety_factor = MilitaryAI.get_safety_factor()
        universe = fo.getUniverse()
        if fleet_rating >= safety_factor * threat:
            return True
        elif not p_threat and self.target.id in fo.getEmpire(
        ).supplyUnobstructedSystems:
            return True
        else:
            sys1 = universe.getSystem(system_id)
            sys1_name = sys1 and sys1.name or "unknown"
            target_system = self.target.get_system()
            target_system_name = (target_system and
                                  target_system.get_object().name) or "unknown"
            my_other_fleet_rating = foAI.foAIstate.systemStatus.get(
                self.target.id,
                {}).get('myFleetRating',
                        0)  # TODO: adjust calc for any departing fleets
            is_military = foAI.foAIstate.get_fleet_role(
                self.fleet.id) == MissionType.MILITARY

            total_rating = my_other_fleet_rating + fleet_rating
            if any(
                ((my_other_fleet_rating > 3 * safety_factor * threat),
                 (is_military and total_rating > safety_factor * threat),
                 (is_military and total_rating > 0.8 * safety_factor * threat
                  and fleet_rating > 0.2 * threat))):
                if verbose:
                    print "\tAdvancing fleet %d (rating %d) at system %d (%s) into system %d (%s) with threat %d because of sufficient empire fleet strength already at destination" % (
                        self.fleet.id, fleet_rating, system_id, sys1_name,
                        self.target.id, target_system_name, threat)
                return True
            elif threat == p_threat and not self.fleet.get_object(
            ).aggressive and not my_other_fleet_rating and not target_sys_status.get(
                    'localEnemyFleetIDs', [-1]):
                if verbose:
                    print(
                        "\tAdvancing fleet %d (rating %d) at system %d (%s) into system %d (%s) with planet threat %d because nonaggressive"
                        + " and no other fleets present to trigger combat") % (
                            self.fleet.id, fleet_rating, system_id, sys1_name,
                            self.target.id, target_system_name, threat)
                return True
            else:
                if verbose:
                    print "\tHolding fleet %d (rating %d) at system %d (%s) before travelling to system %d (%s) with threat %d" % (
                        self.fleet.id, fleet_rating, system_id, sys1_name,
                        self.target.id, target_system_name, threat)
                needs_vis = foAI.foAIstate.misc.setdefault('needs_vis', [])
                if self.target.id not in needs_vis:
                    needs_vis.append(self.target.id)
                return False
        return True
예제 #29
0
def calculatePriorities():
    "calculates the priorities of the AI player"
    print("checking statuses")
    # Industry, Research, Colony, Invasion, Military
    times=[]
    tasks = []
    times.append( time() )
    tasks.append("init")
    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_RESOURCE_PRODUCTION, 50) # let this one stay fixed & just adjust Research
    times.append( time() )
    tasks.append( "setting Production Priority" )
    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_RESOURCE_RESEARCH, calculateResearchPriority())
    times.append( time() )
    tasks.append(  "setting Research Priority")
    ColonisationAI.getColonyFleets() # sets foAI.foAIstate.colonisablePlanetIDs and foAI.foAIstate.outpostPlanetIDs  and many other values used by other modules
    times.append( time() )
    tasks.append(  "Evaluating Colonization Status")
    InvasionAI.getInvasionFleets() # sets AIstate.invasionFleetIDs, AIstate.opponentPlanetIDs, and AIstate.invasionTargetedPlanetIDs
    times.append( time() )
    tasks.append(  "Evaluating Invasion Status")
    MilitaryAI.getMilitaryFleets() # sets AIstate.militaryFleetIDs and AIstate.militaryTargetedSystemIDs
    times.append( time() )
    tasks.append(  "Evaluating Military Status")

    print("calculating priorities")
    calculateIndustryPriority()#purely for reporting purposes
    times.append( time() )
    tasks.append(  "reporting Production Priority")

    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_RESOURCE_TRADE, 0)
    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_RESOURCE_CONSTRUCTION, 0)

    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_EXPLORATION, calculateExplorationPriority())
    times.append( time() )
    tasks.append(  "setting Exploration Priority")
    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_OUTPOST, calculateOutpostPriority())
    times.append( time() )
    tasks.append(  "setting Outpost Priority")
    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_COLONISATION, calculateColonisationPriority())
    times.append( time() )
    tasks.append(  "setting Colony Priority")
    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_INVASION, calculateInvasionPriority())
    times.append( time() )
    tasks.append(  "setting Invasion Priority")
    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_MILITARY, calculateMilitaryPriority())
    times.append( time() )
    tasks.append(  "setting Military Priority")
    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_BUILDINGS, 25)

    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_RESEARCH_LEARNING, calculateLearningPriority())
    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_RESEARCH_GROWTH, calculateGrowthPriority())
    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_RESEARCH_PRODUCTION, calculateTechsProductionPriority())
    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_RESEARCH_CONSTRUCTION, calculateConstructionPriority())
    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_RESEARCH_ECONOMICS, 0)
    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_RESEARCH_SHIPS, calculateShipsPriority())
    foAI.foAIstate.setPriority(EnumsAI.AIPriorityType.PRIORITY_RESEARCH_DEFENSE, 0)
    times.append( time() )
    tasks.append(  "total processing")
    
    for t_index in range(1, len(times)-1):
        print "calculatePriorities(): %40s took %d msec"%(tasks[t_index],  int(1000*(times[t_index]-times[t_index-1])))
    print "calculatePriorities(): %40s took %d msec"%(tasks[-1],  int(1000*(times[-1]-times[0])))
예제 #30
0
    def issue_fleet_orders(self):
        """issues AIFleetOrders which can be issued in system and moves to next one if is possible"""
        # TODO: priority
        order_completed = True
        print
        print "Checking orders for fleet %s (on turn %d), with mission type %s" % (self.fleet.get_object(), fo.currentTurn(), self.type or 'No mission')
        if MissionType.INVASION == self.type:
            self._check_retarget_invasion()
        for fleet_order in self.orders:
            print "Checking order: %s" % fleet_order
            if isinstance(fleet_order, (OrderColonize, OrderOutpost, OrderInvade)):  # TODO: invasion?
                if self._check_abort_mission(fleet_order):
                    print "Aborting fleet order %s" % fleet_order
                    return
            self.check_mergers(context=str(fleet_order))
            if fleet_order.can_issue_order(verbose=False):
                if isinstance(fleet_order, OrderMove) and order_completed:  # only move if all other orders completed
                    print "Issuing fleet order %s" % fleet_order
                    fleet_order.issue_order()
                elif not isinstance(fleet_order, OrderMove):
                    print "Issuing fleet order %s" % fleet_order
                    fleet_order.issue_order()
                else:
                    print "NOT issuing (even though can_issue) fleet order %s" % fleet_order
                print "Order issued: %s" % fleet_order.order_issued
                if not fleet_order.order_issued:
                    order_completed = False
            else:  # check that we're not held up by a Big Monster
                if fleet_order.order_issued:
                    # It's unclear why we'd really get to this spot, but it has been observed to happen, perhaps due to
                    # game being reloaded after code changes.
                    # Go on to the next order.
                    continue
                print "CAN'T issue fleet order %s" % fleet_order
                if isinstance(fleet_order, OrderMove):
                    this_system_id = fleet_order.target.id
                    this_status = foAI.foAIstate.systemStatus.setdefault(this_system_id, {})
                    if this_status.get('monsterThreat', 0) > fo.currentTurn() * MilitaryAI.cur_best_mil_ship_rating() / 4.0:
                        if (self.type not in (MissionType.MILITARY,
                                              MissionType.SECURE) or
                            fleet_order != self.orders[-1]  # if this move order is not this mil fleet's final destination, and blocked by Big Monster, release and hope for more effective reassignment
                            ):
                            print "Aborting mission due to being blocked by Big Monster at system %d, threat %d" % (this_system_id, foAI.foAIstate.systemStatus[this_system_id]['monsterThreat'])
                            print "Full set of orders were:"
                            for this_order in self.orders:
                                print " - %s" % this_order
                            self.clear_fleet_orders()
                            self.clear_target()
                            return
            # moving to another system stops issuing all orders in system where fleet is
            # move order is also the last order in system
            if isinstance(fleet_order, OrderMove):
                fleet = self.fleet.get_object()
                if fleet.systemID != fleet_order.target.id:
                    break
        else:  # went through entire order list
            if order_completed:
                print "Final order is completed"
                orders = self.orders
                last_order = orders[-1] if orders else None
                universe = fo.getUniverse()

                if last_order and isinstance(last_order, OrderColonize):
                    planet = universe.getPlanet(last_order.target.id)
                    sys_partial_vis_turn = universe.getVisibilityTurnsMap(planet.systemID, fo.empireID()).get(fo.visibility.partial, -9999)
                    planet_partial_vis_turn = universe.getVisibilityTurnsMap(planet.id, fo.empireID()).get(fo.visibility.partial, -9999)
                    if planet_partial_vis_turn == sys_partial_vis_turn and not planet.currentMeterValue(fo.meterType.population):
                        print "Potential Error: Fleet %d has tentatively completed its colonize mission but will wait to confirm population." % self.fleet.id
                        print "    Order details are %s" % last_order
                        print "    Order is valid: %s; issued: %s; executed: %s" % (last_order.is_valid(), last_order.order_issued, last_order.executed)
                        if not last_order.is_valid():
                            source_target = last_order.fleet
                            target_target = last_order.target
                            print "        source target validity: %s; target target validity: %s " % (bool(source_target), bool(target_target))
                        return  # colonize order must not have completed yet
                clear_all = True
                last_sys_target = -1
                if last_order and isinstance(last_order, OrderMilitary):
                    last_sys_target = last_order.target.id
                    # if (MissionType.SECURE == self.type) or # not doing this until decide a way to release from a SECURE mission
                    secure_targets = set(AIstate.colonyTargetedSystemIDs + AIstate.outpostTargetedSystemIDs + AIstate.invasionTargetedSystemIDs + AIstate.blockadeTargetedSystemIDs)
                    if last_sys_target in secure_targets:  # consider a secure mission
                        if last_sys_target in AIstate.colonyTargetedSystemIDs:
                            secure_type = "Colony"
                        elif last_sys_target in AIstate.outpostTargetedSystemIDs:
                            secure_type = "Outpost"
                        elif last_sys_target in AIstate.invasionTargetedSystemIDs:
                            secure_type = "Invasion"
                        elif last_sys_target in AIstate.blockadeTargetedSystemIDs:
                            secure_type = "Blockade"
                        else:
                            secure_type = "Unidentified"
                        print "Fleet %d has completed initial stage of its mission to secure system %d (targeted for %s), may release a portion of ships" % (self.fleet.id, last_sys_target, secure_type)
                        clear_all = False
                fleet_id = self.fleet.id
                if clear_all:
                    if orders:
                        print "Fleet %d has completed its mission; clearing all orders and targets." % self.fleet.id
                        print "Full set of orders were:"
                        for this_order in orders:
                            print "\t\t %s" % this_order
                        self.clear_fleet_orders()
                        self.clear_target()
                        if foAI.foAIstate.get_fleet_role(fleet_id) in (MissionType.MILITARY,
                                                                       MissionType.SECURE):
                            allocations = MilitaryAI.get_military_fleets(mil_fleets_ids=[fleet_id], try_reset=False, thisround="Fleet %d Reassignment" % fleet_id)
                            if allocations:
                                MilitaryAI.assign_military_fleets_to_systems(use_fleet_id_list=[fleet_id], allocations=allocations)
                    else:  # no orders
                        print "No Current Orders"
                else:
                    # TODO: evaluate releasing a smaller portion or none of the ships
                    system_status = foAI.foAIstate.systemStatus.setdefault(last_sys_target, {})
                    new_fleets = []
                    threat_present = (system_status.get('totalThreat', 0) != 0) or (system_status.get('neighborThreat', 0) != 0)
                    target_system = universe.getSystem(last_sys_target)
                    if not threat_present and target_system:
                        for pid in target_system.planetIDs:
                            planet = universe.getPlanet(pid)
                            if planet and planet.owner != fo.empireID() and planet.currentMeterValue(fo.meterType.maxDefense) > 0:
                                threat_present = True
                                break
                    if not threat_present:
                        print "No current threat in target system; releasing a portion of ships."
                        new_fleets = FleetUtilsAI.split_fleet(self.fleet.id)  # at least first stage of current task is done; release extra ships for potential other deployments
                    else:
                        print "Threat remains in target system; NOT releasing any ships."
                    new_military_fleets = []
                    for fleet_id in new_fleets:
                        if foAI.foAIstate.get_fleet_role(fleet_id) in COMBAT_MISSION_TYPES:
                            new_military_fleets.append(fleet_id)
                    allocations = []
                    if new_military_fleets:
                        allocations = MilitaryAI.get_military_fleets(mil_fleets_ids=new_military_fleets, try_reset=False, thisround="Fleet Reassignment %s" % new_military_fleets)
                    if allocations:
                        MilitaryAI.assign_military_fleets_to_systems(use_fleet_id_list=new_military_fleets, allocations=allocations)
예제 #31
0
파일: AIstate.py 프로젝트: MatGB/freeorion
    def update_system_status(self):
        print 10 * "=", "Updating System Threats", 10 * "="
        universe = fo.getUniverse()
        empire = fo.getEmpire()
        empire_id = fo.empireID()
        destroyed_object_ids = universe.destroyedObjectIDs(empire_id)
        supply_unobstructed_systems = set(empire.supplyUnobstructedSystems)
        min_hidden_attack = 4
        min_hidden_health = 8
        system_id_list = universe.systemIDs  # will normally look at this, the list of all known systems

        # for use in debugging
        verbose = False

        # assess enemy fleets that may have been momentarily visible
        cur_e_fighters = {CombatRatingsAI.default_ship_stats().get_stats(hashable=True): [0]}  # start with a dummy entry
        old_e_fighters = {CombatRatingsAI.default_ship_stats().get_stats(hashable=True): [0]}  # start with a dummy entry
        enemy_fleet_ids = []
        enemies_by_system = {}
        my_fleets_by_system = {}
        fleet_spot_position = {}
        saw_enemies_at_system = {}
        my_milship_rating = MilitaryAI.cur_best_mil_ship_rating()
        current_turn = fo.currentTurn()
        for fleet_id in universe.fleetIDs:
            fleet = universe.getFleet(fleet_id)
            if fleet is None:
                continue
            if not fleet.empty:
                # TODO: check if currently in system and blockaded before accepting destination as location
                this_system_id = (fleet.nextSystemID != INVALID_ID and fleet.nextSystemID) or fleet.systemID
                if fleet.ownedBy(empire_id):
                    if fleet_id not in destroyed_object_ids:
                        my_fleets_by_system.setdefault(this_system_id, []).append(fleet_id)
                        fleet_spot_position.setdefault(fleet.systemID, []).append(fleet_id)
                else:
                    dead_fleet = fleet_id in destroyed_object_ids
                    if not fleet.ownedBy(-1) and (fleet.hasArmedShips or fleet.hasFighterShips):
                        ship_stats = CombatRatingsAI.FleetCombatStats(fleet_id).get_ship_stats(hashable=True)
                        e_f_dict = [cur_e_fighters, old_e_fighters][dead_fleet]  # track old/dead enemy fighters for rating assessments in case not enough current info
                        for stats in ship_stats:
                            attacks = stats[0]
                            if attacks:
                                e_f_dict.setdefault(stats, [0])[0] += 1
                    partial_vis_turn = universe.getVisibilityTurnsMap(fleet_id, empire_id).get(fo.visibility.partial, -9999)
                    if not dead_fleet:
                        # TODO: consider checking death of individual ships.  If ships had been moved from this fleet
                        # into another fleet, we might have witnessed their death in that other fleet but if this fleet
                        # had not been seen since before that transfer then the ships might also still be listed here.
                        sys_status = self.systemStatus.setdefault(this_system_id, {})
                        sys_status['enemy_ship_count'] = sys_status.get('enemy_ship_count', 0) + len(fleet.shipIDs)
                        if partial_vis_turn >= current_turn - 1:  # only interested in immediately recent data
                            saw_enemies_at_system[fleet.systemID] = True
                            enemy_fleet_ids.append(fleet_id)
                            enemies_by_system.setdefault(this_system_id, []).append(fleet_id)
                            if not fleet.ownedBy(-1):
                                self.misc.setdefault('enemies_sighted', {}).setdefault(current_turn, []).append(fleet_id)
                                rating = CombatRatingsAI.get_fleet_rating(fleet_id, enemy_stats=CombatRatingsAI.get_empire_standard_fighter())
                                if rating > 0.25 * my_milship_rating:
                                    self.misc.setdefault('dangerous_enemies_sighted', {}).setdefault(current_turn, []).append(fleet_id)
        e_f_dict = [cur_e_fighters, old_e_fighters][len(cur_e_fighters) == 1]
        std_fighter = sorted([(v, k) for k, v in e_f_dict.items()])[-1][1]
        self.__empire_standard_enemy = std_fighter
        self.empire_standard_enemy_rating = self.get_standard_enemy().get_rating()
        # TODO: If no current information available, rate against own fighters

        # assess fleet and planet threats & my local fleets
        for sys_id in system_id_list:
            sys_status = self.systemStatus.setdefault(sys_id, {})
            system = universe.getSystem(sys_id)
            if verbose:
                print "AIState threat evaluation for %s" % system
            # update fleets
            sys_status['myfleets'] = my_fleets_by_system.get(sys_id, [])
            sys_status['myFleetsAccessible'] = fleet_spot_position.get(sys_id, [])
            local_enemy_fleet_ids = enemies_by_system.get(sys_id, [])
            sys_status['localEnemyFleetIDs'] = local_enemy_fleet_ids
            if system:
                sys_status['name'] = system.name
                for fid in system.fleetIDs:
                    if fid in destroyed_object_ids:  # TODO: double check are these checks/deletes necessary?
                        self.delete_fleet_info(fid)  # this is safe even if fleet wasn't mine
                        continue
                    fleet = universe.getFleet(fid)
                    if not fleet or fleet.empty:
                        self.delete_fleet_info(fid)  # this is safe even if fleet wasn't mine
                        continue

            # update threats
            sys_vis_dict = universe.getVisibilityTurnsMap(sys_id, fo.empireID())
            partial_vis_turn = sys_vis_dict.get(fo.visibility.partial, -9999)
            mob_ratings = []  # for mobile unowned monster fleets
            lost_fleet_rating = 0
            enemy_ratings = []
            monster_ratings = []
            mobile_fleets = []
            for fid in local_enemy_fleet_ids:
                fleet = universe.getFleet(fid)
                if not fleet:
                    continue
                fleet_rating = CombatRatingsAI.get_fleet_rating(fid, enemy_stats=CombatRatingsAI.get_empire_standard_fighter())
                if fleet.speed == 0:
                    monster_ratings.append(fleet_rating)
                    if verbose:
                        print "\t immobile enemy fleet %s has rating %.1f" % (fleet, fleet_rating)
                else:
                    if verbose:
                        print "\t mobile enemy fleet %s has rating %.1f" % (fleet, fleet_rating)
                    mobile_fleets.append(fid)
                    if fleet.unowned:
                        mob_ratings.append(fleet_rating)
                    else:
                        enemy_ratings.append(fleet_rating)
            enemy_rating = CombatRatingsAI.combine_ratings_list(enemy_ratings)
            monster_rating = CombatRatingsAI.combine_ratings_list(monster_ratings)
            mob_rating = CombatRatingsAI.combine_ratings_list(mob_ratings)
            if fleetsLostBySystem.get(sys_id, []):
                lost_fleet_rating = CombatRatingsAI.combine_ratings_list(fleetsLostBySystem[sys_id])
            if not system or partial_vis_turn == -9999:  # under current visibility rules should not be possible to have any losses or other info here, but just in case...
                if verbose:
                    print "Have never had partial vis for system %d ( %s ) -- basing threat assessment on old info and lost ships" % (sys_id, sys_status.get('name', "name unknown"))
                sys_status.setdefault('local_fleet_threats', set())
                sys_status['planetThreat'] = 0
                sys_status['fleetThreat'] = int(max(CombatRatingsAI.combine_ratings(enemy_rating, mob_rating), 0.98 * sys_status.get('fleetThreat', 0), 1.1 * lost_fleet_rating - monster_rating))
                sys_status['monsterThreat'] = int(max(monster_rating, 0.98 * sys_status.get('monsterThreat', 0), 1.1 * lost_fleet_rating - enemy_rating - mob_rating))
                sys_status['enemy_threat'] = int(max(enemy_rating, 0.98 * sys_status.get('enemy_threat', 0), 1.1 * lost_fleet_rating - monster_rating - mob_rating))
                sys_status['mydefenses'] = {'overall': 0, 'attack': 0, 'health': 0}
                sys_status['totalThreat'] = sys_status['fleetThreat']
                sys_status['regional_fleet_threats'] = sys_status['local_fleet_threats'].copy()
                continue

            # have either stale or current info
            pattack = 0
            phealth = 0
            mypattack, myphealth = 0, 0
            for pid in system.planetIDs:
                prating = self.assess_planet_threat(pid, sighting_age=current_turn - partial_vis_turn)
                planet = universe.getPlanet(pid)
                if not planet:
                    continue
                if planet.owner == self.empireID:  # TODO: check for diplomatic status
                    mypattack += prating['attack']
                    myphealth += prating['health']
                else:
                    if [special for special in planet.specials if "_NEST_" in special]:
                        sys_status['nest_threat'] = 100
                    pattack += prating['attack']
                    phealth += prating['health']
            sys_status['planetThreat'] = pattack * phealth
            sys_status['mydefenses'] = {'overall': mypattack * myphealth, 'attack': mypattack, 'health': myphealth}

            if max(sys_status.get('totalThreat', 0), pattack * phealth) >= 0.6 * lost_fleet_rating:  # previous threat assessment could account for losses, ignore the losses now
                lost_fleet_rating = 0

            # TODO use sitrep combat info rather than estimating stealthed enemies by fleets lost to them
            # TODO also only consider past stealthed fleet threat to still be present if the system is still obstructed
            # TODO: track visibility across turns in order to distinguish the blip of visibility in (losing) combat,
            # which FO currently treats as being for the previous turn, partially superseding the previous visibility for that turn
            if not partial_vis_turn == current_turn:  # (universe.getVisibility(sys_id, self.empire_id) >= fo.visibility.partial):
                sys_status.setdefault('local_fleet_threats', set())
                sys_status['currently_visible'] = False
                # print "Stale visibility for system %d ( %s ) -- last seen %d, current Turn %d -- basing threat assessment on old info and lost ships"%(sys_id, sys_status.get('name', "name unknown"), partial_vis_turn, currentTurn)
                sys_status['fleetThreat'] = int(max(CombatRatingsAI.combine_ratings(enemy_rating, mob_rating), 0.98 * sys_status.get('fleetThreat', 0), 2.0 * lost_fleet_rating - max(sys_status.get('monsterThreat', 0), monster_rating)))
                sys_status['enemy_threat'] = int(max(enemy_rating, 0.98 * sys_status.get('enemy_threat', 0), 1.1 * lost_fleet_rating - max(sys_status.get('monsterThreat', 0), monster_rating)))
                sys_status['monsterThreat'] = int(max(monster_rating, 0.98 * sys_status.get('monsterThreat', 0)))
                # sys_status['totalThreat'] = ((pattack + enemy_attack + monster_attack) ** 0.8) * ((phealth + enemy_health + monster_health)** 0.6)  # reevaluate this
                sys_status['totalThreat'] = max(CombatRatingsAI.combine_ratings_list([enemy_rating, mob_rating, monster_rating, pattack * phealth]), 2 * lost_fleet_rating, 0.98 * sys_status.get('totalThreat', 0))
            else:  # system considered visible #TODO: reevaluate as visibility rules change
                sys_status['currently_visible'] = True
                sys_status['local_fleet_threats'] = set(mobile_fleets)
                sys_status['fleetThreat'] = int(max(CombatRatingsAI.combine_ratings(enemy_rating, mob_rating), 2 * lost_fleet_rating - monster_rating))  # includes mobile monsters
                if verbose:
                    print "enemy threat calc parts: enemy rating %.1f, lost fleet rating %.1f, monster_rating %.1f" % (enemy_rating, lost_fleet_rating, monster_rating)
                sys_status['enemy_threat'] = int(max(enemy_rating, 2 * lost_fleet_rating - monster_rating))  # does NOT include mobile monsters
                sys_status['monsterThreat'] = monster_rating
                sys_status['totalThreat'] = CombatRatingsAI.combine_ratings_list([enemy_rating, mob_rating, monster_rating, pattack * phealth])
            sys_status['regional_fleet_threats'] = sys_status['local_fleet_threats'].copy()
            sys_status['fleetThreat'] = max(sys_status['fleetThreat'], sys_status.get('nest_threat', 0))
            sys_status['totalThreat'] = max(sys_status['totalThreat'], sys_status.get('nest_threat', 0))

            if partial_vis_turn > 0 and sys_id not in supply_unobstructed_systems:  # has been seen with Partial Vis, but is currently supply-blocked
                sys_status['fleetThreat'] = max(sys_status['fleetThreat'], min_hidden_attack * min_hidden_health)
                sys_status['totalThreat'] = max(sys_status['totalThreat'], ((pattack + min_hidden_attack) ** 0.8) * ((phealth + min_hidden_health) ** 0.6))
            if verbose and sys_status['fleetThreat'] > 0:
                print "%s intermediate status: %s" % (system, sys_status)

        enemy_supply, enemy_near_supply = self.assess_enemy_supply()  # TODO: assess change in enemy supply over time
        # assess secondary threats (threats of surrounding systems) and update my fleet rating
        for sys_id in system_id_list:
            sys_status = self.systemStatus[sys_id]
            sys_status['enemies_supplied'] = enemy_supply.get(sys_id, [])
            sys_status['enemies_nearly_supplied'] = enemy_near_supply.get(sys_id, [])
            my_ratings_list = []
            my_ratings_against_planets_list = []
            for fid in sys_status['myfleets']:
                this_rating = self.get_rating(fid, True, self.get_standard_enemy())
                my_ratings_list.append(this_rating)
                my_ratings_against_planets_list.append(self.get_rating(fid, against_planets=True))
            if sys_id != INVALID_ID:
                sys_status['myFleetRating'] = CombatRatingsAI.combine_ratings_list(my_ratings_list)
                sys_status['myFleetRatingVsPlanets'] = CombatRatingsAI.combine_ratings_list(my_ratings_against_planets_list)
                sys_status['all_local_defenses'] = CombatRatingsAI.combine_ratings(sys_status['myFleetRating'], sys_status['mydefenses']['overall'])
            sys_status['neighbors'] = set(dict_from_map(universe.getSystemNeighborsMap(sys_id, self.empireID)))
            
        for sys_id in system_id_list:
            sys_status = self.systemStatus[sys_id]
            neighbors = sys_status.get('neighbors', set())
            this_system = fo.getUniverse().getSystem(sys_id)
            if verbose:
                print "Regional Assessment for %s with local fleet threat %.1f" % (this_system, sys_status.get('fleetThreat', 0))
            jumps2 = set()
            jumps3 = set()
            jumps4 = set()
            for seta, setb in [(neighbors, jumps2), (jumps2, jumps3), (jumps3, jumps4)]:
                for sys2id in seta:
                    setb.update(self.systemStatus.get(sys2id, {}).get('neighbors', set()))
            jump2ring = jumps2 - neighbors - {sys_id}
            jump3ring = jumps3 - jumps2 - neighbors - {sys_id}
            jump4ring = jumps4 - jumps3  - jumps2 - neighbors - {sys_id}
            sys_status['2jump_ring'] = jump2ring
            sys_status['3jump_ring'] = jump3ring
            sys_status['4jump_ring'] = jump4ring
            threat, max_threat, myrating, j1_threats = self.area_ratings(neighbors, ref_sys_name="neighbors %s" % this_system) if verbose else self.area_ratings(neighbors)
            sys_status['neighborThreat'] = threat
            sys_status['max_neighbor_threat'] = max_threat
            sys_status['my_neighbor_rating'] = myrating
            threat, max_threat, myrating, j2_threats = self.area_ratings(jump2ring, ref_sys_name="jump2 %s" % this_system) if verbose else self.area_ratings(jump2ring)
            sys_status['jump2_threat'] = threat
            sys_status['my_jump2_rating'] = myrating
            threat, max_threat, myrating, j3_threats = self.area_ratings(jump3ring)
            sys_status['jump3_threat'] = threat
            sys_status['my_jump3_rating'] = myrating
            threat_keys = ['fleetThreat', 'neighborThreat', 'jump2_threat']  # for local system includes both enemies and mobs
            sys_status['regional_threat'] = CombatRatingsAI.combine_ratings_list(map(lambda x: sys_status.get(x, 0), threat_keys))
            # TODO: investigate cases where regional_threat has been nonzero but no regional_threat_fleets
            # (probably due to attenuating history of past threats)
            sys_status.setdefault('regional_fleet_threats', set()).update(j1_threats, j2_threats)
예제 #32
0
def evaluate_invasion_planet(planet_id, empire, secure_fleet_missions, verbose=True):
    """Return the invasion value (score, troops) of a planet."""
    detail = []
    building_values = {"BLD_IMPERIAL_PALACE": 1000,
                       "BLD_CULTURE_ARCHIVES": 1000,
                       "BLD_SHIPYARD_BASE": 100,
                       "BLD_SHIPYARD_ORG_ORB_INC": 200,
                       "BLD_SHIPYARD_ORG_XENO_FAC": 200,
                       "BLD_SHIPYARD_ORG_CELL_GRO_CHAMB": 200,
                       "BLD_SHIPYARD_CON_NANOROBO": 300,
                       "BLD_SHIPYARD_CON_GEOINT": 400,
                       "BLD_SHIPYARD_CON_ADV_ENGINE": 1000,
                       "BLD_SHIPYARD_AST": 300,
                       "BLD_SHIPYARD_AST_REF": 1000,
                       "BLD_SHIPYARD_ENRG_SOLAR": 1500,
                       "BLD_INDUSTRY_CENTER": 500,
                       "BLD_GAS_GIANT_GEN": 200,
                       "BLD_SOL_ORB_GEN": 800,
                       "BLD_BLACK_HOLE_POW_GEN": 2000,
                       "BLD_ENCLAVE_VOID": 500,
                       "BLD_NEUTRONIUM_EXTRACTOR": 2000,
                       "BLD_NEUTRONIUM_SYNTH": 2000,
                       "BLD_NEUTRONIUM_FORGE": 1000,
                       "BLD_CONC_CAMP": 100,
                       "BLD_BIOTERROR_PROJECTOR": 1000,
                       "BLD_SHIPYARD_ENRG_COMP": 3000,
                       }
    # TODO: add more factors, as used for colonization
    universe = fo.getUniverse()
    empire_id = empire.empireID
    max_jumps = 8
    planet = universe.getPlanet(planet_id)
    if planet is None:  # TODO: exclude planets with stealth higher than empireDetection
        print "invasion AI couldn't access any info for planet id %d" % planet_id
        return [0, 0]

    sys_partial_vis_turn = universe.getVisibilityTurnsMap(planet.systemID, empire_id).get(fo.visibility.partial, -9999)
    planet_partial_vis_turn = universe.getVisibilityTurnsMap(planet_id, empire_id).get(fo.visibility.partial, -9999)

    if planet_partial_vis_turn < sys_partial_vis_turn:
        print "invasion AI couldn't get current info on planet id %d (was stealthed at last sighting)" % planet_id
        # TODO: track detection strength, order new scouting when it goes up
        return [0, 0]  # last time we had partial vis of the system, the planet was stealthed to us

    species_name = planet.speciesName
    species = fo.getSpecies(species_name)
    if not species:  # this call iterates over this Empire's available species with which it could colonize after an invasion
        planet_eval = ColonisationAI.assign_colonisation_values([planet_id], EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, None, empire, detail)
        pop_val = max(0.75*planet_eval.get(planet_id, [0])[0], ColonisationAI.evaluate_planet(planet_id, EnumsAI.AIFleetMissionType.FLEET_MISSION_OUTPOST, None, empire, detail))
    else:
        pop_val = ColonisationAI.evaluate_planet(planet_id, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, species_name, empire, detail)

    bld_tally = 0
    for bldType in [universe.getObject(bldg).buildingTypeName for bldg in planet.buildingIDs]:
        bval = building_values.get(bldType, 50)
        bld_tally += bval
        detail.append("%s: %d" % (bldType, bval))

    p_sys_id = planet.systemID
    capitol_id = PlanetUtilsAI.get_capital()
    least_jumps_path = []
    clear_path = True
    if capitol_id:
        homeworld = universe.getPlanet(capitol_id)
        if homeworld:
            home_system_id = homeworld.systemID
            eval_system_id = planet.systemID
            if (home_system_id != -1) and (eval_system_id != -1):
                least_jumps_path = list(universe.leastJumpsPath(home_system_id, eval_system_id, empire_id))
                max_jumps = len(least_jumps_path)
    system_status = foAI.foAIstate.systemStatus.get(p_sys_id, {})
    system_fleet_treat = system_status.get('fleetThreat', 1000)
    system_monster_threat = system_status.get('monsterThreat', 0)
    sys_total_threat = system_fleet_treat + system_monster_threat + system_status.get('planetThreat', 0)
    max_path_threat = system_fleet_treat
    mil_ship_rating = MilitaryAI.cur_best_mil_ship_rating()
    for path_sys_id in least_jumps_path:
        path_leg_status = foAI.foAIstate.systemStatus.get(path_sys_id, {})
        path_leg_threat = path_leg_status.get('fleetThreat', 1000) + path_leg_status.get('monsterThreat', 0)
        if path_leg_threat > 0.5 * mil_ship_rating:
            clear_path = False
            if path_leg_threat > max_path_threat:
                max_path_threat = path_leg_threat

    troops = planet.currentMeterValue(fo.meterType.troops)
    max_troops = planet.currentMeterValue(fo.meterType.maxTroops)

    this_system = universe.getSystem(p_sys_id)
    secure_targets = [p_sys_id] + list(this_system.planetIDs)
    system_secured = False
    for mission in secure_fleet_missions:
        if system_secured:
            break
        secure_fleet_id = mission.target_id
        s_fleet = universe.getFleet(secure_fleet_id)
        if not s_fleet or s_fleet.systemID != p_sys_id:
            continue
        for ai_target in mission.get_targets(EnumsAI.AIFleetMissionType.FLEET_MISSION_SECURE):
            target_obj = ai_target.target_obj
            if (target_obj is not None) and target_obj.id in secure_targets:
                system_secured = True
                break

    if verbose:
        print "invasion eval of %s %d --- maxShields %.1f -- sysFleetThreat %.1f -- sysMonsterThreat %.1f" % (
            planet.name, planet_id, planet.currentMeterValue(fo.meterType.maxShield), system_fleet_treat,
            system_monster_threat)
    supply_val = 0
    enemy_val = 0
    if planet.owner != -1:  # value in taking this away from an enemy
        enemy_val = 20 * (planet.currentMeterValue(fo.meterType.targetIndustry) + 2*planet.currentMeterValue(fo.meterType.targetResearch))
    if p_sys_id in ColonisationAI.annexable_system_ids:  # TODO: extend to rings
        supply_val = 100
    elif p_sys_id in ColonisationAI.annexable_ring1:
        supply_val = 200
    elif p_sys_id in ColonisationAI.annexable_ring2:
        supply_val = 300
    elif p_sys_id in ColonisationAI.annexable_ring3:
        supply_val = 400
    if max_path_threat > 0.5 * mil_ship_rating:
        if max_path_threat < 3 * mil_ship_rating:
            supply_val *= 0.5
        else:
            supply_val *= 0.2
        
    threat_factor = min(1, 0.2*MilitaryAI.totMilRating/(sys_total_threat+0.001))**2  # devalue invasions that would require too much military force
    build_time = 4

    planned_troops = troops if system_secured else min(troops+max_jumps+build_time, max_troops)
    if not tech_is_complete("SHP_ORG_HULL"):
        troop_cost = math.ceil(planned_troops/6.0) * (40*(1+foAI.foAIstate.shipCount * AIDependencies.SHIP_UPKEEP))
    else:
        troop_cost = math.ceil(planned_troops/6.0) * (20*(1+foAI.foAIstate.shipCount * AIDependencies.SHIP_UPKEEP))
    planet_score = retaliation_risk_factor(planet.owner) * threat_factor * max(0, pop_val+supply_val+bld_tally+enemy_val-0.8*troop_cost)
    if clear_path:
        planet_score *= 1.5
    invasion_score = [planet_score, planned_troops]
    print invasion_score, "projected Troop Cost:", troop_cost, ", threatFactor: ", threat_factor, ", planet detail ", detail, "popval, supplyval, bldval, enemyval", pop_val, supply_val, bld_tally, enemy_val
    return invasion_score
예제 #33
0
def evaluate_invasion_planet(planet_id, empire, secure_fleet_missions, verbose=True):
    """Return the invasion value (score, troops) of a planet."""
    detail = []
    building_values = {"BLD_IMPERIAL_PALACE": 1000,
                       "BLD_CULTURE_ARCHIVES": 1000,
                       "BLD_SHIPYARD_BASE": 100,
                       "BLD_SHIPYARD_ORG_ORB_INC": 200,
                       "BLD_SHIPYARD_ORG_XENO_FAC": 200,
                       "BLD_SHIPYARD_ORG_CELL_GRO_CHAMB": 200,
                       "BLD_SHIPYARD_CON_NANOROBO": 300,
                       "BLD_SHIPYARD_CON_GEOINT": 400,
                       "BLD_SHIPYARD_CON_ADV_ENGINE": 1000,
                       "BLD_SHIPYARD_AST": 300,
                       "BLD_SHIPYARD_AST_REF": 1000,
                       "BLD_SHIPYARD_ENRG_SOLAR": 1500,
                       "BLD_INDUSTRY_CENTER": 500,
                       "BLD_GAS_GIANT_GEN": 200,
                       "BLD_SOL_ORB_GEN": 800,
                       "BLD_BLACK_HOLE_POW_GEN": 2000,
                       "BLD_ENCLAVE_VOID": 500,
                       "BLD_NEUTRONIUM_EXTRACTOR": 2000,
                       "BLD_NEUTRONIUM_SYNTH": 2000,
                       "BLD_NEUTRONIUM_FORGE": 1000,
                       "BLD_CONC_CAMP": 100,
                       "BLD_BIOTERROR_PROJECTOR": 1000,
                       "BLD_SHIPYARD_ENRG_COMP": 3000,
                       }
    # TODO: add more factors, as used for colonization
    universe = fo.getUniverse()
    empire_id = empire.empireID
    max_jumps = 8
    planet = universe.getPlanet(planet_id)
    if planet is None:  # TODO: exclude planets with stealth higher than empireDetection
        print "invasion AI couldn't access any info for planet id %d" % planet_id
        return [0, 0]

    sys_partial_vis_turn = universe.getVisibilityTurnsMap(planet.systemID, empire_id).get(fo.visibility.partial, -9999)
    planet_partial_vis_turn = universe.getVisibilityTurnsMap(planet_id, empire_id).get(fo.visibility.partial, -9999)

    if planet_partial_vis_turn < sys_partial_vis_turn:
        print "invasion AI couldn't get current info on planet id %d (was stealthed at last sighting)" % planet_id
        # TODO: track detection strength, order new scouting when it goes up
        return [0, 0]  # last time we had partial vis of the system, the planet was stealthed to us

    species_name = planet.speciesName
    species = fo.getSpecies(species_name)
    if not species:  # this call iterates over this Empire's available species with which it could colonize after an invasion
        planet_eval = ColonisationAI.assign_colonisation_values([planet_id], EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, None, empire, detail)
        pop_val = max(0.75*planet_eval.get(planet_id, [0])[0], ColonisationAI.evaluate_planet(planet_id, EnumsAI.AIFleetMissionType.FLEET_MISSION_OUTPOST, None, empire, detail))
    else:
        pop_val = ColonisationAI.evaluate_planet(planet_id, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, species_name, empire, detail)

    bld_tally = 0
    for bldType in [universe.getObject(bldg).buildingTypeName for bldg in planet.buildingIDs]:
        bval = building_values.get(bldType, 50)
        bld_tally += bval
        detail.append("%s: %d" % (bldType, bval))

    p_sys_id = planet.systemID
    capitol_id = PlanetUtilsAI.get_capital()
    least_jumps_path = []
    clear_path = True
    if capitol_id:
        homeworld = universe.getPlanet(capitol_id)
        if homeworld:
            home_system_id = homeworld.systemID
            eval_system_id = planet.systemID
            if (home_system_id != -1) and (eval_system_id != -1):
                least_jumps_path = list(universe.leastJumpsPath(home_system_id, eval_system_id, empire_id))
                max_jumps = len(least_jumps_path)
    system_status = foAI.foAIstate.systemStatus.get(p_sys_id, {})
    system_fleet_treat = system_status.get('fleetThreat', 1000)
    system_monster_threat = system_status.get('monsterThreat', 0)
    sys_total_threat = system_fleet_treat + system_monster_threat + system_status.get('planetThreat', 0)
    max_path_threat = system_fleet_treat
    mil_ship_rating = MilitaryAI.cur_best_mil_ship_rating()
    for path_sys_id in least_jumps_path:
        path_leg_status = foAI.foAIstate.systemStatus.get(path_sys_id, {})
        path_leg_threat = path_leg_status.get('fleetThreat', 1000) + path_leg_status.get('monsterThreat', 0)
        if path_leg_threat > 0.5 * mil_ship_rating:
            clear_path = False
            if path_leg_threat > max_path_threat:
                max_path_threat = path_leg_threat

    pop = planet.currentMeterValue(fo.meterType.population)
    target_pop = planet.currentMeterValue(fo.meterType.targetPopulation)
    troops = planet.currentMeterValue(fo.meterType.troops)
    max_troops = planet.currentMeterValue(fo.meterType.maxTroops)
    # TODO: refactor troop determination into function for use in mid-mission updates and also consider defender techs
    max_troops += AIDependencies.TROOPS_PER_POP * (target_pop - pop)

    this_system = universe.getSystem(p_sys_id)
    secure_targets = [p_sys_id] + list(this_system.planetIDs)
    system_secured = False
    for mission in secure_fleet_missions:
        if system_secured:
            break
        secure_fleet_id = mission.target_id
        s_fleet = universe.getFleet(secure_fleet_id)
        if not s_fleet or s_fleet.systemID != p_sys_id:
            continue
        for ai_target in mission.get_targets(EnumsAI.AIFleetMissionType.FLEET_MISSION_SECURE):
            target_obj = ai_target.target_obj
            if (target_obj is not None) and target_obj.id in secure_targets:
                system_secured = True
                break
    system_secured = system_secured and system_status.get('myFleetRating',0)

    if verbose:
        print "invasion eval of %s %d --- maxShields %.1f -- sysFleetThreat %.1f -- sysMonsterThreat %.1f" % (
            planet.name, planet_id, planet.currentMeterValue(fo.meterType.maxShield), system_fleet_treat,
            system_monster_threat)
    supply_val = 0
    enemy_val = 0
    if planet.owner != -1:  # value in taking this away from an enemy
        enemy_val = 20 * (planet.currentMeterValue(fo.meterType.targetIndustry) + 2*planet.currentMeterValue(fo.meterType.targetResearch))
    if p_sys_id in ColonisationAI.annexable_system_ids:  # TODO: extend to rings
        supply_val = 100
    elif p_sys_id in ColonisationAI.annexable_ring1:
        supply_val = 200
    elif p_sys_id in ColonisationAI.annexable_ring2:
        supply_val = 300
    elif p_sys_id in ColonisationAI.annexable_ring3:
        supply_val = 400
    if max_path_threat > 0.5 * mil_ship_rating:
        if max_path_threat < 3 * mil_ship_rating:
            supply_val *= 0.5
        else:
            supply_val *= 0.2
        
    threat_factor = min(1, 0.2*MilitaryAI.totMilRating/(sys_total_threat+0.001))**2  # devalue invasions that would require too much military force
    build_time = 4

    planned_troops = troops if system_secured else min(troops+max_jumps+build_time, max_troops)
    if not tech_is_complete("SHP_ORG_HULL"):
        troop_cost = math.ceil(planned_troops/6.0) * (40*(1+foAI.foAIstate.shipCount * AIDependencies.SHIP_UPKEEP))
    else:
        troop_cost = math.ceil(planned_troops/6.0) * (20*(1+foAI.foAIstate.shipCount * AIDependencies.SHIP_UPKEEP))
    planet_score = retaliation_risk_factor(planet.owner) * threat_factor * max(0, pop_val+supply_val+bld_tally+enemy_val-0.8*troop_cost)
    if clear_path:
        planet_score *= 1.5
    invasion_score = [planet_score, planned_troops]
    print invasion_score, "projected Troop Cost:", troop_cost, ", threatFactor: ", threat_factor, ", planet detail ", detail, "popval, supplyval, bldval, enemyval", pop_val, supply_val, bld_tally, enemy_val
    return invasion_score
예제 #34
0
    def issue_fleet_orders(self):
        """issues AIFleetOrders which can be issued in system and moves to next one if is possible"""
        # TODO: priority
        order_completed = True
        print "--------------"
        print "Checking orders for fleet %d (on turn %d), with mission types %s" % (
            self.target_id, fo.currentTurn(),
            [AIFleetMissionType.name(mt) for mt in self.get_mission_types()])
        print "\t Full Orders are:"
        for this_order in self.orders:
            print "\t\t| %s" % this_order
        print "/t/t------"
        if AIFleetMissionType.FLEET_MISSION_INVASION in self.get_mission_types(
        ):
            self._check_retarget_invasion()
        for fleet_order in self.orders:
            print "\t| checking Order: %s" % fleet_order
            order_type = fleet_order.order_type
            if order_type in [
                    AIFleetOrderType.ORDER_COLONISE,
                    AIFleetOrderType.ORDER_OUTPOST,
                    AIFleetOrderType.ORDER_INVADE
            ]:  # TODO: invasion?
                if self._check_abort_mission(fleet_order):
                    print "\t\t| Aborting fleet order %s" % fleet_order
                    return
            self.check_mergers(context=str(fleet_order))
            if fleet_order.can_issue_order(verbose=True):
                if order_type == AIFleetOrderType.ORDER_MOVE and order_completed:  # only move if all other orders completed
                    print "\t\t| issuing fleet order %s" % fleet_order
                    fleet_order.issue_order()
                elif order_type not in [
                        AIFleetOrderType.ORDER_MOVE,
                        AIFleetOrderType.ORDER_DEFEND
                ]:
                    print "\t\t| issuing fleet order %s" % fleet_order
                    fleet_order.issue_order()
                else:
                    print "\t\t| NOT issuing (even though can_issue) fleet order %s" % fleet_order
                print "\t\t| order status-- execution completed: %s" % fleet_order.execution_completed
                if not fleet_order.execution_completed:
                    order_completed = False
            else:  # check that we're not held up by a Big Monster
                print "\t\t| CAN'T issue fleet order %s" % fleet_order
                if order_type == AIFleetOrderType.ORDER_MOVE:
                    this_system_id = fleet_order.target.target_id
                    this_status = foAI.foAIstate.systemStatus.setdefault(
                        this_system_id, {})
                    if this_status.get('monsterThreat', 0) > fo.currentTurn(
                    ) * ProductionAI.cur_best_mil_ship_rating() / 4.0:
                        first_mission = self.get_mission_types(
                        )[0] if self.get_mission_types(
                        ) else AIFleetMissionType.FLEET_MISSION_INVALID
                        if (first_mission not in (
                                AIFleetMissionType.FLEET_MISSION_ATTACK,
                                AIFleetMissionType.FLEET_MISSION_MILITARY,
                                AIFleetMissionType.FLEET_MISSION_HIT_AND_RUN,
                                AIFleetMissionType.FLEET_MISSION_SECURE,
                        ) or fleet_order != self.orders[
                                -1]  # if this move order is not this mil fleet's final destination, and blocked by Big Monster, release and hope for more effective reassignment
                            ):
                            print "Aborting mission due to being blocked by Big Monster at system %d, threat %d" % (
                                this_system_id, foAI.foAIstate.
                                systemStatus[this_system_id]['monsterThreat'])
                            print "Full set of orders were:"
                            for this_order in self.orders:
                                print "\t\t %s" % this_order
                            self.clear_fleet_orders()
                            self.clear_targets(
                                ([-1] + self.get_mission_types()[:1])[-1])
                            return
            # moving to another system stops issuing all orders in system where fleet is
            # move order is also the last order in system
            if order_type == AIFleetOrderType.ORDER_MOVE:
                fleet = fo.getUniverse().getFleet(self.target_id)
                if fleet.systemID != fleet_order.target.target_id:
                    break
        else:  # went through entire order list
            if order_completed:
                print "\t| Final order is completed"
                orders = self.orders
                last_order = orders[-1] if orders else None
                universe = fo.getUniverse()

                if last_order and last_order.order_type == AIFleetOrderType.ORDER_COLONISE:
                    planet = universe.getPlanet(last_order.target.target_id)
                    sys_partial_vis_turn = universe.getVisibilityTurnsMap(
                        planet.systemID,
                        fo.empireID()).get(fo.visibility.partial, -9999)
                    planet_partial_vis_turn = universe.getVisibilityTurnsMap(
                        planet.id, fo.empireID()).get(fo.visibility.partial,
                                                      -9999)
                    if planet_partial_vis_turn == sys_partial_vis_turn and not planet.currentMeterValue(
                            fo.meterType.population):
                        print "Potential Error: Fleet %d has tentatively completed its colonize mission but will wait to confirm population." % self.target_id
                        print "    Order details are %s" % last_order
                        print "    Order is valid: %s ; is Executed : %s; is execution completed: %s " % (
                            last_order.is_valid(), last_order.isExecuted(),
                            last_order.isExecutionCompleted())
                        if not last_order.is_valid():
                            source_target = last_order.fleet
                            target_target = last_order.target
                            print "        source target validity: %s; target target validity: %s " % (
                                source_target.valid, target_target.valid)
                            if EnumsAI.TargetType.TARGET_SHIP == source_target.target_type:
                                ship_id = source_target.target_id
                                ship = universe.getShip(ship_id)
                                if not ship:
                                    print "Ship id %d not a valid ship id" % ship_id
                                print "        source target Ship (%d), species %s, can%s colonize" % (
                                    ship_id, ship.speciesName,
                                    ["not", ""][ship.canColonize])
                        return  # colonize order must not have completed yet
                clearAll = True
                last_sys_target = -1
                if last_order and last_order.order_type == AIFleetOrderType.ORDER_MILITARY:
                    last_sys_target = last_order.target.target_id
                    # if (AIFleetMissionType.FLEET_MISSION_SECURE in self.get_mission_types()) or # not doing this until decide a way to release from a SECURE mission
                    secure_targets = set(AIstate.colonyTargetedSystemIDs +
                                         AIstate.outpostTargetedSystemIDs +
                                         AIstate.invasionTargetedSystemIDs +
                                         AIstate.blockadeTargetedSystemIDs)
                    if last_sys_target in secure_targets:  # consider a secure mission
                        if last_sys_target in AIstate.colonyTargetedSystemIDs:
                            secure_type = "Colony"
                        elif last_sys_target in AIstate.outpostTargetedSystemIDs:
                            secure_type = "Outpost"
                        elif last_sys_target in AIstate.invasionTargetedSystemIDs:
                            secure_type = "Invasion"
                        elif last_sys_target in AIstate.blockadeTargetedSystemIDs:
                            secure_type = "Blockade"
                        else:
                            secure_type = "Unidentified"
                        print "Fleet %d has completed initial stage of its mission to secure system %d (targeted for %s), may release a portion of ships" % (
                            self.target_id, last_sys_target, secure_type)
                        clearAll = False
                fleet_id = self.target_id
                if clearAll:
                    if orders:
                        print "Fleet %d has completed its mission; clearing all orders and targets." % self.target_id
                        print "Full set of orders were:"
                        for this_order in orders:
                            print "\t\t %s" % this_order
                        self.clear_fleet_orders()
                        self.clear_targets(
                            ([-1] + self.get_mission_types()[:1])[-1])
                        if foAI.foAIstate.get_fleet_role(fleet_id) in (
                                AIFleetMissionType.FLEET_MISSION_MILITARY,
                                AIFleetMissionType.FLEET_MISSION_ATTACK,
                                AIFleetMissionType.FLEET_MISSION_DEFEND,
                                AIFleetMissionType.FLEET_MISSION_HIT_AND_RUN,
                                AIFleetMissionType.FLEET_MISSION_SECURE):
                            allocations = MilitaryAI.get_military_fleets(
                                milFleetIDs=[fleet_id],
                                tryReset=False,
                                thisround="Fleet %d Reassignment" % fleet_id)
                            if allocations:
                                MilitaryAI.assign_military_fleets_to_systems(
                                    useFleetIDList=[fleet_id],
                                    allocations=allocations)
                    else:  # no orders
                        print "No Current Orders"
                else:
                    #TODO: evaluate releasing a smaller portion or none of the ships
                    system_status = foAI.foAIstate.systemStatus.setdefault(
                        last_sys_target, {})
                    new_fleets = []
                    threat_present = (system_status.get('totalThreat', 0) !=
                                      0) or (system_status.get(
                                          'neighborThreat', 0) != 0)
                    target_system = universe.getSystem(last_sys_target)
                    if not threat_present and target_system:
                        for pid in target_system.planetIDs:
                            planet = universe.getPlanet(pid)
                            if planet and planet.owner != fo.empireID(
                            ) and planet.currentMeterValue(
                                    fo.meterType.maxDefense) > 0:
                                threat_present = True
                                break
                    if not threat_present:
                        print "No current threat in target system; releasing a portion of ships."
                        new_fleets = FleetUtilsAI.split_fleet(
                            self.target_id
                        )  # at least first stage of current task is done; release extra ships for potential other deployments
                    else:
                        print "Threat remains in target system; NOT releasing any ships."
                    new_military_fleets = []
                    for fleet_id in new_fleets:
                        if foAI.foAIstate.get_fleet_role(
                                fleet_id) in COMBAT_MISSION_TYPES:
                            new_military_fleets.append(fleet_id)
                    allocations = []
                    if new_military_fleets:
                        allocations = MilitaryAI.get_military_fleets(
                            milFleetIDs=new_military_fleets,
                            tryReset=False,
                            thisround="Fleet Reassignment %s" %
                            new_military_fleets)
                    if allocations:
                        MilitaryAI.assign_military_fleets_to_systems(
                            useFleetIDList=new_military_fleets,
                            allocations=allocations)
예제 #35
0
    def issue_fleet_orders(self):
        """issues AIFleetOrders which can be issued in system and moves to next one if is possible"""
        # TODO: priority
        order_completed = True

        debug(
            "\nChecking orders for fleet %s (on turn %d), with mission type %s"
            % (self.fleet.get_object(), fo.currentTurn(), self.type
               or 'No mission'))
        if MissionType.INVASION == self.type:
            self._check_retarget_invasion()
        just_issued_move_order = False
        last_move_target_id = INVALID_ID
        # Note: the following abort check somewhat assumes only one major mission type
        for fleet_order in self.orders:
            if (isinstance(fleet_order,
                           (OrderColonize, OrderOutpost, OrderInvade))
                    and self._check_abort_mission(fleet_order)):
                return
        aistate = get_aistate()
        for fleet_order in self.orders:
            if just_issued_move_order and self.fleet.get_object(
            ).systemID != last_move_target_id:
                # having just issued a move order, we will normally stop issuing orders this turn, except that if there
                # are consecutive move orders we will consider moving through the first destination rather than stopping
                # Without the below noinspection directive, PyCharm is concerned about the 2nd part of the test
                # noinspection PyTypeChecker
                if (not isinstance(fleet_order, OrderMove)
                        or self.need_to_pause_movement(last_move_target_id,
                                                       fleet_order)):
                    break
            debug("Checking order: %s" % fleet_order)
            self.check_mergers(context=str(fleet_order))
            if fleet_order.can_issue_order(verbose=False):
                if isinstance(
                        fleet_order, OrderMove
                ) and order_completed:  # only move if all other orders completed
                    debug("Issuing fleet order %s" % fleet_order)
                    fleet_order.issue_order()
                    just_issued_move_order = True
                    last_move_target_id = fleet_order.target.id
                elif not isinstance(fleet_order, OrderMove):
                    debug("Issuing fleet order %s" % fleet_order)
                    fleet_order.issue_order()
                else:
                    debug(
                        "NOT issuing (even though can_issue) fleet order %s" %
                        fleet_order)
                debug("Order issued: %s" % fleet_order.order_issued)
                if not fleet_order.executed:
                    order_completed = False
            else:  # check that we're not held up by a Big Monster
                if fleet_order.order_issued:
                    # A previously issued order that wasn't instantly executed must have had cirumstances change so that
                    # the order can't currently be reissued (or perhaps simply a savegame has been reloaded on the same
                    # turn the order was issued).
                    if not fleet_order.executed:
                        order_completed = False
                    # Go on to the next order.
                    continue
                debug("CAN'T issue fleet order %s" % fleet_order)
                if isinstance(fleet_order, OrderMove):
                    this_system_id = fleet_order.target.id
                    this_status = aistate.systemStatus.setdefault(
                        this_system_id, {})
                    threat_threshold = fo.currentTurn(
                    ) * MilitaryAI.cur_best_mil_ship_rating() / 4.0
                    if this_status.get('monsterThreat', 0) > threat_threshold:
                        # if this move order is not this mil fleet's final destination, and blocked by Big Monster,
                        # release and hope for more effective reassignment
                        if (self.type not in (MissionType.MILITARY,
                                              MissionType.SECURE)
                                or fleet_order != self.orders[-1]):
                            debug(
                                "Aborting mission due to being blocked by Big Monster at system %d, threat %d"
                                % (this_system_id,
                                   aistate.systemStatus[this_system_id]
                                   ['monsterThreat']))
                            debug("Full set of orders were:")
                            for this_order in self.orders:
                                debug(" - %s" % this_order)
                            self.clear_fleet_orders()
                            self.clear_target()
                            return
                break  # do not order the next order until this one is finished.
        else:  # went through entire order list
            if order_completed:
                debug("Final order is completed")
                orders = self.orders
                last_order = orders[-1] if orders else None
                universe = fo.getUniverse()

                if last_order and isinstance(last_order, OrderColonize):
                    planet = universe.getPlanet(last_order.target.id)
                    sys_partial_vis_turn = get_partial_visibility_turn(
                        planet.systemID)
                    planet_partial_vis_turn = get_partial_visibility_turn(
                        planet.id)
                    if (planet_partial_vis_turn == sys_partial_vis_turn
                            and not planet.initialMeterValue(
                                fo.meterType.population)):
                        warn(
                            "Fleet %d has tentatively completed its "
                            "colonize mission but will wait to confirm population."
                            % self.fleet.id)
                        debug("    Order details are %s" % last_order)
                        debug(
                            "    Order is valid: %s; issued: %s; executed: %s"
                            % (last_order.is_valid(), last_order.order_issued,
                               last_order.executed))
                        if not last_order.is_valid():
                            source_target = last_order.fleet
                            target_target = last_order.target
                            debug(
                                "        source target validity: %s; target target validity: %s "
                                % (bool(source_target), bool(target_target)))
                        return  # colonize order must not have completed yet
                clear_all = True
                last_sys_target = INVALID_ID
                if last_order and isinstance(last_order, OrderMilitary):
                    last_sys_target = last_order.target.id
                    # not doing this until decide a way to release from a SECURE mission
                    # if (MissionType.SECURE == self.type) or
                    secure_targets = set(AIstate.colonyTargetedSystemIDs +
                                         AIstate.outpostTargetedSystemIDs +
                                         AIstate.invasionTargetedSystemIDs)
                    if last_sys_target in secure_targets:  # consider a secure mission
                        if last_sys_target in AIstate.colonyTargetedSystemIDs:
                            secure_type = "Colony"
                        elif last_sys_target in AIstate.outpostTargetedSystemIDs:
                            secure_type = "Outpost"
                        elif last_sys_target in AIstate.invasionTargetedSystemIDs:
                            secure_type = "Invasion"
                        else:
                            secure_type = "Unidentified"
                        debug(
                            "Fleet %d has completed initial stage of its mission "
                            "to secure system %d (targeted for %s), "
                            "may release a portion of ships" %
                            (self.fleet.id, last_sys_target, secure_type))
                        clear_all = False
                fleet_id = self.fleet.id
                if clear_all:
                    if orders:
                        debug(
                            "Fleet %d has completed its mission; clearing all orders and targets."
                            % self.fleet.id)
                        debug("Full set of orders were:")
                        for this_order in orders:
                            debug("\t\t %s" % this_order)
                        self.clear_fleet_orders()
                        self.clear_target()
                        if aistate.get_fleet_role(fleet_id) in (
                                MissionType.MILITARY, MissionType.SECURE):
                            allocations = MilitaryAI.get_military_fleets(
                                mil_fleets_ids=[fleet_id],
                                try_reset=False,
                                thisround="Fleet %d Reassignment" % fleet_id)
                            if allocations:
                                MilitaryAI.assign_military_fleets_to_systems(
                                    use_fleet_id_list=[fleet_id],
                                    allocations=allocations)
                    else:  # no orders
                        debug("No Current Orders")
                else:
                    # TODO: evaluate releasing a smaller portion or none of the ships
                    system_status = aistate.systemStatus.setdefault(
                        last_sys_target, {})
                    new_fleets = []
                    threat_present = system_status.get(
                        'totalThreat', 0) + system_status.get(
                            'neighborThreat', 0) > 0
                    target_system = universe.getSystem(last_sys_target)
                    if not threat_present and target_system:
                        for pid in target_system.planetIDs:
                            planet = universe.getPlanet(pid)
                            if (planet and planet.owner != fo.empireID()
                                    and planet.currentMeterValue(
                                        fo.meterType.maxDefense) > 0):
                                threat_present = True
                                break
                    if not threat_present:
                        debug(
                            "No current threat in target system; releasing a portion of ships."
                        )
                        # at least first stage of current task is done;
                        # release extra ships for potential other deployments
                        new_fleets = FleetUtilsAI.split_fleet(self.fleet.id)
                    else:
                        debug(
                            "Threat remains in target system; NOT releasing any ships."
                        )
                    new_military_fleets = []
                    for fleet_id in new_fleets:
                        if aistate.get_fleet_role(
                                fleet_id) in COMBAT_MISSION_TYPES:
                            new_military_fleets.append(fleet_id)
                    allocations = []
                    if new_military_fleets:
                        allocations = MilitaryAI.get_military_fleets(
                            mil_fleets_ids=new_military_fleets,
                            try_reset=False,
                            thisround="Fleet Reassignment %s" %
                            new_military_fleets)
                    if allocations:
                        MilitaryAI.assign_military_fleets_to_systems(
                            use_fleet_id_list=new_military_fleets,
                            allocations=allocations)
예제 #36
0
    def _get_target_for_protection_mission(self):
        """Get a target for a PROTECT_REGION mission.

        1) If primary target (system target of this mission) is under attack, move to primary target.
        2) If neighbors of primary target have local enemy forces weaker than this fleet, may move to attack
        3) If no neighboring fleets or strongest enemy force is too strong, move to defend primary target
        """
        # TODO: Also check fleet rating vs planets in decision making below not only vs fleets
        universe = fo.getUniverse()
        primary_objective = self.target.id
        debug("Trying to find target for protection mission. Target: %s", self.target)
        immediate_threat = MilitaryAI.get_system_local_threat(primary_objective)
        if immediate_threat:
            debug("Immediate threat! Moving to primary mission target")
            return primary_objective
        else:
            debug("No immediate threats.")
            # Try to eliminate neighbouring fleets
            neighbors = universe.getImmediateNeighbors(primary_objective, fo.empireID())
            threat_list = sorted(map(
                lambda x: (MilitaryAI.get_system_local_threat(x), x),
                neighbors
            ), reverse=True)

            if not threat_list:
                debug("No neighbors (?!). Moving to primary mission target")
                return primary_objective

            debug("%s", threat_list)
            top_threat, candidate_system = threat_list[0]
            if not top_threat:
                # TODO: Move into second ring but needs more careful evaluation
                # For now, consider staying at the current location if enemy
                # owns a planet here which we can bombard.
                current_system_id = self.fleet.get_current_system_id()
                if current_system_id in neighbors:
                    system = universe.getSystem(current_system_id)
                    if assertion_fails(system is not None):
                        return primary_objective
                    empire_id = fo.empireID()
                    for planet_id in system.planetIDs:
                        planet = universe.getPlanet(planet_id)
                        if (planet and
                                not planet.ownedBy(empire_id) and
                                not planet.unowned):
                            debug("Currently no neighboring threats. "
                                  "Staying for bombardment of planet %s", planet)
                            self.clear_fleet_orders()
                            self.set_target(MissionType.MILITARY, TargetSystem(current_system_id))
                            self.generate_fleet_orders()
                            self.issue_fleet_orders()
                            return INVALID_ID

                # TODO consider attacking neighboring, non-military fleets
                # - needs more careful evaluation against neighboring threats
                # empire_id = fo.empireID()
                # for sys_id in neighbors:
                #     system = universe.getSystem(sys_id)
                #     if assertion_fails(system is not None):
                #         continue
                #     local_fleets = system.fleetIDs
                #     for fleet_id in local_fleets:
                #         fleet = universe.getFleet(fleet_id)
                #         if not fleet or fleet.ownedBy(empire_id):
                #             continue
                #         return sys_id

                debug("No neighboring threats. Moving to primary mission target")
                return primary_objective

            # TODO rate against threat in target system
            # TODO only engage if can reach in 1 turn or leaves sufficient defense behind
            fleet_rating = CombatRatingsAI.get_fleet_rating(self.fleet.id)
            debug("This fleet rating: %d. Enemy Rating: %d", fleet_rating, top_threat)
            safety_factor = get_aistate().character.military_safety_factor()
            if fleet_rating < safety_factor*top_threat:
                debug("Neighboring threat is too powerful. Moving to primary mission target")
                return primary_objective  # do not engage!

            debug("Engaging neighboring threat: %d", candidate_system)
            return candidate_system
예제 #37
0
    def issueAIFleetOrders(self):
        "issues AIFleetOrders which can be issued in system and moves to next one if is possible"

        # TODO: priority
        ordersCompleted = True
        print "Checking orders for fleet %d"%(self.getAITargetID())
        #print "\t Full Orders are:"
        #for aiFleetOrder2 in self.getAIFleetOrders():
        #    print "\t\t %s"%aiFleetOrder2
        for aiFleetOrder in self.getAIFleetOrders():
            print "   %s"%(aiFleetOrder)
            clearAll=False
            if aiFleetOrder.getAIFleetOrderType() in [EnumsAI.AIFleetOrderType.ORDER_COLONISE,  EnumsAI.AIFleetOrderType.ORDER_OUTPOST]:#TODO: invasion?
                universe=fo.getUniverse()
                planet = universe.getPlanet(aiFleetOrder.getTargetAITarget().getTargetID())
                if  not planet:
                    clearAll =True
                elif aiFleetOrder.getAIFleetOrderType() == EnumsAI.AIFleetOrderType.ORDER_COLONISE :
                    if  ( (planet.currentMeterValue(fo.meterType.population) >0) or  not ( planet.unowned  or planet.ownedBy(fo.empireID()) ) ) :
                        clearAll =True
                elif not planet.unowned:
                        clearAll =True
                if clearAll:
                    print "Fleet %d had a target planet that is no longer valid for this mission; aborting."%(self.getAITargetID() )
                    self.clearAIFleetOrders()
                    self.clearAITargets(([-1]+ self.getAIMissionTypes()[:1])[-1])
                    FleetUtilsAI.splitFleet(self.getAITargetID() )
                    return
            self.checkMergers(context=str(aiFleetOrder))
            if aiFleetOrder.canIssueOrder(verbose=True):
                #print "    " + str(aiFleetOrder) currently already printed in canIssueOrder()
                if aiFleetOrder.getAIFleetOrderType() == EnumsAI.AIFleetOrderType.ORDER_MOVE and ordersCompleted: #only move if all other orders completed
                    aiFleetOrder.issueOrder()
                elif aiFleetOrder.getAIFleetOrderType() not in [ EnumsAI.AIFleetOrderType.ORDER_MOVE,  EnumsAI.AIFleetOrderType.ORDER_DEFEND]:
                    aiFleetOrder.issueOrder()
                if not aiFleetOrder.isExecutionCompleted():
                    ordersCompleted = False
            else: #check that we're not held up by a Big Monster
                if aiFleetOrder.getAIFleetOrderType() == EnumsAI.AIFleetOrderType.ORDER_MOVE:
                    thisSysID = aiFleetOrder.getTargetAITarget().getTargetID()
                    thisStatus = foAI.foAIstate.systemStatus.setdefault(thisSysID, {})
                    if ( thisStatus.get('monsterThreat', 0) >  fo.currentTurn() * ProductionAI.curBestMilShipRating()/4.0 )   :
                        if ( ( (self.getAIMissionTypes() + [-1] )[0] not in [  EnumsAI.AIFleetMissionType.FLEET_MISSION_ATTACK,   
                                                                                        EnumsAI.AIFleetMissionType.FLEET_MISSION_MILITARY, 
                                                                                        EnumsAI.AIFleetMissionType.FLEET_MISSION_HIT_AND_RUN, 
                                                                                        EnumsAI.AIFleetMissionType.FLEET_MISSION_SECURE, 
                                                                                    ])  or
                             (  aiFleetOrder !=   self.getAIFleetOrders()[-1]  )   # if this move order is not this mil fleet's final destination, and blocked by Big Monster, release and hope for more effective reassignment
                             ):
                            print "Aborting mission due to being blocked by Big Monster at system %d ,  threat %d"%(thisSysID,  foAI.foAIstate.systemStatus[thisSysID]['monsterThreat'])
                            print "Full set of orders were:"
                            for aiFleetOrder2 in self.getAIFleetOrders():
                                print "\t\t %s"%aiFleetOrder2
                            self.clearAIFleetOrders()
                            self.clearAITargets(([-1]+ self.getAIMissionTypes()[:1])[-1])
                            return
            # moving to another system stops issuing all orders in system where fleet is
            # move order is also the last order in system
            if aiFleetOrder.getAIFleetOrderType() == EnumsAI.AIFleetOrderType.ORDER_MOVE:
                fleet = fo.getUniverse().getFleet( self.getAITargetID() )
                if fleet.systemID != aiFleetOrder.getTargetAITarget().getTargetID():
                    break
        else: #went through entire order list
            if ordersCompleted:
                orders=self.getAIFleetOrders()
                lastOrder= orders and orders[-1]
                universe=fo.getUniverse()
                if orders and lastOrder.getAIFleetOrderType() == EnumsAI.AIFleetOrderType.ORDER_COLONISE:
                    planet = universe.getPlanet(lastOrder.getTargetAITarget().getTargetID())
                    pop=planet.currentMeterValue(fo.meterType.population)
                    if pop==0:
                        print "Fleet %d has tentatively completed its colonize mission but will wait to confirm population."%(self.getAITargetID() )
                        print "    Order details are %s"%lastOrder
                        print "    Order is valid: %s ; is Executed : %s  ; is execution completed: %s "%(lastOrder.isValid(),  lastOrder.isExecuted(),  lastOrder.isExecutionCompleted())
                        if not lastOrder.isValid():
                            sourceT = lastOrder.getSourceAITarget()
                            targT = lastOrder.getTargetAITarget()
                            print "        source target validity: %s   ; target target validity: %s "%(sourceT.isValid() ,  targT.isValid())
                            if EnumsAI.AITargetType.TARGET_SHIP == sourceT:
                                shipID = sourceT.getTargetID()
                                ship = universe.getShip(shipID)
                                if not ship:
                                    print "Ship id %d not a valid ship id"%(shipID)
                                print "        source target Ship (%d), species %s,   can%s colonize"%(   shipID,  ship.speciesName,    ["not", ""][ship.canColonize])
                        return  # colonize order must not have completed yet
                clearAll=True
                if orders and lastOrder.getAIFleetOrderType() == EnumsAI.AIFleetOrderType.ORDER_MILITARY:
                    # if (AIFleetMissionType.FLEET_MISSION_SECURE in self.getAIMissionTypes())  or   # not doing this until decide a way to release from a SECURE mission
                    if   (lastOrder.getTargetAITarget().getTargetID() in list(set(AIstate.colonyTargetedSystemIDs + AIstate.outpostTargetedSystemIDs + 
                                                                                                                                                AIstate.invasionTargetedSystemIDs + AIstate.blockadeTargetedSystemIDs))): #consider a secure mission
                        print "Fleet %d has completed initial stage of its mission to secure system %d, may release a portion of ships"%(self.getAITargetID() ,  lastOrder.getTargetAITarget().getTargetID())
                        clearAll=False
                fleetID=self.getAITargetID()
                fleet=universe.getFleet(fleetID)
                if fleet.systemID != -1:
                    loc = fleet.systemID
                else:
                    loc=fleet.nextSystemID
                if clearAll:
                    print "Fleet %d has completed its mission; clearing all orders and targets."%(self.getAITargetID() )
                    print "Full set of orders were:"
                    for aiFleetOrder2 in self.getAIFleetOrders():
                        print "\t\t %s"%aiFleetOrder2
                    self.clearAIFleetOrders()
                    self.clearAITargets(([-1]+ self.getAIMissionTypes()[:1])[-1])
                    if foAI.foAIstate.getFleetRole(fleetID) in [    EnumsAI.AIFleetMissionType.FLEET_MISSION_MILITARY, 
                                                                                                                        EnumsAI.AIFleetMissionType.FLEET_MISSION_ATTACK,  
                                                                                                                        EnumsAI.AIFleetMissionType.FLEET_MISSION_DEFEND, 
                                                                                                                        EnumsAI.AIFleetMissionType.FLEET_MISSION_HIT_AND_RUN, 
                                                                                                                        EnumsAI.AIFleetMissionType.FLEET_MISSION_SECURE       ]:
                        allocations = MilitaryAI.getMilitaryFleets(milFleetIDs=[fleetID],  tryReset=False,  round="Fleet %d Reassignment"%fleetID)
                        if allocations:
                            MilitaryAI.assignMilitaryFleetsToSystems(useFleetIDList=[fleetID],  allocations=allocations)
                else:
                    #TODO: evaluate releasing a smaller portion or none of the ships 
                    newFleets=FleetUtilsAI.splitFleet(self.getAITargetID() ) #at least first stage of current task is done; release extra ships for potential other deployments
                    newMilFleets = []
                    for fleetID in newFleets:
                        if foAI.foAIstate.getFleetRole(fleetID) in [    EnumsAI.AIFleetMissionType.FLEET_MISSION_MILITARY, 
                                                                                                                            EnumsAI.AIFleetMissionType.FLEET_MISSION_ATTACK,  
                                                                                                                            EnumsAI.AIFleetMissionType.FLEET_MISSION_DEFEND, 
                                                                                                                            EnumsAI.AIFleetMissionType.FLEET_MISSION_HIT_AND_RUN, 
                                                                                                                            EnumsAI.AIFleetMissionType.FLEET_MISSION_SECURE       ]:
                            newMilFleets.append(fleetID)
                    allocations = MilitaryAI.getMilitaryFleets(milFleetIDs=newMilFleets,  tryReset=False,  round="Fleet Reassignment %s"%newMilFleets)
                    if allocations:
                        MilitaryAI.assignMilitaryFleetsToSystems(useFleetIDList=newMilFleets,  allocations=allocations)
예제 #38
0
def generateOrders():
    global lastTurnTimestamp
    universe = fo.getUniverse()
    turnStartTime=time() #starting AI timer here, to be sure AI doesn't get blame for any  lags in server being able to provide the Universe object
    empire = fo.getEmpire()
    planetID = PlanetUtilsAI.getCapital()
    planet=None
    if planetID is not None:
        planet = universe.getPlanet(planetID)
    print "***************************************************************************"
    print "***************************************************************************"
    print ("Generating Orders")
    print "EmpireID:    " + str(empire.empireID) + " Name: " + empire.name+ "_"+str(empire.empireID-1) +"_pid:"+str(fo.playerID())+"_"+fo.playerName()+"_"+aggressions.get(foAIstate.aggression,  "?") + " Turn: " + str(fo.currentTurn())
    empireColor=empire.colour
    print "EmpireColors: %d %d %d %d"%(empireColor.r,  empireColor.g,  empireColor.b,  empireColor.a)
    if planet: 
        print "CapitalID: " + str(planetID) + " Name: " + planet.name + " Species: " + planet.speciesName 
    else:
        print "CapitalID: None Currently      Name: None     Species: None "
    print "***************************************************************************"
    print "***************************************************************************"
    
    if fo.currentTurn() == 1:
        declareWarOnAll()

    # turn cleanup !!! this was formerly done at start of every turn -- not sure why
    splitNewFleets()

    #updateShipDesigns()   #should not be needed anymore;
    #updateFleetsRoles()
    
    foAIstate.clean() #checks exploration border & clears roles/missions of missing fleets & updates fleet locs
    foAIstate.reportSystemThreats()
    # ...missions
    # ...demands/priorities

    print("Calling AI Modules")

    # call AI modules
    timer=[time()]
    try: PriorityAI.calculatePriorities()
    except: print "Error: exception triggered and caught:  ",  traceback.format_exc() # try traceback.print_exc()
    timer.append( time()  )
    try: ExplorationAI.assignScoutsToExploreSystems()
    except: print "Error: exception triggered and caught:  ",  traceback.format_exc()
    timer.append( time()  )
    try: ColonisationAI.assignColonyFleetsToColonise()
    except: print "Error: exception triggered and caught:  ",  traceback.format_exc()
    timer.append( time()  )
    try: InvasionAI.assignInvasionFleetsToInvade()
    except: print "Error: exception triggered and caught:  ",  traceback.format_exc()
    timer.append( time()  )
    try: MilitaryAI.assignMilitaryFleetsToSystems()
    except: print "Error: exception triggered and caught:  ",  traceback.format_exc()
    timer.append( time()  )
    try: FleetUtilsAI.generateAIFleetOrdersForAIFleetMissions()
    except: print "Error: exception triggered and caught:  ",  traceback.format_exc()
    timer.append( time()  )
    try: FleetUtilsAI.issueAIFleetOrdersForAIFleetMissions()
    except: print "Error: exception triggered and caught:  ",  traceback.format_exc()
    timer.append( time()  )
    try: ResearchAI.generateResearchOrders()
    except: print "Error: exception triggered and caught:  ",  traceback.format_exc()
    timer.append( time()  )
    try: ProductionAI.generateProductionOrders()
    except: print "Error: exception triggered and caught:  ",  traceback.format_exc()
    timer.append( time()  )
    try: ResourcesAI.generateResourcesOrders()    
    except: print "Error: exception triggered and caught:  ",  traceback.format_exc()
    timer.append( time()  )
    try: foAIstate.afterTurnCleanup()
    except: print "Error: exception triggered and caught:  ",  traceback.format_exc()
    timer.append( time()  )
    times = [timer[i] - timer[i-1] for i in range(1,  len(timer) ) ]
    turnEndTime=time()
    timeFmt = "%30s: %8d msec  "
    print "AI Module Time Requirements:"
    for mod,  modTime in zip(__timerEntries,  times):
        print timeFmt%((30*' '+mod)[-30:],  int(1000*modTime))
    if __timerFile:
        __timerFile.write(  __timerFileFmt%tuple( [ fo.currentTurn() ]+map(lambda x: int(1000*x),  times )) +'\n')
        __timerFile.flush()
    if __timerBucketFile:
        __timerBucketFile.write(  __timerBucketFileFmt%tuple( [ fo.currentTurn(),  (turnStartTime-lastTurnTimestamp)*1000, (turnEndTime-turnStartTime)*1000   ]) +'\n')
        __timerBucketFile.flush()
        lastTurnTimestamp = time()
        
    try: fo.doneTurn()
    except: print "Error: exception triggered and caught:  ",  traceback.format_exc()
예제 #39
0
    def update_system_status(self):
        print 10 * "=", "Updating System Threats", 10 * "="
        universe = fo.getUniverse()
        empire = fo.getEmpire()
        empire_id = fo.empireID()
        destroyed_object_ids = universe.destroyedObjectIDs(empire_id)
        supply_unobstructed_systems = set(empire.supplyUnobstructedSystems)
        min_hidden_attack = 4
        min_hidden_health = 8
        system_id_list = universe.systemIDs  # will normally look at this, the list of all known systems

        # for use in debugging
        verbose = False

        # assess enemy fleets that may have been momentarily visible
        cur_e_fighters = {
            CombatRatingsAI.default_ship_stats().get_stats(hashable=True): [0]
        }  # start with a dummy entry
        old_e_fighters = {
            CombatRatingsAI.default_ship_stats().get_stats(hashable=True): [0]
        }  # start with a dummy entry
        enemy_fleet_ids = []
        enemies_by_system = {}
        my_fleets_by_system = {}
        fleet_spot_position = {}
        saw_enemies_at_system = {}
        my_milship_rating = MilitaryAI.cur_best_mil_ship_rating()
        current_turn = fo.currentTurn()
        for fleet_id in universe.fleetIDs:
            fleet = universe.getFleet(fleet_id)
            if fleet is None:
                continue
            if not fleet.empty:
                # TODO: check if currently in system and blockaded before accepting destination as location
                this_system_id = (fleet.nextSystemID != INVALID_ID
                                  and fleet.nextSystemID) or fleet.systemID
                if fleet.ownedBy(empire_id):
                    if fleet_id not in destroyed_object_ids:
                        my_fleets_by_system.setdefault(this_system_id,
                                                       []).append(fleet_id)
                        fleet_spot_position.setdefault(fleet.systemID,
                                                       []).append(fleet_id)
                else:
                    dead_fleet = fleet_id in destroyed_object_ids
                    if not fleet.ownedBy(-1) and (fleet.hasArmedShips
                                                  or fleet.hasFighterShips):
                        ship_stats = CombatRatingsAI.FleetCombatStats(
                            fleet_id).get_ship_stats(hashable=True)
                        e_f_dict = [
                            cur_e_fighters, old_e_fighters
                        ][dead_fleet]  # track old/dead enemy fighters for rating assessments in case not enough current info
                        for stats in ship_stats:
                            attacks = stats[0]
                            if attacks:
                                e_f_dict.setdefault(stats, [0])[0] += 1
                    partial_vis_turn = universe.getVisibilityTurnsMap(
                        fleet_id, empire_id).get(fo.visibility.partial, -9999)
                    if not dead_fleet:
                        # TODO: consider checking death of individual ships.  If ships had been moved from this fleet
                        # into another fleet, we might have witnessed their death in that other fleet but if this fleet
                        # had not been seen since before that transfer then the ships might also still be listed here.
                        sys_status = self.systemStatus.setdefault(
                            this_system_id, {})
                        sys_status['enemy_ship_count'] = sys_status.get(
                            'enemy_ship_count', 0) + len(fleet.shipIDs)
                        if partial_vis_turn >= current_turn - 1:  # only interested in immediately recent data
                            saw_enemies_at_system[fleet.systemID] = True
                            enemy_fleet_ids.append(fleet_id)
                            enemies_by_system.setdefault(this_system_id,
                                                         []).append(fleet_id)
                            if not fleet.ownedBy(-1):
                                self.misc.setdefault('enemies_sighted',
                                                     {}).setdefault(
                                                         current_turn,
                                                         []).append(fleet_id)
                                rating = CombatRatingsAI.get_fleet_rating(
                                    fleet_id,
                                    enemy_stats=CombatRatingsAI.
                                    get_empire_standard_fighter())
                                if rating > 0.25 * my_milship_rating:
                                    self.misc.setdefault(
                                        'dangerous_enemies_sighted',
                                        {}).setdefault(current_turn,
                                                       []).append(fleet_id)
        e_f_dict = [cur_e_fighters, old_e_fighters][len(cur_e_fighters) == 1]
        std_fighter = sorted([(v, k) for k, v in e_f_dict.items()])[-1][1]
        self.__empire_standard_enemy = std_fighter
        self.empire_standard_enemy_rating = self.get_standard_enemy(
        ).get_rating()
        # TODO: If no current information available, rate against own fighters

        # assess fleet and planet threats & my local fleets
        for sys_id in system_id_list:
            sys_status = self.systemStatus.setdefault(sys_id, {})
            system = universe.getSystem(sys_id)
            if verbose:
                print "AIState threat evaluation for %s" % system
            # update fleets
            sys_status['myfleets'] = my_fleets_by_system.get(sys_id, [])
            sys_status['myFleetsAccessible'] = fleet_spot_position.get(
                sys_id, [])
            local_enemy_fleet_ids = enemies_by_system.get(sys_id, [])
            sys_status['localEnemyFleetIDs'] = local_enemy_fleet_ids
            if system:
                sys_status['name'] = system.name
                for fid in system.fleetIDs:
                    if fid in destroyed_object_ids:  # TODO: double check are these checks/deletes necessary?
                        self.delete_fleet_info(
                            fid)  # this is safe even if fleet wasn't mine
                        continue
                    fleet = universe.getFleet(fid)
                    if not fleet or fleet.empty:
                        self.delete_fleet_info(
                            fid)  # this is safe even if fleet wasn't mine
                        continue

            # update threats
            sys_vis_dict = universe.getVisibilityTurnsMap(
                sys_id, fo.empireID())
            partial_vis_turn = sys_vis_dict.get(fo.visibility.partial, -9999)
            mob_ratings = []  # for mobile unowned monster fleets
            lost_fleet_rating = 0
            enemy_ratings = []
            monster_ratings = []
            mobile_fleets = []
            for fid in local_enemy_fleet_ids:
                fleet = universe.getFleet(fid)
                if not fleet:
                    continue
                fleet_rating = CombatRatingsAI.get_fleet_rating(
                    fid,
                    enemy_stats=CombatRatingsAI.get_empire_standard_fighter())
                if fleet.speed == 0:
                    monster_ratings.append(fleet_rating)
                    if verbose:
                        print "\t immobile enemy fleet %s has rating %.1f" % (
                            fleet, fleet_rating)
                else:
                    if verbose:
                        print "\t mobile enemy fleet %s has rating %.1f" % (
                            fleet, fleet_rating)
                    mobile_fleets.append(fid)
                    if fleet.unowned:
                        mob_ratings.append(fleet_rating)
                    else:
                        enemy_ratings.append(fleet_rating)
            enemy_rating = CombatRatingsAI.combine_ratings_list(enemy_ratings)
            monster_rating = CombatRatingsAI.combine_ratings_list(
                monster_ratings)
            mob_rating = CombatRatingsAI.combine_ratings_list(mob_ratings)
            if fleetsLostBySystem.get(sys_id, []):
                lost_fleet_rating = CombatRatingsAI.combine_ratings_list(
                    fleetsLostBySystem[sys_id])
            if not system or partial_vis_turn == -9999:  # under current visibility rules should not be possible to have any losses or other info here, but just in case...
                if verbose:
                    print "Have never had partial vis for system %d ( %s ) -- basing threat assessment on old info and lost ships" % (
                        sys_id, sys_status.get('name', "name unknown"))
                sys_status.setdefault('local_fleet_threats', set())
                sys_status['planetThreat'] = 0
                sys_status['fleetThreat'] = int(
                    max(
                        CombatRatingsAI.combine_ratings(
                            enemy_rating, mob_rating),
                        0.98 * sys_status.get('fleetThreat', 0),
                        1.1 * lost_fleet_rating - monster_rating))
                sys_status['monsterThreat'] = int(
                    max(monster_rating,
                        0.98 * sys_status.get('monsterThreat', 0),
                        1.1 * lost_fleet_rating - enemy_rating - mob_rating))
                sys_status['enemy_threat'] = int(
                    max(enemy_rating, 0.98 * sys_status.get('enemy_threat', 0),
                        1.1 * lost_fleet_rating - monster_rating - mob_rating))
                sys_status['mydefenses'] = {
                    'overall': 0,
                    'attack': 0,
                    'health': 0
                }
                sys_status['totalThreat'] = sys_status['fleetThreat']
                sys_status['regional_fleet_threats'] = sys_status[
                    'local_fleet_threats'].copy()
                continue

            # have either stale or current info
            pattack = 0
            phealth = 0
            mypattack, myphealth = 0, 0
            for pid in system.planetIDs:
                prating = self.assess_planet_threat(pid,
                                                    sighting_age=current_turn -
                                                    partial_vis_turn)
                planet = universe.getPlanet(pid)
                if not planet:
                    continue
                if planet.owner == self.empireID:  # TODO: check for diplomatic status
                    mypattack += prating['attack']
                    myphealth += prating['health']
                else:
                    if [
                            special for special in planet.specials
                            if "_NEST_" in special
                    ]:
                        sys_status['nest_threat'] = 100
                    pattack += prating['attack']
                    phealth += prating['health']
            sys_status['planetThreat'] = pattack * phealth
            sys_status['mydefenses'] = {
                'overall': mypattack * myphealth,
                'attack': mypattack,
                'health': myphealth
            }

            if max(
                    sys_status.get('totalThreat', 0), pattack * phealth
            ) >= 0.6 * lost_fleet_rating:  # previous threat assessment could account for losses, ignore the losses now
                lost_fleet_rating = 0

            # TODO use sitrep combat info rather than estimating stealthed enemies by fleets lost to them
            # TODO also only consider past stealthed fleet threat to still be present if the system is still obstructed
            # TODO: track visibility across turns in order to distinguish the blip of visibility in (losing) combat,
            # which FO currently treats as being for the previous turn, partially superseding the previous visibility for that turn
            if not partial_vis_turn == current_turn:  # (universe.getVisibility(sys_id, self.empire_id) >= fo.visibility.partial):
                sys_status.setdefault('local_fleet_threats', set())
                sys_status['currently_visible'] = False
                # print "Stale visibility for system %d ( %s ) -- last seen %d, current Turn %d -- basing threat assessment on old info and lost ships"%(sys_id, sys_status.get('name', "name unknown"), partial_vis_turn, currentTurn)
                sys_status['fleetThreat'] = int(
                    max(
                        CombatRatingsAI.combine_ratings(
                            enemy_rating, mob_rating),
                        0.98 * sys_status.get('fleetThreat', 0),
                        2.0 * lost_fleet_rating -
                        max(sys_status.get('monsterThreat', 0),
                            monster_rating)))
                sys_status['enemy_threat'] = int(
                    max(
                        enemy_rating, 0.98 * sys_status.get('enemy_threat', 0),
                        1.1 * lost_fleet_rating -
                        max(sys_status.get('monsterThreat', 0),
                            monster_rating)))
                sys_status['monsterThreat'] = int(
                    max(monster_rating,
                        0.98 * sys_status.get('monsterThreat', 0)))
                # sys_status['totalThreat'] = ((pattack + enemy_attack + monster_attack) ** 0.8) * ((phealth + enemy_health + monster_health)** 0.6)  # reevaluate this
                sys_status['totalThreat'] = max(
                    CombatRatingsAI.combine_ratings_list([
                        enemy_rating, mob_rating, monster_rating,
                        pattack * phealth
                    ]), 2 * lost_fleet_rating,
                    0.98 * sys_status.get('totalThreat', 0))
            else:  # system considered visible #TODO: reevaluate as visibility rules change
                sys_status['currently_visible'] = True
                sys_status['local_fleet_threats'] = set(mobile_fleets)
                sys_status['fleetThreat'] = int(
                    max(
                        CombatRatingsAI.combine_ratings(
                            enemy_rating, mob_rating), 2 * lost_fleet_rating -
                        monster_rating))  # includes mobile monsters
                if verbose:
                    print "enemy threat calc parts: enemy rating %.1f, lost fleet rating %.1f, monster_rating %.1f" % (
                        enemy_rating, lost_fleet_rating, monster_rating)
                sys_status['enemy_threat'] = int(
                    max(enemy_rating, 2 * lost_fleet_rating -
                        monster_rating))  # does NOT include mobile monsters
                sys_status['monsterThreat'] = monster_rating
                sys_status[
                    'totalThreat'] = CombatRatingsAI.combine_ratings_list([
                        enemy_rating, mob_rating, monster_rating,
                        pattack * phealth
                    ])
            sys_status['regional_fleet_threats'] = sys_status[
                'local_fleet_threats'].copy()
            sys_status['fleetThreat'] = max(sys_status['fleetThreat'],
                                            sys_status.get('nest_threat', 0))
            sys_status['totalThreat'] = max(sys_status['totalThreat'],
                                            sys_status.get('nest_threat', 0))

            if partial_vis_turn > 0 and sys_id not in supply_unobstructed_systems:  # has been seen with Partial Vis, but is currently supply-blocked
                sys_status['fleetThreat'] = max(
                    sys_status['fleetThreat'],
                    min_hidden_attack * min_hidden_health)
                sys_status['totalThreat'] = max(
                    sys_status['totalThreat'],
                    ((pattack + min_hidden_attack)**0.8) *
                    ((phealth + min_hidden_health)**0.6))
            if verbose and sys_status['fleetThreat'] > 0:
                print "%s intermediate status: %s" % (system, sys_status)

        enemy_supply, enemy_near_supply = self.assess_enemy_supply(
        )  # TODO: assess change in enemy supply over time
        # assess secondary threats (threats of surrounding systems) and update my fleet rating
        for sys_id in system_id_list:
            sys_status = self.systemStatus[sys_id]
            sys_status['enemies_supplied'] = enemy_supply.get(sys_id, [])
            sys_status['enemies_nearly_supplied'] = enemy_near_supply.get(
                sys_id, [])
            my_ratings_list = []
            my_ratings_against_planets_list = []
            for fid in sys_status['myfleets']:
                this_rating = self.get_rating(fid, True,
                                              self.get_standard_enemy())
                my_ratings_list.append(this_rating)
                my_ratings_against_planets_list.append(
                    self.get_rating(fid, against_planets=True))
            if sys_id != INVALID_ID:
                sys_status[
                    'myFleetRating'] = CombatRatingsAI.combine_ratings_list(
                        my_ratings_list)
                sys_status[
                    'myFleetRatingVsPlanets'] = CombatRatingsAI.combine_ratings_list(
                        my_ratings_against_planets_list)
                sys_status[
                    'all_local_defenses'] = CombatRatingsAI.combine_ratings(
                        sys_status['myFleetRating'],
                        sys_status['mydefenses']['overall'])
            sys_status['neighbors'] = set(
                dict_from_map(
                    universe.getSystemNeighborsMap(sys_id, self.empireID)))

        for sys_id in system_id_list:
            sys_status = self.systemStatus[sys_id]
            neighbors = sys_status.get('neighbors', set())
            this_system = fo.getUniverse().getSystem(sys_id)
            if verbose:
                print "Regional Assessment for %s with local fleet threat %.1f" % (
                    this_system, sys_status.get('fleetThreat', 0))
            jumps2 = set()
            jumps3 = set()
            jumps4 = set()
            for seta, setb in [(neighbors, jumps2), (jumps2, jumps3),
                               (jumps3, jumps4)]:
                for sys2id in seta:
                    setb.update(
                        self.systemStatus.get(sys2id,
                                              {}).get('neighbors', set()))
            jump2ring = jumps2 - neighbors - {sys_id}
            jump3ring = jumps3 - jumps2 - neighbors - {sys_id}
            jump4ring = jumps4 - jumps3 - jumps2 - neighbors - {sys_id}
            sys_status['2jump_ring'] = jump2ring
            sys_status['3jump_ring'] = jump3ring
            sys_status['4jump_ring'] = jump4ring
            threat, max_threat, myrating, j1_threats = self.area_ratings(
                neighbors, ref_sys_name="neighbors %s" %
                this_system) if verbose else self.area_ratings(neighbors)
            sys_status['neighborThreat'] = threat
            sys_status['max_neighbor_threat'] = max_threat
            sys_status['my_neighbor_rating'] = myrating
            threat, max_threat, myrating, j2_threats = self.area_ratings(
                jump2ring, ref_sys_name="jump2 %s" %
                this_system) if verbose else self.area_ratings(jump2ring)
            sys_status['jump2_threat'] = threat
            sys_status['my_jump2_rating'] = myrating
            threat, max_threat, myrating, j3_threats = self.area_ratings(
                jump3ring)
            sys_status['jump3_threat'] = threat
            sys_status['my_jump3_rating'] = myrating
            threat_keys = ['fleetThreat', 'neighborThreat', 'jump2_threat'
                           ]  # for local system includes both enemies and mobs
            sys_status[
                'regional_threat'] = CombatRatingsAI.combine_ratings_list(
                    map(lambda x: sys_status.get(x, 0), threat_keys))
            # TODO: investigate cases where regional_threat has been nonzero but no regional_threat_fleets
            # (probably due to attenuating history of past threats)
            sys_status.setdefault('regional_fleet_threats',
                                  set()).update(j1_threats, j2_threats)
    def can_issue_order(self, verbose=False):
        """If FleetOrder can be issued now."""
        # for some orders, may need to re-issue if invasion/outposting/colonization was interrupted
        if self.executed and self.order_type not in [AIFleetOrderType.ORDER_OUTPOST, AIFleetOrderType.ORDER_COLONISE, AIFleetOrderType.ORDER_INVADE]:
            return False
        if not self.is_valid():
            return False
        universe = fo.getUniverse()
        ship_id = None
        fleet_id = self.fleet.target_id
        fleet = universe.getFleet(fleet_id)
        system_id = fleet.systemID
        target_id = self.target.target_id

        if verbose:
            sys1 = universe.getSystem(system_id)
            sys_name = sys1 and sys1.name or "unknown"
            main_fleet_mission = foAI.foAIstate.get_fleet_mission(fleet_id)
            main_mission_type = (main_fleet_mission.get_mission_types() + [-1])[0]
            print "** %s -- Mission Type  %s (%s) , current loc sys %d  - %s" % (self, AIFleetMissionTypeNames.name(main_mission_type), main_mission_type, system_id, sys_name)
        #
        # outpost
        #
        if AIFleetOrderType.ORDER_OUTPOST == self.order_type:  # TODO: check for separate fleet holding outpost ships

            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)
            ship = universe.getShip(ship_id)
            planet = universe.getPlanet(self.target.target_id)
            return ship is not None and fleet.systemID == planet.systemID and ship.canColonize
        #
        # colonise
        #
        elif AIFleetOrderType.ORDER_COLONISE == self.order_type:  # TODO: check for separate fleet holding colony ships
            if TargetType.TARGET_FLEET == self.fleet.target_type:
                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)
            ship = universe.getShip(ship_id)
            planet = universe.getPlanet(self.target.target_id)
            if ship and not ship.canColonize:
                print "Error: colonization fleet %d has no colony ship" % fleet_id
            return ship is not None and fleet.systemID == planet.systemID and ship.canColonize
        #
        # invade
        #
        elif AIFleetOrderType.ORDER_INVADE == self.order_type:  # TODO: check for separate fleet holding invasion ships
            if TargetType.TARGET_FLEET == self.fleet.target_type:
                ship_id = FleetUtilsAI.get_ship_id_with_role(fleet_id, AIShipRoleType.SHIP_ROLE_MILITARY_INVASION, False)
                if ship_id is None:
                    ship_id = FleetUtilsAI.get_ship_id_with_role(fleet_id, AIShipRoleType.SHIP_ROLE_BASE_INVASION)
            ship = universe.getShip(ship_id)
            planet = universe.getPlanet(self.target.target_id)
            return ship is not None and fleet.systemID == planet.systemID and ship.canInvade and not planet.currentMeterValue(fo.meterType.shield)
        #
        # military
        #
        elif AIFleetOrderType.ORDER_MILITARY == self.order_type:
            if TargetType.TARGET_FLEET == self.fleet.target_type:
                ship_id = FleetUtilsAI.get_ship_id_with_role(fleet_id, AIShipRoleType.SHIP_ROLE_MILITARY)
            ship = universe.getShip(ship_id)
            system = universe.getSystem(self.target.target_id)
            return ship is not None and fleet.systemID == system.systemID and ship.isArmed
        #
        # split fleet
        #
        elif AIFleetOrderType.ORDER_SPLIT_FLEET == self.order_type:
            return len(fleet.shipIDs) > 1
        #
        # move -- have fleets will do a safety check, also check for potential military fleet mergers
        #
        elif AIFleetOrderType.ORDER_MOVE == self.order_type:
            #  target_id = self.target.target_id
            # TODO: figure out better way to have invasions (& possibly colonizations) require visibility on target without needing visibility of all intermediate systems
            if False and main_mission_type not in [AIFleetMissionType.FLEET_MISSION_ATTACK,  # TODO: consider this later
                                                 AIFleetMissionType.FLEET_MISSION_MILITARY,
                                                 AIFleetMissionType.FLEET_MISSION_SECURE,
                                                 AIFleetMissionType.FLEET_MISSION_HIT_AND_RUN,
                                                 AIFleetMissionType.FLEET_MISSION_EXPLORATION]:
                if not universe.getVisibility(target_id, foAI.foAIstate.empireID) >= fo.visibility.partial:
                    #if not target_id in interior systems
                    foAI.foAIstate.needsEmergencyExploration.append(fleet.systemID)
                    return False

            system_id = fleet.systemID
            if system_id == target_id:
                return True  # TODO: already there, but could consider retreating

            fleet_rating = foAI.foAIstate.get_rating(fleet_id).get('overall', 0)
            target_sys_status = foAI.foAIstate.systemStatus.get(target_id, {})
            f_threat = target_sys_status.get('fleetThreat', 0)
            m_threat = target_sys_status.get('monsterThreat', 0)
            p_threat = target_sys_status.get('planetThreat', 0)
            threat = f_threat + m_threat + p_threat
            safety_factor = MilitaryAI.get_safety_factor()
            if fleet_rating >= safety_factor * threat:
                return True
            else:
                sys1 = universe.getSystem(system_id)
                sys1_name = sys1 and sys1.name or "unknown"
                targ1 = universe.getSystem(target_id)
                targ1_name = (targ1 and targ1.name) or "unknown"
                # following line was poor because AIstate.militaryFleetIDs only covers fleets without current missions
                # my_other_fleet_rating = sum([foAI.foAIstate.fleetStatus.get(fleet_id, {}).get('rating', 0) for fleet_id in foAI.foAIstate.militaryFleetIDs if ( foAI.foAIstate.fleetStatus.get(fleet_id, {}).get('sysID', -1) == thisSystemID ) ])
                # myOtherFleetsRatings = [foAI.foAIstate.fleetStatus.get(fid, {}).get('rating', {}) for fid in foAI.foAIstate.systemStatus.get(target_id, {}).get('myfleets', [])]
                # my_other_fleet_rating = sum([foAI.foAIstate.fleetStatus.get(fid, {}).get('rating', 0) for fid in foAI.foAIstate.systemStatus.get( target_id, {}).get('myfleets', []) ])
                my_other_fleet_rating = foAI.foAIstate.systemStatus.get(target_id, {}).get('myFleetRating', 0)  # TODO: adjust calc for any departing fleets
                is_military = foAI.foAIstate.get_fleet_role(fleet_id) == AIFleetMissionType.FLEET_MISSION_MILITARY
                if ((my_other_fleet_rating > 3 * safety_factor * threat) or
                            (is_military and my_other_fleet_rating + fleet_rating > safety_factor * threat) or
                            (is_military and my_other_fleet_rating + fleet_rating > 0.8 * safety_factor * threat and fleet_rating > 0.2 * threat)):
                    if verbose:
                        print "\tAdvancing fleet %d (rating %d) at system %d (%s) into system %d (%s) with threat %d because of sufficient empire fleet strength already at destination" % (fleet_id, fleet_rating, system_id, sys1_name, target_id, targ1_name, threat)
                    return True
                elif threat == p_threat and not fleet.aggressive and not my_other_fleet_rating and not target_sys_status.get('localEnemyFleetIDs', [-1]):
                    if verbose:
                        print ("\tAdvancing fleet %d (rating %d) at system %d (%s) into system %d (%s) with planet threat %d because nonaggressive" +
                               " and no other fleets present to trigger combat") % (fleet_id, fleet_rating, system_id, sys1_name, target_id, targ1_name, threat)
                    return True
                else:
                    if verbose:
                        print "\tHolding fleet %d (rating %d) at system %d (%s) before travelling to system %d (%s) with threat %d" % (fleet_id, fleet_rating, system_id, sys1_name, target_id, targ1_name, threat)
                    return False
        else:  # default returns true
            return True
예제 #41
0
    def issue_fleet_orders(self):
        """issues AIFleetOrders which can be issued in system and moves to next one if is possible"""
        # TODO: priority
        order_completed = True

        debug("\nChecking orders for fleet %s (on turn %d), with mission type %s and target %s",
              self.fleet.get_object(), fo.currentTurn(), self.type or 'No mission', self.target or 'No Target')
        if MissionType.INVASION == self.type:
            self._check_retarget_invasion()
        just_issued_move_order = False
        last_move_target_id = INVALID_ID
        # Note: the following abort check somewhat assumes only one major mission type
        for fleet_order in self.orders:
            if (isinstance(fleet_order, (OrderColonize, OrderOutpost, OrderInvade)) and
                    self._check_abort_mission(fleet_order)):
                return
        aistate = get_aistate()
        for fleet_order in self.orders:
            if just_issued_move_order and self.fleet.get_object().systemID != last_move_target_id:
                # having just issued a move order, we will normally stop issuing orders this turn, except that if there
                # are consecutive move orders we will consider moving through the first destination rather than stopping
                # Without the below noinspection directive, PyCharm is concerned about the 2nd part of the test
                # noinspection PyTypeChecker
                if (not isinstance(fleet_order, OrderMove) or
                        self.need_to_pause_movement(last_move_target_id, fleet_order)):
                    break
            debug("Checking order: %s" % fleet_order)
            self.check_mergers(context=str(fleet_order))
            if fleet_order.can_issue_order(verbose=False):
                # only move if all other orders completed
                if isinstance(fleet_order, OrderMove) and order_completed:
                    debug("Issuing fleet order %s" % fleet_order)
                    fleet_order.issue_order()
                    just_issued_move_order = True
                    last_move_target_id = fleet_order.target.id
                elif not isinstance(fleet_order, OrderMove):
                    debug("Issuing fleet order %s" % fleet_order)
                    fleet_order.issue_order()
                else:
                    debug("NOT issuing (even though can_issue) fleet order %s" % fleet_order)
                status_words = tuple(["not", ""][_s] for _s in [fleet_order.order_issued, fleet_order.executed])
                debug("Order %s issued and %s fully executed." % status_words)
                if not fleet_order.executed:
                    order_completed = False
            else:  # check that we're not held up by a Big Monster
                if fleet_order.order_issued:
                    # A previously issued order that wasn't instantly executed must have had cirumstances change so that
                    # the order can't currently be reissued (or perhaps simply a savegame has been reloaded on the same
                    # turn the order was issued).
                    if not fleet_order.executed:
                        order_completed = False
                    # Go on to the next order.
                    continue
                debug("CAN'T issue fleet order %s because:" % fleet_order)
                fleet_order.can_issue_order(verbose=True)
                if isinstance(fleet_order, OrderMove):
                    this_system_id = fleet_order.target.id
                    this_status = aistate.systemStatus.setdefault(this_system_id, {})
                    threat_threshold = fo.currentTurn() * MilitaryAI.cur_best_mil_ship_rating() / 4.0
                    if this_status.get('monsterThreat', 0) > threat_threshold:
                        # if this move order is not this mil fleet's final destination, and blocked by Big Monster,
                        # release and hope for more effective reassignment
                        if (self.type not in (MissionType.MILITARY, MissionType.SECURE) or
                                fleet_order != self.orders[-1]):
                            debug("Aborting mission due to being blocked by Big Monster at system %d, threat %d" % (
                                this_system_id, aistate.systemStatus[this_system_id]['monsterThreat']))
                            debug("Full set of orders were:")
                            for this_order in self.orders:
                                debug(" - %s" % this_order)
                            self.clear_fleet_orders()
                            self.clear_target()
                            return
                break  # do not order the next order until this one is finished.
        else:  # went through entire order list
            if order_completed:
                debug("Final order is completed")
                orders = self.orders
                last_order = orders[-1] if orders else None
                universe = fo.getUniverse()

                if last_order and isinstance(last_order, OrderColonize):
                    planet = universe.getPlanet(last_order.target.id)
                    sys_partial_vis_turn = get_partial_visibility_turn(planet.systemID)
                    planet_partial_vis_turn = get_partial_visibility_turn(planet.id)
                    if (planet_partial_vis_turn == sys_partial_vis_turn and
                            not planet.initialMeterValue(fo.meterType.population)):
                        warn("Fleet %d has tentatively completed its "
                             "colonize mission but will wait to confirm population." % self.fleet.id)
                        debug("    Order details are %s" % last_order)
                        debug("    Order is valid: %s; issued: %s; executed: %s" % (
                            last_order.is_valid(), last_order.order_issued, last_order.executed))
                        if not last_order.is_valid():
                            source_target = last_order.fleet
                            target_target = last_order.target
                            debug("        source target validity: %s; target target validity: %s " % (
                                bool(source_target), bool(target_target)))
                        return  # colonize order must not have completed yet
                clear_all = True
                last_sys_target = INVALID_ID
                if last_order and isinstance(last_order, OrderMilitary):
                    last_sys_target = last_order.target.id
                    # not doing this until decide a way to release from a SECURE mission
                    # if (MissionType.SECURE == self.type) or
                    secure_targets = set(AIstate.colonyTargetedSystemIDs +
                                         AIstate.outpostTargetedSystemIDs +
                                         AIstate.invasionTargetedSystemIDs)
                    if last_sys_target in secure_targets:  # consider a secure mission
                        if last_sys_target in AIstate.colonyTargetedSystemIDs:
                            secure_type = "Colony"
                        elif last_sys_target in AIstate.outpostTargetedSystemIDs:
                            secure_type = "Outpost"
                        elif last_sys_target in AIstate.invasionTargetedSystemIDs:
                            secure_type = "Invasion"
                        else:
                            secure_type = "Unidentified"
                        debug("Fleet %d has completed initial stage of its mission "
                              "to secure system %d (targeted for %s), "
                              "may release a portion of ships" % (self.fleet.id, last_sys_target, secure_type))
                        clear_all = False

                # for PROTECT_REGION missions, only release fleet if no more threat
                if self.type == MissionType.PROTECT_REGION:
                    # use military logic code below to determine if can release
                    # any or even all of the ships.
                    clear_all = False
                    last_sys_target = self.target.id
                    debug("Check if PROTECT_REGION mission with target %d is finished.", last_sys_target)

                fleet_id = self.fleet.id
                if clear_all:
                    if orders:
                        debug("Fleet %d has completed its mission; clearing all orders and targets." % self.fleet.id)
                        debug("Full set of orders were:")
                        for this_order in orders:
                            debug("\t\t %s" % this_order)
                        self.clear_fleet_orders()
                        self.clear_target()
                        if aistate.get_fleet_role(fleet_id) in (MissionType.MILITARY, MissionType.SECURE):
                            allocations = MilitaryAI.get_military_fleets(mil_fleets_ids=[fleet_id],
                                                                         try_reset=False,
                                                                         thisround="Fleet %d Reassignment" % fleet_id)
                            if allocations:
                                MilitaryAI.assign_military_fleets_to_systems(use_fleet_id_list=[fleet_id],
                                                                             allocations=allocations)
                    else:  # no orders
                        debug("No Current Orders")
                else:
                    potential_threat = CombatRatingsAI.combine_ratings(
                        MilitaryAI.get_system_local_threat(last_sys_target),
                        MilitaryAI.get_system_neighbor_threat(last_sys_target)
                    )
                    threat_present = potential_threat > 0
                    debug("Fleet threat present? %s", threat_present)
                    target_system = universe.getSystem(last_sys_target)
                    if not threat_present and target_system:
                        for pid in target_system.planetIDs:
                            planet = universe.getPlanet(pid)
                            if (planet and
                                    planet.owner != fo.empireID() and
                                    planet.currentMeterValue(fo.meterType.maxDefense) > 0):
                                debug("Found local planetary threat: %s", planet)
                                threat_present = True
                                break
                    if not threat_present:
                        debug("No current threat in target system; releasing a portion of ships.")
                        # at least first stage of current task is done;
                        # release extra ships for potential other deployments
                        new_fleets = FleetUtilsAI.split_fleet(self.fleet.id)
                        if self.type == MissionType.PROTECT_REGION:
                            self.clear_fleet_orders()
                            self.clear_target()
                            new_fleets.append(self.fleet.id)
                    else:
                        debug("Threat remains in target system; Considering to release some ships.")
                        new_fleets = []
                        fleet_portion_to_remain = self._portion_of_fleet_needed_here()
                        if fleet_portion_to_remain > 1:
                            debug("Can not release fleet yet due to large threat.")
                        elif fleet_portion_to_remain > 0:
                            debug("Not all ships are needed here - considering releasing a few")
                            fleet_remaining_rating = CombatRatingsAI.get_fleet_rating(fleet_id)
                            fleet_min_rating = fleet_portion_to_remain * fleet_remaining_rating
                            debug("Starting rating: %.1f, Target rating: %.1f",
                                  fleet_remaining_rating, fleet_min_rating)
                            allowance = CombatRatingsAI.rating_needed(fleet_remaining_rating, fleet_min_rating)
                            debug("May release ships with total rating of %.1f", allowance)
                            ship_ids = list(self.fleet.get_object().shipIDs)
                            for ship_id in ship_ids:
                                ship_rating = CombatRatingsAI.get_ship_rating(ship_id)
                                debug("Considering to release ship %d with rating %.1f", ship_id, ship_rating)
                                if ship_rating > allowance:
                                    debug("Remaining rating insufficient. Not released.")
                                    continue
                                debug("Splitting from fleet.")
                                new_fleet_id = FleetUtilsAI.split_ship_from_fleet(fleet_id, ship_id)
                                if assertion_fails(new_fleet_id and new_fleet_id != INVALID_ID):
                                    break
                                new_fleets.append(new_fleet_id)
                                fleet_remaining_rating = CombatRatingsAI.rating_difference(
                                    fleet_remaining_rating, ship_rating)
                                allowance = CombatRatingsAI.rating_difference(
                                    fleet_remaining_rating, fleet_min_rating)
                                debug("Remaining fleet rating: %.1f - Allowance: %.1f",
                                      fleet_remaining_rating, allowance)
                            if new_fleets:
                                aistate.get_fleet_role(fleet_id, force_new=True)
                                aistate.update_fleet_rating(fleet_id)
                                aistate.ensure_have_fleet_missions(new_fleets)
                        else:
                            debug("Planetary defenses are deemed sufficient. Release fleet.")
                            new_fleets = FleetUtilsAI.split_fleet(self.fleet.id)

                    new_military_fleets = []
                    for fleet_id in new_fleets:
                        if aistate.get_fleet_role(fleet_id) in COMBAT_MISSION_TYPES:
                            new_military_fleets.append(fleet_id)
                    allocations = []
                    if new_military_fleets:
                        allocations = MilitaryAI.get_military_fleets(
                            mil_fleets_ids=new_military_fleets,
                            try_reset=False,
                            thisround="Fleet Reassignment %s" % new_military_fleets
                        )
                    if allocations:
                        MilitaryAI.assign_military_fleets_to_systems(use_fleet_id_list=new_military_fleets,
                                                                     allocations=allocations)
예제 #42
0
    def issue_fleet_orders(self):
        """issues AIFleetOrders which can be issued in system and moves to next one if is possible"""
        # TODO: priority
        order_completed = True

        debug("\nChecking orders for fleet %s (on turn %d), with mission type %s and target %s",
              self.fleet.get_object(), fo.currentTurn(), self.type or 'No mission', self.target or 'No Target')
        if MissionType.INVASION == self.type:
            self._check_retarget_invasion()
        just_issued_move_order = False
        last_move_target_id = INVALID_ID
        # Note: the following abort check somewhat assumes only one major mission type
        for fleet_order in self.orders:
            if (isinstance(fleet_order, (OrderColonize, OrderOutpost, OrderInvade)) and
                    self._check_abort_mission(fleet_order)):
                return
        aistate = get_aistate()
        for fleet_order in self.orders:
            if just_issued_move_order and self.fleet.get_object().systemID != last_move_target_id:
                # having just issued a move order, we will normally stop issuing orders this turn, except that if there
                # are consecutive move orders we will consider moving through the first destination rather than stopping
                # Without the below noinspection directive, PyCharm is concerned about the 2nd part of the test
                # noinspection PyTypeChecker
                if (not isinstance(fleet_order, OrderMove) or
                        self.need_to_pause_movement(last_move_target_id, fleet_order)):
                    break
            debug("Checking order: %s" % fleet_order)
            self.check_mergers(context=str(fleet_order))
            if fleet_order.can_issue_order(verbose=False):
                # only move if all other orders completed
                if isinstance(fleet_order, OrderMove) and order_completed:
                    debug("Issuing fleet order %s" % fleet_order)
                    fleet_order.issue_order()
                    just_issued_move_order = True
                    last_move_target_id = fleet_order.target.id
                elif not isinstance(fleet_order, OrderMove):
                    debug("Issuing fleet order %s" % fleet_order)
                    fleet_order.issue_order()
                else:
                    debug("NOT issuing (even though can_issue) fleet order %s" % fleet_order)
                status_words = tuple(["not", ""][_s] for _s in [fleet_order.order_issued, fleet_order.executed])
                debug("Order %s issued and %s fully executed." % status_words)
                if not fleet_order.executed:
                    order_completed = False
            else:  # check that we're not held up by a Big Monster
                if fleet_order.order_issued:
                    # A previously issued order that wasn't instantly executed must have had cirumstances change so that
                    # the order can't currently be reissued (or perhaps simply a savegame has been reloaded on the same
                    # turn the order was issued).
                    if not fleet_order.executed:
                        order_completed = False
                    # Go on to the next order.
                    continue
                debug("CAN'T issue fleet order %s because:" % fleet_order)
                fleet_order.can_issue_order(verbose=True)
                if isinstance(fleet_order, OrderMove):
                    this_system_id = fleet_order.target.id
                    this_status = aistate.systemStatus.setdefault(this_system_id, {})
                    threat_threshold = fo.currentTurn() * MilitaryAI.cur_best_mil_ship_rating() / 4.0
                    if this_status.get('monsterThreat', 0) > threat_threshold:
                        # if this move order is not this mil fleet's final destination, and blocked by Big Monster,
                        # release and hope for more effective reassignment
                        if (self.type not in (MissionType.MILITARY, MissionType.SECURE) or
                                fleet_order != self.orders[-1]):
                            debug("Aborting mission due to being blocked by Big Monster at system %d, threat %d" % (
                                this_system_id, aistate.systemStatus[this_system_id]['monsterThreat']))
                            debug("Full set of orders were:")
                            for this_order in self.orders:
                                debug(" - %s" % this_order)
                            self.clear_fleet_orders()
                            self.clear_target()
                            return
                break  # do not order the next order until this one is finished.
        else:  # went through entire order list
            if order_completed:
                debug("Final order is completed")
                orders = self.orders
                last_order = orders[-1] if orders else None
                universe = fo.getUniverse()

                if last_order and isinstance(last_order, OrderColonize):
                    planet = universe.getPlanet(last_order.target.id)
                    sys_partial_vis_turn = get_partial_visibility_turn(planet.systemID)
                    planet_partial_vis_turn = get_partial_visibility_turn(planet.id)
                    if (planet_partial_vis_turn == sys_partial_vis_turn and
                            not planet.initialMeterValue(fo.meterType.population)):
                        warning("Fleet %s has tentatively completed its "
                                "colonize mission but will wait to confirm population.", self.fleet)
                        debug("    Order details are %s" % last_order)
                        debug("    Order is valid: %s; issued: %s; executed: %s" % (
                            last_order.is_valid(), last_order.order_issued, last_order.executed))
                        if not last_order.is_valid():
                            source_target = last_order.fleet
                            target_target = last_order.target
                            debug("        source target validity: %s; target target validity: %s " % (
                                bool(source_target), bool(target_target)))
                        return  # colonize order must not have completed yet
                clear_all = True
                last_sys_target = INVALID_ID
                if last_order and isinstance(last_order, OrderMilitary):
                    last_sys_target = last_order.target.id
                    # not doing this until decide a way to release from a SECURE mission
                    # if (MissionType.SECURE == self.type) or
                    secure_targets = set(AIstate.colonyTargetedSystemIDs +
                                         AIstate.outpostTargetedSystemIDs +
                                         AIstate.invasionTargetedSystemIDs)
                    if last_sys_target in secure_targets:  # consider a secure mission
                        if last_sys_target in AIstate.colonyTargetedSystemIDs:
                            secure_type = "Colony"
                        elif last_sys_target in AIstate.outpostTargetedSystemIDs:
                            secure_type = "Outpost"
                        elif last_sys_target in AIstate.invasionTargetedSystemIDs:
                            secure_type = "Invasion"
                        else:
                            secure_type = "Unidentified"
                        debug("Fleet %d has completed initial stage of its mission "
                              "to secure system %d (targeted for %s), "
                              "may release a portion of ships" % (self.fleet.id, last_sys_target, secure_type))
                        clear_all = False

                # for PROTECT_REGION missions, only release fleet if no more threat
                if self.type == MissionType.PROTECT_REGION:
                    # use military logic code below to determine if can release
                    # any or even all of the ships.
                    clear_all = False
                    last_sys_target = self.target.id
                    debug("Check if PROTECT_REGION mission with target %d is finished.", last_sys_target)

                fleet_id = self.fleet.id
                if clear_all:
                    if orders:
                        debug("Fleet %d has completed its mission; clearing all orders and targets." % self.fleet.id)
                        debug("Full set of orders were:")
                        for this_order in orders:
                            debug("\t\t %s" % this_order)
                        self.clear_fleet_orders()
                        self.clear_target()
                        if aistate.get_fleet_role(fleet_id) in (MissionType.MILITARY, MissionType.SECURE):
                            allocations = MilitaryAI.get_military_fleets(mil_fleets_ids=[fleet_id],
                                                                         try_reset=False,
                                                                         thisround="Fleet %d Reassignment" % fleet_id)
                            if allocations:
                                MilitaryAI.assign_military_fleets_to_systems(use_fleet_id_list=[fleet_id],
                                                                             allocations=allocations)
                    else:  # no orders
                        debug("No Current Orders")
                else:
                    potential_threat = combine_ratings(
                        MilitaryAI.get_system_local_threat(last_sys_target),
                        MilitaryAI.get_system_neighbor_threat(last_sys_target)
                    )
                    threat_present = potential_threat > 0
                    debug("Fleet threat present? %s", threat_present)
                    target_system = universe.getSystem(last_sys_target)
                    if not threat_present and target_system:
                        for pid in target_system.planetIDs:
                            planet = universe.getPlanet(pid)
                            if (planet and
                                    planet.owner != fo.empireID() and
                                    planet.currentMeterValue(fo.meterType.maxDefense) > 0):
                                debug("Found local planetary threat: %s", planet)
                                threat_present = True
                                break
                    if not threat_present:
                        debug("No current threat in target system; releasing a portion of ships.")
                        # at least first stage of current task is done;
                        # release extra ships for potential other deployments
                        new_fleets = FleetUtilsAI.split_fleet(self.fleet.id)
                        if self.type == MissionType.PROTECT_REGION:
                            self.clear_fleet_orders()
                            self.clear_target()
                            new_fleets.append(self.fleet.id)
                    else:
                        debug("Threat remains in target system; Considering to release some ships.")
                        new_fleets = []
                        fleet_portion_to_remain = self._portion_of_fleet_needed_here()
                        if fleet_portion_to_remain >= 1:
                            debug("Can not release fleet yet due to large threat.")
                        elif fleet_portion_to_remain > 0:
                            debug("Not all ships are needed here - considering releasing a few")
                            # TODO: Rate against specific enemy threat cause
                            fleet_remaining_rating = CombatRatingsAI.get_fleet_rating(fleet_id)
                            fleet_min_rating = fleet_portion_to_remain * fleet_remaining_rating
                            debug("Starting rating: %.1f, Target rating: %.1f",
                                  fleet_remaining_rating, fleet_min_rating)
                            allowance = CombatRatingsAI.rating_needed(fleet_remaining_rating, fleet_min_rating)
                            debug("May release ships with total rating of %.1f", allowance)
                            ship_ids = list(self.fleet.get_object().shipIDs)
                            for ship_id in ship_ids:
                                ship_rating = CombatRatingsAI.get_ship_rating(ship_id)
                                debug("Considering to release ship %d with rating %.1f", ship_id, ship_rating)
                                if ship_rating > allowance:
                                    debug("Remaining rating insufficient. Not released.")
                                    continue
                                debug("Splitting from fleet.")
                                new_fleet_id = FleetUtilsAI.split_ship_from_fleet(fleet_id, ship_id)
                                if assertion_fails(new_fleet_id and new_fleet_id != INVALID_ID):
                                    break
                                new_fleets.append(new_fleet_id)
                                fleet_remaining_rating = CombatRatingsAI.rating_difference(
                                    fleet_remaining_rating, ship_rating)
                                allowance = CombatRatingsAI.rating_difference(
                                    fleet_remaining_rating, fleet_min_rating)
                                debug("Remaining fleet rating: %.1f - Allowance: %.1f",
                                      fleet_remaining_rating, allowance)
                            if new_fleets:
                                aistate.get_fleet_role(fleet_id, force_new=True)
                                aistate.update_fleet_rating(fleet_id)
                                aistate.ensure_have_fleet_missions(new_fleets)
                        else:
                            debug("Planetary defenses are deemed sufficient. Release fleet.")
                            new_fleets = FleetUtilsAI.split_fleet(self.fleet.id)

                    new_military_fleets = []
                    for fleet_id in new_fleets:
                        if aistate.get_fleet_role(fleet_id) in COMBAT_MISSION_TYPES:
                            new_military_fleets.append(fleet_id)
                    allocations = []
                    if new_military_fleets:
                        allocations = MilitaryAI.get_military_fleets(
                            mil_fleets_ids=new_military_fleets,
                            try_reset=False,
                            thisround="Fleet Reassignment %s" % new_military_fleets
                        )
                    if allocations:
                        MilitaryAI.assign_military_fleets_to_systems(use_fleet_id_list=new_military_fleets,
                                                                     allocations=allocations)
예제 #43
0
def evaluate_invasion_planet(planet_id, secure_fleet_missions, verbose=True):
    """Return the invasion value (score, troops) of a planet."""
    detail = []
    building_values = {"BLD_IMPERIAL_PALACE": 1000,
                       "BLD_CULTURE_ARCHIVES": 1000,
                       "BLD_AUTO_HISTORY_ANALYSER": 100,
                       "BLD_SHIPYARD_BASE": 100,
                       "BLD_SHIPYARD_ORG_ORB_INC": 200,
                       "BLD_SHIPYARD_ORG_XENO_FAC": 200,
                       "BLD_SHIPYARD_ORG_CELL_GRO_CHAMB": 200,
                       "BLD_SHIPYARD_CON_NANOROBO": 300,
                       "BLD_SHIPYARD_CON_GEOINT": 400,
                       "BLD_SHIPYARD_CON_ADV_ENGINE": 1000,
                       "BLD_SHIPYARD_AST": 300,
                       "BLD_SHIPYARD_AST_REF": 1000,
                       "BLD_SHIPYARD_ENRG_SOLAR": 1500,
                       "BLD_INDUSTRY_CENTER": 500,
                       "BLD_GAS_GIANT_GEN": 200,
                       "BLD_SOL_ORB_GEN": 800,
                       "BLD_BLACK_HOLE_POW_GEN": 2000,
                       "BLD_ENCLAVE_VOID": 500,
                       "BLD_NEUTRONIUM_EXTRACTOR": 2000,
                       "BLD_NEUTRONIUM_SYNTH": 2000,
                       "BLD_NEUTRONIUM_FORGE": 1000,
                       "BLD_CONC_CAMP": 100,
                       "BLD_BIOTERROR_PROJECTOR": 1000,
                       "BLD_SHIPYARD_ENRG_COMP": 3000,
                       }
    # TODO: add more factors, as used for colonization
    universe = fo.getUniverse()
    empire_id = fo.empireID()
    max_jumps = 8
    planet = universe.getPlanet(planet_id)
    if planet is None:  # TODO: exclude planets with stealth higher than empireDetection
        print "invasion AI couldn't access any info for planet id %d" % planet_id
        return [0, 0]

    sys_partial_vis_turn = universe.getVisibilityTurnsMap(planet.systemID, empire_id).get(fo.visibility.partial, -9999)
    planet_partial_vis_turn = universe.getVisibilityTurnsMap(planet_id, empire_id).get(fo.visibility.partial, -9999)

    if planet_partial_vis_turn < sys_partial_vis_turn:
        print "invasion AI couldn't get current info on planet id %d (was stealthed at last sighting)" % planet_id
        # TODO: track detection strength, order new scouting when it goes up
        return [0, 0]  # last time we had partial vis of the system, the planet was stealthed to us

    species_name = planet.speciesName
    species = fo.getSpecies(species_name)
    if not species or AIDependencies.TAG_DESTROYED_ON_CONQUEST in species.tags:
        # this call iterates over this Empire's available species with which it could colonize after an invasion
        planet_eval = ColonisationAI.assign_colonisation_values([planet_id], MissionType.INVASION, None, detail)
        pop_val = max(0.75 * planet_eval.get(planet_id, [0])[0],
                      ColonisationAI.evaluate_planet(planet_id, MissionType.OUTPOST, None, detail))
    else:
        pop_val = ColonisationAI.evaluate_planet(planet_id, MissionType.INVASION, species_name, detail)

    bld_tally = 0
    for bldType in [universe.getBuilding(bldg).buildingTypeName for bldg in planet.buildingIDs]:
        bval = building_values.get(bldType, 50)
        bld_tally += bval
        detail.append("%s: %d" % (bldType, bval))

    tech_tally = 0
    for unlocked_tech in AIDependencies.SPECIES_TECH_UNLOCKS.get(species_name, []):
        if not tech_is_complete(unlocked_tech):
            rp_cost = fo.getTech(unlocked_tech).researchCost(empire_id)
            tech_tally += rp_cost * 4
            detail.append("%s: %d" % (unlocked_tech, rp_cost * 4))

    p_sys_id = planet.systemID
    capitol_id = PlanetUtilsAI.get_capital()
    least_jumps_path = []
    clear_path = True
    if capitol_id:
        homeworld = universe.getPlanet(capitol_id)
        if homeworld:
            home_system_id = homeworld.systemID
            eval_system_id = planet.systemID
            if (home_system_id != INVALID_ID) and (eval_system_id != INVALID_ID):
                least_jumps_path = list(universe.leastJumpsPath(home_system_id, eval_system_id, empire_id))
                max_jumps = len(least_jumps_path)
    system_status = foAI.foAIstate.systemStatus.get(p_sys_id, {})
    system_fleet_treat = system_status.get('fleetThreat', 1000)
    system_monster_threat = system_status.get('monsterThreat', 0)
    sys_total_threat = system_fleet_treat + system_monster_threat + system_status.get('planetThreat', 0)
    max_path_threat = system_fleet_treat
    mil_ship_rating = MilitaryAI.cur_best_mil_ship_rating()
    for path_sys_id in least_jumps_path:
        path_leg_status = foAI.foAIstate.systemStatus.get(path_sys_id, {})
        path_leg_threat = path_leg_status.get('fleetThreat', 1000) + path_leg_status.get('monsterThreat', 0)
        if path_leg_threat > 0.5 * mil_ship_rating:
            clear_path = False
            if path_leg_threat > max_path_threat:
                max_path_threat = path_leg_threat

    pop = planet.currentMeterValue(fo.meterType.population)
    target_pop = planet.currentMeterValue(fo.meterType.targetPopulation)
    troops = planet.currentMeterValue(fo.meterType.troops)
    max_troops = planet.currentMeterValue(fo.meterType.maxTroops)
    # TODO: refactor troop determination into function for use in mid-mission updates and also consider defender techs
    max_troops += AIDependencies.TROOPS_PER_POP * (target_pop - pop)

    this_system = universe.getSystem(p_sys_id)
    secure_targets = [p_sys_id] + list(this_system.planetIDs)
    system_secured = False
    for mission in secure_fleet_missions:
        if system_secured:
            break
        secure_fleet_id = mission.fleet.id
        s_fleet = universe.getFleet(secure_fleet_id)
        if not s_fleet or s_fleet.systemID != p_sys_id:
            continue
        if mission.type == MissionType.SECURE:
            target_obj = mission.target.get_object()
            if target_obj is not None and target_obj.id in secure_targets:
                system_secured = True
                break
    system_secured = system_secured and system_status.get('myFleetRating', 0)

    if verbose:
        print ("Invasion eval of %s\n"
               " - maxShields: %.1f\n"
               " - sysFleetThreat: %.1f\n"
               " - sysMonsterThreat: %.1f") % (
            planet, planet.currentMeterValue(fo.meterType.maxShield), system_fleet_treat,
            system_monster_threat)
    supply_val = 0
    enemy_val = 0
    if planet.owner != -1:  # value in taking this away from an enemy
        enemy_val = 20 * (planet.currentMeterValue(fo.meterType.targetIndustry) + 2*planet.currentMeterValue(fo.meterType.targetResearch))
    if p_sys_id in ColonisationAI.annexable_system_ids:  # TODO: extend to rings
        supply_val = 100
    elif p_sys_id in ColonisationAI.annexable_ring1:
        supply_val = 200
    elif p_sys_id in ColonisationAI.annexable_ring2:
        supply_val = 300
    elif p_sys_id in ColonisationAI.annexable_ring3:
        supply_val = 400
    if max_path_threat > 0.5 * mil_ship_rating:
        if max_path_threat < 3 * mil_ship_rating:
            supply_val *= 0.5
        else:
            supply_val *= 0.2

    threat_factor = min(1, 0.2*MilitaryAI.get_tot_mil_rating()/(sys_total_threat+0.001))**2  # devalue invasions that would require too much military force

    design_id, _, locs = ProductionAI.get_best_ship_info(PriorityType.PRODUCTION_INVASION)
    if not locs or not universe.getPlanet(locs[0]):
        # We are in trouble anyway, so just calculate whatever approximation...
        build_time = 4
        planned_troops = troops if system_secured else min(troops + max_jumps + build_time, max_troops)
        planned_troops += .01  # we must attack with more troops than there are defenders
        troop_cost = math.ceil((planned_troops+_TROOPS_SAFETY_MARGIN) / 6.0) * 20 * FleetUtilsAI.get_fleet_upkeep()
    else:
        loc = locs[0]
        species_here = universe.getPlanet(loc).speciesName
        design = fo.getShipDesign(design_id)
        cost_per_ship = design.productionCost(empire_id, loc)
        build_time = design.productionTime(empire_id, loc)
        troops_per_ship = CombatRatingsAI.weight_attack_troops(design.troopCapacity,
                                                               CombatRatingsAI.get_species_troops_grade(species_here))
        planned_troops = troops if system_secured else min(troops + max_jumps + build_time, max_troops)
        planned_troops += .01  # we must attack with more troops than there are defenders
        ships_needed = math.ceil((planned_troops+_TROOPS_SAFETY_MARGIN) / float(troops_per_ship))
        troop_cost = ships_needed * cost_per_ship  # fleet upkeep is already included in query from server

    # apply some bias to expensive operations
    normalized_cost = float(troop_cost) / max(fo.getEmpire().productionPoints, 1)
    normalized_cost = max(1, normalized_cost)
    cost_score = (normalized_cost**2 / 50.0) * troop_cost

    base_score = pop_val + supply_val + bld_tally + tech_tally + enemy_val - cost_score
    planet_score = retaliation_risk_factor(planet.owner) * threat_factor * max(0, base_score)
    if clear_path:
        planet_score *= 1.5
    if verbose:
        print (' - planet score: %.2f\n'
               ' - troop score: %.2f\n'
               ' - projected troop cost: %.1f\n'
               ' - threat factor: %s\n'
               ' - planet detail: %s\n'
               ' - popval: %.1f\n'
               ' - supplyval: %.1f\n'
               ' - bldval: %s\n'
               ' - enemyval: %s') % (planet_score, planned_troops, troop_cost,
                                     threat_factor, detail, pop_val, supply_val, bld_tally, enemy_val)
    return [planet_score, planned_troops]
예제 #44
0
def evaluate_invasion_planet(planet_id, secure_fleet_missions, verbose=True):
    """Return the invasion value (score, troops) of a planet."""
    universe = fo.getUniverse()
    empire_id = fo.empireID()
    detail = []

    planet = universe.getPlanet(planet_id)
    if planet is None:
        debug("Invasion AI couldn't access any info for planet id %d" % planet_id)
        return [0, 0]

    system_id = planet.systemID

    # by using the following instead of simply relying on stealth meter reading, can (sometimes) plan ahead even if
    # planet is temporarily shrouded by an ion storm
    predicted_detectable = EspionageAI.colony_detectable_by_empire(planet_id, empire=fo.empireID(),
                                                                   default_result=False)
    if not predicted_detectable:
        if get_partial_visibility_turn(planet_id) < fo.currentTurn():
            debug("InvasionAI predicts planet id %d to be stealthed" % planet_id)
            return [0, 0]
        else:
            debug("InvasionAI predicts planet id %d to be stealthed" % planet_id +
                  ", but somehow have current visibity anyway, will still consider as target")

    # Check if the target planet was extra-stealthed somehow its system was last viewed
    # this test below may augment the tests above, but can be thrown off by temporary combat-related sighting
    system_last_seen = get_partial_visibility_turn(planet_id)
    planet_last_seen = get_partial_visibility_turn(system_id)
    if planet_last_seen < system_last_seen:
        # TODO: track detection strength, order new scouting when it goes up
        debug("Invasion AI considering planet id %d (stealthed at last view), still proceeding." % planet_id)

    # get a baseline evaluation of the planet as determined by ColonisationAI
    species_name = planet.speciesName
    species = fo.getSpecies(species_name)
    if not species or AIDependencies.TAG_DESTROYED_ON_CONQUEST in species.tags:
        # this call iterates over this Empire's available species with which it could colonize after an invasion
        planet_eval = ColonisationAI.assign_colonisation_values([planet_id], MissionType.INVASION, None, detail)
        colony_base_value = max(0.75 * planet_eval.get(planet_id, [0])[0],
                                ColonisationAI.evaluate_planet(planet_id, MissionType.OUTPOST, None, detail))
    else:
        colony_base_value = ColonisationAI.evaluate_planet(planet_id, MissionType.INVASION, species_name, detail)

    # Add extra score for all buildings on the planet
    building_values = {"BLD_IMPERIAL_PALACE": 1000,
                       "BLD_CULTURE_ARCHIVES": 1000,
                       "BLD_AUTO_HISTORY_ANALYSER": 100,
                       "BLD_SHIPYARD_BASE": 100,
                       "BLD_SHIPYARD_ORG_ORB_INC": 200,
                       "BLD_SHIPYARD_ORG_XENO_FAC": 200,
                       "BLD_SHIPYARD_ORG_CELL_GRO_CHAMB": 200,
                       "BLD_SHIPYARD_CON_NANOROBO": 300,
                       "BLD_SHIPYARD_CON_GEOINT": 400,
                       "BLD_SHIPYARD_CON_ADV_ENGINE": 1000,
                       "BLD_SHIPYARD_AST": 300,
                       "BLD_SHIPYARD_AST_REF": 1000,
                       "BLD_SHIPYARD_ENRG_SOLAR": 1500,
                       "BLD_INDUSTRY_CENTER": 500,
                       "BLD_GAS_GIANT_GEN": 200,
                       "BLD_SOL_ORB_GEN": 800,
                       "BLD_BLACK_HOLE_POW_GEN": 2000,
                       "BLD_ENCLAVE_VOID": 500,
                       "BLD_NEUTRONIUM_EXTRACTOR": 2000,
                       "BLD_NEUTRONIUM_SYNTH": 2000,
                       "BLD_NEUTRONIUM_FORGE": 1000,
                       "BLD_CONC_CAMP": 100,
                       "BLD_BIOTERROR_PROJECTOR": 1000,
                       "BLD_SHIPYARD_ENRG_COMP": 3000,
                       }
    bld_tally = 0
    for bldType in [universe.getBuilding(bldg).buildingTypeName for bldg in planet.buildingIDs]:
        bval = building_values.get(bldType, 50)
        bld_tally += bval
        detail.append("%s: %d" % (bldType, bval))

    # Add extra score for unlocked techs when we conquer the species
    tech_tally = 0
    value_per_pp = 4
    for unlocked_tech in AIDependencies.SPECIES_TECH_UNLOCKS.get(species_name, []):
        if not tech_is_complete(unlocked_tech):
            rp_cost = fo.getTech(unlocked_tech).researchCost(empire_id)
            tech_value = value_per_pp * rp_cost
            tech_tally += tech_value
            detail.append("%s: %d" % (unlocked_tech, tech_value))

    max_jumps = 8
    capitol_id = PlanetUtilsAI.get_capital()
    least_jumps_path = []
    clear_path = True
    if capitol_id:
        homeworld = universe.getPlanet(capitol_id)
        if homeworld and homeworld.systemID != INVALID_ID and system_id != INVALID_ID:
            least_jumps_path = list(universe.leastJumpsPath(homeworld.systemID, system_id, empire_id))
            max_jumps = len(least_jumps_path)
    aistate = get_aistate()
    system_status = aistate.systemStatus.get(system_id, {})
    system_fleet_treat = system_status.get('fleetThreat', 1000)
    system_monster_threat = system_status.get('monsterThreat', 0)
    sys_total_threat = system_fleet_treat + system_monster_threat + system_status.get('planetThreat', 0)
    max_path_threat = system_fleet_treat
    mil_ship_rating = MilitaryAI.cur_best_mil_ship_rating()
    for path_sys_id in least_jumps_path:
        path_leg_status = aistate.systemStatus.get(path_sys_id, {})
        path_leg_threat = path_leg_status.get('fleetThreat', 1000) + path_leg_status.get('monsterThreat', 0)
        if path_leg_threat > 0.5 * mil_ship_rating:
            clear_path = False
            if path_leg_threat > max_path_threat:
                max_path_threat = path_leg_threat

    pop = planet.currentMeterValue(fo.meterType.population)
    target_pop = planet.currentMeterValue(fo.meterType.targetPopulation)
    troops = planet.currentMeterValue(fo.meterType.troops)
    troop_regen = planet.currentMeterValue(fo.meterType.troops) - planet.initialMeterValue(fo.meterType.troops)
    max_troops = planet.currentMeterValue(fo.meterType.maxTroops)
    # TODO: refactor troop determination into function for use in mid-mission updates and also consider defender techs
    max_troops += AIDependencies.TROOPS_PER_POP * (target_pop - pop)

    this_system = universe.getSystem(system_id)
    secure_targets = [system_id] + list(this_system.planetIDs)
    system_secured = False
    for mission in secure_fleet_missions:
        if system_secured:
            break
        secure_fleet_id = mission.fleet.id
        s_fleet = universe.getFleet(secure_fleet_id)
        if not s_fleet or s_fleet.systemID != system_id:
            continue
        if mission.type in [MissionType.SECURE, MissionType.MILITARY]:
            target_obj = mission.target.get_object()
            if target_obj is not None and target_obj.id in secure_targets:
                system_secured = True
                break
    system_secured = system_secured and system_status.get('myFleetRating', 0)

    if verbose:
        debug("Invasion eval of %s\n"
              " - maxShields: %.1f\n"
              " - sysFleetThreat: %.1f\n"
              " - sysMonsterThreat: %.1f",
              planet, planet.currentMeterValue(fo.meterType.maxShield), system_fleet_treat, system_monster_threat)
    enemy_val = 0
    if planet.owner != -1:  # value in taking this away from an enemy
        enemy_val = 20 * (planet.currentMeterValue(fo.meterType.targetIndustry) +
                          2*planet.currentMeterValue(fo.meterType.targetResearch))

    # devalue invasions that would require too much military force
    preferred_max_portion = MilitaryAI.get_preferred_max_military_portion_for_single_battle()
    total_max_mil_rating = MilitaryAI.get_concentrated_tot_mil_rating()
    threat_exponent = 2  # TODO: make this a character trait; higher aggression with a lower exponent
    threat_factor = min(1, preferred_max_portion * total_max_mil_rating/(sys_total_threat+0.001))**threat_exponent

    design_id, _, locs = ProductionAI.get_best_ship_info(PriorityType.PRODUCTION_INVASION)
    if not locs or not universe.getPlanet(locs[0]):
        # We are in trouble anyway, so just calculate whatever approximation...
        build_time = 4
        planned_troops = troops if system_secured else min(troops + troop_regen*(max_jumps + build_time), max_troops)
        planned_troops += .01  # we must attack with more troops than there are defenders
        troop_cost = math.ceil((planned_troops+_TROOPS_SAFETY_MARGIN) / 6.0) * 20 * FleetUtilsAI.get_fleet_upkeep()
    else:
        loc = locs[0]
        species_here = universe.getPlanet(loc).speciesName
        design = fo.getShipDesign(design_id)
        cost_per_ship = design.productionCost(empire_id, loc)
        build_time = design.productionTime(empire_id, loc)
        troops_per_ship = CombatRatingsAI.weight_attack_troops(design.troopCapacity,
                                                               CombatRatingsAI.get_species_troops_grade(species_here))
        planned_troops = troops if system_secured else min(troops + troop_regen*(max_jumps + build_time), max_troops)
        planned_troops += .01  # we must attack with more troops than there are defenders
        ships_needed = math.ceil((planned_troops+_TROOPS_SAFETY_MARGIN) / float(troops_per_ship))
        troop_cost = ships_needed * cost_per_ship  # fleet upkeep is already included in query from server

    # apply some bias to expensive operations
    normalized_cost = float(troop_cost) / max(fo.getEmpire().productionPoints, 1)
    normalized_cost = max(1., normalized_cost)
    cost_score = (normalized_cost**2 / 50.0) * troop_cost

    base_score = colony_base_value + bld_tally + tech_tally + enemy_val - cost_score
    # If the AI does have enough total miltary to attack this target, and the target is more than minimally valuable,
    # don't let the threat_factor discount the adjusted value below MIN_INVASION_SCORE +1, so that if there are no
    # other targets the AI could still pursue this one.  Otherwise, scoring pressure from
    # MilitaryAI.get_preferred_max_military_portion_for_single_battle might prevent the AI from attacking heavily
    # defended but still defeatable targets even if it has no softer targets available.
    if total_max_mil_rating > sys_total_threat and base_score > 2 * MIN_INVASION_SCORE:
        threat_factor = max(threat_factor, (MIN_INVASION_SCORE + 1)/base_score)
    planet_score = retaliation_risk_factor(planet.owner) * threat_factor * max(0, base_score)
    if clear_path:
        planet_score *= 1.5
    if verbose:
        debug(' - planet score: %.2f\n'
              ' - planned troops: %.2f\n'
              ' - projected troop cost: %.1f\n'
              ' - threat factor: %s\n'
              ' - planet detail: %s\n'
              ' - popval: %.1f\n'
              ' - bldval: %s\n'
              ' - enemyval: %s',
              planet_score, planned_troops, troop_cost, threat_factor, detail, colony_base_value, bld_tally, enemy_val)
        debug(' - system secured: %s' % system_secured)
    return [planet_score, planned_troops]
예제 #45
0
def evaluate_invasion_planet(planet_id):
    """Return the invasion value (score, troops) of a planet."""
    universe = fo.getUniverse()
    empire_id = fo.empireID()
    detail = []

    planet = universe.getPlanet(planet_id)
    if planet is None:
        debug("Invasion AI couldn't access any info for planet id %d" %
              planet_id)
        return [0, 0]

    system_id = planet.systemID

    # by using the following instead of simply relying on stealth meter reading,
    # can (sometimes) plan ahead even if planet is temporarily shrouded by an ion storm
    predicted_detectable = EspionageAI.colony_detectable_by_empire(
        planet_id, empire=fo.empireID(), default_result=False)
    if not predicted_detectable:
        if get_partial_visibility_turn(planet_id) < fo.currentTurn():
            debug("InvasionAI predicts planet id %d to be stealthed" %
                  planet_id)
            return [0, 0]
        else:
            debug(
                "InvasionAI predicts planet id %d to be stealthed" %
                planet_id +
                ", but somehow have current visibility anyway, will still consider as target"
            )

    # Check if the target planet was extra-stealthed somehow its system was last viewed
    # this test below may augment the tests above,
    # but can be thrown off by temporary combat-related sighting
    system_last_seen = get_partial_visibility_turn(planet_id)
    planet_last_seen = get_partial_visibility_turn(system_id)
    if planet_last_seen < system_last_seen:
        # TODO: track detection strength, order new scouting when it goes up
        debug(
            "Invasion AI considering planet id %d (stealthed at last view), still proceeding."
            % planet_id)

    # get a baseline evaluation of the planet as determined by ColonisationAI
    species_name = planet.speciesName
    species = fo.getSpecies(species_name)
    empire_research_list = tuple(element.tech
                                 for element in fo.getEmpire().researchQueue)
    if not species or AIDependencies.TAG_DESTROYED_ON_CONQUEST in species.tags:
        # this call iterates over this Empire's available species with which it could colonize after an invasion
        planet_eval = ColonisationAI.assign_colonisation_values(
            [planet_id], MissionType.INVASION, None, detail)
        colony_base_value = max(
            0.75 * planet_eval.get(planet_id, [0])[0],
            calculate_planet_colonization_rating.
            calculate_planet_colonization_rating(
                planet_id=planet_id,
                mission_type=MissionType.OUTPOST,
                spec_name=None,
                detail=detail,
                empire_research_list=empire_research_list,
            ),
        )
    else:
        colony_base_value = calculate_planet_colonization_rating.calculate_planet_colonization_rating(
            planet_id=planet_id,
            mission_type=MissionType.INVASION,
            spec_name=species_name,
            detail=detail,
            empire_research_list=empire_research_list,
        )

    # Add extra score for all buildings on the planet
    building_values = {
        "BLD_IMPERIAL_PALACE": 1000,
        "BLD_CULTURE_ARCHIVES": 1000,
        "BLD_AUTO_HISTORY_ANALYSER": 100,
        "BLD_SHIPYARD_BASE": 100,
        "BLD_SHIPYARD_ORG_ORB_INC": 200,
        "BLD_SHIPYARD_ORG_XENO_FAC": 200,
        "BLD_SHIPYARD_ORG_CELL_GRO_CHAMB": 200,
        "BLD_SHIPYARD_CON_NANOROBO": 300,
        "BLD_SHIPYARD_CON_GEOINT": 400,
        "BLD_SHIPYARD_CON_ADV_ENGINE": 1000,
        "BLD_SHIPYARD_AST": 300,
        "BLD_SHIPYARD_AST_REF": 1000,
        "BLD_SHIPYARD_ENRG_SOLAR": 1500,
        "BLD_INDUSTRY_CENTER": 500,
        "BLD_GAS_GIANT_GEN": 200,
        "BLD_SOL_ORB_GEN": 800,
        "BLD_BLACK_HOLE_POW_GEN": 2000,
        "BLD_ENCLAVE_VOID": 500,
        "BLD_NEUTRONIUM_EXTRACTOR": 2000,
        "BLD_NEUTRONIUM_SYNTH": 2000,
        "BLD_NEUTRONIUM_FORGE": 1000,
        "BLD_CONC_CAMP": 100,
        "BLD_BIOTERROR_PROJECTOR": 1000,
        "BLD_SHIPYARD_ENRG_COMP": 3000,
    }
    bld_tally = 0
    for bldType in [
            universe.getBuilding(bldg).buildingTypeName
            for bldg in planet.buildingIDs
    ]:
        bval = building_values.get(bldType, 50)
        bld_tally += bval
        detail.append("%s: %d" % (bldType, bval))

    # Add extra score for unlocked techs when we conquer the species
    tech_tally = 0
    value_per_pp = 4
    for unlocked_tech in AIDependencies.SPECIES_TECH_UNLOCKS.get(
            species_name, []):
        if not tech_is_complete(unlocked_tech):
            rp_cost = fo.getTech(unlocked_tech).researchCost(empire_id)
            tech_value = value_per_pp * rp_cost
            tech_tally += tech_value
            detail.append("%s: %d" % (unlocked_tech, tech_value))

    least_jumps_path, max_jumps = _get_path_from_capital(planet)
    clear_path = True

    aistate = get_aistate()
    system_status = aistate.systemStatus.get(system_id, {})
    system_fleet_treat = system_status.get("fleetThreat", 1000)
    system_monster_threat = system_status.get("monsterThreat", 0)
    sys_total_threat = system_fleet_treat + system_monster_threat + system_status.get(
        "planetThreat", 0)
    max_path_threat = system_fleet_treat
    mil_ship_rating = MilitaryAI.cur_best_mil_ship_rating()
    for path_sys_id in least_jumps_path:
        path_leg_status = aistate.systemStatus.get(path_sys_id, {})
        path_leg_threat = path_leg_status.get(
            "fleetThreat", 1000) + path_leg_status.get("monsterThreat", 0)
        if path_leg_threat > 0.5 * mil_ship_rating:
            clear_path = False
            if path_leg_threat > max_path_threat:
                max_path_threat = path_leg_threat

    pop = planet.currentMeterValue(fo.meterType.population)
    target_pop = planet.currentMeterValue(fo.meterType.targetPopulation)
    troops = planet.currentMeterValue(fo.meterType.troops)
    troop_regen = planet.currentMeterValue(
        fo.meterType.troops) - planet.initialMeterValue(fo.meterType.troops)
    max_troops = planet.currentMeterValue(fo.meterType.maxTroops)
    # TODO: refactor troop determination into function for use in mid-mission updates and also consider defender techs
    max_troops += AIDependencies.TROOPS_PER_POP * (target_pop - pop)

    this_system = universe.getSystem(system_id)
    secure_targets = [system_id] + list(this_system.planetIDs)
    system_secured = False

    secure_fleets = get_aistate().get_fleet_missions_with_any_mission_types(
        [MissionType.SECURE, MissionType.MILITARY])
    for mission in secure_fleets:
        secure_fleet_id = mission.fleet.id
        s_fleet = universe.getFleet(secure_fleet_id)
        if not s_fleet or s_fleet.systemID != system_id:
            continue
        if mission.type in [MissionType.SECURE, MissionType.MILITARY]:
            target_obj = mission.target.get_object()
            if target_obj is not None and target_obj.id in secure_targets:
                system_secured = True
                break
    system_secured = system_secured and system_status.get("myFleetRating", 0)
    debug(
        "Invasion eval of %s\n"
        " - maxShields: %.1f\n"
        " - sysFleetThreat: %.1f\n"
        " - sysMonsterThreat: %.1f",
        planet,
        planet.currentMeterValue(fo.meterType.maxShield),
        system_fleet_treat,
        system_monster_threat,
    )
    enemy_val = 0
    if planet.owner != -1:  # value in taking this away from an enemy
        enemy_val = 20 * (
            planet.currentMeterValue(fo.meterType.targetIndustry) +
            2 * planet.currentMeterValue(fo.meterType.targetResearch))

    # devalue invasions that would require too much military force
    preferred_max_portion = MilitaryAI.get_preferred_max_military_portion_for_single_battle(
    )
    total_max_mil_rating = MilitaryAI.get_concentrated_tot_mil_rating()
    threat_exponent = 2  # TODO: make this a character trait; higher aggression with a lower exponent
    threat_factor = min(
        1, preferred_max_portion * total_max_mil_rating /
        (sys_total_threat + 0.001))**threat_exponent

    design_id, _, locs = get_best_ship_info(PriorityType.PRODUCTION_INVASION)
    if not locs or not universe.getPlanet(locs[0]):
        # We are in trouble anyway, so just calculate whatever approximation...
        build_time = 4
        planned_troops = troops if system_secured else min(
            troops + troop_regen * (max_jumps + build_time), max_troops)
        planned_troops += 0.01  # we must attack with more troops than there are defenders
        troop_cost = math.ceil((planned_troops + _TROOPS_SAFETY_MARGIN) /
                               6.0) * 20 * FleetUtilsAI.get_fleet_upkeep()
    else:
        loc = locs[0]
        species_here = universe.getPlanet(loc).speciesName
        design = fo.getShipDesign(design_id)
        cost_per_ship = design.productionCost(empire_id, loc)
        build_time = design.productionTime(empire_id, loc)
        troops_per_ship = CombatRatingsAI.weight_attack_troops(
            design.troopCapacity,
            get_species_tag_grade(species_here, Tags.ATTACKTROOPS))
        planned_troops = troops if system_secured else min(
            troops + troop_regen * (max_jumps + build_time), max_troops)
        planned_troops += 0.01  # we must attack with more troops than there are defenders
        ships_needed = math.ceil(
            (planned_troops + _TROOPS_SAFETY_MARGIN) / float(troops_per_ship))
        troop_cost = ships_needed * cost_per_ship  # fleet upkeep is already included in query from server

    # apply some bias to expensive operations
    normalized_cost = float(troop_cost) / max(fo.getEmpire().productionPoints,
                                              1)
    normalized_cost = max(1.0, normalized_cost)
    cost_score = (normalized_cost**2 / 50.0) * troop_cost

    base_score = colony_base_value + bld_tally + tech_tally + enemy_val - cost_score
    # If the AI does have enough total military to attack this target, and the target is more than minimally valuable,
    # don't let the threat_factor discount the adjusted value below MIN_INVASION_SCORE +1, so that if there are no
    # other targets the AI could still pursue this one.  Otherwise, scoring pressure from
    # MilitaryAI.get_preferred_max_military_portion_for_single_battle might prevent the AI from attacking heavily
    # defended but still defeatable targets even if it has no softer targets available.
    if total_max_mil_rating > sys_total_threat and base_score > 2 * MIN_INVASION_SCORE:
        threat_factor = max(threat_factor,
                            (MIN_INVASION_SCORE + 1) / base_score)
    planet_score = retaliation_risk_factor(planet.owner) * threat_factor * max(
        0, base_score)
    if clear_path:
        planet_score *= 1.5
    debug(
        " - planet score: %.2f\n"
        " - planned troops: %.2f\n"
        " - projected troop cost: %.1f\n"
        " - threat factor: %s\n"
        " - planet detail: %s\n"
        " - popval: %.1f\n"
        " - bldval: %s\n"
        " - enemyval: %s",
        planet_score,
        planned_troops,
        troop_cost,
        threat_factor,
        detail,
        colony_base_value,
        bld_tally,
        enemy_val,
    )
    debug(" - system secured: %s" % system_secured)
    return [planet_score, planned_troops]
예제 #46
0
    def issue_fleet_orders(self):
        """issues AIFleetOrders which can be issued in system and moves to next one if is possible"""
        # TODO: priority
        order_completed = True
        print
        print "Checking orders for fleet %s (on turn %d), with mission type %s" % (
            self.fleet.get_object(), fo.currentTurn(), self.type or 'No mission')
        if MissionType.INVASION == self.type:
            self._check_retarget_invasion()
        just_issued_move_order = False
        last_move_target_id = INVALID_ID
        # Note: the following abort check somewhat assumes only one major mission type
        for fleet_order in self.orders:
            if (isinstance(fleet_order, (OrderColonize, OrderOutpost, OrderInvade)) and
                    self._check_abort_mission(fleet_order)):
                return
        for fleet_order in self.orders:
            if just_issued_move_order and self.fleet.get_object().systemID != last_move_target_id:
                # having just issued a move order, we will normally stop issuing orders this turn, except that if there
                # are consecutive move orders we will consider moving through the first destination rather than stopping
                # Without the below noinspection directive, PyCharm is concerned about the 2nd part of the test
                # noinspection PyTypeChecker
                if (not isinstance(fleet_order, OrderMove) or
                        self.need_to_pause_movement(last_move_target_id, fleet_order)):
                    break
            print "Checking order: %s" % fleet_order
            self.check_mergers(context=str(fleet_order))
            if fleet_order.can_issue_order(verbose=False):
                if isinstance(fleet_order, OrderMove) and order_completed:  # only move if all other orders completed
                    print "Issuing fleet order %s" % fleet_order
                    fleet_order.issue_order()
                    just_issued_move_order = True
                    last_move_target_id = fleet_order.target.id
                elif not isinstance(fleet_order, OrderMove):
                    print "Issuing fleet order %s" % fleet_order
                    fleet_order.issue_order()
                else:
                    print "NOT issuing (even though can_issue) fleet order %s" % fleet_order
                print "Order issued: %s" % fleet_order.order_issued
                if not fleet_order.executed:
                    order_completed = False
            else:  # check that we're not held up by a Big Monster
                if fleet_order.order_issued:
                    # A previously issued order that wasn't instantly executed must have had cirumstances change so that
                    # the order can't currently be reissued (or perhaps simply a savegame has been reloaded on the same
                    # turn the order was issued).
                    if not fleet_order.executed:
                        order_completed = False
                    # Go on to the next order.
                    continue
                print "CAN'T issue fleet order %s" % fleet_order
                if isinstance(fleet_order, OrderMove):
                    this_system_id = fleet_order.target.id
                    this_status = foAI.foAIstate.systemStatus.setdefault(this_system_id, {})
                    threat_threshold = fo.currentTurn() * MilitaryAI.cur_best_mil_ship_rating() / 4.0
                    if this_status.get('monsterThreat', 0) > threat_threshold:
                        # if this move order is not this mil fleet's final destination, and blocked by Big Monster,
                        # release and hope for more effective reassignment
                        if (self.type not in (MissionType.MILITARY, MissionType.SECURE) or
                                fleet_order != self.orders[-1]):
                            print "Aborting mission due to being blocked by Big Monster at system %d, threat %d" % (
                                this_system_id, foAI.foAIstate.systemStatus[this_system_id]['monsterThreat'])
                            print "Full set of orders were:"
                            for this_order in self.orders:
                                print " - %s" % this_order
                            self.clear_fleet_orders()
                            self.clear_target()
                            return
                break  # do not order the next order until this one is finished.
        else:  # went through entire order list
            if order_completed:
                print "Final order is completed"
                orders = self.orders
                last_order = orders[-1] if orders else None
                universe = fo.getUniverse()

                if last_order and isinstance(last_order, OrderColonize):
                    planet = universe.getPlanet(last_order.target.id)
                    sys_partial_vis_turn = get_partial_visibility_turn(planet.systemID)
                    planet_partial_vis_turn = get_partial_visibility_turn(planet.id)
                    if (planet_partial_vis_turn == sys_partial_vis_turn and
                            not planet.initialMeterValue(fo.meterType.population)):
                        warn("Fleet %d has tentatively completed its "
                             "colonize mission but will wait to confirm population." % self.fleet.id)
                        print "    Order details are %s" % last_order
                        print "    Order is valid: %s; issued: %s; executed: %s" % (
                            last_order.is_valid(), last_order.order_issued, last_order.executed)
                        if not last_order.is_valid():
                            source_target = last_order.fleet
                            target_target = last_order.target
                            print "        source target validity: %s; target target validity: %s " % (
                                bool(source_target), bool(target_target))
                        return  # colonize order must not have completed yet
                clear_all = True
                last_sys_target = INVALID_ID
                if last_order and isinstance(last_order, OrderMilitary):
                    last_sys_target = last_order.target.id
                    # not doing this until decide a way to release from a SECURE mission
                    # if (MissionType.SECURE == self.type) or
                    secure_targets = set(AIstate.colonyTargetedSystemIDs +
                                         AIstate.outpostTargetedSystemIDs +
                                         AIstate.invasionTargetedSystemIDs)
                    if last_sys_target in secure_targets:  # consider a secure mission
                        if last_sys_target in AIstate.colonyTargetedSystemIDs:
                            secure_type = "Colony"
                        elif last_sys_target in AIstate.outpostTargetedSystemIDs:
                            secure_type = "Outpost"
                        elif last_sys_target in AIstate.invasionTargetedSystemIDs:
                            secure_type = "Invasion"
                        else:
                            secure_type = "Unidentified"
                        print ("Fleet %d has completed initial stage of its mission "
                               "to secure system %d (targeted for %s), "
                               "may release a portion of ships" % (self.fleet.id, last_sys_target, secure_type))
                        clear_all = False
                fleet_id = self.fleet.id
                if clear_all:
                    if orders:
                        print "Fleet %d has completed its mission; clearing all orders and targets." % self.fleet.id
                        print "Full set of orders were:"
                        for this_order in orders:
                            print "\t\t %s" % this_order
                        self.clear_fleet_orders()
                        self.clear_target()
                        if foAI.foAIstate.get_fleet_role(fleet_id) in (MissionType.MILITARY,
                                                                       MissionType.SECURE):
                            allocations = MilitaryAI.get_military_fleets(mil_fleets_ids=[fleet_id],
                                                                         try_reset=False,
                                                                         thisround="Fleet %d Reassignment" % fleet_id)
                            if allocations:
                                MilitaryAI.assign_military_fleets_to_systems(use_fleet_id_list=[fleet_id],
                                                                             allocations=allocations)
                    else:  # no orders
                        print "No Current Orders"
                else:
                    # TODO: evaluate releasing a smaller portion or none of the ships
                    system_status = foAI.foAIstate.systemStatus.setdefault(last_sys_target, {})
                    new_fleets = []
                    threat_present = system_status.get('totalThreat', 0) + system_status.get('neighborThreat', 0) > 0
                    target_system = universe.getSystem(last_sys_target)
                    if not threat_present and target_system:
                        for pid in target_system.planetIDs:
                            planet = universe.getPlanet(pid)
                            if (planet and
                                    planet.owner != fo.empireID() and
                                    planet.currentMeterValue(fo.meterType.maxDefense) > 0):
                                threat_present = True
                                break
                    if not threat_present:
                        print "No current threat in target system; releasing a portion of ships."
                        # at least first stage of current task is done;
                        # release extra ships for potential other deployments
                        new_fleets = FleetUtilsAI.split_fleet(self.fleet.id)
                    else:
                        print "Threat remains in target system; NOT releasing any ships."
                    new_military_fleets = []
                    for fleet_id in new_fleets:
                        if foAI.foAIstate.get_fleet_role(fleet_id) in COMBAT_MISSION_TYPES:
                            new_military_fleets.append(fleet_id)
                    allocations = []
                    if new_military_fleets:
                        allocations = MilitaryAI.get_military_fleets(
                            mil_fleets_ids=new_military_fleets,
                            try_reset=False,
                            thisround="Fleet Reassignment %s" % new_military_fleets
                        )
                    if allocations:
                        MilitaryAI.assign_military_fleets_to_systems(use_fleet_id_list=new_military_fleets,
                                                                     allocations=allocations)
예제 #47
0
    def issue_fleet_orders(self):
        """issues AIFleetOrders which can be issued in system and moves to next one if is possible"""
        # TODO: priority
        order_completed = True
        print "--------------"
        print "Checking orders for fleet %d (on turn %d)" % (self.target_id, fo.currentTurn())
        print "\t Full Orders are:"
        for this_orders in self.orders:
            print "\t\t %s" % this_orders
        print "/t/t------"
        if AIFleetMissionType.FLEET_MISSION_INVASION in self.get_mission_types():
            self._check_retarget_invasion()
        for fleet_order in self.orders:
            print "  checking Order: %s" % fleet_order
            order_type = fleet_order.get_fleet_order_type()
            if order_type in [AIFleetOrderType.ORDER_COLONISE,
                              AIFleetOrderType.ORDER_OUTPOST,
                              AIFleetOrderType.ORDER_INVADE]:  # TODO: invasion?
                if self._check_abort_mission(fleet_order):
                    return
            self.check_mergers(context=str(fleet_order))
            if fleet_order.can_issue_order(verbose=True):
                if order_type == AIFleetOrderType.ORDER_MOVE and order_completed:  # only move if all other orders completed
                    fleet_order.issue_order()
                elif order_type not in [AIFleetOrderType.ORDER_MOVE, AIFleetOrderType.ORDER_DEFEND]:
                    fleet_order.issue_order()
                if not fleet_order.is_execution_completed():
                    order_completed = False
            else:  # check that we're not held up by a Big Monster
                if order_type == AIFleetOrderType.ORDER_MOVE:
                    this_system_id = fleet_order.get_target_target().target_id
                    this_status = foAI.foAIstate.systemStatus.setdefault(this_system_id, {})
                    if this_status.get('monsterThreat', 0) > fo.currentTurn() * ProductionAI.curBestMilShipRating()/4.0:
                        first_mission = self.get_mission_types()[0] if self.get_mission_types() else AIFleetMissionType.FLEET_MISSION_INVALID
                        if (first_mission not in (AIFleetMissionType.FLEET_MISSION_ATTACK,
                                                   AIFleetMissionType.FLEET_MISSION_MILITARY,
                                                   AIFleetMissionType.FLEET_MISSION_HIT_AND_RUN,
                                                   AIFleetMissionType.FLEET_MISSION_SECURE,
                                                   ) or
                            fleet_order != self.orders[-1]  # if this move order is not this mil fleet's final destination, and blocked by Big Monster, release and hope for more effective reassignment
                            ):
                            print "Aborting mission due to being blocked by Big Monster at system %d, threat %d"%(this_system_id, foAI.foAIstate.systemStatus[this_system_id]['monsterThreat'])
                            print "Full set of orders were:"
                            for this_orders in self.orders:
                                print "\t\t %s" % this_orders
                            self.clear_fleet_orders()
                            self.clear_targets(([-1] + self.get_mission_types()[:1])[-1])
                            return
            # moving to another system stops issuing all orders in system where fleet is
            # move order is also the last order in system
            if order_type == AIFleetOrderType.ORDER_MOVE:
                fleet = fo.getUniverse().getFleet(self.target_id)
                if fleet.systemID != fleet_order.get_target_target().target_id:
                    break
        else:  # went through entire order list
            if order_completed:
                orders = self.orders
                last_order = orders[-1] if orders else None
                universe = fo.getUniverse()

                if last_order and last_order.get_fleet_order_type() == AIFleetOrderType.ORDER_COLONISE:
                    planet = universe.getPlanet(last_order.get_target_target().target_id)
                    sys_partial_vis_turn = dict_from_map(universe.getVisibilityTurnsMap(planet.systemID, fo.empireID())).get(fo.visibility.partial, -9999)
                    planet_partial_vis_turn = dict_from_map(universe.getVisibilityTurnsMap(planet.id, fo.empireID())).get(fo.visibility.partial, -9999)
                    if planet_partial_vis_turn == sys_partial_vis_turn and not planet.currentMeterValue(fo.meterType.population):
                        print "Potential Error: Fleet %d has tentatively completed its colonize mission but will wait to confirm population." % self.target_id
                        print "    Order details are %s" % last_order
                        print "    Order is valid: %s ; is Executed : %s; is execution completed: %s " % (last_order.is_valid(), last_order.isExecuted(), last_order.isExecutionCompleted())
                        if not last_order.is_valid():
                            source_target = last_order.get_source_target()
                            target_target = last_order.get_target_target()
                            print "        source target validity: %s; target target validity: %s " % (source_target.valid, target_target.valid)
                            if EnumsAI.AITargetType.TARGET_SHIP == source_target.target_type:
                                ship_id = source_target.target_id
                                ship = universe.getShip(ship_id)
                                if not ship:
                                    print "Ship id %d not a valid ship id" % ship_id
                                print "        source target Ship (%d), species %s, can%s colonize" % (ship_id, ship.speciesName, ["not", ""][ship.canColonize])
                        return  # colonize order must not have completed yet
                clearAll = True
                last_sys_target = -1
                if last_order and last_order.get_fleet_order_type() == AIFleetOrderType.ORDER_MILITARY:
                    last_sys_target = last_order.get_target_target().target_id
                    # if (AIFleetMissionType.FLEET_MISSION_SECURE in self.get_mission_types()) or # not doing this until decide a way to release from a SECURE mission
                    secure_targets = set(AIstate.colonyTargetedSystemIDs + AIstate.outpostTargetedSystemIDs + AIstate.invasionTargetedSystemIDs + AIstate.blockadeTargetedSystemIDs)
                    if last_sys_target in secure_targets:  # consider a secure mission
                        if last_sys_target in AIstate.colonyTargetedSystemIDs:
                            secure_type = "Colony"
                        elif last_sys_target in AIstate.outpostTargetedSystemIDs:
                            secure_type = "Outpost"
                        elif last_sys_target in AIstate.invasionTargetedSystemIDs:
                            secure_type = "Invasion"
                        elif last_sys_target in AIstate.blockadeTargetedSystemIDs:
                            secure_type = "Blockade"
                        else:
                            secure_type = "Unidentified"
                        print "Fleet %d has completed initial stage of its mission to secure system %d (targeted for %s), may release a portion of ships" % (self.target_id, last_sys_target, secure_type)
                        clearAll = False
                fleet_id = self.target_id
                if clearAll:
                    if orders:
                        print "Fleet %d has completed its mission; clearing all orders and targets." % self.target_id
                        print "Full set of orders were:"
                        for this_orders in orders:
                            print "\t\t %s" % this_orders
                        self.clear_fleet_orders()
                        self.clear_targets(([-1] + self.get_mission_types()[:1])[-1])
                        if foAI.foAIstate.get_fleet_role(fleet_id) in (AIFleetMissionType.FLEET_MISSION_MILITARY,
                                                                       AIFleetMissionType.FLEET_MISSION_ATTACK,
                                                                       AIFleetMissionType.FLEET_MISSION_DEFEND,
                                                                       AIFleetMissionType.FLEET_MISSION_HIT_AND_RUN,
                                                                       AIFleetMissionType.FLEET_MISSION_SECURE):
                            allocations = MilitaryAI.get_military_fleets(milFleetIDs=[fleet_id], tryReset=False, thisround="Fleet %d Reassignment" % fleet_id)
                            if allocations:
                                MilitaryAI.assign_military_fleets_to_systems(useFleetIDList=[fleet_id], allocations=allocations)
                    else:  # no orders
                        print "No Current Orders"
                else:
                    #TODO: evaluate releasing a smaller portion or none of the ships
                    system_status = foAI.foAIstate.systemStatus.setdefault(last_sys_target, {})
                    new_fleets = []
                    threat_present = (system_status.get('totalThreat', 0) != 0) or (system_status.get('neighborThreat', 0) != 0)
                    target_system = universe.getSystem(last_sys_target)
                    if not threat_present and target_system:
                        for pid in target_system.planetIDs:
                            planet = universe.getPlanet(pid)
                            if planet and planet.owner != fo.empireID() and planet.currentMeterValue(fo.meterType.maxDefense) > 0:
                                threat_present = True
                                break
                    if not threat_present:
                        print "No current threat in target system; releasing a portion of ships."
                        new_fleets = FleetUtilsAI.split_fleet(self.target_id)  # at least first stage of current task is done; release extra ships for potential other deployments
                    else:
                        print "Threat remains in target system; NOT releasing any ships."
                    new_military_fleets = []
                    for fleet_id in new_fleets:
                        if foAI.foAIstate.get_fleet_role(fleet_id) in (AIFleetMissionType.FLEET_MISSION_MILITARY,
                                                                       AIFleetMissionType.FLEET_MISSION_ATTACK,
                                                                       AIFleetMissionType.FLEET_MISSION_DEFEND,
                                                                       AIFleetMissionType.FLEET_MISSION_HIT_AND_RUN,
                                                                       AIFleetMissionType.FLEET_MISSION_SECURE):
                            new_military_fleets.append(fleet_id)
                    allocations = []
                    if new_military_fleets:
                        allocations = MilitaryAI.get_military_fleets(milFleetIDs=new_military_fleets, tryReset=False, thisround="Fleet Reassignment %s" % new_military_fleets)
                    if allocations:
                        MilitaryAI.assign_military_fleets_to_systems(useFleetIDList=new_military_fleets, allocations=allocations)
예제 #48
0
    def can_issue_order(self, verbose=False):
        """If FleetOrder can be issued now."""
        # for some orders, may need to re-issue if invasion/outposting/colonization was interrupted
        if self.executed and self.order_type not in [AIFleetOrderType.ORDER_OUTPOST, AIFleetOrderType.ORDER_COLONISE, AIFleetOrderType.ORDER_INVADE]:
            return False
        if not self.is_valid():
            return False
        universe = fo.getUniverse()
        ship_id = None
        fleet_id = self.fleet.target_id
        fleet = universe.getFleet(fleet_id)
        system_id = fleet.systemID
        target_id = self.target.target_id

        if verbose:
            sys1 = universe.getSystem(system_id)
            sys_name = sys1 and sys1.name or "unknown"
            main_fleet_mission = foAI.foAIstate.get_fleet_mission(fleet_id)
            main_mission_type = (main_fleet_mission.get_mission_types() + [-1])[0]
            print "** %s -- Mission Type  %s (%s) , current loc sys %d  - %s" % (self, AIFleetMissionTypeNames.name(main_mission_type), main_mission_type, system_id, sys_name)
        #
        # outpost
        #
        if AIFleetOrderType.ORDER_OUTPOST == self.order_type:  # TODO: check for separate fleet holding outpost ships

            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)
            ship = universe.getShip(ship_id)
            planet = universe.getPlanet(self.target.target_id)
            return ship is not None and fleet.systemID == planet.systemID and ship.canColonize
        #
        # colonise
        #
        elif AIFleetOrderType.ORDER_COLONISE == self.order_type:  # TODO: check for separate fleet holding colony ships
            if TargetType.TARGET_FLEET == self.fleet.target_type:
                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)
            ship = universe.getShip(ship_id)
            planet = universe.getPlanet(self.target.target_id)
            if ship and not ship.canColonize:
                print "Error: colonization fleet %d has no colony ship" % fleet_id
            return ship is not None and fleet.systemID == planet.systemID and ship.canColonize
        #
        # invade
        #
        elif AIFleetOrderType.ORDER_INVADE == self.order_type:  # TODO: check for separate fleet holding invasion ships
            if TargetType.TARGET_FLEET == self.fleet.target_type:
                ship_id = FleetUtilsAI.get_ship_id_with_role(fleet_id, AIShipRoleType.SHIP_ROLE_MILITARY_INVASION, False)
                if ship_id is None:
                    ship_id = FleetUtilsAI.get_ship_id_with_role(fleet_id, AIShipRoleType.SHIP_ROLE_BASE_INVASION)
            ship = universe.getShip(ship_id)
            planet = universe.getPlanet(self.target.target_id)
            return ship is not None and fleet.systemID == planet.systemID and ship.canInvade and not planet.currentMeterValue(fo.meterType.shield)
        #
        # military
        #
        elif AIFleetOrderType.ORDER_MILITARY == self.order_type:
            if TargetType.TARGET_FLEET == self.fleet.target_type:
                ship_id = FleetUtilsAI.get_ship_id_with_role(fleet_id, AIShipRoleType.SHIP_ROLE_MILITARY)
            ship = universe.getShip(ship_id)
            system = universe.getSystem(self.target.target_id)
            return ship is not None and fleet.systemID == system.systemID and ship.isArmed
        #
        # split fleet
        #
        elif AIFleetOrderType.ORDER_SPLIT_FLEET == self.order_type:
            return len(fleet.shipIDs) > 1
        #
        # move -- have fleets will do a safety check, also check for potential military fleet mergers
        #
        elif AIFleetOrderType.ORDER_MOVE == self.order_type:
            #  target_id = self.target.target_id
            # TODO: figure out better way to have invasions (& possibly colonizations) require visibility on target without needing visibility of all intermediate systems
            if False and main_mission_type not in [AIFleetMissionType.FLEET_MISSION_ATTACK,  # TODO: consider this later
                                                 AIFleetMissionType.FLEET_MISSION_MILITARY,
                                                 AIFleetMissionType.FLEET_MISSION_SECURE,
                                                 AIFleetMissionType.FLEET_MISSION_HIT_AND_RUN,
                                                 AIFleetMissionType.FLEET_MISSION_EXPLORATION]:
                if not universe.getVisibility(target_id, foAI.foAIstate.empireID) >= fo.visibility.partial:
                    #if not target_id in interior systems
                    foAI.foAIstate.needsEmergencyExploration.append(fleet.systemID)
                    return False

            system_id = fleet.systemID
            if system_id == target_id:
                return True  # TODO: already there, but could consider retreating

            fleet_rating = foAI.foAIstate.get_rating(fleet_id).get('overall', 0)
            target_sys_status = foAI.foAIstate.systemStatus.get(target_id, {})
            f_threat = target_sys_status.get('fleetThreat', 0)
            m_threat = target_sys_status.get('monsterThreat', 0)
            p_threat = target_sys_status.get('planetThreat', 0)
            threat = f_threat + m_threat + p_threat
            safety_factor = MilitaryAI.get_safety_factor()
            if fleet_rating >= safety_factor * threat:
                return True
            else:
                sys1 = universe.getSystem(system_id)
                sys1_name = sys1 and sys1.name or "unknown"
                targ1 = universe.getSystem(target_id)
                targ1_name = (targ1 and targ1.name) or "unknown"
                # following line was poor because AIstate.militaryFleetIDs only covers fleets without current missions
                # my_other_fleet_rating = sum([foAI.foAIstate.fleetStatus.get(fleet_id, {}).get('rating', 0) for fleet_id in foAI.foAIstate.militaryFleetIDs if ( foAI.foAIstate.fleetStatus.get(fleet_id, {}).get('sysID', -1) == thisSystemID ) ])
                # myOtherFleetsRatings = [foAI.foAIstate.fleetStatus.get(fid, {}).get('rating', {}) for fid in foAI.foAIstate.systemStatus.get(target_id, {}).get('myfleets', [])]
                # my_other_fleet_rating = sum([foAI.foAIstate.fleetStatus.get(fid, {}).get('rating', 0) for fid in foAI.foAIstate.systemStatus.get( target_id, {}).get('myfleets', []) ])
                my_other_fleet_rating = foAI.foAIstate.systemStatus.get(target_id, {}).get('myFleetRating', 0)  # TODO: adjust calc for any departing fleets
                is_military = foAI.foAIstate.get_fleet_role(fleet_id) == AIFleetMissionType.FLEET_MISSION_MILITARY
                if ((my_other_fleet_rating > 3 * safety_factor * threat) or
                            (is_military and my_other_fleet_rating + fleet_rating > safety_factor * threat) or
                            (is_military and my_other_fleet_rating + fleet_rating > 0.8 * safety_factor * threat and fleet_rating > 0.2 * threat)):
                    if verbose:
                        print "\tAdvancing fleet %d (rating %d) at system %d (%s) into system %d (%s) with threat %d because of sufficient empire fleet strength already at destination" % (fleet_id, fleet_rating, system_id, sys1_name, target_id, targ1_name, threat)
                    return True
                elif threat == p_threat and not fleet.aggressive and not my_other_fleet_rating and not target_sys_status.get('localEnemyFleetIDs', [-1]):
                    if verbose:
                        print ("\tAdvancing fleet %d (rating %d) at system %d (%s) into system %d (%s) with planet threat %d because nonaggressive" +
                               " and no other fleets present to trigger combat") % (fleet_id, fleet_rating, system_id, sys1_name, target_id, targ1_name, threat)
                    return True
                else:
                    if verbose:
                        print "\tHolding fleet %d (rating %d) at system %d (%s) before travelling to system %d (%s) with threat %d" % (fleet_id, fleet_rating, system_id, sys1_name, target_id, targ1_name, threat)
                    return False
        else:  # default returns true
            return True