def evaluate_engagement(self, own_units: Units, enemy_units: Units, bias=1): own_ranged: Units = own_units.filter(lambda u: u.ground_range > 3) own_melee: Units = own_units.tags_not_in(own_ranged.tags) enemy_ranged: Units = enemy_units.filter(lambda u: u.ground_range > 3) try: own_ranged_value = bias * self.bot.calculate_combat_value( own_ranged) except: own_ranged_value = 0 try: enemy_ranged_value = self.bot.calculate_combat_value(enemy_ranged) except: enemy_ranged_value = 0 corrected_own_value = bias * self.bot.calculate_combat_value(own_units) if own_ranged_value < enemy_ranged_value and own_units.exists: perimeter = self.get_enemy_perimeter( enemy_units.not_structure, self.bot.known_enemy_structures, own_units.center) if own_melee.exists: own_melee_value = bias * self.bot.calculate_combat_value( Units(own_melee.take(perimeter * 2, require_all=False), self.bot._game_data)) else: own_melee_value = 0 corrected_own_value = own_melee_value + own_ranged_value evaluation = corrected_own_value - self.bot.calculate_combat_value( enemy_units) return evaluation
def group_solve_combat(self, units: Units, current_command: Action) -> Action: beaming_phoenixes = units.filter(lambda p: p.orders and p.orders[0].ability.id == AbilityId.GRAVITONBEAM_GRAVITONBEAM) if beaming_phoenixes and len(beaming_phoenixes) > len(units) * 0.5: self.allow_lift = False else: self.allow_lift = True return current_command
def __init__(self, knowledge: Knowledge, close_enemies: Units, unit: Unit, our_units: Units, our_median: Point2): self.ai = knowledge.ai self.our_units = our_units self.our_median = our_median self.close_enemies = close_enemies self.my_height = self.ai.get_terrain_height(unit) self.enemy_power = ExtendedPower(knowledge.unit_values) self.our_power = ExtendedPower(knowledge.unit_values) for unit in our_units: # type: Unit self.our_power.add_unit(unit) self.worker_only = False if self.close_enemies.exists: self.enemy_center = close_enemies.center # Can be empty! self.powered_enemies = close_enemies.filter(lambda x: knowledge.unit_values.power(x) > 0.1) if self.powered_enemies.exists: self.closest = unit.position.closest(self.powered_enemies) self.worker_only = True for enemy in self.powered_enemies: # type: Unit if not knowledge.unit_values.is_worker(enemy): self.worker_only = False self.enemy_power.add_unit(enemy) else: self.closest = unit.position.closest(self.close_enemies) self.enemy_center_height = self.ai.get_terrain_height(self.enemy_center) self.closest_height = self.ai.get_terrain_height(self.closest) else: self.powered_enemies = Units([], self.ai) # empty list
def enemy_in_range(self, position: Point2, range: Union[int, float], only_targetable = True) -> Units: units = Units([], self.ai) if self.enemy_tree is None: return units for index in self.enemy_tree.query_ball_point(np.array([position.x, position.y]), range): units.append(self.knowledge.known_enemy_units[index]) if only_targetable: return units.filter(lambda x: x.can_be_attacked or x.is_snapshot) return units
def calculate_combat_value(self, units: Units): value = 0 for unit in units.filter(lambda u: u.can_attack_ground): if unit.type_id == DRONE or unit.type_id == UnitTypeId.PROBE or unit.type_id == UnitTypeId.SCV: resources = (10, 0) elif unit.type_id == UnitTypeId.BUNKER: resources = (300, 0) else: resources = self.get_resource_value(unit.type_id) minerals = resources[0] vespene = resources[1] value += (minerals + vespene) return value
def in_attack_range_of( self, unit: Unit, enemies: Units, bonus_distance: Union[int, float] = 0 ) -> Optional[Units]: """ Get enemies in attack range of a given unit @param unit: @param enemies: @param bonus_distance: @return: """ if not unit or not enemies: return None return enemies.filter( lambda e: self.target_in_range(unit, e, bonus_distance=bonus_distance) )
async def defender_base(self, iteration, units: Units): for nexus in self.townhalls: enemysNear = (self.enemy_units | self.enemy_structures ).filter(lambda unit: unit.can_be_attacked and unit. is_attacking).closer_than(15, nexus) if enemysNear.amount > 0: ownUnitsNear = units.filter( lambda unit: unit.can_attack).closer_than(20, nexus) print("atacando para defender") if ownUnitsNear.amount >= enemysNear.amount * 0.6: print("atacando para defender") for unit in ownUnitsNear: unit.attack(enemysNear.closest_to(unit)) else: print("Foge para defender") nexusAux = self.townhalls nexusAux.remove(nexus) for unit in ownUnitsNear: unit.move(nexusAux.closest_to(nexus))
def add_workers(self, new_workers: Units): try: # Only add the units to the workers list if all of them are workers and aren't already in the list if new_workers.amount == new_workers(UnitTypeId.PROBE).amount: # Only add the units to the workers list if none them already is in the list if new_workers.filter(lambda w: w in self.workers).empty: self.workers.extend(new_workers) else: raise WorkerManagementException else: raise UnitTypeException except UnitTypeException: print( f"Only workers can be added to a workers list: {nw.type_id for nw in new_workers}" ) print() except WorkerManagementException: print( f"Some of the workers are already associated to the base: {nw.tag for nw in new_workers} | {w.tag for w in self.workers}" ) print()
async def pickup_micro(bot: sc2.BotAI, marines: Units = None, medivacs: Units = None, endangered_marines_tags: Set[int] = set(), target: Point2 = None, retreat_point: Point2 = None): """ Pickup micro on medivacs and marines. - Marines a move to enemy main. - Medivacs heal lowest marines. - Stim when in range of an enemy unit. Marines less than EMPATHY_STIM_RANGE away from a stimmed marine will stim themselves. - Marines are picked up when at or below MARINE_PICKUP_THRESHOLD, and dropped off at a safe location. """ MARINE_PICKUP_THRESHOLD = 10 EMPATHY_STIM_RANGE = 10 marines: Units = marines medivacs: Units = medivacs target: Point2 = target or bot.enemy_start_locations[0] retreat_point: Point2 = bot.start_location energy_medivacs: Units = medivacs.filter( lambda m: m.energy_percentage >= 0.1) for marine in marines: endangered_marines_nearby = marines.filter( lambda u: u.type_id == UnitTypeId.MARINE and u.tag != marine.tag and u.tag in endangered_marines_tags and u.distance_to( marine) <= EMPATHY_STIM_RANGE) marine_endangered = marine.tag in endangered_marines_tags if (marine_endangered and marine.health <= MARINE_PICKUP_THRESHOLD and medivacs): closest_medivac = medivacs.filter( lambda m: m.cargo_left > 0).sorted( key=lambda m: m.distance_to(marine)) marine.smart(closest_medivac.first) elif ((marine_endangered or endangered_marines_nearby) and not marine.has_buff(BuffId.STIMPACK) and energy_medivacs): marine(AbilityId.EFFECT_STIM_MARINE) else: marine.attack(target) sorted_marines = marines.sorted(key=lambda m: m.health) sorted_marines_iter = iter(sorted_marines) endangered_marines = sorted_marines.filter( lambda m: m.tag in endangered_marines_tags) endangered_marines_iter = iter(endangered_marines) for medivac in medivacs: if medivac.has_cargo: # drop off at closest safe position enemies_in_range = bot.enemy_units.filter( lambda e: e.ground_range >= e.distance_to(medivac)).sorted( lambda e: e.distance_to(medivac)) if (not enemies_in_range and ((await bot.can_place(UnitTypeId.SENSORTOWER, [medivac.position]))[0] or (await bot.can_place(UnitTypeId.CREEPTUMOR, [medivac.position]))[0])): # TODO: make sure location valid, and within expo radius medivac(AbilityId.UNLOADALLAT_MEDIVAC, medivac) if medivac.is_moving: medivac.hold_position() elif enemies_in_range: # TODO: helper method to determine "direction" of battle first_enemy = enemies_in_range.first.position enemy_vector = (first_enemy.x - medivac.position.x, first_enemy.y - medivac.position.y) safe_point = (medivac.position.x - enemy_vector[0], medivac.position.y - enemy_vector[1]) medivac.move(medivac.position.towards(Point2(safe_point), 3)) else: medivac.move(retreat_point) elif not (len(medivac.orders) > 0 and medivac.orders[0].ability.id == AbilityId.LOAD_MEDIVAC): next_endangered_marine = next(endangered_marines_iter, None) if next_endangered_marine: if not medivac.has_buff( BuffId.MEDIVACSPEEDBOOST) and await bot.can_cast( medivac, AbilityId.EFFECT_MEDIVACIGNITEAFTERBURNERS): medivac(AbilityId.EFFECT_MEDIVACIGNITEAFTERBURNERS) elif next_endangered_marine.health <= MARINE_PICKUP_THRESHOLD: # move and load medivac(AbilityId.LOAD_MEDIVAC, next_endangered_marine) else: medivac(AbilityId.MEDIVACHEAL_HEAL, next_endangered_marine) elif marines: next_marine = next(sorted_marines_iter, sorted_marines.random_or(None)) if next_marine: medivac.attack(next_marine.position) else: # no marines medivac.move(retreat_point)