def checkMergers(self, fleetID=None, context=""): if fleetID==None: fleetID = self.getAITargetID() #mainFleetMission=foAI.foAIstate.getAIFleetMission(fleetID) mainMissionTypeList = self.getAIMissionTypes() #normally, currently, should only be one if len( mainMissionTypeList ) != 1: return #if this fleet has multiple mission types, will not subsume other fleets fleetRoleB = foAI.foAIstate.getFleetRole(fleetID) mainMissionType = mainMissionTypeList[0] if mainMissionType not in [ EnumsAI.AIFleetMissionType.FLEET_MISSION_ATTACK, EnumsAI.AIFleetMissionType.FLEET_MISSION_DEFEND, EnumsAI.AIFleetMissionType.FLEET_MISSION_LAST_STAND , EnumsAI.AIFleetMissionType.FLEET_MISSION_MILITARY, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION, EnumsAI.AIFleetMissionType.FLEET_MISSION_SECURE, EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_DEFENSE, ]: return universe = fo.getUniverse() empireID = fo.empireID() fleetB = universe.getFleet(fleetID) systemID = fleetB.systemID if systemID == -1: return # can't merge fleets in middle of starlane sysStatus = foAI.foAIstate.systemStatus[systemID] destroyedList = list( universe.destroyedObjectIDs(empireID) ) otherFleetsHere= [fid for fid in sysStatus.get('myfleets', []) if ( (fid != fleetID) and (fid not in destroyedList) ) ] if otherFleetsHere==[]: return #nothing of record to merge with mainMissionTargets = self.getAITargets(mainMissionType) if mainMissionTargets == []: pass #return #let's let invasion fleets with no target get merged mMT0=None mMT0ID = None else: mMT0=mainMissionTargets[0] mMT0ID = mMT0.getTargetID() if len(mainMissionTargets)>1: pass print "\tConsidering merging fleets into fleet %d, but it has multiple targets: %s"%(fleetID, str(mainMissionTargets)) sys1=universe.getSystem(systemID) sysName = (sys1 and sys1.name) or "unknown" compatibileRolesMap={ EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_DEFENSE: [EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_DEFENSE], EnumsAI.AIFleetMissionType.FLEET_MISSION_MILITARY: [EnumsAI.AIFleetMissionType.FLEET_MISSION_MILITARY], EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION: [EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION], EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION: [EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION], } for fid in otherFleetsHere: fleetRoleA = foAI.foAIstate.getFleetRole(fid) if fleetRoleA not in compatibileRolesMap[fleetRoleB] : #TODO: if fleetRoles such as LongRange start being used, adjust this continue # will only considering subsuming fleets that have a compatible role fleet2 = universe.getFleet(fid) if not (fleet2 and (fleet2.systemID == systemID)): continue if not (fleet2.ownedBy(foAI.foAIstate.empireID) and ( (fleet2.speed > 0) or (fleetB.speed == 0) )): continue f2Mission=foAI.foAIstate.getAIFleetMission(fid) doMerge=False needLeft=0 if ( fleetRoleA== EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_DEFENSE ) or (fleetRoleB== EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_DEFENSE ): if fleetRoleA==fleetRoleB: doMerge=True elif ( fleetRoleA== EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION ) or (fleetRoleB== EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION ): if fleetRoleA==fleetRoleB: doMerge=False#TODO: could allow merger if both orb invaders and both same target elif not f2Mission and (fleetB.speed > 0) and (fleet2.speed > 0): doMerge=True else: f2MType = (f2Mission.getAIMissionTypes()+[-1])[0] f2Targets = f2Mission.getAITargets(f2MType) if len(f2Targets)>1: pass elif len(f2Targets)==0 and ( (fleetB.speed > 0) or (fleet2.speed == 0) ): #print "\t\t\t ** Considering merging fleetA (id: %4d) into fleetB (id %d ) and former has no targets, will take it. FleetA mission was %s "%(fid, fleetID, f2Mission) doMerge=True else: targetB = f2Targets[0].getTargetID() if targetB == mMT0ID: print "Military fleet %d has same target as %s fleet %d and will (at least temporarily) be merged into the latter"%(fid, AIFleetMissionTypeNames.name( fleetRoleB) , fleetID) doMerge=True #TODO: should probably ensure that fleetA has aggression on now elif (fleetB.speed > 0): neighbors = foAI.foAIstate.systemStatus.get(systemID, {}).get('neighbors', []) if (targetB==systemID) and mMT0ID in neighbors: #consider 'borrowing' for work in neighbor system if f2MType in [ EnumsAI.AIFleetMissionType.FLEET_MISSION_ATTACK, EnumsAI.AIFleetMissionType.FLEET_MISSION_DEFEND, EnumsAI.AIFleetMissionType.FLEET_MISSION_MILITARY, EnumsAI.AIFleetMissionType.FLEET_MISSION_SECURE, ]: #continue if f2MType in [ EnumsAI.AIFleetMissionType.FLEET_MISSION_DEFEND, EnumsAI.AIFleetMissionType.FLEET_MISSION_SECURE, #actually, currently this is probably the onle one of all four that should really be possibile in this situation ]: needLeft = 1.5*sum( [ sysStat.get('fleetThreat', 0) for sysStat in [foAI.foAIstate.systemStatus.get(neighbor, {}) for neighbor in [ nid for nid in foAI.foAIstate.systemStatus.get(systemID, {}).get('neighbors', []) if nid != mMT0ID ] ] ] ) fBRating = foAI.foAIstate.getRating(fid) if (needLeft < fBRating.get('overall', 0)) and fBRating.get('nships', 0)>1 : doMerge=True if doMerge: FleetUtilsAI.mergeFleetAintoB(fid, fleetID, needLeft, context="Order %s of mission %s"%(context, str(self))) return
def assignInvasionFleetsToInvade(): # assign fleet targets to invadable planets universe = fo.getUniverse() empire = fo.getEmpire() empireID = empire.empireID fleetSupplyableSystemIDs = empire.fleetSupplyableSystemIDs fleetSupplyablePlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(fleetSupplyableSystemIDs) allTroopBaseFleetIDs = FleetUtilsAI.getEmpireFleetIDsByRole(EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION) availTroopBaseFleetIDs = set(FleetUtilsAI.extractFleetIDsWithoutMissionTypes(allTroopBaseFleetIDs)) for fid in list(availTroopBaseFleetIDs): if fid not in availTroopBaseFleetIDs: continue fleet = universe.getFleet(fid) if not fleet: continue sysID = fleet.systemID system = universe.getSystem(sysID) availPlanets = set(system.planetIDs).intersection(set( foAI.foAIstate.qualifyingTroopBaseTargets.keys())) print "Considering Base Troopers in %s, found planets %s and regtistered targets %s with status %s"%(system.name, list(system.planetIDs), availPlanets, [(pid, foAI.foAIstate.qualifyingTroopBaseTargets[pid]) for pid in availPlanets]) targets = [pid for pid in availPlanets if foAI.foAIstate.qualifyingTroopBaseTargets[pid][1] != -1 ] if not targets: print "Error found no valid target for troop base in system %s (%d)"%(system.name, sysID) continue status=foAI.foAIstate.systemStatus.get( sysID, {} ) local_base_troops = set(status.get('myfleets', [])).intersection(availTroopBaseFleetIDs) troop_pod_tally = 0 for fid2 in local_base_troops: troop_pod_tally += FleetUtilsAI.countPartsFleetwide(fid2, ["GT_TROOP_POD"]) targetID=-1 bestScore=-1 target_troops = 0 # for pid, rating in assignInvasionValues(targets, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, fleetSupplyablePlanetIDs, empire).items(): p_score, p_troops = rating if p_score>bestScore: if p_troops >= 2*troop_pod_tally: pass #continue bestScore = p_score targetID = pid target_troops = p_troops if targetID != -1: local_base_troops.discard(fid) foundFleets = [] podsNeeded= math.ceil( (target_troops - 2*(FleetUtilsAI.countPartsFleetwide(fid, ["GT_TROOP_POD"]))+0.05)/2.0) foundStats={} minStats= {'rating':0, 'troopPods':podsNeeded} targetStats={'rating':10,'troopPods':podsNeeded} theseFleets = FleetUtilsAI.getFleetsForMission(1, targetStats , minStats, foundStats, "", systemsToCheck=[sysID], systemsChecked=[], fleetPoolSet=local_base_troops, fleetList=foundFleets, verbose=False) for fid2 in foundFleets: FleetUtilsAI.mergeFleetAintoB(fid2, fid) availTroopBaseFleetIDs.discard(fid2) availTroopBaseFleetIDs.discard(fid) foAI.foAIstate.qualifyingTroopBaseTargets[targetID][1] = -1 #TODO: should probably delete aiTarget = AITarget.AITarget(EnumsAI.AITargetType.TARGET_PLANET, targetID) aiFleetMission = foAI.foAIstate.getAIFleetMission(fid) aiFleetMission.addAITarget(EnumsAI.AIFleetMissionType.FLEET_MISSION_ORBITAL_INVASION, aiTarget) invasionFleetIDs = AIstate.invasionFleetIDs sendInvasionFleets(invasionFleetIDs, AIstate.invasionTargets, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) allInvasionFleetIDs = FleetUtilsAI.getEmpireFleetIDsByRole(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION) for fid in FleetUtilsAI.extractFleetIDsWithoutMissionTypes(allInvasionFleetIDs): thisMission = foAI.foAIstate.getAIFleetMission(fid) thisMission.checkMergers(context="Post-send consolidation of unassigned troops")
def check_retarget_invasion(self): "checks if an invasion mission should be retargeted" universe=fo.getUniverse() empire = fo.getEmpire() empire_id = fo.empireID() fleet_id = self.target_id fleet=universe.getFleet(fleet_id) if fleet.systemID == -1: #next_loc=fleet.nextSystemID return #TODO: still check system = universe.getSystem(fleet.systemID) if not system: return orders=self.getAIFleetOrders() last_sys_target = -1 if orders: last_sys_target = orders[-1].getTargetAITarget().target_id if last_sys_target == fleet.systemID: return #TODO: check for best local target open_targets = [] already_targeted = InvasionAI.getInvasionTargetedPlanetIDs(system.planetIDs, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, empire_id) for pid in system.planetIDs: if pid in already_targeted or (pid in foAI.foAIstate.qualifyingTroopBaseTargets): continue planet = universe.getPlanet(pid) if planet.unowned or (planet.owner == empire_id): continue if (planet.currentMeterValue(fo.meterType.shield)) <= 0: open_targets.append(pid) if not open_targets: return troop_pod_tally = FleetUtilsAI.countPartsFleetwide(fleet_id, ["GT_TROOP_POD"]) targetID=-1 bestScore=-1 target_troops = 0 # fleetSupplyableSystemIDs = empire.fleetSupplyableSystemIDs fleetSupplyablePlanetIDs = PlanetUtilsAI.getPlanetsInSystemsIDs(fleetSupplyableSystemIDs) for pid, rating in InvasionAI.assignInvasionValues(open_targets, EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, fleetSupplyablePlanetIDs, empire).items(): p_score, p_troops = rating if p_score>bestScore: if p_troops >= 2*troop_pod_tally: continue bestScore = p_score targetID = pid target_troops = p_troops if targetID == -1: return newFleets=FleetUtilsAI.splitFleet(fleet_id) self.clearAITargets(-1)#TODO: clear from foAIstate self.clearAIFleetOrders() podsNeeded= max(0, math.ceil( (target_troops - 2*(FleetUtilsAI.countPartsFleetwide(fleet_id, ["GT_TROOP_POD"]))+0.05)/2.0) ) foundStats={} minStats= {'rating':0, 'troopPods':podsNeeded} targetStats={'rating':10,'troopPods':podsNeeded} foundFleets = [] theseFleets = FleetUtilsAI.getFleetsForMission(1, targetStats , minStats, foundStats, "", systemsToCheck=[fleet.systemID], systemsChecked=[], fleetPoolSet=set(newFleets), fleetList=foundFleets, verbose=False) for fid2 in foundFleets: FleetUtilsAI.mergeFleetAintoB(fid2, fleet_id) aiTarget = AITarget.AITarget(EnumsAI.AITargetType.TARGET_PLANET, targetID) self.addAITarget(EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION, aiTarget) self.generateAIFleetOrders()