class Gateway: def __init__(self, unit): self.tag = unit.tag self.unit = unit self.label = 'Idle' self.transform_started = False self.warpgate = False self.queued = False self.unitCounter = UnitCounter() self.trainList = [ 'Zealot', 'Stalker', 'Adept', 'Sentry', 'HighTemplar' ] async def make_decision(self, game, unit): self.game = game self.unit = unit self.abilities = self.game.allAbilities.get(self.unit.tag) self.queueStatus() if unit.name == 'Gateway': self.warpgate = False else: self.warpgate = True if not self.queued: await self.runList() else: self.label = "Busy {}".format(str(len(self.abilities))) self.label += " {}".format(str(self.queued)) # self.label += "- {}".format(str(unit.is_idle)) #debugging info if self.game.debugAllowed: if _debug or self.unit.is_selected: self.game._client.debug_text_3d(self.label, self.unit.position3d) async def runList(self): #check to see if we can become a warpgate. if self.transformGate(): self.label = 'Transforming to Warpgate' return #check to see if saving resources are being requested. if self.resourcesSaved(): self.label = 'Resources being saved' return if await self.trainUnit(): return async def trainUnit(self): #make sure we can spend. if not self.game.can_spend: self.label = 'No spending allowed' return #get unit to train trainee = self.bestTrain() if trainee: if self.warpgate: warpAbil = self.unitCounter.getWarpAbility(trainee) if warpAbil in self.abilities: placement = await self.warpgate_placement(warpAbil) if placement: self.game.combinedActions.append( self.unit.warp_in( self.unitCounter.getUnitID(trainee), placement)) self.game.can_spend = False return True else: self.game.combinedActions.append( self.unit.train(self.unitCounter.getUnitID(trainee))) self.game.can_spend = False return True def resourcesSaved(self): if self.game._strat_manager.saving: return True def transformGate(self): #see if we can train into a warpgate. #if self.game._science_manager._warpgate_researched: if self.game.buildingList.warpgateAvail: #warp if we can. if AbilityId.MORPH_WARPGATE in self.abilities: self.game.combinedActions.append( self.unit(AbilityId.MORPH_WARPGATE)) self.transform_started = True return True #see if we are in the process of warping. if self.transform_started and not self.warpgate: if 'upgradetowarpgate' in str(self.unit.orders).lower(): return True #utilities def queueStatus(self): if self.warpgate: if len(self.abilities) < 2 and ( self.game.minerals > 100 or (self.game.vespene > 100 and self.game.minerals > 50)) and self.game.supply_left > 1: self.queued = True else: self.queued = False else: if self.unit.is_idle: self.queued = False else: self.queued = True def canBuild(self, trainee): if self.game.can_afford(self.unitCounter.getUnitID(trainee)): #make sure we can actually build it and the core is finished. if self.game.enemy_race == Race.Terran and trainee == 'Zealot' and not self.game.units( CYBERNETICSCORE).ready.exists: return False #don't build zealots to start so we can get stalkers out sooner. #don't build a sentry before other units. if self.game._strat_manager.army_power == 0 and trainee == 'Sentry': return False if trainee != 'Zealot': if not self.game.units(CYBERNETICSCORE).ready.exists: return False if trainee == 'HighTemplar' and not self.game.units( TEMPLARARCHIVE).ready.exists: return False return True def bestTrain(self): bestName = None bestCount = -1 bestNeeded = False for name, count in self.game._strat_manager.able_army.items(): #check if its one of our types. if name in self.trainList: #check if it's needed or not. if self.game._strat_manager.check_allowed(name): bestNeeded = True if self.canBuild(name) and count > bestCount: bestName = name bestCount = count if bestName: self.label = "Best {}".format(bestName) return bestName if bestNeeded: self.label = 'need resources' return None #apparently couldn't build anything in the ideal list that is being allowed, check for anything to build. #if minerals are backing up, then go ahead and build anything. if self.game.minerals > 550 and self.game.vespene > 550: bestName = None bestCount = -1 for name, count in self.game._strat_manager.able_army.items(): if name == 'Sentry': continue #check if its one of our types. if name in self.trainList: #check if it's needed or not. if self.canBuild(name): if count > bestCount: bestName = name bestCount = count if bestName: self.label = "2nd {}".format(bestName) return bestName ####at some point, lets just build zealots to fill supply. if self.game.minerals > 2000 and self.game.vespene < 200: return 'Zealot' if self.game.minerals > 5000: return 'Zealot' self.label = 'Allowing resources elsewhere' return None async def warpgate_placement(self, unit_ability): #todo: first, check for a warp prism in pylon mode. if not self.game.under_attack and len( self.game.units(WARPPRISMPHASING).ready) > 0: pos = self.game.units( WARPPRISMPHASING).ready.random.position.to2.random_on_distance( 3) placement = await self.game.find_placement(unit_ability, pos, placement_step=1) if placement: return placement #find super pylons and sort them closest to the enemy. #loop the pylons and find one that isn't in range of an enemy. #if no super pylons exist, find any pylon and do it again. closestEnemy = None if len(self.game.cached_enemies) > 0: closestEnemy = self.game.cached_enemies.closest_to( self.game.start_location) if closestEnemy and self.game.units(PYLON).ready.exists: if len(self.game.units.of_type([NEXUS, WARPGATE])) > 0: for building in self.game.units().of_type([ NEXUS, WARPGATE ]).ready.sorted(lambda x: x.distance_to(closestEnemy)): superPylons = self.game.units(PYLON).ready.closer_than( 6, building) for pylon in superPylons: if len(self.game.cached_enemies.closer_than( 12, pylon)) > len( self.game.units.exclude_type(PROBE). not_structure.closer_than(12, pylon)): #print ('skipping super', str(len(self.game.cached_enemies.closer_than(12, pylon))), str(len(self.game.units.exclude_type(PROBE).not_structure.closer_than(12, pylon)))) continue else: #found a good pylon. pos = pylon.position.to2.random_on_distance(4) placement = await self.game.find_placement( unit_ability, pos, placement_step=1) if placement: #print ('super placement', str(len(self.game.cached_enemies.closer_than(12, pylon))), str(len(self.game.units.exclude_type(PROBE).not_structure.closer_than(12, pylon)))) return placement #no valid super found, check all pylons. regPylons = self.game.units(PYLON).ready.sorted( lambda x: x.distance_to(closestEnemy)) for pylon in regPylons: if len(self.game.cached_enemies.closer_than(12, pylon)) > len( self.game.units.exclude_type( PROBE).not_structure.closer_than(12, pylon)): #print ('skipping regular', str(len(self.game.cached_enemies.closer_than(12, pylon))), str(len(self.game.units.exclude_type(PROBE).not_structure.closer_than(12, pylon)))) continue else: #found a good pylon. pos = pylon.position.to2.random_on_distance(4) placement = await self.game.find_placement( unit_ability, pos, placement_step=1) if placement: #print ('regular placement', str(len(self.game.cached_enemies.closer_than(12, pylon))), str(len(self.game.units.exclude_type(PROBE).not_structure.closer_than(12, pylon)))) return placement #enemies must be around everywhere, just pick a random pylon and place it. pylon = self.game.units(PYLON).ready.random if pylon: pos = pylon.position.to2.random_on_distance(4) placement = await self.game.find_placement(unit_ability, pos, placement_step=1) if placement: #print ('random placement', str(len(self.game.cached_enemies.closer_than(12, pylon))), str(len(self.game.units.exclude_type(PROBE).not_structure.closer_than(12, pylon)))) return placement else: #just place the unit closest to the defensive position. if len(self.game.units( PYLON).ready) > 0 and self.game.defensive_pos: pylon = self.game.units(PYLON).ready.closest_to( self.game.defensive_pos) if pylon: pos = pylon.position.to2.random_on_distance(4) placement = await self.game.find_placement( unit_ability, pos, placement_step=1) if placement: #print ('defensive placement') return placement return None @property def inQueue(self) -> bool: return self.queued
class Stargate: def __init__(self, unit): self.tag = unit.tag self.unit = unit self.label = 'Idle' self.queued = False self.unitCounter = UnitCounter() self.trainList = ['VoidRay', 'Phoenix', 'Tempest', 'Carrier'] async def make_decision(self, game, unit): self.game = game self.unit = unit self.abilities = self.game.allAbilities.get(self.unit.tag) self.queueStatus() if self.unit.is_idle: await self.runList() else: self.label = "Busy {}".format(str(len(self.abilities))) #debugging info if self.game.debugAllowed: if _debug or self.unit.is_selected: self.game._client.debug_text_3d(self.label, self.unit.position3d) async def runList(self): #check to see if saving resources are being requested. if self.resourcesSaved(): self.label = 'Resources being saved' return if await self.trainUnit(): return async def trainUnit(self): #make sure we can spend. if not self.game.can_spend: self.label = 'No spending allowed' return #get unit to train trainee = self.bestTrain() if trainee: self.game.combinedActions.append( self.unit.train(self.unitCounter.getUnitID(trainee))) self.game.can_spend = False return True def resourcesSaved(self): if self.game._strat_manager.saving: return True #utilities def canBuild(self, trainee): if self.game.can_afford(self.unitCounter.getUnitID(trainee)): return True def bestTrain(self): bestName = None bestCount = -1 bestNeeded = False for name, count in self.game._strat_manager.able_army.items(): #check if its one of our types. if name in self.trainList: #check if it's needed or not. if self.game._strat_manager.check_allowed(name): bestNeeded = True if self.canBuild(name) and count > bestCount: bestName = name bestCount = count if bestName: self.label = "Best {}".format(bestName) return bestName if bestNeeded: self.label = 'need resources' return None #apparently couldn't build anything in the ideal list that is being allowed, check for anything to build. #if minerals are backing up, then go ahead and build anything. if self.game.minerals > 550 and self.game.vespene > 500: bestName = None bestCount = -1 for name, count in self.game._strat_manager.able_army.items(): #check if its one of our types. if name in self.trainList: #check if it's needed or not. if self.canBuild(name): if count > bestCount: bestName = name bestCount = count if bestName: self.label = "2nd {}".format(bestName) return bestName self.label = 'Allowing resources elsewhere' return None def queueStatus(self): if self.unit.is_idle: self.queued = False else: self.queued = True @property def inQueue(self) -> bool: return self.queued
class Robo: def __init__(self, unit): self.tag = unit.tag self.unit = unit self.label = 'Idle' self.queued = False self.unitCounter = UnitCounter() self.trainList = ['Immortal', 'WarpPrism', 'Colossus', 'Disruptor', 'Observer'] async def make_decision(self, game, unit): self.game = game self.unit = unit self.abilities = self.game.allAbilities.get(self.unit.tag) self.queueStatus() if self.unit.is_idle: await self.runList() else: self.label = "Busy {}".format(str(len(self.abilities))) #debugging info if self.game.debugAllowed: if _debug or self.unit.is_selected: self.game._client.debug_text_3d(self.label, self.unit.position3d) async def runList(self): #check to see if saving resources are being requested. if self.resourcesSaved(): self.label = 'Resources being saved' return if self.trainUnit(): return if self.trainObservers(): return def trainObservers(self): #train observers if under the min. if self.game.can_spend and not self.game.under_attack and self.game._strat_manager.army_power > 40 and self.game.units(OBSERVER).amount < 2: self.game.combinedActions.append(self.unit.train(OBSERVER)) self.game.can_spend = False return True return False def trainUnit(self): #make sure we can spend. if not self.game.can_spend: self.label = 'No spending allowed' return #get unit to train trainee = self.bestTrain() if trainee == 'Observer' and len(self.game.units(OBSERVER)) >= 5: return False if trainee: self.game.combinedActions.append(self.unit.train(self.unitCounter.getUnitID(trainee))) self.game.can_spend = False return True return False def resourcesSaved(self): if self.game._strat_manager.saving: return True #utilities def canBuild(self, trainee): if self.game.can_afford(self.unitCounter.getUnitID(trainee)): return True def bestTrain(self): #if it's been at least 7 minutes in the game, make a warpprism if one doesn't exist. if not self.game.defend_only and self.game.trueGates >= 3 and len(self.game.units.of_type([WARPPRISMPHASING,WARPPRISM])) == 0 and not self.game.already_pending(WARPPRISM): return 'WarpPrism' bestName = None bestCount = -1 bestNeeded = False for name, count in self.game._strat_manager.able_army.items(): #check if its one of our types. if name in self.trainList: #check if it's needed or not. if self.game._strat_manager.check_allowed(name): bestNeeded = True if self.canBuild(name) and count > bestCount: bestName = name bestCount = count if bestName: self.label = "Best {}".format(bestName) return bestName if bestNeeded: self.label = 'need resources' return None #apparently couldn't build anything in the ideal list that is being allowed, check for anything to build. #if minerals are backing up, then go ahead and build anything. if self.game.minerals > 550 and self.game.vespene > 500: bestName = None bestCount = -1 for name, count in self.game._strat_manager.able_army.items(): #check if its one of our types. if name in self.trainList: #check if it's needed or not. if self.canBuild(name): if count > bestCount: bestName = name bestCount = count if bestName: self.label = "2nd {}".format(bestName) return bestName self.label = 'Allowing resources elsewhere' return None def queueStatus(self): if self.unit.is_idle: self.queued = False else: self.queued = True @property def inQueue(self) -> bool: return self.queued