Skip to content

Commit

Permalink
feat: support new micro maps
Browse files Browse the repository at this point in the history
  • Loading branch information
raspersc2 committed Nov 1, 2024
1 parent 22cf93e commit d0f9de1
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 13 deletions.
124 changes: 124 additions & 0 deletions bot/combat/generic_engagement.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
from dataclasses import dataclass
from typing import TYPE_CHECKING, Union

import numpy as np
from sc2.ids.ability_id import AbilityId
from sc2.ids.unit_typeid import UnitTypeId as UnitID
from sc2.position import Point2

from ares import ManagerMediator
from ares.behaviors.combat.individual import CombatIndividualBehavior
from ares.consts import ALL_STRUCTURES
from ares.behaviors.combat.individual import (
AMove,
StutterUnitBack,
StutterUnitForward,
UseAbility,
)
from cython_extensions import cy_closest_to
from sc2.unit import Unit
from sc2.units import Units

if TYPE_CHECKING:
from ares import AresBot


@dataclass
class GenericEngagement(CombatIndividualBehavior):
"""A very opinionated behavior to control any melee or ranged unit
in battle.
Attributes
----------
unit: Unit
The unit we want to control.
nearby_targets : Units
The nearby enemy we want to fight.
stutter_forward : bool
Should unit aggressively fight?
If set to `False` unit will kite back.
use_blink : bool
Use blink if available?
default = True
"""

unit: Unit
nearby_targets: Union[Units, list[Unit]]
stutter_forward: bool
use_blink: bool = True

def execute(
self, ai: "AresBot", config: dict, mediator: ManagerMediator, **kwargs
) -> bool:
"""Shoot at the target if possible, else kite back.
Parameters
----------
ai : AresBot
Bot object that will be running the game
config :
Dictionary with the data from the configuration file
mediator :
ManagerMediator used for getting information from other managers.
**kwargs :
None
Returns
-------
bool :
CombatBehavior carried out an action.
"""

unit = self.unit
nearby_targets = self.nearby_targets
if non_structures := [
u for u in nearby_targets if u.type_id not in ALL_STRUCTURES
]:
if tanks := [
u for u in non_structures if u.type_id == UnitID.SIEGETANKSIEGED
]:
enemy_target: Unit = cy_closest_to(unit.position, tanks)
else:
enemy_target: Unit = cy_closest_to(unit.position, non_structures)
else:
enemy_target: Unit = cy_closest_to(unit.position, nearby_targets)
if self.stutter_forward:
if (
self.use_blink
and AbilityId.EFFECT_BLINK_STALKER in unit.abilities
and ai.is_visible(enemy_target.position)
):
return UseAbility(
ability=AbilityId.EFFECT_BLINK_STALKER,
unit=unit,
target=enemy_target.position,
).execute(ai, config, mediator)
else:
return StutterUnitForward(unit, enemy_target).execute(
ai, config, mediator
)
else:
grid: np.ndarray = mediator.get_ground_grid
if unit.is_flying:
grid = mediator.get_air_grid
if self.unit.ground_range < 3.0:
return AMove(unit=unit, target=enemy_target).execute(
ai, config, mediator
)
else:
if (
unit.shield_percentage < 0.2
and AbilityId.EFFECT_BLINK_STALKER in unit.abilities
):
safe_spot: Point2 = mediator.find_closest_safe_spot(
from_pos=unit.position, grid=grid
)
return UseAbility(
ability=AbilityId.EFFECT_BLINK_STALKER,
unit=unit,
target=safe_spot,
).execute(ai, config, mediator)
else:
return StutterUnitBack(
unit=unit, target=enemy_target, grid=grid
).execute(ai, config, mediator)
2 changes: 1 addition & 1 deletion bot/combat/high_ground_combat.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
KeepUnitSafe,
)

from ares.cython_extensions.geometry import cy_towards
from cython_extensions import cy_towards
from bot.combat.base_combat import BaseCombat

if TYPE_CHECKING:
Expand Down
11 changes: 5 additions & 6 deletions bot/combat/protect_position.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
ShootTargetInRange,
KeepUnitSafe,
)
from ares.cython_extensions.combat_utils import cy_pick_enemy_target
from ares.cython_extensions.units_utils import cy_closest_to
from cython_extensions import cy_pick_enemy_target, cy_closest_to
from bot.combat.base_combat import BaseCombat
from bot.consts import BEST_RANGE

Expand Down Expand Up @@ -108,12 +107,12 @@ def _defensive_engagement(
defensive_engagement.add(AMove(unit, target))
return defensive_engagement

def _calculate_defensive_concave(self, units: Units, defend_position: Point2) -> None:
def _calculate_defensive_concave(
self, units: Units, defend_position: Point2
) -> None:
target_location: Point2 = self.ai.enemy_structures[0].position

setup_from: Point2 = defend_position.position.towards(
target_location, 5.5
)
setup_from: Point2 = defend_position.position.towards(target_location, 5.5)
num_points = len(units)
distance_spread: float = num_points * 0.35
mid_value_depth = distance_spread * 0.6
Expand Down
25 changes: 22 additions & 3 deletions bot/combat_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@

from ares import ManagerMediator
from ares.consts import UnitRole, UnitTreeQueryType
from ares.cython_extensions.geometry import cy_distance_to
from ares.cython_extensions.units_utils import cy_closest_to
from cython_extensions import cy_distance_to, cy_closest_to
from bot.combat.base_combat import BaseCombat
from bot.combat.generic_engagement import GenericEngagement
from bot.consts import BEST_RANGE
from bot.combat.harass_pylon import HarassPylon
from bot.combat.high_ground_combat import HighGroundCombat
Expand Down Expand Up @@ -66,7 +66,9 @@ def home(self) -> Point2:

@property
def close_ramp(self) -> bool:
return cy_distance_to(self.ramps_sorted_to_spawn[0].bottom_center, self.home) < 8.5
return (
cy_distance_to(self.ramps_sorted_to_spawn[0].bottom_center, self.home) < 8.5
)

@property
def defend_position(self) -> Point2:
Expand All @@ -88,6 +90,23 @@ def _enemy_in_range_of_pylon(self) -> Optional[Units]:
return everything_near_pylon[0]

def execute(self):
map_name: str = self.ai.game_info.map_name.upper()
if (
"BOT MICRO ARENA" not in map_name and "PLATEAU MICRO" not in map_name
) or not self.mediator.get_map_data_object.map_ramps:
for unit in self.ai.units:
all_close_enemy: Units = self.mediator.get_units_in_range(
start_points=[self.ai.units.center],
distances=100.2,
query_tree=UnitTreeQueryType.AllEnemy,
)[0]
if all_close_enemy:
self.ai.register_behavior(
GenericEngagement(unit, all_close_enemy, False)
)

return

if self.ai.structures and self.ai.units and not self._initial_setup:
self._assign_initial_units()
self._calculate_high_ground_spots()
Expand Down
2 changes: 1 addition & 1 deletion bot/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from ares import AresBot
from ares.consts import ALL_STRUCTURES
from ares.cython_extensions.units_utils import cy_closest_to
from cython_extensions.units_utils import cy_closest_to
from ares.dicts.unit_data import UNIT_DATA
from sc2.data import Race
from sc2.position import Point2
Expand Down
6 changes: 4 additions & 2 deletions run.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,9 @@ def main():
# Local game
# alternative example code if finding the map path is problematic
map_list: List[str] = [
"PlateauMicro_1"
# "PlateauMicro_1"
# "BotMicroArena_6",
"Tier1MicroAIArena_a4"
]

random_race = random.choice([Race.Zerg, Race.Terran, Race.Protoss])
Expand All @@ -79,7 +80,8 @@ def main():
maps.get(random.choice(map_list)),
[
bot1,
bot2,
# bot2,
Computer(random_race, Difficulty.VeryEasy, ai_build=AIBuild.Macro),
],
realtime=False,
)
Expand Down

0 comments on commit d0f9de1

Please sign in to comment.