コード例 #1
0
    async def _control_inject_queen_near_base(
        self,
        air_threats_near_bases: Units,
        ground_threats_near_bases: Units,
        queen: Unit,
        townhall: Unit,
        grid: Optional[np.ndarray] = None,
    ) -> None:
        """
        Between injects, we want the Queen to have the following behavior:
        - Attack any enemy that gets too close
        - Move the Queen back if she goes too far from the townhall
        - Stay out of the mineral line, incase bot has custom mineral gathering (don't block workers)
        """
        # don't do anything else, just move the queen back
        if queen.distance_to(townhall) > 8:
            queen.move(townhall)
            return

        close_threats: Units = Units([], self.bot)
        # we can only have close threats if enemy are near our bases in the first place
        # so save calculation otherwise
        if air_threats_near_bases or ground_threats_near_bases:
            close_threats = self.bot.enemy_units.filter(
                lambda enemy: enemy.position.distance_to(townhall) < 12)

        if close_threats:
            await self.do_queen_micro(queen, close_threats, grid)
        # every now and then, check queen is not in the mineral field blocking workers
        elif self.bot.state.game_loop % 32 == 0:
            close_mfs: Units = self.bot.mineral_field.filter(
                lambda mf: mf.distance_to(townhall) < 8)
            # make a small adjustment away from the minerals
            if close_mfs and queen.distance_to(close_mfs.center) < 6:
                queen.move(queen.position.towards(close_mfs.center, -1))
コード例 #2
0
    def move_phoenix(self, phoenix: Unit):
        enemy_main = self.knowledge.enemy_expansion_zones[0].center_location
        if phoenix.distance_to(enemy_main) <= 10:
            self.reached_enemy_main = True

        if not self.reached_enemy_main:
            target = self.select_target()
            self.do(phoenix.move(target))

            if target != self.last_target:
                self.last_target = target
                self.print(f"scouting {target}, interval {self.time_interval}")
        else:
            # This else makes it scout around possible main tech positions
            if self.last_target is None:
                self.last_target = self.select_target()

            if self.ai.enemy_race == Race.Protoss:
                new_target = self.knowledge.enemy_expansion_zones[
                    0].behind_mineral_position_center.towards(
                        self.knowledge.enemy_expansion_zones[0].
                        mineral_line_center, 20).random_on_distance(7)
                if phoenix.distance_to(self.last_target) <= 3:
                    self.do(phoenix.move(new_target))
                    self.last_target = new_target
            elif self.ai.enemy_race == Race.Terran:
                new_target = self.knowledge.enemy_expansion_zones[
                    1].behind_mineral_position_center.towards(
                        self.knowledge.enemy_expansion_zones[1].
                        mineral_line_center, 20).random_on_distance(7)
                if phoenix.distance_to(self.last_target) <= 3:
                    self.do(phoenix.move(new_target))
                    self.last_target = new_target
コード例 #3
0
    def use_force_field(self, enemies: EnemyData, sentry: Unit, time: float):
        force_field_is_good_idea = self.last_force_field_time + self.force_field_cooldown < time
        for key, value in self.tag_shield_used_dict.items():
            if value + 5 < time:
                # Some sentry has used its shield, it might be a good idea to use FF now
                force_field_is_good_idea = True

        if not force_field_is_good_idea:
             return [] # Hard priorizationg for guardian shield.

        relevant_enemies = enemies.close_enemies.not_structure.not_flying\
            .exclude_type(UnitValue.worker_types).exclude_type(UnitTypeId.SIEGETANKSIEGED)

        if sentry.energy < FORCE_FIELD_ENERGY_COST or relevant_enemies.amount < 5 or enemies.enemy_power.ground_presence < 15:
            return []

        center = relevant_enemies.center

        if self.last_force_field_time + 2 > time and len(self.last_force_field_positions) > self.last_force_fields_used:
            index = self.last_force_fields_used
            position = self.last_force_field_positions[index]
            if sentry.distance_to(position) < 9:
                self.last_force_fields_used += 1
                self.knowledge.print(f"JOINING FORCE FIELDS {position}!")
                return [CombatAction(sentry, position, False, ability= AbilityId.FORCEFIELD_FORCEFIELD)]
            else:
                self.knowledge.print(f"TOO FAR AWAY TO JOIN FORCE FIELDS {position}!")
                return[CombatAction(sentry, position, False)]

        if self.last_force_field_time + self.force_field_cooldown < time:
            point: Point2 = relevant_enemies.closest_to(sentry).position
            target_center = point.towards(center, 3)
            distance = sentry.distance_to(target_center)

            if distance < 9:
                # Activate force fields!
                self.last_force_field_time = time
                self.last_force_fields_used = 1
                point = sentry.position
                point = target_center.towards(point, 1)
                direction_v = target_center.offset( (-point.x, -point.y))
                perpenticular_v = Point2((direction_v.y, -direction_v.x))

                if enemies.powered_enemies(UnitTypeId.ZERGLING).amount - 10 > enemies.powered_enemies.amount:
                    if enemies.powered_enemies.amount > 10:
                        self.last_force_field_positions = self.ff_pos(target_center, direction_v, perpenticular_v, ff_centercube)
                    else:
                        self.last_force_field_positions = self.ff_pos(target_center, direction_v, perpenticular_v, ff_triangle)

                elif enemies.enemy_power.ground_presence > 25:
                    # Only use 5x FF against huge masses
                    self.last_force_field_positions = self.ff_pos(target_center, direction_v, perpenticular_v, ff_wall5)
                else:
                    self.last_force_field_positions = self.ff_pos(target_center, direction_v, perpenticular_v, ff_wall3)
                self.knowledge.print(f"Force fields ordered to: {self.last_force_field_positions}")

                return [CombatAction(sentry, self.last_force_field_positions[0], False,
                                     ability=AbilityId.FORCEFIELD_FORCEFIELD)]
        return []
コード例 #4
0
ファイル: defence.py プロジェクト: august-k/queens-sc2
    async def handle_unit(
        self,
        air_threats_near_bases: Units,
        ground_threats_near_bases: Units,
        unit: Unit,
        th_tag: int = 0,
    ) -> None:
        if self.policy.pass_own_threats:
            air_threats: Units = air_threats_near_bases
            ground_threats: Units = ground_threats_near_bases
        else:
            air_threats: Units = self.enemy_air_threats
            ground_threats: Units = self.enemy_ground_threats

        transfuse_target: Unit = self.get_transfuse_target(unit.position)
        self.used_transfuse_this_step: bool = False
        if (transfuse_target and transfuse_target is not unit
                and not self.used_transfuse_this_step):
            unit(AbilityId.TRANSFUSION_TRANSFUSION, transfuse_target)
            self.used_transfuse_this_step = True
        elif self.priority_enemy_units:
            await self.do_queen_micro(unit, self.priority_enemy_units)
        elif self.policy.attack_condition():
            await self.do_queen_offensive_micro(unit,
                                                self.policy.attack_target)
        elif self.policy.defend_against_ground and ground_threats:
            await self.do_queen_micro(unit, ground_threats)
        elif self.policy.defend_against_air and air_threats:
            await self.do_queen_micro(unit, air_threats)
        elif unit.distance_to(self.policy.rally_point) > 12:
            unit.move(self.policy.rally_point)
コード例 #5
0
    async def handle_unit(
        self,
        air_threats_near_bases: Units,
        ground_threats_near_bases: Units,
        priority_enemy_units: Units,
        unit: Unit,
        th_tag: int = 0,
        grid: Optional[np.ndarray] = None,
        nydus_networks: Optional[Units] = None,
        nydus_canals: Optional[Units] = None,
    ) -> None:
        canal: Optional[Unit] = None
        network: Optional[Unit] = None
        # canal is what we place else where on the map
        if nydus_canals:
            canal = nydus_canals.closest_to(self.policy.nydus_target)
        # network is what is morphed from a drone
        if nydus_networks:
            network = nydus_networks.closest_to(self.bot.start_location)

        unit_distance_to_target: float = unit.distance_to(self.policy.nydus_target)

        if canal and network:
            await self._manage_nydus_attack(
                canal, network, unit, unit_distance_to_target, grid
            )
コード例 #6
0
    def position_terran(self, unit: Unit) -> Optional[Point2]:
        """
        Copied and modified from grid_building.py
        Finds the closest landing location to dettach from addons.
        """
        buildings = self.ai.structures

        current_location: Optional[Point2] = None
        current_distance = math.inf

        reserved_landing_locations: Set[Point2] = set(
            self.knowledge.building_solver.structure_target_move_location.
            values())

        for point in self.knowledge.building_solver.building_position:
            # If a structure is landing here from AddonSwap() then dont use this location
            if point in reserved_landing_locations:
                continue
                # If this location has a techlab or reactor next to it, then don't create a new structure here
            if point in self.knowledge.building_solver.free_addon_locations:
                continue
            if buildings.closer_than(1, point):
                continue
            dist = unit.distance_to(point)
            if dist < current_distance:
                current_location = point
                current_distance = dist
        return current_location
コード例 #7
0
    async def handle_unit(
        self,
        air_threats_near_bases: Units,
        ground_threats_near_bases: Units,
        unit: Unit,
        priority_enemy_units: Units,
        th_tag: int = 0,
    ) -> None:

        should_spread_creep: bool = self._check_queen_can_spread_creep(unit)
        self.creep_targets = self.policy.creep_targets

        if priority_enemy_units:
            await self.do_queen_micro(unit, priority_enemy_units)
        elif (self.policy.defend_against_air and air_threats_near_bases
              and not should_spread_creep):
            await self.do_queen_micro(unit, air_threats_near_bases)
        elif (self.policy.defend_against_ground and ground_threats_near_bases
              and not should_spread_creep):
            await self.do_queen_micro(unit, ground_threats_near_bases)
        elif self.bot.enemy_units and self.bot.enemy_units.filter(
                # custom filter to replace in_attack_range_of so that it can be used with memory units
                lambda enemy: enemy.position.distance_to(unit) < max(
                    unit.air_range, unit.ground_range)):
            unit.move(self.policy.rally_point)
        elif (unit.energy >= 25 and len(unit.orders) == 0
              and self.creep_coverage < self.policy.target_perc_coverage):
            await self.spread_creep(unit)
        elif unit.distance_to(self.policy.rally_point) > 7:
            if len(unit.orders) > 0:
                if unit.orders[0].ability.button_name != "CreepTumor":
                    unit.move(self.policy.rally_point)
            elif len(unit.orders) == 0:
                unit.move(self.policy.rally_point)
コード例 #8
0
    def _check_nydus_role(self, queen: Unit) -> None:
        """
        If there are nydus's we may want to steal this queen for the nydus
        Or if this queen already has a nydus role, we should remove the nydus role if required
        """
        steal_from: Set[UnitID] = self.nydus.policy.steal_from
        # check if queens should be assigned to nydus role, is there a network and a canal?
        if (self.nydus_networks and self.nydus_canals
                and self.nydus.policy.active
                and len(self.nydus_queen_tags) < self.nydus.policy.max_queens
                and queen.tag not in self.nydus_queen_tags
                and queen.tag in self.assigned_queen_tags):
            # queen can only be in one role
            role_to_check: QueenRoles = (
                QueenRoles.Defence if queen.tag in self.defence_queen_tags else
                (QueenRoles.Creep if queen.tag in self.creep_queen_tags else
                 QueenRoles.Defence))
            # queen role is in one of the allowed roles to steal from
            if role_to_check in steal_from:
                self.remove_unit(queen.tag)
                self.assigned_queen_tags.add(queen.tag)
                self.nydus_queen_tags.append(queen.tag)

        # TODO: Work out how to handle aborting a Nydus:
        #   - Policy option for when Queen goes back into canal if too much danger?
        #   - What if the canal dies and the queen has an escape path?
        # At the moment assigning a Queen to Nydus is a one way trip
        # Here we only handle, Queens being assigned to Nydus and then the canal getting destroyed in the meantime
        if (queen.tag in self.nydus_queen_tags
                and queen.distance_to(self.nydus.policy.nydus_target) > 50
                and not self.nydus_canals):
            # removing should be enough, queen then should be given a new role automatically
            self.remove_unit(queen.tag)
コード例 #9
0
ファイル: inject.py プロジェクト: august-k/queens-sc2
    async def handle_unit(
        self,
        air_threats_near_bases: Units,
        ground_threats_near_bases: Units,
        unit: Unit,
        th_tag: int,
    ) -> None:
        if self.policy.pass_own_threats:
            air_threats: Units = air_threats_near_bases
            ground_threats: Units = ground_threats_near_bases
        else:
            air_threats: Units = self.enemy_air_threats
            ground_threats: Units = self.enemy_ground_threats

        ths: Units = self.bot.townhalls.ready.tags_in([th_tag])
        if ths:
            th: Unit = ths.first
            if self.priority_enemy_units:
                await self.do_queen_micro(unit, self.priority_enemy_units)
            elif self.policy.defend_against_air and air_threats:
                await self.do_queen_micro(unit, air_threats)
            elif self.policy.defend_against_ground and ground_threats:
                await self.do_queen_micro(unit, ground_threats)
            else:
                if unit.energy >= 25:
                    unit(AbilityId.EFFECT_INJECTLARVA, th)
                # regardless of policy, chase away enemy close to th
                # but if queen gets too far away, walk back to th
                elif unit.distance_to(th) > 7:
                    unit.move(th.position)
                elif self.bot.enemy_units.filter(
                        lambda enemy: enemy.position.distance_to(unit) < 10):
                    unit.attack(
                        self.find_closest_enemy(unit, self.bot.enemy_units))
コード例 #10
0
    async def handle_unit(
        self,
        air_threats_near_bases: Units,
        ground_threats_near_bases: Units,
        priority_enemy_units: Units,
        unit: Unit,
        th_tag: int = 0,
        grid: Optional[np.ndarray] = None,
        nydus_networks: Optional[Units] = None,
        nydus_canals: Optional[Units] = None,
    ) -> None:

        if priority_enemy_units:
            await self.do_queen_micro(unit, priority_enemy_units, grid)
        elif self.policy.attack_condition():
            await self.do_queen_offensive_micro(unit,
                                                self.policy.attack_target)
        elif self.policy.defend_against_ground and ground_threats_near_bases:
            await self.do_queen_micro(unit, ground_threats_near_bases, grid)
        elif self.policy.defend_against_air and air_threats_near_bases:
            await self.do_queen_micro(unit, air_threats_near_bases, grid)
        elif (self.map_data and grid is not None
              and not self.is_position_safe(grid, unit.position)):
            await self.move_towards_safe_spot(unit, grid)
        elif unit.distance_to(self.policy.rally_point) > 12:
            unit.move(self.policy.rally_point)
コード例 #11
0
ファイル: micro_voidrays.py プロジェクト: lladdy/sharpy-sc2
    def unit_solve_combat(self, unit: Unit, current_command: Action) -> Action:
        if self.engage_ratio < 0.25 and self.can_engage_ratio < 0.25:
            return current_command

        if self.move_type in {MoveType.PanicRetreat, MoveType.DefensiveRetreat}:
            return current_command

        if self.cd_manager.is_ready(unit.tag, AbilityId.EFFECT_VOIDRAYPRISMATICALIGNMENT):
            close_enemies = self.cache.enemy_in_range(unit.position, 7).filter(lambda u: u.is_armored)
            if close_enemies:
                return Action(None, False, AbilityId.EFFECT_VOIDRAYPRISMATICALIGNMENT)

        shoot = self.should_shoot(unit)
        if not shoot:
            if self.should_retreat(unit):
                pos = self.pather.find_weak_influence_air(unit.position, 4)
                return Action(pos, False)

        current_command = self.focus_fire(unit, current_command, None)

        if not shoot:
            if self.engaged_power.air_power < 1:
                if unit.distance_to(current_command.target) > 2:
                    return Action(current_command.target.position, False)
        return current_command
コード例 #12
0
    def evasive_move_to(self, position_to, unit: Unit):
        enemy_anti_air_units = self.knowledge.unit_cache.enemy_in_range(unit.position3d, 11) \
            .filter(lambda u: u.can_attack_air).visible

        if enemy_anti_air_units.exists:
            position = unit.position3d
            for aa in enemy_anti_air_units:
                distance = unit.distance_to(aa.position3d)
                amount_of_evade = 15 - distance
                if distance > 0:
                    position = position.towards(aa, -amount_of_evade)
            # after the for loop, position is the best vector away from enemy
            distance_to_best_evade_point = unit.distance_to(position)
            should_go = position.towards(position_to,
                                         distance_to_best_evade_point)
            return Action(should_go, False)
        else:
            return Action(position_to, False)
コード例 #13
0
 async def harass_command(self, dt: Unit, prism: Unit):
     self.knowledge.roles.set_task(UnitTask.Reserved, dt)
     if self.is_revealed_by_enemy(dt):
         if dt.distance_to(
                 prism) <= 5 and prism.shield_health_percentage >= 0.4:
             self.do(dt.smart(prism))
             return True
         else:
             self.do(dt.move(prism))
             return True
     else:
         await self.attack_priority_targets(dt, prism)
     return True
コード例 #14
0
 def is_revealed_by_enemy(self, dt: Unit) -> bool:
     detectors = self.knowledge.unit_cache.enemy_in_range(dt.position, 20) \
         .filter(lambda x: (x.detect_range - 1) > dt.distance_to(x.position))
     if detectors.exists:
         if detectors.filter(lambda x: x.is_flying).exists:
             self.enemy_air_detector = True
         return True
     for effect in self.ai.state.effects:
         if effect.id == EffectId.SCANNERSWEEP:
             if Point2.center(effect.positions).distance_to(
                     dt.position) < 15:
                 return True
     return False
コード例 #15
0
 def attack_prime(self, unit: Unit, target: Unit) -> bool:
     if (
             self.WORKERS
     ):  # probably should change this name as it's referring to closest enemy workers to the reaper
         workers = self.WORKERS.filter(
             lambda unit: unit.distance_to(unit.position) < 20)
         if len(workers) > 0:
             prime_target = min(self.WORKERS,
                                key=lambda x: x.health_percentage)
             self.ai.do(unit.attack(prime_target))
             return True
     self.ai.do(unit.attack(target))
     return True
コード例 #16
0
ファイル: creep.py プロジェクト: august-k/queens-sc2
    async def handle_unit(
        self,
        air_threats_near_bases: Units,
        ground_threats_near_bases: Units,
        unit: Unit,
        th_tag: int = 0,
    ) -> None:
        if self.policy.pass_own_threats:
            air_threats: Units = air_threats_near_bases
            ground_threats: Units = ground_threats_near_bases
        else:
            air_threats: Units = self.enemy_air_threats
            ground_threats: Units = self.enemy_ground_threats

        should_spread_creep: bool = self._check_queen_can_spread_creep(unit)
        self.creep_targets = self.policy.creep_targets
        transfuse_target: Unit = self.get_transfuse_target(unit.position)
        # allow transfuse if energy has built up
        if unit.energy >= 50 and transfuse_target and transfuse_target is not unit:
            unit(AbilityId.TRANSFUSION_TRANSFUSION, transfuse_target)
        elif self.priority_enemy_units:
            await self.do_queen_micro(unit, self.priority_enemy_units)
        elif self.policy.defend_against_air and air_threats and not should_spread_creep:
            await self.do_queen_micro(unit, air_threats)
        elif (
            self.policy.defend_against_ground
            and ground_threats
            and not should_spread_creep
        ):
            await self.do_queen_micro(unit, ground_threats)
        elif self.bot.enemy_units and self.bot.enemy_units.filter(
            # custom filter to replace in_attack_range_of so that it can be used with memory units
            lambda enemy: enemy.position.distance_to(unit)
            < max(unit.air_range, unit.ground_range)
        ):
            unit.move(self.policy.rally_point)
        elif (
            unit.energy >= 25
            and len(unit.orders) == 0
            and self.creep_coverage < self.policy.target_perc_coverage
        ):
            await self.spread_creep(unit)
        elif unit.distance_to(self.policy.rally_point) > 7:
            if len(unit.orders) > 0:
                if unit.orders[0].ability.button_name != "CreepTumor":
                    unit.move(self.policy.rally_point)
            elif len(unit.orders) == 0:
                unit.move(self.policy.rally_point)
コード例 #17
0
    async def attack_command(self, unit: Unit, prism: Unit):
        self.knowledge.roles.set_task(UnitTask.Reserved, unit)
        if self.is_revealed_by_enemy(unit):
            if unit.distance_to(
                    prism) <= 8 and prism.shield_health_percentage >= 0.4:
                self.do(unit.smart(prism))
                return True

            else:
                base = self.knowledge.own_main_zone.center_location
                self.do(unit.move(base))
                return True

        else:
            await self.attack_priority_targets(unit, prism)
        return True
コード例 #18
0
    def unit_solve_combat(self, unit: Unit, current_command: Action) -> Action:
        relevant_enemies = self.enemies_near_by.not_flying.visible
        siege_mode: Optional[AbilityId] = None

        if self.move_type in {
                MoveType.PanicRetreat, MoveType.DefensiveRetreat
        }:
            if unit.type_id == UnitTypeId.SIEGETANKSIEGED and not relevant_enemies.exists:
                siege_mode = AbilityId.UNSIEGE_UNSIEGE
        else:
            if relevant_enemies.exists:
                distance = relevant_enemies.closest_distance_to(unit)
            else:
                distance = 100

            # distance_closest = enemies.closest.distance_to(unit)

            unsiege_threshold = 15
            if self.move_type == MoveType.SearchAndDestroy:
                unsiege_threshold = 20

            status = self.get_siege_status(unit)

            if unit.type_id == UnitTypeId.SIEGETANK and distance > 5 and distance < 13:
                # don't siege up on the main base ramp!
                if unit.distance_to(
                        self.knowledge.enemy_base_ramp.bottom_center) > 7:
                    siege_mode = AbilityId.SIEGEMODE_SIEGEMODE

            if distance > unsiege_threshold and \
                    (unit.type_id == UnitTypeId.SIEGETANKSIEGED and distance > unsiege_threshold):
                siege_mode = AbilityId.UNSIEGE_UNSIEGE

            if unit.type_id == UnitTypeId.SIEGETANKSIEGED and not relevant_enemies.exists:
                siege_mode = AbilityId.UNSIEGE_UNSIEGE

        status = self.get_siege_status(unit)
        order = status.relay_order(unit, siege_mode, self.ai.time)

        if order:
            return order

        if unit.type_id == UnitTypeId.SIEGETANKSIEGED:
            return current_command
        else:
            return super().unit_solve_combat(unit, current_command)
コード例 #19
0
ファイル: spread_creep2.py プロジェクト: etzhang416/sc2_bot
    def get_next_creep_tumor_position(self, tumor: Unit) -> Optional[Point2]:
        """ Tries to find a suitable position for tumors to move to next. """
        tumor_pos: Point2 = tumor.position
        # TODO Find the closest by ground path instead of air distance
        target_pos = tumor_pos.closest(self.available_tumor_locations)

        path = self.knowledge.pathing_manager.path_finder_terrain.find_path(
            tumor_pos, target_pos)[0]
        # Skip positions close to the tumor, try to find the location furthest from tumor first
        for position_tuple in path[:2:-1]:
            position = Point2(position_tuple)
            # Although creep tumor have 10 cast range on tumor placements, there are still sometimes errors of 'too far away'
            if self.is_placeable(position) and self.ai.is_visible(
                    position) and tumor.distance_to(position) < 9:
                return position

        # A position could not be found, use the old function to find a location
        # TODO Investigate why sometimes a tumor location could not be found, ideas: next location is blocked by vision blocker or creeping up a ramp
        return self.get_next_creep_tumor_position2(tumor)
コード例 #20
0
ファイル: creep.py プロジェクト: raspersc2/queens-sc2
    async def spread_creep(self, queen: Unit,
                           grid: Optional[np.ndarray]) -> None:
        if self.creep_target_index >= len(self.creep_targets):
            self.creep_target_index = 0

        if self.first_tumor and self.policy.first_tumor_position:
            queen(AbilityId.BUILD_CREEPTUMOR_QUEEN,
                  self.policy.first_tumor_position)
            # retry a few times, sometimes queen gets blocked when spawning
            if self.first_tumor_retry_attempts > 5:
                self.first_tumor = False
            self.first_tumor_retry_attempts += 1
            return

        should_lay_tumor: bool = True
        # if using map_data, creep will follow ground path to the targets
        if self.map_data:
            if grid is None:
                grid = self.map_data.get_pyastar_grid()
            pos: Point2 = self._find_closest_to_target_using_path(
                self.creep_targets[self.creep_target_index], self.creep_map,
                grid)

        else:
            pos: Point2 = self._find_closest_to_target(
                self.creep_targets[self.creep_target_index], self.creep_map)

        if (not pos or (self.policy.should_tumors_block_expansions is False
                        and self.position_blocks_expansion(pos))
                or self.position_near_enemy_townhall(pos)
                or self.position_near_nydus_worm(pos)
                or self._existing_tumors_too_close(pos)):
            should_lay_tumor = False

        if should_lay_tumor:
            queen(AbilityId.BUILD_CREEPTUMOR_QUEEN, pos)
            self.pending_positions.append((pos, self.bot.time))

        # can't lay tumor right now, go back home
        elif queen.distance_to(self.policy.rally_point) > 7:
            queen.move(self.policy.rally_point)

        self.creep_target_index += 1
コード例 #21
0
ファイル: creep.py プロジェクト: raspersc2/queens-sc2
    async def handle_unit(
        self,
        air_threats_near_bases: Units,
        ground_threats_near_bases: Units,
        priority_enemy_units: Units,
        unit: Unit,
        th_tag: int = 0,
        grid: Optional[np.ndarray] = None,
        nydus_networks: Optional[Units] = None,
        nydus_canals: Optional[Units] = None,
    ) -> None:

        should_spread_creep: bool = self._check_queen_can_spread_creep(unit)
        self.creep_targets = self.policy.creep_targets

        if priority_enemy_units:
            await self.do_queen_micro(unit, priority_enemy_units, grid)
        elif (self.policy.defend_against_air and air_threats_near_bases
              and not should_spread_creep):
            await self.do_queen_micro(unit, air_threats_near_bases, grid)
        elif (self.policy.defend_against_ground and ground_threats_near_bases
              and not should_spread_creep):
            await self.do_queen_micro(unit, ground_threats_near_bases, grid)
        elif self.bot.enemy_units and self.bot.enemy_units.filter(
                # custom filter to replace in_attack_range_of so that it can be used with memory units
                lambda enemy: enemy.position.distance_to(unit) < max(
                    unit.air_range, unit.ground_range)):
            unit.move(self.policy.rally_point)
        elif (unit.energy >= 25 and len(unit.orders) == 0
              and self.creep_coverage < self.policy.target_perc_coverage):
            await self.spread_creep(unit, grid)
        elif (self.map_data and grid is not None
              and not self.is_position_safe(grid, unit.position)):
            await self.move_towards_safe_spot(unit, grid)
        elif unit.distance_to(self.policy.rally_point) > 7:
            if len(unit.orders) > 0:
                if unit.orders[0].ability.button_name != "CreepTumor":
                    unit.move(self.policy.rally_point)
            elif len(unit.orders) == 0:
                unit.move(self.policy.rally_point)
        # check if tumor has been placed at a location yet
        self._clear_pending_positions()
コード例 #22
0
    def unit_solve_combat(self, unit: Unit, current_command: Action) -> Action:
        if self.engage_ratio < 0.25 and self.can_engage_ratio < 0.25:
            return current_command

        if self.move_type == MoveType.DefensiveRetreat:
            if self.ready_to_shoot(unit):
                closest = self.closest_units.get(unit.tag, None)
                if closest and closest.is_target:
                    unit_range = self.unit_values.real_range(
                        unit, closest, self.knowledge)
                    if unit_range > 0 and unit_range > unit.distance_to(
                            closest):
                        return Action(closest, True)
            return current_command

        elif self.move_type == MoveType.PanicRetreat:
            return current_command

        if self.ready_to_shoot(unit):
            if self.closest_group and self.closest_group.ground_units:
                current_command = Action(self.closest_group.center, True)
            else:
                current_command = Action(current_command.target, True)
        else:
            closest = self.closest_units[unit.tag]

            # d = unit.distance_to(closest)
            unit_range = self.unit_values.real_range(unit, closest,
                                                     self.knowledge) - 0.5

            if unit.is_flying:
                best_position = self.pather.find_low_inside_air(
                    unit.position, closest.position, unit_range)
            else:
                best_position = self.pather.find_low_inside_ground(
                    unit.position, closest.position, unit_range)

            return Action(best_position, False)

        if self.ready_to_shoot(unit) and current_command.is_attack:
            return self.focus_fire(unit, current_command, self.prio_dict)
        return current_command
コード例 #23
0
    async def handle_unit(
        self,
        air_threats_near_bases: Units,
        ground_threats_near_bases: Units,
        unit: Unit,
        priority_enemy_units: Units,
        th_tag: int = 0,
    ) -> None:

        if priority_enemy_units:
            await self.do_queen_micro(unit, priority_enemy_units)
        elif self.policy.attack_condition():
            await self.do_queen_offensive_micro(unit,
                                                self.policy.attack_target)
        elif self.policy.defend_against_ground and ground_threats_near_bases:
            await self.do_queen_micro(unit, ground_threats_near_bases)
        elif self.policy.defend_against_air and air_threats_near_bases:
            await self.do_queen_micro(unit, air_threats_near_bases)
        elif unit.distance_to(self.policy.rally_point) > 12:
            unit.move(self.policy.rally_point)
コード例 #24
0
    async def up_and_down(self, harass_prism: Unit):
        self.knowledge.roles.set_task(UnitTask.Reserved, harass_prism)

        if harass_prism.has_buff(BuffId.LOCKON):
            cyclones = self.knowledge.unit_cache.enemy_in_range(
                harass_prism.position3d, 20).of_type(UnitTypeId.CYCLONE)
            if cyclones:
                closest_cyclone = cyclones.closest_to(harass_prism)
                position = harass_prism.position.towards(closest_cyclone, -18)
                self.do(harass_prism.move(position))
                return True

        if harass_prism.health_percentage <= 0.2:
            self.do(
                harass_prism(AbilityId.UNLOADALLAT_WARPPRISM,
                             harass_prism.position))
            return True

        if harass_prism.distance_to(self.get_enemy_main_platform()) <= 12 and \
                (not self.is_revealed_by_enemy(harass_prism)) and \
                harass_prism.cargo_used > 0:
            self.do(
                harass_prism(AbilityId.UNLOADALLAT_WARPPRISM,
                             harass_prism.position))
            return True
        target = self.get_enemy_main_platform()

        dts = self.knowledge.unit_cache.by_tags(
            [self.ninja_dt_1_tag, self.ninja_dt_2_tag])
        if dts.exists and harass_prism.cargo_used < 4:
            target = dts.center
            for dt in dts:
                if self.is_revealed_by_enemy(dt):
                    self.do(harass_prism.move(dt.position))
                    return True
        self.prism_evasive_move_to(harass_prism, target)
        return True
コード例 #25
0
            def sort_method(unit: Unit):
                role = self.roles.unit_role(unit)
                # if self.knowledge.my_race == Race.Protoss and role == UnitTask.Building:
                #     return 0

                if unit.distance_to(self.knowledge.enemy_main_zone.behind_mineral_position_center) <= 50:
                    return 10

                if role == UnitTask.Idle:
                    return 1

                if role == UnitTask.Gathering:
                    if unit.is_gathering and isinstance(unit.order_target, int):
                        target = self.cache.by_tag(unit.order_target)
                        if target and target.is_mineral_field:
                            return 2
                        else:
                            return 4
                    if unit.is_carrying_vespene:
                        return 5
                    if unit.is_carrying_minerals:
                        return 3
                    return 3
                return 10
コード例 #26
0
ファイル: micro_phoenixes.py プロジェクト: etzhang416/sc2_bot
    def unit_solve_combat(self, unit: Unit, current_command: Action) -> Action:

        if self.move_type == MoveType.DefensiveRetreat or self.move_type == MoveType.PanicRetreat:
            if self.ready_to_shoot(unit):
                closest = self.closest_units.get(unit.tag, None)
                if closest:
                    real_range = self.unit_values.real_range(unit, closest)
                    if 0 < real_range < unit.distance_to(closest):
                        return Action(closest.position, True)

            return current_command

        # Phoenixes are generally faster than the rest of the army

        # if self.engage_ratio < 0.25 and self.can_engage_ratio < 0.25:
        #     if self.group.ground_units:
        #         # Regroup with the ground army
        #         return Action(self.group.center, False)

        has_energy = unit.energy > GRAVITON_BEAM_ENERGY

        if has_energy and self.allow_lift:
            best_target: Optional[Unit] = None
            best_score: float = 0
            close_enemies = self.cache.enemy_in_range(unit.position, 14)

            for enemy in close_enemies:  # type: Unit
                if enemy.is_flying or enemy.is_structure or enemy.has_buff(
                        BuffId.GRAVITONBEAM):
                    continue

                if self.move_type != MoveType.Harass and enemy.type_id in self.unit_values.worker_types:
                    # If we are not doing any harass, don't lift low priority workers up.
                    # We need to prioritize energy to actual combat units
                    continue

                pos: Point2 = enemy.position
                score = self.lift_priority.get(
                    enemy.type_id, -1) + (1 - pos.distance_to(unit) / 10)
                if score > best_score:
                    best_target = enemy
                    best_score = score

            if best_target:
                if best_score > 5 or not close_enemies.flying.exists:
                    self.print(
                        f"Phoenix at {unit.position} lifting {best_target.type_id} at {best_target.position}"
                    )

                    if unit.distance_to(best_target) > 8:
                        destination = self.knowledge.pathing_manager.find_influence_air_path(
                            unit.position, best_target.position)
                        return Action(destination, False)
                    return Action(best_target, False,
                                  AbilityId.GRAVITONBEAM_GRAVITONBEAM)

        if self.engage_ratio < 0.25 and self.can_engage_ratio < 0.25:
            # Not in combat
            return current_command

        targets = self.enemies_near_by.flying

        if targets:
            closest = targets.closest_to(unit)
            # d = unit.distance_to(closest)
            real_range = self.unit_values.real_range(unit, closest) - 1
            best_position = self.pather.find_low_inside_air(
                unit.position, closest.position, real_range)

            return Action(best_position, False)

        return current_command
コード例 #27
0
    def unit_solve_combat(self, unit: Unit, current_command: Action) -> Action:
        if self.engage_ratio < 0.25 and self.can_engage_ratio < 0.25:
            return current_command

        if self.move_type == MoveType.DefensiveRetreat:
            if self.ready_to_shoot(unit):
                closest = self.closest_units.get(unit.tag, None)
                if closest and self.is_target(closest):
                    range = self.unit_values.real_range(unit, closest)
                    if range > 0 and range > unit.distance_to(closest):
                        return Action(closest, True)
            return current_command

        elif self.move_type == MoveType.PanicRetreat:
            return current_command

        if self.is_locked_on(
                unit
        ) and self.enemies_near_by and not self.ready_to_shoot(unit):
            cyclones = self.enemies_near_by(UnitTypeId.CYCLONE)
            if cyclones:
                closest_cyclone = cyclones.closest_to(unit)
                backstep: Point2 = closest_cyclone.position.towards(
                    unit.position, 15)
                if unit.is_flying:
                    backstep = self.pather.find_weak_influence_air(backstep, 4)
                else:
                    backstep = self.pather.find_weak_influence_ground(
                        backstep, 4)
                return Action(backstep, False)

        if self.should_retreat(
                unit) and self.closest_group and not self.ready_to_shoot(unit):
            backstep: Point2 = unit.position.towards(self.closest_group.center,
                                                     -3)
            if unit.is_flying:
                backstep = self.pather.find_weak_influence_air(backstep, 4)
            else:
                backstep = self.pather.find_weak_influence_ground(backstep, 4)
            return Action(backstep, False)

        if self.model == CombatModel.StalkerToSiege:
            siege_units = self.enemies_near_by.of_type(siege)
            if siege_units:
                target = siege_units.closest_to(unit)
                if target.distance_to(unit) < 7:
                    return Action(target, True)

        if self.model == CombatModel.StalkerToRoach:
            if self.ready_to_shoot(unit):
                if self.closest_group:
                    current_command = Action(self.closest_group.center, True)
                else:
                    current_command = Action(current_command.target, True)
            else:
                closest = self.closest_units[unit.tag]

                # d = unit.distance_to(closest)
                range = self.unit_values.real_range(unit, closest) - 0.5

                if unit.is_flying:
                    best_position = self.pather.find_low_inside_air(
                        unit.position, closest.position, range)
                else:
                    best_position = self.pather.find_low_inside_ground(
                        unit.position, closest.position, range)

                return Action(best_position, False)

        elif self.model == CombatModel.RoachToStalker:
            if self.ready_to_shoot(unit):
                if self.closest_group:
                    current_command = Action(self.closest_group.center, True)
                else:
                    current_command = Action(current_command.target, True)
            else:
                # Instead of backstep, move forward
                current_command = self.focus_fire(unit, current_command,
                                                  self.prio_dict)
                if isinstance(current_command.target, Unit):
                    current_command.target = current_command.target.position
                    current_command.is_attack = False
                return current_command

        if self.ready_to_shoot(unit) and current_command.is_attack:
            return self.focus_fire(unit, current_command, self.prio_dict)
        return current_command
コード例 #28
0
    def unit_solve_combat(self, unit: Unit, current_command: Action) -> Action:
        if self.force_fielding(unit):
            # Don't do anything if force field is ordered
            return NoAction()

        if (
            not self.shield_up
            and self.should_shield_up
            and unit.energy >= SHIELD_ENERGY_COST
            and self.last_shield_up + 0.5 < self.ai.time
        ):
            self.shield_up = True
            self.last_shield_up = self.ai.time
            return Action(None, False, AbilityId.GUARDIANSHIELD_GUARDIANSHIELD)

        if unit.shield_percentage < 0.1:
            if self.range_power > 5 and unit.energy >= HALLUCINATION_ENERGY_COST:
                return Action(None, False, AbilityId.HALLUCINATION_ARCHON)
            if self.melee_power > 5 and unit.energy >= FORCE_FIELD_ENERGY_COST:
                melee = self.knowledge.unit_cache.enemy(self.unit_values.melee)
                if melee:
                    closest = melee.closest_to(unit)
                    pos = unit.position.towards(closest, 0.6)
                    return Action(pos, False, AbilityId.FORCEFIELD_FORCEFIELD)

        if self.move_type == MoveType.SearchAndDestroy and unit.energy >= FORCE_FIELD_ENERGY_COST:
            # Look for defensive force field on ramp or other choke
            natural: Zone = self.knowledge.expansion_zones[1]
            main: Zone = self.knowledge.expansion_zones[0]
            d_natural = unit.distance_to(natural.center_location)
            d_main = unit.distance_to(main.center_location)

            if d_natural < 15 and d_natural < d_main and self.closest_group_distance < 10:
                # Sentry is at the natural
                zealot_pos: Point2 = self.knowledge.building_solver.zealot_position
                if self.knowledge.enemy_race == Race.Zerg and natural.our_wall() and zealot_pos:
                    # Protect gate keeper
                    our_keepers = self.cache.own_in_range(zealot_pos, 2).not_structure
                    combined_health = 0
                    for keeper in our_keepers:  # type: Unit
                        combined_health += keeper.health + keeper.shield

                    if combined_health < 70:
                        action = self.should_force_field(zealot_pos.towards(self.closest_group.center, 0.6))
                        if action:
                            return action

                if self.model == CombatModel.StalkerToSpeedlings:
                    # Protect buildings
                    buildings = self.cache.own_in_range(unit.position, 8).structure
                    for building in buildings:  # type: Unit
                        if building.health + building.shield < 300:
                            action = self.should_force_field(building.position.towards(self.closest_group.center, 1.2))
                            if action:
                                return action

            elif not natural.is_ours or natural.power_balance < 0 and d_main < main.radius:
                # Protect main base ramp
                not_flying = self.cache.enemy_in_range(self.main_ramp_position, 3).filter(
                    lambda u: not u.is_flying and not u.is_structure
                )
                if not_flying:
                    action = self.should_force_field(self.main_ramp_position)
                    if action:
                        return action

            #  and self.model == CombatModel.StalkerToSpeedlings
        return super().unit_solve_combat(unit, current_command)
コード例 #29
0
    async def _manage_nydus_attack(
        self,
        canal: Unit,
        network: Unit,
        unit: Unit,
        unit_distance_to_target: float,
        grid: Optional[np.ndarray] = None,
    ) -> None:
        """
        Get a Queen through the nydus and out the other side!
        @param canal: The canal is the worm placed on the map
        @param network: This is built at home
        @param unit: In this case, the queen we want to move through
        @param unit_distance_to_target:
        @return:
        """
        # user does not have some predefined nydus logic, so we unload the proxy canal for them
        if len(canal.passengers_tags) > 0 and not self.policy.nydus_move_function:
            canal(AbilityId.UNLOADALL_NYDUSWORM)

        # worm has popped somewhere, but we are waiting for it to finish, move next to network ready to go
        # usually we want queens last in anyway, so this gives a chance for other units to enter the nydus
        if not canal.is_ready and unit.distance_to(canal) > 30:
            unit.move(network.position)
        # both canal and network must be ready
        else:
            # unit needs to go through the nydus
            if unit_distance_to_target > 45 and unit.distance_to(network) < 70:
                # user has some custom code for moving units through nydus
                if self.policy.nydus_move_function:
                    self.policy.nydus_move_function(unit, self.policy.nydus_target)
                # manage this ourselves
                else:
                    network(AbilityId.LOAD_NYDUSNETWORK, unit)
            # else queen should micro on the other side
            # remember that all queens already have transfuse code baked in
            else:
                # queen has enough energy for a transfuse and a tumor, so put a tumor down where she currently is
                if unit.energy >= 75 and self.bot.has_creep(unit.position):
                    # check if there are too many tumors already
                    tumors: Units = self.bot.structures.filter(
                        lambda s: s.type_id
                        in {UnitID.CREEPTUMORBURROWED, UnitID.CREEPTUMORQUEEN}
                        and s.distance_to(unit) < 15
                    )
                    if tumors.amount < 7:
                        unit(AbilityId.BUILD_CREEPTUMOR_QUEEN, unit.position)
                if unit.is_using_ability(AbilityId.BUILD_CREEPTUMOR_QUEEN):
                    return
                # get priority target, ie: target the flying enemies first
                target: Optional[Unit] = self._get_target_from_close_enemies(unit)
                if target:
                    if self.attack_ready(unit, target):
                        unit.attack(target)
                    elif self.map_data and grid is not None:
                        await self.move_towards_safe_spot(unit, grid)
                    else:
                        distance: float = (
                            unit.ground_range + unit.radius + target.radius
                        )
                        move_to: Point2 = target.position.towards(unit, distance)
                        if self.bot.in_pathing_grid(move_to):
                            unit.move(move_to)
                # check if there is anything around here to attack,
                # if not then we attack the general attack target the user has passed in
                # TODO: In the future, this is where we would want the queens to come home
                #   At the moment a nydus queen is on a one way trip
                elif (
                    self.enemy_ground_units_near_nydus_target.amount == 0
                    and self.enemy_flying_units_near_nydus_target.amount == 0
                ):
                    await self.do_queen_offensive_micro(unit, self.policy.attack_target)
                # there are targets, but nothing in range so move towards the nydus target
                else:
                    unit.move(self.policy.nydus_target)