Dentosal / python-sc2

A StarCraft II bot api client library for Python 3
MIT License
588 stars 182 forks source link

self.find_placement() not working for creep tumors #47

Open BurnySc2 opened 6 years ago

BurnySc2 commented 6 years ago

I've been trying to make my bot spread creep across the map, however I've run into an issue with the

loc = await self.find_placement(CREEPTUMORBURROWED, near, placement_step=1, max_distance=5)

function. It only returns None, and never a location. Creep tumors are the only 1x1 size buildings, the next bigger sized unit (that requires creep also) is the spine / spore crawler with 2x2. So far I've been using

loc = await self.find_placement(SPINECRAWLER, near, placement_step=1, max_distance=5)

instead, but that does not work well for ramps, edges or maps with (walkable) water (map example: Odyssey has lots of water), where normal buildings cannot be placed but creep tumors can.

Another issue is trying to access the

locationAttempts = 30
ability = self._game_data.abilities[BUILD_CREEPTUMOR_QUEEN.value]
# or the following:
ability = self._game_data.units[CREEPTUMORQUEEN.value].creation_ability
# in a circular motion around the location, figure out which is a valid location:
positions = [Point2((location.x + spreadDistance * math.cos(math.pi * alpha * 2 / locationAttempts), location.y + spreadDistance * math.sin(math.pi * alpha * 2 / locationAttempts))) for alpha in range(locationAttempts)]
validPlacements = await self._client.query_building_placement(ability, positions)

self._client.query_building_placemen() function from the client.py file. The issue might be related as all the results report . This function is very useful when trying to check many locations in one await sweep.

BurnySc2 commented 6 years ago

I just did some other excessive testing with other ability enums and I actually found a working one!

ability = self._game_data.units[CREEPTUMORQUEEN.value].creation_ability
ability = self._game_data.units[CREEPTUMOR.value].creation_ability
ability = self._game_data.units[CREEPTUMORBURROWED.value].creation_ability
ability = self._game_data.abilities[BUILD_CREEPTUMOR_QUEEN.value]
ability = self._game_data.abilities[BUILD_CREEPTUMOR_TUMOR.value]
ability = self._game_data.abilities[BUILD_CREEPTUMOR.value]

All of the above don't work but what does work is

ability = self._game_data.abilities[ZERGBUILD_CREEPTUMOR.value]

Now valid placements can be checked by

# positions = list of various Point2 or Point3 objects
# check if any of the positions are valid
validPlacements = await self._client.query_building_placement(ability, positions)
# filter valid results
validPlacements = [p for index, p in enumerate(positions) if validPlacements[index] == ActionResult.Success]
# now "validPlacements" will contain a list of points where it is possible to place creep tumors
# of course creep tumors have a limited range to place creep tumors but queens can move anywhere
if validPlacements and self.units(QUEEN).idle.exists:
    queen = self.units(QUEEN).idle.random
    for location in validPlacements:
        err = await self.do(queen(BUILD_CREEPTUMOR_QUEEN, location))
        # or the tumor alternative:
        # err = await self.do(tumor(BUILD_CREEPTUMOR_TUMOR, location))
        if not err:
            break

Now it works on ramps and in other (usually unbuildable) places. screenshot2018-06-13 16_12_30

Dentosal commented 6 years ago

This must at least be documented better. Looking to add an example for this soon.