예제 #1
0
    def getRequiredSystemAITargets(self):
        "returns all system AITargets required to visit in this object"

        # TODO: add parameter turn

        result = []
        if AITargetType.TARGET_SYSTEM == self.getAITargetType():
            result.append(self)

        elif AITargetType.TARGET_PLANET == self.getAITargetType():
            universe = fo.getUniverse()
            planet = universe.getPlanet(self.getTargetID())
            aiTarget = AITarget(AITargetType.TARGET_SYSTEM, planet.systemID)

            result.append(aiTarget)

        elif AITargetType.TARGET_FLEET == self.getAITargetType():
            # Fleet systemID is where is fleet going.
            # If fleet is going nowhere, then it is location of fleet
            universe = fo.getUniverse()
            fleet = universe.getFleet(self.getTargetID())
            systemID = fleet.nextSystemID
            if (systemID == -1):
                systemID = fleet.systemID
            aiTarget = AITarget(AITargetType.TARGET_SYSTEM, systemID)

            result.append(aiTarget)

        return result
예제 #2
0
def dump_universe():
    """Dump the universe but not more than once per turn."""
    cur_turn = fo.currentTurn()

    if (not hasattr(dump_universe, "last_dump") or
            dump_universe.last_dump < cur_turn):
        dump_universe.last_dump = cur_turn
        fo.getUniverse().dump()  # goes to debug logger
예제 #3
0
def avail_mil_needing_repair(mil_fleet_ids, split_ships=False, on_mission=False, repair_limit=0.70):
    """Returns tuple of lists: (ids_needing_repair, ids_not)."""
    fleet_buckets = [[], []]
    universe = fo.getUniverse()
    cutoff = [repair_limit, 0.25][on_mission]
    aistate = get_aistate()
    for fleet_id in mil_fleet_ids:
        fleet = universe.getFleet(fleet_id)
        ship_buckets = [[], []]
        ships_cur_health = [0, 0]
        ships_max_health = [0, 0]
        for ship_id in fleet.shipIDs:
            this_ship = universe.getShip(ship_id)
            cur_struc = this_ship.initialMeterValue(fo.meterType.structure)
            max_struc = this_ship.initialMeterValue(fo.meterType.maxStructure)
            ship_ok = cur_struc >= cutoff * max_struc
            ship_buckets[ship_ok].append(ship_id)
            ships_cur_health[ship_ok] += cur_struc
            ships_max_health[ship_ok] += max_struc
        this_sys_id = fleet.systemID if fleet.nextSystemID == INVALID_ID else fleet.nextSystemID
        fleet_ok = (sum(ships_cur_health) >= cutoff * sum(ships_max_health))
        local_status = aistate.systemStatus.get(this_sys_id, {})
        my_local_rating = combine_ratings(local_status.get('mydefenses', {}).get('overall', 0), local_status.get('myFleetRating', 0))
        my_local_rating_vs_planets = local_status.get('myFleetRatingVsPlanets', 0)
        combat_trigger = bool(local_status.get('fleetThreat', 0) or local_status.get('monsterThreat', 0))
        if not combat_trigger and local_status.get('planetThreat', 0):
            universe = fo.getUniverse()
            system = universe.getSystem(this_sys_id)
            for planet_id in system.planetIDs:
                planet = universe.getPlanet(planet_id)
                if planet.ownedBy(fo.empireID()):  # TODO: also exclude at-peace planets
                    continue
                if planet.unowned and not EspionageAI.colony_detectable_by_empire(planet_id, empire=fo.empireID()):
                    continue
                if sum([planet.currentMeterValue(meter_type) for meter_type in
                        [fo.meterType.defense, fo.meterType.shield, fo.meterType.construction]]):
                    combat_trigger = True
                    break
        needed_here = combat_trigger and local_status.get('totalThreat', 0) > 0  # TODO: assess if remaining other forces are sufficient
        safely_needed = needed_here and my_local_rating > local_status.get('totalThreat', 0) and my_local_rating_vs_planets > local_status.get('planetThreat', 0)  # TODO: improve both assessment prongs
        if not fleet_ok:
            if safely_needed:
                print "Fleet %d at %s needs repair but deemed safely needed to remain for defense" % (fleet_id, universe.getSystem(fleet.systemID))
            else:
                if needed_here:
                    print "Fleet %d at %s needed present for combat, but is damaged and deemed unsafe to remain." % (fleet_id, universe.getSystem(fleet.systemID))
                    print "\t my_local_rating: %.1f ; threat: %.1f" % (my_local_rating, local_status.get('totalThreat', 0))
                print "Selecting fleet %d at %s for repair" % (fleet_id, universe.getSystem(fleet.systemID))
        fleet_buckets[fleet_ok or bool(safely_needed)].append(fleet_id)
    return fleet_buckets
예제 #4
0
def startNewGame(aggression=fo.aggression.aggressive):  # pylint: disable=invalid-name
    """Called by client when a new game is started (but not when a game is loaded).
    Should clear any pre-existing state and set up whatever is needed for AI to generate orders."""
    empire = fo.getEmpire()
    if empire.eliminated:
        print "This empire has been eliminated. Ignoring new game start message."
        return

    turn_timer.start("Server Processing")
    print "New game started, AI Aggression level %d" % aggression

    # initialize AIstate
    global foAIstate
    foAIstate = AIstate.AIstate(aggression=aggression)
    foAIstate.session_start_cleanup()
    print "Initialized foAIstate class"
    planet_id = PlanetUtilsAI.get_capital()
    universe = fo.getUniverse()
    if planet_id is not None and planet_id != -1:
        planet = universe.getPlanet(planet_id)
        new_name = " ".join([random.choice(_capitals.get(aggression, []) or [" "]).strip(), planet.name])
        print "Capitol City Names are: ", _capitals
        print "This Capitol New name is ", new_name
        res = fo.issueRenameOrder(planet_id, new_name)
        print "Capitol Rename attempt result: %d; planet now named %s" % (res, planet.name)

    diplomatic_corp_configs = {fo.aggression.beginner: DiplomaticCorp.BeginnerDiplomaticCorp,
                               fo.aggression.maniacal: DiplomaticCorp.ManiacalDiplomaticCorp}
    global diplomatic_corp
    diplomatic_corp = diplomatic_corp_configs.get(aggression, DiplomaticCorp.DiplomaticCorp)()
예제 #5
0
def merge_fleet_a_into_b(fleet_a_id, fleet_b_id, leave_rating=0, need_rating=0, context=""):
    universe = fo.getUniverse()
    fleet_a = universe.getFleet(fleet_a_id)
    fleet_b = universe.getFleet(fleet_b_id)
    if not fleet_a or not fleet_b:
        return 0
    system_id = fleet_a.systemID
    if fleet_b.systemID != system_id:
        return 0
    remaining_rating = CombatRatingsAI.get_fleet_rating(fleet_a_id)
    transferred_rating = 0
    for ship_id in fleet_a.shipIDs:
        this_ship = universe.getShip(ship_id)
        if not this_ship:
            continue
        this_rating = CombatRatingsAI.ShipCombatStats(ship_id).get_rating()
        remaining_rating = CombatRatingsAI.rating_needed(remaining_rating, this_rating)
        if remaining_rating < leave_rating:  # merging this would leave old fleet under minimum rating, try other ships.
            continue
        transferred = fo.issueFleetTransferOrder(ship_id, fleet_b_id)
        if transferred:
            transferred_rating = CombatRatingsAI.combine_ratings(transferred_rating, this_rating)
        else:
            print "  *** transfer of ship %4d, formerly of fleet %4d, into fleet %4d failed; %s" % (
                ship_id, fleet_a_id, fleet_b_id, (" context is %s" % context) if context else "")
        if need_rating != 0 and need_rating <= transferred_rating:
            break
    fleet_a = universe.getFleet(fleet_a_id)
    if not fleet_a or fleet_a.empty or fleet_a_id in universe.destroyedObjectIDs(fo.empireID()):
        foAI.foAIstate.delete_fleet_info(fleet_a_id)
    foAI.foAIstate.update_fleet_rating(fleet_b_id)
예제 #6
0
def assign_invasion_values(planet_ids, mission_type, fleet_suppliable_planet_ids, empire):
    """Creates a dictionary that takes planet_ids as key and their invasion score as value."""
    planet_values = {}
    neighbor_values = {}
    neighbor_val_ratio = .95
    universe = fo.getUniverse()
    secure_missions = foAI.foAIstate.get_fleet_missions_with_any_mission_types([EnumsAI.AIFleetMissionType.FLEET_MISSION_SECURE])
    for pid in planet_ids:
        planet_values[pid] = neighbor_values.setdefault(pid, evaluate_invasion_planet(pid, empire, secure_missions))
        print "planet %d, values %s" % (pid, planet_values[pid])
        planet = universe.getPlanet(pid)
        species_name = (planet and planet.speciesName) or ""
        species = fo.getSpecies(species_name)
        if species and species.canProduceShips:
            system = universe.getSystem(planet.systemID)
            if not system:
                continue
            planet_industries = {}
            for pid2 in system.planetIDs:
                planet2 = universe.getPlanet(pid2)
                species_name2 = (planet2 and planet2.speciesName) or ""
                species2 = fo.getSpecies(species_name2)
                if species2 and species2.canProduceShips:
                    planet_industries[pid2] = planet2.currentMeterValue(fo.meterType.industry) + 0.1  # to prevent divide-by-zero
            industry_ratio = planet_industries[pid] / max(planet_industries.values())
            for pid2 in system.planetIDs:
                if pid2 == pid:
                    continue
                planet2 = universe.getPlanet(pid2)
                if planet2 and (planet2.owner != empire.empireID) and ((planet2.owner != -1) or (planet.currentMeterValue(fo.meterType.population) > 0)):  # TODO check for allies
                    planet_values[pid][0] += industry_ratio * neighbor_val_ratio * (neighbor_values.setdefault(pid2, evaluate_invasion_planet(pid2, empire, secure_missions))[0])
    return planet_values
예제 #7
0
def get_current_and_max_structure(fleet):
    """Return a 2-tuple of the sums of structure and maxStructure meters of all ships in the fleet

    :param fleet:
    :type fleet: int | universe_object.Fleet | fo.Fleet
    :return: tuple of sums of structure and maxStructure meters of all ships in the fleet
    :rtype: (float, float)
    """

    universe = fo.getUniverse()
    destroyed_ids = universe.destroyedObjectIDs(fo.empireID())
    if isinstance(fleet, int):
        fleet = universe.getFleet(fleet)
    elif isinstance(fleet, Fleet):
        fleet = fleet.get_object()
    if not fleet:
        return (0.0, 0.0)
    ships_cur_health = 0
    ships_max_health = 0
    for ship_id in fleet.shipIDs:
        # Check if we have see this ship get destroyed in a different fleet since the last time we saw the subject fleet
        # this may be redundant with the new fleet assignment check made below, but for its limited scope it may be more
        # reliable, in that it does not rely on any particular handling of post-destruction stats
        if ship_id in destroyed_ids:
            continue
        this_ship = universe.getShip(ship_id)
        # check that the ship has not been seen in a new fleet since this current fleet was last observed
        if not (this_ship and this_ship.fleetID == fleet.id):
            continue
        ships_cur_health += this_ship.initialMeterValue(fo.meterType.structure)
        ships_max_health += this_ship.initialMeterValue(fo.meterType.maxStructure)

    return ships_cur_health, ships_max_health
예제 #8
0
def getAllPopulatedSystemIDs(planetIDs):
    "return list of all populated systemIDs"

    universe = fo.getUniverse()
    allPopulatedSystemIDs = []
    popPlanets=getPopulatedPlanetIDs(planetIDs)
    return [universe.getPlanet(planetID).systemID for planetID in popPlanets ]
예제 #9
0
def calculate_estimated_time_of_arrival(fleet_id, target_system_id):
    universe = fo.getUniverse()
    fleet = universe.getFleet(fleet_id)
    if not fleet or not fleet.speed:
        return 99999
    distance = universe.shortestPathDistance(fleet_id, target_system_id)
    return math.ceil(float(distance) / fleet.speed)
예제 #10
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)
예제 #11
0
def identifyFleetsRoles():
    "identify fleet roles"

    # assign roles to fleets
    universe = fo.getUniverse()
    for fleetID in universe.fleetIDs:
        foAIstate.addFleetRole(fleetID, FleetUtilsAI.assessFleetRole(fleetID))
예제 #12
0
def getCapital(): # if no current capital returns planet with biggest pop
    universe = fo.getUniverse()
    empire = fo.getEmpire()
    if empire == None:
        print "Danger Danger! FO can't find an empire for me!!!!"
        return None
    empireID = empire.empireID
    capitalID = empire.capitalID
    homeworld = universe.getPlanet(capitalID)
    if homeworld:
        if homeworld.owner==empireID:
            return capitalID
        else:
            print "Nominal Capitol %s does not appear to be owned by empire %d  %s"%(homeworld.name,  empireID,  empire.name)
    #exploredSystemIDs = empire.exploredSystemIDs
    #exploredPlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(exploredSystemIDs)
    empireOwnedPlanetIDs = getOwnedPlanetsByEmpire(universe.planetIDs, empireID)
    peopledPlanets = getPopulatedPlanetIDs(  empireOwnedPlanetIDs)
    if not peopledPlanets:
        if empireOwnedPlanetIDs:
            return empireOwnedPlanetIDs[0]
        else:
            return None
    popMap = []
    for planetID in peopledPlanets:
        popMap.append( ( universe.getPlanet(planetID).currentMeterValue(fo.meterType.population) ,  planetID) )
    popMap.sort()
    return popMap[-1][-1]
예제 #13
0
def set_planet_production_and_research_specials(focus_manager):
    """Set production and research specials.
    Sets production/research specials for known (COMPUTRONIUM, HONEYCOMB and CONC_CAMP)
    production/research specials.
    Remove planets from list of candidates using bake_future_focus."""
    # TODO remove reliance on rules knowledge.  Just scan for specials with production
    # and research bonuses and use what you find. Perhaps maintain a list
    # of know types of specials
    # TODO use "best" COMPUTRON planet instead of first found, where "best" means least industry loss,
    # least threatened, no foci change penalty etc.
    universe = fo.getUniverse()
    already_have_comp_moon = False
    for pid, info in focus_manager.raw_planet_info.items():
        planet = info.planet
        if "COMPUTRONIUM_SPECIAL" in planet.specials and RESEARCH in planet.availableFoci and not already_have_comp_moon:
            if focus_manager.bake_future_focus(pid, RESEARCH):
                already_have_comp_moon = True
                print "%s focus of planet %s (%d) (with Computronium Moon) at Research Focus" % (["set", "left"][info.current_focus == RESEARCH], planet.name, pid)
                continue
        if "HONEYCOMB_SPECIAL" in planet.specials and INDUSTRY in planet.availableFoci:
            if focus_manager.bake_future_focus(pid, INDUSTRY):
                print "%s focus of planet %s (%d) (with Honeycomb) at Industry Focus" % (["set", "left"][info.current_focus == INDUSTRY], planet.name, pid)
                continue
        if ((([bld.buildingTypeName for bld in map(universe.getBuilding, planet.buildingIDs) if bld.buildingTypeName in
               ["BLD_CONC_CAMP", "BLD_CONC_CAMP_REMNANT"]])
             or ([ccspec for ccspec in planet.specials if ccspec in
                  ["CONC_CAMP_MASTER_SPECIAL", "CONC_CAMP_SLAVE_SPECIAL"]]))
                and INDUSTRY in planet.availableFoci):
            if focus_manager.bake_future_focus(pid, INDUSTRY):
                print "%s focus of planet %s (%d) (with Concentration Camps/Remnants) at Industry Focus" % (["set", "left"][info.current_focus == INDUSTRY], planet.name, pid)
                continue
            else:
                new_planet = universe.getPlanet(pid)
                print ("Error: Failed setting %s for Concentration Camp planet %s (%d) with species %s and current focus %s, but new planet copy shows %s" %
                       (info.future_focus, planet.name, pid, planet.speciesName, planet.focus, new_planet.focus))
예제 #14
0
 def clean(self):
     global invasionTargets
     "turn start AIstate cleanup"
     
     fleetsLostBySystem.clear()
     fleetsLostByID.clear()
     invasionTargets=[]
     
     ExplorationAI.graphFlags.clear()
     print "-------------------------------------------------"
     print "Border Exploration Update"
     print "-------------------------------------------------"
     for sysID in list(self.visBorderSystemIDs):
         ExplorationAI.followVisSystemConnections(sysID,  self.origHomeSystemID)
     newlyExplored = ExplorationAI.updateExploredSystems()
     nametags=[]
     universe = fo.getUniverse()
     for sysID in newlyExplored:
         newsys = universe.getSystem(sysID)
         nametags.append(  "ID:%4d -- %20s"%(sysID, (newsys and newsys.name) or"name unknown"  )    )# an explored system *should* always be able to be gotten 
     if newlyExplored:
         print "-------------------------------------------------"
         print "newly explored systems: \n"+"\n".join(nametags)
         print "-------------------------------------------------"
     # cleanup fleet roles
     #self.updateFleetLocs()
     self.__cleanFleetRoles()
     self.__cleanAIFleetMissions(FleetUtilsAI.getEmpireFleetIDs())
     print "Fleets lost by system: %s"%fleetsLostBySystem
     self.updateSystemStatus()
     ExplorationAI.updateScoutFleets() #should do this after clearing dead  fleets, currently should be already done here
예제 #15
0
def avail_mil_needing_repair(mil_fleet_ids, split_ships=False, on_mission=False, repair_limit=0.70):
    """Returns tuple of lists: (ids_needing_repair, ids_not)."""
    fleet_buckets = [[], []]
    universe = fo.getUniverse()
    cutoff = [repair_limit, 0.25][on_mission]
    for fleet_id in mil_fleet_ids:
        fleet = universe.getFleet(fleet_id)
        ship_buckets = [[], []]
        ships_cur_health = [0, 0]
        ships_max_health = [0, 0]
        for ship_id in fleet.shipIDs:
            this_ship = universe.getShip(ship_id)
            cur_struc = this_ship.currentMeterValue(fo.meterType.structure)
            max_struc = this_ship.currentMeterValue(fo.meterType.maxStructure)
            ship_ok = cur_struc >= cutoff * max_struc
            ship_buckets[ship_ok].append(ship_id)
            ships_cur_health[ship_ok] += cur_struc
            ships_max_health[ship_ok] += max_struc
        this_sys_id = (fleet.nextSystemID != -1 and fleet.nextSystemID) or fleet.systemID
        fleet_ok = (sum(ships_cur_health) >= cutoff * sum(ships_max_health))
        local_status = foAI.foAIstate.systemStatus.get(this_sys_id, {})
        my_local_rating = combine_ratings(local_status.get('mydefenses', {}).get('overall', 0), local_status.get('myFleetRating', 0))
        needed_here = local_status.get('totalThreat', 0) > 0  # TODO: assess if remaining other forces are sufficient
        safely_needed = needed_here and my_local_rating > local_status.get('totalThreat', 0)  # TODO: improve both assessment prongs
        if not fleet_ok:
            if safely_needed:
                print "Fleet %d at %s needs repair but deemed safely needed to remain for defense" % (fleet_id, ppstring(PlanetUtilsAI.sys_name_ids([fleet.systemID])))
            else:
                if needed_here:
                    print "Fleet %d at %s needed present for combat, but is damaged and deemed unsafe to remain." % (fleet_id, ppstring(PlanetUtilsAI.sys_name_ids([fleet.systemID])))
                    print "\t my_local_rating: %.1f ; threat: %.1f" % (my_local_rating, local_status.get('totalThreat', 0))
                print "Selecting fleet %d at %s for repair" % (fleet_id, ppstring(PlanetUtilsAI.sys_name_ids([fleet.systemID])))
        fleet_buckets[fleet_ok or safely_needed].append(fleet_id)
    return fleet_buckets
예제 #16
0
    def _portion_of_fleet_needed_here(self):
        """Calculate the portion of the fleet needed in target system considering enemy forces."""
        # TODO check rating against planets
        if assertion_fails(self.type in COMBAT_MISSION_TYPES, msg=str(self)):
            return 0
        if assertion_fails(self.target and self.target.id != INVALID_ID, msg=str(self)):
            return 0
        system_id = self.target.id
        aistate = get_aistate()
        local_defenses = MilitaryAI.get_my_defense_rating_in_system(system_id)
        potential_threat = CombatRatingsAI.combine_ratings(
            MilitaryAI.get_system_local_threat(system_id),
            MilitaryAI.get_system_neighbor_threat(system_id)
        )
        universe = fo.getUniverse()
        system = universe.getSystem(system_id)

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

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

        fleet_rating = CombatRatingsAI.get_fleet_rating(self.fleet.id)
        return CombatRatingsAI.rating_needed(potential_threat, local_defenses) / float(fleet_rating)
예제 #17
0
def evaluateSystem(systemID, missionType, empireProvinceSystemIDs, otherTargetedSystemIDs, empire):
    "return the military value of a system"

    universe = fo.getUniverse()
    system = universe.getSystem(systemID)
    if (system == None): return 0

    # give preference to home system then closest systems
    empireID = empire.empireID
    capitalID = PlanetUtilsAI.getCapital()
    homeworld = universe.getPlanet(capitalID)
    if homeworld:
        homeSystemID = homeworld.systemID
        evalSystemID = system.systemID
        leastJumpsPath = len(universe.leastJumpsPath(homeSystemID, evalSystemID, empireID))
        distanceFactor = 1.001/(leastJumpsPath + 1)
    else:
        homeSystemID=-1
        distanceFactor=0

    if systemID == homeSystemID:
        return 10
    elif systemID in empireProvinceSystemIDs:
        return 4 + distanceFactor
    elif systemID in otherTargetedSystemIDs:
        return 2 + distanceFactor
    else:
        return 1 + .25 * distanceFactor
예제 #18
0
def sendColonyShips(colonyFleetIDs, evaluatedPlanets, missionType):
    "sends a list of colony ships to a list of planet_value_pairs"
    fleetPool = colonyFleetIDs[:]
    potentialTargets =   [  (pid, (score, specName)  )  for (pid,  (score, specName) ) in  evaluatedPlanets if score > 30 ]

    print "colony/outpost  ship matching -- fleets  %s to planets %s"%( fleetPool,  evaluatedPlanets)
    #for planetID_value_pair in evaluatedPlanets:
    fleetPool=set(fleetPool)
    universe=fo.getUniverse()
    while (len(fleetPool) > 0 ) and ( len(potentialTargets) >0):
        thisTarget = potentialTargets.pop(0)
        thisPlanetID=thisTarget[0]
        thisSysID = universe.getPlanet(thisPlanetID).systemID
        if (foAI.foAIstate.systemStatus.setdefault(thisSysID, {}).setdefault('monsterThreat', 0) > 2000) or (fo.currentTurn() <20  and foAI.foAIstate.systemStatus[thisSysID]['monsterThreat'] > 200):
            print "Skipping colonization of system %s due to Big Monster,  threat %d"%(PlanetUtilsAI.sysNameIDs([thisSysID]),  foAI.foAIstate.systemStatus[thisSysID]['monsterThreat'])
            continue
        thisSpec=thisTarget[1][1]
        foundFleets=[]
        thisFleetList = FleetUtilsAI.getFleetsForMission(nships=1,  targetStats={},  minStats={},  curStats={},  species=thisSpec,  systemsToCheck=[thisSysID],  systemsChecked=[], 
                                                     fleetPoolSet = fleetPool,   fleetList=foundFleets,  verbose=False)
        if thisFleetList==[]:
            fleetPool.update(foundFleets)#just to be safe
            continue #must have no compatible colony/outpost ships 
        fleetID = thisFleetList[0]

        aiTarget = AITarget.AITarget(AITargetType.TARGET_PLANET, thisPlanetID)
        aiFleetMission = foAI.foAIstate.getAIFleetMission(fleetID)
        aiFleetMission.addAITarget(missionType, aiTarget)
예제 #19
0
파일: AIstate.py 프로젝트: Vezzra/freeorion
 def __border_exploration_update(self):
     universe = fo.getUniverse()
     exploration_center = PlanetUtilsAI.get_capital_sys_id()
     # a bad state probably from an old savegame, or else empire has lost (or almost has)
     if exploration_center == INVALID_ID:
         exploration_center = self.__origin_home_system_id
     ExplorationAI.graph_flags.clear()
     if fo.currentTurn() < 50:
         print "-------------------------------------------------"
         print "Border Exploration Update (relative to %s)" % universe.getSystem(exploration_center)
         print "-------------------------------------------------"
     if self.visBorderSystemIDs == {INVALID_ID}:
         self.visBorderSystemIDs.clear()
         self.visBorderSystemIDs.add(exploration_center)
     for sys_id in list(self.visBorderSystemIDs):  # This set is modified during iteration.
         if fo.currentTurn() < 50:
             print "Considering border system %s" % universe.getSystem(sys_id)
         ExplorationAI.follow_vis_system_connections(sys_id, exploration_center)
     newly_explored = ExplorationAI.update_explored_systems()
     nametags = []
     for sys_id in newly_explored:
         newsys = universe.getSystem(sys_id)
         # an explored system *should* always be able to be gotten
         nametags.append("ID:%4d -- %-20s" % (sys_id, (newsys and newsys.name) or "name unknown"))
     if newly_explored:
         print "-------------------------------------------------"
         print "Newly explored systems:\n%s" % "\n".join(nametags)
         print "-------------------------------------------------"
예제 #20
0
 def need_to_pause_movement(self, last_move_target_id, new_move_order):
     """
     When a fleet has consecutive move orders, assesses whether something about the interim destination warrants
     forcing a stop (such as a military fleet choosing to engage with an enemy fleet about to enter the same system,
     or it may provide a good vantage point to view current status of next system in path). Assessments about whether
     the new destination is suitable to move to are (currently) separately made by OrderMove.can_issue_order()
     :param last_move_target_id:
     :type last_move_target_id: int
     :param new_move_order:
     :type new_move_order: OrderMove
     :rtype: bool
     """
     fleet = self.fleet.get_object()
     # don't try skipping over more than one System
     if fleet.nextSystemID != last_move_target_id:
         return True
     universe = fo.getUniverse()
     current_dest_system = universe.getSystem(fleet.nextSystemID)
     if not current_dest_system:
         # shouldn't really happen, but just to be safe
         return True
     distance_to_next_system = ((fleet.x - current_dest_system.x)**2 + (fleet.y - current_dest_system.y)**2)**0.5
     surplus_travel_distance = fleet.speed - distance_to_next_system
     # if need more than one turn to reach current destination, then don't add another jump yet
     if surplus_travel_distance < 0:
         return True
     # TODO: add assessments for other situations we'd prefer to pause, such as cited above re military fleets, and
     # for situations where high value fleets like colony fleets might deem it safest to stop and look around
     # before proceeding
     return False
예제 #21
0
    def _need_repair(self, repair_limit=0.70):
        """Check if fleet needs to be repaired.

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

         :param repair_limit: percentage of health below which the fleet is sent to repair
         :type repair_limit: float
         :return: True if fleet needs repair
         :rtype: bool
        """
        # TODO: More complex evaluation if fleet needs repair (consider self-repair, distance, threat, mission...)
        universe = fo.getUniverse()
        fleet_id = self.fleet.id
        # if we are already at a system where we can repair, make sure we use it...
        system = self.fleet.get_system()
        # TODO starlane obstruction is not considered in the next call
        nearest_dock = MoveUtilsAI.get_best_drydock_system_id(system.id, fleet_id)
        if nearest_dock == system.id:
            repair_limit = 0.99
        # if combat fleet, use military repair check
        if foAI.foAIstate.get_fleet_role(fleet_id) in COMBAT_MISSION_TYPES:
            return fleet_id in MilitaryAI.avail_mil_needing_repair([fleet_id], on_mission=bool(self.orders),
                                                                   repair_limit=repair_limit)[0]
        # TODO: Allow to split fleet to send only damaged ships to repair
        fleet = universe.getFleet(fleet_id)
        ships_cur_health = 0
        ships_max_health = 0
        for ship_id in fleet.shipIDs:
            this_ship = universe.getShip(ship_id)
            ships_cur_health += this_ship.currentMeterValue(fo.meterType.structure)
            ships_max_health += this_ship.currentMeterValue(fo.meterType.maxStructure)
        return ships_cur_health < repair_limit * ships_max_health
예제 #22
0
파일: AIstate.py 프로젝트: Vezzra/freeorion
    def __split_new_fleets(self):
        """Split any new fleets.

        This function is supposed to be called once at the beginning of the turn.
        Splitting the auto generated fleets at game start or those created by
        recently built ships allows the AI to assign correct roles to all ships.
        """
        # TODO: check length of fleets for losses or do in AIstate.__cleanRoles
        universe = fo.getUniverse()
        known_fleets = self.get_fleet_roles_map()
        self.newlySplitFleets.clear()

        fleets_to_split = [fleet_id for fleet_id in FleetUtilsAI.get_empire_fleet_ids() if fleet_id not in known_fleets]
        if fleets_to_split:
            print "Trying to split %d new fleets" % len(fleets_to_split)
        for fleet_id in fleets_to_split:
            fleet = universe.getFleet(fleet_id)
            if not fleet:
                warn("Trying to split fleet %d but seemingly does not exist" % fleet_id)
                continue
            fleet_len = len(fleet.shipIDs)
            if fleet_len == 1:
                continue
            new_fleets = FleetUtilsAI.split_fleet(fleet_id)
            print "Split fleet %d with %d ships into %d new fleets:" % (fleet_id, fleet_len, len(new_fleets))
예제 #23
0
def canTravelToSystemAndReturnToResupply(fleetID, fromSystemAITarget, toSystemAITarget, empireID,  verbose=False):
    "check if fleet can travel from starting system to wanted system"

    systemAITargets = []
    if not fromSystemAITarget.getTargetID() == toSystemAITarget.getTargetID:
        # get supplyable systems
        empire = fo.getEmpire()
        fleetSupplyableSystemIDs = empire.fleetSupplyableSystemIDs
        # get current fuel and max fuel
        universe = fo.getUniverse()
        fleet = universe.getFleet(fleetID)
        maxFuel = int(fleet.maxFuel)
        fuel = int(fleet.fuel)
        if verbose:
            print "   fleet ID %d  has  %.1f fuel  to get from %s    to  %s"%(fleetID,  fuel,  fromSystemAITarget,  toSystemAITarget )

        # try to find path without going resupply first
        supplySystemAITarget = getNearestSuppliedSystem(toSystemAITarget.getTargetID(), empireID)
        systemAITargets = __findPathWithFuelToSystemWithPossibleReturn(fromSystemAITarget, toSystemAITarget, empireID, systemAITargets, fleetSupplyableSystemIDs, maxFuel, fuel, supplySystemAITarget)
        # resupply in system first is required to find path
        if not(fromSystemAITarget.getTargetID() in fleetSupplyableSystemIDs) and len(systemAITargets) == 0:
            # add supply system to visit
            fromSystemAITarget = getNearestSuppliedSystem(fromSystemAITarget.getTargetID(), empireID)
            systemAITargets.append(fromSystemAITarget)
            # find path from supplied system to wanted system
            systemAITargets = __findPathWithFuelToSystemWithPossibleReturn(fromSystemAITarget, toSystemAITarget, empireID, systemAITargets, fleetSupplyableSystemIDs, maxFuel, maxFuel, supplySystemAITarget)

    return systemAITargets
예제 #24
0
def can_travel_to_system(fleet_id, start, target, ensure_return=False):
    """
    Return list systems to be visited.

    :param fleet_id:
    :type fleet_id: int
    :param start:
    :type start: target.TargetSystem
    :param target:
    :type target:  target.TargetSystem
    :param ensure_return:
    :type ensure_return: bool
    :return:
    :rtype: list
    """
    if start == target:
        return [TargetSystem(start.id)]

    debug("Requesting path for fleet %s from %s to %s" % (fo.getUniverse().getFleet(fleet_id), start, target))
    target_distance_from_supply = -min(state.get_system_supply(target.id), 0)

    # low-aggression AIs may not travel far from supply
    if not get_aistate().character.may_travel_beyond_supply(target_distance_from_supply):
        debug("May not move %d out of supply" % target_distance_from_supply)
        return []

    min_fuel_at_target = target_distance_from_supply if ensure_return else 0
    path_info = pathfinding.find_path_with_resupply(start.id, target.id, fleet_id,
                                                    minimum_fuel_at_target=min_fuel_at_target)
    if path_info is None:
        debug("Found no valid path.")
        return []

    debug("Found valid path: %s" % str(path_info))
    return [TargetSystem(sys_id) for sys_id in path_info.path]
예제 #25
0
파일: AIstate.py 프로젝트: Vezzra/freeorion
    def __update_empire_standard_enemy(self):
        """Update the empire's standard enemy.

        The standard enemy is the enemy that is most often seen.
        """
        # TODO: If no current information available, rate against own fighters
        universe = fo.getUniverse()
        empire_id = fo.empireID()

        # assess enemy fleets that may have been momentarily visible (start with dummy entries)
        dummy_stats = CombatRatingsAI.default_ship_stats().get_stats(hashable=True)
        cur_e_fighters = Counter()  # actual visible enemies
        old_e_fighters = Counter({dummy_stats: 0})  # destroyed enemies TODO: consider seen but out of sight enemies

        for fleet_id in universe.fleetIDs:
            fleet = universe.getFleet(fleet_id)
            if (not fleet or fleet.empty or fleet.ownedBy(empire_id) or fleet.unowned or
                    not (fleet.hasArmedShips or fleet.hasFighterShips)):
                continue

            # track old/dead enemy fighters for rating assessments in case not enough current info
            ship_stats = CombatRatingsAI.FleetCombatStats(fleet_id).get_ship_stats(hashable=True)
            dead_fleet = fleet_id in universe.destroyedObjectIDs(empire_id)
            e_f_dict = old_e_fighters if dead_fleet else cur_e_fighters
            for stats in ship_stats:
                # log only ships that are armed
                if stats[0]:
                    e_f_dict[stats] += 1

        e_f_dict = cur_e_fighters or old_e_fighters
        self.__empire_standard_enemy = sorted([(v, k) for k, v in e_f_dict.items()])[-1][1]
        self.empire_standard_enemy_rating = self.get_standard_enemy().get_rating()
예제 #26
0
    def bake_future_focus(self, pid, focus, update=True):
        """Set the focus and moves it from the raw list to the baked list of planets.

        pid -- pid
        focus -- future focus to use
        update -- If update is True then the meters of the raw planets will be updated.
                  If the planet's change of focus will have a global effect (growth,
                  production or research special), then update should be True.
        Return success or failure
        """
        info = self.raw_planet_info.get(pid)
        success = bool(info is not None and
                       (info.current_focus == focus
                        or (focus in info.planet.availableFoci
                            and fo.issueChangeFocusOrder(pid, focus))))
        if success:
            if update and info.current_focus != focus:
                universe = fo.getUniverse()
                universe.updateMeterEstimates(self.raw_planet_info.keys())
                industry_target = info.planet.currentMeterValue(fo.meterType.targetIndustry)
                research_target = info.planet.currentMeterValue(fo.meterType.targetResearch)
                info.possible_output[focus] = (industry_target, research_target)

            info.future_focus = focus
            self.baked_planet_info[pid] = self.raw_planet_info.pop(pid)
        return success
예제 #27
0
 def issue_order(self):
     if not super(OrderMilitary, self).issue_order():
         return False
     target_sys_id = self.target.id
     fleet = self.target.get_object()
     system_status = foAI.foAIstate.systemStatus.get(target_sys_id, {})
     total_threat = sum(system_status.get(threat, 0) for threat in ('fleetThreat', 'planetThreat', 'monsterThreat'))
     combat_trigger = system_status.get('fleetThreat', 0) or system_status.get('monsterThreat', 0)
     if not combat_trigger and system_status.get('planetThreat', 0):
         universe = fo.getUniverse()
         system = universe.getSystem(target_sys_id)
         for planet_id in system.planetIDs:
             planet = universe.getPlanet(planet_id)
             if planet.ownedBy(fo.empireID()):  # TODO: also exclude at-peace planets
                 continue
             if planet.unowned and not EspionageAI.colony_detectable_by_empire(planet_id, empire=fo.empireID()):
                 continue
             if sum([planet.currentMeterValue(meter_type) for meter_type in
                     [fo.meterType.defense, fo.meterType.shield, fo.meterType.construction]]):
                 combat_trigger = True
                 break
     if not all((
                 fleet,
                 fleet.systemID == target_sys_id,
                 system_status.get('currently_visible', False),
                 not (total_threat and combat_trigger)
     )):
         self.executed = False
     return True
예제 #28
0
def send_invasion_fleets(fleet_ids, evaluated_planets, mission_type):
    """sends a list of invasion fleets to a list of planet_value_pairs"""
    universe = fo.getUniverse()
    invasion_fleet_pool = set(fleet_ids)
    if not invasion_fleet_pool:
        return

    for planet_id, pscore, ptroops in evaluated_planets:
        planet = universe.getPlanet(planet_id)
        if not planet:
            continue
        sys_id = planet.systemID
        found_fleets = []
        found_stats = {}
        min_stats = {'rating': 0, 'troopCapacity': ptroops}
        target_stats = {'rating': 10, 'troopCapacity': ptroops+1}
        these_fleets = FleetUtilsAI.get_fleets_for_mission(1, target_stats, min_stats, found_stats, "",
                                                           systems_to_check=[sys_id], systems_checked=[],
                                                           fleet_pool_set=invasion_fleet_pool, fleet_list=found_fleets,
                                                           verbose=False)
        if not these_fleets:
            if not FleetUtilsAI.stats_meet_reqs(found_stats, min_stats):
                print "Insufficient invasion troop allocation for system %d ( %s ) -- requested %s , found %s" % (
                    sys_id, universe.getSystem(sys_id).name, min_stats, found_stats)
                invasion_fleet_pool.update(found_fleets)
                continue
            else:
                these_fleets = found_fleets
        target = AITarget.AITarget(EnumsAI.TargetType.TARGET_PLANET, planet_id)
        print "assigning invasion fleets %s to target %s" % (these_fleets, target)
        for fleetID in these_fleets:
            fleet_mission = foAI.foAIstate.get_fleet_mission(fleetID)
            fleet_mission.clear_fleet_orders()
            fleet_mission.clear_targets((fleet_mission.get_mission_types() + [-1])[0])
            fleet_mission.add_target(mission_type, target)
예제 #29
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)
예제 #30
0
파일: AIstate.py 프로젝트: Vezzra/freeorion
 def __report_system_threats(self):
     """Print a table with system threats to the logfile."""
     current_turn = fo.currentTurn()
     if current_turn >= 100:
         return
     threat_table = Table([
         Text('System'), Text('Vis.'), Float('Total'), Float('by Monsters'), Float('by Fleets'),
         Float('by Planets'), Float('1 jump away'), Float('2 jumps'), Float('3 jumps')],
         table_name="System Threat Turn %d" % current_turn
     )
     universe = fo.getUniverse()
     for sys_id in universe.systemIDs:
         sys_status = self.systemStatus.get(sys_id, {})
         system = universe.getSystem(sys_id)
         threat_table.add_row([
             system,
             "Yes" if sys_status.get('currently_visible', False) else "No",
             sys_status.get('totalThreat', 0),
             sys_status.get('monsterThreat', 0),
             sys_status.get('fleetThreat', 0),
             sys_status.get('planetThreat', 0),
             sys_status.get('neighborThreat', 0.0),
             sys_status.get('jump2_threat', 0.0),
             sys_status.get('jump3_threat', 0.0),
         ])
     info(threat_table)
예제 #31
0
def split_ship_from_fleet(fleet_id, ship_id):
    universe = fo.getUniverse()
    fleet = universe.getFleet(fleet_id)
    if assertion_fails(fleet is not None):
        return

    if assertion_fails(ship_id in fleet.shipIDs):
        return

    if assertion_fails(fleet.numShips > 1, "Can't split last ship from fleet"):
        return

    new_fleet_id = fo.issueNewFleetOrder("Fleet %4d" % ship_id, ship_id)
    if new_fleet_id:
        aistate = get_aistate()
        new_fleet = universe.getFleet(new_fleet_id)
        if not new_fleet:
            warn("Newly split fleet %d not available from universe" %
                 new_fleet_id)
        debug("Successfully split ship %d from fleet %d into new fleet %d",
              ship_id, fleet_id, new_fleet_id)
        fo.issueRenameOrder(new_fleet_id, "Fleet %4d" %
                            new_fleet_id)  # to ease review of debugging logs
        fo.issueAggressionOrder(new_fleet_id, True)
        aistate.update_fleet_rating(new_fleet_id)
        aistate.newlySplitFleets[new_fleet_id] = True
        # register the new fleets so AI logic is aware of them
        sys_status = aistate.systemStatus.setdefault(fleet.systemID, {})
        sys_status['myfleets'].append(new_fleet_id)
        sys_status['myFleetsAccessible'].append(new_fleet_id)
    else:
        if fleet.systemID == INVALID_ID:
            warn(
                "Tried to split ship id (%d) from fleet %d when fleet is in starlane"
                % (ship_id, fleet_id))
        else:
            warn(
                "Got no fleet ID back after trying to split ship id (%d) from fleet %d"
                % (ship_id, fleet_id))
    return new_fleet_id
예제 #32
0
def startNewGame(aggression_input=fo.aggression.aggressive):  # pylint: disable=invalid-name
    """Called by client when a new game is started (but not when a game is loaded).
    Should clear any pre-existing state and set up whatever is needed for AI to generate orders."""
    empire = fo.getEmpire()
    if empire.eliminated:
        print "This empire has been eliminated. Ignoring new game start message."
        return

    turn_timer.start("Server Processing")

    # initialize AIstate
    global foAIstate
    print "Initializing foAIstate..."
    foAIstate = AIstate.AIstate(aggression_input)
    aggression_trait = foAIstate.character.get_trait(Aggression)
    print "New game started, AI Aggression level %d (%s)" % (
        aggression_trait.key, get_trait_name_aggression(foAIstate.character))
    foAIstate.session_start_cleanup()
    print "Initialization of foAIstate complete!"
    print "Trying to rename our homeworld..."
    planet_id = PlanetUtilsAI.get_capital()
    universe = fo.getUniverse()
    if planet_id is not None and planet_id != INVALID_ID:
        planet = universe.getPlanet(planet_id)
        new_name = " ".join([
            random.choice(possible_capitals(foAIstate.character)).strip(),
            planet.name
        ])
        print "    Renaming to %s..." % new_name
        res = fo.issueRenameOrder(planet_id, new_name)
        print "    Result: %d; Planet is now named %s" % (res, planet.name)

    diplomatic_corp_configs = {
        fo.aggression.beginner: DiplomaticCorp.BeginnerDiplomaticCorp,
        fo.aggression.maniacal: DiplomaticCorp.ManiacalDiplomaticCorp
    }
    global diplomatic_corp
    diplomatic_corp = diplomatic_corp_configs.get(
        aggression_trait.key, DiplomaticCorp.DiplomaticCorp)()
    TechsListsAI.test_tech_integrity()
예제 #33
0
def can_travel_to_system(fleet_id, start, target, ensure_return=False):
    """
    Return list systems to be visited.

    :param fleet_id:
    :type fleet_id: int
    :param start:
    :type start: target.TargetSystem
    :param target:
    :type target:  target.TargetSystem
    :param ensure_return:
    :type ensure_return: bool
    :return:
    :rtype: list
    """
    if start == target:
        return [TargetSystem(start.id)]

    debug("Requesting path for fleet %s from %s to %s" %
          (fo.getUniverse().getFleet(fleet_id), start, target))
    target_distance_from_supply = -min(state.get_system_supply(target.id), 0)

    # low-aggression AIs may not travel far from supply
    if not get_aistate().character.may_travel_beyond_supply(
            target_distance_from_supply):
        debug("May not move %d out of supply" % target_distance_from_supply)
        return []

    min_fuel_at_target = target_distance_from_supply if ensure_return else 0
    path_info = pathfinding.find_path_with_resupply(
        start.id,
        target.id,
        fleet_id,
        minimum_fuel_at_target=min_fuel_at_target)
    if path_info is None:
        debug("Found no valid path.")
        return []

    debug("Found valid path: %s" % str(path_info))
    return [TargetSystem(sys_id) for sys_id in path_info.path]
예제 #34
0
def get_capital() -> PlanetId:
    """
    Return current empire capital id.

    If no current capital returns planet with biggest population in first not empty group.
    First check all planets with coloniser species, after that with ship builders and at last all inhabited planets.
    """
    universe = fo.getUniverse()
    empire = fo.getEmpire()
    empire_id = empire.empireID
    capital_id = empire.capitalID
    homeworld = universe.getPlanet(capital_id)
    if homeworld:
        if homeworld.owner == empire_id:
            return capital_id
        else:
            debug(
                "Nominal Capitol %s does not appear to be owned by empire %d %s"
                % (homeworld.name, empire_id, empire.name))
    empire_owned_planet_ids = get_owned_planets_by_empire(universe.planetIDs)
    peopled_planets = get_populated_planet_ids(empire_owned_planet_ids)
    if not peopled_planets:
        if empire_owned_planet_ids:
            return empire_owned_planet_ids[0]
        else:
            return INVALID_ID
    try:
        for spec_list in [get_colony_builders(), get_ship_builders(), None]:
            population_id_pairs = []
            for planet_id in peopled_planets:
                planet = universe.getPlanet(planet_id)
                if spec_list is None or planet.speciesName in spec_list:
                    population_id_pairs.append(
                        (planet.initialMeterValue(fo.meterType.population),
                         planet_id))
            if population_id_pairs:
                return max(population_id_pairs)[-1]
    except Exception as e:
        error(e, exc_info=True)
    return INVALID_ID  # shouldn't ever reach here
예제 #35
0
def update_explored_systems():
    universe = fo.getUniverse()
    empire = fo.getEmpire()
    obs_lanes = empire.obstructedStarlanes()
    obs_lanes_list = [el for el in obs_lanes]  # should result in list of tuples (sys_id1, sys_id2)
    if obs_lanes_list:
        print "Obstructed starlanes are: %s" % ', '.join('%s-%s' % item for item in obs_lanes_list)
    else:
        print "No obstructed Starlanes"
    empire_id = fo.empireID()
    newly_explored = []
    still_unexplored = []
    for sys_id in list(foAI.foAIstate.unexploredSystemIDs):
        # consider making determination according to visibility rather than actual visit,
        # which I think is what empire.hasExploredSystem covers (Dilvish-fo)
        if empire.hasExploredSystem(sys_id):
            foAI.foAIstate.unexploredSystemIDs.discard(sys_id)
            foAI.foAIstate.exploredSystemIDs.add(sys_id)
            system = universe.getSystem(sys_id)
            print "Moved system %s from unexplored list to explored list" % system
            border_unexplored_system_ids.discard(sys_id)
            newly_explored.append(sys_id)
        else:
            still_unexplored.append(sys_id)

    neighbor_list = []
    dummy = []
    for id_list, next_list in [(newly_explored, neighbor_list), (neighbor_list, dummy)]:
        for sys_id in id_list:
            neighbors = list(universe.getImmediateNeighbors(sys_id, empire_id))
            for neighbor_id in neighbors:
                # when it matters, unexplored will be smaller than explored
                if neighbor_id not in foAI.foAIstate.unexploredSystemIDs:
                    next_list.append(neighbor_id)

    for sys_id in still_unexplored:
        neighbors = list(universe.getImmediateNeighbors(sys_id, empire_id))
        if any(nid in foAI.foAIstate.exploredSystemIDs for nid in neighbors):
            border_unexplored_system_ids.add(sys_id)
    return newly_explored
예제 #36
0
    def __init__(self):
        self.have_gas_giant = False
        self.have_asteroids = False
        self.owned_asteroid_coatings = 0
        self.have_ruins = False
        self.have_nest = False
        self.have_computronium = False
        self.have_honeycomb = False
        self.have_worldtree = False
        self.num_researchers = 0  # population with research focus
        self.num_industrialists = 0  # population with industry focus

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

        for planet_info in _get_planets_info().values():
            planet = universe.getPlanet(planet_info.pid)
            if planet.ownedBy(empire_id):

                if AIDependencies.ANCIENT_RUINS_SPECIAL in planet.specials:
                    self.have_ruins = True

                if AIDependencies.WORLDTREE_SPECIAL in planet.specials:
                    self.have_world_tree = True

                if AIDependencies.ASTEROID_COATING_OWNED_SPECIAL in planet.specials:
                    self.owned_asteroid_coatings += 1

                if planet.focus == FocusType.FOCUS_RESEARCH and AIDependencies.COMPUTRONIUM_SPECIAL in planet.specials:
                    self.have_computronium = True

                if planet.focus == FocusType.FOCUS_INDUSTRY and AIDependencies.HONEYCOMB_SPECIAL in planet.specials:
                    self.have_honeycomb = True

                population = planet.currentMeterValue(fo.meterType.population)
                if planet.focus == FocusType.FOCUS_INDUSTRY:
                    self.num_industrialists += population
                elif planet.focus == FocusType.FOCUS_RESEARCH:
                    self.num_researchers += population
예제 #37
0
 def __report_last_turn_fleet_missions(self):
     """Print a table reviewing last turn fleet missions to the log file."""
     universe = fo.getUniverse()
     mission_table = Table(
             [Text('Fleet'), Text('Mission'), Text('Ships'), Float('Rating'), Float('Troops'), Text('Target')],
             table_name="Turn %d: Fleet Mission Review from Last Turn" % fo.currentTurn())
     for fleet_id, mission in self.get_fleet_missions_map().items():
         fleet = universe.getFleet(fleet_id)
         if not fleet:
             continue
         if not mission:
             mission_table.add_row([fleet])
         else:
             mission_table.add_row([
                 fleet,
                 mission.type or "None",
                 len(fleet.shipIDs),
                 CombatRatingsAI.get_fleet_rating(fleet_id),
                 FleetUtilsAI.count_troops_in_fleet(fleet_id),
                 mission.target or "-"
             ])
     info(mission_table)
예제 #38
0
    def __update_planets(self):
        """
        Update information about planets.
        """
        universe = fo.getUniverse()
        empire_id = fo.empireID()
        for pid in universe.planetIDs:
            planet = universe.getPlanet(pid)
            self.__planet_info[pid] = PlanetInfo(pid, planet.speciesName,
                                                 planet.owner, planet.systemID)

            if planet.ownedBy(empire_id):
                population = planet.currentMeterValue(fo.meterType.population)
                if AIDependencies.ANCIENT_RUINS_SPECIAL in planet.specials:
                    self.__have_ruins = True
                if population > 0 and AIDependencies.COMPUTRONIUM_SPECIAL in planet.specials:
                    self.__have_computronium = True  # TODO: Check if species can set research focus

                if planet.focus == FocusType.FOCUS_INDUSTRY:
                    self.__num_industrialists += population
                elif planet.focus == FocusType.FOCUS_RESEARCH:
                    self.__num_researchers += population
예제 #39
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)
예제 #40
0
def set_planet_protection_foci(focus_manager):
    """Assess and set protection foci"""
    universe = fo.getUniverse()
    for pid, pinfo in list(focus_manager.raw_planet_info.items()):
        planet = pinfo.planet
        if PROTECTION in planet.availableFoci and assess_protection_focus(
                pinfo, focus_manager.priority):
            current_focus = planet.focus
            if focus_manager.bake_future_focus(pid, PROTECTION):
                if current_focus != PROTECTION:
                    debug(
                        "Tried setting %s for planet %s (%d) with species %s and current focus %s, "
                        "got result %d and focus %s",
                        pinfo.future_focus,
                        planet.name,
                        pid,
                        planet.speciesName,
                        current_focus,
                        True,
                        planet.focus,
                    )
                debug(
                    "%s focus of planet %s (%d) at Protection(Defense) Focus",
                    ["set", "left"][current_focus == PROTECTION],
                    planet.name,
                    pid,
                )
                continue
            else:
                new_planet = universe.getPlanet(pid)
                warning(
                    "Failed setting PROTECTION for planet %s (%d) with species %s and current focus %s, "
                    "but new planet copy shows %s",
                    planet.name,
                    pid,
                    planet.speciesName,
                    planet.focus,
                    new_planet.focus,
                )
예제 #41
0
def _calculate_industry_priority():  # currently only used to print status
    """calculates the demand for industry"""
    universe = fo.getUniverse()
    empire = fo.getEmpire()
    # get current industry production & Target
    industry_production = empire.resourceProduction(fo.resourceType.industry)
    owned_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire(
        universe.planetIDs)
    planets = map(universe.getPlanet, owned_planet_ids)
    target_pp = sum(
        map(lambda x: x.currentMeterValue(fo.meterType.targetIndustry),
            planets))

    # currently, previously set to 50 in calculatePriorities(), this is just for reporting
    industry_priority = foAI.foAIstate.get_priority(
        PriorityType.RESOURCE_PRODUCTION)

    print
    print "Industry Production (current/target) : ( %.1f / %.1f ) at turn %s" % (
        industry_production, target_pp, fo.currentTurn())
    print "Priority for Industry: %s" % industry_priority
    return industry_priority
예제 #42
0
def _systems_connected(system1: SystemId, system2: SystemId) -> bool:
    if system1 == INVALID_ID:
        return False

    # optimization: We cache a set of systems connected to the capital
    # system in a single DFS and check if the systems are both in that set.
    # This allows us to avoid a BFS for each pair of systems.
    # Only in case neither of the system connects to the capital, we need to
    # run the BFS.
    connected_system_set = systems_connected_to_system(get_capital_sys_id())
    sys1_connected_to_capital = system1 in connected_system_set
    sys2_connected_to_capital = system2 in connected_system_set
    if sys1_connected_to_capital and sys2_connected_to_capital:
        # both connected to the capital - so must be connected to each other
        return True

    if sys1_connected_to_capital != sys2_connected_to_capital:
        # Only one connected to the capital - can't be connected to each other
        return False

    # both are not connected to the home system - they may or may not be connected to each other
    return fo.getUniverse().systemsConnected(system1, system2, fo.empireID())
예제 #43
0
 def issue_order(self):
     if not super(OrderMilitary, self).issue_order():
         return False
     target_sys_id = self.target.id
     fleet = self.target.get_object()
     system_status = get_aistate().systemStatus.get(target_sys_id, {})
     total_threat = sum(
         system_status.get(threat, 0)
         for threat in ("fleetThreat", "planetThreat", "monsterThreat"))
     combat_trigger = system_status.get(
         "fleetThreat", 0) or system_status.get("monsterThreat", 0)
     if not combat_trigger and system_status.get("planetThreat", 0):
         universe = fo.getUniverse()
         system = universe.getSystem(target_sys_id)
         for planet_id in system.planetIDs:
             planet = universe.getPlanet(planet_id)
             if planet.ownedBy(
                     fo.empireID()):  # TODO: also exclude at-peace planets
                 continue
             if planet.unowned and not EspionageAI.colony_detectable_by_empire(
                     planet_id, empire=fo.empireID()):
                 continue
             if sum([
                     planet.currentMeterValue(meter_type)
                     for meter_type in [
                         fo.meterType.defense, fo.meterType.shield,
                         fo.meterType.construction
                     ]
             ]):
                 combat_trigger = True
                 break
     if not all((
             fleet,
             fleet.systemID == target_sys_id,
             system_status.get("currently_visible", False),
             not (total_threat and combat_trigger),
     )):
         self.executed = False
     return True
예제 #44
0
def startNewGame(aggression=fo.aggression.aggressive):  # pylint: disable=invalid-name
    """Called by client when a new game is started (but not when a game is loaded).
    Should clear any pre-existing state and set up whatever is needed for AI to generate orders."""
    turn_timer.start("Server Processing")
    print "New game started, AI Aggression level %d" % aggression

    # initialize AIstate
    global foAIstate
    foAIstate = AIstate.AIstate(aggression=aggression)
    foAIstate.session_start_cleanup()
    print "Initialized foAIstate class"
    planet_id = PlanetUtilsAI.get_capital()
    universe = fo.getUniverse()
    if planet_id is not None and planet_id != -1:
        planet = universe.getPlanet(planet_id)
        new_name = random.choice(_capitols.get(
            aggression, "").split('\n')).strip() + " " + planet.name
        print "Capitol City Names are: ", _capitols
        print "This Capitol New name is ", new_name
        res = fo.issueRenameOrder(planet_id, new_name)
        print "Capitol Rename attempt result: %d; planet now named %s" % (
            res, planet.name)
예제 #45
0
    def is_valid(self) -> bool:
        """
        Check the colonization plan for validity, i.e. if it could be executed in the future.

        The plan is valid if it is possible to outpost the target planet
        and if the planet envisioned to build the outpost bases can still do so.
        """
        universe = fo.getUniverse()

        # make sure target is valid
        target = universe.getPlanet(self.target)
        if target is None or (not target.unowned) or target.speciesName:
            return False

        # make sure source is valid
        source = universe.getPlanet(self.source)
        if not (source and source.ownedBy(fo.empireID()) and source.speciesName
                and fo.getSpecies(source.speciesName).canColonize):
            return False

        # appears to be valid
        return True
예제 #46
0
    def _need_repair(self, repair_limit=0.70):
        """Check if fleet needs to be repaired.

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

         :param repair_limit: percentage of health below which the fleet is sent to repair
         :type repair_limit: float
         :return: True if fleet needs repair
         :rtype: bool
        """
        # TODO: More complex evaluation if fleet needs repair (consider self-repair, distance, threat, mission...)
        universe = fo.getUniverse()
        fleet_id = self.fleet.id
        # if we are already at a system where we can repair, make sure we use it...
        system = self.fleet.get_system()
        # TODO starlane obstruction is not considered in the next call
        nearest_dock = MoveUtilsAI.get_best_drydock_system_id(
            system.id, fleet_id)
        if nearest_dock == system.id:
            repair_limit = 0.99
        # if combat fleet, use military repair check
        if foAI.foAIstate.get_fleet_role(fleet_id) in COMBAT_MISSION_TYPES:
            return fleet_id in MilitaryAI.avail_mil_needing_repair(
                [fleet_id],
                on_mission=bool(self.orders),
                repair_limit=repair_limit)[0]
        # TODO: Allow to split fleet to send only damaged ships to repair
        fleet = universe.getFleet(fleet_id)
        ships_cur_health = 0
        ships_max_health = 0
        for ship_id in fleet.shipIDs:
            this_ship = universe.getShip(ship_id)
            ships_cur_health += this_ship.initialMeterValue(
                fo.meterType.structure)
            ships_max_health += this_ship.initialMeterValue(
                fo.meterType.maxStructure)
        return ships_cur_health < repair_limit * ships_max_health
예제 #47
0
    def assign_bases_to_colonize(self):
        universe = fo.getUniverse()
        all_outpost_base_fleet_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(
            MissionType.ORBITAL_OUTPOST)
        avail_outpost_base_fleet_ids = FleetUtilsAI.extract_fleet_ids_without_mission_types(
            all_outpost_base_fleet_ids)
        for fid in avail_outpost_base_fleet_ids:
            fleet = universe.getFleet(fid)
            if not fleet:
                continue
            sys_id = fleet.systemID
            system = universe.getSystem(sys_id)

            avail_plans = [
                plan for plan in self._colonization_plans.values()
                if plan.target in system.planetIDs and not plan.base_assigned
            ]
            avail_plans.sort(key=lambda x: x.score, reverse=True)
            for plan in avail_plans:
                success = plan.assign_base(fid)
                if success:
                    break
예제 #48
0
    def enqueue_base(self) -> bool:
        """
        Enqueue the base according to the plan.

        :return: True on success, False on failure
        """
        if self.base_enqueued:
            warning("Tried to enqueue a base eventhough already done that.")
            return False

        # find the best possible base design for the source planet
        universe = fo.getUniverse()
        best_ship, _, _ = get_best_ship_info(PriorityType.PRODUCTION_ORBITAL_OUTPOST, self.source)
        if best_ship is None:
            warning("Can't find optimized outpost base design at %s" % (universe.getPlanet(self.source)))
            try:
                best_ship = next(
                    design
                    for design in fo.getEmpire().availableShipDesigns
                    if "SD_OUTPOST_BASE" == fo.getShipDesign(design).name
                )
                debug("Falling back to base design SD_OUTPOST_BASE")
            except StopIteration:
                # fallback design not available
                return False

        # enqueue the design at the source planet
        retval = fo.issueEnqueueShipProductionOrder(best_ship, self.source)
        debug(
            "Enqueueing Outpost Base at %s for %s with result %s"
            % (universe.getPlanet(self.source), universe.getPlanet(self.target), retval)
        )

        if not retval:
            warning("Failed to enqueue outpost base at %s" % universe.getPlanet(self.source))
            return False

        self.base_enqueued = True
        return True
예제 #49
0
def __print_candidate_table(candidates, mission, show_detail=False):
    universe = fo.getUniverse()
    if mission == "Colonization":
        first_column = Text("Score/Species")

        def get_first_column_value(x):
            return round(x[0], 2), x[1]

    elif mission == "Outposts":
        first_column = Number("Score")
        get_first_column_value = itemgetter(0)
    else:
        warning("__print_candidate_table(%s, %s): Invalid mission type" %
                (candidates, mission))
        return
    columns = [
        first_column,
        Text("Planet"),
        Text("System"),
        Sequence("Specials")
    ]
    if show_detail:
        columns.append(Sequence("Detail"))
    candidate_table = Table(*columns,
                            table_name="Potential Targets for %s in Turn %d" %
                            (mission, fo.currentTurn()))
    for planet_id, score_tuple in candidates:
        if score_tuple[0] > 0.5:
            planet = universe.getPlanet(planet_id)
            entries = [
                get_first_column_value(score_tuple),
                planet,
                universe.getSystem(planet.systemID),
                planet.specials,
            ]
            if show_detail:
                entries.append(score_tuple[-1])
            candidate_table.add_row(*entries)
    candidate_table.print_table(info)
예제 #50
0
def _get_stellar_tomography_bonus(system_id: SystemId) -> float:
    universe = fo.getUniverse()
    system = universe.getSystem(system_id)
    if system.starType == fo.starType.blackHole:
        factor = get_named_real(
            "LRN_STELLAR_TOMO_BLACK_TARGET_RESEARCH_PERPLANET")
    elif system.starType == fo.starType.neutron:
        factor = get_named_real(
            "LRN_STELLAR_TOMO_NEUTRON_TARGET_RESEARCH_PERPLANET")
    else:
        factor = get_named_real(
            "LRN_STELLAR_TOMO_NORMAL_STAR_TARGET_RESEARCH_PERPLANET")

    def is_our_researcher(pid):
        planet = universe.getPlanet(pid)
        return planet.focus == FocusType.FOCUS_RESEARCH and planet.owner == fo.empireID(
        )

    num_researcher = sum(1 for pid in system.planetIDs
                         if is_our_researcher(pid))
    # if we add another planet with research focus, all will profit. (n+1)^2 - n^2 = 2n + 1
    return (num_researcher * 2 + 1) * factor
예제 #51
0
 def issue_order(self):
     if not super(OrderRepair, self).issue_order():
         return False
     fleet_id = self.fleet.id
     system_id = self.target.get_system().id
     fleet = self.fleet.get_object()  # type: fo.fleet
     if system_id == fleet.systemID:
         if foAI.foAIstate.get_fleet_role(fleet_id) == MissionType.EXPLORATION:
             if system_id in foAI.foAIstate.needsEmergencyExploration:
                 foAI.foAIstate.needsEmergencyExploration.remove(system_id)
     elif system_id != fleet.nextSystemID:
         fo.issueAggressionOrder(fleet_id, False)
         start_id = FleetUtilsAI.get_fleet_system(fleet)
         dest_id = MoveUtilsAI.get_safe_path_leg_to_dest(fleet_id, start_id, system_id)
         universe = fo.getUniverse()
         print "fleet %d with order type(%s) sent to safe leg dest %s and ultimate dest %s" % (
             fleet_id, self.ORDER_NAME, universe.getSystem(dest_id), universe.getSystem(system_id))
         fo.issueFleetMoveOrder(fleet_id, dest_id)
         print "Order issued: %s fleet: %s target: %s" % (self.ORDER_NAME, self.fleet, self.target)
     ships_cur_health, ships_max_health = FleetUtilsAI.get_current_and_max_structure(fleet_id)
     self.executed = (ships_cur_health == ships_max_health)
     return True
예제 #52
0
    def issue_order(self):
        if not super(OrderInvade, self).can_issue_order():
            return
        result = False
        planet_id = self.target.id
        planet = self.target.get_object()
        planet_name = planet and planet.name or "invisible"
        fleet = self.fleet.get_object()
        detail_str = ""
        universe = fo.getUniverse()

        global dumpTurn
        for ship_id in fleet.shipIDs:
            ship = universe.getShip(ship_id)
            if foAI.foAIstate.get_ship_role(ship.design.id) in [ShipRoleType.MILITARY_INVASION, ShipRoleType.BASE_INVASION]:
                result = fo.issueInvadeOrder(ship_id, planet_id) or result  # will track if at least one invasion troops successfully deployed
                print "Order issued: %s fleet: %s target: %s" % (self.ORDER_NAME, self.fleet, self.target)
                shields = planet.currentMeterValue(fo.meterType.shield)
                owner = planet.owner
                if not result:
                    planet_stealth = planet.currentMeterValue(fo.meterType.stealth)
                    pop = planet.currentMeterValue(fo.meterType.population)
                    detail_str = " -- planet has %.1f stealth, shields %.1f, %.1f population and is owned by empire %d" % (planet_stealth, shields, pop, owner)
                print "Ordered troop ship ID %d to invade %s, got result %d" % (ship_id, planet_name, result), detail_str
                if not result:
                    if 'needsEmergencyExploration' not in dir(foAI.foAIstate):
                        foAI.foAIstate.needsEmergencyExploration = []
                    if fleet.systemID not in foAI.foAIstate.needsEmergencyExploration:
                        foAI.foAIstate.needsEmergencyExploration.append(fleet.systemID)
                        print "Due to trouble invading, adding system %d to Emergency Exploration List" % fleet.systemID
                        self.executed = False
                    if shields > 0 and owner == -1 and dumpTurn < fo.currentTurn():
                        dumpTurn = fo.currentTurn()
                        print "Universe Dump to debug invasions:"
                        universe.dump()
                    break
        if result:
            print "Successfully ordered troop ship(s) to invade %s, with detail %s" % (planet_name, detail_str)
예제 #53
0
def startNewGame(aggression=fo.aggression.aggressive):  # pylint: disable=invalid-name
    """Called by client when a new game is started (but not when a game is loaded).
    Should clear any pre-existing state and set up whatever is needed for AI to generate orders."""
    empire = fo.getEmpire()
    if empire.eliminated:
        print "This empire has been eliminated. Ignoring new game start message."
        return

    turn_timer.start("Server Processing")
    print "New game started, AI Aggression level %d (%s)" % (
        aggression, UserString(_aggression_names[aggression]))

    # initialize AIstate
    global foAIstate
    foAIstate = AIstate.AIstate(aggression=aggression)
    foAIstate.session_start_cleanup()
    print "Initialized foAIstate class"
    planet_id = PlanetUtilsAI.get_capital()
    universe = fo.getUniverse()
    if planet_id is not None and planet_id != -1:
        planet = universe.getPlanet(planet_id)
        new_name = " ".join([
            random.choice(_capitals.get(aggression, []) or [" "]).strip(),
            planet.name
        ])
        print "Capitol City Names are: ", _capitals
        print "This Capitol New name is ", new_name
        res = fo.issueRenameOrder(planet_id, new_name)
        print "Capitol Rename attempt result: %d; planet now named %s" % (
            res, planet.name)

    diplomatic_corp_configs = {
        fo.aggression.beginner: DiplomaticCorp.BeginnerDiplomaticCorp,
        fo.aggression.maniacal: DiplomaticCorp.ManiacalDiplomaticCorp
    }
    global diplomatic_corp
    diplomatic_corp = diplomatic_corp_configs.get(
        aggression, DiplomaticCorp.DiplomaticCorp)()
예제 #54
0
def startNewGame(aggression_input=fo.aggression.aggressive):  # pylint: disable=invalid-name
    """Called by client when a new game is started (but not when a game is loaded).
    Should clear any pre-existing state and set up whatever is needed for AI to generate orders."""
    empire = fo.getEmpire()
    if empire is None:
        fatal("This client has no empire. Ignoring new game start message.")
        return

    if empire.eliminated:
        info(
            "This empire has been eliminated. Ignoring new game start message."
        )
        return

    turn_timer.start("Server Processing")

    # initialize AIstate
    debug("Initializing AI state...")
    create_new_aistate(aggression_input)
    aistate = get_aistate()
    aggression_trait = aistate.character.get_trait(Aggression)
    debug("New game started, AI Aggression level %d (%s)" %
          (aggression_trait.key, get_trait_name_aggression(aistate.character)))
    aistate.session_start_cleanup()
    debug("Initialization of AI state complete!")
    debug("Trying to rename our homeworld...")
    planet_id = PlanetUtilsAI.get_capital()
    universe = fo.getUniverse()
    if planet_id is not None and planet_id != INVALID_ID:
        planet = universe.getPlanet(planet_id)
        new_name = " ".join([
            random.choice(possible_capitals(aistate.character)).strip(),
            planet.name
        ])
        debug("    Renaming to %s..." % new_name)
        res = fo.issueRenameOrder(planet_id, new_name)
        debug("    Result: %d; Planet is now named %s" % (res, planet.name))
    _pre_game_start(empire.empireID, aistate)
예제 #55
0
    def _check_abort_mission(self, fleet_order):
        """ checks if current mission (targeting a planet) should be aborted"""
        planet = fo.getUniverse().getPlanet(fleet_order.target.target_id)
        if planet:
            order_type = fleet_order.order_type
            if order_type == AIFleetOrderType.ORDER_COLONISE:
                if planet.currentMeterValue(fo.meterType.population) == 0 and (planet.ownedBy(fo.empireID()) or planet.unowned):
                    return False
            elif order_type == AIFleetOrderType.ORDER_OUTPOST:
                if planet.unowned:
                    return False
            elif order_type == AIFleetOrderType.ORDER_INVADE: #TODO add substantive abort check
                return False
            else:
                return False

        # canceling fleet orders
        print "   %s" % fleet_order
        print "Fleet %d had a target planet that is no longer valid for this mission; aborting." % self.target_id
        self.clear_fleet_orders()
        self.clear_targets(([-1] + self.get_mission_types()[:1])[-1])
        FleetUtilsAI.split_fleet(self.target_id)
        return True
예제 #56
0
    def __init__(self):
        universe = fo.getUniverse()

        resource_timer.start("getPlanets")
        planet_ids = list(PlanetUtilsAI.get_owned_planets_by_empire())

        resource_timer.start("Targets")
        self.all_planet_info = {
            pid: PlanetFocusInfo(universe.getPlanet(pid))
            for pid in planet_ids
        }

        self.raw_planet_info = dict(self.all_planet_info)
        self.baked_planet_info = {}
        for pid, pinfo in list(self.raw_planet_info.items()):
            if not pinfo.planet.availableFoci:
                self.baked_planet_info[pid] = self.raw_planet_info.pop(pid)
        aistate = get_aistate()
        self.priority = (
            aistate.get_priority(PriorityType.RESOURCE_PRODUCTION),
            aistate.get_priority(PriorityType.RESOURCE_RESEARCH),
            aistate.get_priority(PriorityType.RESOURCE_INFLUENCE),
        )
예제 #57
0
def set_planet_production_and_research_specials(focus_manager):
    """Set production and research specials.
    Sets production/research specials for known (COMPUTRONIUM, HONEYCOMB and CONC_CAMP)
    production/research specials.
    Remove planets from list of candidates using bake_future_focus."""
    # TODO use "best" COMPUTRON planet instead of first found, where "best" means least industry loss,
    # least threatened, no foci change penalty etc.
    universe = fo.getUniverse()
    already_have_comp_moon = False
    for pid, pinfo in focus_manager.raw_planet_info.items():
        planet = pinfo.planet
        if (AIDependencies.COMPUTRONIUM_SPECIAL in planet.specials and
                RESEARCH in planet.availableFoci and not already_have_comp_moon):
            if focus_manager.bake_future_focus(pid, RESEARCH):
                already_have_comp_moon = True
                print "%s focus of planet %s (%d) (with Computronium Moon) at Research Focus" % (
                    ["set", "left"][pinfo.current_focus == RESEARCH], planet.name, pid)
                continue
        if "HONEYCOMB_SPECIAL" in planet.specials and INDUSTRY in planet.availableFoci:
            if focus_manager.bake_future_focus(pid, INDUSTRY):
                print "%s focus of planet %s (%d) (with Honeycomb) at Industry Focus" % (
                    ["set", "left"][pinfo.current_focus == INDUSTRY], planet.name, pid)
                continue
        if ((([bld.buildingTypeName for bld in map(universe.getBuilding, planet.buildingIDs) if bld.buildingTypeName in
               ["BLD_CONC_CAMP", "BLD_CONC_CAMP_REMNANT"]])
             or ([ccspec for ccspec in planet.specials if ccspec in
                  ["CONC_CAMP_MASTER_SPECIAL", "CONC_CAMP_SLAVE_SPECIAL"]]))
                and INDUSTRY in planet.availableFoci):
            if focus_manager.bake_future_focus(pid, INDUSTRY):
                print "%s focus of planet %s (%d) (with Concentration Camps/Remnants) at Industry Focus" % (
                    ["set", "left"][pinfo.current_focus == INDUSTRY], planet.name, pid)
                continue
            else:
                new_planet = universe.getPlanet(pid)
                warn("Failed setting %s for Concentration Camp planet %s (%d)"
                     " with species %s and current focus %s, but new planet copy shows %s" % (
                        pinfo.future_focus, planet.name, pid, planet.speciesName, planet.focus, new_planet.focus))
예제 #58
0
def can_travel_to_system_and_return_to_resupply(fleet_id, from_system_target, to_system_target):
    """
    Filter systems where fleet can travel from starting system. # TODO rename function
    
    :param fleet_id:
    :type fleet_id: int
    :param from_system_target:
    :type from_system_target: universe_object.System
    :param to_system_target:
    :type to_system_target: universe_object.System
    :return:
    :rtype: list
    """
    system_targets = []
    if not from_system_target.id == to_system_target.id:
        # get supplyable systems
        empire = fo.getEmpire()
        fleet_supplyable_system_ids = empire.fleetSupplyableSystemIDs
        # get current fuel and max fuel
        universe = fo.getUniverse()
        fleet = universe.getFleet(fleet_id)
        max_fuel = int(fleet.maxFuel)
        fuel = int(fleet.fuel)
        # if verbose:
        # print "   fleet ID %d has %.1f fuel to get from %s to %s"%(fleetID, fuel, fromSystemAITarget, toSystemAITarget )

        # try to find path without going resupply first
        supply_system_target = get_nearest_supplied_system(to_system_target.id)
        system_targets = __find_path_with_fuel_to_system_with_possible_return(from_system_target, to_system_target, system_targets, fleet_supplyable_system_ids, max_fuel, fuel, supply_system_target)
        # resupply in system first is required to find path
        if from_system_target.id not in fleet_supplyable_system_ids and not system_targets:
            # add supply system to visit
            from_system_target = get_nearest_supplied_system(from_system_target.id)
            system_targets.append(from_system_target)
            # find path from supplied system to wanted system
            system_targets = __find_path_with_fuel_to_system_with_possible_return(from_system_target, to_system_target, system_targets, fleet_supplyable_system_ids, max_fuel, max_fuel, supply_system_target)
    return system_targets
예제 #59
0
def _evaluate_specials(planet: fo.planet, species: fo.species) -> float:
    universe = fo.getUniverse()
    system = universe.getSystem(planet.systemID)
    result = 0.0
    for pid in system.planetIDs:
        if pid == planet.id:
            value = AIDependencies.STABILITY_PER_LIKED_SPECIAL_ON_PLANET
            eval_planet = planet
        else:
            value = AIDependencies.STABILITY_PER_LIKED_SPECIAL_IN_SYSTEM
            eval_planet = universe.getPlanet(pid)
        for special in eval_planet.specials:
            if special in species.likes:
                result += value
            if special in species.dislikes:
                result -= value
    if have_worldtree() and not AIDependencies.not_affect_by_special(
            AIDependencies.WORLDTREE_SPECIAL, species.name):
        result += AIDependencies.STABILITY_BY_WORLDTREE
    gaia = AIDependencies.GAIA_SPECIAL
    if gaia in planet.specials and not AIDependencies.not_affect_by_special(
            gaia, species):
        result += 5  # TBD add named real
    return result
예제 #60
0
def merge_fleet_a_into_b(fleet_a_id, fleet_b_id, leave_rating=0, need_rating=0, context=""):
    universe = fo.getUniverse()
    fleet_a = universe.getFleet(fleet_a_id)
    fleet_b = universe.getFleet(fleet_b_id)
    if not fleet_a or not fleet_b:
        return 0
    remaining_rating = CombatRatingsAI.get_fleet_rating(fleet_a_id)
    transferred_rating = 0
    b_has_monster = False
    for ship_id in fleet_b.shipIDs:
        this_ship = universe.getShip(ship_id)
        if not this_ship:
            continue
        if this_ship.isMonster:
            b_has_monster = True
            break
    for ship_id in fleet_a.shipIDs:
        this_ship = universe.getShip(ship_id)
        if not this_ship or this_ship.isMonster != b_has_monster:  # TODO Is there any reason for the monster check?
            continue
        this_rating = CombatRatingsAI.ShipCombatStats(ship_id).get_rating()
        remaining_rating = CombatRatingsAI.rating_needed(remaining_rating, this_rating)
        if remaining_rating < leave_rating:  # merging this would leave old fleet under minimum rating, try other ships.
            continue
        transferred = fo.issueFleetTransferOrder(ship_id, fleet_b_id)
        if transferred:
            transferred_rating = CombatRatingsAI.combine_ratings(transferred_rating, this_rating)
        else:
            print "  *** transfer of ship %4d, formerly of fleet %4d, into fleet %4d failed; %s" % (
                ship_id, fleet_a_id, fleet_b_id, (" context is %s" % context) if context else "")
        if need_rating != 0 and need_rating <= transferred_rating:
            break
    fleet_a = universe.getFleet(fleet_a_id)
    if not fleet_a or fleet_a.empty or fleet_a_id in universe.destroyedObjectIDs(fo.empireID()):
        foAI.foAIstate.delete_fleet_info(fleet_a_id)
    foAI.foAIstate.update_fleet_rating(fleet_b_id)