def send_colony_ships(colony_fleet_ids, evaluated_planets, mission_type): """sends a list of colony ships to a list of planet_value_pairs""" fleet_pool = colony_fleet_ids[:] try_all = False if mission_type == MissionType.OUTPOST: cost = 20 + outpod_pod_cost() else: try_all = True cost = 20 + colony_pod_cost_turns()[1] if fo.currentTurn() < 50: cost *= 0.4 # will be making fast tech progress so value is underestimated elif fo.currentTurn() < 80: cost *= 0.8 # will be making fast-ish tech progress so value is underestimated potential_targets = [ (pid, (score, specName)) for (pid, (score, specName)) in evaluated_planets if score > (0.8 * cost) and score > MINIMUM_COLONY_SCORE ] debug("Colony/outpost ship matching: fleets %s to planets %s" % (fleet_pool, evaluated_planets)) if try_all: debug("Trying best matches to current colony ships") best_scores = dict(evaluated_planets) potential_targets = [] for pid, ratings in _all_colony_opportunities.items(): for rating in ratings: if rating[0] >= 0.75 * best_scores.get(pid, [9999])[0]: potential_targets.append((pid, rating)) potential_targets.sort(key=itemgetter(1), reverse=True) # added a lot of checking because have been getting mysterious exception, after too many recursions to get info fleet_pool = set(fleet_pool) universe = fo.getUniverse() for fid in fleet_pool: fleet = universe.getFleet(fid) if not fleet or fleet.empty: warning("Bad fleet ( ID %d ) given to colonization routine; will be skipped" % fid) fleet_pool.remove(fid) continue report_str = "Fleet ID (%d): %d ships; species: " % (fid, fleet.numShips) for sid in fleet.shipIDs: ship = universe.getShip(sid) if not ship: report_str += "NoShip, " else: report_str += "%s, " % ship.speciesName debug(report_str) debug("") already_targeted = [] # for planetID_value_pair in evaluatedPlanets: aistate = get_aistate() while fleet_pool and potential_targets: target = potential_targets.pop(0) if target in already_targeted: continue planet_id = target[0] if planet_id in already_targeted: continue planet = universe.getPlanet(planet_id) sys_id = planet.systemID if ( aistate.systemStatus.setdefault(sys_id, {}).setdefault("monsterThreat", 0) > 2000 or fo.currentTurn() < 20 and aistate.systemStatus[sys_id]["monsterThreat"] > 200 ): debug( "Skipping colonization of system %s due to Big Monster, threat %d" % (universe.getSystem(sys_id), aistate.systemStatus[sys_id]["monsterThreat"]) ) already_targeted.append(planet_id) continue # make sure not to run into stationary guards if ExplorationAI.system_could_have_unknown_stationary_guard(sys_id): ExplorationAI.request_emergency_exploration(sys_id) continue this_spec = target[1][1] found_fleets = [] try: this_fleet_list = FleetUtilsAI.get_fleets_for_mission( target_stats={}, min_stats={}, cur_stats={}, starting_system=sys_id, species=this_spec, fleet_pool_set=fleet_pool, fleet_list=found_fleets, ) except Exception as e: error(e, exc_info=True) continue if not this_fleet_list: fleet_pool.update(found_fleets) # just to be safe continue # must have no compatible colony/outpost ships fleet_id = this_fleet_list[0] already_targeted.append(planet_id) ai_target = TargetPlanet(planet_id) aistate.get_fleet_mission(fleet_id).set_target(mission_type, ai_target)
def issue_order(self): if not super(OrderInvade, self).can_issue_order(): return False universe = fo.getUniverse() planet_id = self.target.id planet = self.target.get_object() fleet = self.fleet.get_object() invasion_roles = (ShipRoleType.BASE_INVASION, ShipRoleType.MILITARY_INVASION) debug("Issuing order: %s fleet: %s target: %s" % (self.ORDER_NAME, self.fleet, self.target)) # will track if at least one invasion troops successfully deployed result = True aistate = get_aistate() overkill_margin = 2 # TODO: get from character module; allows a handful of extra troops to be immediately # defending planet # invasion orders processed before regen takes place, so use initialMeterValue() here troops_wanted = planet.initialMeterValue( fo.meterType.troops) + overkill_margin troops_already_assigned = 0 # TODO: get from other fleets in same system troops_assigned = 0 # Todo: evaluate all local troop ships (including other fleets) before using any, make sure base invasion troops # are used first, and that not too many altogether are used (choosing an optimal collection to use). for invasion_role in invasion_roles: # first checks base troops, then regular if not result: break for ship_id in fleet.shipIDs: if troops_already_assigned + troops_assigned >= troops_wanted: break ship = universe.getShip(ship_id) if aistate.get_ship_role(ship.design.id) != invasion_role: continue debug("Ordering troop ship %d to invade %s" % (ship_id, planet)) result = fo.issueInvadeOrder(ship_id, planet_id) and result if not result: shields = planet.currentMeterValue(fo.meterType.shield) planet_stealth = planet.currentMeterValue( fo.meterType.stealth) pop = planet.currentMeterValue(fo.meterType.population) warning("Invasion order failed!") debug( " -- planet has %.1f stealth, shields %.1f, %.1f population and " "is owned by empire %d" % (planet_stealth, shields, pop, planet.owner)) if "needsEmergencyExploration" not in dir(aistate): aistate.needsEmergencyExploration = [] # TODO: Check if this even makes sense - to invade a planet the ship must be in the system # which should grant the same visibility as a scout ship... ExplorationAI.request_emergency_exploration(fleet.systemID) debug( "Due to trouble invading, added system %d to Emergency Exploration List" % fleet.systemID) self.executed = False # debug(universe.getPlanet(planet_id).dump()) # TODO: fix fo.UniverseObject.dump() break troops_assigned += ship.troopCapacity # TODO: split off unused troop ships into new fleet and give new orders this cycle if result: debug("Successfully ordered %d troopers to invade %s" % (troops_assigned, planet)) return True else: return False