-
Notifications
You must be signed in to change notification settings - Fork 182
Expand file tree
/
Copy paththreebase_voidray.py
More file actions
131 lines (112 loc) · 6.1 KB
/
threebase_voidray.py
File metadata and controls
131 lines (112 loc) · 6.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
from sc2 import maps
from sc2.bot_ai import BotAI
from sc2.data import Difficulty, Race
from sc2.ids.ability_id import AbilityId
from sc2.ids.buff_id import BuffId
from sc2.ids.unit_typeid import UnitTypeId
from sc2.main import run_game
from sc2.player import Bot, Computer
class ThreebaseVoidrayBot(BotAI):
async def on_step(self, iteration: int):
target_base_count = 3
target_stargate_count = 3
if iteration == 0:
await self.chat_send("(glhf)")
if not self.townhalls.ready:
# Attack with all workers if we don't have any nexuses left, attack-move on enemy spawn (doesn't work on 4 player map) so that probes auto attack on the way
for worker in self.workers:
worker.attack(self.enemy_start_locations[0])
return
nexus = self.townhalls.ready.random
# If this random nexus is not idle and has not chrono buff, chrono it with one of the nexuses we have
if not nexus.is_idle and not nexus.has_buff(BuffId.CHRONOBOOSTENERGYCOST):
nexuses = self.structures(UnitTypeId.NEXUS)
abilities = await self.get_available_abilities(nexuses)
for loop_nexus, abilities_nexus in zip(nexuses, abilities):
if AbilityId.EFFECT_CHRONOBOOSTENERGYCOST in abilities_nexus:
loop_nexus(AbilityId.EFFECT_CHRONOBOOSTENERGYCOST, nexus)
break
# If we have at least 5 void rays, attack closes enemy unit/building, or if none is visible: attack move towards enemy spawn
if self.units(UnitTypeId.VOIDRAY).amount > 5:
for vr in self.units(UnitTypeId.VOIDRAY):
# Activate charge ability if the void ray just attacked
if vr.weapon_cooldown > 0:
vr(AbilityId.EFFECT_VOIDRAYPRISMATICALIGNMENT)
# Choose target and attack, filter out invisible targets
targets = (self.enemy_units | self.enemy_structures).filter(lambda unit: unit.can_be_attacked)
if targets:
target = targets.closest_to(vr)
vr.attack(target)
else:
vr.attack(self.enemy_start_locations[0])
# Distribute workers in gas and across bases
await self.distribute_workers()
# If we are low on supply, build pylon
if (
self.supply_left < 2
and self.already_pending(UnitTypeId.PYLON) == 0
or self.supply_used > 15
and self.supply_left < 4
and self.already_pending(UnitTypeId.PYLON) < 2
):
# Always check if you can afford something before you build it
if self.can_afford(UnitTypeId.PYLON):
await self.build(UnitTypeId.PYLON, near=nexus)
# Train probe on nexuses that are undersaturated (avoiding distribute workers functions)
# if nexus.assigned_harvesters < nexus.ideal_harvesters and nexus.is_idle:
if self.supply_workers + self.already_pending(UnitTypeId.PROBE) < self.townhalls.amount * 22 and nexus.is_idle:
if self.can_afford(UnitTypeId.PROBE):
nexus.train(UnitTypeId.PROBE)
# If we have less than 3 nexuses and none pending yet, expand
if self.townhalls.ready.amount + self.already_pending(UnitTypeId.NEXUS) < 3:
if self.can_afford(UnitTypeId.NEXUS):
await self.expand_now()
# Once we have a pylon completed
if self.structures(UnitTypeId.PYLON).ready:
pylon = self.structures(UnitTypeId.PYLON).ready.random
if self.structures(UnitTypeId.GATEWAY).ready:
# If we have gateway completed, build cyber core
if not self.structures(UnitTypeId.CYBERNETICSCORE):
if (
self.can_afford(UnitTypeId.CYBERNETICSCORE)
and self.already_pending(UnitTypeId.CYBERNETICSCORE) == 0
):
await self.build(UnitTypeId.CYBERNETICSCORE, near=pylon)
else:
# If we have no gateway, build gateway
if self.can_afford(UnitTypeId.GATEWAY) and self.already_pending(UnitTypeId.GATEWAY) == 0:
await self.build(UnitTypeId.GATEWAY, near=pylon)
# Build gas near completed nexuses once we have a cybercore (does not need to be completed
if self.structures(UnitTypeId.CYBERNETICSCORE):
for nexus in self.townhalls.ready:
vgs = self.vespene_geyser.closer_than(15, nexus)
for vg in vgs:
if self.can_afford(UnitTypeId.ASSIMILATOR):
worker = self.select_build_worker(vg.position)
if worker is not None:
if not self.gas_buildings or not self.gas_buildings.closer_than(1, vg):
worker.build_gas(vg)
worker.stop(queue=True)
# If we have less than 3 but at least 3 nexuses, build stargate
if self.structures(UnitTypeId.PYLON).ready and self.structures(UnitTypeId.CYBERNETICSCORE).ready:
pylon = self.structures(UnitTypeId.PYLON).ready.random
if (
self.townhalls.ready.amount + self.already_pending(UnitTypeId.NEXUS) >= target_base_count
and self.structures(UnitTypeId.STARGATE).ready.amount + self.already_pending(UnitTypeId.STARGATE)
< target_stargate_count
):
if self.can_afford(UnitTypeId.STARGATE):
await self.build(UnitTypeId.STARGATE, near=pylon)
# Save up for expansions, loop over idle completed stargates and queue void ray if we can afford
if self.townhalls.amount >= 3:
for sg in self.structures(UnitTypeId.STARGATE).ready.idle:
if self.can_afford(UnitTypeId.VOIDRAY):
sg.train(UnitTypeId.VOIDRAY)
def main():
run_game(
maps.get("(2)CatalystLE"),
[Bot(Race.Protoss, ThreebaseVoidrayBot()), Computer(Race.Protoss, Difficulty.Easy)],
realtime=False,
)
if __name__ == "__main__":
main()