Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • stebr364/pycommandcenter
  • starcraft-ai-course/pycommandcenter
  • eriah592/pycommandcenter
  • edvbe696/pycommandcenter
  • dawab699/pycommandcenter
  • hanja189/pycommandcenter
  • teoga849/pycommandcenter
  • musab250/pycommandcenter
  • emibr898/pycommandcenter
  • chrgu102/pycommandcenter
  • axega544/pycommandcenter
  • edvth289/pycommandcenter
  • jonbo278/py-command-center-v-2
13 results
Show changes
Showing
with 649 additions and 332 deletions
......@@ -19,20 +19,25 @@ Table of contents
-----------------
.. toctree::
:maxdepth: 3
:maxdepth: 2
gettingstarted
PyCommandCenter<_autosummary/commandcenter>
Coordinator<_autosummary/commandcenter.Coordinator>
helpers
idabot
unit
types
coordinates
constants
replays
idareplayobserver
replayunit
.. autosummary::
:toctree: _autosummary
:hidden:
library
library.Coordinator
commandcenter
commandcenter.Coordinator
.. _replays:
Replays
=======
This page will describe two different techniques for handling replays. The
first technique parses the information saved in the replay file. The second
uses the information in the replay file to actually replay the game. The
different techniques have certain advantages and disadvantages. The main
one is that the reader is a lot faster while replaying the game provides
a lot more information.
SC2Reader
---------
SC2Reader_ is a library that can be used to implement the first technique.
Here is a short example that uses SC2Reader to extract the build order.
.. _SC2Reader: https://github.com/ggtracker/sc2reader
.. code-block:: python
import sc2reader
import json
from sc2reader.factories import SC2Factory
# The path to the replays
PATH = "../Replays"
def main():
# Creates a generator of all the replays in the dictionary
replays = sc2reader.load_replays(PATH, load_level=3)
games = []
# Loops through every relay
for replay in replays:
building_order = []
if is_terran_vs_terran(replay):
# Loops through every event
for event in replay.events:
# Check if the event is that a building is crated
if type(event) == sc2reader.events.tracker.UnitInitEvent:
if event.unit.name not in building_order:
building_order.append(event.unit.name)
games.append(building_order)
return games
def is_terran_vs_terran(replay):
try:
return sc2reader.constants.LOCALIZED_RACES[replay.players[0].play_race] == "Terran" \
and sc2reader.constants.LOCALIZED_RACES[replay.players[1].play_race] == "Terran"
except(KeyError):
return False
if __name__ == '__main__':
games = main()
text = json.dumps(games)
print("Res: " + text)
SC2Reader has good documation_ that also describe what information
could be found. `What is in a Replay`_ and Events_ gives a good idea
if the information you want could be collected with SC2Reader.
.. _documation: https://sc2reader.readthedocs.io/en/latest/index.html
.. _What is in a Replay: https://sc2reader.readthedocs.io/en/latest/articles/whatsinareplay.html
.. _Events: https://sc2reader.readthedocs.io/en/latest/events/index.html
ReplayObserver
--------------
This is the second technique it is much like using a bot but with the difference
that no action can be preform just observations.
.. code-block:: python
from commandcenter import *
class MyObserver(ReplayObserver):
def __init__(self):
ReplayObserver.__init__(self)
def on_game_start(self):
ReplayObserver.on_game_start(self)
def on_step(self):
ReplayObserver.on_step(self)
def main():
coordinator = Coordinator(r"D:/StarCraft II/Versions/Base<version>/SC2_x64.exe")
if coordinator.load_replay_list("D:/Replays/"):
observer = MyObserver()
coordinator.add_replay_observer(observer)
while coordinator.update():
pass
else:
print("No replays found")
if __name__ == "__main__":
main()
.. toctree::
ReplayUnit
==========
.. autoclass:: commandcenter.ReplayUnit
Properties:
.. autoattribute:: buffs
.. autoattribute:: build_percentage
.. autoattribute:: energy
.. autoattribute:: facing
.. autoattribute:: hit_points
.. autoattribute:: max_hit_points
.. autoattribute:: id
.. autoattribute:: is_alive
.. autoattribute:: is_blip
.. autoattribute:: is_being_constructed
.. autoattribute:: is_burrowed
.. autoattribute:: is_cloaked
.. autoattribute:: is_completed
.. autoattribute:: is_flying
.. autoattribute:: is_idle
.. autoattribute:: is_powered
.. autoattribute:: is_training
.. autoattribute:: is_valid
.. autoattribute:: ReplayUnit.player
.. autoattribute:: position
.. autoattribute:: current_ability_id
.. autoattribute:: progress
.. autoattribute:: radius
.. autoattribute:: shields
.. autoattribute:: tile_position
.. autoattribute:: unit_type
.. autoattribute:: weapon_cooldown
.. autoattribute:: is_carrying_minerals
.. toctree::
\ No newline at end of file
Types
=====
For a full list of all unit types see the enum :class:`library.UNIT_TYPEID`.
For more information about a certain unit type, the wrapper class
:class:`library.UnitType` can be used.
For a full list of all unit types see the enum :class:`commandcenter.UNIT_TYPEID`.
For more information about a certain unit type, the wrapper class :class:`commandcenter.UnitType` can be used.
For a full list of all abilities and upgrades, see :class:`library.ABILITY_ID`
, :class:`library.UPGRADE_ID` and :class:`library.EFFECT_ID` respectively. Note that these does not have any
For a full list of all abilities and upgrades, see :class:`commandcenter.ABILITY_ID`, :class:`commandcenter.UPGRADE_ID` and :class:`commandcenter.EFFECT_ID` respectively. Note that these does not have any
wrapper classes for them.
If any of the ID's doesn't respond with the game. Before contacting the labassistent, check the game version
and the compatibility through Liquipedia. Some ID's might be left after a patch and is not available in
the game anymore.
If any of the ID's doesn't respond with the game. Before contacting the labassistent, check the game version and the compatibility through Liquipedia. Some ID's might be left after a patch and is not available in the game anymore.
UnitType
--------
As explained above, this class is a wrapper around the class
:class:`library.UNIT_TYPEID`.
.. autoclass:: library.UnitType
.. autoclass:: commandcenter.UnitType
:members:
:undoc-members:
:special-members: __init__
......@@ -27,29 +20,38 @@ As explained above, this class is a wrapper around the class
UNIT_TYPEID
-----------
.. autoclass:: library.UNIT_TYPEID
:members:
:undoc-members:
.. dropdown:: UNIT_TYPEID Enum (click to expand)
.. autoclass:: commandcenter.UNIT_TYPEID
:members:
:undoc-members:
ABILITY_ID
----------
.. autoclass:: library.ABILITY_ID
:members:
:undoc-members:
.. dropdown:: ABILITY_ID Enum (click to expand)
.. autoclass:: commandcenter.ABILITY_ID
:members:
:undoc-members:
UPGRADE_ID
----------
.. autoclass:: library.UPGRADE_ID
:members:
:undoc-members:
.. dropdown:: UPGRADE_ID Enum (click to expand)
.. autoclass:: commandcenter.UPGRADE_ID
:members:
:undoc-members:
EFFECT_ID
----------
EffectID is for things like ravager bile, or fungal or even a scan.
.. autoclass:: library.EFFECT_ID
:members:
:undoc-members:
.. dropdown:: EFFECT_ID Enum (click to expand)
.. autoclass:: commandcenter.EFFECT_ID
:members:
:undoc-members:
.. toctree::
Unit
====
.. class:: library.Unit
.. autoclass:: commandcenter.Unit
An instance of the class Unit represents one unit in the game. The units are
not limited to moveable units, but every entity which is not part of the
background is a unit. For example, the minerals and geysers are units as
well as all buildings.
For all possible types of units see the enum :class:`library.UNIT_TYPEID`.
Some types of objects are almost the same, for example there are many types
of mineral deposits, but all of them are mineable. This is one of the
motivations behind the :class:`library.UnitType` which aims to to make the
list of types more manageable. The UnitType can be accessed by the
:any:`Unit.unit_type` property.
It is possible to use Unit as keys in a dictionary, which might be helpful
for bookkeeping.
Properties:
.. autoattribute:: buffs
Returns a list of BuffID
.. autoattribute:: build_percentage
.. autoattribute:: energy
.. autoattribute:: facing
Returns the direction the unit is facing
.. autoattribute:: has_target
.. autoattribute:: hit_points
.. autoattribute:: max_hit_points
.. autoattribute:: max_shields
.. autoattribute:: max_energy
.. autoattribute:: id
.. autoattribute:: is_alive
.. autoattribute:: is_blip
Returns true if unit is a "blip" - a ping on the map
.. autoattribute:: is_being_constructed
Returns build_progress > 0
.. autoattribute:: is_burrowed
.. autoattribute:: is_cloaked
.. autoattribute:: is_completed
Returns build_progress >= 1
.. autoattribute:: is_flying
.. autoattribute:: is_idle
.. autoattribute:: is_powered
.. autoattribute:: is_training
.. autoattribute:: is_valid
.. attribute:: Unit.player
Returns the constant corresponding to player which this unit belongs to.
See :ref:`playerconstants` for more information
.. autoattribute:: player
.. autoattribute:: position
.. autoattribute:: current_ability_id
.. autoattribute:: progress
Returns the progress of currently used ability (-1 if not using ability)
.. autoattribute:: progression_list
.. autoattribute:: radius
Retruns the radius of the unit
.. autoattribute:: shields
.. autoattribute:: tile_position
.. autoattribute:: unit_type
.. autoattribute:: weapon_cooldown
.. autoattribute:: is_carrying_minerals
Returns if this unit is currently holding minerals
.. autoattribute:: is_carrying_gas
Returns if this unit is currently holding gas
.. attribute:: Unit.target
Returns target if unit has one, otherwise will fail the assertion (make sure not to call this unless certain that the unit has a target!)
.. autoattribute:: target
.. autoattribute:: gas_left_in_refinery
This is used on the geyser.
Returns the amount of gas left in refinery
.. autoattribute:: minerals_left_in_mineralfield
Returns the amount of minerals left in mineralfield
.. autoattribute:: owner
Returns the Player ID, the owner of the unit
Methods:
.. automethod:: ability
Call an ability directly, different abilities has different targets. Some target the unit itself (no argument), target a point (Point2D as argument) and some target a Unit (instance of Unit as argument)
.. method:: Unit.is_constructing(self, unit_type: library.UnitType)
Returns true if the unit is currently constructing another unit of type `unit_type`. Note that `unit_type` needs to be an instance of :class:`library.UnitType`
.. automethod:: is_constructing
.. automethod:: stop
.. automethod:: attack_unit
.. automethod:: attack_move
.. method:: Unit.move(self, point)
Move the unit to the given point, the point being an instance of either
:class:`library.Point2D` or :class:`library.Point2DI`.
.. automethod:: Unit.move(self, point)
.. automethod:: right_click
.. automethod:: repair
.. automethod:: build
......@@ -122,11 +59,9 @@ Unit
.. automethod:: train
.. automethod:: research
.. automethod:: morph
.. method:: Unit.has_target
Returns True if the target has a valid target and False otherwise
.. automethod:: hold_position
.. automethod:: patrol
.. automethod:: stop_dance
Stop and dance
.. toctree::
\ No newline at end of file
Subproject commit ed07e49236d937fd4ae98d0b0cb58a962cd269a6
Subproject commit 35ff42b56e9d34d9a944266eb25f2c899dbdfed7
# Installing PyCommandCenter in PyCharm
Start by downloading the library from the [PyCommandCenter repository](https://gitlab.liu.se/starcraft-ai-course/pycommandcenter/-/tags).
Place the library in your repository.
Add the library to the Python path in Python by:
1. File->Settings->Project: (project name)->Project Interpreter.
2. Select the cog in the upper right corner and select "Show All".
3. In the new window that opens, select the icon which shows a few folders connected with lines.
4. In the new window, first press the plus icon, and then select the path of your repository (the path to where you placed the library).
5. Restart PyCharm with "File->Invalidate Caches/Restart->Invalidate and Restart".
\ No newline at end of file
......@@ -17,7 +17,7 @@ link_directories(${PROJECT_BINARY_DIR}/cpp-sc2/bin)
add_definitions(-DSC2API)
# Create the executable.
pybind11_add_module(library library.cpp library.h ${BOT_SOURCES} ${LIBRARY_SOURCES})
target_link_libraries(library PRIVATE
pybind11_add_module(commandcenter library.cpp library.h ${BOT_SOURCES} ${LIBRARY_SOURCES})
target_link_libraries(commandcenter PRIVATE
sc2api sc2lib sc2utils sc2protocol libprotobuf
)
......@@ -5,22 +5,27 @@ namespace py = pybind11;
void define_base_location(py::module & m)
{
py::class_<BaseLocation>(m, "BaseLocation")
.def_property_readonly("geysers", &BaseLocation::getGeysers, "List of geysers at base location (List of units)")
.def_property_readonly("minerals", &BaseLocation::getMinerals, "List of mineral fields at base location (List of unit)")
.def_property_readonly("mineral_fields", &BaseLocation::getMinerals, "Alias for minerals in order to differentiate from harvested minerals")
.def_property_readonly("is_start_location", &BaseLocation::isStartLocation, "True if the base location is a start location, False otherwise")
.def_property_readonly("depot_position", &BaseLocation::getDepotPosition, "Point2DI position suitable for placing a town hall (base structure)")
.def_property_readonly("position", &BaseLocation::getPosition)
.def_property_readonly("geysers", &BaseLocation::getGeysers, "List of geysers at base location (List of units).")
.def_property_readonly("minerals", &BaseLocation::getMinerals, "List of mineral fields at base location (List of unit). Also returns the empty mineral fields.")
.def("is_start_location", &BaseLocation::isStartLocation, "True if the base location is a start location, False otherwise.")
.def_property_readonly("depot_position", &BaseLocation::getDepotPosition, "A suitable position for building a town hall (Command Center, Hatchery or Nexus), defined as a :class:`library.Point2DI`.")
.def_property_readonly("position", &BaseLocation::getPosition, "The position of the center of the BaseLocation, defined as a :class:`commandcenter.Point2D`.")
.def("get_ground_distance", py::overload_cast<const CCPosition &>(&BaseLocation::getGroundDistance, py::const_))
.def("get_ground_distance", py::overload_cast<const CCTilePosition &>(&BaseLocation::getGroundDistance, py::const_))
.def("is_occupied_by_player", &BaseLocation::isOccupiedByPlayer, "player constant"_a)
.def("is_player_start_location", &BaseLocation::isPlayerStartLocation, "player_constant"_a)
.def("contains_position", &BaseLocation::containsPosition);
.def("get_ground_distance", py::overload_cast<const CCTilePosition &>(&BaseLocation::getGroundDistance, py::const_), "Returns the ground distance between the provided position and the base location. Note that this uses a BFS approach and may overshoot a bit.")
.def("is_occupied_by_player", &BaseLocation::isOccupiedByPlayer, "player constant"_a, "If the baselocation is occupied by the provided player. See :ref:`playerconstants` for more information.")
.def("is_player_start_location", &BaseLocation::isPlayerStartLocation, "player_constant"_a, "If the baselocation is the start location of the provided player. See :ref:`playerconstants` for more information.")
.def("contains_position", &BaseLocation::containsPosition, "If the baselocation contains the provided :class:`commandcenter.Point2D` position.")
.doc() = R"(
Represents a base location on the map. A base location is a location on the map where a player can build a base. It contains information about the resources available at the location, the position of the location, and other information.
)";
py::class_<BaseLocationManager>(m, "BaseLocationManager")
.def_property_readonly("base_locations", &BaseLocationManager::getBaseLocations, py::return_value_policy::reference)
.def_property_readonly("starting_base_locations", &BaseLocationManager::getStartingBaseLocations, py::return_value_policy::reference)
.def("get_occupied_base_locations", &BaseLocationManager::getOccupiedBaseLocations, py::return_value_policy::reference, "player_constant"_a)
.def("get_player_starting_base_location", &BaseLocationManager::getPlayerStartingBaseLocation, py::return_value_policy::copy, "player_constant"_a)
.def("get_next_expansion", &BaseLocationManager::getNextExpansion, py::return_value_policy::copy, "player_constant"_a);
.def_property_readonly("base_locations", &BaseLocationManager::getBaseLocations, py::return_value_policy::reference, "A list of all :class:`commandcenter.BaseLocation` on the current map.")
.def_property_readonly("starting_base_locations", &BaseLocationManager::getStartingBaseLocations, py::return_value_policy::reference, "A list of all :class:`commandcenter.BaseLocation` on the current map which a player started at, indexed by Player constant(see :ref:`playerconstants`).")
.def("get_occupied_base_locations", &BaseLocationManager::getOccupiedBaseLocations, py::return_value_policy::reference, "player_constant"_a, "Returns a list of all :class:`commandcenter.BaseLocation` that are occupied by the provided :ref:`playerconstants`.")
.def("get_player_starting_base_location", &BaseLocationManager::getPlayerStartingBaseLocation, py::return_value_policy::copy, "player_constant"_a, "Returns the :class:`commandcenter.BaseLocation` that provided :ref:`playerconstants` started at.")
.def("get_next_expansion", &BaseLocationManager::getNextExpansion, py::return_value_policy::copy, "player_constant"_a, "Returns the :class:`commandcenter.BaseLocation` that is closest to the startlocation of provided :ref:`playerconstants` that is possible to expand to.")
.doc() = R"(
As the name implies this class helps you manage the base locations on the map.
)";
}
\ No newline at end of file
......@@ -5,9 +5,16 @@ namespace py = pybind11;
void define_building_placer(py::module & m)
{
py::class_<BuildingPlacer>(m, "BuildingPlacer")
.def("can_build_here", &BuildingPlacer::canBuildHere, "x"_a, "y"_a, "unit_type"_a)
.def("can_build_here_with_spaces", &BuildingPlacer::canBuildHereWithSpace, "Creates a square with the help of x, y, distance_to_building and the size of the unit_type. Good approach if we later gonna make a addon to the building.", "x"_a, "y"_a, "unit_type"_a, "distance_to_building"_a)
.def("get_build_location_near", &BuildingPlacer::getBuildLocationNear, "The search_count is how many building we should check (nearby buildings, instead of i < size, we can switch size to search_count). distance_to_building is the distance to the closest building.", "point2di"_a, "unit_type"_a, "distance_to_building"_a = 2, "search_count"_a = 1000)
.def("reserve_tiles", &BuildingPlacer::reserveTiles, "It's possible to reserve tiles, which makes it impossible to build at the position given by x and y.", "x"_a, "y"_a, "width"_a, "height"_a)
.def("free_tiles", &BuildingPlacer::freeTiles,"Free the tile (x, y) from reservation", "x"_a, "y"_a, "width"_a, "height"_a);
.def("can_build_here", &BuildingPlacer::canBuildHere, "x"_a, "y"_a, "unit_type"_a, "Returns if the provided unit_type it possible to be built at the location. Note: This function uses the width and height of the unit_type and this is not correct for add-ons. So to check addons please use can_build_here_with_size with a hardcoded size instead.")
.def("can_build_here_with_size", &BuildingPlacer::canBuildHereWithSize, "x"_a, "y"_a, "width"_a, "height"_a, "Checks if it is possible to build something with the provided width and height at the provided coordinates. Note: False if the it overlaps with a base location.")
.def("can_build_here_with_spaces", &BuildingPlacer::canBuildHereWithSpace, "Creates a square with the help of x, y, distance_to_building and the size of the unit_type. Good approach if we plan to later construct an add-on. Note: Does not reserve those extra tiles given by distance_to_building for the future. Note: This function uses the width and height of the unit_type and this is not correct for add-ons. So to check add-ons use can_build_here_with_size with a hardcoded size instead.", "x"_a, "y"_a, "unit_type"_a, "distance_to_building"_a)
.def("get_build_location_near", &BuildingPlacer::getBuildLocationNear, "The search_count represents how many building we should check (nearby buildings, instead of i < size, we can switch size to search_count). distance_to_building is the distance to the closest building.", "point2di"_a, "unit_type"_a, "distance_to_building"_a = 2, "search_count"_a = 1000)
.def("reserve_tiles", &BuildingPlacer::reserveTiles, "Reserves tiles, which makes it impossible to build at the position given by x and y.", "x"_a, "y"_a, "width"_a, "height"_a)
.def("free_tiles", &BuildingPlacer::freeTiles,"Free the tile (x, y) from reservation.", "x"_a, "y"_a, "width"_a, "height"_a)
.doc() = R"(
This class is useful for placing all buildings, except refineries and town halls (Command Centers, Hacheries and Nexus).
If you want to place a town hall, take a look at attribute `depot_location` of :class:`commandcenter.BaseLocation`.
If you want to place a refinery, take a look at attribute `geysers` of :class:`commandcenter.BaseLocation` and the method build_target of :class:`commandcenter.Unit`.
)";
}
\ No newline at end of file
......@@ -20,4 +20,7 @@ void define_color(py::module & m)
color.attr("PURPLE") = sc2::Colors::Purple;
color.attr("BLACK") = sc2::Colors::Black;
color.attr("GRAY") = sc2::Colors::Gray;
color.doc() = R"(
Represents a color in RGB format. The color is represented by three integers, each ranging from 0 to 255. The color can be created by providing the red, green and blue values. The class also contains some predefined colors.
)";
}
\ No newline at end of file
......@@ -10,39 +10,64 @@ void define_map_tools(py::module & m)
.def("get_distance", py::overload_cast<const CCPosition &>(&DistanceMap::getDistance, py::const_), "position"_a)
.def("get_sorted_tiles", &DistanceMap::getSortedTiles)
.def("get_start_tile", &DistanceMap::getStartTile)
.def("draw", &DistanceMap::draw, "bot"_a);
.def("draw", &DistanceMap::draw, "bot"_a)
.doc() = R"(
This class is used to calculate the distance between two points on the map.
The distance is calculated using a BFS algorithm. Keep in mind that it can overshoot the distance a bit.
)";
const CCColor white{ 255, 255, 255 };
py::class_<MapTools>(m, "MapTools")
.def_property_readonly("width", &MapTools::width, "The width of the map")
.def_property_readonly("height", &MapTools::height, "The height of the map")
.def_property_readonly("width", &MapTools::width, "The width of the map.")
.def_property_readonly("height", &MapTools::height, "The height of the map.")
.def_property_readonly("map_name", &MapTools::name, "The name of the map.")
//.def("terrainHeight", &MapTools::terrainHeight, py::const_)
.def("draw_line", py::overload_cast<const CCPosition &, const CCPosition &, const CCColor &>(&MapTools::drawLine, py::const_), py::arg("start"), py::arg("stop"), py::arg("color") = sc2::Colors::White)
.def("draw_box", py::overload_cast<const CCPosition &, const CCPosition &, const CCColor &>(&MapTools::drawBox, py::const_), py::arg("top_left"), py::arg("bottom_right"), py::arg("color") = sc2::Colors::White)
.def("draw_circle", py::overload_cast<const CCPosition &, CCPositionType, const CCColor &>(&MapTools::drawCircle, py::const_), py::arg("center"), py::arg("radius"), py::arg("color") = sc2::Colors::White)
.def("draw_resource_circle", &MapTools::drawResourceCircle, py::arg("center"), py::arg("radius"), py::arg("color") = sc2::Colors::White)
.def("terrainHeight", &MapTools::terrainHeightFromCoord, "x"_a, "y"_a)
.def("draw_line", py::overload_cast<const CCPosition &, const CCPosition &, const CCColor &>(&MapTools::drawLine, py::const_), py::arg("start"), py::arg("stop"), py::arg("color") = sc2::Colors::White, "Draws a line with the given color between to two points.")
.def("draw_tile", py::overload_cast<const CCTilePosition &, const CCColor &>(&MapTools::drawTile, py::const_), py::arg("tile"), py::arg("color") = sc2::Colors::White, "Draws an outline with the given color to the given tile.")
.def("draw_box", py::overload_cast<const CCPosition &, const CCPosition &, const CCColor &>(&MapTools::drawBox, py::const_), py::arg("top_left"), py::arg("bottom_right"), py::arg("color") = sc2::Colors::White, "Draws a box with the given color from the top left corner to the botom right.")
.def("draw_circle", py::overload_cast<const CCPosition &, CCPositionType, const CCColor &>(&MapTools::drawCircle, py::const_), py::arg("center"), py::arg("radius"), py::arg("color") = sc2::Colors::White, "Draws a circle with the given color with the provided point as center and the float as radius.")
.def("draw_resource_sphere", &MapTools::drawResourceSphere, py::arg("center"), py::arg("radius"), py::arg("color") = sc2::Colors::White, "Draws a 3D sphere with the given color with the provided point as center and the float as radius.")
.def("draw_text", &MapTools::drawText, "position"_a, "text"_a, "color"_a = sc2::Colors::White)
.def("draw_text_screen", &MapTools::drawTextScreen, "percentage_x"_a, "percentage_y"_a, "text"_a, "color"_a = sc2::Colors::White)
.def("is_valid_tile", py::overload_cast<int, int>(&MapTools::isValidTile, py::const_), "x"_a, "y"_a)
.def("is_valid_tile", py::overload_cast<const CCTilePosition &>(&MapTools::isValidTile, py::const_), "point_2di"_a)
.def("is_valid_position", py::overload_cast<const CCPosition &>(&MapTools::isValidPosition, py::const_), "point_2d"_a)
.def("is_valid_tile", py::overload_cast<int, int>(&MapTools::isValidTile, py::const_), "x"_a, "y"_a, "Checks whether the position is valid for the map.")
.def("is_valid_tile", py::overload_cast<const CCTilePosition &>(&MapTools::isValidTile, py::const_), "point_2di"_a, "Checks whether the tile is valid for the map.")
.def("is_valid_position", py::overload_cast<const CCPosition &>(&MapTools::isValidPosition, py::const_), "point_2d"_a, "Checks whether the position is valid for the map.")
.def("is_powered", &MapTools::isPowered, "x"_a, "y"_a)
.def("is_explored", py::overload_cast<int, int>(&MapTools::isExplored, py::const_), "x"_a, "y"_a)
.def("is_explored", py::overload_cast<const CCPosition &>(&MapTools::isExplored, py::const_), "point2d"_a)
.def("is_explored", py::overload_cast<const CCTilePosition &>(&MapTools::isExplored, py::const_), "point2di"_a)
.def("is_connected", py::overload_cast<int, int, int, int>(&MapTools::isConnected, py::const_), "x1"_a, "y1"_a, "x2"_a, "y2"_a)
.def("is_connected", py::overload_cast<const CCTilePosition &, const CCTilePosition &>(&MapTools::isConnected, py::const_), "from"_a, "too"_a)
.def("is_connected", py::overload_cast<const CCPosition &, const CCPosition &>(&MapTools::isConnected, py::const_), "from"_a, "too"_a)
.def("is_walkable", py::overload_cast<int, int>(&MapTools::isWalkable, py::const_), "x"_a, "y"_a)
.def("is_walkable", py::overload_cast<const CCTilePosition &>(&MapTools::isWalkable, py::const_), "point2di"_a)
.def("is_buildable", py::overload_cast<int, int>(&MapTools::isBuildable, py::const_), "x"_a, "y"_a)
.def("is_buildable", py::overload_cast<const CCTilePosition &>(&MapTools::isBuildable, py::const_), "point2di"_a)
.def("is_visible", &MapTools::isVisible, "x"_a, "y"_a)
.def("can_build_type_at_position", &MapTools::canBuildTypeAtPosition, "x"_a, "y"_a, "unit_type"_a)
.def("is_depot_buildable_tile", &MapTools::isDepotBuildableTile, "x"_a, "y"_a)
.def("get_ground_distance", &MapTools::getGroundDistance, "from"_a, "to"_a)
.def("is_explored", py::overload_cast<int, int>(&MapTools::isExplored, py::const_), "x"_a, "y"_a, "Returns whether the coordinates has been explored or not.")
.def("is_explored", py::overload_cast<const CCPosition &>(&MapTools::isExplored, py::const_), "point2d"_a, "Returns whether the coordinate has been explored or not.")
.def("is_explored", py::overload_cast<const CCTilePosition &>(&MapTools::isExplored, py::const_), "point2di"_a, "Returns whether the tile has been explored or not.")
.def("is_connected", py::overload_cast<int, int, int, int>(&MapTools::isConnected, py::const_), "x1"_a, "y1"_a, "x2"_a, "y2"_a, "Returns whether the coordinates are connected.")
.def("is_connected", py::overload_cast<const CCTilePosition &, const CCTilePosition &>(&MapTools::isConnected, py::const_), "from"_a, "to"_a, "Returns whether the tiles are connected.")
.def("is_connected", py::overload_cast<const CCPosition &, const CCPosition &>(&MapTools::isConnected, py::const_), "from"_a, "to"_a, "Returns whether the positions are of two connected tiles.")
.def("is_walkable", py::overload_cast<int, int>(&MapTools::isWalkable, py::const_), "x"_a, "y"_a, "Returns whether the coordinates is walkable.")
.def("is_walkable", py::overload_cast<const CCTilePosition &>(&MapTools::isWalkable, py::const_), "point2di"_a, "Returns whether the tile is walkable.")
.def("is_buildable", py::overload_cast<int, int>(&MapTools::isBuildable, py::const_), "x"_a, "y"_a, "Returns whether it is possible to build at the provided coordinate.")
.def("is_buildable", py::overload_cast<const CCTilePosition &>(&MapTools::isBuildable, py::const_), "point2di"_a, "Returns whether it is possible to build on tile.")
.def("is_visible", &MapTools::isVisible, "x"_a, "y"_a, "Returns whether the location identified by the coordinates is visible.")
.def("can_build_type_at_position", &MapTools::canBuildTypeAtPosition, "x"_a, "y"_a, "unit_type"_a, "Returns whether it is possible to build the provided unittype at the location.")
.def("is_depot_buildable_tile", &MapTools::isDepotBuildableTile, "x"_a, "y"_a, "Returns whether it is possbile to build a depot at the position.")
.def("get_ground_distance", &MapTools::getGroundDistance, "Returns the ground distance between the two points. Note that this uses a BFS approach and may overshoot a bit. The function will also do the calculations with integers resulting in that sometimes when close to a wall it might return -1 even though a path is available.", "from"_a, "to"_a)
.def("get_distance_map", py::overload_cast<const CCTilePosition &>(&MapTools::getDistanceMap, py::const_), "point2di"_a)
.def("get_distance_map", py::overload_cast<const CCPosition &>(&MapTools::getDistanceMap, py::const_), "point2d"_a)
.def("get_closest_tiles_to", &MapTools::getClosestTilesTo, "Returns a list of positions, where the first position is the closest and the last is the furthest", "point2di"_a)
.def("get_least_recently_seen_tile", &MapTools::getLeastRecentlySeenTile);
.def("get_closest_tiles_to", &MapTools::getClosestTilesTo, "Returns a list of positions, where the first position is the closest and the last is the farthest.", "point2di"_a)
.def("get_least_recently_seen_tile", &MapTools::getLeastRecentlySeenTile, "Returns the tile for which the most time has passed since it was last visible.")
.doc() = R"(
This class contains two types of methods:
* Methods for drawing information to the screen
* Methods for extracting information about the map
First, let us look at the method concerning drawing information to the
screen. Methods with the suffix ``_screen`` takes percentages of the
screens height and width, i.e. values between 0 and 1. Methods without
this suffix uses the same coordinate system as the game, i.e. world
coordinates.
The top three methods below takes in a Point2D, but it's possible to
send in x and y as floats instead of Point2D.
There is also methods which are useful for extracting information about the
game map.
)";
}
\ No newline at end of file
......@@ -9,6 +9,9 @@ void define_point(py::module & m)
py::class_<sc2::Point2D>(m, "Point2D", py::dynamic_attr())
.def(py::init<float, float>())
.def(py::init())
.def(py::init([](const sc2::Point2DI & p) {
return sc2::Point2D(p.x, p.y);
}))
.def_readwrite("x", &sc2::Point2D::x)
.def_readwrite("y", &sc2::Point2D::y)
.def(py::self += py::self)
......@@ -16,7 +19,7 @@ void define_point(py::module & m)
.def(py::self *= float())
.def(py::self /= float())
// These does not compile, but it is not a good idea to compare floats with floats anyway
//.def(py::self == py::self)
.def(py::self == py::self) // compiles now and this one is needed for __hash__. Outdated comment??
//.def(py::self != py::self)
.def(py::self + py::self)
.def(py::self - py::self)
......@@ -24,6 +27,14 @@ void define_point(py::module & m)
.def(float() * py::self)
.def(py::self / float())
.def(float() / py::self)
.def("__eq__",
[](const sc2::Point2D & p1, const sc2::Point2D & p2) {
return (p1.x == p2.x && p1.y == p2.y);
})
.def("__hash__",
[](const sc2::Point2D & p) {
return py::make_tuple(p.x, p.y).attr("__hash__")();
})
.def("__repr__",
[](const sc2::Point2D & p) {
return "<Point2D: (" + std::to_string(p.x) + ", " + std::to_string(p.y) + ")>";
......@@ -35,10 +46,18 @@ void define_point(py::module & m)
py::class_<sc2::Point2DI>(m, "Point2DI", py::dynamic_attr())
.def(py::init<int, int>())
.def(py::init())
.def(py::init([](const sc2::Point2D & p) {
return sc2::Point2DI(p);
}))
.def_readwrite("x", &sc2::Point2DI::x)
.def_readwrite("y", &sc2::Point2DI::y)
.def(py::self == py::self)
.def(py::self != py::self)
.def("__hash__",
[](const sc2::Point2DI & p) {
return py::make_tuple(p.x, p.y).attr("__hash__")();
})
.def("__repr__",
[](const sc2::Point2DI & p) {
return "<Point2DI: (" + std::to_string(p.x) + ", " + std::to_string(p.y) + ")>";
......
#include "library.h"
namespace py = pybind11;
void define_replay_unit(py::module & m)
{
py::class_<ReplayUnit>(m, "ReplayUnit")
.def_property_readonly("id", &ReplayUnit::getID, "The ID of the unit.")
.def_property_readonly("unit_type", &ReplayUnit::getType, "The :class:`commandcenter.UnitType` of the unit.")
.def_property_readonly("position", &ReplayUnit::getPosition, "The :class:`commandcenter.Point2D` of the unit.")
.def_property_readonly("tile_position", &ReplayUnit::getTilePosition, "The :class:`commandcenter.Point2DI` of the unit.")
.def_property_readonly("hit_points", &ReplayUnit::getHitPoints, "The hit points of the unit.")
.def_property_readonly("shields", &ReplayUnit::getShields, "The shields of the unit.")
.def_property_readonly("energy", &ReplayUnit::getEnergy, "The energy of the unit.")
.def_property_readonly("player", &ReplayUnit::getPlayer, "Returns the constant corresponding to player which this unit belongs to. See :ref:`playerconstants` for more information.")
.def_property_readonly("build_percentage", &ReplayUnit::getBuildPercentage, "The build percentage of the unit.")
.def_property_readonly("weapon_cooldown", &ReplayUnit::getWeaponCooldown, "The weapon cooldown of the unit.")
.def_property_readonly("is_completed", &ReplayUnit::isCompleted, "Whether the unit is completed, returns build_progress >= 1.")
.def_property_readonly("is_being_constructed", &ReplayUnit::isBeingConstructed, "Whether the unit is being constructed, returns build_progress > 0.")
.def_property_readonly("is_cloaked", &ReplayUnit::isCloaked, "Whether the unit is cloaked.")
.def_property_readonly("is_flying", &ReplayUnit::isFlying, "Whether the unit is flying.")
.def_property_readonly("buffs", &ReplayUnit::buffs, "Returns a list of BuffIDs representing the buffs on the unit.")
.def_property_readonly("is_alive", &ReplayUnit::isAlive, "Whether the unit is alive.")
.def_property_readonly("is_powered", &ReplayUnit::isPowered, "Whether the unit is powered.")
.def_property_readonly("is_idle", &ReplayUnit::isIdle, "Whether the unit is idle.")
.def_property_readonly("is_burrowed", &ReplayUnit::isBurrowed, "Whether the unit is burrowed.")
.def_property_readonly("is_valid", &ReplayUnit::isValid, "Whether the unit is valid.")
.def_property_readonly("is_training", &ReplayUnit::isTraining, "Whether the unit is training.")
.def_property_readonly("is_blip", &ReplayUnit::isBlip, "Whether the unit is a blip ie a ping on the map.")
.def_property_readonly("target", &ReplayUnit::getTarget, "The target of the unit.")
.def_property_readonly("has_target", &ReplayUnit::hasTarget, "Whether the unit has a target.")
.def_property_readonly("max_hit_points", &ReplayUnit::getMaxHitPoints, "The maximum hit points of the unit.")
.def_property_readonly("progress", &ReplayUnit::getProgress, "Returns the progress of currently used ability (-1 if not using ability).")
.def_property_readonly("current_ability_id", &ReplayUnit::getCurrentAbilityID, "The AbilityID of currently used ability.")
.def_property_readonly("facing", &ReplayUnit::getFacing, "Returns the direction the unit is facing.")
.def_property_readonly("radius", &ReplayUnit::getRadius, "The radius of the unit.")
.def_property_readonly("is_carrying_minerals", &ReplayUnit::isCarryingMinerals, "Whether the unit is carrying minerals.")
.def("__hash__", [](const ReplayUnit & unit) { return std::hash<const sc2::Unit *>{}(unit.getUnitPtr()); })
.def(py::self == py::self)
.def("__repr__", [](const ReplayUnit & unit) { return "<Unit of type: '" + unit.getType().getName() + "'>"; })
.doc() = R"(
The ReplayUnit class is used to represent a unit in a replay of a game.
A ReplayUnit is a :class:`commandcenter.Unit` with some limitations.
It provides various properties and methods to access information about the unit, such as its ID, type, position, hit points, energy, and more.
It is possible to use ReplayUnit as keys in a dictionary, which might be helpful for bookkeeping.
)";
}
......@@ -6,7 +6,7 @@ namespace py = pybind11;
void define_typeenums(py::module & m)
{
py::enum_<sc2::UNIT_TYPEID>(m, "UNIT_TYPEID")
py::enum_<sc2::UNIT_TYPEID>(m, "UNIT_TYPEID", "Acts as a full list of all unit types in the game. Depending on which game version you're using some of these might not be available.")
.value("ABANDONEDBUILDING", sc2::UNIT_TYPEID::ABANDONEDBUILDING)
.value("ABERRATIONACGLUESCREENDUMMY", sc2::UNIT_TYPEID::ABERRATIONACGLUESCREENDUMMY)
.value("ACCELERATIONZONEFLYINGLARGE", sc2::UNIT_TYPEID::ACCELERATIONZONEFLYINGLARGE)
......@@ -2000,7 +2000,7 @@ void define_typeenums(py::module & m)
.value("_8SLOTBAG", sc2::UNIT_TYPEID::_8SLOTBAG)
.def("__eq__", [](const sc2::UNIT_TYPEID &value, sc2::UnitTypeID &value2) { return value == value2; });
py::enum_<sc2::ABILITY_ID>(m, "ABILITY_ID")
py::enum_<sc2::ABILITY_ID>(m, "ABILITY_ID", "Acts as a full list of all abilities in the game. Dependeing on which game version you use, some of these might not work.")
.value("INVALID", sc2::ABILITY_ID::INVALID)
.value("ADVANCEDCONSTRUCTION_CANCEL", sc2::ABILITY_ID::ADVANCEDCONSTRUCTION_CANCEL)
.value("AGGRESSIVEMUTATION", sc2::ABILITY_ID::AGGRESSIVEMUTATION)
......@@ -2545,7 +2545,6 @@ void define_typeenums(py::module & m)
.value("LURKERASPECTMP_LURKERMP", sc2::ABILITY_ID::LURKERASPECTMP_LURKERMP)
.value("LURKERASPECT_CANCEL", sc2::ABILITY_ID::LURKERASPECT_CANCEL)
.value("LURKERASPECT_LURKER", sc2::ABILITY_ID::LURKERASPECT_LURKER)
.value("LIGHTBRIDGEONTOPRIGHT_LIGHTBRIDGEON", sc2::ABILITY_ID::LIGHTBRIDGEONTOPRIGHT_LIGHTBRIDGEON)
.value("MAKEVULTURESPIDERMINES_SPIDERMINEREPLENISH", sc2::ABILITY_ID::MAKEVULTURESPIDERMINES_SPIDERMINEREPLENISH)
.value("MASSIVEKNOCKOVER", sc2::ABILITY_ID::MASSIVEKNOCKOVER)
.value("MAXIUMTHRUST_MAXIMUMTHRUST", sc2::ABILITY_ID::MAXIUMTHRUST_MAXIMUMTHRUST)
......@@ -2931,8 +2930,7 @@ void define_typeenums(py::module & m)
.value("SENTRYGUNBURROW_BURROWTURRET", sc2::ABILITY_ID::SENTRYGUNBURROW_BURROWTURRET)
.value("SENTRYGUNUNBURROW_UNBURROWTURRET", sc2::ABILITY_ID::SENTRYGUNUNBURROW_UNBURROWTURRET)
.value("SHAKURASLIGHTBRIDGENE10OUT_BRIDGEEXTEND", sc2::ABILITY_ID::SHAKURASLIGHTBRIDGENE10OUT_BRIDGEEXTEND)
.value("SHAKURASLIGHTBRIDGENE10_BRIDGERETRACT", sc2::ABILITY_ID::PORTCITY_BRIDGE_UNITNW12OUT_BRIDGEEXTEND)
.value("PORTCITY_BRIDGE_UNITNW12_BRIDGERETRACT", sc2::ABILITY_ID::SHAKURASLIGHTBRIDGENE10_BRIDGERETRACT)
.value("SHAKURASLIGHTBRIDGENE10_BRIDGERETRACT", sc2::ABILITY_ID::SHAKURASLIGHTBRIDGENE10_BRIDGERETRACT)
.value("SHAKURASLIGHTBRIDGENE12OUT_BRIDGEEXTEND", sc2::ABILITY_ID::SHAKURASLIGHTBRIDGENE12OUT_BRIDGEEXTEND)
.value("SHAKURASLIGHTBRIDGENE12_BRIDGERETRACT", sc2::ABILITY_ID::SHAKURASLIGHTBRIDGENE12_BRIDGERETRACT)
.value("SHAKURASLIGHTBRIDGENE8OUT_BRIDGEEXTEND", sc2::ABILITY_ID::SHAKURASLIGHTBRIDGENE8OUT_BRIDGEEXTEND)
......@@ -3092,7 +3090,6 @@ void define_typeenums(py::module & m)
.value("TRAIN_PHOENIX", sc2::ABILITY_ID::TRAIN_PHOENIX)
.value("TRAIN_PROBE", sc2::ABILITY_ID::TRAIN_PROBE)
.value("TRAIN_QUEEN", sc2::ABILITY_ID::TRAIN_QUEEN)
.value("SPECTREHOLDFIRE", sc2::ABILITY_ID::SPECTREHOLDFIRE)
.value("TRAIN_RAVEN", sc2::ABILITY_ID::TRAIN_RAVEN)
.value("TRAIN_REAPER", sc2::ABILITY_ID::TRAIN_REAPER)
.value("TRAIN_ROACH", sc2::ABILITY_ID::TRAIN_ROACH)
......@@ -3208,7 +3205,7 @@ void define_typeenums(py::module & m)
.value("_330MMBARRAGECANNONS", sc2::ABILITY_ID::_330MMBARRAGECANNONS)
.value("_330MMBARRAGECANNONS_CANCEL", sc2::ABILITY_ID::_330MMBARRAGECANNONS_CANCEL);
py::enum_<sc2::UPGRADE_ID>(m, "UPGRADE_ID")
py::enum_<sc2::UPGRADE_ID>(m, "UPGRADE_ID", "Acts as a full list of upgrades available in the game. Depending on which game version you use, some of these upgrades may not be available.")
.value("ABDOMINALFORTITUDE", sc2::UPGRADE_ID::ABDOMINALFORTITUDE)
.value("ADEPTKILLBOUNCE", sc2::UPGRADE_ID::ADEPTKILLBOUNCE)
.value("ADEPTPIERCINGATTACK", sc2::UPGRADE_ID::ADEPTPIERCINGATTACK)
......@@ -3385,6 +3382,7 @@ void define_typeenums(py::module & m)
.value("PSIDISRUPTOR", sc2::UPGRADE_ID::PSIDISRUPTOR)
.value("PSIONICAMPLIFIERS", sc2::UPGRADE_ID::PSIONICAMPLIFIERS)
.value("PSISTORMTECH", sc2::UPGRADE_ID::PSISTORMTECH)
.value("CONCUSSIONSHELLS", sc2::UPGRADE_ID::PUNISHERGRENADES)
.value("PUNISHERGRENADES", sc2::UPGRADE_ID::PUNISHERGRENADES)
.value("RAPIDDEPLOYMENT", sc2::UPGRADE_ID::RAPIDDEPLOYMENT)
.value("RAVAGERRANGE", sc2::UPGRADE_ID::RAVAGERRANGE)
......@@ -3511,7 +3509,7 @@ void define_typeenums(py::module & m)
.value("ZERGMISSILEWEAPONSLEVEL3", sc2::UPGRADE_ID::ZERGMISSILEWEAPONSLEVEL3)
.value("_330MMBARRAGECANNONS", sc2::UPGRADE_ID::_330MMBARRAGECANNONS);
py::enum_<sc2::BUFF_ID>(m, "BUFF_ID")
py::enum_<sc2::BUFF_ID>(m, "BUFF_ID", "An enumeration of buffs that can affect units.")
.value("ACCELERATIONZONEFLYINGTEMPORALFIELD", sc2::BUFF_ID::ACCELERATIONZONEFLYINGTEMPORALFIELD)
.value("ACCELERATIONZONETEMPORALFIELD", sc2::BUFF_ID::ACCELERATIONZONETEMPORALFIELD)
.value("ADEPTDEATHCHECK", sc2::BUFF_ID::ADEPTDEATHCHECK)
......@@ -3807,7 +3805,7 @@ void define_typeenums(py::module & m)
.value("_250MMSTRIKECANNONS", sc2::BUFF_ID::_250MMSTRIKECANNONS)
.value("_330MMBARRAGECANNONS", sc2::BUFF_ID::_330MMBARRAGECANNONS);
py::enum_<sc2::EFFECT_ID>(m, "EFFECT_ID")
py::enum_<sc2::EFFECT_ID>(m, "EFFECT_ID", "An enumeration of all the effect ids in the game.")
.value("BLINDINGCLOUD", sc2::EFFECT_ID::BLINDINGCLOUD)
.value("CORROSIVEBILE", sc2::EFFECT_ID::CORROSIVEBILE)
.value("GUARDIANSHIELD", sc2::EFFECT_ID::GUARDIANSHIELD)
......
......@@ -6,25 +6,37 @@ void define_tech_tree(py::module & m)
{
py::class_<TypeData>(m, "TypeData")
.def_readonly("race", &TypeData::race)
.def_readonly("mineral_cost", &TypeData::mineralCost, "mineral cost of the item")
.def_readonly("gas_cost", &TypeData::gasCost, "gas cost of the item")
.def_readonly("supply_cost", &TypeData::supplyCost, "supply cost of the item")
.def_readonly("build_time", &TypeData::buildTime, "build time of the item in seconds (should be 32 game updates per tick, can someone verify this?)")
.def_readonly("is_unit", &TypeData::isUnit)
.def_readonly("is_building", &TypeData::isBuilding)
.def_readonly("is_worker", &TypeData::isWorker)
.def_readonly("is_refinery", &TypeData::isRefinery)
.def_readonly("is_supply_provider", &TypeData::isSupplyProvider)
.def_readonly("is_resource_depot", &TypeData::isResourceDepot)
.def_readonly("is_addon", &TypeData::isAddon)
.def_readonly("build_ability", &TypeData::buildAbility, "the ability that creates this item")
.def_readonly("warp_ability", &TypeData::warpAbility, "the ability that creates this item via warp-in")
.def_readonly("what_builds", &TypeData::whatBuilds, "any of these units can build the item")
.def_readonly("required_units", &TypeData::requiredUnits, "owning ONE of these is required to make -> List[UnitType]")
.def_readonly("required_upgrades", &TypeData::requiredUpgrades, "having ALL of these is required to make -> List[UPGRADE_ID]")
.def_readonly("required_addons", &TypeData::requiredAddons, "a unit of this type must be present next to the producer -> List[UnitType]");
.def_readonly("mineral_cost", &TypeData::mineralCost, "The mineral cost of the item.")
.def_readonly("gas_cost", &TypeData::gasCost, "The gas cost of the item.")
.def_readonly("supply_cost", &TypeData::supplyCost, "The supply cost of the item.")
.def_readonly("build_time", &TypeData::buildTime, "The build time of the item in seconds (should be 32 game updates per tick).")
.def_readonly("is_unit", &TypeData::isUnit, "Whether the item is a unit.")
.def_readonly("is_building", &TypeData::isBuilding, "Whether the item is a building.")
.def_readonly("is_worker", &TypeData::isWorker, "Whether the item is a worker.")
.def_readonly("is_refinery", &TypeData::isRefinery, "Whether the item is a refinery.")
.def_readonly("is_supply_provider", &TypeData::isSupplyProvider, "Whether the item is a supply provider.")
.def_readonly("is_resource_depot", &TypeData::isResourceDepot, "Whether the item is a resource depot.")
.def_readonly("is_addon", &TypeData::isAddon, "Whether the item is an add-on.")
.def_readonly("build_ability", &TypeData::buildAbility, "The ability that creates this item.")
.def_readonly("warp_ability", &TypeData::warpAbility, "The ability that creates this item via warp-in.")
.def_readonly("what_builds", &TypeData::whatBuilds, "The units that can build the item.")
.def_readonly("required_units", &TypeData::requiredUnits, "Owning ONE of these (List[UnitType]) is required to make the item.")
.def_readonly("required_upgrades", &TypeData::requiredUpgrades, "Having ALL of these (List[UPGRADE_ID]) is required to make the item.")
.def_readonly("required_addons", &TypeData::requiredAddons, "A unit of this type (List[UnitType]) must be present next to the producer.")
.doc() = R"(
Allows you to get information about a unit type or upgrade. This is a read-only class.
)";
py::class_<TechTree>(m, "TechTree")
.def("get_data", py::overload_cast<const UnitType &>(&TechTree::getData, py::const_))
.def("get_data", py::overload_cast<const CCUpgrade &>(&TechTree::getData, py::const_));
.def("get_data", py::overload_cast<const CCUpgrade &>(&TechTree::getData, py::const_), "Argument is either an instance of the class :class:`commandcenter.UnitType` or an instance of the class :class:`commandcenter.CCUpgrade`, depending on what information is wanted.")
.def("suppress_warnings", &TechTree::setSuppressWarnings, "Suppress type and upgrade warnings." ,"b"_a)
.doc() = R"(
This class contains all information about units and what is required to
build a certain unit and what builds it. It only has one method, which is
used to look-up unit types properties.
Instead of using TechTree, it's possible to use the functions in UnitType for
structure, etc. In IDABot there is functions for getting data about upgrades.
)";
}
......@@ -5,60 +5,80 @@ namespace py = pybind11;
void define_unit(py::module & m)
{
py::class_<Unit>(m, "Unit")
.def_property_readonly("unit_type", &Unit::getType, "The :class:`library.UnitType` of the unit")
.def_property_readonly("position", &Unit::getPosition, "The :class:`library.Point2D` of the unit")
.def_property_readonly("tile_position", &Unit::getTilePosition, "The :class:`library.Point2DI` of the unit")
.def_property_readonly("hit_points", &Unit::getHitPoints)
.def_property_readonly("shields", &Unit::getShields)
.def_property_readonly("energy", &Unit::getEnergy)
.def_property_readonly("player", &Unit::getPlayer)
.def_property_readonly("id", &Unit::getID)
.def_property_readonly("build_percentage", &Unit::getBuildPercentage)
.def_property_readonly("weapon_cooldown", &Unit::getWeaponCooldown)
.def_property_readonly("is_completed", &Unit::isCompleted)
.def_property_readonly("is_being_constructed", &Unit::isBeingConstructed)
.def_property_readonly("is_cloaked", &Unit::isCloaked)
.def_property_readonly("is_flying", &Unit::isFlying)
.def_property_readonly("buffs", &Unit::buffs)
.def_property_readonly("is_alive", &Unit::isAlive)
.def_property_readonly("is_powered", &Unit::isPowered)
.def_property_readonly("is_idle", &Unit::isIdle)
.def_property_readonly("is_burrowed", &Unit::isBurrowed)
.def_property_readonly("is_valid", &Unit::isValid)
.def_property_readonly("is_training", &Unit::isTraining)
.def_property_readonly("is_blip", &Unit::isBlip)
.def_property_readonly("target", &Unit::getTarget)
.def_property_readonly("has_target", &Unit::hasTarget)
.def_property_readonly("max_hit_points", &Unit::getMaxHitPoints)
.def_property_readonly("progress", &Unit::getProgress)
.def_property_readonly("current_ability_id", &Unit::getCurrentAbilityID, "The AbilityID of currently used ability")
.def_property_readonly("facing", &Unit::getFacing)
.def_property_readonly("radius", &Unit::getRadius)
.def_property_readonly("is_carrying_minerals", &Unit::isCarryingMinerals)
.def_property_readonly("is_carrying_gas", &Unit::isCarryingGas)
.def_property_readonly("gas_left_in_refinery", &Unit::gasLeftInGeyser)
.def_property_readonly("minerals_left_in_mineralfield", &Unit::mineralsLeftInMineralfield)
.def_property_readonly("owner", &Unit::getOwner)
.def("hold_position", &Unit::holdPosition)
.def("patrol", py::overload_cast<const CCPosition &>(&Unit::patrol, py::const_))
.def("stop_dance", &Unit::stopDance)
.def("stop", &Unit::stop)
.def("attack_unit", &Unit::attackUnit)
.def("attack_move", &Unit::attackMove)
.def_property_readonly("unit_type", &Unit::getType, "The :class:`commandcenter.UnitType` of the unit.")
.def_property_readonly("position", &Unit::getPosition, "The :class:`commandcenter.Point2D` of the unit.")
.def_property_readonly("tile_position", &Unit::getTilePosition, "The :class:`commandcenter.Point2DI` of the unit.")
.def_property_readonly("hit_points", &Unit::getHitPoints, "Health of the unit.")
.def_property_readonly("shields", &Unit::getShields, "Shield of the unit.")
.def_property_readonly("energy", &Unit::getEnergy, "Energy of the unit.")
.def_property_readonly("player", &Unit::getPlayer, "Returns the constant corresponding to player which this unit belongs to. See :ref:`playerconstants` for more information.")
.def_property_readonly("id", &Unit::getID, "Returns an int to identify the unit. This value does not stay the same for units you lose vision of, so maybe not best idea to use as a way of keeping track of them.")
.def_property_readonly("build_percentage", &Unit::getBuildPercentage, "Gives progress under construction. Range [0.0, 1.0]. 1.0 == finished.")
.def_property_readonly("weapon_cooldown", &Unit::getWeaponCooldown, "Time remaining for a weapon on cooldown.")
.def_property_readonly("is_completed", &Unit::isCompleted, "Returns build_progress >= 1.")
.def_property_readonly("is_being_constructed", &Unit::isBeingConstructed, "Returns (build_progress > 0 and not is_completed).")
.def_property_readonly("is_cloaked", &Unit::isCloaked, "If the unit is cloaked.")
.def_property_readonly("is_flying", &Unit::isFlying, "If the unit is flying.")
.def_property_readonly("buffs", &Unit::buffs, "Returns a list buffs on this unit. Only valid for this player's units.")
.def_property_readonly("is_alive", &Unit::isAlive, "Whether the unit is alive or not.")
.def_property_readonly("is_powered", &Unit::isPowered, "Whether the unit is powered by a pylon.")
.def_property_readonly("is_idle", &Unit::isIdle, "Whether the unit has any orders.")
.def_property_readonly("is_burrowed", &Unit::isBurrowed, "Whether the unit is burrowed.")
.def_property_readonly("is_valid", &Unit::isValid, "Whether the unit is valid")
.def_property_readonly("is_training", &Unit::isTraining, "Returns True if the unit is a building and is training another unit.")
.def_property_readonly("is_blip", &Unit::isBlip, "Returns true if unit is a 'blip' - a ping on the map.")
.def_property_readonly("target", &Unit::getTarget, "Returns target unit if one exists, otherwise return itself.")
.def_property_readonly("has_target", &Unit::hasTarget, "Returns True if the target has a valid target and False otherwise.")
.def_property_readonly("max_hit_points", &Unit::getMaxHitPoints, "Returns the max health.")
.def_property_readonly("progress", &Unit::getProgress, "Returns the progress of currently used ability (-1 if not using ability).")
.def_property_readonly("progression_list", &Unit::getAllProgress, "Returns a list containing the progression on all the processes in order. Empty list if no process exists.")
.def_property_readonly("current_ability_id", &Unit::getCurrentAbilityID, "The AbilityID of currently used ability.")
.def_property_readonly("facing", &Unit::getFacing, "Direction the unit faces in radians (1 radian == 57.296 degrees).")
.def_property_readonly("radius", &Unit::getRadius, "Returns the radius of the unit.")
.def_property_readonly("is_carrying_minerals", &Unit::isCarryingMinerals, "Returns if this unit is currently holding minerals.")
.def_property_readonly("is_carrying_gas", &Unit::isCarryingGas, "Returns if this unit is currently holding gas.")
.def_property_readonly("gas_left_in_refinery", &Unit::gasLeftInGeyser, "Amount of vespene left in the the refinery.")
.def_property_readonly("minerals_left_in_mineralfield", &Unit::mineralsLeftInMineralfield, "Amount of minerals if the unit is a mineral field.")
.def_property_readonly("owner", &Unit::getOwner, "Which player owns a unit. Not same as player; 'player' originates from IDA implementation whilst 'owner' originates from StarCraft II.")
.def_property_readonly("max_shields", &Unit::maxShields, "Max shield of the unit.")
.def_property_readonly("max_energy", &Unit::maxEnergy, "Max energy of the unit.")
.def("hold_position", &Unit::holdPosition, "Unit will hold its position.")
.def("patrol", py::overload_cast<const CCPosition &>(&Unit::patrol, py::const_), "Unit will patrol back and forth from its current location to the given Point2D.")
.def("stop_dance", &Unit::stopDance, "Unit will Stop and dance.")
.def("stop", &Unit::stop, "Unit will stop.")
.def("attack_unit", &Unit::attackUnit, "Unit will attack the provided unit.")
.def("attack_move", &Unit::attackMove, "Moves to provided Point2D location. If an enemy is seen on the way it will try to attack it. Will chase after the enemy as long as it is visible.")
.def("ability", py::overload_cast<sc2::AbilityID>(&Unit::ability, py::const_))
.def("ability", py::overload_cast<sc2::AbilityID, const CCPosition &>(&Unit::ability, py::const_))
.def("ability", py::overload_cast<sc2::AbilityID, const Unit &>(&Unit::ability, py::const_))
.def("ability", py::overload_cast<sc2::AbilityID, const Unit &>(&Unit::ability, py::const_), "Call an ability directly, different abilities has different targets. Some target the unit itself (no argument), target a point (Point2D as argument) and some target a Unit (instance of Unit as argument).")
.def("move", py::overload_cast<const CCPosition &>(&Unit::move, py::const_))
.def("move", py::overload_cast<const CCTilePosition &>(&Unit::move, py::const_))
.def("right_click", &Unit::rightClick, "Same as right-clicking in the game, for example making workers mine minerals")
.def("repair", &Unit::repair)
.def("build", &Unit::build, "Build unit of type building_type at given position", "building_type"_a, "position"_a)
.def("build_target", &Unit::buildTarget, "Build building_type on top of target Unit, useful for building refineries", "building_type"_a, "target"_a)
.def("train", &Unit::train, "Train unit of type", "unit_type"_a)
.def("morph", &Unit::morph, "Morph into type of unit_type", "unit_type"_a)
.def("research", &Unit::research, "Research the given :class:`library.UPGRADE_ID`", "upgrade_id"_a)
.def("is_constructing", &Unit::isConstructing, "unit_type"_a)
.def("move", py::overload_cast<const CCTilePosition &>(&Unit::move, py::const_), "Move the unit to the given point, the point being an instance of either :class:`commandcenter.Point2D` or :class:`commandcenter.Point2DI`.")
.def("right_click", &Unit::rightClick, "Same as right-clicking in the game, for example making workers mine minerals.")
.def("repair", &Unit::repair, "Right-clicks on the provided unit in order to repair it.")
.def("build", &Unit::build, "Build unit of type building_type at given position.", "building_type"_a, "position"_a)
.def("build_target", &Unit::buildTarget, "Build building_type on top of target Unit, useful for building refineries.", "building_type"_a, "target"_a)
.def("train", &Unit::train, "Train unit of type.", "unit_type"_a)
.def("morph", &Unit::morph, "Morph into type of unit_type.", "unit_type"_a)
.def("research", &Unit::research, "Research the given :class:`commandcenter.UPGRADE_ID`.", "upgrade_id"_a)
.def("is_constructing", &Unit::isConstructing, "unit_type"_a, "Returns true if the unit is currently constructing another unit of type `unit_type`. Note that `unit_type` needs to be an instance of :class:`commandcenter.UnitType`.")
.def("__hash__", [](const Unit & unit) { return std::hash<const sc2::Unit *>{}(unit.getUnitPtr()); })
.def(py::self == py::self)
.def("__repr__", [](const Unit & unit) { return "<Unit of type: '" + unit.getType().getName() + "'>"; });
.def("__repr__", [](const Unit & unit) { return "<Unit of type: '" + unit.getType().getName() + "'>"; })
.doc() = R"(
An instance of the class Unit represents one unit in the game. The units are
not limited to moveable units, but every entity which is not part of the
background is a unit. For example, the minerals and geysers are units as
well as all buildings.
For all possible types of units see the enum :class:`commandcenter.UNIT_TYPEID`.
Some types of objects are almost the same, for example there are many types
of mineral deposits, but all of them are mineable. This is one of the
motivations behind the :class:`commandcenter.UnitType` which aims to to make the
list of types more manageable. The UnitType can be accessed by the
:any:`Unit.unit_type` property.
It is possible to use Unit as keys in a dictionary, which might be helpful
for bookkeeping.
)" ;
}
......@@ -5,47 +5,59 @@ namespace py = pybind11;
void define_unittype(py::module & m)
{
py::class_<UnitType>(m, "UnitType")
.def(py::init<const sc2::UnitTypeID &, IDABot &>())
.def(py::self == py::self)
.def(py::init([](const sc2::UnitTypeID & type, IDABot & bot) {
return UnitType(type, bot, bot);
}))
.def_property_readonly("unit_typeid", [](UnitType & unit_type) { return static_cast<sc2::UNIT_TYPEID>(unit_type.getAPIUnitType()); })
.def_property_readonly("name", &UnitType::getName)
.def_property_readonly("race", &UnitType::getRace)
.def_property_readonly("movement_speed", &UnitType::getMovementSpeed)
.def_property_readonly("sight_range", &UnitType::getSightRange)
.def_property_readonly("required_structure", &UnitType::getRequiredStructure)
.def_property_readonly("is_valid", &UnitType::isValid)
.def_property_readonly("is_building", &UnitType::isBuilding)
.def_property_readonly("is_combat_unit", &UnitType::isCombatUnit, "The unit is not any of the following: worker, supply provider, building, larva, egg")
.def_property_readonly("is_supply_provider", &UnitType::isSupplyProvider)
.def_property_readonly("is_resource_depot", &UnitType::isResourceDepot)
.def_property_readonly("is_refinery", &UnitType::isRefinery)
.def_property_readonly("is_detector", &UnitType::isDetector)
.def_property_readonly("is_geyser", &UnitType::isGeyser)
.def_property_readonly("is_mineral", &UnitType::isMineral)
.def_property_readonly("is_worker", &UnitType::isWorker)
.def_property_readonly("is_morphed_building", &UnitType::isMorphedBuilding)
.def_property_readonly("name", &UnitType::getName, "The name of the unit as a string.")
.def_property_readonly("race", &UnitType::getRace, "The race the unit belongs to.")
.def_property_readonly("movement_speed", &UnitType::getMovementSpeed, "Movement speed of unit type.")
.def_property_readonly("sight_range", &UnitType::getSightRange, "Range the unit reveals vision.")
.def_property_readonly("required_structure", &UnitType::getRequiredStructure, "Structure required to build this unit. (Or any with the same tech_alias.)")
.def_property_readonly("is_valid", &UnitType::isValid, "Its a valid unit type.")
.def_property_readonly("is_building", &UnitType::isBuilding, "Is this unit type a building or not.")
.def_property_readonly("is_combat_unit", &UnitType::isCombatUnit, "The unit is not any of the following, worker, supply provider, building, larva, egg.")
.def_property_readonly("is_supply_provider", &UnitType::isSupplyProvider, "The unit provides supply.")
.def_property_readonly("is_resource_depot", &UnitType::isResourceDepot, "The unit is one of the following, hatchery, lair, hive, commandcenter, orbialtcommand, planetaryfortress, nexus.")
.def_property_readonly("is_refinery", &UnitType::isRefinery, "The unit is one of the following (depending on race), refinery, assimilator, extractor.")
.def_property_readonly("is_detector", &UnitType::isDetector, "Is this a unit type which is a detector unit.")
.def_property_readonly("is_geyser", &UnitType::isGeyser, "Is the unit type a geyser.")
.def_property_readonly("is_mineral", &UnitType::isMineral, "Is the unit type a mineralfield.")
.def_property_readonly("is_worker", &UnitType::isWorker, "Is the unit type a unit which is a worker.")
.def_property_readonly("is_morphed_building", &UnitType::isMorphedBuilding, "Has this building been morphed.")
// Not implemented in CommandCenter
//.def_property_readonly("can_attack", &UnitType::canAttack)
//.def_property_readonly("can_Move", &UnitType::canMove)
.def_property_readonly("is_addon", &UnitType::isAddon)
.def_property_readonly("attack_range", &UnitType::getAttackRange)
.def_property_readonly("tile_width", &UnitType::tileWidth)
.def_property_readonly("tile_height", &UnitType::tileHeight)
.def_property_readonly("supply_provided", &UnitType::supplyProvided)
.def_property_readonly("supply_required", &UnitType::supplyRequired)
.def_property_readonly("mineral_price", &UnitType::mineralPrice)
.def_property_readonly("gas_price", &UnitType::gasPrice)
.def_property_readonly("is_overlord", &UnitType::isOverlord)
.def_property_readonly("is_larva", &UnitType::isLarva)
.def_property_readonly("is_egg", &UnitType::isEgg)
.def_property_readonly("is_queen", &UnitType::isQueen)
.def_property_readonly("is_tank", &UnitType::isTank)
.def_property_readonly("get_equivalent_units", &UnitType::getEquivalentUnits)
.def_property_readonly("required_attached", &UnitType::requiredAttached)
.def_property_readonly("build_time", &UnitType::getBuildTime)
.def_property_readonly("is_addon", &UnitType::isAddon, "Is this unit type a add-on.")
.def_property_readonly("can_attack_ground", &UnitType::canAttackGound, "True if this unit can attack ground units.")
.def_property_readonly("can_attack_air", &UnitType::canAttackAir, "True if this unit can attack air units.")
.def_property_readonly("attack_range", &UnitType::getAttackRange, "Returns the attack range of the unit type.")
.def_property_readonly("attack_damage", &UnitType::getAttackDamage, "Returns the base attack damage of the unit type.")
.def_property_readonly("tile_width", &UnitType::tileWidth, "Returns the width of the unit type.")
.def_property_readonly("tile_height", &UnitType::tileHeight, "Returns the height of the unit type.")
.def_property_readonly("supply_provided", &UnitType::supplyProvided, "Amount of supply provided by the unit type.")
.def_property_readonly("supply_required", &UnitType::supplyRequired, "Amount of supply required for the unit type.")
.def_property_readonly("mineral_price", &UnitType::mineralPrice, "Mineral price of the unit type.")
.def_property_readonly("gas_price", &UnitType::gasPrice, "Gas price of the unit type.")
.def_property_readonly("is_overlord", &UnitType::isOverlord, "Is this a ZERG_OVERLORD.")
.def_property_readonly("is_larva", &UnitType::isLarva, "is this a ZERG_LARVA.")
.def_property_readonly("is_egg", &UnitType::isEgg, "is this a ZERG_EGG.")
.def_property_readonly("is_queen", &UnitType::isQueen, "is this a ZERG_QUEEN.")
.def_property_readonly("is_tank", &UnitType::isTank, "is this a TERRAN_SIEGETANK or TERRAN_SIEGETANKSIEGED.")
.def_property_readonly("get_equivalent_units", &UnitType::getEquivalentUnits, "Units this is equivalent to in terms of satisfying tech requirements.")
.def_property_readonly("required_attached", &UnitType::requiredAttached, "Whether tech_requirement is an add-on.")
.def_property_readonly("build_time", &UnitType::getBuildTime, "How long the unit takes to build.")
.def("__hash__", [](const UnitType & unit_type) { return std::hash<CCUnitID>{}(unit_type.getAPIUnitType()); })
.def(py::self == py::self)
.def("__repr__", [](const UnitType & unit_type) { return "<UnitType: '" + unit_type.getName() + "'>"; });
.def("__repr__", [](const UnitType & unit_type) { return "<UnitType: '" + unit_type.getName() + "'>"; })
.def("is", &UnitType::is)
.def("__lt__", &UnitType::operator<, py::is_operator())
.def("__eq__", &UnitType::operator==, py::is_operator())
.doc() = R"(
Wrapper for :class:`commandcenter.UNIT_TYPEID`. Represents a type of unit in the game.
NOTE: A lot of functions utilize checks that require the game to be running.
Therefore if you get an unexpected segmentation fault, it is likely due to the game not being in a running state.
)";
// Not implemented in CommandCenter
//.def("whatBuilds", &UnitType::whatBuilds);
......
......@@ -22,4 +22,7 @@ void define_util(py::module & mod)
m.def("dist", py::overload_cast<const Unit &, const Unit &>(&Util::Dist));
m.def("dist", py::overload_cast<const Unit &, const CCPosition &>(&Util::Dist));
m.def("dist", py::overload_cast<const CCPosition &, const CCPosition &>(&Util::Dist));
m.doc() = R"(
The util module provides utility functions for the library.
)";
}
\ No newline at end of file
This diff is collapsed.