diff --git a/src/ai/api/ai_road.hpp b/src/ai/api/ai_road.hpp new file mode 100644 --- /dev/null +++ b/src/ai/api/ai_road.hpp @@ -0,0 +1,408 @@ +/* $Id$ */ + +/** @file ai_road.hpp Everything to query and build roads. */ + +#ifndef AI_ROAD_HPP +#define AI_ROAD_HPP + +#include "ai_object.hpp" +#include "ai_error.hpp" +#include "ai_tile.hpp" + +/** + * Class that handles all road related functions. + */ +class AIRoad : public AIObject { +public: + static const char *GetClassName() { return "AIRoad"; } + + /** + * All road related error messages. + */ + enum ErrorMessages { + /** Base for road building / maintaining errors */ + ERR_ROAD_BASE = AIError::ERR_CAT_ROAD << AIError::ERR_CAT_BIT_SIZE, + + /** Road works are in progress */ + ERR_ROAD_WORKS_IN_PROGRESS, // [STR_ROAD_WORKS_IN_PROGRESS] + + /** Drive through is in the wrong direction */ + ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION, // [STR_DRIVE_THROUGH_ERROR_DIRECTION] + + /** Drive through roads can't be build on town owned roads */ + ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD, // [STR_DRIVE_THROUGH_ERROR_ON_TOWN_ROAD] + + + /** One way roads can't have junctions */ + ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS, // [STR_ERR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION] + }; + + /** + * Types of road known to the game. + */ + enum RoadType { + /* Values are important, as they represent the internal state of the game. */ + ROADTYPE_ROAD = 0, //!< Build road objects. + ROADTYPE_TRAM = 1, //!< Build tram objects. + + ROADTYPE_INVALID = -1, //!< Invalid RoadType. + }; + + /** + * Checks whether the given tile is actually a tile with road that can be + * used to traverse a tile. This excludes road depots and 'normal' road + * stations, but includes drive through stations. + * @param tile The tile to check. + * @pre AIMap::IsValidTile(tile). + * @return True if and only if the tile has road. + */ + static bool IsRoadTile(TileIndex tile); + + /** + * Checks whether the given tile is actually a tile with a road depot. + * @param tile The tile to check. + * @pre AIMap::IsValidTile(tile). + * @return True if and only if the tile has a road depot. + */ + static bool IsRoadDepotTile(TileIndex tile); + + /** + * Checks whether the given tile is actually a tile with a road station. + * @param tile The tile to check. + * @pre AIMap::IsValidTile(tile). + * @return True if and only if the tile has a road station. + */ + static bool IsRoadStationTile(TileIndex tile); + + /** + * Checks whether the given tile is actually a tile with a drive through + * road station. + * @param tile The tile to check. + * @pre AIMap::IsValidTile(tile). + * @return True if and only if the tile has a drive through road station. + */ + static bool IsDriveThroughRoadStationTile(TileIndex tile); + + /** + * Check if a given RoadType is available. + * @param road_type The RoadType to check for. + * @return True if this RoadType can be used. + */ + static bool IsRoadTypeAvailable(RoadType road_type); + + /** + * Get the current RoadType set for all AIRoad functions. + * @return The RoadType currently set. + */ + static RoadType GetCurrentRoadType(); + + /** + * Set the RoadType for all further AIRoad functions. + * @param road_type The RoadType to set. + */ + static void SetCurrentRoadType(RoadType road_type); + + /** + * Check if a given tile has RoadType. + * @param tile The tile to check. + * @param road_type The RoadType to check for. + * @pre AIMap::IsValidTile(tile). + * @pre IsRoadTypeAvailable(road_type). + * @return True if the tile contains a RoadType object. + */ + static bool HasRoadType(TileIndex tile, RoadType road_type); + + /** + * Checks whether the given tiles are directly connected, i.e. whether + * a road vehicle can travel from the center of the first tile to the + * center of the second tile. + * @param tile_from The source tile. + * @param tile_to The destination tile. + * @pre AIMap::IsValidTile(tile_from). + * @pre AIMap::IsValidTile(tile_to). + * @pre 'tile_from' and 'tile_to' are directly neighbouring tiles. + * @return True if and only if a road vehicle can go from tile_from to tile_to. + */ + static bool AreRoadTilesConnected(TileIndex tile_from, TileIndex tile_to); + + /** + * Lookup function for building road parts independend on whether the + * "building on slopes" setting is enabled or not. + * This implementation can be used for abstract reasoning about a tile as + * it needs the slope and existing road parts of the tile as information. + * @param slope The slope of the tile to examine. + * @param existing An array with the existing neighbours in the same format + * as "start" and "end", e.g. AIMap.GetTileIndex(0, 1). + * As a result of this all values of the existing array + * must be of type integer. + * @param start The tile from where the 'tile to be considered' will be + * entered. This is a relative tile, so valid parameters are: + * AIMap.GetTileIndex(0, 1), AIMap.GetTileIndex(0, -1), + * AIMap.GetTileIndex(1, 0) and AIMap.GetTileIndex(-1, 0). + * @param end The tile from where the 'tile to be considered' will be + * exited. This is a relative tile, sovalid parameters are: + * AIMap.GetTileIndex(0, 1), AIMap.GetTileIndex(0, -1), + * AIMap.GetTileIndex(1, 0) and AIMap.GetTileIndex(-1, 0). + * @pre start != end. + * @pre slope must be a valid slope, i.e. one specified in AITile::Slope. + * @note Passing data that would be invalid in-game, e.g. existing containing + * road parts that can not be build on a tile with the given slope, + * does not necessarily means that -1 is returned, i.e. not all + * preconditions written here or assumed by the game are extensively + * checked to make sure the data entered is valid. + * @return 0 when the build parts do not connect, 1 when they do connect once + * they are build or 2 when building the first part automatically + * builds the second part. -1 means the preconditions are not met. + */ + static int32 CanBuildConnectedRoadParts(AITile::Slope slope, struct Array *existing, TileIndex start, TileIndex end); + + /** + * Lookup function for building road parts independend on whether the + * "building on slopes" setting is enabled or not. + * This implementation can be used for reasoning about an existing tile. + * @param tile The the tile to examine. + * @param start The tile from where "tile" will be entered. + * @param end The tile from where "tile" will be exited. + * @pre start != end. + * @pre tile != start. + * @pre tile != end. + * @pre AIMap.IsValidTile(tile). + * @pre AIMap.IsValidTile(start). + * @pre AIMap.IsValidTile(end). + * @pre AIMap.GetDistanceManhattanToTile(tile, start) == 1. + * @pre AIMap.GetDistanceManhattanToTile(tile, end) == 1. + * @return 0 when the build parts do not connect, 1 when they do connect once + * they are build or 2 when building the first part automatically + * builds the second part. -1 means the preconditions are not met. + */ + static int32 CanBuildConnectedRoadPartsHere(TileIndex tile, TileIndex start, TileIndex end); + + /** + * Count how many neighbours are road. + * @param tile The tile to check on. + * @pre AIMap::IsValidTile(tile). + * @return 0 means no neighbour road; max value is 4. + */ + static int32 GetNeighbourRoadCount(TileIndex tile); + + /** + * Gets the tile in front of a road depot. + * @param depot The road depot tile. + * @pre IsRoadDepotTile(depot). + * @return The tile in front of the depot. + */ + static TileIndex GetRoadDepotFrontTile(TileIndex depot); + + /** + * Gets the tile in front of a road station. + * @param station The road station tile. + * @pre IsRoadStationTile(station). + * @return The tile in front of the road station. + */ + static TileIndex GetRoadStationFrontTile(TileIndex station); + + /** + * Gets the tile at the back of a drive through road station. + * So, one side of the drive through station is retrieved with + * GetTileInFrontOfStation, the other with this function. + * @param station The road station tile. + * @pre IsDriveThroughRoadStationTile(station). + * @return The tile at the back of the drive through road station. + */ + static TileIndex GetDriveThroughBackTile(TileIndex station); + + /** + * Builds a road from the center of tile start to the center of tile end. + * @param start The start tile of the road. + * @param end The end tile of the road. + * @pre 'start' is not equal to 'end'. + * @pre AIMap::IsValidTile(start). + * @pre AIMap::IsValidTile(end). + * @pre 'start' and 'end' are in a straight line, i.e. + * AIMap::GetTileX(start) == AIMap::GetTileX(end) or + * AIMap::GetTileY(start) == AIMap::GetTileY(end). + * @exception AIError::ERR_ALREADY_BUILT + * @exception AIError::ERR_LAND_SLOPED_WRONG + * @exception AIError::ERR_AREA_NOT_CLEAR + * @exception AIRoad::ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS + * @exception AIRoad::ERR_ROAD_WORKS_IN_PROGRESS + * @exception AIError::ERR_VEHICLE_IN_THE_WAY + * @return Whether the road has been/can be build or not. + */ + static bool BuildRoad(TileIndex start, TileIndex end); + + /** + * Builds a one-way road from the center of tile start to the center + * of tile end. If the road already exists, it is made one-way road. + * If the road already exists and is already one-way in this direction, + * the road is made two-way again. If the road already exists but is + * one-way in the other direction, it's made a 'no'-way road (it's + * forbidden to enter the tile from any direction). + * @param start The start tile of the road. + * @param end The end tile of the road. + * @pre 'start' is not equal to 'end'. + * @pre AIMap::IsValidTile(start). + * @pre AIMap::IsValidTile(end). + * @pre 'start' and 'end' are in a straight line, i.e. + * AIMap::GetTileX(start) == AIMap::GetTileX(end) or + * AIMap::GetTileY(start) == AIMap::GetTileY(end). + * @pre GetCurrentRoadType() == ROADTYPE_ROAD. + * @exception AIError::ERR_ALREADY_BUILT + * @exception AIError::ERR_LAND_SLOPED_WRONG + * @exception AIError::ERR_AREA_NOT_CLEAR + * @exception AIRoad::ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS + * @exception AIRoad::ERR_ROAD_WORKS_IN_PROGRESS + * @exception AIError::ERR_VEHICLE_IN_THE_WAY + * @return Whether the road has been/can be build or not. + */ + static bool BuildOneWayRoad(TileIndex start, TileIndex end); + + /** + * Builds a road from the edge of tile start to the edge of tile end (both + * included). + * @param start The start tile of the road. + * @param end The end tile of the road. + * @pre 'start' is not equal to 'end'. + * @pre AIMap::IsValidTile(start). + * @pre AIMap::IsValidTile(end). + * @pre 'start' and 'end' are in a straight line, i.e. + * AIMap::GetTileX(start) == AIMap::GetTileX(end) or + * AIMap::GetTileY(start) == AIMap::GetTileY(end). + * @exception AIError::ERR_ALREADY_BUILT + * @exception AIError::ERR_LAND_SLOPED_WRONG + * @exception AIError::ERR_AREA_NOT_CLEAR + * @exception AIRoad::ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS + * @exception AIRoad::ERR_ROAD_WORKS_IN_PROGRESS + * @exception AIError::ERR_VEHICLE_IN_THE_WAY + * @return Whether the road has been/can be build or not. + */ + static bool BuildRoadFull(TileIndex start, TileIndex end); + + /** + * Builds a one-way road from the edge of tile start to the edge of tile end + * (both included). If the road already exists, it is made one-way road. + * If the road already exists and is already one-way in this direction, + * the road is made two-way again. If the road already exists but is + * one-way in the other direction, it's made a 'no'-way road (it's + * forbidden to enter the tile from any direction). + * @param start The start tile of the road. + * @param start The start tile of the road. + * @param end The end tile of the road. + * @pre 'start' is not equal to 'end'. + * @pre AIMap::IsValidTile(start). + * @pre AIMap::IsValidTile(end). + * @pre 'start' and 'end' are in a straight line, i.e. + * AIMap::GetTileX(start) == AIMap::GetTileX(end) or + * AIMap::GetTileY(start) == AIMap::GetTileY(end). + * @pre GetCurrentRoadType() == ROADTYPE_ROAD. + * @exception AIError::ERR_ALREADY_BUILT + * @exception AIError::ERR_LAND_SLOPED_WRONG + * @exception AIError::ERR_AREA_NOT_CLEAR + * @exception AIRoad::ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS + * @exception AIRoad::ERR_ROAD_WORKS_IN_PROGRESS + * @exception AIError::ERR_VEHICLE_IN_THE_WAY + * @return Whether the road has been/can be build or not. + */ + static bool BuildOneWayRoadFull(TileIndex start, TileIndex end); + + /** + * Builds a road depot. + * @param tile Place to build the depot. + * @param front The tile exactly in front of the depot. + * @pre AIMap::IsValidTile(tile). + * @pre AIMap::IsValidTile(front). + * @pre 'tile' is not equal to 'front', but in a straight line of it. + * @exception AIError::ERR_FLAT_LAND_REQUIRED + * @exception AIError::ERR_AREA_NOT_CLEAR + * @return Whether the road depot has been/can be build or not. + */ + static bool BuildRoadDepot(TileIndex tile, TileIndex front); + + /** + * Builds a road bus or truck station. + * @param tile Place to build the depot. + * @param front The tile exactly in front of the station. + * For drive-through stations either entrance side can be used. + * @param truck Whether to build a truck (true) or bus (false) station. + * @param drive_through Whether to make the station drive through or not. + * @param join_adjacent When building next to an other station, don't create a new station when this flag is true. + * @pre AIMap::IsValidTile(tile). + * @pre AIMap::IsValidTile(front). + * @pre 'tile' is not equal to 'front', but in a straight line of it. + * @exception AIError::ERR_OWNED_BY_ANOTHER_COMPANY + * @exception AIError::ERR_AREA_NOT_CLEAR + * @exception AIError::ERR_FLAT_LAND_REQUIRED + * @exception AIRoad::ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION + * @exception AIRoad::ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD + * @exception AIError:ERR_VEHICLE_IN_THE_WAY + * @exception AIStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION + * @exception AIStation::ERR_STATION_TOO_MANY_STATIONS + * @exception AIStation::ERR_STATION_TOO_MANY_STATIONS_IN_TOWN + * @return Whether the station has been/can be build or not. + */ + static bool BuildRoadStation(TileIndex tile, TileIndex front, bool truck, bool drive_through, bool join_adjacent); + + /** + * Removes a road from the center of tile start to the center of tile end. + * @param start The start tile of the road. + * @param end The end tile of the road. + * @pre AIMap::IsValidTile(start). + * @pre AIMap::IsValidTile(end). + * @pre 'start' and 'end' are in a straight line, i.e. + * AIMap::GetTileX(start) == AIMap::GetTileX(end) or + * AIMap::GetTileY(start) == AIMap::GetTileY(end). + * @exception AIError::ERR_OWNED_BY_ANOTHER_COMPANY + * @exception AIError::ERR_VEHICLE_IN_THE_WAY + * @exception AIRoad::ERR_ROAD_WORKS_IN_PROGRESS + * @return Whether the road has been/can be removed or not. + */ + static bool RemoveRoad(TileIndex start, TileIndex end); + + /** + * Removes a road from the edge of tile start to the edge of tile end (both + * included). + * @param start The start tile of the road. + * @param end The end tile of the road. + * @pre AIMap::IsValidTile(start). + * @pre AIMap::IsValidTile(end). + * @pre 'start' and 'end' are in a straight line, i.e. + * AIMap::GetTileX(start) == AIMap::GetTileX(end) or + * AIMap::GetTileY(start) == AIMap::GetTileY(end). + * @exception AIError::ERR_OWNED_BY_ANOTHER_COMPANY + * @exception AIError::ERR_VEHICLE_IN_THE_WAY + * @exception AIRoad::ERR_ROAD_WORKS_IN_PROGRESS + * @return Whether the road has been/can be removed or not. + */ + static bool RemoveRoadFull(TileIndex start, TileIndex end); + + /** + * Removes a road depot. + * @param tile Place to remove the depot from. + * @pre AIMap::IsValidTile(tile). + * @pre Tile is a road depot. + * @exception AIError::ERR_OWNED_BY_ANOTHER_COMPANY + * @exception AIError::ERR_VEHICLE_IN_THE_WAY + * @return Whether the road depot has been/can be removed or not. + */ + static bool RemoveRoadDepot(TileIndex tile); + + /** + * Removes a road bus or truck station. + * @param tile Place to remove the station from. + * @pre AIMap::IsValidTile(tile). + * @pre Tile is a road station. + * @exception AIError::ERR_OWNED_BY_ANOTHER_COMPANY + * @exception AIError::ERR_VEHICLE_IN_THE_WAY + * @return Whether the station has been/can be removed or not. + */ + static bool RemoveRoadStation(TileIndex tile); + +private: + + /** + * Internal function used by Build(OneWay)Road(Full). + */ + static bool _BuildRoadInternal(TileIndex start, TileIndex end, bool one_way, bool full); +}; + +#endif /* AI_ROAD_HPP */