156 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			156 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 
								 | 
							
								"""
							 | 
						||
| 
								 | 
							
								This class is very experimental and probably not up to date and needs to be refurbished.
							 | 
						||
| 
								 | 
							
								If it works, you can watch replays with it.
							 | 
						||
| 
								 | 
							
								"""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# pylint: disable=W0201,W0212
							 | 
						||
| 
								 | 
							
								from __future__ import annotations
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								from typing import TYPE_CHECKING, List, Union
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								from .bot_ai_internal import BotAIInternal
							 | 
						||
| 
								 | 
							
								from .data import Alert, Result
							 | 
						||
| 
								 | 
							
								from .game_data import GameData
							 | 
						||
| 
								 | 
							
								from .position import Point2
							 | 
						||
| 
								 | 
							
								from .unit import Unit
							 | 
						||
| 
								 | 
							
								from .units import Units
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								if TYPE_CHECKING:
							 | 
						||
| 
								 | 
							
								    from .client import Client
							 | 
						||
| 
								 | 
							
								    from .game_info import GameInfo
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class ObserverAI(BotAIInternal):
							 | 
						||
| 
								 | 
							
								    """Base class for bots."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @property
							 | 
						||
| 
								 | 
							
								    def time(self) -> float:
							 | 
						||
| 
								 | 
							
								        """ Returns time in seconds, assumes the game is played on 'faster' """
							 | 
						||
| 
								 | 
							
								        return self.state.game_loop / 22.4  # / (1/1.4) * (1/16)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @property
							 | 
						||
| 
								 | 
							
								    def time_formatted(self) -> str:
							 | 
						||
| 
								 | 
							
								        """ Returns time as string in min:sec format """
							 | 
						||
| 
								 | 
							
								        t = self.time
							 | 
						||
| 
								 | 
							
								        return f"{int(t // 60):02}:{int(t % 60):02}"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @property
							 | 
						||
| 
								 | 
							
								    def game_info(self) -> GameInfo:
							 | 
						||
| 
								 | 
							
								        """ See game_info.py """
							 | 
						||
| 
								 | 
							
								        return self._game_info
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @property
							 | 
						||
| 
								 | 
							
								    def game_data(self) -> GameData:
							 | 
						||
| 
								 | 
							
								        """ See game_data.py """
							 | 
						||
| 
								 | 
							
								        return self._game_data
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @property
							 | 
						||
| 
								 | 
							
								    def client(self) -> Client:
							 | 
						||
| 
								 | 
							
								        """ See client.py """
							 | 
						||
| 
								 | 
							
								        return self._client
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def alert(self, alert_code: Alert) -> bool:
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        Check if alert is triggered in the current step.
							 | 
						||
| 
								 | 
							
								        Possible alerts are listed here https://github.com/Blizzard/s2client-proto/blob/e38efed74c03bec90f74b330ea1adda9215e655f/s2clientprotocol/sc2api.proto#L679-L702
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        Example use:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            from sc2.data import Alert
							 | 
						||
| 
								 | 
							
								            if self.alert(Alert.AddOnComplete):
							 | 
						||
| 
								 | 
							
								                print("Addon Complete")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        Alert codes::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            AlertError
							 | 
						||
| 
								 | 
							
								            AddOnComplete
							 | 
						||
| 
								 | 
							
								            BuildingComplete
							 | 
						||
| 
								 | 
							
								            BuildingUnderAttack
							 | 
						||
| 
								 | 
							
								            LarvaHatched
							 | 
						||
| 
								 | 
							
								            MergeComplete
							 | 
						||
| 
								 | 
							
								            MineralsExhausted
							 | 
						||
| 
								 | 
							
								            MorphComplete
							 | 
						||
| 
								 | 
							
								            MothershipComplete
							 | 
						||
| 
								 | 
							
								            MULEExpired
							 | 
						||
| 
								 | 
							
								            NuclearLaunchDetected
							 | 
						||
| 
								 | 
							
								            NukeComplete
							 | 
						||
| 
								 | 
							
								            NydusWormDetected
							 | 
						||
| 
								 | 
							
								            ResearchComplete
							 | 
						||
| 
								 | 
							
								            TrainError
							 | 
						||
| 
								 | 
							
								            TrainUnitComplete
							 | 
						||
| 
								 | 
							
								            TrainWorkerComplete
							 | 
						||
| 
								 | 
							
								            TransformationComplete
							 | 
						||
| 
								 | 
							
								            UnitUnderAttack
							 | 
						||
| 
								 | 
							
								            UpgradeComplete
							 | 
						||
| 
								 | 
							
								            VespeneExhausted
							 | 
						||
| 
								 | 
							
								            WarpInComplete
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param alert_code:
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        assert isinstance(alert_code, Alert), f"alert_code {alert_code} is no Alert"
							 | 
						||
| 
								 | 
							
								        return alert_code.value in self.state.alerts
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @property
							 | 
						||
| 
								 | 
							
								    def start_location(self) -> Point2:
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        Returns the spawn location of the bot, using the position of the first created townhall.
							 | 
						||
| 
								 | 
							
								        This will be None if the bot is run on an arcade or custom map that does not feature townhalls at game start.
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        return self.game_info.player_start_location
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @property
							 | 
						||
| 
								 | 
							
								    def enemy_start_locations(self) -> List[Point2]:
							 | 
						||
| 
								 | 
							
								        """Possible start locations for enemies."""
							 | 
						||
| 
								 | 
							
								        return self.game_info.start_locations
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    async def on_unit_destroyed(self, unit_tag: int):
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        Override this in your bot class.
							 | 
						||
| 
								 | 
							
								        This will event will be called when a unit (or structure, friendly or enemy) dies.
							 | 
						||
| 
								 | 
							
								        For enemy units, this only works if the enemy unit was in vision on death.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param unit_tag:
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    async def on_unit_created(self, unit: Unit):
							 | 
						||
| 
								 | 
							
								        """Override this in your bot class. This function is called when a unit is created.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param unit:"""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    async def on_building_construction_started(self, unit: Unit):
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        Override this in your bot class.
							 | 
						||
| 
								 | 
							
								        This function is called when a building construction has started.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param unit:
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    async def on_building_construction_complete(self, unit: Unit):
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        Override this in your bot class. This function is called when a building
							 | 
						||
| 
								 | 
							
								        construction is completed.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param unit:
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    async def on_start(self):
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        Override this in your bot class. This function is called after "on_start".
							 | 
						||
| 
								 | 
							
								        At this point, game_data, game_info and the first iteration of game_state (self.state) are available.
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    async def on_step(self, iteration: int):
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        You need to implement this function!
							 | 
						||
| 
								 | 
							
								        Override this in your bot class.
							 | 
						||
| 
								 | 
							
								        This function is called on every game step (looped in realtime mode).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param iteration:
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        raise NotImplementedError
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    async def on_end(self, game_result: Result):
							 | 
						||
| 
								 | 
							
								        """Override this in your bot class. This function is called at the end of a game.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :param game_result:"""
							 |