def resumeLoadedGame(saved_state_string): # pylint: disable=invalid-name """Called by client to when resume a loaded game.""" if fo.getEmpire() is None: print "This client has no empire. Doing nothing to resume loaded game." return if fo.getEmpire().eliminated: print "This empire has been eliminated. Ignoring resume loaded game." return turn_timer.start("Server Processing") global foAIstate print "Resuming loaded game" if not saved_state_string: print_error("AI given empty state-string to resume from; this is expected if the AI is assigned to an empire " "previously run by a human, but is otherwise an error. AI will be set to Aggressive.") foAIstate = AIstate.AIstate(fo.aggression.aggressive) foAIstate.session_start_cleanup() else: try: # loading saved state # pre load code foAIstate = pickle.loads(saved_state_string) except Exception as e: # assigning new state foAIstate = AIstate.AIstate(fo.aggression.aggressive) foAIstate.session_start_cleanup() print_error("Fail to load aiState from saved game: %s" % e) aggression_trait = foAIstate.character.get_trait(Aggression) 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()
def handle_diplomatic_message(self, message): """Handle a diplomatic message update from the server, such as if another player declares war, accepts peace, or cancels a proposed peace treaty. :param message: message.recipient and message.sender are respective empire IDs :return: """ debug("Received diplomatic %s message from %s to %s." % ( message.type, fo.getEmpire(message.sender), 'me' if message.recipient == fo.empireID() else fo.getEmpire(message.recipient))) # TODO: remove the following early return once proper support for third party diplomatic history is added if message.recipient != fo.empireID(): return aistate = get_aistate() if message.type == fo.diplomaticMessageType.peaceProposal: aistate.log_peace_request(message.sender, message.recipient) proposal_sender_player = fo.empirePlayerID(message.sender) attitude = aistate.character.attitude_to_empire(message.sender, aistate.diplomatic_logs) possible_acknowledgments = [] aggression = aistate.character.get_trait(Aggression) if aggression.key <= fo.aggression.typical: possible_acknowledgments = UserStringList("AI_PEACE_PROPOSAL_ACKNOWLEDGEMENTS_MILD_LIST") if attitude > 0: possible_replies = UserStringList("AI_PEACE_PROPOSAL_RESPONSES_YES_MILD_LIST") else: possible_replies = UserStringList("AI_PEACE_PROPOSAL_RESPONSES_NO_MILD_LIST") else: possible_acknowledgments = UserStringList("AI_PEACE_PROPOSAL_ACKNOWLEDGEMENTS_HARSH_LIST") if attitude > 0: possible_replies = UserStringList("AI_PEACE_PROPOSAL_RESPONSES_YES_HARSH_LIST") else: possible_replies = UserStringList("AI_PEACE_PROPOSAL_RESPONSES_NO_HARSH_LIST") acknowledgement = random.choice(possible_acknowledgments) reply_text = random.choice(possible_replies) debug("Acknowledging proposal with initial message (from %d choices): '%s'" % ( len(possible_acknowledgments), acknowledgement)) fo.sendChatMessage(proposal_sender_player, acknowledgement) if attitude > 0: diplo_reply = fo.diplomaticMessage(message.recipient, message.sender, fo.diplomaticMessageType.acceptPeaceProposal) debug("Sending diplomatic message to empire %s of type %s" % (message.sender, diplo_reply.type)) fo.sendDiplomaticMessage(diplo_reply) debug("sending chat to player %d of empire %d, message body: '%s'" % ( proposal_sender_player, message.sender, reply_text)) fo.sendChatMessage(proposal_sender_player, reply_text) elif message.type == fo.diplomaticMessageType.warDeclaration: # note: apparently this is currently (normally?) sent not as a warDeclaration, # but as a simple diplomatic_status_update to war aistate.log_war_declaration(message.sender, message.recipient)
def _planned_species() -> Mapping[PlanetId, SpeciesName]: universe = fo.getUniverse() production_queue = fo.getEmpire().productionQueue planned_species = {} colonisation_plans = get_aistate().colonisablePlanetIDs for element in production_queue: species_name = _get_species_from_colony_building(element.name) if species_name: planned_species[element.locationID] = species_name for pid in get_owned_planets_by_empire(): planet = universe.getPlanet(pid) if planet.speciesName: # skip already populated planets continue # Finished colony buildings are normal buildings for one turn before turning the outpost into a colony for building in map(universe.getBuilding, planet.buildingIDs): species_name = _get_species_from_colony_building(building.name) if species_name: planned_species[pid] = species_name break if pid not in planned_species: # Without checking the colonisation plans, the AI may start building a colony and buildings # the future species wouldn't like in the same turn. plan = colonisation_plans.get(pid) if plan: planned_species[pid] = plan[1] debug(f"Planned species: {planned_species}") return planned_species
def calculateExplorationPriority(): """calculates the demand for scouts by unexplored systems""" global scoutsNeeded universe = fo.getUniverse() empire = fo.getEmpire() numUnexploredSystems = len( ExplorationAI.borderUnexploredSystemIDs ) #len(foAI.foAIstate.get_explorable_systems(AIExplorableSystemType.EXPLORABLE_SYSTEM_UNEXPLORED)) numScouts = sum( [ foAI.foAIstate.fleetStatus.get(fid, {}).get('nships', 0) for fid in FleetUtilsAI.get_empire_fleet_ids_by_role( EnumsAI.AIFleetMissionType.FLEET_MISSION_EXPLORATION)] ) # FleetUtilsAI.get_empire_fleet_ids_by_role(AIFleetMissionType.FLEET_MISSION_EXPLORATION) productionQueue = empire.productionQueue queuedScoutShips=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) == EnumsAI.AIShipRoleType.SHIP_ROLE_CIVILIAN_EXPLORATION : queuedScoutShips += element.remaining * element.blocksize milShips = MilitaryAI.num_milships # intent of the following calc is essentially # new_scouts_needed = min(need_cap_A, need_cap_B, base_need) - already_got_or_queued # where need_cap_A is to help prevent scouting needs from swamping military needs, and # need_cap_B is to help regulate investment into scouting while the empire is small. # These caps could perhaps instead be tied more directly to military priority and # total empire production. scoutsNeeded = max(0, min( 4+int(milShips/5), 4+int(fo.currentTurn()/50) , 2+ numUnexploredSystems**0.5 ) - numScouts - queuedScoutShips ) explorationPriority = int(40*scoutsNeeded) print print "Number of Scouts : " + str(numScouts) print "Number of Unexplored systems: " + str(numUnexploredSystems) print "military size: ", milShips print "Priority for scouts : " + str(explorationPriority) return explorationPriority
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 print "Initializing foAIstate..." foAIstate = AIstate.AIstate(aggression) 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 != -1: planet = universe.getPlanet(planet_id) new_name = " ".join([random.choice(_capitals.get(aggression, []) or [" "]).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, DiplomaticCorp.DiplomaticCorp)() TechsListsAI.test_tech_integrity()
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: fleet_supplyable_system_ids = fo.getEmpire().fleetSupplyableSystemIDs fuel = int(FleetUtilsAI.get_fuel(fleet_id)) # int to get actual number of jumps max_fuel = int(FleetUtilsAI.get_max_fuel(fleet_id)) # 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
def prepareForSave(): # pylint: disable=invalid-name """Called by client when the game is about to be saved, to let the Python AI know it should save any AI state information, such as plans or knowledge about the game from previous turns, in the state string so that they can be restored if the game is loaded.""" empire = fo.getEmpire() if empire is None: fatal("This client has no empire. Doing nothing to prepare for save.") return if empire.eliminated: info("This empire has been eliminated. Save info request") return info("Preparing for game save by serializing state") # serialize (convert to string) global state dictionary and send to AI client to be stored in save file import savegame_codec try: dump_string = savegame_codec.build_savegame_string() fo.setSaveStateString(dump_string) except Exception as e: error( "Failed to encode the AIstate as save-state string. " "The resulting save file should be playable but the AI " "may have a different aggression. The error raised was: %s" % e, exc_info=True, )
def can_travel_to_system_and_return_to_resupply(fleet_id, from_system_target, to_system_target): """ Check if fleet can travel from starting system to wanted system.""" system_targets = [] if not from_system_target.target_id == to_system_target.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.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 not from_system_target.target_id in fleet_supplyable_system_ids and not system_targets: # add supply system to visit from_system_target = get_nearest_supplied_system(from_system_target.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
def trooper_move_reqs_met(main_fleet_mission, order, verbose): """ Indicates whether or not move requirements specific to invasion troopers are met for the provided mission and order. :type main_fleet_mission: AIFleetMission.AIFleetMission :type order: OrderMove :param verbose: whether to print verbose decision details :type verbose: bool :rtype: bool """ # Don't advance outside of our fleet-supply zone unless the target either has no shields at all or there # is already a military fleet assigned to secure the target, and don't take final jump unless the planet is # (to the AI's knowledge) down to zero shields. Additional checks will also be done by the later # generic movement code invasion_target = main_fleet_mission.target invasion_planet = invasion_target.get_object() invasion_system = invasion_target.get_system() supplied_systems = fo.getEmpire().fleetSupplyableSystemIDs # if about to leave supply lines if order.target.id not in supplied_systems or fo.getUniverse( ).jumpDistance(order.fleet.id, invasion_system.id) < 5: if invasion_planet.currentMeterValue(fo.meterType.maxShield): military_support_fleets = MilitaryAI.get_military_fleets_with_target_system( invasion_system.id) if not military_support_fleets: if verbose: debug( "trooper_move_reqs_met() holding Invasion fleet %d before leaving supply " "because target (%s) has nonzero max shields and there is not yet a military fleet " "assigned to secure the target system." % (order.fleet.id, invasion_planet)) return False # if there is a threat in the enemy system, do give military ships at least 1 turn to clear it delay_to_move_troops = 1 if MilitaryAI.get_system_local_threat( order.target.id) else 0 def eta(fleet_id): return FleetUtilsAI.calculate_estimated_time_of_arrival( fleet_id, invasion_system.id) eta_this_fleet = eta(order.fleet.id) if all(((eta_this_fleet - delay_to_move_troops) <= eta(fid) and eta(fid)) for fid in military_support_fleets): if verbose: debug( "trooper_move_reqs_met() holding Invasion fleet %d before leaving supply " "because target (%s) has nonzero max shields and no assigned military fleet would arrive" "at least %d turn earlier than the invasion fleet" % (order.fleet.id, invasion_planet, delay_to_move_troops)) return False if verbose: debug( "trooper_move_reqs_met() allowing Invasion fleet %d to leave supply " "because target (%s) has zero max shields or there is a military fleet assigned to secure " "the target system which will arrive at least 1 turn before the invasion fleet.", order.fleet.id, invasion_planet) return True
def getInvasionFleets(): "get invasion fleets" allInvasionFleetIDs = FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_INVASION) AIstate.invasionFleetIDs = FleetUtilsAI.extractFleetIDsWithoutMissionTypes(allInvasionFleetIDs) # get supplyable planets universe = fo.getUniverse() empire = fo.getEmpire() empireID = empire.empireID fleetSupplyableSystemIDs = empire.fleetSupplyableSystemIDs fleetSupplyablePlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(fleetSupplyableSystemIDs) # get competitor planets exploredSystemIDs = empire.exploredSystemIDs exploredPlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(exploredSystemIDs) allOwnedPlanetIDs = PlanetUtilsAI.getAllOwnedPlanetIDs(exploredPlanetIDs) # print "All Owned and Populated PlanetIDs: " + str(allOwnedPlanetIDs) empireOwnedPlanetIDs = PlanetUtilsAI.getOwnedPlanetsByEmpire(universe.planetIDs, empireID) # print "Empire Owned PlanetIDs: " + str(empireOwnedPlanetIDs) competitorPlanetIDs = list(set(allOwnedPlanetIDs) - set(empireOwnedPlanetIDs)) print "Competitor PlanetIDs: " + str(competitorPlanetIDs) print "" print "Invasion Targeted SystemIDs: " + str(AIstate.invasionTargetedSystemIDs) invasionTargetedPlanetIDs = getInvasionTargetedPlanetIDs(universe.planetIDs, AIFleetMissionType.FLEET_MISSION_INVASION, empireID) allInvasionTargetedSystemIDs = PlanetUtilsAI.getSystems(invasionTargetedPlanetIDs) # export invasion targeted systems for other AI modules AIstate.invasionTargetedSystemIDs = allInvasionTargetedSystemIDs print "Invasion Targeted PlanetIDs: " + str(invasionTargetedPlanetIDs) invasionFleetIDs = FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_INVASION) if not invasionFleetIDs: print "Available Invasion Fleets: 0" else: print "Invasion FleetIDs: " + str(FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_INVASION)) numInvasionFleets = len(FleetUtilsAI.extractFleetIDsWithoutMissionTypes(invasionFleetIDs)) print "Invasion Fleets Without Missions: " + str(numInvasionFleets) evaluatedPlanetIDs = list(set(competitorPlanetIDs) - set(invasionTargetedPlanetIDs)) # print "Evaluated PlanetIDs: " + str(evaluatedPlanetIDs) evaluatedPlanets = assignInvasionValues(evaluatedPlanetIDs, AIFleetMissionType.FLEET_MISSION_INVASION, fleetSupplyablePlanetIDs, empire) sortedPlanets = evaluatedPlanets.items() sortedPlanets.sort(lambda x, y: cmp(x[1], y[1]), reverse=True) print "" print "Invadable planetIDs:" for evaluationPair in sortedPlanets: print " ID|Score: " + str(evaluationPair) # export opponent planets for other AI modules AIstate.opponentPlanetIDs = sortedPlanets
def printResourcesPriority(): "calculate top resource priority" universe = fo.getUniverse() empire = fo.getEmpire() empireID = empire.empireID ownedPlanetIDs = PlanetUtilsAI.getOwnedPlanetsByEmpire(universe.planetIDs, empireID) print "Resource Management:" print "" print "Resource Priorities:" resourcePriorities = {} for priorityType in getAIPriorityResourceTypes(): resourcePriorities[priorityType] = foAI.foAIstate.getPriority(priorityType) sortedPriorities = resourcePriorities.items() sortedPriorities.sort(lambda x,y: cmp(x[1], y[1]), reverse=True) topPriority = -1 for evaluationPair in sortedPriorities: if topPriority < 0: topPriority = evaluationPair[0] print " ID|Score: " + str(evaluationPair) print " Top Resource Priority: " + str(topPriority) # what is the focus of available resource centers? print "" print "Planet Resources Foci:" for planetID in ownedPlanetIDs: planet = universe.getPlanet(planetID) planetPopulation = planet.currentMeterValue(fo.meterType.population) print " ID: " + str(planetID) + " Name: " + str(planet.name) + " Type: " + str(planet.type) + " Size: " + str(planet.size) + " Focus: " + str(planet.focus) + " Species: " + str(planet.speciesName) + " Population: " + str(planetPopulation)
def startNewGame(aggression=4): global __timerFile, lastTurnTimestamp, __timerBucketFile print "New game started, AI Agression level %d"%aggression # initialize AIstate global foAIstate foAIstate = AIstate.AIstate(aggression=aggression) foAIstate.sessionStartCleanup() print "Initialized foAIstate class" if __timerFile: __timerFile.close() if ResourcesAI.resourceTimerFile: ResourcesAI.resourceTimerFile.close() empireID = fo.getEmpire().empireID try: if os.path.exists("timers") and os.path.isdir("timers"): timerpath="timers"+os.path.sep+"timer_%02d.dat"%(empireID-1) __timerFile = open(timerpath, 'w') __timerFile.write("Turn\t" + "\t".join(__timerEntries) +'\n') timerBucketpath="timers"+os.path.sep+"timer_bucket_%02d.dat"%(empireID-1) __timerBucketFile = open(timerBucketpath, 'w') __timerBucketFile.write("Turn\t" + "\t".join(__timerBucketEntries) +'\n') lastTurnTimestamp = time() if ResourcesAI.doResourceTiming: ResourcesAI.resourceTimerFile = open("timers"+os.path.sep+"resourceTimer_%2d.dat"%(empireID-1), 'w') ResourcesAI.resourceTimerFile.write("Turn\t"+ "\t".join(ResourcesAI.__timerEntries)+"\n") print "timer file saved at "+timerpath except: __timerFile=None ResourcesAI.resourceTimerFile =None ResourcesAI.doResourceTiming = False print "Error: exception caught starting timing: ", traceback.format_exc() print "won't record timing info"
def _calculate_exploration_priority(): """Calculates the demand for scouts by unexplored systems.""" empire = fo.getEmpire() num_unexplored_systems = len(ExplorationAI.border_unexplored_system_ids) num_scouts = sum([foAI.foAIstate.fleetStatus.get(fid, {}).get('nships', 0) for fid in FleetUtilsAI.get_empire_fleet_ids_by_role( MissionType.EXPLORATION)]) production_queue = empire.productionQueue queued_scout_ships = 0 for queue_index in range(0, len(production_queue)): element = production_queue[queue_index] if element.buildType == EmpireProductionTypes.BT_SHIP: if foAI.foAIstate.get_ship_role(element.designID) == ShipRoleType.CIVILIAN_EXPLORATION: queued_scout_ships += element.remaining * element.blocksize mil_ships = MilitaryAI.get_num_military_ships() # intent of the following calc is essentially # new_scouts_needed = min(need_cap_A, need_cap_B, base_need) - already_got_or_queued # where need_cap_A is to help prevent scouting needs from swamping military needs, and # need_cap_B is to help regulate investment into scouting while the empire is small. # These caps could perhaps instead be tied more directly to military priority and # total empire production. desired_number_of_scouts = int(min(4 + mil_ships/5, 4 + fo.currentTurn()/50.0, 2 + num_unexplored_systems**0.5)) scouts_needed = max(0, desired_number_of_scouts - (num_scouts + queued_scout_ships)) exploration_priority = int(40 * scouts_needed) print print "Number of Scouts: %s" % num_scouts print "Number of Unexplored systems: %s" % num_unexplored_systems print "Military size: %s" % mil_ships print "Priority for scouts: %s" % exploration_priority return exploration_priority
def _get_modified_research_bonuses(planet: fo.planet) -> List[Bonus]: """ Get list of per-population bonuses which are added before multiplication with the species skill value. """ # use fo.getEmpire().researchQueue directly here to simplify caching this function specials = planet.specials return [ Bonus( AIDependencies.ANCIENT_RUINS_SPECIAL in specials or AIDependencies.ANCIENT_RUINS_SPECIAL2 in specials, get_named_real("ANCIENT_RUINS_MIN_STABILITY"), get_named_real("ANCIENT_RUINS_TARGET_RESEARCH_PERPOP"), ), Bonus( fo.getEmpire().policyAdopted("PLC_DIVERSITY"), get_named_real("PLC_DIVERSITY_MIN_STABILITY"), (len(get_empire_planets_by_species()) - get_named_int("PLC_DIVERSITY_THRESHOLD")) * get_named_real("PLC_DIVERSITY_SCALING"), ), Bonus( tech_soon_available("GRO_ENERGY_META", 3), get_named_real("GRO_ENERGY_META_MIN_STABILITY"), get_named_real("GRO_ENERGY_META_TARGET_RESEARCH_PERPOP"), ), Bonus( bool(BuildingType.ENCLAVE_VOID.built_or_queued_at()), get_named_real("BLD_ENCLAVE_VOID_MIN_STABILITY"), get_named_real("BLD_ENCLAVE_VOID_TARGET_RESEARCH_PERPOP"), ), ]
def dislike_factor() -> float: """Returns multiplier for dislike effects.""" # See happiness.macros has_liberty = fo.getEmpire().policyAdopted("PLC_LIBERTY") # conformance not used yet return fo.getNamedValue( "PLC_LIBERTY_DISLIKE_FACTOR") if has_liberty else 1.0
def startNewGame(): # 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 # initialize AIstate debug("Initializing AI state...") aistate = create_new_aistate(_choose_aggression()) 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 != 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)
def print_resource_ai_footer(): empire = fo.getEmpire() pp, rp = empire.productionPoints, empire.resourceProduction(fo.resourceType.research) # Next string used in charts. Don't modify it! print "Current Output (turn %4d) RP/PP : %.2f ( %.1f / %.1f )" % (fo.currentTurn(), rp / (pp + 0.0001), rp, pp) print "------------------------" print "ResourcesAI Time Requirements:"
def calculateFoodPriority(): "calculates the AI's need for food" # attempts to sustain a food stockpile whose size depends on the AI empires population # foodStockpile == 0 => returns 100, foodStockpile == foodTarget => returns 0 empire = fo.getEmpire() foodProduction = empire.resourceProduction(fo.resourceType.food) foodStockpile = empire.resourceStockpile(fo.resourceType.food) foodTarget = 10 * empire.population() * AIstate.foodStockpileSize if (foodTarget == 0): return 0 foodPriority = (foodTarget - foodStockpile) / foodTarget * 115 print "" print "Food Production: " + str(foodProduction) print "Size of Food Stockpile: " + str(foodStockpile) print "Target Food Stockpile : " + str (foodTarget) print "Priority for Food : " + str(foodPriority) if foodPriority < 0: return 0 return foodPriority
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)()
def __cleanExplorableSystems(self, startSystemID): "cleanup of all explorable systems" universe = fo.getUniverse() systemIDs = universe.systemIDs empireID = fo.empireID() empire = fo.getEmpire() for systemID in systemIDs: system = universe.getSystem(systemID) if not system: continue #print "system with id: " + str(systemID) if (empire.hasExploredSystem(systemID)): self.addExplorableSystem(AIExplorableSystemType.EXPLORABLE_SYSTEM_EXPLORED, systemID) self.removeExplorableSystem(AIExplorableSystemType.EXPLORABLE_SYSTEM_UNEXPLORED, systemID) #print " has been explored" continue if (startSystemID == -1 or not universe.systemsConnected(systemID, startSystemID, empireID)): for explorableSystemsType in EnumsAI.getAIExplorableSystemTypes(): self.removeExplorableSystem(explorableSystemsType, systemID) #print " is not connected to system with id: " + str(startSystemID) continue explorableSystemsType = self.getExplorableSystem(systemID) if (explorableSystemsType == AIExplorableSystemType.EXPLORABLE_SYSTEM_VISIBLE): #print " is already explored system target" continue #print " is now an unexplored system" self.addExplorableSystem(AIExplorableSystemType.EXPLORABLE_SYSTEM_UNEXPLORED, systemID)
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()
def prepareForSave(): # pylint: disable=invalid-name """Called by client when the game is about to be saved, to let the Python AI know it should save any AI state information, such as plans or knowledge about the game from previous turns, in the state string so that they can be restored if the game is loaded.""" empire = fo.getEmpire() if empire is None: print "This client has no empire. Doing nothing to prepare for save." return if empire.eliminated: info("This empire has been eliminated. Save info request") return info("Preparing for game save by serializing state") # serialize (convert to string) global state dictionary and send to AI client to be stored in save file try: dump_string = pickle.dumps(foAIstate) print "foAIstate pickled to string, about to send to server" fo.setSaveStateString(dump_string) except: error( "foAIstate unable to pickle save-state string; " "the save file should be playable but the AI may have a different aggression.", exc_info=True)
def calculateIndustryPriority(): "calculates the demand for industry" universe = fo.getUniverse() empire = fo.getEmpire() empireID = empire.empireID # get current industry production & Target industryProduction = empire.resourceProduction(fo.resourceType.industry) ownedPlanetIDs = PlanetUtilsAI.getOwnedPlanetsByEmpire(universe.planetIDs, empireID) planets = map(universe.getPlanet, ownedPlanetIDs) targetPP = sum( map( lambda x: x.currentMeterValue(fo.meterType.targetIndustry), planets) ) if fo.currentTurn() < 20: industryPriority = 20 # mid industry , high research at beginning of game to get easy gro tech elif fo.currentTurn() < 30: industryPriority = 25 # mid industry , mid research elif fo.currentTurn() < 40: industryPriority = 40 # high industry , mid research elif fo.currentTurn() < 50: industryPriority = 50 # high industry , mid research else: industryPriority = 60 # high industry , low-mid research # increase demand for industry industry production is low #industryPriority = 380 / (industryProduction + 0.001) print "" print "Industry Production (current/target) : ( %.1f / %.1f ) at turn %s"%(industryProduction, targetPP, fo.currentTurn()) print "Priority for Industry: " + str(industryPriority) return industryPriority
def calculateResearchPriority(): "calculates the AI empire's demand for research" universe = fo.getUniverse() empire = fo.getEmpire() empireID = empire.empireID gotAlgo = empire.getTechStatus("LRN_ALGO_ELEGANCE") == fo.techStatus.complete totalPP = empire.productionPoints totalRP = empire.resourceProduction(fo.resourceType.research) # get current industry production & Target ownedPlanetIDs = PlanetUtilsAI.getOwnedPlanetsByEmpire(universe.planetIDs, empireID) planets = map(universe.getPlanet, ownedPlanetIDs) targetRP = sum( map( lambda x: x.currentMeterValue(fo.meterType.targetResearch), planets) ) if (fo.currentTurn() < 20) or not gotAlgo: researchPriority = 60 # mid industry , high research at beginning of game to get easy gro tech and to get research booster Algotrithmic Elegance elif fo.currentTurn() < 30: researchPriority = 30 # mid industry , mid research elif fo.currentTurn() < 40: researchPriority = 20 # high industry , low research else: researchPriority = 15 # high industry , low research print "" print "Research Production (current/target) : ( %.1f / %.1f )"%(totalRP, targetRP) print "Priority for Research: " + str(researchPriority) return researchPriority
def calculateExplorationPriority(): "calculates the demand for scouts by unexplored systems" universe = fo.getUniverse() empire = fo.getEmpire() numUnexploredSystems = len( ExplorationAI.__borderUnexploredSystemIDs ) #len(foAI.foAIstate.getExplorableSystems(AIExplorableSystemType.EXPLORABLE_SYSTEM_UNEXPLORED)) scoutIDs = ExplorationAI.currentScoutFleetIDs # FleetUtilsAI.getEmpireFleetIDsByRole(AIFleetMissionType.FLEET_MISSION_EXPLORATION) numScouts = len(scoutIDs) productionQueue = empire.productionQueue queuedScoutShips=0 for queue_index in range(0, len(productionQueue)): element=productionQueue[queue_index] if element.buildType == AIEmpireProductionTypes.BT_SHIP: if foAI.foAIstate.getShipRole(element.designID) == AIShipRoleType.SHIP_ROLE_CIVILIAN_EXPLORATION : queuedScoutShips +=element.remaining explorationPriority = 95*math.ceil( math.sqrt(max(0, (numUnexploredSystems - (numScouts+queuedScoutShips)) / (numUnexploredSystems +0.001) ))) print "" print "Number of Scouts : " + str(numScouts) print "Number of Unexplored systems: " + str(numUnexploredSystems) print "Priority for scouts : " + str(explorationPriority) return explorationPriority
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
def prepareForSave(): # pylint: disable=invalid-name """Called by client when the game is about to be saved, to let the Python AI know it should save any AI state information, such as plans or knowledge about the game from previous turns, in the state string so that they can be restored if the game is loaded.""" empire = fo.getEmpire() if empire is None: fatal("This client has no empire. Doing nothing to prepare for save.") return if empire.eliminated: info("This empire has been eliminated. Save info request") return info("Preparing for game save by serializing state") # serialize (convert to string) global state dictionary and send to AI client to be stored in save file import savegame_codec try: dump_string = savegame_codec.build_savegame_string() fo.setSaveStateString(dump_string) except Exception as e: error("Failed to encode the AIstate as save-state string. " "The resulting save file should be playable but the AI " "may have a different aggression. The error raised was: %s" % e, exc_info=True)
def getCapitalID(): "return planetID of empire capital" empire = fo.getEmpire() capitalID = empire.capitalID return capitalID
def can_issue_order(self, verbose=False): if not super(OrderMove, self).can_issue_order(verbose=verbose): return False # TODO: figure out better way to have invasions (& possibly colonizations) require visibility on target without needing visibility of all intermediate systems # if False and main_mission_type not in [AIFleetMissionType.FLEET_MISSION_ATTACK, # TODO: consider this later # AIFleetMissionType.FLEET_MISSION_MILITARY, # AIFleetMissionType.FLEET_MISSION_SECURE, # AIFleetMissionType.FLEET_MISSION_HIT_AND_RUN, # AIFleetMissionType.FLEET_MISSION_EXPLORATION]: # if not universe.getVisibility(target_id, foAI.foAIstate.empireID) >= fo.visibility.partial: # #if not target_id in interior systems # foAI.foAIstate.needsEmergencyExploration.append(fleet.systemID) # return False system_id = self.fleet.get_system().id if system_id == self.target.get_system().id: return True # TODO: already there, but could consider retreating fleet_rating = foAI.foAIstate.get_rating(self.fleet.id).get('overall', 0) target_sys_status = foAI.foAIstate.systemStatus.get(self.target.id, {}) f_threat = target_sys_status.get('fleetThreat', 0) m_threat = target_sys_status.get('monsterThreat', 0) p_threat = target_sys_status.get('planetThreat', 0) threat = f_threat + m_threat + p_threat safety_factor = MilitaryAI.get_safety_factor() universe = fo.getUniverse() if fleet_rating >= safety_factor * threat: return True elif not p_threat and self.target.id in fo.getEmpire().supplyUnobstructedSystems: return True else: sys1 = universe.getSystem(system_id) sys1_name = sys1 and sys1.name or "unknown" targ1 = self.target.get_system() targ1_name = (targ1 and targ1.get_object().name) or "unknown" # following line was poor because AIstate.militaryFleetIDs only covers fleets without current missions # my_other_fleet_rating = sum([foAI.foAIstate.fleetStatus.get(fleet_id, {}).get('rating', 0) for fleet_id in foAI.foAIstate.militaryFleetIDs if ( foAI.foAIstate.fleetStatus.get(fleet_id, {}).get('sysID', -1) == thisSystemID ) ]) # myOtherFleetsRatings = [foAI.foAIstate.fleetStatus.get(fid, {}).get('rating', {}) for fid in foAI.foAIstate.systemStatus.get(target_id, {}).get('myfleets', [])] # my_other_fleet_rating = sum([foAI.foAIstate.fleetStatus.get(fid, {}).get('rating', 0) for fid in foAI.foAIstate.systemStatus.get( target_id, {}).get('myfleets', []) ]) my_other_fleet_rating = foAI.foAIstate.systemStatus.get(self.target.id, {}).get('myFleetRating', 0) # TODO: adjust calc for any departing fleets is_military = foAI.foAIstate.get_fleet_role(self.fleet.id) == AIFleetMissionType.FLEET_MISSION_MILITARY if ((my_other_fleet_rating > 3 * safety_factor * threat) or (is_military and my_other_fleet_rating + fleet_rating > safety_factor * threat) or (is_military and my_other_fleet_rating + fleet_rating > 0.8 * safety_factor * threat and fleet_rating > 0.2 * threat)): if verbose: print "\tAdvancing fleet %d (rating %d) at system %d (%s) into system %d (%s) with threat %d because of sufficient empire fleet strength already at destination" % ( self.fleet.id, fleet_rating, system_id, sys1_name, self.target.id, targ1_name, threat) return True elif threat == p_threat and not self.fleet.get_object().aggressive and not my_other_fleet_rating and not target_sys_status.get('localEnemyFleetIDs', [-1]): if verbose: print ("\tAdvancing fleet %d (rating %d) at system %d (%s) into system %d (%s) with planet threat %d because nonaggressive" + " and no other fleets present to trigger combat") % (self.fleet.id, fleet_rating, system_id, sys1_name, self.target.id, targ1_name, threat) return True else: if verbose: print "\tHolding fleet %d (rating %d) at system %d (%s) before travelling to system %d (%s) with threat %d" % (self.fleet.id, fleet_rating, system_id, sys1_name, self.target.id, targ1_name, threat) needs_vis = foAI.foAIstate.misc.setdefault('needs_vis', []) if self.target.id not in needs_vis: needs_vis.append(self.target.id) return False return True
def setCapitalIDResourceFocus(): "set resource focus of CapitalID planet" universe = fo.getUniverse() empire = fo.getEmpire() empireID = empire.empireID empirePlanetIDs = PlanetUtilsAI.getOwnedPlanetsByEmpire(universe.planetIDs, empireID) capitalID = PlanetUtilsAI.getCapital() topPriority = topResourcePriority() if topPriority == AIPriorityType.PRIORITY_RESOURCE_GROWTH: newFocus = AIFocusType.FOCUS_GROWTH for planetID in empirePlanetIDs: planet = universe.getPlanet(planetID) focus = newFocus if planetID == capitalID and focus in planet.availableFoci: fo.issueChangeFocusOrder(planetID, focus) elif topPriority == AIPriorityType.PRIORITY_RESOURCE_PRODUCTION: newFocus = AIFocusType.FOCUS_INDUSTRY for planetID in empirePlanetIDs: planet = universe.getPlanet(planetID) focus = newFocus if planetID == capitalID and focus in planet.availableFoci: fo.issueChangeFocusOrder(planetID, focus) elif topPriority == AIPriorityType.PRIORITY_RESOURCE_RESEARCH: newFocus = AIFocusType.FOCUS_RESEARCH for planetID in empirePlanetIDs: planet = universe.getPlanet(planetID) focus = newFocus if planetID == capitalID and focus in planet.availableFoci: fo.issueChangeFocusOrder(planetID, focus)
def generateDefaultResearchOrders(): "generate default research orders" empire = fo.getEmpire() totalRP = empire.resourceProduction(fo.resourceType.research) # get all usable researchable techs not already completed or queued for research completedTechs = getCompletedTechs() possibleProjects = getPossibleProjects() researchQueue = empire.researchQueue researchQueueList = getResearchQueueTechs () possibleResearchProjects = (set(possibleProjects)-(set(completedTechs)|set(researchQueueList))) print "Techs in possibleResearchProjects list after enqueues to Research Queue:" for techname in possibleResearchProjects: print " " + techname print "" # store projects mapped to their costs, so they can be sorted by that cost projectsDict = dict() for name in possibleResearchProjects: projectsDict[name] = fo.getTech(name).researchCost(empire.empireID) # iterate through techs in order of cost print "enqueuing techs. already spent RP: " + str(spentRP()) + " total RP: " + str(totalRP) for name, cost in sorted(projectsDict.items(), key=lambda(k, v):(v, k)): # abort if no RP left if spentRP() >= totalRP: break # add tech to queue fo.issueEnqueueTechOrder(name, -1) print " enqueued tech " + name + " : cost: " + str(cost) + "RP" print ""
def _calculate_exploration_priority(): """Calculates the demand for scouts by unexplored systems.""" empire = fo.getEmpire() num_unexplored_systems = len(ExplorationAI.borderUnexploredSystemIDs) num_scouts = sum([foAI.foAIstate.fleetStatus.get(fid, {}).get('nships', 0) for fid in FleetUtilsAI.get_empire_fleet_ids_by_role( MissionType.EXPLORATION)]) production_queue = empire.productionQueue queued_scout_ships = 0 for queue_index in range(0, len(production_queue)): element = production_queue[queue_index] if element.buildType == EmpireProductionTypes.BT_SHIP: if foAI.foAIstate.get_ship_role(element.designID) == ShipRoleType.CIVILIAN_EXPLORATION: queued_scout_ships += element.remaining * element.blocksize mil_ships = MilitaryAI.get_num_military_ships() # intent of the following calc is essentially # new_scouts_needed = min(need_cap_A, need_cap_B, base_need) - already_got_or_queued # where need_cap_A is to help prevent scouting needs from swamping military needs, and # need_cap_B is to help regulate investment into scouting while the empire is small. # These caps could perhaps instead be tied more directly to military priority and # total empire production. desired_number_of_scouts = int(min(4 + mil_ships/5, 4 + fo.currentTurn()/50.0, 2 + num_unexplored_systems**0.5)) scouts_needed = max(0, desired_number_of_scouts - (num_scouts + queued_scout_ships)) exploration_priority = int(40 * scouts_needed) print print "Number of Scouts: %s" % num_scouts print "Number of Unexplored systems: %s" % num_unexplored_systems print "Military size: %s" % mil_ships print "Priority for scouts: %s" % exploration_priority return exploration_priority
def resumeLoadedGame(saved_state_string): # pylint: disable=invalid-name """Called by client to when resume a loaded game.""" if fo.getEmpire().eliminated: print "This empire has been eliminated. Ignoring resume loaded game." return turn_timer.start("Server Processing") global foAIstate print "Resuming loaded game" try: # loading saved state # pre load code foAIstate = pickle.loads(saved_state_string) except Exception as e: # assigning new state foAIstate = AIstate.AIstate(fo.aggression.aggressive) foAIstate.session_start_cleanup() print_error("Fail to load aiState form saved game: %s" % e) aggression_trait = foAIstate.character.get_trait(Aggression) 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()
def calculateColonisationPriority(): "calculates the demand for colony ships by colonisable planets" global allottedColonyTargets totalPP=fo.getEmpire().productionPoints colonyCost=120*(1+ 0.06*len( list(AIstate.popCtrIDs) )) turnsToBuild=8#TODO: check for susp anim pods, build time 10 allottedPortion = [0.4, 0.5][ random.choice([0, 1]) ] #fo.empireID() % 2 if ( foAI.foAIstate.getPriority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_COLONISATION) > 2 * foAI.foAIstate.getPriority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_MILITARY)): allottedPortion *= 1.5 #allottedColonyTargets = 1+ int(fo.currentTurn()/50) allottedColonyTargets = 1 + int( totalPP*turnsToBuild*allottedPortion/colonyCost) numColonisablePlanetIDs = len( [ pid for (pid, (score, specName) ) in foAI.foAIstate.colonisablePlanetIDs if score > 60 ][:allottedColonyTargets+2] ) if (numColonisablePlanetIDs == 0): return 1 colonyshipIDs = FleetUtilsAI.getEmpireFleetIDsByRole(EnumsAI.AIFleetMissionType.FLEET_MISSION_COLONISATION) numColonyships = len(FleetUtilsAI.extractFleetIDsWithoutMissionTypes(colonyshipIDs)) colonisationPriority = 121 * (1+numColonisablePlanetIDs - numColonyships) / (numColonisablePlanetIDs+1) # print "" # print "Number of Colony Ships : " + str(numColonyships) # print "Number of Colonisable planets : " + str(numColonisablePlanetIDs) # print "Priority for colony ships : " + str(colonisationPriority) if colonisationPriority < 1: return 1 return colonisationPriority
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()
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()
def calculateExplorationPriority(): """calculates the demand for scouts by unexplored systems""" global scoutsNeeded universe = fo.getUniverse() empire = fo.getEmpire() numUnexploredSystems = len( ExplorationAI.borderUnexploredSystemIDs ) #len(foAI.foAIstate.get_explorable_systems(AIExplorableSystemType.EXPLORABLE_SYSTEM_UNEXPLORED)) numScouts = sum( [ foAI.foAIstate.fleetStatus.get(fid, {}).get('nships', 0) for fid in ExplorationAI.currentScoutFleetIDs] ) # FleetUtilsAI.get_empire_fleet_ids_by_role(AIFleetMissionType.FLEET_MISSION_EXPLORATION) productionQueue = empire.productionQueue queuedScoutShips=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) == EnumsAI.AIShipRoleType.SHIP_ROLE_CIVILIAN_EXPLORATION : queuedScoutShips += element.remaining * element.blocksize milShips = MilitaryAI.num_milships scoutsNeeded = max(0, min( 4+int(milShips/5), 4+int(fo.currentTurn()/50) , 2+ numUnexploredSystems**0.5 ) - numScouts - queuedScoutShips ) explorationPriority = int(40*scoutsNeeded) print print "Number of Scouts : " + str(numScouts) print "Number of Unexplored systems: " + str(numUnexploredSystems) print "military size: ", milShips print "Priority for scouts : " + str(explorationPriority) return explorationPriority
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]
def resumeLoadedGame(saved_state_string): # pylint: disable=invalid-name """Called by client to when resume a loaded game.""" debug("Resuming loaded game") if saved_state_string == "NO_STATE_YET" and fo.currentTurn() == 1: info("AI given uninitialized state-string to resume from on turn 1.") info( "Assuming post-universe-generation autosave before any orders were sent " "and behaving as if a new game was started.") return startNewGame() if fo.getEmpire() is None: fatal( "This client has no empire. Doing nothing to resume loaded game.") return if fo.getEmpire().eliminated: info("This empire has been eliminated. Ignoring resume loaded game.") return aistate = None if saved_state_string == "NOT_SET_BY_CLIENT_TYPE": info("AI assigned to empire previously run by human.") chat_human( "We have been assigned an empire previously run by a human player. We can manage this." ) elif saved_state_string == "": error( "AI given empty state-string to resume from. " "AI can continue but behaviour may be different from the previous session." ) else: try: # loading saved state aistate = load_aistate(saved_state_string) except Exception as e: error( "Failed to load the AIstate from the savegame: %s" " AI can continue but behaviour may be different from the previous session.", e, exc_info=True, ) if aistate is None: info("Creating new ai state due to failed load.") aistate = create_new_aistate(_choose_aggression()) aistate.session_start_cleanup() _pre_game_start(fo.getEmpire().empireID)
def resumeLoadedGame(saved_state_string): # pylint: disable=invalid-name """Called by client to when resume a loaded game.""" if fo.getEmpire() is None: print "This client has no empire. Doing nothing to resume loaded game." return if fo.getEmpire().eliminated: print "This empire has been eliminated. Ignoring resume loaded game." return turn_timer.start("Server Processing") global foAIstate print "Resuming loaded game" if not saved_state_string: error( "AI given empty state-string to resume from; this is expected if the AI is assigned to an empire " "previously run by a human, but is otherwise an error. AI will be set to Aggressive." ) foAIstate = AIstate.AIstate(fo.aggression.aggressive) foAIstate.session_start_cleanup() else: import savegame_codec try: # loading saved state foAIstate = savegame_codec.load_savegame_string(saved_state_string) except Exception as e: # assigning new state foAIstate = AIstate.AIstate(fo.aggression.aggressive) foAIstate.session_start_cleanup() error( "Failed to load the AIstate from the savegame. The AI will" " play with a fresh AIstate instance with aggression level set" " to 'aggressive'. The behaviour of the AI may be different" " than in the original session. The error raised was: %s" % e, exc_info=True) aggression_trait = foAIstate.character.get_trait(Aggression) 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() debug('Size of already issued orders: ' + str(fo.getOrders().size))
def _check_abort_mission(self, fleet_order: AIFleetOrder): """checks if current mission (targeting a planet) should be aborted""" planet_stealthed = False target_is_planet = fleet_order.target and isinstance( fleet_order.target, TargetPlanet) planet = None if target_is_planet: planet = fleet_order.target.get_object() # Check visibility prediction, but if somehow still have current visibility, don't # abort the mission yet if not EspionageAI.colony_detectable_by_empire( planet.id, empire=fo.empireID()): if get_partial_visibility_turn(planet.id) == fo.currentTurn(): debug( "EspionageAI predicts planet id %d to be stealthed" % planet.id + ", but somehow have current visibity anyway, so won't trigger mission abort" ) else: debug( "EspionageAI predicts we can no longer detect %s, will abort mission" % fleet_order.target) planet_stealthed = True if target_is_planet and not planet_stealthed: # TBD use fleet_order.is_valid or add fleet_order.should_abort if isinstance(fleet_order, OrderColonize): if planet.initialMeterValue(fo.meterType.population) == 0 and ( planet.ownedBy(fo.empireID()) or planet.unowned): return False elif isinstance(fleet_order, OrderOutpost): if planet.unowned: return False elif isinstance(fleet_order, OrderInvade): if planet.owner == fo.getEmpire().empireID: debug( f"Abandoning invasion for {planet}, it already belongs to us" ) return True if planet.currentMeterValue(fo.meterType.maxShield): military_support_fleets = MilitaryAI.get_military_fleets_with_target_system( planet.systemID) if not military_support_fleets: # Maybe try again later... debug( f"Abandoning Invasion mission for {planet} because target has nonzero max shields " f"and there is no military fleet assigned to secure the target system." ) return True return False else: return False # canceling fleet orders debug(" %s" % fleet_order) debug( "Fleet %d had a target planet that is no longer valid for this mission; aborting." % self.fleet.id) FleetUtilsAI.split_fleet(self.fleet.id) return True
def __init__(self, aggression): # Do not allow to create AIstate instances with an invalid version number. if not hasattr(AIstate, 'version'): raise ConversionError("AIstate must have an integer version attribute for savegame compatibility") if not isinstance(AIstate.version, int): raise ConversionError("Version attribute of AIstate must be an integer!") if AIstate.version < 0: raise ConversionError("AIstate savegame compatibility version must be a positive integer!") # need to store the version explicitly as the class variable "version" is only stored in the # self.__class__.__dict__ while we only pickle the object (i.e. self.__dict__ ) self.version = AIstate.version # Debug info # unique id for game self.uid = self.generate_uid(first=True) # unique ids for turns. {turn: uid} self.turn_uids = {} self._aggression = aggression # 'global' (?) variables self.colonisablePlanetIDs = odict() self.colonisableOutpostIDs = odict() # self.__aiMissionsByFleetID = {} self.__shipRoleByDesignID = {} self.__fleetRoleByID = {} self.diplomatic_logs = {} self.__priorityByType = {} # initialize home system knowledge universe = fo.getUniverse() empire = fo.getEmpire() self.empireID = empire.empireID homeworld = universe.getPlanet(empire.capitalID) self.__origin_home_system_id = homeworld.systemID if homeworld else INVALID_ID self.visBorderSystemIDs = {self.__origin_home_system_id} self.visInteriorSystemIDs = set() self.exploredSystemIDs = set() self.unexploredSystemIDs = {self.__origin_home_system_id} self.fleetStatus = {} # keys: 'sysID', 'nships', 'rating' # systemStatus keys: 'name', 'neighbors' (sysIDs), '2jump_ring' (sysIDs), '3jump_ring', '4jump_ring', 'enemy_ship_count' # 'fleetThreat', 'planetThreat', 'monsterThreat' (specifically, immobile nonplanet threat), 'totalThreat', 'localEnemyFleetIDs', # 'neighborThreat', 'max_neighbor_threat', 'jump2_threat' (up to 2 jumps away), 'jump3_threat', 'jump4_threat', 'regional_threat' # 'myDefenses' (planet rating), 'myfleets', 'myFleetsAccessible'(not just next desitination), 'myFleetRating' # 'my_neighbor_rating' (up to 1 jump away), 'my_jump2_rating', 'my_jump3_rating', my_jump4_rating' # 'local_fleet_threats', 'regional_fleet_threats' <== these are only for mobile fleet threats self.systemStatus = {} self.needsEmergencyExploration = [] self.newlySplitFleets = {} self.militaryRating = 0 self.shipCount = 4 self.misc = {} self.qualifyingColonyBaseTargets = {} self.qualifyingOutpostBaseTargets = {} self.qualifyingTroopBaseTargets = {} self.__empire_standard_enemy = CombatRatingsAI.default_ship_stats().get_stats(hashable=True) # TODO: track on a per-empire basis self.empire_standard_enemy_rating = 0 # TODO: track on a per-empire basis self.character = create_character(aggression, self.empireID)
def calculateColonisationPriority(): """calculates the demand for colony ships by colonisable planets""" global allottedColonyTargets, colony_growth_barrier enemies_sighted = foAI.foAIstate.misc.get('enemies_sighted', {}) galaxy_is_sparse = ColonisationAI.galaxy_is_sparse() total_pp = fo.getEmpire().productionPoints num_colonies = len(list(AIstate.popCtrIDs)) # significant growth barrier for low aggression, negligible for high aggression colony_growth_barrier = 2 + ( (0.5 + foAI.foAIstate.aggression)**2) * fo.currentTurn() / 50.0 colonyCost = AIDependencies.COLONY_POD_COST * ( 1 + AIDependencies.COLONY_POD_UPKEEP * num_colonies) turnsToBuild = 8 # TODO: check for susp anim pods, build time 10 mil_prio = foAI.foAIstate.get_priority( EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_MILITARY) allottedPortion = ([[[0.6, 0.8], [0.3, 0.4]], [[0.8, 0.9], [ 0.3, 0.4 ]]][galaxy_is_sparse][any(enemies_sighted)][fo.empireID() % 2]) #if ( foAI.foAIstate.get_priority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_COLONISATION) # > 2 * foAI.foAIstate.get_priority(EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_MILITARY)): # allottedPortion *= 1.5 if mil_prio < 100: allottedPortion *= 2 elif mil_prio < 200: allottedPortion *= 1.5 elif fo.currentTurn() > 100: allottedPortion *= 0.75**(num_colonies / 10.0) #allottedColonyTargets = 1+ int(fo.currentTurn()/50) allottedColonyTargets = 1 + int( total_pp * turnsToBuild * allottedPortion / colonyCost) outpost_prio = foAI.foAIstate.get_priority( EnumsAI.AIPriorityType.PRIORITY_PRODUCTION_OUTPOST) # if have any outposts to build, don't build colony ships TODO: make more complex assessment if outpost_prio > 0 or num_colonies > colony_growth_barrier: return 0.0 if num_colonies > colony_growth_barrier: return 0.0 numColonisablePlanetIDs = len([ pid for (pid, (score, _)) in foAI.foAIstate.colonisablePlanetIDs.items() if score > 60 ][:allottedColonyTargets + 2]) if numColonisablePlanetIDs == 0: return 1 colonyshipIDs = FleetUtilsAI.get_empire_fleet_ids_by_role( EnumsAI.AIFleetMissionType.FLEET_MISSION_COLONISATION) numColonyships = len( FleetUtilsAI.extract_fleet_ids_without_mission_types(colonyshipIDs)) colonisationPriority = 60 * (1 + numColonisablePlanetIDs - numColonyships ) / (numColonisablePlanetIDs + 1) # print # print "Number of Colony Ships : " + str(numColonyships) # print "Number of Colonisable planets : " + str(numColonisablePlanetIDs) # print "Priority for colony ships : " + str(colonisationPriority) if colonisationPriority < 1: return 0 return colonisationPriority
def print_resources_priority(): """Calculate top resource priority.""" universe = fo.getUniverse() empire = fo.getEmpire() empire_planet_ids = PlanetUtilsAI.get_owned_planets_by_empire() debug("Resource Priorities:") resource_priorities = {} aistate = get_aistate() for priority_type in get_priority_resource_types(): resource_priorities[priority_type] = aistate.get_priority( priority_type) sorted_priorities = sorted(resource_priorities.items(), key=itemgetter(1), reverse=True) top_priority = -1 for evaluation_priority, evaluation_score in sorted_priorities: if top_priority < 0: top_priority = evaluation_priority debug(" %s: %.2f", evaluation_priority, evaluation_score) # what is the focus of available resource centers? debug("") warnings = {} foci_table = Table( Text("Planet"), Text("Size"), Text("Type"), Text("Focus"), Text("Species"), Text("Pop"), table_name="Planetary Foci Overview Turn %d" % fo.currentTurn(), ) for pid in empire_planet_ids: planet = universe.getPlanet(pid) population = planet.currentMeterValue(fo.meterType.population) max_population = planet.currentMeterValue( fo.meterType.targetPopulation) if max_population < 1 and population > 0: warnings[planet.name] = (population, max_population) foci_table.add_row( planet, planet.size, planet.type, "_".join(str(planet.focus).split("_")[1:])[:8], planet.speciesName, "%.1f/%.1f" % (population, max_population), ) foci_table.print_table(info) debug( "Empire Totals:\nPopulation: %5d \nProduction: %5d\nResearch: %5d\n", empire.population(), empire.productionPoints, empire.resourceProduction(fo.resourceType.research), ) for name, (cp, mp) in warnings.items(): warning( "Population Warning! -- %s has unsustainable current pop %d -- target %d", name, cp, mp)
def queued_at(self) -> List[PlanetId]: """ Return list of planet ids where this building is queued. """ return [ element.locationID for element in fo.getEmpire().productionQueue if (element.name == self.value) ]
def _get_policy_multiplier(stability) -> float: # if fo.getEmpire().policyAdopted("TECHNOCRACY") and stability >= get_named_real("PLC_TECHNOCRACY_MIN_STABILITY"): # return 1.0 + get_named_real("PLC_TECHNOCRACY_TARGET_RESEARCH_PERCENT") if fo.getEmpire().policyAdopted( "TECHNOCRACY" ) and stability >= get_named_real("PLC_TECHNOCRACY_MIN_STABILITY"): return 1.0 + get_named_real("PLC_TECHNOCRACY_TARGET_RESEARCH_PERCENT") return 1.0
def generate_default_research_order(): """ Generate default research orders. Add cheapest technology from possible researches until current turn point totally spent. """ empire = fo.getEmpire() total_rp = empire.resourceProduction(fo.resourceType.research) # get all usable researchable techs not already completed or queued for research queued_techs = get_research_queue_techs() def is_possible(tech_name): return all([ empire.getTechStatus(tech_name) == fo.techStatus.researchable, not tech_is_complete(tech_name), not exclude_tech(tech_name), tech_name not in queued_techs, ]) # (cost, name) for all tech that possible to add to queue, cheapest last possible = sorted( [(fo.getTech(tech).researchCost(empire.empireID), tech) for tech in fo.techs() if is_possible(tech)], reverse=True, ) debug("Techs in possible list after enqueues to Research Queue:") for _, tech in possible: debug(" " + tech) debug("") # iterate through techs in order of cost fo.updateResearchQueue() total_spent = fo.getEmpire().researchQueue.totalSpent debug("Enqueuing techs. already spent RP: %s total RP: %s", total_spent, total_rp) while total_rp > 0 and possible: cost, name = possible.pop() # get chipest total_rp -= cost fo.issueEnqueueTechOrder(name, -1) debug(" enqueued tech %s : cost: %s RP", name, cost) debug("")
def get_possible_projects(): """get possible projects""" preliminary_projects = [] empire = fo.getEmpire() for tech_name in fo.techs(): if empire.getTechStatus(tech_name) == fo.techStatus.researchable: preliminary_projects.append(tech_name) return set(preliminary_projects) - set(TechsListsAI.unusable_techs())
def can_travel_to_system(fleet_id, from_system_target, to_system_target, ensure_return=False): """ Return list systems to be visited. :param fleet_id: :param 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 :param ensure_return: :type ensure_return: bool :return: :rtype: list """ empire = fo.getEmpire() empire_id = empire.empireID fleet_supplyable_system_ids = set(empire.fleetSupplyableSystemIDs) # get current fuel and max fuel universe = fo.getUniverse() fleet = universe.getFleet(fleet_id) fuel = int(fleet.fuel) if fuel < 1.0 or from_system_target.id == to_system_target.id: return [] if foAI.foAIstate.aggression <= fo.aggression.typical or True: # TODO: sort out if shortestPath leaves off some intermediate destinations path_func = universe.leastJumpsPath else: path_func = universe.shortestPath start_sys_id = from_system_target.id target_sys_id = to_system_target.id if start_sys_id != -1 and target_sys_id != -1: short_path = list(path_func(start_sys_id, target_sys_id, empire_id)) else: short_path = [] legs = zip(short_path[:-1], short_path[1:]) # suppliedStops = [ sid for sid in short_path if sid in fleet_supplyable_system_ids ] # unsupplied_stops = [sid for sid in short_path if sid not in suppliedStops ] unsupplied_stops = [sys_b for sys_a, sys_b in legs if ((sys_a not in fleet_supplyable_system_ids) and (sys_b not in fleet_supplyable_system_ids))] # print "getting path from %s to %s "%(ppstring(PlanetUtilsAI.sys_name_ids([ start_sys_id ])), ppstring(PlanetUtilsAI.sys_name_ids([ target_sys_id ])) ), # print " ::: found initial path %s having suppliedStops %s and unsupplied_stops %s ; tot fuel available is %.1f"%( ppstring(PlanetUtilsAI.sys_name_ids( short_path[:])), suppliedStops, unsupplied_stops, fuel) if False: if target_sys_id in fleet_supplyable_system_ids: print "target has FleetSupply" elif target_sys_id in ColonisationAI.annexable_ring1: print "target in Ring 1" elif target_sys_id in ColonisationAI.annexable_ring2: print "target in Ring 2, has enough aggression is ", foAI.foAIstate.aggression >= fo.aggression.typical elif target_sys_id in ColonisationAI.annexable_ring3: print "target in Ring 2, has enough aggression is ", foAI.foAIstate.aggression >= fo.aggression.aggressive if (not unsupplied_stops or not ensure_return or target_sys_id in fleet_supplyable_system_ids and len(unsupplied_stops) <= fuel or target_sys_id in ColonisationAI.annexable_ring1 and len(unsupplied_stops) < fuel or foAI.foAIstate.aggression >= fo.aggression.typical and target_sys_id in ColonisationAI.annexable_ring2 and len(unsupplied_stops) < fuel - 1 or foAI.foAIstate.aggression >= fo.aggression.aggressive and target_sys_id in ColonisationAI.annexable_ring3 and len(unsupplied_stops) < fuel - 2): return [universe_object.System(sid) for sid in short_path] else: # print " getting path from 'can_travel_to_system_and_return_to_resupply' ", return can_travel_to_system_and_return_to_resupply(fleet_id, from_system_target, to_system_target)
def inspect_ai_interface(): capital_id = PlanetUtilsAI.get_capital() universe = fo.getUniverse() fleets_int_vector = universe.fleetIDs fleet = universe.getFleet(list(fleets_int_vector)[0]) ship = universe.getShip(list(universe.shipIDs)[0]) design = fo.getShipDesign(ship.designID) empire = fo.getEmpire() tech = fo.getTech('SHP_WEAPON_2_1') tech_spec = list(tech.unlockedItems)[0] part_id = list(empire.availableShipParts)[0] part_type = fo.getPartType(part_id) prod_queue = empire.productionQueue fo.issueEnqueueShipProductionOrder( list(empire.availableShipDesigns)[0], capital_id) research_queue = empire.researchQueue fo.issueEnqueueTechOrder('SHP_WEAPON_1_2', -1) planet = universe.getPlanet(capital_id) building = list(planet.buildingIDs)[0] inspect( fo, universe, fleet, planet, universe.getSystem(planet.systemID), ship, empire, design, tech, tech_spec, fo.getFieldType('FLD_ION_STORM'), fo.getBuildingType('BLD_SHIPYARD_BASE'), fo.getGalaxySetupData(), fo.getHullType('SH_XENTRONIUM'), fo.getPartType('SR_WEAPON_1_1'), fo.getSpecial('MODERATE_TECH_NATIVES_SPECIAL'), fo.getSpecies('SP_ABADDONI'), fo.getTech('SHP_WEAPON_4_1'), fo.diplomaticMessage(1, 2, fo.diplomaticMessageType.acceptProposal), fleets_int_vector, part_type, prod_queue, prod_queue.allocatedPP, prod_queue[0], research_queue, research_queue[0], empire.getSitRep(0), universe.getBuilding(building), ) exit(1) # exit game to main menu no need to play anymore.
def _print_systems_and_supply(system_ids): universe = fo.getUniverse() empire = fo.getEmpire() fleet_supplyable_system_ids = empire.fleetSupplyableSystemIDs for system_id in system_ids: system = universe.getSystem(system_id) debug(' %s%s' % (system if system else " S_%s<>" % system_id, 'supplied' if system_id in fleet_supplyable_system_ids else ''))
def handleDiplomaticStatusUpdate(status_update): # pylint: disable=invalid-name """Called when this player receives an update about the diplomatic status between players, which may or may not include this player.""" empire = fo.getEmpire() if empire.eliminated: print "This empire has been eliminated. Ignoring diplomatic status update" return diplomatic_corp.handle_diplomatic_status_update(status_update)
def handleDiplomaticMessage(message): # pylint: disable=invalid-name """Called when this player receives a diplomatic message update from the server, such as if another player declares war, accepts peace, or cancels a proposed peace treaty.""" empire = fo.getEmpire() if empire.eliminated: print "This empire has been eliminated. Ignoring diplomatic message" return diplomatic_corp.handle_diplomatic_message(message)
def generate_fleet_orders(self): """generates AIFleetOrders from fleets targets to accomplish""" universe = fo.getUniverse() fleet_id = self.fleet.id fleet = universe.getFleet(fleet_id) if (not fleet) or fleet.empty or ( fleet_id in universe.destroyedObjectIDs(fo.empireID()) ): # fleet was probably merged into another or was destroyed foAI.foAIstate.delete_fleet_info(fleet_id) return # TODO: priority self.clear_fleet_orders() system_id = fleet.systemID start_sys_id = [fleet.nextSystemID, system_id][system_id >= 0] # if fleet doesn't have any mission, then repair if needed or resupply if is current location not in supplyable system empire = fo.getEmpire() fleet_supplyable_system_ids = empire.fleetSupplyableSystemIDs # if (not self.hasAnyAIMissionTypes()): if not self.target and (system_id not in set(AIstate.colonyTargetedSystemIDs + AIstate.outpostTargetedSystemIDs + AIstate.invasionTargetedSystemIDs + AIstate.blockadeTargetedSystemIDs)): if self._need_repair(): repair_fleet_order = MoveUtilsAI.get_repair_fleet_order( self.fleet, start_sys_id) if repair_fleet_order.is_valid(): self.orders.append(repair_fleet_order) if fleet.fuel < fleet.maxFuel and self.get_location_target( ).id not in fleet_supplyable_system_ids: resupply_fleet_order = MoveUtilsAI.get_resupply_fleet_order( self.fleet, self.get_location_target()) if resupply_fleet_order.is_valid(): self.orders.append(resupply_fleet_order) return # no targets # for some targets fleet has to visit systems and therefore fleet visit them if self.target: system_targets_required_to_visit = [self.target.get_system()] orders_to_visit_systems = MoveUtilsAI.get_fleet_orders_from_system_targets( self.fleet, system_targets_required_to_visit) # TODO: if fleet doesn't have enough fuel to get to final target, consider resetting Mission for fleet_order in orders_to_visit_systems: self.orders.append(fleet_order) # if fleet is in some system = fleet.system_id >=0, then also generate system AIFleetOrders if system_id >= 0 and self.target: # system in where fleet is system_target = System(system_id) # if mission aiTarget has required system where fleet is, then generate fleet_order from this aiTarget # for all targets in all mission types get required systems to visit if system_target == self.target.get_system(): # from target required to visit get fleet orders to accomplish target fleet_order = self._get_fleet_order_from_target( self.type, self.target) self.orders.append(fleet_order)
def _system_to_supply_group() -> Mapping[SystemId, int]: """ Create a mapping of SystemIds to supply_group_id. Used buy supply_connected, get_supply_group_id and get_supply_group. """ result = {} for num, group in enumerate(fo.getEmpire().resourceSupplyGroups, start=1): result.update((sys_id, num) for sys_id in group) return result
def update_explored_systems(): universe = fo.getUniverse() empire = fo.getEmpire() obs_lanes = empire.obstructedStarlanes() #print "object is: %s"%(obs_lanes, ) #IntPairVec 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" % obs_lanes_list else: print "No obstructed Starlanes" empire_id = foAI.foAIstate.empireID newly_explored = [] still_unexplored = [] for sys_id in list(foAI.foAIstate.unexploredSystemIDs): if empire.hasExploredSystem( sys_id ): # consider making determination according to visibility rather than actual visit, which I think is what empire.hasExploredSystem covers del foAI.foAIstate.unexploredSystemIDs[sys_id] foAI.foAIstate.exploredSystemIDs[sys_id] = 1 sys = universe.getSystem(sys_id) print "Moved system %d ( %s ) from unexplored list to explored list" % ( sys_id, (sys and sys.name) or "name unknown") if sys_id in borderUnexploredSystemIDs: del borderUnexploredSystemIDs[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)) all_explored = True for neighbor_id in neighbors: if neighbor_id in foAI.foAIstate.unexploredSystemIDs: # when it matters, unexplored will be smaller than explored all_explored = False else: next_list.append(neighbor_id) if all_explored: interiorExploredSystemIDs[sys_id] = 1 if sys_id in borderExploredSystemIDs: del borderExploredSystemIDs[sys_id] else: borderExploredSystemIDs[sys_id] = 1 for sys_id in still_unexplored: neighbors = list(universe.getImmediateNeighbors(sys_id, empire_id)) any_explored = False for neighbor_id in neighbors: if neighbor_id in foAI.foAIstate.exploredSystemIDs: # consider changing to unexplored test -- when it matters, unexplored will be smaller than explored, but need to not get previously untreated neighbors any_explored = True if any_explored: borderUnexploredSystemIDs[sys_id] = 1 return newly_explored
def _calculate_colonisation_priority(): """Calculates the demand for colony ships by colonisable planets.""" global allottedColonyTargets enemies_sighted = foAI.foAIstate.misc.get('enemies_sighted', {}) galaxy_is_sparse = ColonisationAI.galaxy_is_sparse() total_pp = fo.getEmpire().productionPoints num_colonies = state.get_number_of_colonies() colony_growth_barrier = foAI.foAIstate.character.max_number_colonies() if num_colonies > colony_growth_barrier: return 0.0 colony_cost = AIDependencies.COLONY_POD_COST * (1 + AIDependencies.COLONY_POD_UPKEEP * num_colonies) turns_to_build = 8 # TODO: check for susp anim pods, build time 10 mil_prio = foAI.foAIstate.get_priority(PriorityType.PRODUCTION_MILITARY) allotted_portion = ([[[0.6, 0.8], [0.3, 0.4]], [[0.8, 0.9], [0.4, 0.6]]][galaxy_is_sparse] [any(enemies_sighted)]) allotted_portion = foAI.foAIstate.character.preferred_colonization_portion(allotted_portion) # if ( foAI.foAIstate.get_priority(AIPriorityType.PRIORITY_PRODUCTION_COLONISATION) # > 2 * foAI.foAIstate.get_priority(AIPriorityType.PRIORITY_PRODUCTION_MILITARY)): # allotted_portion *= 1.5 if mil_prio < 100: allotted_portion *= 2 elif mil_prio < 200: allotted_portion *= 1.5 elif fo.currentTurn() > 100: allotted_portion *= 0.75 ** (num_colonies / 10.0) # allottedColonyTargets = 1+ int(fo.currentTurn()/50) allottedColonyTargets = 1 + int(total_pp * turns_to_build * allotted_portion / colony_cost) outpost_prio = foAI.foAIstate.get_priority(PriorityType.PRODUCTION_OUTPOST) # if have no SP_SLY, and have any outposts to build, don't build colony ships TODO: make more complex assessment colonizers = list(ColonisationAI.empire_colonizers) if "SP_SLY" not in colonizers and outpost_prio > 0: return 0.0 colony_opportunities = [species_name for (_, (score, species_name)) in foAI.foAIstate.colonisablePlanetIDs.items() if score > 60] num_colonisable_planet_ids = len(colony_opportunities) if num_colonisable_planet_ids == 0: return 1 colony_ship_ids = FleetUtilsAI.get_empire_fleet_ids_by_role(MissionType.COLONISATION) num_colony_ships = len(FleetUtilsAI.extract_fleet_ids_without_mission_types(colony_ship_ids)) colonisation_priority = 60 * (1.0 + num_colonisable_planet_ids - num_colony_ships) / (num_colonisable_planet_ids + 1) if colonizers == ["SP_SLY"]: colonisation_priority *= 2 elif "SP_SLY" in colonizers: colonisation_priority *= (1.0 + colony_opportunities.count("SP_SLY")) / num_colonisable_planet_ids # print # print "Number of Colony Ships : " + str(num_colony_ships) # print "Number of Colonisable planets : " + str(num_colonisable_planet_ids) # print "Priority for colony ships : " + str(colonisation_priority) if colonisation_priority < 1: return 0 return colonisation_priority