Exemple #1
0
class ScoutBaseAction(ActBase):
    _units: Units

    def __init__(self, only_once: bool) -> None:
        super().__init__()
        self.current_target = Point2((0, 0))
        self.ended = False
        self.only_once = only_once

    async def start(self, knowledge: "Knowledge"):
        await super().start(knowledge)
        self._units = Units([], self.ai)

    def set_scouts(self, scouts: List[Unit]):
        self._units.clear()
        self._units.extend(scouts)
Exemple #2
0
class Scout(SubActs):
    units: Units

    def __init__(self, unit_types: Union[UnitTypeId, Set[UnitTypeId]], unit_count: int, *args: ScoutBaseAction):
        """
        Scout act for all races, loops the given scout actions
        @param unit_types: Types of units accepted as scouts
        @param unit_count: Units required to be used in scouting, scouting will only start after all are available
        @param args: Scout actions, cen be to scout a certain location, or to move around in certain way. Defaults to scouting enemy main
        """
        if isinstance(unit_types, UnitTypeId):
            self.unit_types = set()
            self.unit_types.add(unit_types)
        else:
            self.unit_types = unit_types
        self.unit_count = unit_count

        if len(args) > 0:
            super().__init__(*args)
        else:
            super().__init__(ScoutLocation.scout_main())

        self.scout_tags: List[int] = []
        self.started = False
        self.ended = False
        self.index = 0

    async def start(self, knowledge: "Knowledge"):
        await super().start(knowledge)
        self.units = Units([], self.ai)

    async def execute(self) -> bool:
        if self.ended:
            return True

        self.units.clear()

        if self.find_units():
            return True

        if self.units:
            self.roles.set_tasks(UnitTask.Scouting, self.units)
            await self.micro_units()  # Ignore if the scouting has finished
        return True

    async def micro_units(self) -> bool:
        """
        Micros units
        @return: True when finished
        """
        count = len(self.orders)
        self.index = self.index % count

        for looped in range(0, count + 1):
            if looped == count:
                self.ended = True
                return True
            # noinspection PyTypeChecker
            action: ScoutBaseAction = self.orders[self.index]
            action.set_scouts(self.units)
            result = await action.execute()
            if not result:
                # Not finished
                return False

            self.index = (self.index + 1) % count
        return False

    def find_units(self) -> bool:
        if not self.started:
            if UnitTypeId.OVERLORD in self.unit_types:
                free_units = self.roles.get_types_from(
                    self.unit_types, UnitTask.Idle, UnitTask.Moving, UnitTask.Gathering, UnitTask.Reserved
                )
            else:
                free_units = self.roles.get_types_from(
                    self.unit_types, UnitTask.Idle, UnitTask.Moving, UnitTask.Gathering
                )
            if len(free_units) >= self.unit_count:
                # TODO: Better selection?
                new_scouts = free_units.random_group_of(self.unit_count)
                self.units.extend(new_scouts)
                self.scout_tags = new_scouts.tags

                self.started = True
        else:
            scouts = self.roles.get_types_from(self.unit_types, UnitTask.Scouting)
            self.units.extend(scouts.tags_in(self.scout_tags))
            if not self.units:
                # Scouts are dead, end the scout act
                self.ended = True
                return True
class NydusMain(ActBase):
    """Set up Nydus in their main."""

    units: Units

    def __init__(self, unit_type: UnitTypeId, amount: int):
        super().__init__()
        self.micro = MicroRules()
        self.micro.load_default_methods()
        self.micro.unit_micros[UnitTypeId.ZERGLING] = SuicideLingMicro()
        self.started = False
        self.ended = False
        self.unit_type = unit_type
        self.amount = amount
        self.lair_tech = MorphLair()
        self.network = ActBuilding(UnitTypeId.NYDUSNETWORK, to_count=1)
        self.zerg_build = ZergUnit(unit_type)
        self.tags: List[int] = []

    async def start(self, knowledge: "Knowledge"):
        await super(NydusMain, self).start(knowledge)
        await self.lair_tech.start(knowledge)
        await self.network.start(knowledge)
        await self.zerg_build.start(knowledge)
        await self.micro.start(knowledge)
        self.units = Units([], self.ai)

    async def execute(self) -> bool:
        if self.cache.own(UnitTypeId.NYDUSCANAL).ready:
            for canal in self.cache.own(UnitTypeId.NYDUSCANAL).ready:
                self.do(canal(AbilityId.UNLOADALL_NYDUSWORM))

        if self.knowledge.lost_units_manager.own_lost_type(UnitTypeId.NYDUSCANAL):
            self.ended = True

        if self.ended:
            return True

        if self.cache.own(self.unit_type).amount < self.amount:
            self.zerg_build.to_count = self.amount
            await self.zerg_build.execute()

        self.units.clear()

        if not self.get_count(UnitTypeId.LAIR, include_pending=True, include_not_ready=True) + self.get_count(
            UnitTypeId.HIVE
        ):
            await self.lair_tech.execute()
            return True

        if not self.get_count(UnitTypeId.NYDUSNETWORK, include_pending=True, include_not_ready=True):
            await self.network.execute()
            return True

        # build the nydus worm
        if not self.get_count(UnitTypeId.NYDUSCANAL) and self.get_count(
            UnitTypeId.NYDUSNETWORK, include_not_ready=False, include_pending=False
        ):
            closest_overlord = self.cache.own(UnitTypeId.OVERLORD).closest_to(self.knowledge.enemy_start_location)
            nydus_network = self.cache.own(UnitTypeId.NYDUSNETWORK).first
            for i in range(11):
                pos = closest_overlord.position.towards(self.knowledge.enemy_start_location, i)
                if self.ai.get_terrain_z_height(pos) != self.ai.get_terrain_z_height(
                    self.knowledge.enemy_start_location
                ):
                    continue
                if self.ai.is_visible(pos) and await self.ai.can_place(UnitTypeId.NYDUSCANAL, pos):
                    self.do(nydus_network(AbilityId.BUILD_NYDUSWORM, pos))
            if i == 10 and not nydus_network.orders:
                self.do(closest_overlord.move(closest_overlord.position.towards(pos, 1)))

        # put units into the Nydus
        if self.get_count(UnitTypeId.NYDUSCANAL, include_pending=True, include_not_ready=True) and self.get_count(
            UnitTypeId.NYDUSNETWORK, include_pending=False, include_not_ready=False
        ):
            network = self.cache.own(UnitTypeId.NYDUSNETWORK).first
            if not self.started:
                free_units = self.roles.get_types_from(
                    {self.unit_type}, UnitTask.Idle, UnitTask.Moving, UnitTask.Gathering
                )
                if free_units.amount < self.amount:
                    return True
                self.units.extend(free_units.random_group_of(self.amount))
                self.tags = self.units.tags
                self.started = True
            else:
                unit_grouping = self.roles.get_types_from({self.unit_type}, UnitTask.Reserved)
                self.units.extend(unit_grouping.tags_in(self.tags))
                if not self.units:
                    self.ended = True
                    return True

        if self.units:
            network = None
            canal = None
            if self.get_count(UnitTypeId.NYDUSNETWORK):
                network = self.cache.own(UnitTypeId.NYDUSNETWORK).first
            if self.get_count(UnitTypeId.NYDUSCANAL):
                canal = self.cache.own(UnitTypeId.NYDUSCANAL).first
            if not canal or not network:
                return True
            self.roles.set_tasks(UnitTask.Reserved, self.units)
            for unit in self.units:
                if unit.distance_to(canal) <= unit.distance_to(network):
                    self.combat.add_unit(unit)
                else:
                    self.do(network(AbilityId.LOAD_NYDUSNETWORK, unit))
            self.combat.execute(
                self.knowledge.enemy_expansion_zones[0].center_location, MoveType.Assault, rules=self.micro
            )

        return True  # never block