diff --git a/create-visual-studio-solution-python38.sh b/create-visual-studio-solution-python38.sh index 081c3e887218f6621b141865c47dc7dc70aabcdf..324f984c01dbc1727bfe0f83f395fc16f6833357 100644 --- a/create-visual-studio-solution-python38.sh +++ b/create-visual-studio-solution-python38.sh @@ -3,4 +3,3 @@ mkdir build38 cd build38 "C:\Program Files\CMake\bin\cmake" .. -G "Visual Studio 15 Win64" -DPYTHON_EXECUTABLE:FILEPATH="C:/Program Files/Python38/python.exe" - diff --git a/create-visual-studio-solution-python39.sh b/create-visual-studio-solution-python39.sh new file mode 100644 index 0000000000000000000000000000000000000000..1d032bd4fe5e96db107fde946800f0d52ad6a4a2 --- /dev/null +++ b/create-visual-studio-solution-python39.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +mkdir build +cd build +"C:\Program Files\CMake\bin\cmake" .. -G "Visual Studio 15 Win64" -DPYTHON_EXECUTABLE:FILEPATH="C:/Program Files/Python39/python.exe" diff --git a/docs/coordinates.rst b/docs/coordinates.rst index fb74871e26f4a5a45f9a16451ae9910756e8b20f..a9ef7d42cdf78daa64484b05118761bfd4b2dfc2 100644 --- a/docs/coordinates.rst +++ b/docs/coordinates.rst @@ -3,7 +3,14 @@ Coordinates The library uses 2 types of coordinate classes. One for integers and one for floats, these are called :class:`library.Point2DI` and -:class:`library.Point2D`. +:class:`library.Point2D`. Convertion between the two types is possible by +sending the other type as argument in the constructor. In the case of +Point2D to Point2DI the floating point values will just be casted into +integer values. + +Both of the types are hashable so they can be used in sets and dictionaries. +Note that it is the tuple (x_val, y_val) that will be hashed so don't mix +those sets or dictionaries with normal tuples. Point2DI -------- diff --git a/docs/helpers.rst b/docs/helpers.rst index 68802b440ee021816569900ad82f6520ae54db31..9f3c4f0967575ba653c8d1c4ab24e13636cada2a 100644 --- a/docs/helpers.rst +++ b/docs/helpers.rst @@ -22,20 +22,15 @@ BaseLocationManager .. class:: library.BaseLocationManager - .. attribute:: library.BaseLocationManager.base_locations + .. autoattribute:: base_locations - A list of all :class:`library.BaseLocation` on the current map + .. autoattribute:: starting_base_locations - .. attribute:: library.BaseLocationManager.starting_base_locations + .. automethod:: get_occupied_base_locations - A list of all :class:`library.BaseLocation` on the current map which a player - started at, indexed by Player constant (see :ref:`playerconstants`). + .. automethod:: get_player_starting_base_location - .. automethod:: library.BaseLocationManager.get_occupied_base_locations - - .. automethod:: library.BaseLocationManager.get_player_starting_base_location - - .. automethod:: library.BaseLocationManager.get_next_expansion + .. automethod:: get_next_expansion BaseLocation ~~~~~~~~~~~~ @@ -46,16 +41,9 @@ BaseLocation the BaseLocationManager to keep track of all base locations and related information. - .. attribute:: library.BaseLocation.position - - The position of the center of the BaseLocation, defined as a :class:`library.Point2D`. - - .. attribute:: library.BaseLocation.depot_position + .. autoattribute:: position - A suitable position for building a town hall (Command Center, Hatchery or - Nexus), defined as a :class:`library.Point2DI`. - - .. autoattribute:: mineral_fields + .. autoattribute:: depot_position .. autoattribute:: minerals @@ -133,32 +121,8 @@ MapTools The top three methods below takes in a Point2D, but it's possible to send in x and y as floats instead of Point2D. - .. automethod:: draw_box - .. automethod:: draw_circle - .. automethod:: draw_resource_sphere - .. automethod:: draw_line - .. automethod:: draw_text - .. automethod:: draw_text_screen - - These are methods which are useful for extracting information about the - game map: - - .. automethod:: can_build_type_at_position - .. automethod:: get_closest_tiles_to - .. automethod:: get_distance_map - .. automethod:: get_ground_distance - .. automethod:: get_least_recently_seen_tile - .. autoattribute:: height - .. autoattribute:: width - .. automethod:: is_buildable - .. automethod:: is_connected - .. automethod:: is_depot_buildable_tile - .. automethod:: is_explored - .. automethod:: is_powered - .. automethod:: is_valid_position - .. automethod:: is_valid_tile - .. automethod:: is_visible - .. automethod:: is_walkable + There is also methods which are useful for extracting information about the + game map. Color ~~~~~ diff --git a/docs/idabot.rst b/docs/idabot.rst index 6a4c6be2f210cfc04ad3b0ccc10ce43ad113caf2..8284f4534b5800d43242e5215111f5d1b63ea7a4 100644 --- a/docs/idabot.rst +++ b/docs/idabot.rst @@ -11,21 +11,10 @@ IDABot Instances of managers: - .. attribute:: IDABot.base_location_manager - - An instance of the class :class:`library.BaseLocationManager` - - .. attribute:: IDABot.tech_tree - - An instance of the class :class:`library.TechTree` - - .. attribute:: IDABot.map_tools - - An instance of the class :class:`library.MapTools` - - .. attribute:: IDABot.building_placer - - An instance of the class :class:`library.BuildingPlacer` + .. autoattribute:: base_location_manager + .. autoattribute:: tech_tree + .. autoattribute:: map_tools + .. autoattribute:: building_placer Inherited methods: @@ -43,29 +32,12 @@ IDABot Methods: - .. method:: IDABot.get_all_units(self) -> List[library.Unit] - - Retrieves a list of all visible units - - .. method:: IDABot.get_my_units(self) -> List[library.Unit] - - Retrieves a list of all your visible units - - .. method:: IDABot.get_player_race(self) -> library.Race - - Returns the players race, useful if you play Race.Random - - .. method:: IDABot.send_chat(self, message) - - Sends the string 'message' to the game chat - - .. method:: IDABot.has_creep(self, Point2D) -> Boolean - - Returns if the position has a creep - - .. method:: IDABot.move_camera(self, Point2DI) - - Move the camera to the position + .. automethod:: get_all_units + .. automethod:: get_my_units + .. automethod:: get_player_race + .. automethod:: send_chat + .. automethod:: has_creep + .. automethod:: move_camera .. method:: IDABot.ability_for_upgrade(self, UpgradeID) @@ -76,105 +48,44 @@ IDABot the unit of scv has the ability for this. You can then use the unit.ability(AbilityID) on the scv for creating the upgrade. - .. method:: IDABot.upgrade_mineral_cost(self, UpgradeID) - - Mineral cost of researching the upgrade - - .. method:: IDABot.upgrade_gas_cost(self, UpgradeID) - - Vespene/gas cost of researching the upgrade - - .. method:: IDABot.upgrade_research_time(self, UpgradeID) - - Time in GameLoops to research this upgrade - - .. method:: IDABot.effect_radius(self, EffectID) - - Size of the circle the effect impacts + .. automethod:: upgrade_mineral_cost + .. automethod:: upgrade_gas_cost + .. automethod:: upgrade_research_time + .. automethod:: effect_radius Attributes: .. autoattribute:: minerals - .. autoattribute:: gas - .. autoattribute:: current_supply - .. autoattribute:: max_supply - .. autoattribute:: current_frame + .. autoattribute:: start_location + ,, autoattribute:: start_locations Debug ----- +.. class:: library.IDABot -When developing AI-methods or when simply having a problem. -The debug-methods are a great tool for speeding up the process. - - .. method:: IDABot.debug_create_unit(self, UnitTypeID, Point2D, Player Constant, Int) - - This method creates the nr (INT) of units on the position :class:`library.Point2D`, the unit - belongs to the Player Constant - - .. method:: IDABot.debug_kill_unit(self, Unit) - - Kills the :class:`library.Unit` - - .. method:: IDABot.debug_show_map(self) - - Make the entire map visible - - .. method:: IDABot.debug_fast_build(self) - - Set the build time in game to 1 - - .. method:: IDABot.debug_enemy_control(self) - - Gives the player full control over the enemy - - .. method:: IDABot.debug_fast_build(self) - - Set the build time in game to 1 - - .. method:: IDABot.debug_ignore_food(self) - - Ignore food in game - - .. method:: IDABot.debug_ignore_resource_cost(self) - - Ignore the resource cost in game. Everything cost 0 resources - - .. method:: IDABot.debug_give_all_resources(self) - - Set the mineral and vespene gas to 5000 - - .. method:: IDABot.debug_god_mode(self) - - Give yourself god mode in the game - - .. method:: IDABot.debug_ignore_mineral(self) - - Ignore the mineral cost in the game - - .. method:: IDABot.debug_no_cooldowns(self) - - Deactivate cooldowns (Basically setting them to 0) - - .. method:: IDABot.debug_give_all_tech(self) - - Give yourself all tech - - .. method:: IDABot.debug_give_all_upgrades(self) - - Give yourself all upgrades - - .. method:: IDABot.debug_set_score(self, Float) - - Set the player score in game - - .. method:: IDABot.debug_end_game(self, Boolean) - - End the game, if the Boolean is True then victory. - If False, defeat. + When developing AI-methods or when simply having a problem. + The debug-methods are a great tool for speeding up the process. + + .. automethod:: debug_create_unit + .. automethod:: debug_kill_unit + .. automethod:: IDABot.debug_show_map(self) + .. automethod:: IDABot.debug_fast_build(self) + .. automethod:: debug_enemy_control + .. automethod:: debug_fast_build + .. automethod:: debug_ignore_food + .. automethod:: debug_ignore_resource_cost + .. automethod:: debug_give_all_resources + .. automethod:: debug_god_mode + .. automethod:: debug_ignore_mineral + .. automethod:: debug_no_cooldowns + .. automethod:: debug_give_all_tech + .. automethod:: debug_give_all_upgrades + .. automethod:: debug_set_score + .. automethod:: debug_end_game .. method:: IDABot.debug_set_energy(self, Float, Unit) @@ -183,12 +94,9 @@ The debug-methods are a great tool for speeding up the process. Note: This is not in percent of the unit energy. Same goes for life and shields. - .. method:: IDABot.debug_set_life(self, Float, Unit) - - Set the amount (Float) of life to the unit + .. automethod:: debug_set_life - .. method:: IDABot.debug_set_shields(self, Float, Unit) + .. automethod:: debug_set_shields - Set the amount (Float) of shield to the unit .. toctree:: \ No newline at end of file diff --git a/docs/unit.rst b/docs/unit.rst index 55a65d72c4c4f55dfd892d81ad19027c5bbaefc1..de4f7b401b5677d1fa9f0296f92fc39adc04968a 100644 --- a/docs/unit.rst +++ b/docs/unit.rst @@ -21,96 +21,50 @@ Unit 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 - Returns the max health .. 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 @@ -118,6 +72,7 @@ Unit Move the unit to the given point, the point being an instance of either :class:`library.Point2D` or :class:`library.Point2DI`. + .. automethod:: right_click .. automethod:: repair .. automethod:: build @@ -125,13 +80,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 diff --git a/python-api-src/lib_base_location.cpp b/python-api-src/lib_base_location.cpp index 9f18f8af329642f301634390b56f898ff6e4bdd9..3fdda68bb322327f93869d0f725dd1d6205a9704 100644 --- a/python-api-src/lib_base_location.cpp +++ b/python-api-src/lib_base_location.cpp @@ -6,21 +6,21 @@ 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("minerals", &BaseLocation::getMinerals, "List of mineral fields at base location (List of unit), Note: also returns the empty mineralfields") + //.def_property_readonly("mineral_fields", &BaseLocation::getMinerals, "Alias for minerals in order to differentiate from harvested minerals") // This just did the same thing as minerals (above) removed to avoid confusion .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("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:`library.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("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 palyer. See :ref:`playerconstants` for more information") + .def("contains_position", &BaseLocation::containsPosition, "If the baselocation contains the provided :class:`library.Point2D` position"); 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_property_readonly("base_locations", &BaseLocationManager::getBaseLocations, py::return_value_policy::reference, "A list of all :class:`library.BaseLocation` on the current map") + .def_property_readonly("starting_base_locations", &BaseLocationManager::getStartingBaseLocations, py::return_value_policy::reference, "A list of all :class:`library.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) - .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("get_player_starting_base_location", &BaseLocationManager::getPlayerStartingBaseLocation, py::return_value_policy::copy, "player_constant"_a, "Returns the :class:`library.BaseLocation` that provided :ref:`playerconstants` started at.") + .def("get_next_expansion", &BaseLocationManager::getNextExpansion, py::return_value_policy::copy, "player_constant"_a, "Returns the :class:`library.BaseLocation` that is closest to the startlocation of provided :ref:`playerconstants` that is possible to expand to."); } \ No newline at end of file diff --git a/python-api-src/lib_building_placer.cpp b/python-api-src/lib_building_placer.cpp index f2aed9730fc09bea3c798a35ddc9dfcf06e7dc7e..56da5e8ffe71ee1d97e075ffc5959caea3009013 100644 --- a/python-api-src/lib_building_placer.cpp +++ b/python-api-src/lib_building_placer.cpp @@ -5,8 +5,9 @@ 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("can_build_here", &BuildingPlacer::canBuildHere, "x"_a, "y"_a, "unit_type"_a, "Returns if the provided unittype it possible to be built at the location. Note: This function uses the width and height of the unittype and this is not correct for addons. 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 baselocation") + .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. 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 unittype and this is not correct for addons. So to check addons please 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 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); diff --git a/python-api-src/lib_map_tools.cpp b/python-api-src/lib_map_tools.cpp index b871070a089ad951c63e60e28e59d61a3fee3701..2f8e344393e44db6d6bc166f4aa9f0aad7eec19d 100644 --- a/python-api-src/lib_map_tools.cpp +++ b/python-api-src/lib_map_tools.cpp @@ -16,33 +16,35 @@ void define_map_tools(py::module & m) 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("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_sphere", &MapTools::drawResourceSphere, py::arg("center"), py::arg("radius"), py::arg("color") = sc2::Colors::White) + .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 cornor 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 if the position is valid for the map") + .def("is_valid_tile", py::overload_cast<const CCTilePosition &>(&MapTools::isValidTile, py::const_), "point_2di"_a, "Checks if the tile is valid for the map") + .def("is_valid_position", py::overload_cast<const CCPosition &>(&MapTools::isValidPosition, py::const_), "point_2d"_a, "Checks if 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 if the coordinates has been explored or not") + .def("is_explored", py::overload_cast<const CCPosition &>(&MapTools::isExplored, py::const_), "point2d"_a, "Returns if the coordinate has been explored or not") + .def("is_explored", py::overload_cast<const CCTilePosition &>(&MapTools::isExplored, py::const_), "point2di"_a, "Returns if 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 if the coordinates are connected") + .def("is_connected", py::overload_cast<const CCTilePosition &, const CCTilePosition &>(&MapTools::isConnected, py::const_), "from"_a, "too"_a, "Returns if the tiles are connected") + .def("is_connected", py::overload_cast<const CCPosition &, const CCPosition &>(&MapTools::isConnected, py::const_), "from"_a, "too"_a, "Returns if the positions are of two connected tiles") + .def("is_walkable", py::overload_cast<int, int>(&MapTools::isWalkable, py::const_), "x"_a, "y"_a, "Returns if the coordinates is walkable") + .def("is_walkable", py::overload_cast<const CCTilePosition &>(&MapTools::isWalkable, py::const_), "point2di"_a, "Returns if the tile is walkable") + .def("is_buildable", py::overload_cast<int, int>(&MapTools::isBuildable, py::const_), "x"_a, "y"_a, "Return if it is possible to build at the provided coordinate") + .def("is_buildable", py::overload_cast<const CCTilePosition &>(&MapTools::isBuildable, py::const_), "point2di"_a, "Return if it is possible to build on tile") + .def("is_visible", &MapTools::isVisible, "x"_a, "y"_a, "Can you see the coordinates") + .def("can_build_type_at_position", &MapTools::canBuildTypeAtPosition, "x"_a, "y"_a, "unit_type"_a, "Is it possible to build the provided unittype at the location") + .def("is_depot_buildable_tile", &MapTools::isDepotBuildableTile, "x"_a, "y"_a, "Is it possbile do 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_least_recently_seen_tile", &MapTools::getLeastRecentlySeenTile, "Returns the tile that the most time has passed since it was visible"); } \ No newline at end of file diff --git a/python-api-src/lib_point.cpp b/python-api-src/lib_point.cpp index 6e46840601cfaf0e8921c0d034384e23d45831ad..be968a3f182bbb2ece49ab7047e1524e6e13d42b 100644 --- a/python-api-src/lib_point.cpp +++ b/python-api-src/lib_point.cpp @@ -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) + ")>"; diff --git a/python-api-src/lib_unit.cpp b/python-api-src/lib_unit.cpp index de09cc58769e8068353ffaab5d94be400208919c..99a4f56d282b728c181c6e745efe814e28a50dd5 100644 --- a/python-api-src/lib_unit.cpp +++ b/python-api-src/lib_unit.cpp @@ -8,58 +8,60 @@ void define_unit(py::module & m) .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("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. Note: 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, "Wheter the unit has any orders") + .def_property_readonly("is_burrowed", &Unit::isBurrowed, "If the unit is burrowed.") + .def_property_readonly("is_valid", &Unit::isValid, "If the unit is valid") + .def_property_readonly("is_training", &Unit::isTraining, "Returns True if the unit is a building and is traing 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) - .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_property_readonly("max_shields", &Unit::maxShields) - .def_property_readonly("max_energy", &Unit::maxEnergy) - .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("facing", &Unit::getFacing, "Direction the unit faces in radians (1 radian == 57.296 degrees)") + .def_property_readonly("radius", &Unit::getRadius, "Retruns 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. Note: Not same as player. Player is from IDA implementation and owner is from sc2") + .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("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("repair", &Unit::repair, "Rightclicks 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:`library.UPGRADE_ID`", "upgrade_id"_a) - .def("is_constructing", &Unit::isConstructing, "unit_type"_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:`library.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() + "'>"; }); diff --git a/python-api-src/lib_unittype.cpp b/python-api-src/lib_unittype.cpp index 723f5e1f170076ff82ea437b25c77a14bf593ffd..c67f74fab7c5d1408d7563aeba24190fb4f9e51d 100644 --- a/python-api-src/lib_unittype.cpp +++ b/python-api-src/lib_unittype.cpp @@ -5,44 +5,49 @@ namespace py = pybind11; void define_unittype(py::module & m) { py::class_<UnitType>(m, "UnitType") - .def(py::init<const sc2::UnitTypeID &, IDABot &>()) + .def(py::init([](const sc2::UnitTypeID & type, IDABot & bot) { + return UnitType(type, bot, bot); + })) .def(py::self == py::self) .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("name", &UnitType::getName, "The name of the unit as a sting.") + .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) - .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("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 mophed") // 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 addon") + .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() + "'>"; }); diff --git a/python-api-src/library.cpp b/python-api-src/library.cpp index 1121edcf6e235f282a3971134d5b2895c1adc8a2..fdfe49e5cc4da999bde93f95ec76eb0e1d38b193 100644 --- a/python-api-src/library.cpp +++ b/python-api-src/library.cpp @@ -80,42 +80,42 @@ PYBIND11_MODULE(library, m) .def(py::init()) .def("on_game_start", &IDABot::OnGameStart) .def("on_step", &IDABot::OnStep) - .def("send_chat", &IDABot::SendChat, "Send a message to the game chat", "message"_a) - .def("get_all_units", &IDABot::GetAllUnits, "Returns a list of all units") - .def("get_my_units", &IDABot::GetMyUnits, "Returns a list of all units beloning to the player") - .def("get_player_race", &IDABot::GetPlayerRace) - .def("debug_create_unit", &IDABot::DebugCreateUnit, "unit_type"_a, "p"_a, "player_id"_a = 1, "count"_a = 1) - .def("debug_kill_unit", &IDABot::DebugKillUnit, "Kill unit from debug mode") + .def("send_chat", &IDABot::SendChat, "Sends the string 'message' to the game chat", "message"_a) + .def("get_all_units", &IDABot::GetAllUnits, "Returns a list of all visible units, including minerals and geysers") + .def("get_my_units", &IDABot::GetMyUnits, "Returns a list of all your units") + .def("get_player_race", &IDABot::GetPlayerRace, "Returns the players race, useful if you play Race.Random") + .def("debug_create_unit", &IDABot::DebugCreateUnit, "This method creates the nr (INT) of units on the position :class:`library.Point2D`, the unit belongs to the Player Constant", "unit_type"_a, "p"_a, "player_id"_a = 0, "count"_a = 1) + .def("debug_kill_unit", &IDABot::DebugKillUnit, "Kill the unit from debug mode") .def("debug_show_map", &IDABot::DebugShowMap, "Show the entire map through debug mode") - .def("debug_fast_build", &IDABot::DebugFastBuild, "Set build time to 1 through debug mode") + .def("debug_fast_build", &IDABot::DebugFastBuild, "Set build time in game to 1 through debug mode") .def("debug_enemy_control", &IDABot::DebugEnemyControl, "Control the enemy through debug mode") - .def("debug_ignore_food", &IDABot::DebugIgnoreFood, "Ignore the food through debug mode") - .def("debug_ignore_resource_cost", &IDABot::DebugIgnoreResourceCost, "Ignore the resource cost through debug mode") - .def("debug_give_all_resources", &IDABot::DebugGiveAllResources, "Give all the resources through debug mode") + .def("debug_ignore_food", &IDABot::DebugIgnoreFood, "Ignore the food in game through debug mode") + .def("debug_ignore_resource_cost", &IDABot::DebugIgnoreResourceCost, "Ignore the resource cost in game, making, everything cost zero resources through debug mode") + .def("debug_give_all_resources", &IDABot::DebugGiveAllResources, "Set the mineral and vespene gas to 5000 through debug mode") .def("debug_god_mode", &IDABot::DebugGodMode, "Give the player god mode") - .def("debug_ignore_mineral", &IDABot::DebugIgnoreMineral, "Ignore the mineral cost through debug mode") - .def("debug_no_cooldowns", &IDABot::DebugNoCooldowns, "Deactive cooldowns through debug mode") + .def("debug_ignore_mineral", &IDABot::DebugIgnoreMineral, "Ignore the mineral cost in game through debug mode") + .def("debug_no_cooldowns", &IDABot::DebugNoCooldowns, "Deactive cooldowns (Basically setting them to 0) through debug mode") .def("debug_give_all_tech", &IDABot::DebugGiveAllTech, "Give all the tech to the player through debug mode") - .def("debug_give_all_upgrades", &IDABot::DebugGiveAllUpgrades, "Give all the upgrades to the player trough debug mode") - .def("debug_set_score", &IDABot::DebugSetScore, "Set the Players score through debug mode") - .def("debug_end_game", &IDABot::DebugEndGame, "End the game through debug mode") + .def("debug_give_all_upgrades", &IDABot::DebugGiveAllUpgrades, "Give all the upgrades to the player through debug mode") + .def("debug_set_score", &IDABot::DebugSetScore, "Set the Players score in game through debug mode") + .def("debug_end_game", &IDABot::DebugEndGame, "End the game through debug mode. If the Boolean is True then victory. If False, defeat.") .def("debug_set_energy", &IDABot::DebugSetEnergy, "Set the energy on a unit through debug mode") .def("debug_set_life", &IDABot::DebugSetLife, "Set the life on a unit through debug mode") .def("debug_set_shields", &IDABot::DebugSetShields, "Set the shields on a unit through debug mode") .def("get_enemy_base_location", &IDABot::GetEnemyBaseLocations, "Return the CCpostion of the enemy base") - .def("move_camera", &IDABot::CameraMove, "Move the camera to p postion", "p"_a) + .def("move_camera", &IDABot::CameraMove, "Move the camera to the postion", "p"_a) .def("has_creep", &IDABot::HasCreep, "Returns true if there is creep at position p", "p"_a) .def("ability_for_upgrade", &IDABot::abilityForUpgrade, "Ability that researches this upgrade", "upgrade"_a) .def("upgrade_mineral_cost", &IDABot::UpgradeMineralCost, "Mineral cost of researching the upgrade", "upgrade"_a) .def("upgrade_gas_cost", &IDABot::UpgradeGasCost, "Vespene/gas cost of researching the upgrade", "upgrade"_a) .def("upgrade_research_time", &IDABot::UpgradeResearchTime, "Time in GameLoops to research this upgrade", "upgrade"_a) .def("effect_radius", &IDABot::RadiusEffect, "Size of the circle the effect impacts", "effect"_a) - .def_property_readonly("base_location_manager", &IDABot::Bases) - .def_property_readonly("tech_tree", &IDABot::GetTechTree) - .def_property_readonly("map_tools", &IDABot::Map) - .def_property_readonly("building_placer", &IDABot::GetBuildingPlacer) - .def_property_readonly("start_location", &IDABot::GetStartLocation, "CCPosition representing the start location") - .def_property_readonly("start_locations", &IDABot::GetStartLocations, "CCPosition representing the start locations") + .def_property_readonly("base_location_manager", &IDABot::Bases, "An instance of the class :class:`library.BaseLocationManager`") + .def_property_readonly("tech_tree", &IDABot::GetTechTree, "An instance of the class :class:`library.TechTree`") + .def_property_readonly("map_tools", &IDABot::Map, "An instance of the class :class:`library.MapTools`") + .def_property_readonly("building_placer", &IDABot::GetBuildingPlacer, "An instance of the class :class:`library.BuildingPlacer`") + .def_property_readonly("start_location", &IDABot::GetStartLocation, "CCPosition representing the start location, note that it is the depot position that is returned.") + .def_property_readonly("start_locations", &IDABot::GetStartLocations, "List of CCPositions representing the start locations, note that it is the depot positions and not the center positions") .def_property_readonly("minerals", &IDABot::GetMinerals, "How much minerals we currently have") .def_property_readonly("current_supply", &IDABot::GetCurrentSupply, "How much supply we are currently using") .def_property_readonly("max_supply", &IDABot::GetMaxSupply, "How much supply we can currently use") diff --git a/src/BaseLocation.cpp b/src/BaseLocation.cpp index b74c4b8e6199e32452bcbec83e793b684316f888..31750667dda60ebcab41b3a158cbacedb4ee77c4 100644 --- a/src/BaseLocation.cpp +++ b/src/BaseLocation.cpp @@ -131,6 +131,14 @@ void BaseLocation::setPlayerOccupying(CCPlayer player, bool occupying) } } +void BaseLocation::setMinerals(std::vector<Unit> & mineralFields) { + m_minerals = mineralFields; +} + +void BaseLocation::setGeysers(std::vector<Unit> & geysers) { + m_geysers = geysers; +} + bool BaseLocation::isInResourceBox(int tileX, int tileY) const { CCPositionType px = Util::TileToPosition((float)tileX); diff --git a/src/BaseLocation.h b/src/BaseLocation.h index 1b22c2addd9936a55042dce5f018d500ad6afe1b..4378c73bfbc8124e66a351354d2add6a1dee9c4e 100644 --- a/src/BaseLocation.h +++ b/src/BaseLocation.h @@ -50,6 +50,8 @@ public: bool isInResourceBox(int x, int y) const; void setPlayerOccupying(CCPlayer player, bool occupying); + void setMinerals(std::vector<Unit> & mineralFields); + void setGeysers(std::vector<Unit> & geysers); const std::vector<CCTilePosition> & getClosestTiles() const; diff --git a/src/BaseLocationManager.cpp b/src/BaseLocationManager.cpp index 848c23fcb7d25a7e86ab1ffdb0108206eff39d3d..93a89d9cb750783de7f087a99c8b7fc041df08b8 100644 --- a/src/BaseLocationManager.cpp +++ b/src/BaseLocationManager.cpp @@ -138,6 +138,12 @@ void BaseLocationManager::onFrame() { drawBaseLocations(); + // make sure that mineralfields and geysers are up to date in the different bases + for (BaseLocation & baselocation : m_baseLocationData) { + updateMinerals(baselocation); + updateGeysers(baselocation); + } + // reset the player occupation information for each location for (auto & baseLocation : m_baseLocationData) { @@ -247,6 +253,32 @@ void BaseLocationManager::onFrame() } +void BaseLocationManager::updateMinerals(BaseLocation & baseToUpdate) { + std::vector<Unit> newMinerals; + for (Unit oldMineral : baseToUpdate.getMinerals()) { + for (auto & mineral : m_bot.GetAllUnits()) { + if (oldMineral.getPosition() == mineral.getPosition() && mineral.getType().isMineral()) { + newMinerals.push_back(mineral); + break; + } + } + } + baseToUpdate.setMinerals(newMinerals); +} + +void BaseLocationManager::updateGeysers(BaseLocation & baseToUpdate) { + std::vector<Unit> newGeysers; + for (Unit oldGeyser : baseToUpdate.getGeysers()) { + for (auto & geyser : m_bot.GetAllUnits()) { + if (oldGeyser.getPosition() == geyser.getPosition() && geyser.getType().isGeyser()) { + newGeysers.push_back(geyser); + break; + } + } + } + baseToUpdate.setGeysers(newGeysers); +} + BaseLocation * BaseLocationManager::getBaseLocation(const CCPosition & pos) const { if (!m_bot.Map().isValidPosition(pos)) { return nullptr; } @@ -293,7 +325,6 @@ const std::set<const BaseLocation *> & BaseLocationManager::getOccupiedBaseLocat return m_occupiedBaseLocations.at(player); } - const BaseLocation * BaseLocationManager::getNextExpansion(int player) const { const BaseLocation * homeBase = getPlayerStartingBaseLocation(player); diff --git a/src/BaseLocationManager.h b/src/BaseLocationManager.h index 8d57be3bf86bce6b6ece0618b67026e58d83e173..1577bbaf3293a19db6d6082f809ca297fc6b53c0 100644 --- a/src/BaseLocationManager.h +++ b/src/BaseLocationManager.h @@ -32,4 +32,9 @@ public: const BaseLocation * getNextExpansion(int player) const; +private: + void updateMinerals(BaseLocation & baseToUpdate); + void updateGeysers(BaseLocation & baseToUpdate); + + }; diff --git a/src/BuildingPlacer.cpp b/src/BuildingPlacer.cpp index 9638349f5ee62fe63449ac8bf44e4af5c644bf91..8ecf797909c4d2898b27fa2bae569a848554001f 100644 --- a/src/BuildingPlacer.cpp +++ b/src/BuildingPlacer.cpp @@ -14,6 +14,23 @@ void BuildingPlacer::onStart() m_reserveMap = std::vector< std::vector<bool> >(m_bot.Map().width(), std::vector<bool>(m_bot.Map().height(), false)); } +void BuildingPlacer::updateReserved(const std::vector<Unit> & units) +{ + freeAllTiles(); + + for (Unit unit : units) { + reserveTiles(unit.getTilePosition().x, unit.getTilePosition().y, unit.getType().tileWidth(), unit.getType().tileHeight()); + } +} + +void BuildingPlacer::freeAllTiles() { + for (int x = 0; x < m_reserveMap.size(); x++) { + for (int y = 0; y < m_reserveMap[x].size(); y++) { + m_reserveMap[x][y] = false; + } + } +} + bool BuildingPlacer::isInResourceBox(int tileX, int tileY) const { return m_bot.Bases().getPlayerStartingBaseLocation(Players::Self)->isInResourceBox(tileX, tileY); @@ -32,12 +49,12 @@ bool BuildingPlacer::canBuildHere(int bx, int by, const UnitType & type) const int xdelta = (int)std::ceil((width - 1.0) / 2); int ydelta = (int)std::ceil((height - 1.0) / 2); - // check the reserve map + // check the reserve map, that it is a valid tile and not a wall for (int x = bx - xdelta; x < bx + width - xdelta; x++) { for (int y = by - ydelta; y < by + height - ydelta; y++) { - if (!m_bot.Map().isValidTile(x, y) || m_reserveMap[x][y]) + if (!m_bot.Map().isValidTile(x, y) || isReserved(x, y) || !m_bot.Map().isWalkable(x, y)) { return false; } @@ -53,6 +70,59 @@ bool BuildingPlacer::canBuildHere(int bx, int by, const UnitType & type) const return true; } +bool BuildingPlacer::canBuildHereWithSize(int bx, int by, int width, int height) +{ + if (isInResourceBox(bx, by)) + { + return false; + } + + int xdelta = (int)std::ceil((width - 1.0) / 2); + int ydelta = (int)std::ceil((height - 1.0) / 2); + + // check the reserve map, that it is a valid tile and not a wall + for (int x = bx - xdelta; x < bx + width - xdelta; x++) + { + for (int y = by - ydelta; y < by + height - ydelta; y++) + { + if (!m_bot.Map().isValidTile(x, y) || isReserved(x, y) || !m_bot.Map().isWalkable(x, y)) + { + return false; + } + } + } + + // Check so it doesn't overlap with a baselocation + // dimensions of the proposed location + + int tx1 = bx - xdelta; + int ty1 = by - ydelta; + int tx2 = tx1 + width - xdelta; + int ty2 = ty1 + height - ydelta; + + // for each base location + for (const BaseLocation * base : m_bot.Bases().getBaseLocations()) + { + // dimensions of the base location + int bx1 = (int)base->getDepotPosition().x; + int by1 = (int)base->getDepotPosition().y; + int bx2 = bx1 + Util::GetTownHall(m_bot.GetPlayerRace(Players::Self), m_bot).tileWidth(); + int by2 = by1 + Util::GetTownHall(m_bot.GetPlayerRace(Players::Self), m_bot).tileHeight(); + + // conditions for non-overlap are easy + bool noOverlap = (tx2 < bx1) || (tx1 > bx2) || (ty2 < by1) || (ty1 > by2); + + // If there is overlap, return false + if (!noOverlap) + { + return false; + } + } + + // otherwise there is no overlap + return true; +} + //returns true if we can build this type of unit here with the specified amount of space. bool BuildingPlacer::canBuildHereWithSpace(int bx, int by, const UnitType & type, int buildDist) const { @@ -64,6 +134,7 @@ bool BuildingPlacer::canBuildHereWithSpace(int bx, int by, const UnitType & type // height and width of the building int width = type.tileWidth(); + int height = type.tileHeight(); int xdelta = (int)std::ceil((width - 1.0) / 2); int ydelta = (int)std::ceil((height - 1.0) / 2); @@ -97,7 +168,7 @@ bool BuildingPlacer::canBuildHereWithSpace(int bx, int by, const UnitType & type { if (!type.isRefinery()) { - if (!buildable(type, x, y) || m_reserveMap[x][y]) + if (!buildable(type, x, y) || isReserved(x, y) || !m_bot.Map().isWalkable(x, y)) // added isWalkabale in order to check towards walls { return false; } @@ -197,6 +268,7 @@ bool BuildingPlacer::buildable(const UnitType & type, int x, int y) const void BuildingPlacer::reserveTiles(int bx, int by, int width, int height) { + // THIS is never called, that's why spacing doesnt work correctly int rwidth = (int)m_reserveMap.size(); int rheight = (int)m_reserveMap[0].size(); diff --git a/src/BuildingPlacer.h b/src/BuildingPlacer.h index 791d3d95fe7c8c613124ab9ca506b75094c9a6b0..e10c228c5bc60e44f397859353762fcb6c112e53 100644 --- a/src/BuildingPlacer.h +++ b/src/BuildingPlacer.h @@ -5,6 +5,7 @@ class IDABot; class BaseLocation; class UnitType; +class Unit; class BuildingPlacer { @@ -23,9 +24,12 @@ public: BuildingPlacer(IDABot & bot); void onStart(); + void updateReserved(const std::vector<Unit> & units); + void freeAllTiles(); // determines whether we can build at a given location bool canBuildHere(int bx, int by, const UnitType & type) const; + bool canBuildHereWithSize(int bx, int by, int width, int height); bool canBuildHereWithSpace(int bx, int by, const UnitType & type, int buildDist) const; // returns a build location near a building's desired location diff --git a/src/IDABot.cpp b/src/IDABot.cpp index 10c29c16ce0c28d2cd0b6bf40a7a62ea33ee1140..8a5fbf7ef07cfaee5f3edb394938cf60c6b8241a 100644 --- a/src/IDABot.cpp +++ b/src/IDABot.cpp @@ -72,6 +72,13 @@ void IDABot::OnStep() m_map.onFrame(); m_unitInfo.onFrame(); m_bases.onFrame(); + + // suppress warnings while we update the tiles occupied by units + bool old_suppress = m_techTree.getSuppressWarnings(); + m_techTree.setSuppressWarnings(true); + m_buildingPlacer.updateReserved(GetAllUnits()); + m_techTree.setSuppressWarnings(old_suppress); + // ----------------------------------------------------------------- // Draw debug interface, and send debug interface to the Sc2 client. // ----------------------------------------------------------------- @@ -231,7 +238,22 @@ const TypeData & IDABot::Data(const MetaType & type) const void IDABot::DebugCreateUnit(UnitTypeID unit_type, const CCPosition& p, uint32_t player_id, uint32_t count) { - Debug()->DebugCreateUnit(unit_type, p, player_id, count); + switch (player_id) // playerconstants for the IDAbot is not the same as for the sc2 API + { + case 0: + Debug()->DebugCreateUnit(unit_type, p, 1, count); + break; + case 1: + Debug()->DebugCreateUnit(unit_type, p, 2, count); + break; + case 2: + Debug()->DebugCreateUnit(unit_type, p, 0, count); + break; + case 3: + Debug()->DebugCreateUnit(unit_type, p, 3, count); + default: + break; + } } void IDABot::DebugKillUnit(const Unit unit) diff --git a/src/MapTools.cpp b/src/MapTools.cpp index 74363174179090016da9be8037b70bf90f09b0fd..23d5b210e40f2654fa6514fb538d0d7688d8d1e4 100644 --- a/src/MapTools.cpp +++ b/src/MapTools.cpp @@ -40,7 +40,8 @@ typedef std::vector<std::vector<float>> vvf; // constructor for MapTools MapTools::MapTools(IDABot & bot) - : m_bot (bot) + : m_bot(bot) + , m_mapName ("") , m_width (0) , m_height (0) , m_maxZ (0.0f) @@ -54,6 +55,7 @@ void MapTools::onStart() #ifdef SC2API m_width = m_bot.Observation()->GetGameInfo().width; m_height = m_bot.Observation()->GetGameInfo().height; + m_mapName= m_bot.Observation()->GetGameInfo().map_name; #else m_width = BWAPI::Broodwar->mapWidth(); m_height = BWAPI::Broodwar->mapHeight(); @@ -344,7 +346,8 @@ bool MapTools::isValidPosition(const CCPosition & pos) const void MapTools::drawLine(CCPositionType x1, CCPositionType y1, CCPositionType x2, CCPositionType y2, const CCColor & color) const { #ifdef SC2API - m_bot.Debug()->DebugLineOut(sc2::Point3D(x1, y1, terrainHeight(x1, y1) + 0.2f), sc2::Point3D(x2, y2, terrainHeight(x2, y2) + 0.2f), color); + //m_bot.Debug()->DebugLineOut(sc2::Point3D(x1, y1, terrainHeight(x1, y1) + 0.2f), sc2::Point3D(x2, y2, terrainHeight(x2, y2) + 0.2f), color); + m_bot.Debug()->DebugLineOut(sc2::Point3D(x1, y1, m_maxZ), sc2::Point3D(x2, y2, m_maxZ), color); // changed to m_maxZ instead fo terrainHeight since it doesnot work correctly #else BWAPI::Broodwar->drawLineMap(BWAPI::Position(x1, y1), BWAPI::Position(x2, y2), color); #endif @@ -371,6 +374,10 @@ void MapTools::drawTile(int tileX, int tileY, const CCColor & color) const drawLine(px, py + d, px, py, color); } +void MapTools::drawTile(const CCTilePosition & pos, const CCColor & color) const { + drawTile(pos.x, pos.y, color); +} + void MapTools::drawBox(CCPositionType x1, CCPositionType y1, CCPositionType x2, CCPositionType y2, const CCColor & color) const { #ifdef SC2API @@ -538,6 +545,11 @@ int MapTools::height() const return m_height; } +std::string MapTools::name() const +{ + return m_mapName; +} + const std::vector<CCTilePosition> & MapTools::getClosestTilesTo(const CCTilePosition & pos) const { return getDistanceMap(pos).getSortedTiles(); diff --git a/src/MapTools.h b/src/MapTools.h index 870052aaa453330c54037fd70ba4f2027022743e..b5490addd247fc22478e157ebfbd864f9d010306 100644 --- a/src/MapTools.h +++ b/src/MapTools.h @@ -8,11 +8,12 @@ class IDABot; class MapTools { - IDABot & m_bot; - int m_width; - int m_height; - float m_maxZ; - int m_frame; + IDABot & m_bot; + std::string m_mapName; + int m_width; + int m_height; + float m_maxZ; + int m_frame; // a cache of already computed distance maps, which is mutable since it only acts as a cache @@ -45,11 +46,13 @@ public: int width() const; int height() const; + std::string name() const; float terrainHeight(float x, float y) const; void drawLine(CCPositionType x1, CCPositionType y1, CCPositionType x2, CCPositionType y2, const CCColor & color = CCColor(255, 255, 255)) const; void drawLine(const CCPosition & p1, const CCPosition & p2, const CCColor & color = CCColor(255, 255, 255)) const; void drawTile(int tileX, int tileY, const CCColor & color = CCColor(255, 255, 255)) const; + void drawTile(const CCTilePosition & pos, const CCColor & color) const; void drawBox(CCPositionType x1, CCPositionType y1, CCPositionType x2, CCPositionType y2, const CCColor & color = CCColor(255, 255, 255)) const; void drawBox(const CCPosition & tl, const CCPosition & br, const CCColor & color = CCColor(255, 255, 255)) const; void drawCircle(CCPositionType x1, CCPositionType x2, CCPositionType radius, const CCColor & color = CCColor(255, 255, 255)) const; diff --git a/src/TechTree.cpp b/src/TechTree.cpp index d0a94c49e05cc43eb9f9f6063029dc40783fb284..1c7c983d91990f667c84a3842fb60f7e1a170adf 100644 --- a/src/TechTree.cpp +++ b/src/TechTree.cpp @@ -101,6 +101,10 @@ void TechTree::setSuppressWarnings(bool b) suppressWarnings = b; } +bool TechTree::getSuppressWarnings() const +{ + return suppressWarnings; +} void TechTree::initUnitTypeData() { @@ -275,7 +279,7 @@ void TechTree::initUpgradeData() m_upgradeData[sc2::UPGRADE_ID::PUNISHERGRENADES] = { sc2::Race::Terran, 50, 50, 0, 960, false, false, false, false, false, false, false, sc2::ABILITY_ID::RESEARCH_CONCUSSIVESHELLS, 0, { UnitType(sc2::UNIT_TYPEID::TERRAN_SCV, m_client) }, {}, {} }; m_upgradeData[sc2::UPGRADE_ID::RAVENCORVIDREACTOR] = { sc2::Race::Terran, 150, 150, 0, 1760, false, false, false, false, false, false, false, sc2::ABILITY_ID::RESEARCH_RAVENCORVIDREACTOR, 0, { UnitType(sc2::UNIT_TYPEID::TERRAN_SCV, m_client) }, {}, {} }; m_upgradeData[sc2::UPGRADE_ID::RAVENRECALIBRATEDEXPLOSIVES] = { sc2::Race::Terran, 150, 150, 0, 1760, false, false, false, false, false, false, false, sc2::ABILITY_ID::RESEARCH_RAVENRECALIBRATEDEXPLOSIVES, 0, { UnitType(sc2::UNIT_TYPEID::TERRAN_SCV, m_client) }, {}, {} }; - m_upgradeData[sc2::UPGRADE_ID::SHIELDWALL] = { sc2::Race::Terran, 100, 100, 0, 1760, false, false, false, false, false, false, false, sc2::ABILITY_ID::RESEARCH_COMBATSHIELD, 0, { UnitType(sc2::UNIT_TYPEID::TERRAN_BARRACKSTECHLAB, m_client) }, {}, {} }; + m_upgradeData[sc2::UPGRADE_ID::SHIELDWALL] = { sc2::Race::Terran, 100, 100, 0, 1760, false, false, false, false, false, false, false, sc2::ABILITY_ID::RESEARCH_COMBATSHIELD, 0, { UnitType(sc2::UNIT_TYPEID::TERRAN_BARRACKSTECHLAB, m_client) }, {}, {} }; m_upgradeData[sc2::UPGRADE_ID::STIMPACK] = { sc2::Race::Terran, 100, 100, 0, 2720, false, false, false, false, false, false, false, sc2::ABILITY_ID::RESEARCH_STIMPACK, 0, { UnitType(sc2::UNIT_TYPEID::TERRAN_SCV, m_client) }, {}, {} }; m_upgradeData[sc2::UPGRADE_ID::TERRANBUILDINGARMOR] = { sc2::Race::Terran, 150, 150, 0, 2240, false, false, false, false, false, false, false, sc2::ABILITY_ID::RESEARCH_TERRANSTRUCTUREARMORUPGRADE, 0, { UnitType(sc2::UNIT_TYPEID::TERRAN_ENGINEERINGBAY, m_client) }, {}, {} }; m_upgradeData[sc2::UPGRADE_ID::TERRANINFANTRYARMORSLEVEL1] = { sc2::Race::Terran, 100, 100, 0, 2560, false, false, false, false, false, false, false, sc2::ABILITY_ID::RESEARCH_TERRANINFANTRYARMORLEVEL1, 0, { UnitType(sc2::UNIT_TYPEID::TERRAN_ENGINEERINGBAY, m_client) }, {}, {} }; diff --git a/src/TechTree.h b/src/TechTree.h index 412aaf49c0b50c5781dbb4825a1fadc1a62651b0..df75efb5bb0ffaa9fcf495d18c3003181b4ae3c4 100644 --- a/src/TechTree.h +++ b/src/TechTree.h @@ -45,7 +45,8 @@ public: void onStart(); void setSuppressWarnings(bool b); - + bool getSuppressWarnings() const; + const TypeData & getData(const UnitType & type) const; const TypeData & getData(const CCUpgrade & type) const; const TypeData & getData(const MetaType & type) const; diff --git a/src/Unit.cpp b/src/Unit.cpp index 50b5fa4df5485a7fba382a06bcc2431fceedec02..130eaa3185e6bb8428500bcdbd13cb98f1f59d56 100644 --- a/src/Unit.cpp +++ b/src/Unit.cpp @@ -118,7 +118,7 @@ bool Unit::isCompleted() const bool Unit::isTraining() const { BOT_ASSERT(isValid(), "Unit is not valid"); - return m_unit->orders.size() > 0; + return m_unit->orders.size() > 0 && m_unitType.isBuilding(); } bool Unit::isBeingConstructed() const @@ -339,6 +339,12 @@ Unit Unit::getTarget() const if(getUnitPtr()->orders.size() > 0){ // t_id is set to the unit tag of the target CCUnitID t_id = getUnitPtr()->orders[0].target_unit_tag; + + // if it doesn't have a target. Return itself + if (m_bot->GetUnit(t_id) == nullptr) { + return *this; + } + // IDABot finds the unit with this tag return m_bot->GetUnit(t_id); } @@ -400,6 +406,20 @@ float Unit::getProgress() const return -1; } +const std::vector<float> Unit::getAllProgress() const +{ + BOT_ASSERT(isValid(), "Unit is not valid"); + // If unit has order, return progress of first order + std::vector<float> progressions; + if (getUnitPtr()->orders.size() > 0) { + for(int i = 0; i < getUnitPtr()->orders.size(); i++) { + progressions.push_back(getUnitPtr()->orders[i].progress); + } + } + + return progressions; +} + sc2::AbilityID Unit::getCurrentAbilityID() const { BOT_ASSERT(isValid(), "Unit is not valid"); diff --git a/src/Unit.h b/src/Unit.h index f68a09bf1b3e4dd4fad4043265e52cf85a0a49e9..a33c6ffb53ee4fb78676a1625e3aa96310e6f80d 100644 --- a/src/Unit.h +++ b/src/Unit.h @@ -56,6 +56,7 @@ public: Unit getTarget() const; CCHealth getMaxHitPoints() const; float getProgress() const; + const std::vector<float> getAllProgress() const; sc2::AbilityID getCurrentAbilityID() const; void holdPosition() const; void patrol(const CCPosition & targetPosition) const; diff --git a/src/UnitType.cpp b/src/UnitType.cpp index 56b113e6ca713f53de307fefad181b39ec6c437e..f4fcbd4c3c41d9169eb0558a514e145de0cc9086 100644 --- a/src/UnitType.cpp +++ b/src/UnitType.cpp @@ -16,7 +16,7 @@ UnitType::UnitType(const sc2::UnitTypeID & type, sc2::Client & client) , m_observer(nullptr) { - + } UnitType::UnitType(const sc2::UnitTypeID & type, sc2::Client & client, IDABot & bot) @@ -25,6 +25,7 @@ UnitType::UnitType(const sc2::UnitTypeID & type, sc2::Client & client, IDABot & , m_bot(&bot) , m_observer(nullptr) { + } UnitType::UnitType(const sc2::UnitTypeID & type, sc2::Client & client, IDAReplayObserver & observer) @@ -34,9 +35,8 @@ UnitType::UnitType(const sc2::UnitTypeID & type, sc2::Client & client, IDAReplay , m_bot(nullptr) { -} - +} sc2::UnitTypeID UnitType::getAPIUnitType() const { @@ -135,9 +135,12 @@ bool UnitType::isRefinery() const #ifdef SC2API switch (m_type.ToType()) { - case sc2::UNIT_TYPEID::TERRAN_REFINERY : return true; - case sc2::UNIT_TYPEID::PROTOSS_ASSIMILATOR : return true; - case sc2::UNIT_TYPEID::ZERG_EXTRACTOR : return true; + case sc2::UNIT_TYPEID::TERRAN_REFINERY : return true; + case sc2::UNIT_TYPEID::TERRAN_REFINERYRICH : return true; + case sc2::UNIT_TYPEID::PROTOSS_ASSIMILATOR : return true; + case sc2::UNIT_TYPEID::PROTOSS_ASSIMILATORRICH : return true; + case sc2::UNIT_TYPEID::ZERG_EXTRACTOR : return true; + case sc2::UNIT_TYPEID::ZERG_EXTRACTORRICH : return true; default: return false; } #else @@ -171,6 +174,10 @@ bool UnitType::isGeyser() const case sc2::UNIT_TYPEID::NEUTRAL_VESPENEGEYSER : return true; case sc2::UNIT_TYPEID::NEUTRAL_PROTOSSVESPENEGEYSER : return true; case sc2::UNIT_TYPEID::NEUTRAL_SPACEPLATFORMGEYSER : return true; + case sc2::UNIT_TYPEID::NEUTRAL_SHAKURASVESPENEGEYSER: return true; + case sc2::UNIT_TYPEID::NEUTRAL_RICHVESPENEGEYSER : return true; + case sc2::UNIT_TYPEID::NEUTRAL_PURIFIERVESPENEGEYSER: return true; + default: return false; } #else @@ -183,12 +190,15 @@ bool UnitType::isMineral() const #ifdef SC2API switch (m_type.ToType()) { - case sc2::UNIT_TYPEID::NEUTRAL_MINERALFIELD : return true; - case sc2::UNIT_TYPEID::NEUTRAL_MINERALFIELD750 : return true; - case sc2::UNIT_TYPEID::NEUTRAL_RICHMINERALFIELD : return true; - case sc2::UNIT_TYPEID::NEUTRAL_RICHMINERALFIELD750 : return true; - case sc2::UNIT_TYPEID::NEUTRAL_LABMINERALFIELD : return true; - case sc2::UNIT_TYPEID::NEUTRAL_LABMINERALFIELD750 : return true; + case sc2::UNIT_TYPEID::NEUTRAL_MINERALFIELD : return true; + case sc2::UNIT_TYPEID::NEUTRAL_MINERALFIELD750 : return true; + case sc2::UNIT_TYPEID::NEUTRAL_RICHMINERALFIELD : return true; + case sc2::UNIT_TYPEID::NEUTRAL_RICHMINERALFIELD750 : return true; + case sc2::UNIT_TYPEID::NEUTRAL_LABMINERALFIELD : return true; + case sc2::UNIT_TYPEID::NEUTRAL_LABMINERALFIELD750 : return true; + case sc2::UNIT_TYPEID::NEUTRAL_PURIFIERMINERALFIELD : return true; + case sc2::UNIT_TYPEID::NEUTRAL_PURIFIERMINERALFIELD750 : return true; + default: return false; } #else @@ -212,6 +222,54 @@ bool UnitType::isWorker() const #endif } +bool UnitType::canAttackGound() const +{ +#ifdef SC2API + auto & weapons = m_client->Observation()->GetUnitTypeData()[m_type].weapons; + + if (weapons.empty()) + { + return false; + } + for (auto & weapon : weapons) + { + if (weapon.type == sc2::Weapon::TargetType::Ground || weapon.type == sc2::Weapon::TargetType::Any) + { + return true; + } + } + return false; +#else + // TODO: this is nothing right now... + // just like with the attackRange we should never get in here. + return 0.0f; +#endif +} + +bool UnitType::canAttackAir() const +{ +#ifdef SC2API + auto & weapons = m_client->Observation()->GetUnitTypeData()[m_type].weapons; + + if (weapons.empty()) + { + return false; + } + for (auto & weapon : weapons) + { + if (weapon.type == sc2::Weapon::TargetType::Air || weapon.type == sc2::Weapon::TargetType::Any) + { + return true; + } + } + return false; +#else + // TODO: this is nothing right now... + // just like with the attackRange we should never get in here. + return 0.0f; +#endif +} + CCPositionType UnitType::getAttackRange() const { #ifdef SC2API @@ -238,6 +296,33 @@ CCPositionType UnitType::getAttackRange() const #endif } +float UnitType::getAttackDamage() const +{ +#ifdef SC2API + auto & weapons = m_client->Observation()->GetUnitTypeData()[m_type].weapons; + + if (weapons.empty()) + { + return 0.0f; + } + + float maxDamage = 0.0f; + for (auto & weapon : weapons) + { + if (weapon.range > maxDamage) + { + maxDamage = weapon.damage_; + } + } + + return maxDamage; +#else + // TODO: this is nothing right now... + // just like with the attackRange we should never get in here. + return 0.0f; +#endif +} + int UnitType::tileWidth() const { #ifdef SC2API diff --git a/src/UnitType.h b/src/UnitType.h index 1491bb11d335f2b9ed01dd7fcf60b01b8dc9eea6..1fe66ae7cb2f78c13b224a273986711ec4f1720a 100644 --- a/src/UnitType.h +++ b/src/UnitType.h @@ -49,7 +49,10 @@ public: bool canAttack() const; bool canMove() const; bool isAddon() const; + bool canAttackGound() const; + bool canAttackAir() const; CCPositionType getAttackRange() const; + float getAttackDamage() const; int tileWidth() const; int tileHeight() const; int supplyProvided() const;