async def execute(self) -> bool: unit: Unit all_defenders = self.knowledge.roles.all_from_task(UnitTask.Defending) for i in range(0, len(self.knowledge.expansion_zones)): zone: 'Zone' = self.knowledge.expansion_zones[i] zone_tags = self.defender_tags[i] zone_defenders_all = all_defenders.tags_in(zone_tags) zone_worker_defenders = zone_defenders_all(self.worker_type) zone_defenders = zone_defenders_all.exclude_type(self.worker_type) enemies = zone.known_enemy_units # Let's loop zone starting from our main, which is the one we want to defend the most # Check that zone is either in our control or is our start location that has no Nexus if zone_defenders.exists or zone.is_ours or zone == self.knowledge.own_main_zone: if not self.defense_required(enemies): # Delay before removing defenses in case we just lost visibility of the enemies if zone.last_scouted_center == self.knowledge.ai.time \ or self.zone_seen_enemy[i] + PlanZoneDefense.ZONE_CLEAR_TIMEOUT < self.ai.time: self.knowledge.roles.clear_tasks(zone_defenders_all) zone_defenders.clear() zone_tags.clear() continue # Zone is well under control. else: self.zone_seen_enemy[i] = self.ai.time if enemies.exists: # enemy_center = zone.assaulting_enemies.center enemy_center = enemies.closest_to( zone.center_location).position elif zone.assaulting_enemies: enemy_center = zone.assaulting_enemies.closest_to( zone.center_location).position else: enemy_center = zone.gather_point defense_required = ExtendedPower(self.unit_values) defense_required.add_power(zone.assaulting_enemy_power) defense_required.multiply(1.5) defenders = ExtendedPower(self.unit_values) for unit in zone_defenders: self.combat.add_unit(unit) defenders.add_unit(unit) # Add units to defenders that are being warped in. for unit in self.knowledge.roles.units( UnitTask.Idle).not_ready: if unit.distance_to(zone.center_location) < zone.radius: # unit is idle in the zone, add to defenders self.combat.add_unit(unit) self.knowledge.roles.set_task(UnitTask.Defending, unit) zone_tags.append(unit.tag) if not defenders.is_enough_for(defense_required): defense_required.substract_power(defenders) for unit in self.knowledge.roles.get_defenders( defense_required, zone.center_location): if unit.distance_to( zone.center_location) < zone.radius: # Only count units that are close as defenders defenders.add_unit(unit) self.knowledge.roles.set_task(UnitTask.Defending, unit) self.combat.add_unit(unit) zone_tags.append(unit.tag) if len(enemies) > 1 or (len(enemies) == 1 and enemies[0].type_id not in self.unit_values.worker_types): # Pull workers to defend only and only if the enemy isn't one worker scout if defenders.is_enough_for(defense_required): # Workers should return to mining. for unit in zone_worker_defenders: zone.go_mine(unit) if unit.tag in zone_tags: # Just in case, should be in zone tags always. zone_tags.remove(unit.tag) # Zone is well under control without worker defense. else: await self.worker_defence(defenders.power, defense_required, enemy_center, zone, zone_tags, zone_worker_defenders) self.combat.execute(enemy_center, MoveType.SearchAndDestroy) return True # never block
def execute(self, target: Point2, move_type=MoveType.Assault): our_units = self.get_all_units() if len(our_units) < 1: return self.own_groups: List[CombatUnits] = self.group_own_units( our_units, 12) total_power = ExtendedPower(self.unit_values) for group in self.own_groups: total_power.add_power(group.power) if self.debug: fn = lambda group: group.center.distance_to(self.ai.start_location) sorted_list = sorted(self.own_groups, key=fn) for i in range(0, len(sorted_list)): sorted_list[i].debug_index = i for group in self.own_groups: center = group.center closest_enemies = self.closest_group(center, self.enemy_groups) if closest_enemies is None: if move_type == MoveType.PanicRetreat: self.move_to(group, target, move_type) else: self.attack_to(group, target, move_type) else: power = group.power enemy_power = ExtendedPower(closest_enemies) enemy_center = closest_enemies.center is_in_combat = group.is_in_combat(closest_enemies) # pseudocode for attack if move_type == MoveType.DefensiveRetreat or move_type == MoveType.PanicRetreat: self.move_to(group, target, move_type) break if power.power > self.regroup_threshold * total_power.power: # Most of the army is here if (group.is_too_spread_out() and not is_in_combat): self.regroup(group, group.center) else: self.attack_to(group, target, move_type) elif is_in_combat: if not power.is_enough_for(enemy_power, 0.75): # Regroup if possible own_closest_group = self.closest_group( center, self.own_groups) if own_closest_group: self.move_to(group, own_closest_group.center, MoveType.ReGroup) else: # fight to bitter end self.attack_to(group, closest_enemies.center, move_type) else: self.attack_to(group, closest_enemies.center, move_type) else: if group.power.is_enough_for(self.all_enemy_power, 0.85): # We have enough units here to crush everything the enemy has self.attack_to(group, closest_enemies.center, move_type) else: # Regroup if possible if move_type == MoveType.Assault: # Group towards attack target own_closest_group = self.closest_group( target, self.own_groups) else: # Group up with closest group own_closest_group = self.closest_group( center, self.own_groups) if own_closest_group: self.move_to(group, own_closest_group.center, MoveType.ReGroup) else: # fight to bitter end self.attack_to(group, closest_enemies.center, move_type) # if move_type == MoveType.SearchAndDestroy: # enemy_closest_group = self.closest_group(center, self.enemy_groups) # if enemy_closest_group: # self.attack_to(actions, group, closest_enemies.center, move_type) # else: # self.attack_to(actions, group, target, move_type) # elif power.is_enough_for(enemy_power, 0.75): # if move_type == MoveType.PanicRetreat: # self.move_to(actions, group, target, move_type) # else: # self.attack_to(actions, group, closest_enemies.center, move_type) # # elif distance > 12: # own_closest_group = self.closest_group(center, self.own_groups) # # if own_closest_group: # self.move_to(actions, group, own_closest_group.center, MoveType.ReGroup) # # elif move_type == MoveType.PanicRetreat: # self.move_to(actions, group, target, move_type) # else: # self.attack_to(actions, group, enemy_center, move_type) # # elif enemy_power.is_enough_for(power, 0.75): # own_closest_group = self.closest_group(center, self.own_groups) # # if own_closest_group: # self.move_to(actions, group, own_closest_group.center, MoveType.ReGroup) # # elif move_type == MoveType.PanicRetreat: # self.move_to(actions, group, target, move_type) # else: # self.attack_to(actions, group, target, move_type) self.tags.clear()