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:"""
 | 
