async def do_queen_micro(self, queen: Unit, enemy: Units, grid: Optional[np.ndarray] = None) -> None: if not queen: return in_range_enemies: Units = self.bot.enemy_units.in_attack_range_of( queen) in_range_enemies = in_range_enemies.exclude_type( {UnitID.EGG, UnitID.LARVA}) if in_range_enemies: target: Unit = self._get_target_from_in_range_enemies( in_range_enemies) if target: if self.attack_ready(queen, target): queen.attack(target) elif self.map_data and grid is not None: await self.move_towards_safe_spot(queen, grid) else: distance: float = queen.ground_range + queen.radius + target.radius move_to: Point2 = target.position.towards(queen, distance) if self.bot.in_pathing_grid(move_to): queen.move(move_to) else: queen.attack(in_range_enemies.center) elif enemy: target = enemy.closest_to(queen) queen.attack(target) elif self.bot.all_enemy_units: target = self.bot.all_enemy_units.closest_to(queen) queen.attack(target)
async def on_before_start(self): """ Override this in your bot class. This function is called before "on_start" and before expansion locations are calculated. Not all data is available yet. """ # Start building first worker before doing any heavy calculations # This is only needed for real time, but we don't really know whether the game is real time or not. await self.start_first_worker() self._client.game_step = int(self.config["general"]["game_step_size"]) if self.realtime_split: # Split workers mfs = self.mineral_field.closer_than(10, self.townhalls.first.position) workers = Units(self.workers, self) for mf in mfs: # type: Unit if workers: worker = workers.closest_to(mf) self.do(worker.gather(mf)) workers.remove(worker) for w in workers: # type: Unit self.do(w.gather(mfs.closest_to(w))) await self._do_actions(self.actions) self.actions.clear()
async def newNexusAndBase(self): if self.bot.units(NEXUS).amount < 2 and not self.bot.already_pending( NEXUS) and self.bot.can_afford(NEXUS): nexus = self.bot.units(NEXUS).first worker = self.bot.workers[0] minerals_next_nexus = self.bot.state.mineral_field.closer_than( 15, nexus) minerals = self.bot.state.mineral_field minerals = Units( self.removeMinerals(minerals_next_nexus, minerals), self.bot._game_data) mineral_field = minerals.closest_to(nexus) if not self.bot.units(PYLON).closer_than( 20.0, mineral_field ).exists and not self.bot.already_pending(PYLON): print("Build ", PYLON) await self.bot.build(PYLON, mineral_field, max_distance=10, unit=worker) if self.bot.can_afford(NEXUS): print("Build ", NEXUS) self.building_nexus = True await self.bot.build(NEXUS, mineral_field, max_distance=10, unit=worker)
class BallFormation(): def __init__(self, knowledge): self.ai = knowledge.ai self.knowledge: 'Knowledge' = knowledge self.unit_values: 'UnitValue' = knowledge.unit_values self.our_units: Units self.keep_together: List[UnitTypeId] = [ UnitTypeId.COLOSSUS, UnitTypeId.OBSERVER, UnitTypeId.PHOENIX ] self.enemy_units_in_combat: Units self.units_in_combat: Units self.units_to_regroup: Units self.minimum_distance = 3.5 def prepare_solve(self, our_units: Units, goal_position: Point2, combat_data: Dict[int, EnemyData], units_median: Point2): self.our_units = our_units time = self.knowledge.ai.time units_behind_tags = [] units_behind_tags.clear() average_distance2 = 0 wait_ended = False self.enemy_units_in_combat = Units([], self.ai) self.units_in_combat = Units([], self.ai) unit_count = len(our_units) # wait for 15% reinforcements wait_count = unit_count * 0.15 if any(our_units): our_units = our_units.sorted_by_distance_to(goal_position) self.units_gather = units_median for unit in our_units: enemy_data = combat_data[unit.tag] if enemy_data.powered_enemies.exists: self.enemy_units_in_combat.append(enemy_data.closest) self.units_in_combat.append(unit) elif enemy_data.enemies_exist: self.units_in_combat.append(unit) def solve_combat(self, goal: CombatGoal, command: CombatAction) -> CombatAction: if self.enemy_units_in_combat.exists: # Move in to assist closest friendly in combat closest_enemy = self.enemy_units_in_combat.closest_to((goal.unit)) return CombatAction(goal.unit, closest_enemy.position, command.is_attack) if goal.unit.distance_to( self.units_gather ) > self.minimum_distance + len(self.our_units) / 10: return CombatAction(goal.unit, self.units_gather, False) return command
def _get_builder(self, location=None): ws = self.bot.workers.gathering if ws: # if workers found not_scouts = Units([w for w in ws if self.scouting_worker is None or w.tag != self.scouting_worker.tag], self.bot.game_data()) if not_scouts.amount > 0: if location is None: return not_scouts.furthest_to(not_scouts.center) else: return not_scouts.closest_to(location) return None
def closest_distance_between_our_theirs(self, combined_enemies: Units) -> Tuple[float, Optional[Unit]]: own = self.ai.units.filter( lambda unit: not unit.is_structure and unit.type_id not in self.unit_values.combat_ignore ) closest: Optional[Unit] = None d = 0 for own_unit in own: # type: Unit closest_temp = combined_enemies.closest_to(own_unit) temp_distance = closest_temp.distance_to(own_unit) if closest is None or temp_distance < d: d = temp_distance closest = closest_temp return (d, closest)
def solve_combat(self, goal: CombatGoal, command: CombatAction, enemies: EnemyData) -> List[CombatAction]: oracle = goal.unit if not oracle.has_buff(BuffId.ORACLEWEAPON): goal.ready_to_shoot = False air_shooter_enemies = Units([], self.ai) enemy: Unit power = ExtendedPower(self.unit_values) for enemy in enemies.close_enemies: if self.unit_values.air_range(enemy) < enemy.distance_to(oracle) + 1: air_shooter_enemies.append(enemy) power.add_unit(enemy) if self.unit_values.is_static_air_defense(enemy): power.add(5) # can't beat turrets with oracle enemy_center = enemies.close_enemies.center for air_shooter in air_shooter_enemies: # type: Unit if air_shooter.is_light and not air_shooter.is_flying: power.add_units(air_shooter_enemies) else: power.add_units(air_shooter_enemies * 2) time = self.knowledge.ai.time if goal.move_type == MoveType.PanicRetreat and oracle.has_buff(BuffId.ORACLEWEAPON): return self.disable_beam(oracle) possible_targets = enemies.close_enemies.filter(lambda u: not u.is_flying and not u.is_structure and u.is_light) if possible_targets.exists: if oracle.energy > 50 and possible_targets.closest_distance_to(oracle) < 5 and not oracle.has_buff(BuffId.ORACLEWEAPON): return self.enable_beam(oracle) if power.air_power > 0 and power.air_power <= 3: target = air_shooter_enemies.closest_to(oracle) if target.is_light or target.health_percentage < 0.5: if not oracle.has_buff(BuffId.ORACLEWEAPON): return self.enable_beam(oracle) # Kill the target return [CombatAction(oracle, target, True)] #target_pos = self.knowledge.pathing_manager.find_weak_influence_air(goal.target, 7) #move_step = self.knowledge.pathing_manager.find_influence_air_path(oracle.position, target_pos) return [CombatAction(oracle, target.position, True)] elif goal.ready_to_shoot and possible_targets: return [CombatAction(oracle, possible_targets.closest_to(oracle), True)] elif power.air_power > 12: # Panic retreat to whatever direction if goal.move_type in offensive: new_target: Point2 = self.knowledge.pathing_manager.find_weak_influence_air(goal.target, 7) step = self.knowledge.pathing_manager.find_influence_air_path(oracle.position, new_target) # backstep: Point2 = self.knowledge.pathing_manager.find_weak_influence_air(oracle.position, 7) move_action = CombatAction(oracle, step, False) else: backstep = self.knowledge.pathing_manager.find_influence_air_path(oracle.position, goal.target) move_action = CombatAction(oracle, backstep, False) # Todo disable beam? return [move_action] elif power.air_power > 3: # Try kiting while killing the target target = self.knowledge.pathing_manager.find_weak_influence_air(goal.target, 7) backstep = self.knowledge.pathing_manager.find_influence_air_path(oracle.position, target) if goal.move_type in offensive: move_action = CombatAction(oracle, backstep, False) else: move_action = CombatAction(oracle, backstep, False) if oracle.has_buff(BuffId.ORACLEWEAPON): if possible_targets: closest = possible_targets.closest_to(oracle) if closest.distance_to(oracle) < 5: return [CombatAction(oracle, closest, True)] return [CombatAction(oracle, command.target, True), move_action] else: return [move_action] if possible_targets.exists: return [CombatAction(oracle, command.target, True)] else: return [CombatAction(oracle, command.target, False)]
class TestUnits(unittest.TestCase): # @classmethod # def setUpClass(cls): # pass # @classmethod # def tearDownClass(cls): # pass def setUp(self): mock_proto_data1 = MockProtoData(tag=245346374, pos=Mock(x=-5, y=6, z=50), health=35, health_max=45, orders=[ Mock(ability_id=AbilityId.ATTACK, target_unit_tag=1337, progress=1.0) ]) mock_proto_data2 = MockProtoData( tag=245346375, pos=Mock(x=-2, y=7, z=50), orders=[ Mock(ability_id=AbilityId.MOVE, target_world_space_pos=Point2((0, 0)), progress=1.0) ]) mock_proto_data3 = MockProtoData( tag=245346376, pos=Mock(x=7, y=7, z=50), ) self.mock_game_state = MockGameState() self.marine1 = Unit(mock_proto_data1, self.mock_game_state) self.marine2 = Unit(mock_proto_data2, self.mock_game_state) self.marine3 = Unit(mock_proto_data3, self.mock_game_state) self.marines = Units([self.marine1, self.marine2, self.marine3], self.mock_game_state) self.emptyUnitsGroup = Units([], self.mock_game_state) def tearDown(self): # unnecessary here del self.marine1 del self.marine2 del self.marine3 del self.marines del self.mock_game_state def test_amount(self): self.assertEqual(self.marines.amount, 3) self.assertEqual(self.emptyUnitsGroup.amount, 0) def test_empty(self): self.assertFalse(self.marines.empty) self.assertTrue(self.emptyUnitsGroup.empty) def test_exists(self): self.assertTrue(self.marines.exists) self.assertFalse(self.emptyUnitsGroup.exists) def test_find_by_tag(self): self.assertEqual(self.marines.find_by_tag(245346374), self.marine1) self.assertIsNone(self.marines.find_by_tag(245346)) def test_first(self): self.assertEqual(self.marines.first, self.marine1) def test_random(self): self.assertTrue( self.marines.random in [self.marine1, self.marine2, self.marine3]) def test_closest_distance_to(self): self.assertEqual(self.marines.closest_distance_to(Point2((10, 10))), (3**2 + 3**2)**0.5) def test_closest_to(self): self.assertEqual(self.marines.closest_to(Point2((10, 10))), self.marine3) def test_furthest_to(self): self.assertEqual(self.marines.furthest_to(Point2((10, 10))), self.marine1) def test_closer_than(self): self.assertEqual(self.marines.closer_than(20, Point2((10, 10))), self.marines) self.assertEqual(self.marines.closer_than(6, Point2((10, 10))), Units([self.marine3], self.mock_game_state)) self.assertEqual(self.marines.closer_than(2, Point2((10, 10))), self.emptyUnitsGroup) def test_tags_in(self): self.assertEqual( self.marines.tags_in({245346374, 245346375}), Units([self.marine1, self.marine2], self.mock_game_state)) self.assertEqual(self.marines.tags_in({}), self.emptyUnitsGroup) def test_tags_not_in(self): self.assertEqual(self.marines.tags_not_in({}), self.marines) self.assertEqual( self.marines.tags_not_in({245346374}), Units([self.marine2, self.marine3], self.mock_game_state)) def test_of_type(self): self.assertEqual(self.marines.of_type(UnitTypeId.MARINE), self.marines) self.assertEqual(self.marines.of_type([UnitTypeId.MARINE]), self.marines) def test_exclude_type(self): self.assertEqual(self.marines.exclude_type([UnitTypeId.MARINE]), self.emptyUnitsGroup) def test_tags(self): self.assertSetEqual(self.marines.tags, {u.tag for u in self.marines}) def test_noqueue(self): self.assertEqual(self.marines.noqueue, Units([self.marine3], self.mock_game_state)) def test_idle(self): self.assertEqual(self.marines.idle, Units([self.marine3], self.mock_game_state)) def test_owned(self): self.assertEqual(self.marines.owned, self.marines) def test_enemy(self): self.assertEqual(self.marines.enemy, self.emptyUnitsGroup)