Beispiel #1
0
def cur_best_mil_ship_rating(include_designs=False):
    """Find the best military ship we have available in this turn and return its rating.

    :param include_designs: toggles if available designs are considered or only existing ships
    :return: float: rating of the best ship
    """
    current_turn = fo.currentTurn()
    if current_turn in best_ship_rating_cache:
        best_rating = best_ship_rating_cache[current_turn]
        if include_designs:
            best_design_rating = ProductionAI.cur_best_military_design_rating()
            best_rating = max(best_rating, best_design_rating)
        return best_rating
    best_rating = 0.001
    universe = fo.getUniverse()
    for fleet_id in FleetUtilsAI.get_empire_fleet_ids_by_role(MissionType.MILITARY):
        fleet = universe.getFleet(fleet_id)
        for ship_id in fleet.shipIDs:
            ship = universe.getShip(ship_id)
            if ship:
                ship_info = [(ship.id, ship.designID, ship.speciesName)]
                ship_rating = foAI.foAIstate.rate_psuedo_fleet(ship_info=ship_info)['overall']
                best_rating = max(best_rating, ship_rating)
    best_ship_rating_cache[current_turn] = best_rating
    if include_designs:
        best_design_rating = ProductionAI.cur_best_military_design_rating()
        best_rating = max(best_rating, best_design_rating)
    return max(best_rating, 0.001)
Beispiel #2
0
def generateOrders():
    empire = fo.getEmpire()
    print "Empire:  " + empire.name + " TURN: " + str(fo.currentTurn())
    print "Capital: " + str(empire.capitalID)

    # turn cleanup
    splitFleet()

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

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

    foAIstate.afterTurnCleanup()
    fo.doneTurn()
Beispiel #3
0
def cur_best_mil_ship_rating(include_designs=False):
    """Find the best military ship we have available in this turn and return its rating.

    :param include_designs: toggles if available designs are considered or only existing ships
    :return: float: rating of the best ship
    """
    current_turn = fo.currentTurn()
    if current_turn in _best_ship_rating_cache:
        best_rating = _best_ship_rating_cache[current_turn]
        if include_designs:
            best_design_rating = ProductionAI.cur_best_military_design_rating()
            best_rating = max(best_rating, best_design_rating)
        return best_rating
    best_rating = 0.001
    universe = fo.getUniverse()
    for fleet_id in FleetUtilsAI.get_empire_fleet_ids_by_role(MissionType.MILITARY):
        fleet = universe.getFleet(fleet_id)
        for ship_id in fleet.shipIDs:
            ship_rating = CombatRatingsAI.ShipCombatStats(ship_id).get_rating(enemy_stats=foAI.foAIstate.get_standard_enemy())
            best_rating = max(best_rating, ship_rating)
    _best_ship_rating_cache[current_turn] = best_rating
    if include_designs:
        best_design_rating = ProductionAI.cur_best_military_design_rating()
        best_rating = max(best_rating, best_design_rating)
    return max(best_rating, 0.001)
Beispiel #4
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()
Beispiel #5
0
def cur_best_mil_ship_rating(include_designs=False):
    """Find the best military ship we have available in this turn and return its rating.

    :param include_designs: toggles if available designs are considered or only existing ships
    :return: float: rating of the best ship
    """
    current_turn = fo.currentTurn()
    if current_turn in _best_ship_rating_cache:
        best_rating = _best_ship_rating_cache[current_turn]
        if include_designs:
            best_design_rating = ProductionAI.cur_best_military_design_rating()
            best_rating = max(best_rating, best_design_rating)
        return best_rating
    best_rating = 0.001
    universe = fo.getUniverse()
    for fleet_id in FleetUtilsAI.get_empire_fleet_ids_by_role(MissionType.MILITARY):
        fleet = universe.getFleet(fleet_id)
        for ship_id in fleet.shipIDs:
            ship_rating = CombatRatingsAI.ShipCombatStats(ship_id).get_rating(enemy_stats=foAI.foAIstate.get_standard_enemy())
            best_rating = max(best_rating, ship_rating)
    _best_ship_rating_cache[current_turn] = best_rating
    if include_designs:
        best_design_rating = ProductionAI.cur_best_military_design_rating()
        best_rating = max(best_rating, best_design_rating)
    return max(best_rating, 0.001)
Beispiel #6
0
def assessShipDesignRole(design):
    if design.parts.__contains__("CO_OUTPOST_POD"):
        if design.starlaneSpeed > 0:
            return AIShipRoleType.SHIP_ROLE_CIVILIAN_OUTPOST
        else:
            return AIShipRoleType.SHIP_ROLE_BASE_OUTPOST
            
    if design.parts.__contains__("CO_COLONY_POD") or design.parts.__contains__("CO_SUSPEND_ANIM_POD"):
        if design.starlaneSpeed > 0:
            return AIShipRoleType.SHIP_ROLE_CIVILIAN_COLONISATION
        else:
            return AIShipRoleType.SHIP_ROLE_BASE_COLONISATION
            
    if design.parts.__contains__("GT_TROOP_POD"):
        if design.starlaneSpeed > 0:
            return AIShipRoleType.SHIP_ROLE_MILITARY_INVASION
        else:
            return AIShipRoleType.SHIP_ROLE_BASE_INVASION
            
    if design.starlaneSpeed == 0:
        if design.parts[0] in [ "SH_DEFENSE_GRID", "SH_DEFLECTOR" ,  "SH_MULTISPEC" ]:
            return AIShipRoleType.SHIP_ROLE_BASE_DEFENSE
        else:
            return AIShipRoleType.SHIP_ROLE_INVALID        
            
    stats = foAI.foAIstate.getDesignStats(design)
    rating = stats['attack'] * ( stats['structure'] + stats['shields'] )
    if  ( "SD_SCOUT" in design.name(False)  )  or (rating < 0.2* ProductionAI.curBestMilShipRating()):
        for part in design.parts:
            if "DT_DETECTOR" in part:
                return AIShipRoleType.SHIP_ROLE_CIVILIAN_EXPLORATION
    if rating > 0: #positive attack stat
        return AIShipRoleType.SHIP_ROLE_MILITARY
    else:
        return AIShipRoleType.SHIP_ROLE_CIVILIAN_EXPLORATION  #let this be the default since even without detection part a ship has some inherent
Beispiel #7
0
def calculateMilitaryPriority():
    "calculates the demand for military ships by military targeted systems"
    global unmetThreat

    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empireID = empire.empireID
    capitalID = PlanetUtilsAI.getCapital()
    if capitalID is not None and capitalID != -1:
        homeworld = universe.getPlanet(capitalID)
    else:
        return 0# no capitol (not even a capitol-in-the-making), means can't produce any ships
        
    have_mod_weaps = ( empire.getTechStatus("SHP_WEAPON_1_4") == fo.techStatus.complete or
                                   empire.getTechStatus("SHP_WEAPON_2_1") == fo.techStatus.complete or
                                   empire.getTechStatus("SHP_WEAPON_4_1") == fo.techStatus.complete )
        
    allottedInvasionTargets = 1+ int(fo.currentTurn()/25)
    targetPlanetIDs =  [pid for pid, pscore, trp in AIstate.invasionTargets[:allottedInvasionTargets] ] + [pid for pid,  pscore in foAI.foAIstate.colonisablePlanetIDs[:allottedColonyTargets]  ] + [pid for pid,  pscore in foAI.foAIstate.colonisableOutpostIDs[:allottedColonyTargets]  ]

    mySystems = set( AIstate.popCtrSystemIDs ).union( AIstate.outpostSystemIDs   )
    targetSystems = set( PlanetUtilsAI.getSystems(targetPlanetIDs)  )

    curShipRating = ProductionAI.curBestMilShipRating()
    cSRR = curShipRating**0.5

    unmetThreat = 0.0
    currentTurn=fo.currentTurn()
    shipsNeeded=0
    defenses_needed = 0
    for sysID in mySystems.union(targetSystems) :
        status=foAI.foAIstate.systemStatus.get( sysID,  {} )
        myRating = status.get('myFleetRating',  0)
        my_defenses = status.get('mydefenses',  {}).get('overall', 0)
        baseMonsterThreat = status.get('monsterThreat', 0)
        #scale monster threat so that in early - mid game big monsters don't over-drive military production
        if currentTurn>200:
            monsterThreat = baseMonsterThreat
        elif currentTurn>100:
            if baseMonsterThreat <2000:
                monsterThreat = baseMonsterThreat
            else:
                monsterThreat = 2000 + (currentTurn/100.0 - 1) *(baseMonsterThreat-2000)
        else:
            monsterThreat = 0
        if sysID in mySystems:
            threatRoot = status.get('fleetThreat', 0)**0.5 + 0.8*status.get('max_neighbor_threat', 0)**0.5 + 0.2*status.get('neighborThreat', 0)**0.5 + monsterThreat**0.5 + status.get('planetThreat', 0)**0.5
        else:
            threatRoot = status.get('fleetThreat', 0)**0.5  + monsterThreat**0.5 + status.get('planetThreat', 0)**0.5
        shipsNeeded += math.ceil(( max(0,   (threatRoot - (myRating**0.5 + my_defenses**0.5)))**2)/curShipRating)

    #militaryPriority = int( 40 + max(0,  75*unmetThreat / curShipRating) )
    militaryPriority = int( 40 + max(0,  75*shipsNeeded) )
    if not have_mod_weaps:
        militaryPriority /= 2
    #print "Calculating Military Priority:  40 + 75 * unmetThreat/curShipRating \n\t  Priority: %d    \t unmetThreat  %.0f        curShipRating: %.0f"%(militaryPriority,  unmetThreat,  curShipRating)
    print "Calculating Military Priority:  40 + 75 * shipsNeeded \n\t  Priority: %d   \t shipsNeeded %d   \t unmetThreat  %.0f        curShipRating: %.0f"%(militaryPriority, shipsNeeded,   unmetThreat,  curShipRating)
    return max( militaryPriority,  0)
Beispiel #8
0
def calculateMilitaryPriority():
    "calculates the demand for military ships by military targeted systems"

    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empireID = empire.empireID
    capitalID = PlanetUtilsAI.getCapital()
    if capitalID:
        homeworld = universe.getPlanet(capitalID)
    else:
        return 0# no capitol (not even a capitol-in-the-making), means can't produce any ships
    allottedInvasionTargets = 1+ int(fo.currentTurn()/25)
    targetPlanetIDs =  [pid for pid, pscore, trp in AIstate.invasionTargets[:allottedInvasionTargets] ] + [pid for pid,  pscore in foAI.foAIstate.colonisablePlanetIDs[:allottedColonyTargets]  ] + [pid for pid,  pscore in foAI.foAIstate.colonisableOutpostIDs[:allottedColonyTargets]  ]
    
    mySystems = set( AIstate.popCtrSystemIDs ).union( AIstate.outpostSystemIDs   )
    targetSystems = set( PlanetUtilsAI.getSystems(targetPlanetIDs)  )
    
    curShipRating = ProductionAI.curBestMilShipRating()
    cSRR = curShipRating**0.5

    unmetThreat = 0.0
    currentTurn=fo.currentTurn()
    shipsNeeded=0
    for sysID in mySystems.union(targetSystems) :
        status=foAI.foAIstate.systemStatus.get( sysID,  {} )
        myAttack,  myHealth =0, 0
        for fid in status.get('myfleets', []) :
            rating= foAI.foAIstate.fleetStatus.get(fid,  {}).get('rating', {})
            myAttack += rating.get('attack', 0)
            myHealth += rating.get('health', 0)
        myRating = myAttack*myHealth
        baseMonsterThreat = status.get('monsterThreat', 0)
        if currentTurn>200:
            monsterThreat = baseMonsterThreat
        elif currentTurn>100:
            if baseMonsterThreat <2000:
                monsterThreat = baseMonsterThreat
            else:
                monsterThreat = 2000 + (currentTurn/100.0 - 1) *(baseMonsterThreat-2000)
        else:
            monsterThreat = 0
            
        threatRoot = status.get('fleetThreat', 0)**0.5 + status.get('planetThreat', 0)**0.5 + monsterThreat**0.5
        if sysID in mySystems:
             threatRoot +=  (0.3* status.get('neighborThreat', 0))**0.5   
        else:
             threatRoot +=  (0.1* status.get('neighborThreat', 0))**0.5   
        threat = threatRoot**2
        unmetThreat += max( 0,  threat - myRating )
        shipsNeeded += math.ceil( max(0,   (threatRoot/cSRR)- (myRating/curShipRating)**0.5 ) )
        
    #militaryPriority = int( 40 + max(0,  75*unmetThreat / curShipRating) )  
    militaryPriority = int( 40 + max(0,  75*shipsNeeded) )  
    #print "Calculating Military Priority:  40 + 75 * unmetThreat/curShipRating \n\t  Priority: %d    \t unmetThreat  %.0f        curShipRating: %.0f"%(militaryPriority,  unmetThreat,  curShipRating)
    print "Calculating Military Priority:  40 + 75 * shipsNeeded \n\t  Priority: %d   \t shipsNeeded %d   \t unmetThreat  %.0f        curShipRating: %.0f"%(militaryPriority, shipsNeeded,   unmetThreat,  curShipRating)
    return max( militaryPriority,  0)
Beispiel #9
0
def calculateInvasionPriority():
    "calculates the demand for troop ships by opponent planets"
    global allottedInvasionTargets
    troopsPerPod=2
    empire=fo.getEmpire()
    
    if foAI.foAIstate.aggression==fo.aggression.beginner and fo.currentTurn()<150:
        return 0
    
    allottedInvasionTargets = 1+ int(fo.currentTurn()/25)
    totalVal= sum( [pscore for pid, pscore, trp in AIstate.invasionTargets[:allottedInvasionTargets] ] )
    troopsNeeded= sum( [(trp+4) for pid, pscore, trp in AIstate.invasionTargets[:allottedInvasionTargets] ] )

    if totalVal == 0: 
        return 0 
    opponentTroopPods = int(troopsNeeded/troopsPerPod)

    productionQueue = empire.productionQueue
    queuedTroopPods=0
    for queue_index  in range(0,  len(productionQueue)):
        element=productionQueue[queue_index]
        if element.buildType == EnumsAI.AIEmpireProductionTypes.BT_SHIP:
             if foAI.foAIstate.getShipRole(element.designID) in  [ EnumsAI.AIShipRoleType.SHIP_ROLE_MILITARY_INVASION,  EnumsAI.AIShipRoleType.SHIP_ROLE_BASE_INVASION] :
                 design = fo.getShipDesign(element.designID)
                 queuedTroopPods += element.remaining*element.blocksize * list(design.parts).count("GT_TROOP_POD") 
    bestShip,  bestDesign,  buildChoices = ProductionAI.getBestShipInfo( EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_INVASION)
    if bestDesign:
        troopsPerBestShip = troopsPerPod*(  list(bestDesign.parts).count("GT_TROOP_POD") )
    else:
        troopsPerBestShip=troopsPerPod #may actually not have any troopers available, but this num will do for now

    #don't cound troop bases here since if through misplanning cannot be used where made, cannot be redeployed
    #troopFleetIDs = FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_INVASION)  + FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION)
    troopFleetIDs = FleetUtilsAI.getEmpireFleetIDsByRole(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) 
    numTroopPods =  sum([ FleetUtilsAI.countPartsFleetwide(fleetID,  ["GT_TROOP_POD"]) for fleetID in  troopFleetIDs])
    troopShipsNeeded = math.ceil((opponentTroopPods - (numTroopPods+ queuedTroopPods ))/troopsPerBestShip)  
     
    #invasionPriority = max(  10+ 200*max(0,  troopShipsNeeded ) , int(0.1* totalVal) )
    invasionPriority = 30+ 150*max(0,  troopShipsNeeded )
    if invasionPriority < 0: 
        return 0
    if foAI.foAIstate.aggression==fo.aggression.beginner:
        return 0.5* invasionPriority
    else:
        return invasionPriority
Beispiel #10
0
def sendInvasionFleets(invasionFleetIDs, evaluatedPlanets, missionType):
    "sends a list of invasion fleets to a list of planet_value_pairs"
    universe=fo.getUniverse()
    invasionPool = invasionFleetIDs[:]  #need to make a copy
    bestShip,  bestDesign,  buildChoices = ProductionAI.getBestShipInfo( EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_INVASION)
    if bestDesign:
        troopsPerBestShip = 2*(  list(bestDesign.parts).count("GT_TROOP_POD") )
    else:
        troopsPerBestShip=5 #may actually not have any troopers available, but this num will do for now

    #sortedTargets=sorted( [  ( pscore-ptroops/2 ,  pID,  pscore,  ptroops) for pID,  pscore,  ptroops in evaluatedPlanets ] ,  reverse=True)

    invasionPool=set(invasionPool)
    for  pID,  pscore,  ptroops in evaluatedPlanets: #
        if not invasionPool: return
        planet=universe.getPlanet(pID)
        if not planet: continue
        sysID = planet.systemID
        foundFleets = []
        podsNeeded= math.ceil( (ptroops+0.05)/2.0)
        foundStats={}
        minStats= {'rating':0, 'troopPods':podsNeeded}
        targetStats={'rating':10,'troopPods':podsNeeded+1}
        theseFleets = FleetUtilsAI.getFleetsForMission(1, targetStats , minStats,   foundStats,  "",  systemsToCheck=[sysID],  systemsChecked=[], fleetPoolSet=invasionPool,   fleetList=foundFleets,  verbose=False)
        if theseFleets == []:
            if not FleetUtilsAI.statsMeetReqs(foundStats,  minStats):
                print "Insufficient invasion troop  allocation for system %d ( %s ) -- requested  %s , found %s"%(sysID,  universe.getSystem(sysID).name,  minStats,  foundStats)
                invasionPool.update( foundFleets )
                continue
            else:
                theseFleets = foundFleets
        aiTarget = AITarget.AITarget(EnumsAI.AITargetType.TARGET_PLANET, pID)
        print "assigning invasion fleets %s to target %s"%(theseFleets,  aiTarget)
        for fleetID in theseFleets:
            fleet=universe.getFleet(fleetID)
            aiFleetMission = foAI.foAIstate.getAIFleetMission(fleetID)
            aiFleetMission.clearAIFleetOrders()
            aiFleetMission.clearAITargets( (aiFleetMission.getAIMissionTypes() + [-1])[0] )
            aiFleetMission.addAITarget(missionType, aiTarget)
Beispiel #11
0
def send_invasion_fleets(invasionFleetIDs, evaluatedPlanets, missionType):
    """sends a list of invasion fleets to a list of planet_value_pairs"""
    universe=fo.getUniverse()
    invasionPool = invasionFleetIDs[:]  #need to make a copy
    bestShip, bestDesign, buildChoices = ProductionAI.getBestShipInfo( EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_INVASION)
    if bestDesign:
        troopsPerBestShip = 2*( list(bestDesign.parts).count("GT_TROOP_POD") )
    else:
        troopsPerBestShip=5 #may actually not have any troopers available, but this num will do for now

    #sortedTargets=sorted( [ ( pscore-ptroops/2 , pID, pscore, ptroops) for pID, pscore, ptroops in evaluatedPlanets ] , reverse=True)

    invasionPool=set(invasionPool)
    for pID, pscore, ptroops in evaluatedPlanets: #
        if not invasionPool: return
        planet=universe.getPlanet(pID)
        if not planet: continue
        sysID = planet.systemID
        foundFleets = []
        podsNeeded= math.ceil( (ptroops+0.05)/2.0)
        foundStats={}
        minStats= {'rating':0, 'troopPods':podsNeeded}
        targetStats={'rating':10,'troopPods':podsNeeded+1}
        theseFleets = FleetUtilsAI.get_fleets_for_mission(1, targetStats , minStats, foundStats, "", systems_to_check=[sysID], systems_checked=[], fleet_pool_set=invasionPool, fleet_list=foundFleets, verbose=False)
        if not theseFleets:
            if not FleetUtilsAI.stats_meet_reqs(foundStats, minStats):
                print "Insufficient invasion troop allocation for system %d ( %s ) -- requested %s , found %s"%(sysID, universe.getSystem(sysID).name, minStats, foundStats)
                invasionPool.update( foundFleets )
                continue
            else:
                theseFleets = foundFleets
        aiTarget = AITarget.AITarget(EnumsAI.TargetType.TARGET_PLANET, pID)
        print "assigning invasion fleets %s to target %s"%(theseFleets, aiTarget)
        for fleetID in theseFleets:
            fleet=universe.getFleet(fleetID)
            aiFleetMission = foAI.foAIstate.get_fleet_mission(fleetID)
            aiFleetMission.clear_fleet_orders()
            aiFleetMission.clear_targets( (aiFleetMission.get_mission_types() + [-1])[0] )
            aiFleetMission.add_target(missionType, aiTarget)
Beispiel #12
0
def _calculate_invasion_priority():
    """Calculates the demand for troop ships by opponent planets."""
    
    global allottedInvasionTargets
    if not foAI.foAIstate.character.may_invade():
        return 0
    
    empire = fo.getEmpire()
    enemies_sighted = foAI.foAIstate.misc.get('enemies_sighted', {})
    multiplier = 1
    num_colonies = len(list(AIstate.popCtrIDs))
    colony_growth_barrier = foAI.foAIstate.character.max_number_colonies()
    if num_colonies > colony_growth_barrier:
        return 0.0
    
    if len(foAI.foAIstate.colonisablePlanetIDs) > 0:
        best_colony_score = max(2, foAI.foAIstate.colonisablePlanetIDs.items()[0][1][0])
    else:
        best_colony_score = 2

    allottedInvasionTargets = 1 + int(fo.currentTurn() / 25)
    total_val = 0
    troops_needed = 0
    for pid, pscore, trp in AIstate.invasionTargets[:allottedInvasionTargets]:
        if pscore > best_colony_score:
            multiplier += 1
            total_val += 2 * pscore
        else:
            total_val += pscore
        troops_needed += trp + 4  # ToDo: This seems like it could be improved by some dynamic calculation of buffer

    if total_val == 0:
        return 0

    production_queue = empire.productionQueue
    queued_troop_capacity = 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) in [ShipRoleType.MILITARY_INVASION,
                                                                  ShipRoleType.BASE_INVASION]:
                design = fo.getShipDesign(element.designID)
                queued_troop_capacity += element.remaining * element.blocksize * design.troopCapacity
    _, best_design, _ = ProductionAI.get_best_ship_info(PriorityType.PRODUCTION_INVASION)
    if best_design:
        troops_per_best_ship = best_design.troopCapacity
    else:
        return 1e-6  # if we can not build troop ships, we don't want to build (non-existing) invasion ships

    # don't count troop bases here as these cannot be redeployed after misplaning
    # troopFleetIDs = FleetUtilsAI.get_empire_fleet_ids_by_role(MissionType.INVASION)\
    #                 + FleetUtilsAI.get_empire_fleet_ids_by_role(MissionType.ORBITAL_INVASION)
    troop_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(MissionType.INVASION)
    total_troop_capacity = sum([FleetUtilsAI.count_troops_in_fleet(fid) for fid in troop_fleet_ids])
    troop_ships_needed = \
        math.ceil((troops_needed - (total_troop_capacity + queued_troop_capacity)) / troops_per_best_ship)

    # invasion_priority = max( 10+ 200*max(0, troop_ships_needed ) , int(0.1* total_val) )
    invasion_priority = multiplier * (30 + 150*max(0, troop_ships_needed))
    if not ColonisationAI.colony_status.get('colonies_under_attack', []):
        if not ColonisationAI.colony_status.get('colonies_under_threat', []):
            invasion_priority *= 2.0
        else:
            invasion_priority *= 1.5
    if not enemies_sighted:
        invasion_priority *= 1.5
        
    if invasion_priority < 0:
        return 0

    return invasion_priority * foAI.foAIstate.character.invasion_priority_scaling()
Beispiel #13
0
def evaluateInvasionPlanet(planetID, missionType, fleetSupplyablePlanetIDs, empire,  secureAIFleetMissions,  verbose=True):
    "return the invasion value (score, troops) of a planet"
    detail = []
    buildingValues = {"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()
    empireID = empire.empireID
    maxJumps=8
    planet = universe.getPlanet(planetID)
    if (planet == None) :  #TODO: exclude planets with stealth higher than empireDetection
        print "invasion AI couldn't access any info for planet id %d"%planetID
        return [0, 0]

    sysPartialVisTurn = dictFromMap(universe.getVisibilityTurnsMap(planet.systemID,  empireID)).get(fo.visibility.partial, -9999)
    planetPartialVisTurn = dictFromMap(universe.getVisibilityTurnsMap(planetID,  empireID)).get(fo.visibility.partial, -9999)

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

    specName=planet.speciesName
    species=fo.getSpecies(specName)
    if not species: #this call iterates over this Empire's available species with which it could colonize after an invasion
        planetEval = ColonisationAI.assignColonisationValues([planetID],  EnumsAI.AIFleetMissionType.FLEET_MISSION_COLONISATION,  [planetID],  None,  empire, detail) #evaluatePlanet is imported from ColonisationAI
        popVal = max( 0.75*planetEval.get(planetID,  [0])[0],   ColonisationAI.evaluatePlanet(planetID,  EnumsAI.AIFleetMissionType.FLEET_MISSION_OUTPOST,  [planetID],  None,  empire, detail)  )
    else:
        popVal = ColonisationAI.evaluatePlanet(planetID,  EnumsAI.AIFleetMissionType.FLEET_MISSION_COLONISATION,  [planetID],  specName,  empire, detail) #evaluatePlanet is imported from ColonisationAI

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

    pSysID = planet.systemID
    capitolID = PlanetUtilsAI.getCapital()
    leastJumpsPath = []
    clear_path = True
    if capitolID:
        homeworld = universe.getPlanet(capitolID)
        if homeworld:
            homeSystemID = homeworld.systemID
            evalSystemID = planet.systemID
            if (homeSystemID != -1) and (evalSystemID != -1):
                leastJumpsPath = list(universe.leastJumpsPath(homeSystemID, evalSystemID, empireID))
                maxJumps =  len(leastJumpsPath)
    system_status = foAI.foAIstate.systemStatus.get(pSysID, {})
    sysFThrt = system_status.get('fleetThreat', 1000 )
    sysMThrt = foAI.foAIstate.systemStatus.get(pSysID, {}).get('monsterThreat', 0 )
    sysPThrt = foAI.foAIstate.systemStatus.get(pSysID, {}).get('planetThreat', 0 )
    sysTotThrt = sysFThrt + sysMThrt + sysPThrt
    max_path_threat = sysFThrt
    mil_ship_rating = ProductionAI.curBestMilShipRating()
    for path_sys_id in leastJumpsPath:
        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)
    maxTroops = planet.currentMeterValue(fo.meterType.maxTroops)

    this_system = universe.getSystem(pSysID)
    secure_targets = [pSysID] + list(this_system.planetIDs)
    system_secured = False
    for mission in secureAIFleetMissions:
        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 != pSysID):
            continue
        for ai_target in mission.getAITargets(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

    pmaxShield = planet.currentMeterValue(fo.meterType.maxShield)
    if verbose:
        print "invasion eval of %s  %d --- maxShields %.1f -- sysFleetThreat %.1f  -- sysMonsterThreat %.1f"%(planet.name,  planetID,  pmaxShield,  sysFThrt,  sysMThrt)
    supplyVal=0
    enemyVal=0
    if planet.owner!=-1 : #value in taking this away from an enemy
        enemyVal= 20* (planet.currentMeterValue(fo.meterType.targetIndustry) +  2*planet.currentMeterValue(fo.meterType.targetResearch))
    if pSysID  in ColonisationAI.annexableSystemIDs: #TODO: extend to rings
        supplyVal =  100
    elif pSysID in ColonisationAI.annexableRing1:
        supplyVal =  200
    elif pSysID in ColonisationAI.annexableRing2:
        supplyVal =  300
    elif pSysID in ColonisationAI.annexableRing2:
        supplyVal =  400
    if ( max_path_threat > 0.5 * mil_ship_rating ):
        if ( max_path_threat < 3 * mil_ship_rating ):
            supplyVal *= 0.5
        else:
            supplyVal *= 0.2
        
    threatFactor = min(1,  0.2*MilitaryAI.totMilRating/(sysTotThrt+0.001))**2  #devalue invasions that would require too much military force
    buildTime=4
    if system_secured:
        plannedTroops = troops
    else:
        plannedTroops = min(troops+maxJumps+buildTime,  maxTroops)
    if ( empire.getTechStatus("SHP_ORG_HULL") != fo.techStatus.complete ):
        troopCost = math.ceil( plannedTroops/6.0) *  ( 40*( 1+foAI.foAIstate.shipCount * AIDependencies.shipUpkeep ) )
    else:
        troopCost = math.ceil( plannedTroops/6.0) *  ( 20*( 1+foAI.foAIstate.shipCount * AIDependencies.shipUpkeep ) )
    planet_score = threatFactor*max(0,  popVal+supplyVal+bldTally+enemyVal-0.8*troopCost)
    if clear_path:
        planet_score *= 1.5
    invscore =  [ planet_score,  plannedTroops ]
    print invscore, "projected Troop Cost:",  troopCost,  ", threatFactor: ", threatFactor,  ", planet detail ",   detail, "popval,  supplyval,  bldval,  enemyval",   popVal,  supplyVal,  bldTally,  enemyVal
    return   invscore
Beispiel #14
0
def get_invasion_fleets():
    invasion_timer.start("gathering initial info")
    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empire_id = fo.empireID()

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

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

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

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

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

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

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

        secure_ai_fleet_missions = foAI.foAIstate.get_fleet_missions_with_any_mission_types(
            [MissionType.SECURE])

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

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

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

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

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

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

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

    # export invasion targeted systems for other AI modules
    AIstate.invasionTargetedSystemIDs = list(all_invasion_targeted_system_ids)
    invasion_timer.stop(section_name="evaluating %d target planets" %
                        (len(evaluated_planet_ids)))
    invasion_timer.stop_print_and_clear()
Beispiel #15
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)
Beispiel #16
0
def _calculate_military_priority():
    """Calculates the demand for military ships by military targeted systems."""
    global unmetThreat

    universe = fo.getUniverse()
    capital_id = PlanetUtilsAI.get_capital()
    if capital_id is None or capital_id == INVALID_ID:
        return 0  # no capitol (not even a capitol-in-the-making), means can't produce any ships

    have_l1_weaps = (tech_is_complete("SHP_WEAPON_1_4") or
                     (tech_is_complete("SHP_WEAPON_1_3") and tech_is_complete("SHP_MIL_ROBO_CONT")) or
                     tech_is_complete("SHP_WEAPON_2_1") or
                     tech_is_complete("SHP_WEAPON_4_1"))
    have_l2_weaps = (tech_is_complete("SHP_WEAPON_2_3") or
                     tech_is_complete("SHP_WEAPON_4_1"))
    enemies_sighted = foAI.foAIstate.misc.get('enemies_sighted', {})

    allotted_invasion_targets = 1 + int(fo.currentTurn()/25)
    target_planet_ids = [pid for pid, pscore, trp in AIstate.invasionTargets[:allotted_invasion_targets]] + [pid for pid, pscore in foAI.foAIstate.colonisablePlanetIDs.items()[:allottedColonyTargets]] + [pid for pid, pscore in foAI.foAIstate.colonisableOutpostIDs.items()[:allottedColonyTargets]]

    my_systems = set(state.get_empire_planets_by_system())
    target_systems = set(PlanetUtilsAI.get_systems(target_planet_ids))

    cur_ship_rating = ProductionAI.cur_best_military_design_rating()
    current_turn = fo.currentTurn()
    ships_needed = 0
    defense_ships_needed = 0
    ships_needed_allocation = []
    for sys_id in my_systems.union(target_systems):
        status = foAI.foAIstate.systemStatus.get(sys_id, {})
        my_rating = status.get('myFleetRating', 0)
        my_defenses = status.get('mydefenses', {}).get('overall', 0)
        base_monster_threat = status.get('monsterThreat', 0)
        # scale monster threat so that in early - mid game big monsters don't over-drive military production
        monster_threat = base_monster_threat
        if current_turn > 200:
            pass
        elif current_turn > 100:
            if base_monster_threat >= 2000:
                monster_threat = 2000 + (current_turn / 100.0 - 1) * (base_monster_threat - 2000)
        elif current_turn > 30:
            if base_monster_threat >= 2000:
                monster_threat = 0
        else:
            if base_monster_threat > 200:
                monster_threat = 0
        if sys_id in my_systems:
            threat_root = status.get('fleetThreat', 0)**0.5 + 0.8*status.get('max_neighbor_threat', 0)**0.5 + 0.2*status.get('neighborThreat', 0)**0.5 + monster_threat**0.5 + status.get('planetThreat', 0)**0.5
        else:
            threat_root = status.get('fleetThreat', 0)**0.5 + monster_threat**0.5 + status.get('planetThreat', 0)**0.5
        ships_needed_here = math.ceil((max(0, (threat_root - (my_rating ** 0.5 + my_defenses ** 0.5))) ** 2) / cur_ship_rating)
        ships_needed += ships_needed_here
        ships_needed_allocation.append((universe.getSystem(sys_id), ships_needed_here))
        if sys_id in my_systems:
            defense_ships_needed += ships_needed_here

    part1 = min(1 * fo.currentTurn(), 40)
    part2 = max(0, int(75 * ships_needed))
    military_priority = part1 + part2
    if not have_l1_weaps:
        military_priority /= 2.0
    elif not (have_l2_weaps and enemies_sighted):
        military_priority /= 1.5
    fmt_string = "Calculating Military Priority:  min(t,40) + max(0,75 * ships_needed) \n\t  Priority: %d  \t ships_needed: %d \t defense_ships_needed: %d \t curShipRating: %.0f \t l1_weaps: %s \t enemies_sighted: %s"
    print fmt_string % (military_priority, ships_needed, defense_ships_needed, cur_ship_rating, have_l1_weaps, enemies_sighted)
    print "Source of milship demand: ", ships_needed_allocation

    military_priority *= foAI.foAIstate.character.military_priority_scaling()
    return max(military_priority, 0)
Beispiel #17
0
def calculateInvasionPriority():
    """calculates the demand for troop ships by opponent planets"""

    global allottedInvasionTargets
    if foAI.foAIstate.aggression <= fo.aggression.turtle:
        return 0

    troopsPerPod = 2
    empire = fo.getEmpire()
    enemies_sighted = foAI.foAIstate.misc.get('enemies_sighted', {})
    multiplier = 1
    num_colonies = len(list(AIstate.popCtrIDs))
    if num_colonies > colonyGrowthBarrier:
        return 0.0

    if len(foAI.foAIstate.colonisablePlanetIDs) > 0:
        bestColonyScore = max(
            2,
            foAI.foAIstate.colonisablePlanetIDs.items()[0][1][0])
    else:
        bestColonyScore = 2

    if foAI.foAIstate.aggression == fo.aggression.beginner and fo.currentTurn(
    ) < 150:
        return 0

    allottedInvasionTargets = 1 + int(fo.currentTurn() / 25)
    totalVal = 0
    troopsNeeded = 0
    for pid, pscore, trp in AIstate.invasionTargets[:allottedInvasionTargets]:
        if pscore > bestColonyScore:
            multiplier += 1
            totalVal += 2 * pscore
        else:
            totalVal += pscore
        troopsNeeded += trp + 4

    if totalVal == 0:
        return 0
    opponentTroopPods = int(troopsNeeded / troopsPerPod)

    productionQueue = empire.productionQueue
    queuedTroopPods = 0
    for queue_index in range(0, len(productionQueue)):
        element = productionQueue[queue_index]
        if element.buildType == EnumsAI.AIEmpireProductionTypes.BT_SHIP:
            if foAI.foAIstate.get_ship_role(element.designID) in [
                    EnumsAI.AIShipRoleType.SHIP_ROLE_MILITARY_INVASION,
                    EnumsAI.AIShipRoleType.SHIP_ROLE_BASE_INVASION
            ]:
                design = fo.getShipDesign(element.designID)
                queuedTroopPods += element.remaining * element.blocksize * list(
                    design.parts).count("GT_TROOP_POD")
    bestShip, bestDesign, buildChoices = ProductionAI.getBestShipInfo(
        EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_INVASION)
    if bestDesign:
        troopsPerBestShip = troopsPerPod * (list(
            bestDesign.parts).count("GT_TROOP_POD"))
    else:
        troopsPerBestShip = troopsPerPod  #may actually not have any troopers available, but this num will do for now

    #don't cound troop bases here since if through misplanning cannot be used where made, cannot be redeployed
    #troopFleetIDs = FleetUtilsAI.get_empire_fleet_ids_by_role(AIFleetMissionType.FLEET_MISSION_INVASION) + FleetUtilsAI.get_empire_fleet_ids_by_role(AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION)
    troopFleetIDs = FleetUtilsAI.get_empire_fleet_ids_by_role(
        EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION)
    numTroopPods = sum([
        FleetUtilsAI.count_parts_fleetwide(fleetID, ["GT_TROOP_POD"])
        for fleetID in troopFleetIDs
    ])
    troopShipsNeeded = math.ceil(
        (opponentTroopPods -
         (numTroopPods + queuedTroopPods)) / troopsPerBestShip)

    #invasionPriority = max( 10+ 200*max(0, troopShipsNeeded ) , int(0.1* totalVal) )
    invasionPriority = multiplier * (30 + 150 * max(0, troopShipsNeeded))
    if not ColonisationAI.colony_status.get('colonies_under_attack', []):
        if not ColonisationAI.colony_status.get('colonies_under_threat', []):
            invasionPriority *= 2.0
        else:
            invasionPriority *= 1.5
    if not enemies_sighted:
        invasionPriority *= 1.5

    if invasionPriority < 0:
        return 0
    if foAI.foAIstate.aggression == fo.aggression.beginner:
        return 0.5 * invasionPriority
    else:
        return invasionPriority
Beispiel #18
0
def calculateMilitaryPriority():
    """calculates the demand for military ships by military targeted systems"""
    global unmetThreat

    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empireID = empire.empireID
    capitalID = PlanetUtilsAI.get_capital()
    if capitalID is not None and capitalID != -1:
        homeworld = universe.getPlanet(capitalID)
    else:
        return 0  # no capitol (not even a capitol-in-the-making), means can't produce any ships

    have_l1_weaps = (
        tech_is_complete("SHP_WEAPON_1_4")
        or (tech_is_complete("SHP_WEAPON_1_3") and tech_is_complete("SHP_MIL_ROBO_CONT"))
        or tech_is_complete("SHP_WEAPON_2_1")
        or tech_is_complete("SHP_WEAPON_4_1")
    )
    have_l2_weaps = tech_is_complete("SHP_WEAPON_2_3") or tech_is_complete("SHP_WEAPON_4_1")
    enemies_sighted = foAI.foAIstate.misc.get("enemies_sighted", {})

    allottedInvasionTargets = 1 + int(fo.currentTurn() / 25)
    targetPlanetIDs = (
        [pid for pid, pscore, trp in AIstate.invasionTargets[:allottedInvasionTargets]]
        + [pid for pid, pscore in foAI.foAIstate.colonisablePlanetIDs.items()[:allottedColonyTargets]]
        + [pid for pid, pscore in foAI.foAIstate.colonisableOutpostIDs.items()[:allottedColonyTargets]]
    )

    mySystems = set(AIstate.popCtrSystemIDs).union(AIstate.outpostSystemIDs)
    targetSystems = set(PlanetUtilsAI.get_systems(targetPlanetIDs))

    curShipRating = ProductionAI.cur_best_military_design_rating()
    cSRR = curShipRating ** 0.5

    defense_ships_needed = 0
    currentTurn = fo.currentTurn()
    ships_needed = 0
    defense_ships_needed = 0
    ships_needed_allocation = []
    for sysID in mySystems.union(targetSystems):
        status = foAI.foAIstate.systemStatus.get(sysID, {})
        myRating = status.get("myFleetRating", 0)
        my_defenses = status.get("mydefenses", {}).get("overall", 0)
        baseMonsterThreat = status.get("monsterThreat", 0)
        # scale monster threat so that in early - mid game big monsters don't over-drive military production
        monsterThreat = baseMonsterThreat
        if currentTurn > 200:
            pass
        elif currentTurn > 100:
            if baseMonsterThreat >= 2000:
                monsterThreat = 2000 + (currentTurn / 100.0 - 1) * (baseMonsterThreat - 2000)
        elif currentTurn > 30:
            if baseMonsterThreat >= 2000:
                monsterThreat = 0
        else:
            if baseMonsterThreat > 200:
                monsterThreat = 0
        if sysID in mySystems:
            threatRoot = (
                status.get("fleetThreat", 0) ** 0.5
                + 0.8 * status.get("max_neighbor_threat", 0) ** 0.5
                + 0.2 * status.get("neighborThreat", 0) ** 0.5
                + monsterThreat ** 0.5
                + status.get("planetThreat", 0) ** 0.5
            )
        else:
            threatRoot = (
                status.get("fleetThreat", 0) ** 0.5 + monsterThreat ** 0.5 + status.get("planetThreat", 0) ** 0.5
            )
        ships_needed_here = math.ceil(
            (max(0, (threatRoot - (myRating ** 0.5 + my_defenses ** 0.5))) ** 2) / curShipRating
        )
        ships_needed += ships_needed_here
        ships_needed_allocation.append((sysID, ships_needed_here))
        if sysID in mySystems:
            defense_ships_needed += ships_needed_here

    part1 = min(1 * fo.currentTurn(), 40)
    part2 = max(0, int(75 * ships_needed))
    militaryPriority = part1 + part2
    if not have_l1_weaps:
        militaryPriority /= 2.0
    elif not (have_l2_weaps and enemies_sighted):
        militaryPriority /= 1.5
    fmt_string = "Calculating Military Priority:  min(t,40) + max(0,75 * ships_needed) \n\t  Priority: %d  \t ships_needed: %d \t defense_ships_needed: %d \t curShipRating: %.0f \t l1_weaps: %s \t enemies_sighted: %s"
    print fmt_string % (
        militaryPriority,
        ships_needed,
        defense_ships_needed,
        curShipRating,
        have_l1_weaps,
        enemies_sighted,
    )
    print "Source of milship demand: ", ships_needed_allocation

    if foAI.foAIstate.aggression < fo.aggression.typical:
        militaryPriority *= (1.0 + foAI.foAIstate.aggression) / (1.0 + fo.aggression.typical)
    return max(militaryPriority, 0)
Beispiel #19
0
def get_invasion_fleets():
    invasion_timer.start("gathering initial info")
    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empire_id = empire.empireID

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    empire_owned_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs)

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

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

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

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

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

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

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

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

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

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

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

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

    # export invasion targeted systems for other AI modules
    AIstate.invasionTargetedSystemIDs = list(all_invasion_targeted_system_ids)
    invasion_timer.stop(section_name="evaluating %d target planets" % (len(evaluated_planet_ids)))
    invasion_timer.end()
Beispiel #21
0
    def 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)
Beispiel #22
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 = ProductionAI.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
Beispiel #23
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()
Beispiel #24
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]
                if orders and lastOrder.getAIFleetOrderType() == EnumsAI.AIFleetOrderType.ORDER_COLONISE:
                    universe=fo.getUniverse()
                    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
                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])
                else:
                    #TODO: evaluate releasing a smaller portion or none of the ships 
                    FleetUtilsAI.splitFleet(self.getAITargetID() ) #at least first stage of current task is done; release extra ships for potential other deployments
Beispiel #25
0
def get_invasion_fleets():
    invasion_timer.start("gathering initial info")
    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empire_id = empire.empireID

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    # export invasion targeted systems for other AI modules
    AIstate.invasionTargetedSystemIDs = list(all_invasion_targeted_system_ids)
    invasion_timer.stop(section_name="evaluating %d target planets" % (len(evaluated_planet_ids)))
    invasion_timer.end()
Beispiel #26
0
def calculateMilitaryPriority():
    """calculates the demand for military ships by military targeted systems"""
    global unmetThreat

    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empireID = empire.empireID
    capitalID = PlanetUtilsAI.get_capital()
    if capitalID is not None and capitalID != -1:
        homeworld = universe.getPlanet(capitalID)
    else:
        return 0  # no capitol (not even a capitol-in-the-making), means can't produce any ships

    have_l1_weaps = (tech_is_complete("SHP_WEAPON_1_4")
                     or (tech_is_complete("SHP_WEAPON_1_3")
                         and tech_is_complete("SHP_MIL_ROBO_CONT"))
                     or tech_is_complete("SHP_WEAPON_2_1")
                     or tech_is_complete("SHP_WEAPON_4_1"))
    have_l2_weaps = (tech_is_complete("SHP_WEAPON_2_3")
                     or tech_is_complete("SHP_WEAPON_4_1"))
    enemies_sighted = foAI.foAIstate.misc.get('enemies_sighted', {})

    allottedInvasionTargets = 1 + int(fo.currentTurn() / 25)
    targetPlanetIDs = [
        pid for pid, pscore, trp in
        AIstate.invasionTargets[:allottedInvasionTargets]
    ] + [
        pid for pid, pscore in foAI.foAIstate.colonisablePlanetIDs.items()
        [:allottedColonyTargets]
    ] + [
        pid for pid, pscore in foAI.foAIstate.colonisableOutpostIDs.items()
        [:allottedColonyTargets]
    ]

    mySystems = set(AIstate.popCtrSystemIDs).union(AIstate.outpostSystemIDs)
    targetSystems = set(PlanetUtilsAI.get_systems(targetPlanetIDs))

    curShipRating = ProductionAI.cur_best_mil_ship_rating()
    cSRR = curShipRating**0.5

    defense_ships_needed = 0
    currentTurn = fo.currentTurn()
    ships_needed = 0
    defense_ships_needed = 0
    ships_needed_allocation = []
    for sysID in mySystems.union(targetSystems):
        status = foAI.foAIstate.systemStatus.get(sysID, {})
        myRating = status.get('myFleetRating', 0)
        my_defenses = status.get('mydefenses', {}).get('overall', 0)
        baseMonsterThreat = status.get('monsterThreat', 0)
        #scale monster threat so that in early - mid game big monsters don't over-drive military production
        monsterThreat = baseMonsterThreat
        if currentTurn > 200:
            pass
        elif currentTurn > 100:
            if baseMonsterThreat >= 2000:
                monsterThreat = 2000 + (currentTurn / 100.0 -
                                        1) * (baseMonsterThreat - 2000)
        elif currentTurn > 30:
            if baseMonsterThreat >= 2000:
                monsterThreat = 0
        else:
            if baseMonsterThreat > 200:
                monsterThreat = 0
        if sysID in mySystems:
            threatRoot = status.get('fleetThreat', 0)**0.5 + 0.8 * status.get(
                'max_neighbor_threat', 0)**0.5 + 0.2 * status.get(
                    'neighborThreat',
                    0)**0.5 + monsterThreat**0.5 + status.get(
                        'planetThreat', 0)**0.5
        else:
            threatRoot = status.get('fleetThreat',
                                    0)**0.5 + monsterThreat**0.5 + status.get(
                                        'planetThreat', 0)**0.5
        ships_needed_here = math.ceil(
            (max(0, (threatRoot -
                     (myRating**0.5 + my_defenses**0.5)))**2) / curShipRating)
        ships_needed += ships_needed_here
        ships_needed_allocation.append((sysID, ships_needed_here))
        if sysID in mySystems:
            defense_ships_needed += ships_needed_here

    scale = (75 + ProductionAI.curBestMilShipCost()) / 2.0
    #militaryPriority = int( 40 + max(0, 75*unmetThreat / curShipRating) )
    part1 = min(1 * fo.currentTurn(), 40)
    part2 = max(0, int(75 * ships_needed))
    militaryPriority = part1 + part2
    #militaryPriority = min(1*fo.currentTurn(), 40) + max(0, int(scale*ships_needed))
    if not have_l1_weaps:
        militaryPriority /= 2.0
    elif not (have_l2_weaps and enemies_sighted):
        militaryPriority /= 1.5
    #print "Calculating Military Priority:  40 + 75 * unmetThreat/curShipRating \n\t  Priority: %d    \t unmetThreat  %.0f        curShipRating: %.0f"%(militaryPriority,  unmetThreat,  curShipRating)
    fmt_string = "Calculating Military Priority:  min(t,40) + %d * ships_needed \n\t  Priority: %d  \t ships_needed: %d \t defense_ships_needed: %d \t curShipRating: %.0f \t l1_weaps: %s \t enemies_sighted: %s"
    print fmt_string % (scale, militaryPriority, ships_needed,
                        defense_ships_needed, curShipRating, have_l1_weaps,
                        enemies_sighted)
    print "Source of milship demand: ", ships_needed_allocation

    if foAI.foAIstate.aggression < fo.aggression.typical:
        militaryPriority *= (1.0 + foAI.foAIstate.aggression) / (
            1.0 + fo.aggression.typical)
    return max(militaryPriority, 0)
Beispiel #27
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]
Beispiel #28
0
def calculateInvasionPriority():
    """calculates the demand for troop ships by opponent planets"""
    
    global allottedInvasionTargets
    if foAI.foAIstate.aggression <= fo.aggression.turtle:
        return 0
    
    empire = fo.getEmpire()
    enemies_sighted = foAI.foAIstate.misc.get('enemies_sighted', {})
    multiplier = 1
    num_colonies = len(list(AIstate.popCtrIDs))
    if num_colonies > colony_growth_barrier:
        return 0.0
    
    if len(foAI.foAIstate.colonisablePlanetIDs) > 0:
        best_colony_score = max(2, foAI.foAIstate.colonisablePlanetIDs.items()[0][1][0])
    else:
        best_colony_score = 2

    if foAI.foAIstate.aggression == fo.aggression.beginner and fo.currentTurn() < 150:
        return 0

    allottedInvasionTargets = 1 + int(fo.currentTurn()/25)
    total_val = 0
    troops_needed = 0
    for pid, pscore, trp in AIstate.invasionTargets[:allottedInvasionTargets]:
        if pscore > best_colony_score:
            multiplier += 1
            total_val += 2 * pscore
        else:
            total_val += pscore
        troops_needed += trp+4  # ToDo: This seems like it could be improved by some dynamic calculation of buffer

    if total_val == 0:
        return 0

    production_queue = empire.productionQueue
    queued_troop_capacity = 0
    for queue_index in range(0, len(production_queue)):
        element = production_queue[queue_index]
        if element.buildType == EnumsAI.AIEmpireProductionTypes.BT_SHIP:
            if foAI.foAIstate.get_ship_role(element.designID) in [EnumsAI.AIShipRoleType.SHIP_ROLE_MILITARY_INVASION,
                                                                  EnumsAI.AIShipRoleType.SHIP_ROLE_BASE_INVASION]:
                design = fo.getShipDesign(element.designID)
                queued_troop_capacity += element.remaining * element.blocksize * design.troopCapacity
    _, best_design, _ = ProductionAI.getBestShipInfo(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_INVASION)
    if best_design:
        troops_per_best_ship = best_design.troopCapacity
    else:
        return 1e-6  # if we can not build troop ships, we don't want to build (non-existing) invasion ships

    # don't count troop bases hereas these cannot be redeployed after misplaning
    # troopFleetIDs = FleetUtilsAI.get_empire_fleet_ids_by_role(AIFleetMissionType.FLEET_MISSION_INVASION)\
    #                 + FleetUtilsAI.get_empire_fleet_ids_by_role(AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION)
    troop_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION)
    total_troop_capacity = sum([FleetUtilsAI.count_troops_in_fleet(fid) for fid in troop_fleet_ids])
    troop_ships_needed = \
        math.ceil((troops_needed - (total_troop_capacity+queued_troop_capacity)) / troops_per_best_ship)

    # invasion_priority = max( 10+ 200*max(0, troop_ships_needed ) , int(0.1* total_val) )
    invasion_priority = multiplier * (30 + 150*max(0, troop_ships_needed))
    if not ColonisationAI.colony_status.get('colonies_under_attack', []):
        if not ColonisationAI.colony_status.get('colonies_under_threat', []):
            invasion_priority *= 2.0
        else:
            invasion_priority *= 1.5
    if not enemies_sighted:
        invasion_priority *= 1.5
        
    if invasion_priority < 0:
        return 0
    if foAI.foAIstate.aggression == fo.aggression.beginner:
        return 0.5 * invasion_priority
    else:
        return invasion_priority
Beispiel #29
0
def get_invasion_fleets():
    invasion_timer.start("gathering initial info")

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

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

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

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

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

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

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

    empire_owned_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(universe.planetIDs)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    # export invasion targeted systems for other AI modules
    AIstate.invasionTargetedSystemIDs = list(all_invasion_targeted_system_ids)
    invasion_timer.stop(section_name="evaluating %d target planets" % (len(evaluatedPlanetIDs)))
    invasion_timer.end()
Beispiel #31
0
def _calculate_military_priority():
    """Calculates the demand for military ships by military targeted systems."""
    global unmetThreat

    universe = fo.getUniverse()
    capital_id = PlanetUtilsAI.get_capital()
    if capital_id is None or capital_id == INVALID_ID:
        return 0  # no capitol (not even a capitol-in-the-making), means can't produce any ships
        
    have_l1_weaps = (tech_is_complete("SHP_WEAPON_1_4") or
                     (tech_is_complete("SHP_WEAPON_1_3") and tech_is_complete("SHP_MIL_ROBO_CONT")) or
                     tech_is_complete("SHP_WEAPON_2_1") or
                     tech_is_complete("SHP_WEAPON_4_1"))
    have_l2_weaps = (tech_is_complete("SHP_WEAPON_2_3") or
                     tech_is_complete("SHP_WEAPON_4_1"))
    enemies_sighted = foAI.foAIstate.misc.get('enemies_sighted', {})
        
    allotted_invasion_targets = 1 + int(fo.currentTurn()/25)
    target_planet_ids = [pid for pid, pscore, trp in AIstate.invasionTargets[:allotted_invasion_targets]] + [pid for pid, pscore in foAI.foAIstate.colonisablePlanetIDs.items()[:allottedColonyTargets]] + [pid for pid, pscore in foAI.foAIstate.colonisableOutpostIDs.items()[:allottedColonyTargets]]

    my_systems = set(AIstate.popCtrSystemIDs).union(AIstate.outpostSystemIDs)
    target_systems = set(PlanetUtilsAI.get_systems(target_planet_ids))

    cur_ship_rating = ProductionAI.cur_best_military_design_rating()
    current_turn = fo.currentTurn()
    ships_needed = 0
    defense_ships_needed = 0
    ships_needed_allocation = []
    for sys_id in my_systems.union(target_systems):
        status = foAI.foAIstate.systemStatus.get(sys_id, {})
        my_rating = status.get('myFleetRating', 0)
        my_defenses = status.get('mydefenses', {}).get('overall', 0)
        base_monster_threat = status.get('monsterThreat', 0)
        # scale monster threat so that in early - mid game big monsters don't over-drive military production
        monster_threat = base_monster_threat
        if current_turn > 200:
            pass
        elif current_turn > 100:
            if base_monster_threat >= 2000:
                monster_threat = 2000 + (current_turn / 100.0 - 1) * (base_monster_threat - 2000)
        elif current_turn > 30:
            if base_monster_threat >= 2000:
                monster_threat = 0
        else:
            if base_monster_threat > 200:
                monster_threat = 0
        if sys_id in my_systems:
            threat_root = status.get('fleetThreat', 0)**0.5 + 0.8*status.get('max_neighbor_threat', 0)**0.5 + 0.2*status.get('neighborThreat', 0)**0.5 + monster_threat**0.5 + status.get('planetThreat', 0)**0.5
        else:
            threat_root = status.get('fleetThreat', 0)**0.5 + monster_threat**0.5 + status.get('planetThreat', 0)**0.5
        ships_needed_here = math.ceil((max(0, (threat_root - (my_rating ** 0.5 + my_defenses ** 0.5))) ** 2) / cur_ship_rating)
        ships_needed += ships_needed_here
        ships_needed_allocation.append((universe.getSystem(sys_id), ships_needed_here))
        if sys_id in my_systems:
            defense_ships_needed += ships_needed_here

    part1 = min(1 * fo.currentTurn(), 40)
    part2 = max(0, int(75 * ships_needed))
    military_priority = part1 + part2
    if not have_l1_weaps:
        military_priority /= 2.0
    elif not (have_l2_weaps and enemies_sighted):
        military_priority /= 1.5
    fmt_string = "Calculating Military Priority:  min(t,40) + max(0,75 * ships_needed) \n\t  Priority: %d  \t ships_needed: %d \t defense_ships_needed: %d \t curShipRating: %.0f \t l1_weaps: %s \t enemies_sighted: %s"
    print fmt_string % (military_priority, ships_needed, defense_ships_needed, cur_ship_rating, have_l1_weaps, enemies_sighted)
    print "Source of milship demand: ", ships_needed_allocation
    
    military_priority *= foAI.foAIstate.character.military_priority_scaling()
    return max(military_priority, 0)
Beispiel #32
0
def calculateInvasionPriority():
    """calculates the demand for troop ships by opponent planets"""
    
    global allottedInvasionTargets
    if foAI.foAIstate.aggression <= fo.aggression.turtle:
        return 0
    
    troopsPerPod=2
    empire=fo.getEmpire()
    enemies_sighted = foAI.foAIstate.misc.get('enemies_sighted',{})
    multiplier = 1
    num_colonies = len( list(AIstate.popCtrIDs) )
    if num_colonies > colonyGrowthBarrier:
        return 0.0
    
    if len(foAI.foAIstate.colonisablePlanetIDs) > 0:
        bestColonyScore = max( 2, foAI.foAIstate.colonisablePlanetIDs[0][1][0] )
    else:
        bestColonyScore = 2

    if foAI.foAIstate.aggression==fo.aggression.beginner and fo.currentTurn()<150:
        return 0

    allottedInvasionTargets = 1+ int(fo.currentTurn()/25)
    totalVal = 0
    troopsNeeded = 0
    for pid, pscore, trp in AIstate.invasionTargets[:allottedInvasionTargets]:
        if pscore > bestColonyScore:
            multiplier += 1
            totalVal += 2 * pscore
        else:
            totalVal += pscore
        troopsNeeded += trp+4

    if totalVal == 0:
        return 0
    opponentTroopPods = int(troopsNeeded/troopsPerPod)

    productionQueue = empire.productionQueue
    queuedTroopPods=0
    for queue_index in range(0, len(productionQueue)):
        element=productionQueue[queue_index]
        if element.buildType == EnumsAI.AIEmpireProductionTypes.BT_SHIP:
            if foAI.foAIstate.get_ship_role(element.designID) in [ EnumsAI.AIShipRoleType.SHIP_ROLE_MILITARY_INVASION, EnumsAI.AIShipRoleType.SHIP_ROLE_BASE_INVASION] :
                design = fo.getShipDesign(element.designID)
                queuedTroopPods += element.remaining*element.blocksize * list(design.parts).count("GT_TROOP_POD")
    bestShip, bestDesign, buildChoices = ProductionAI.getBestShipInfo( EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_INVASION)
    if bestDesign:
        troopsPerBestShip = troopsPerPod*( list(bestDesign.parts).count("GT_TROOP_POD") )
    else:
        troopsPerBestShip=troopsPerPod #may actually not have any troopers available, but this num will do for now

    #don't cound troop bases here since if through misplanning cannot be used where made, cannot be redeployed
    #troopFleetIDs = FleetUtilsAI.get_empire_fleet_ids_by_role(AIFleetMissionType.FLEET_MISSION_INVASION) + FleetUtilsAI.get_empire_fleet_ids_by_role(AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION)
    troopFleetIDs = FleetUtilsAI.get_empire_fleet_ids_by_role(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION)
    numTroopPods = sum([ FleetUtilsAI.count_parts_fleetwide(fleetID, ["GT_TROOP_POD"]) for fleetID in troopFleetIDs])
    troopShipsNeeded = math.ceil((opponentTroopPods - (numTroopPods+ queuedTroopPods ))/troopsPerBestShip)

    #invasionPriority = max( 10+ 200*max(0, troopShipsNeeded ) , int(0.1* totalVal) )
    invasionPriority = multiplier * (30+ 150*max(0, troopShipsNeeded ))
    if not ColonisationAI.colony_status.get('colonies_under_attack', []):
        if not ColonisationAI.colony_status.get('colonies_under_threat', []):
            invasionPriority *= 2.0
        else:
            invasionPriority *= 1.5
    if not enemies_sighted:
        invasionPriority *= 1.5
        
    if invasionPriority < 0:
        return 0
    if foAI.foAIstate.aggression==fo.aggression.beginner:
        return 0.5* invasionPriority
    else:
        return invasionPriority
Beispiel #33
0
def _calculate_invasion_priority():
    """Calculates the demand for troop ships by opponent planets."""

    if not foAI.foAIstate.character.may_invade():
        return 0

    empire = fo.getEmpire()
    enemies_sighted = foAI.foAIstate.misc.get('enemies_sighted', {})
    multiplier = 1
    colony_growth_barrier = foAI.foAIstate.character.max_number_colonies()
    if state.get_number_of_colonies() > colony_growth_barrier:
        return 0.0

    if len(foAI.foAIstate.colonisablePlanetIDs) > 0:
        best_colony_score = max(2, foAI.foAIstate.colonisablePlanetIDs.items()[0][1][0])
    else:
        best_colony_score = 2

    total_val = 0
    troops_needed = 0
    for pid, pscore, trp in AIstate.invasionTargets[:allotted_invasion_targets()]:
        if pscore > best_colony_score:
            multiplier += 1
            total_val += 2 * pscore
        else:
            total_val += pscore
        troops_needed += trp + 4  # ToDo: This seems like it could be improved by some dynamic calculation of buffer

    if total_val == 0:
        return 0

    production_queue = empire.productionQueue
    queued_troop_capacity = 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) in [ShipRoleType.MILITARY_INVASION,
                                                                  ShipRoleType.BASE_INVASION]:
                design = fo.getShipDesign(element.designID)
                queued_troop_capacity += element.remaining * element.blocksize * design.troopCapacity
    _, best_design, _ = ProductionAI.get_best_ship_info(PriorityType.PRODUCTION_INVASION)
    if best_design:
        troops_per_best_ship = best_design.troopCapacity
    else:
        return 1e-6  # if we can not build troop ships, we don't want to build (non-existing) invasion ships

    # don't count troop bases here as these cannot be redeployed after misplaning
    # troopFleetIDs = FleetUtilsAI.get_empire_fleet_ids_by_role(MissionType.INVASION)\
    #                 + FleetUtilsAI.get_empire_fleet_ids_by_role(MissionType.ORBITAL_INVASION)
    troop_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(MissionType.INVASION)
    total_troop_capacity = sum([FleetUtilsAI.count_troops_in_fleet(fid) for fid in troop_fleet_ids])
    troop_ships_needed = \
        math.ceil((troops_needed - (total_troop_capacity + queued_troop_capacity)) / troops_per_best_ship)

    # invasion_priority = max( 10+ 200*max(0, troop_ships_needed ) , int(0.1* total_val) )
    invasion_priority = multiplier * (30 + 150*max(0, troop_ships_needed))
    if not ColonisationAI.colony_status.get('colonies_under_attack', []):
        if not ColonisationAI.colony_status.get('colonies_under_threat', []):
            invasion_priority *= 2.0
        else:
            invasion_priority *= 1.5
    if not enemies_sighted:
        invasion_priority *= 1.5

    if invasion_priority < 0:
        return 0

    return invasion_priority * foAI.foAIstate.character.invasion_priority_scaling()
Beispiel #34
0
def evaluateInvasionPlanet(planetID, missionType, fleetSupplyablePlanetIDs, empire):
    "return the invasion value of a planet"
    detail = []
    buildingValues = {"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":                             150, 
                                            "BLD_SHIPYARD_AST_REF":                     500, 
                                            "BLD_SHIPYARD_ENRG_COMP":           500, 
                                            "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()
    empireID = empire.empireID
    maxJumps=8
    planet = universe.getPlanet(planetID)
    if (planet == None) :  #TODO: exclude planets with stealth higher than empireDetection
        print "invasion AI couldn't get current info on planet %d"%planetID
        return 0, 0

    specName=planet.speciesName
    species=fo.getSpecies(specName)
    if not species:#TODO:  probably stealth makes planet inacccesible & should abort
        return 0, 0
    else:
        popVal = ColonisationAI.evaluatePlanet(planetID,  EnumsAI.AIFleetMissionType.FLEET_MISSION_COLONISATION,  [planetID],  species,  empire, detail) #evaluatePlanet is imported from ColonisationAI

    bldTally=0
    for bldType in [universe.getObject(bldg).buildingTypeName for bldg in planet.buildingIDs]:
        bval = buildingValues.get(bldType,  50)
        bldTally += bval
        detail.append("%s: %d"%(bldType,  bval))
        
        capitolID = PlanetUtilsAI.getCapital()
        if capitolID:
            homeworld = universe.getPlanet(capitolID)
            if homeworld:
                homeSystemID = homeworld.systemID
                evalSystemID = planet.systemID
                leastJumpsPath = len(universe.leastJumpsPath(homeSystemID, evalSystemID, empireID))
            maxJumps =  leastJumpsPath
        
    troops = planet.currentMeterValue(fo.meterType.troops)
    maxTroops = planet.currentMeterValue(fo.meterType.maxTroops)
    
    popTSize = planet.currentMeterValue(fo.meterType.targetPopulation)#TODO: adjust for empire tech
    planetSpecials = list(planet.specials)
    pSysID = planet.systemID#TODO: check star value
    
    pmaxShield = planet.currentMeterValue(fo.meterType.maxShield)
    sysFThrt = foAI.foAIstate.systemStatus.get(pSysID, {}).get('fleetThreat', 1000 )
    sysMThrt = foAI.foAIstate.systemStatus.get(pSysID, {}).get('monsterThreat', 0 )
    print "invasion eval of %s  %d --- maxShields %.1f -- sysFleetThreat %.1f  -- sysMonsterThreat %.1f"%(planet.name,  planetID,  pmaxShield,  sysFThrt,  sysMThrt)
    supplyVal=0
    enemyVal=0
    if planet.owner!=-1 : #value in taking this away from an enemy
        enemyVal= 20* (planet.currentMeterValue(fo.meterType.targetIndustry) +  2*planet.currentMeterValue(fo.meterType.targetResearch))
    if planetID  in fleetSupplyablePlanetIDs: #TODO: extend to rings
        supplyVal =  100
        if planet.owner== -1:
        #if  (pmaxShield <10):
            if ( sysFThrt < 0.5*ProductionAI.curBestMilShipRating() ):
               if ( sysMThrt < 3*ProductionAI.curBestMilShipRating()):
                    supplyVal = 50
               else:
                    supplyVal = 20
            else:
                supplyVal *= int( min(1, ProductionAI.curBestMilShipRating() /  sysFThrt )  )
    buildTime=4
    plannedTroops = min(troops+maxJumps+buildTime,  maxTroops)
    if ( empire.getTechStatus("SHP_ORG_HULL") != fo.techStatus.complete ):
        troopCost = math.ceil( plannedTroops/6.0) *  ( 40*( 1+foAI.foAIstate.shipCount * AIDependencies.shipUpkeep ) )
    else:
        troopCost = math.ceil( plannedTroops/6.0) *  ( 20*( 1+foAI.foAIstate.shipCount * AIDependencies.shipUpkeep ) )
    invscore =  max(0,  popVal+supplyVal+bldTally+enemyVal-0.8*troopCost),  plannedTroops
    print invscore, "projected Troop Cost:",  troopCost,  "planet detail ",   detail,  popVal,  supplyVal,  bldTally,  enemyVal
    return   invscore
Beispiel #35
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]
Beispiel #36
0
def get_invasion_fleets():
    invasion_timer.start("gathering initial info")
    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empire_id = fo.empireID()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    # export invasion targeted systems for other AI modules
    AIstate.invasionTargetedSystemIDs = list(all_invasion_targeted_system_ids)
    invasion_timer.stop(section_name="evaluating %d target planets" % (len(evaluated_planet_ids)))
    invasion_timer.stop_print_and_clear()
Beispiel #37
0
def getColonyFleets():
    global empireSpecies,  empireColonizers,  empireSpeciesSystems,  annexableSystemIDs,  annexableRing1,  annexableRing2,  annexableRing3
    global  annexablePlanetIDs,  curBestMilShipRating
    
    curBestMilShipRating = ProductionAI.curBestMilShipRating()
    
    "get colony fleets"

    allColonyFleetIDs = FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_COLONISATION)
    AIstate.colonyFleetIDs[:] = FleetUtilsAI.extractFleetIDsWithoutMissionTypes(allColonyFleetIDs)

    # get suppliable systems and planets
    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empireID = empire.empireID
    capitalID = PlanetUtilsAI.getCapital()
    #capitalID = empire.capitalID
    homeworld=None
    if capitalID:
        homeworld = universe.getPlanet(capitalID)
    if homeworld:
        speciesName = homeworld.speciesName
        homeworldName=homeworld.name
        homeSystemID = homeworld.systemID
    else:
        speciesName = ""
        homeworldName=" no remaining homeworld "
        homeSystemID = -1
    if not speciesName:
        speciesName = foAI.foAIstate.origSpeciesName
    species = fo.getSpecies(speciesName)
    if not species:
        print "**************************************************************************************"
        print "**************************************************************************************"
        print "Problem determining species for colonization planning: capitalID: %s,  homeworld %s  and species name %s"%(capitalID,  homeworldName,  speciesName)
    else:
        print "Plannning colonization for species name %s"%species.name

    fleetSupplyableSystemIDs = empire.fleetSupplyableSystemIDs
    fleetSupplyablePlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(fleetSupplyableSystemIDs)
    print ""
    print "    fleetSupplyableSystemIDs: " + str(list(fleetSupplyableSystemIDs))
    print "    fleetSupplyablePlanetIDs: " + str(fleetSupplyablePlanetIDs)
    print ""

    print "-------\nEmpire Obstructed Starlanes:"
    print  list(empire.obstructedStarlanes())


    annexableSystemIDs.clear()
    annexableRing1.clear()
    annexableRing2.clear()
    annexableRing3.clear()
    annexablePlanetIDs.clear()
    for sysID in empire.fleetSupplyableSystemIDs:
        annexableSystemIDs.add(sysID)
        for nID in  universe.getImmediateNeighbors(sysID,  empireID):
            annexableSystemIDs.add(nID)
            annexableRing1.add(nID)
    annexableRing1.difference_update(empire.fleetSupplyableSystemIDs)
    print "First Ring of annexable systems: ",  PlanetUtilsAI.sysNameIDs(annexableRing1)
    if empire.getTechStatus("CON_ORBITAL_CON") == fo.techStatus.complete:
        for sysID in list(annexableRing1):
            for nID in  universe.getImmediateNeighbors(sysID,  empireID):
                annexableRing2.add(nID)
        annexableRing2.difference_update(annexableSystemIDs)
        print "Second Ring of annexable systems: ",  PlanetUtilsAI.sysNameIDs(annexableRing2)
        annexableSystemIDs.update(annexableRing2)
        if foAI.foAIstate.aggression > fo.aggression.cautious:
            for sysID in list(annexableRing2):
                for nID in  universe.getImmediateNeighbors(sysID,  empireID):
                    annexableRing3.add(nID)
            annexableRing3.difference_update(annexableSystemIDs)
            print "Third Ring of annexable systems: ",  PlanetUtilsAI.sysNameIDs(annexableRing3)
            annexableSystemIDs.update(annexableRing3)
    annexablePlanetIDs.update( PlanetUtilsAI.getPlanetsInSystemsIDs(annexableSystemIDs))

    # get outpost and colonization planets
    
    exploredSystemIDs = foAI.foAIstate.getExplorableSystems(AIExplorableSystemType.EXPLORABLE_SYSTEM_EXPLORED)
    unExSysIDs = list(foAI.foAIstate.getExplorableSystems(AIExplorableSystemType.EXPLORABLE_SYSTEM_UNEXPLORED))
    unExSystems = map(universe.getSystem,  unExSysIDs)
    print "Unexplored Systems: %s " % [(sysID,  (sys and sys.name) or "name unknown") for sysID,  sys in zip( unExSysIDs,  unExSystems)]
    print "Explored SystemIDs: " + str(list(exploredSystemIDs))

    exploredPlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(exploredSystemIDs)
    print "Explored PlanetIDs: " + str(exploredPlanetIDs)
    print ""
    
    #visibleSystemIDs = foAI.foAIstate.visInteriorSystemIDs.keys() + foAI.foAIstate. visBorderSystemIDs.keys()
    #visiblePlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(visibleSystemIDs)
    #print "VisiblePlanets: %s "%[ (pid,  (universe.getPlanet(pid) and  universe.getPlanet(pid).name) or "unknown") for pid in  visiblePlanetIDs]
    #print ""
    
    #accessibleSystemIDs = [sysID for sysID in visibleSystemIDs if  universe.systemsConnected(sysID, homeSystemID, empireID) ]
    #acessiblePlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(accessibleSystemIDs)

    empireOwnedPlanetIDs = PlanetUtilsAI.getOwnedPlanetsByEmpire(universe.planetIDs, empireID)
    print "Empire Owned PlanetIDs:            " + str(empireOwnedPlanetIDs)
    
    #allOwnedPlanetIDs = PlanetUtilsAI.getAllOwnedPlanetIDs(exploredPlanetIDs) #working with Explored systems not all 'visible' because might not have a path to the latter
    allOwnedPlanetIDs = PlanetUtilsAI.getAllOwnedPlanetIDs(annexablePlanetIDs) #
    print "All annexable Owned or Populated PlanetIDs: " + str(set(allOwnedPlanetIDs)-set(empireOwnedPlanetIDs))

    #unOwnedPlanetIDs = list(set(exploredPlanetIDs) -set(allOwnedPlanetIDs))
    unOwnedPlanetIDs = list(set(annexablePlanetIDs) -set(allOwnedPlanetIDs))
    print "UnOwned annexable PlanetIDs:             " + str(PlanetUtilsAI.planetNameIDs(unOwnedPlanetIDs))
    
    empirePopCtrs = set( PlanetUtilsAI.getPopulatedPlanetIDs(  empireOwnedPlanetIDs) )
    empireOutpostIDs=set(empireOwnedPlanetIDs) - empirePopCtrs
    AIstate.popCtrIDs[:]=list(empirePopCtrs)
    AIstate.popCtrSystemIDs[:]=list(set(PlanetUtilsAI.getSystems(empirePopCtrs)))
    AIstate.outpostIDs[:]=list(empireOutpostIDs)
    AIstate.outpostSystemIDs[:]=list(set(PlanetUtilsAI.getSystems(empireOutpostIDs)))
    AIstate.colonizedSystems.clear()
    for pid in empireOwnedPlanetIDs:
        planet=universe.getPlanet(pid)
        if planet:
            AIstate.colonizedSystems.setdefault(planet.systemID,  []).append(pid)   # track these to plan Solar Generators and Singularity Generators
    AIstate.empireStars.clear()
    for sysID in AIstate.colonizedSystems:
        system = universe.getSystem(sysID)
        if system:
            AIstate.empireStars.setdefault(system.starType, []).append(sysID)
    
    
    oldPopCtrs=[]
    for specN in empireSpecies:
        oldPopCtrs.extend(empireSpecies[specN])
    oldEmpSpec = empireSpecies
    empireSpecies.clear()
    oldEmpCol=empireColonizers
    empireColonizers.clear()
    if empire.getTechStatus(TechsListsAI.exobotTechName) == fo.techStatus.complete:
        empireColonizers["SP_EXOBOT"]=[]# get it into colonizer list even if no colony yet
    empireSpeciesSystems.clear()
    
    for pID in empirePopCtrs:
        planet=universe.getPlanet(pID)
        if not planet:
            print "Error empire has apparently lost sight of former colony at planet %d but doesn't realize it"%pID
            continue
        pSpecName=planet.speciesName
        if pID not in oldPopCtrs:
            if  (AIFocusType.FOCUS_MINING in planet.availableFoci): 
                fo.issueChangeFocusOrder(pID, AIFocusType.FOCUS_MINING)
                print "Changing focus of newly settled planet ID %d : %s  to mining "%(pID,  planet.name )
        empireSpecies[pSpecName] = empireSpecies.get(pSpecName,  [])+[pID]
    print "\n"+"Empire species roster:"
    for specName in empireSpecies:
        thisSpec=fo.getSpecies(specName)
        if thisSpec:
            shipyards=[]
            for pID in empireSpecies[specName]:
                planet=universe.getPlanet(pID)
                if thisSpec.canColonize:
                    if "BLD_SHIPYARD_BASE" in [universe.getObject(bldg).buildingTypeName for bldg in planet.buildingIDs]:
                        shipyards.append(pID)
                empireSpeciesSystems.setdefault(planet.systemID,  {}).setdefault('pids', []).append(pID)
            if thisSpec.canColonize:
                empireColonizers[specName]=shipyards
            print "%s on planets %s; can%s colonize from %d shipyards; has tags %s"%(specName,  empireSpecies[specName],  ["not", ""][thisSpec.canColonize], len(shipyards),  list(thisSpec.tags))
        else:
            print "Unable to retrieve info for Species named %s"%specName
    print""
    if empireSpecies!=oldEmpSpec:
        print "Old empire species: %s  ; new empire species: %s"%(oldEmpSpec,  empireSpecies)
    if empireColonizers!=oldEmpCol:
        print "Old empire colonizers: %s  ; new empire colonizers: %s"%(oldEmpCol,  empireColonizers)
    
    print 

    # export colony targeted systems for other AI modules
    colonyTargetedPlanetIDs = getColonyTargetedPlanetIDs(universe.planetIDs, AIFleetMissionType.FLEET_MISSION_COLONISATION, empireID)
    allColonyTargetedSystemIDs = PlanetUtilsAI.getSystems(colonyTargetedPlanetIDs)
    AIstate.colonyTargetedSystemIDs = allColonyTargetedSystemIDs
    print ""
    print "Colony Targeted SystemIDs:         " + str(AIstate.colonyTargetedSystemIDs)
    print "Colony Targeted PlanetIDs:         " + str(colonyTargetedPlanetIDs)

    colonyFleetIDs = FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_COLONISATION)
    if not colonyFleetIDs:
        print "Available Colony Fleets:             0"
    else:
        print "Colony FleetIDs:                   " + str(FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_COLONISATION))

    numColonyFleets = len(FleetUtilsAI.extractFleetIDsWithoutMissionTypes(colonyFleetIDs))
    print "Colony Fleets Without Missions:      " + str(numColonyFleets)

    outpostTargetedPlanetIDs = getOutpostTargetedPlanetIDs(universe.planetIDs, AIFleetMissionType.FLEET_MISSION_OUTPOST, empireID)
    allOutpostTargetedSystemIDs = PlanetUtilsAI.getSystems(outpostTargetedPlanetIDs)

    # export outpost targeted systems for other AI modules
    AIstate.outpostTargetedSystemIDs = allOutpostTargetedSystemIDs
    print ""
    print "Outpost Targeted SystemIDs:        " + str(AIstate.outpostTargetedSystemIDs)
    print "Outpost Targeted PlanetIDs:        " + str(outpostTargetedPlanetIDs)

    outpostFleetIDs = FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_OUTPOST)
    if not outpostFleetIDs:
        print "Available Outpost Fleets:            0"
    else:
        print "Outpost FleetIDs:                  " + str(FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_OUTPOST))

    numOutpostFleets = len(FleetUtilsAI.extractFleetIDsWithoutMissionTypes(outpostFleetIDs))
    print "Outpost Fleets Without Missions:     " + str(numOutpostFleets)

    evaluatedColonyPlanetIDs = list(set(unOwnedPlanetIDs).union(empireOutpostIDs) - set(colonyTargetedPlanetIDs) )
    # print "Evaluated Colony PlanetIDs:        " + str(evaluatedColonyPlanetIDs)

    evaluatedOutpostPlanetIDs = list(set(unOwnedPlanetIDs) - set(outpostTargetedPlanetIDs)- set(colonyTargetedPlanetIDs))
    # print "Evaluated Outpost PlanetIDs:       " + str(evaluatedOutpostPlanetIDs)

    evaluatedColonyPlanets = assignColonisationValues(evaluatedColonyPlanetIDs, AIFleetMissionType.FLEET_MISSION_COLONISATION, fleetSupplyablePlanetIDs, species, empire)
    removeLowValuePlanets(evaluatedColonyPlanets)

    sortedPlanets = evaluatedColonyPlanets.items()
    sortedPlanets.sort(lambda x, y: cmp(x[1], y[1]), reverse=True)

    print ""
    print "Settleable Colony Planets (score,species) | ID | Name | Specials:"
    for ID, score in sortedPlanets:
        print "   %15s | %5s  | %s  | %s "%(score,  ID,  universe.getPlanet(ID).name ,  list(universe.getPlanet(ID).specials)) 
    print ""

    # export planets for other AI modules
    foAI.foAIstate.colonisablePlanetIDs = sortedPlanets#TODO: should include species designation corresponding to rating

    # get outpost fleets
    allOutpostFleetIDs = FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_OUTPOST)
    AIstate.outpostFleetIDs = FleetUtilsAI.extractFleetIDsWithoutMissionTypes(allOutpostFleetIDs)

    evaluatedOutpostPlanets = assignColonisationValues(evaluatedOutpostPlanetIDs, AIFleetMissionType.FLEET_MISSION_OUTPOST, fleetSupplyablePlanetIDs, species, empire)
    removeLowValuePlanets(evaluatedOutpostPlanets) #bad! lol, was preventing all mining outposts

    sortedOutposts = evaluatedOutpostPlanets.items()
    sortedOutposts.sort(lambda x, y: cmp(x[1], y[1]), reverse=True)

    print "Settleable Outpost PlanetIDs:"
    for ID, score in sortedOutposts:
        print "   %5s | %5s  | %s  | %s "%(score,  ID,  universe.getPlanet(ID).name ,  list(universe.getPlanet(ID).specials)) 
    print ""

    # export outposts for other AI modules
    foAI.foAIstate.colonisableOutpostIDs = sortedOutposts
Beispiel #38
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]
Beispiel #39
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:
        print "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_id=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)
    system_status = foAI.foAIstate.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 = 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)
    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 == 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)
    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:
        print(' - 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)
    return [planet_score, planned_troops]
Beispiel #40
0
def getInvasionFleets():
    "get invasion fleets"

    times=[]
    tasks = []
    times.append( time() )
    tasks.append("init")

    allInvasionFleetIDs = FleetUtilsAI.getEmpireFleetIDsByRole(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION)
    AIstate.invasionFleetIDs = FleetUtilsAI.extractFleetIDsWithoutMissionTypes(allInvasionFleetIDs)

    # get supplyable planets
    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empireID = empire.empireID
    capitalID = PlanetUtilsAI.getCapital()
    #capitalID = empire.capitalID
    homeworld=None
    if capitalID:
        homeworld = universe.getPlanet(capitalID)
    if homeworld:
        homeSystemID = homeworld.systemID
    else:
        speciesName = ""
        homeworldName=" no remaining homeworld "
        homeSystemID = -1

    fleetSupplyableSystemIDs = empire.fleetSupplyableSystemIDs
    fleetSupplyablePlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(fleetSupplyableSystemIDs)

    primeInvadableSystemIDs = set(ColonisationAI.annexableSystemIDs)
    primeInvadablePlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(primeInvadableSystemIDs)

    # get competitor planets
    exploredSystemIDs = empire.exploredSystemIDs
    exploredPlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(exploredSystemIDs)

    visibleSystemIDs = foAI.foAIstate.visInteriorSystemIDs.keys() + foAI.foAIstate. visBorderSystemIDs.keys()
    visiblePlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(visibleSystemIDs)
    if homeSystemID != -1:
        accessibleSystemIDs = [sysID for sysID in visibleSystemIDs if  (sysID != -1 ) and universe.systemsConnected(sysID, homeSystemID, empireID) ]
    else:
        print "Invasion Warning: this empire has no identifiable homeworld,  will therefor treat all visible planets as accessible."
        accessibleSystemIDs = visibleSystemIDs #TODO: check if any troop ships still owned, use their system as home system
    acessiblePlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(accessibleSystemIDs)
    print "Accessible Systems: " + str(PlanetUtilsAI.sysNameIDs(accessibleSystemIDs))
    print

    #allOwnedPlanetIDs = PlanetUtilsAI.getAllOwnedPlanetIDs(exploredPlanetIDs)
    allOwnedPlanetIDs = PlanetUtilsAI.getAllOwnedPlanetIDs(acessiblePlanetIDs)#need these for unpopulated outposts
    # print "All Owned and Populated PlanetIDs: " + str(allOwnedPlanetIDs)

    allPopulatedPlanets=PlanetUtilsAI.getPopulatedPlanetIDs(acessiblePlanetIDs)#need this for natives
    print "All Visible and accessible Populated PlanetIDs (including this empire's): " + str(PlanetUtilsAI.planetNameIDs(allPopulatedPlanets))
    print
    print "Prime Invadable Target Systems: " + str(PlanetUtilsAI.sysNameIDs(primeInvadableSystemIDs))
    print

    empireOwnedPlanetIDs = PlanetUtilsAI.getOwnedPlanetsByEmpire(universe.planetIDs, empireID)
    # print "Empire Owned PlanetIDs:            " + str(empireOwnedPlanetIDs)

    invadablePlanetIDs = set(primeInvadablePlanetIDs).intersection(set(allOwnedPlanetIDs).union(allPopulatedPlanets) - set(empireOwnedPlanetIDs))
    print "Prime Invadable PlanetIDs:              " + str(PlanetUtilsAI.planetNameIDs(invadablePlanetIDs))

    print ""
    print "Current Invasion Targeted SystemIDs:       " + str(PlanetUtilsAI.sysNameIDs(AIstate.invasionTargetedSystemIDs))
    invasionTargetedPlanetIDs = getInvasionTargetedPlanetIDs(universe.planetIDs, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, empireID)
    invasionTargetedPlanetIDs.extend( getInvasionTargetedPlanetIDs(universe.planetIDs, EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION, empireID))
    allInvasionTargetedSystemIDs = set(PlanetUtilsAI.getSystems(invasionTargetedPlanetIDs))

    print "Current Invasion Targeted PlanetIDs:       " + str(PlanetUtilsAI.planetNameIDs(invasionTargetedPlanetIDs))

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

    numInvasionFleets = len(FleetUtilsAI.extractFleetIDsWithoutMissionTypes(invasionFleetIDs))
    print "Invasion Fleets Without Missions:    " + str(numInvasionFleets)
    times.append( time() )
    tasks.append( "gathering initial info" )
    
    availablePP = {}
    for el in  empire.planetsWithAvailablePP:  #keys are sets of ints; data is doubles
        avail_pp = el.data()
        for pid in el.key():
            availablePP[pid] = avail_pp
    if len (invadablePlanetIDs) > 0:
        #print "Evaluating Troop Bases (SpaceInvaders) for %s"%(invadablePlanetIDs)
        pass
    for pid in invadablePlanetIDs: #TODO: reorganize
        planet = universe.getPlanet(pid)
        if not planet: 
            continue
        sysID = planet.systemID
        sysPartialVisTurn = dictFromMap(universe.getVisibilityTurnsMap(planet.systemID,  empireID)).get(fo.visibility.partial, -9999)
        planetPartialVisTurn = dictFromMap(universe.getVisibilityTurnsMap(pid,  empireID)).get(fo.visibility.partial, -9999)
        if (planetPartialVisTurn < sysPartialVisTurn):
            #print "rejecting %s due to stealth"%planet.name
            continue
        for pid2 in ColonisationAI.empireSpeciesSystems.get(sysID,  {}).get('pids', []):
            if availablePP.get(pid2,  0) < 2: #TODO: improve troop base PP sufficiency determination
                #print "rejecting %s due to insufficient avail PP"%planet.name
                break
            planet2 = universe.getPlanet(pid2)
            if not planet2: 
                continue
            if (pid not in  foAI.foAIstate.qualifyingTroopBaseTargets) and (planet2.speciesName  in ColonisationAI.empireShipBuilders):
                #print "Adding %s to Troop Bases (SpaceInvaders) potential target list, from %s"%(planet.name, planet2.name) 
                foAI.foAIstate.qualifyingTroopBaseTargets.setdefault(pid,  [pid2,  -1])
                break

    for pid in list(foAI.foAIstate.qualifyingTroopBaseTargets):
        planet = universe.getPlanet(pid)
        if planet and planet.owner == empireID:
            del foAI.foAIstate.qualifyingTroopBaseTargets[pid]

    reserved_troop_base_targets = []
    secureAIFleetMissions = foAI.foAIstate.getAIFleetMissionsWithAnyMissionTypes([EnumsAI.AIFleetMissionType.FLEET_MISSION_SECURE])
    #print "considering possible troop bases at %s" % (foAI.foAIstate.qualifyingTroopBaseTargets.keys())
    for pid in (set(foAI.foAIstate.qualifyingTroopBaseTargets.keys()) - set(invasionTargetedPlanetIDs)): #TODO: consider overriding standard invasion mission
        planet = universe.getPlanet(pid)
        if  foAI.foAIstate.qualifyingTroopBaseTargets[pid][1] != -1: 
            reserved_troop_base_targets.append(pid)
            if planet:
                allInvasionTargetedSystemIDs.add( planet.systemID )
            continue  #already building for here
        loc = foAI.foAIstate.qualifyingTroopBaseTargets[pid][0]
        this_score,  p_troops = evaluateInvasionPlanet(pid, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, fleetSupplyablePlanetIDs, empire,  secureAIFleetMissions,  False)
        if  (planet.currentMeterValue(fo.meterType.shield)) > 0:
            continue
        bestShip,  colDesign,  buildChoices = ProductionAI.getBestShipInfo(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_ORBITAL_INVASION,  loc)
        if not bestShip:
            #print "Error: no troop base can be built at ",  PlanetUtilsAI.planetNameIDs([loc])
            continue
        #print "selecting  ",  PlanetUtilsAI.planetNameIDs([loc]),  " to build Orbital troop bases"
        n_bases = math.ceil((p_troops+1) / 2)#TODO: reconsider this +1 safety factor
        retval  = fo.issueEnqueueShipProductionOrder(bestShip, loc)
        print "Enqueueing %d Troop Bases at %s for %s"%( n_bases,  PlanetUtilsAI.planetNameIDs([loc]),  PlanetUtilsAI.planetNameIDs([pid]))
        if retval !=0:
            allInvasionTargetedSystemIDs.add( planet.systemID )
            reserved_troop_base_targets.append(pid)
            foAI.foAIstate.qualifyingTroopBaseTargets[pid][1] = loc
            fo.issueChangeProductionQuantityOrder(empire.productionQueue.size -1,  1,  int(n_bases))
            res=fo.issueRequeueProductionOrder(empire.productionQueue.size -1,  0) 
    times.append( time() )
    tasks.append( "planning troop base production" )

    #TODO: check if any invasionTargetedPlanetIDs need more troops assigned
    evaluatedPlanetIDs = list(set(invadablePlanetIDs) - set(invasionTargetedPlanetIDs) - set(reserved_troop_base_targets)  ) 
    print "Evaluating potential invasions, PlanetIDs:               " + str(evaluatedPlanetIDs)

    evaluatedPlanets = assignInvasionValues(evaluatedPlanetIDs, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, fleetSupplyablePlanetIDs, empire)

    sortedPlanets = [(pid,  pscore,  ptroops) for (pid,  (pscore, ptroops)) in evaluatedPlanets.items() ]
    sortedPlanets.sort(lambda x, y: cmp(x[1], y[1]), reverse=True)
    sortedPlanets = [(pid,  pscore%10000,  ptroops) for (pid,  pscore, ptroops) in sortedPlanets ]
    times.append( time() )
    tasks.append( "evaluating %d target planets"%(len(evaluatedPlanetIDs)) )

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

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

    # export invasion targeted systems for other AI modules
    AIstate.invasionTargetedSystemIDs = list(allInvasionTargetedSystemIDs)
    times.append( time() )
    tasks.append( "total processing" )
    for t_index in range(1, len(times)-1):
        print "getInvasionFleets(): %40s took %d msec"%(tasks[t_index],  int(1000*(times[t_index]-times[t_index-1])))
    print "getInvasionFleets(): %40s took %d msec"%(tasks[-1],  int(1000*(times[-1]-times[0])))
Beispiel #41
0
    def getFleetRole(self, fleetID,  forceNew=False):
        "returns fleet role by ID"

        if (not forceNew) and fleetID in self.__fleetRoleByID and self.__fleetRoleByID[fleetID]!=AIFleetMissionType.FLEET_MISSION_INVALID :
            return self.__fleetRoleByID[fleetID]
        else:
            role=FleetUtilsAI.assessFleetRole(fleetID)
            self.__fleetRoleByID[fleetID] = role
            makeAggressive=False
            if role in [AIFleetMissionType.FLEET_MISSION_COLONISATION,  AIFleetMissionType.FLEET_MISSION_OUTPOST,
                                AIFleetMissionType.FLEET_MISSION_ORBITAL_OUTPOST]:
                pass
            if role in [AIFleetMissionType.FLEET_MISSION_EXPLORATION]:
                thisRating=self.getRating(fleetID)
                if float(thisRating.get('overall', 0))/thisRating.get('nships', 1) >= 0.5 * ProductionAI.curBestMilShipRating():
                    makeAggressive=True
            else:
                makeAggressive=True
            fo.issueAggressionOrder(fleetID,  makeAggressive)
            return role
Beispiel #42
0
def evaluatePlanet(planetID, missionType, fleetSupplyablePlanetIDs, species, empire):
    "returns the colonisation value of a planet"
    # TODO: in planet evaluation consider specials and distance
    valMod = 0
    universe = fo.getUniverse()
    empireResearchList = [element.tech for element in empire.researchQueue]
    planet = universe.getPlanet(planetID)
    if (planet == None): return 0
    system = universe.getSystem(planet.systemID)
    tagList=[]
    starBonus=0
    if species:
        tagList = [tag for tag in species.tags]
    if system:
        if (empire.getTechStatus("PRO_SOL_ORB_GEN") == fo.techStatus.complete) or (  "PRO_SOL_ORB_GEN"  in empireResearchList[:8])  :    
            if system.starType in [fo.starType.blue, fo.starType.white]:
                if len (AIstate.empireStars.get(fo.starType.blue,  [])+AIstate.empireStars.get(fo.starType.white,  []))==0:
                    starBonus +=40
                else:
                    starBonus +=5 #still has extra value as an alternate location for solar generators
            if system.starType in [fo.starType.yellow, fo.starType.orange]:
                if len (     AIstate.empireStars.get(fo.starType.blue,  [])+AIstate.empireStars.get(fo.starType.white,  [])+
                                    AIstate.empireStars.get(fo.starType.yellow,  [])+AIstate.empireStars.get(fo.starType.orange,  []))==0:
                    starBonus +=10
                else:
                    starBonus +=2 #still has extra value as an alternate location for solar generators
        if (empire.getTechStatus("PRO_SINGULAR_GEN") == fo.techStatus.complete) or (  "PRO_SINGULAR_GEN"  in empireResearchList[:8])  :    
            if system.starType in [fo.starType.blackHole]:
                if len (AIstate.empireStars.get(fo.starType.blackHole,  []))==0:
                    starBonus +=80 #pretty rare planets, good for generator
                else:
                    starBonus +=20 #still has extra value as an alternate location for generators & for bnlocking enemies generators
        if (empire.getTechStatus("PRO_NEUTRONIUM_EXTRACTION") == fo.techStatus.complete) or (  "PRO_NEUTRONIUM_EXTRACTION"  in empireResearchList[:8])  :    
            if system.starType in [fo.starType.neutron]:
                if len (AIstate.empireStars.get(fo.starType.neutron,  []))==0:
                    starBonus +=40 #pretty rare planets, good for armor
                else:
                    starBonus +=5 #still has extra value as an alternate location for generators & for bnlocking enemies generators
    retval = starBonus
    
    planetSpecials = list(planet.specials)
    if   (missionType == AIFleetMissionType.FLEET_MISSION_OUTPOST ):
        for special in planetSpecials:
            if "_NEST_" in special:
                retval+=10 # get an outpost on the nest quick
        if  ( ( planet.size  ==  fo.planetSize.asteroids ) and  (empire.getTechStatus("PRO_MICROGRAV_MAN") == fo.techStatus.complete )): 
                retval+=10*len( empireSpeciesSystems.get(planet.systemID , []))   # asteroid mining is good return #TODO: check that no preexisting asteroid outpost in system
        for special in [ "MINERALS_SPECIAL",  "CRYSTALS_SPECIAL",  "METALOIDS_SPECIAL"] :
            if special in planetSpecials:
                retval += 30 #expects we can make exobots soonish or will have other colonizers & want to claim the planet
        if  ( ( planet.size  ==  fo.planetSize.gasGiant ) and  ( (empire.getTechStatus("PRO_ORBITAL_GEN") == fo.techStatus.complete ) or (  "PRO_ORBITAL_GEN"  in empireResearchList[:10]) )): 
                retval += 45*len( empireSpeciesSystems.get(planet.systemID , []))   # gias giant generators great, fast return
        if foAI.foAIstate.systemStatus.get(planet.systemID,  {}).get('fleetThreat', 0) > 0:
            retval = retval / 2.0
        return int(retval)
    else: #colonization mission
        asteroidBonus=0
        gasGiantBonus=0
        if   (planet.size==fo.planetSize.gasGiant) and not (species and species.name  ==  "SP_SUPER_TEST"): 
            return 0   
        elif ( planet.size  ==  fo.planetSize.asteroids ):
            if  (species and species.name  in [  "SP_EXOBOT", "SP_SUPER_TEST"  ]):
                for special in [ "MINERALS_SPECIAL",  "CRYSTALS_SPECIAL",  "METALOIDS_SPECIAL"] : #even though as of time of writing only crystals can be in asteroids it seems
                    if special in planetSpecials:
                        retval+=60
                    else:
                        retval+=20
                thrtRatio = foAI.foAIstate.systemStatus.get(planet.systemID,  {}).get('fleetThreat', 0) / float(ProductionAI.curBestMilShipRating())
                if thrtRatio > 4:
                    retval = 2* retval / thrtRatio
                elif thrtRatio >= 2:
                    retval = 0.6* retval
                elif thrtRatio > 0:
                    retval = 0.8* retval
                return int(retval)
            return 0
        if system:
            for pid  in [id for id in system.planetIDs if id != planetID]:
                p2 = universe.getPlanet(pid)
                if p2:
                    if p2.size== fo.planetSize.asteroids :
                        asteroidBonus = 5
                    if p2.size== fo.planetSize.gasGiant :
                        gasGiantBonus += 10
        planetEnv  = environs[ str(species.getPlanetEnvironment(planet.type)) ]
        popSizeMod=0
        popSizeMod += popSizeModMap["env"][planetEnv]
        if empire.getTechStatus("GRO_SUBTER_HAB") == fo.techStatus.complete:    
            if "TECTONIC_INSTABILITY_SPECIAL" not in planetSpecials:
                popSizeMod += popSizeModMap["subHab"][planetEnv]
        if empire.getTechStatus("GRO_SYMBIOTIC_BIO") == fo.techStatus.complete:
            popSizeMod += popSizeModMap["symBio"][planetEnv]
        if empire.getTechStatus("GRO_XENO_GENETICS") == fo.techStatus.complete:
            popSizeMod += popSizeModMap["xenoGen"][planetEnv]
        if empire.getTechStatus("GRO_XENO_HYBRID") == fo.techStatus.complete:
            popSizeMod += popSizeModMap["xenoHyb"][planetEnv]
        if empire.getTechStatus("GRO_CYBORG") == fo.techStatus.complete:
            popSizeMod += popSizeModMap["cyborg"][planetEnv]

        for special in [ "SLOW_ROTATION_SPECIAL",  "SOLID_CORE_SPECIAL"] :
            if special in planetSpecials:
                popSizeMod -= 1

        #have to use these namelists since species tags don't seem available to AI currently
        #for special, namelist in [ ("PROBIOTIC_SPECIAL",  ["SP_HUMAN",  "SP_SCYLIOR",  "SP_GYISACHE",  "SP_HHHOH",  "SP_EAXAW"]),
        #                                                   ("FRUIT_SPECIAL",  ["SP_HUMAN",  "SP_SCYLIOR",  "SP_GYISACHE",  "SP_HHHOH",  "SP_EAXAW",  "SP_TRITH"]),
        #                                                   ("SPICE_SPECIAL",  ["SP_HUMAN",  "SP_SCYLIOR",  "SP_GYISACHE",  "SP_HHHOH",  "SP_EAXAW"]),
        #                                                   ("MONOPOLE_SPECIAL",  ["SP_CRAY"]),
        #                                                   ("SUPERCONDUCTOR_SPECIAL",  ["SP_CRAY"]),
        #                                                   ("POSITRONIUM_SPECIAL",  ["SP_CRAY"]),
        #                                                   ("MINERALS_SPECIAL",  ["SP_GEORGE",  "SP_EGASSEM"]),
        #                                                   ("METALOIDS_SPECIAL",  ["SP_GEORGE",  "SP_EGASSEM"]),
        #                                             ]:
        for special, tag in [ ("PROBIOTIC_SPECIAL",  "ORGANIC"),
                                                           ("FRUIT_SPECIAL",  "ORGANIC"),
                                                           ("SPICE_SPECIAL",  "ORGANIC"),
                                                           ("MONOPOLE_SPECIAL",  "ROBOTIC"),
                                                           ("SUPERCONDUCTOR_SPECIAL",  "ROBOTIC"),
                                                           ("POSITRONIUM_SPECIAL",  "ROBOTIC"),
                                                           ("MINERALS_SPECIAL",  "LITHIC"),
                                                           ("METALOIDS_SPECIAL",  "LITHIC"),
                                                     ]:
            if special in planetSpecials:
                valMod += 5  # extra bonus due to potential applicability to other planets, or to industry
                if  tag in tagList:
                    popSizeMod += 1
                #    print "planet %s had special %s that triggers pop mod for species %s"%(planet.name,  special,  species.name)
                #else:
                #    print "planet %s had special %s without pop mod for species %s"%(planet.name,  special,  species.name)
            
        if "GAIA_SPECIAL" in planet.specials:
            popSizeMod += 3

        popSize = planet.size * popSizeMod
        if empire.getTechStatus("CON_NDIM_STRUC") == fo.techStatus.complete:
            popSize += popSizeModMap["ndim"][planetEnv]
        if empire.getTechStatus("CON_ORBITAL_HAB") == fo.techStatus.complete:
            popSize += popSizeModMap["orbit"][planetEnv]

        if "DIM_RIFT_MASTER_SPECIAL" in planet.specials:
            popSize -= 4


        # give preference to closest worlds
        empireID = empire.empireID
        capitalID = PlanetUtilsAI.getCapital()
        homeworld = universe.getPlanet(capitalID)
        if homeworld:
            homeSystemID = homeworld.systemID
            evalSystemID = planet.systemID
            leastJumpsPath = len(universe.leastJumpsPath(homeSystemID, evalSystemID, empireID))
            distanceFactor = 1.001 / (leastJumpsPath + 1)
        else:
            distanceFactor = 0
        
        if foAI.foAIstate.systemStatus.get(planet.systemID,  {}).get('fleetThreat', 0) > 0:
            threatFactor = 0.7
        else:
            threatFactor = 1.0
    
        if popSize<1:
            return 0
        if (planetID in fleetSupplyablePlanetIDs):
            return (retval+ popSize + distanceFactor + valMod + gasGiantBonus + asteroidBonus)*threatFactor
            #return getPlanetHospitality(planetID, species) * planet.size + distanceFactor
        else:
            return  (retval+popSize + distanceFactor  + valMod)*threatFactor