def splitFleet(): "split all fleets" # TODO: only after analyzing situation in map can fleet can be split universe = fo.getUniverse() for fleetID in universe.fleetIDs: FleetUtilsAI.splitFleet(fleetID) # old fleet may have different role after split, later will be again identified foAIstate.removeFleetRole(fleetID)
def splitNewFleets(): "split any fleets (at creation, can have unplanned mix of ship roles)" print "Review of current Fleet Role/Mission records:" print "--------------------" print "Map of Roles keyed by Fleet ID: %s"%foAIstate.getFleetRolesMap() print "--------------------" print "Map of Missions keyed by ID:" for item in foAIstate.getFleetMissionsMap().items(): print " %4d : %s "%item print "--------------------" # TODO: check length of fleets for losses or do in AIstat.__cleanRoles knownFleets= foAIstate.getFleetRolesMap().keys() foAIstate.newlySplitFleets.clear() splitableFleets=[] for fleetID in FleetUtilsAI.getEmpireFleetIDs(): if fleetID in knownFleets: #not a new fleet continue else: splitableFleets.append(fleetID) if splitableFleets: universe=fo.getUniverse() print ("splitting new fleets") for fleetID in splitableFleets: fleet = universe.getFleet(fleetID) if not fleet: print "Error splittting new fleets; resulting fleet ID %d appears to not exist"%fleetID continue fleetLen = len(list(fleet.shipIDs)) if fleetLen ==1: continue newFleets = FleetUtilsAI.splitFleet(fleetID) # try splitting fleet print "\t from splitting fleet ID %4d with %d ships, got %d new fleets:"%(fleetID, fleetLen, len(newFleets))
def check_abort_mission(self, aiFleetOrder): "checks if current mission should be aborted" abort_mission = False universe=fo.getUniverse() planet = universe.getPlanet(aiFleetOrder.getTargetAITarget().target_id) if not planet: abort_mission =True elif ((aiFleetOrder.getAIFleetOrderType() == EnumsAI.AIFleetOrderType.ORDER_COLONISE) and ( (planet.currentMeterValue(fo.meterType.population) >0) or not ( planet.unowned or planet.ownedBy(fo.empireID()) ) )) : abort_mission =True elif (aiFleetOrder.getAIFleetOrderType() == EnumsAI.AIFleetOrderType.ORDER_OUTPOST) and (not planet.unowned): abort_mission =True if abort_mission: print " %s"%(aiFleetOrder) print "Fleet %d had a target planet that is no longer valid for this mission; aborting."%(self.target_id) self.clearAIFleetOrders() self.clearAITargets(([-1]+ self.getAIMissionTypes()[:1])[-1]) FleetUtilsAI.splitFleet(self.target_id) return True elif aiFleetOrder.getAIFleetOrderType() == EnumsAI.AIFleetOrderType.ORDER_INVADE: pass return False
def issueAIFleetOrders(self): "issues AIFleetOrders which can be issued in system and moves to next one if is possible" # TODO: priority ordersCompleted = True print "Checking orders for fleet %d"%(self.getAITargetID()) #print "\t Full Orders are:" #for aiFleetOrder2 in self.getAIFleetOrders(): # print "\t\t %s"%aiFleetOrder2 for aiFleetOrder in self.getAIFleetOrders(): print " %s"%(aiFleetOrder) clearAll=False if aiFleetOrder.getAIFleetOrderType() in [EnumsAI.AIFleetOrderType.ORDER_COLONISE, EnumsAI.AIFleetOrderType.ORDER_OUTPOST]:#TODO: invasion? universe=fo.getUniverse() planet = universe.getPlanet(aiFleetOrder.getTargetAITarget().getTargetID()) if not planet: clearAll =True elif aiFleetOrder.getAIFleetOrderType() == EnumsAI.AIFleetOrderType.ORDER_COLONISE : if ( (planet.currentMeterValue(fo.meterType.population) >0) or not ( planet.unowned or planet.ownedBy(fo.empireID()) ) ) : clearAll =True elif not planet.unowned: clearAll =True if clearAll: print "Fleet %d had a target planet that is no longer valid for this mission; aborting."%(self.getAITargetID() ) self.clearAIFleetOrders() self.clearAITargets(([-1]+ self.getAIMissionTypes()[:1])[-1]) FleetUtilsAI.splitFleet(self.getAITargetID() ) return self.checkMergers(context=str(aiFleetOrder)) if aiFleetOrder.canIssueOrder(verbose=True): #print " " + str(aiFleetOrder) currently already printed in canIssueOrder() if aiFleetOrder.getAIFleetOrderType() == EnumsAI.AIFleetOrderType.ORDER_MOVE and ordersCompleted: #only move if all other orders completed aiFleetOrder.issueOrder() elif aiFleetOrder.getAIFleetOrderType() not in [ EnumsAI.AIFleetOrderType.ORDER_MOVE, EnumsAI.AIFleetOrderType.ORDER_DEFEND]: aiFleetOrder.issueOrder() if not aiFleetOrder.isExecutionCompleted(): ordersCompleted = False else: #check that we're not held up by a Big Monster if aiFleetOrder.getAIFleetOrderType() == EnumsAI.AIFleetOrderType.ORDER_MOVE: thisSysID = aiFleetOrder.getTargetAITarget().getTargetID() thisStatus = foAI.foAIstate.systemStatus.setdefault(thisSysID, {}) if ( thisStatus.get('monsterThreat', 0) > fo.currentTurn() * ProductionAI.curBestMilShipRating()/4.0 ) : if ( ( (self.getAIMissionTypes() + [-1] )[0] not in [ EnumsAI.AIFleetMissionType.FLEET_MISSION_ATTACK, EnumsAI.AIFleetMissionType.FLEET_MISSION_MILITARY, EnumsAI.AIFleetMissionType.FLEET_MISSION_HIT_AND_RUN, EnumsAI.AIFleetMissionType.FLEET_MISSION_SECURE, ]) or ( aiFleetOrder != self.getAIFleetOrders()[-1] ) # if this move order is not this mil fleet's final destination, and blocked by Big Monster, release and hope for more effective reassignment ): print "Aborting mission due to being blocked by Big Monster at system %d , threat %d"%(thisSysID, foAI.foAIstate.systemStatus[thisSysID]['monsterThreat']) print "Full set of orders were:" for aiFleetOrder2 in self.getAIFleetOrders(): print "\t\t %s"%aiFleetOrder2 self.clearAIFleetOrders() self.clearAITargets(([-1]+ self.getAIMissionTypes()[:1])[-1]) return # moving to another system stops issuing all orders in system where fleet is # move order is also the last order in system if aiFleetOrder.getAIFleetOrderType() == EnumsAI.AIFleetOrderType.ORDER_MOVE: fleet = fo.getUniverse().getFleet( self.getAITargetID() ) if fleet.systemID != aiFleetOrder.getTargetAITarget().getTargetID(): break else: #went through entire order list if ordersCompleted: orders=self.getAIFleetOrders() lastOrder= orders and orders[-1] if orders and lastOrder.getAIFleetOrderType() == EnumsAI.AIFleetOrderType.ORDER_COLONISE: universe=fo.getUniverse() planet = universe.getPlanet(lastOrder.getTargetAITarget().getTargetID()) pop=planet.currentMeterValue(fo.meterType.population) if pop==0: print "Fleet %d has tentatively completed its colonize mission but will wait to confirm population."%(self.getAITargetID() ) print " Order details are %s"%lastOrder print " Order is valid: %s ; is Executed : %s ; is execution completed: %s "%(lastOrder.isValid(), lastOrder.isExecuted(), lastOrder.isExecutionCompleted()) if not lastOrder.isValid(): sourceT = lastOrder.getSourceAITarget() targT = lastOrder.getTargetAITarget() print " source target validity: %s ; target target validity: %s "%(sourceT.isValid() , targT.isValid()) if EnumsAI.AITargetType.TARGET_SHIP == sourceT: shipID = sourceT.getTargetID() ship = universe.getShip(shipID) if not ship: print "Ship id %d not a valid ship id"%(shipID) print " source target Ship (%d), species %s, can%s colonize"%( shipID, ship.speciesName, ["not", ""][ship.canColonize]) return # colonize order must not have completed yet clearAll=True if orders and lastOrder.getAIFleetOrderType() == EnumsAI.AIFleetOrderType.ORDER_MILITARY: # if (AIFleetMissionType.FLEET_MISSION_SECURE in self.getAIMissionTypes()) or # not doing this until decide a way to release from a SECURE mission if (lastOrder.getTargetAITarget().getTargetID() in list(set(AIstate.colonyTargetedSystemIDs + AIstate.outpostTargetedSystemIDs + AIstate.invasionTargetedSystemIDs + AIstate.blockadeTargetedSystemIDs))): #consider a secure mission print "Fleet %d has completed initial stage of its mission to secure system %d, may release a portion of ships"%(self.getAITargetID() , lastOrder.getTargetAITarget().getTargetID()) clearAll=False if clearAll: print "Fleet %d has completed its mission; clearing all orders and targets."%(self.getAITargetID() ) print "Full set of orders were:" for aiFleetOrder2 in self.getAIFleetOrders(): print "\t\t %s"%aiFleetOrder2 self.clearAIFleetOrders() self.clearAITargets(([-1]+ self.getAIMissionTypes()[:1])[-1]) else: #TODO: evaluate releasing a smaller portion or none of the ships FleetUtilsAI.splitFleet(self.getAITargetID() ) #at least first stage of current task is done; release extra ships for potential other deployments
def issueAIFleetOrders(self): "issues AIFleetOrders which can be issued in system and moves to next one if is possible" # TODO: priority ordersCompleted = True print "--------------" print "Checking orders for fleet %d (on turn %d)"%(self.target_id, fo.currentTurn()) print "\t Full Orders are:" for aiFleetOrder2 in self.getAIFleetOrders(): print "\t\t %s"%aiFleetOrder2 print "/t/t------" if EnumsAI.AIFleetMissionType.FLEET_MISSION_INVASION in self.getAIMissionTypes(): self.check_retarget_invasion() for aiFleetOrder in self.getAIFleetOrders(): print " checking Order: %s"%(aiFleetOrder) clearAll=False if aiFleetOrder.getAIFleetOrderType() in [ EnumsAI.AIFleetOrderType.ORDER_COLONISE, EnumsAI.AIFleetOrderType.ORDER_OUTPOST, EnumsAI.AIFleetOrderType.ORDER_INVADE]:#TODO: invasion? if self.check_abort_mission(aiFleetOrder): return self.checkMergers(context=str(aiFleetOrder)) if aiFleetOrder.canIssueOrder(verbose=True): #print " " + str(aiFleetOrder) currently already printed in canIssueOrder() if aiFleetOrder.getAIFleetOrderType() == EnumsAI.AIFleetOrderType.ORDER_MOVE and ordersCompleted: #only move if all other orders completed aiFleetOrder.issueOrder() elif aiFleetOrder.getAIFleetOrderType() not in [ EnumsAI.AIFleetOrderType.ORDER_MOVE, EnumsAI.AIFleetOrderType.ORDER_DEFEND]: aiFleetOrder.issueOrder() if not aiFleetOrder.isExecutionCompleted(): ordersCompleted = False else: #check that we're not held up by a Big Monster if aiFleetOrder.getAIFleetOrderType() == EnumsAI.AIFleetOrderType.ORDER_MOVE: thisSysID = aiFleetOrder.getTargetAITarget().target_id thisStatus = foAI.foAIstate.systemStatus.setdefault(thisSysID, {}) if ( thisStatus.get('monsterThreat', 0) > fo.currentTurn() * ProductionAI.curBestMilShipRating()/4.0 ) : if ( ( (self.getAIMissionTypes() + [-1] )[0] not in [ EnumsAI.AIFleetMissionType.FLEET_MISSION_ATTACK, EnumsAI.AIFleetMissionType.FLEET_MISSION_MILITARY, EnumsAI.AIFleetMissionType.FLEET_MISSION_HIT_AND_RUN, EnumsAI.AIFleetMissionType.FLEET_MISSION_SECURE, ]) or ( aiFleetOrder != self.getAIFleetOrders()[-1] ) # if this move order is not this mil fleet's final destination, and blocked by Big Monster, release and hope for more effective reassignment ): print "Aborting mission due to being blocked by Big Monster at system %d , threat %d"%(thisSysID, foAI.foAIstate.systemStatus[thisSysID]['monsterThreat']) print "Full set of orders were:" for aiFleetOrder2 in self.getAIFleetOrders(): print "\t\t %s"%aiFleetOrder2 self.clearAIFleetOrders() self.clearAITargets(([-1]+ self.getAIMissionTypes()[:1])[-1]) return # moving to another system stops issuing all orders in system where fleet is # move order is also the last order in system if aiFleetOrder.getAIFleetOrderType() == EnumsAI.AIFleetOrderType.ORDER_MOVE: fleet = fo.getUniverse().getFleet( self.target_id) if fleet.systemID != aiFleetOrder.getTargetAITarget().target_id: break else: #went through entire order list if ordersCompleted: orders=self.getAIFleetOrders() lastOrder= orders and orders[-1] universe=fo.getUniverse() if orders and lastOrder.getAIFleetOrderType() == EnumsAI.AIFleetOrderType.ORDER_COLONISE: planet = universe.getPlanet(lastOrder.getTargetAITarget().target_id) system = universe.getSystem(planet.systemID) sysPartialVisTurn = dictFromMap(universe.getVisibilityTurnsMap(planet.systemID, fo.empireID())).get(fo.visibility.partial, -9999) planetPartialVisTurn = dictFromMap(universe.getVisibilityTurnsMap(planet.id, fo.empireID())).get(fo.visibility.partial, -9999) pop=planet.currentMeterValue(fo.meterType.population) if (planetPartialVisTurn == sysPartialVisTurn) and pop==0: print "Potential Error: Fleet %d has tentatively completed its colonize mission but will wait to confirm population."%(self.target_id) print " Order details are %s"%lastOrder print " Order is valid: %s ; is Executed : %s ; is execution completed: %s "%(lastOrder.isValid(), lastOrder.isExecuted(), lastOrder.isExecutionCompleted()) if not lastOrder.isValid(): sourceT = lastOrder.getSourceAITarget() targT = lastOrder.getTargetAITarget() print " source target validity: %s ; target target validity: %s "%(sourceT.valid, targT.valid) if EnumsAI.AITargetType.TARGET_SHIP == sourceT.target_type: shipID = sourceT.target_id ship = universe.getShip(shipID) if not ship: print "Ship id %d not a valid ship id"%(shipID) print " source target Ship (%d), species %s, can%s colonize"%( shipID, ship.speciesName, ["not", ""][ship.canColonize]) return # colonize order must not have completed yet clearAll=True last_sys_target = -1 if orders and lastOrder.getAIFleetOrderType() == EnumsAI.AIFleetOrderType.ORDER_MILITARY: last_sys_target = lastOrder.getTargetAITarget().target_id # if (AIFleetMissionType.FLEET_MISSION_SECURE in self.getAIMissionTypes()) or # not doing this until decide a way to release from a SECURE mission secure_targets = set(AIstate.colonyTargetedSystemIDs + AIstate.outpostTargetedSystemIDs + AIstate.invasionTargetedSystemIDs + AIstate.blockadeTargetedSystemIDs) if (last_sys_target in secure_targets) : #consider a secure mission secureType="Unidentified" if (last_sys_target in AIstate.colonyTargetedSystemIDs): secureType = "Colony" elif last_sys_target in AIstate.outpostTargetedSystemIDs : secureType = "Outpost" elif last_sys_target in AIstate.invasionTargetedSystemIDs : secureType = "Invasion" elif last_sys_target in AIstate.blockadeTargetedSystemIDs : secureType = "Blockade" print "Fleet %d has completed initial stage of its mission to secure system %d (targeted for %s), may release a portion of ships"%(self.target_id, last_sys_target, secureType) clearAll=False fleetID=self.target_id fleet=universe.getFleet(fleetID) if fleet.systemID != -1: loc = fleet.systemID else: loc=fleet.nextSystemID if clearAll: if orders: print "Fleet %d has completed its mission; clearing all orders and targets." % self.target_id print "Full set of orders were:" for aiFleetOrder2 in orders: print "\t\t %s"%aiFleetOrder2 self.clearAIFleetOrders() self.clearAITargets(([-1]+ self.getAIMissionTypes()[:1])[-1]) if foAI.foAIstate.getFleetRole(fleetID) in [ EnumsAI.AIFleetMissionType.FLEET_MISSION_MILITARY, EnumsAI.AIFleetMissionType.FLEET_MISSION_ATTACK, EnumsAI.AIFleetMissionType.FLEET_MISSION_DEFEND, EnumsAI.AIFleetMissionType.FLEET_MISSION_HIT_AND_RUN, EnumsAI.AIFleetMissionType.FLEET_MISSION_SECURE ]: allocations = MilitaryAI.getMilitaryFleets(milFleetIDs=[fleetID], tryReset=False, thisround="Fleet %d Reassignment"%fleetID) if allocations: MilitaryAI.assignMilitaryFleetsToSystems(useFleetIDList=[fleetID], allocations=allocations) else: #no orders print "No Current Orders" else: #TODO: evaluate releasing a smaller portion or none of the ships sysStatus = foAI.foAIstate.systemStatus.setdefault(last_sys_target, {}) newFleets=[] threat_present = (sysStatus.get('totalThreat', 0) != 0) or (sysStatus.get('neighborThreat', 0) != 0) target_system = universe.getSystem(last_sys_target) if (not threat_present) and target_system: for pid in target_system.planetIDs: planet = universe.getPlanet(pid) if planet and (planet.owner != fo.empireID()) and (planet.currentMeterValue(fo.meterType.maxDefense) > 0): threat_present = True break if not threat_present: print "No current threat in target system; releasing a portion of ships." newFleets=FleetUtilsAI.splitFleet(self.target_id) #at least first stage of current task is done; release extra ships for potential other deployments else: print "Threat remains in target system; NOT releasing any ships." newMilFleets = [] for fleetID in newFleets: if foAI.foAIstate.getFleetRole(fleetID) in [ EnumsAI.AIFleetMissionType.FLEET_MISSION_MILITARY, EnumsAI.AIFleetMissionType.FLEET_MISSION_ATTACK, EnumsAI.AIFleetMissionType.FLEET_MISSION_DEFEND, EnumsAI.AIFleetMissionType.FLEET_MISSION_HIT_AND_RUN, EnumsAI.AIFleetMissionType.FLEET_MISSION_SECURE ]: newMilFleets.append(fleetID) allocations=[] if newMilFleets: allocations = MilitaryAI.getMilitaryFleets(milFleetIDs=newMilFleets, tryReset=False, thisround="Fleet Reassignment %s"%newMilFleets) if allocations: MilitaryAI.assignMilitaryFleetsToSystems(useFleetIDList=newMilFleets, allocations=allocations)
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()