rubidium@9453: /* $Id$ */ rubidium@9453: truebrain@9833: /** @file ai_road.cpp Implementation of AIRoad. */ rubidium@9453: rubidium@9453: #include "ai_road.hpp" truebrain@10668: #include "ai_map.hpp" rubidium@10993: #include "ai_list.hpp" truebrain@10339: #include "../../openttd.h" rubidium@9453: #include "../../road_map.h" rubidium@9453: #include "../../station_map.h" rubidium@10513: #include "../../command_type.h" truebrain@10668: #include "../../player_func.h" rubidium@10993: #include "../../settings_type.h" rubidium@10993: #include "../../squirrel_helper_type.hpp" rubidium@9453: truebrain@9737: /* static */ bool AIRoad::IsRoadTile(TileIndex tile) rubidium@9453: { truebrain@9801: if (!::IsValidTile(tile)) return false; rubidium@9453: rubidium@9694: return (::IsTileType(tile, MP_ROAD) && ::GetRoadTileType(tile) != ROAD_TILE_DEPOT) || truebrain@9737: IsDriveThroughRoadStationTile(tile); rubidium@9551: } rubidium@9551: truebrain@9737: /* static */ bool AIRoad::IsRoadDepotTile(TileIndex tile) rubidium@9551: { truebrain@9801: if (!::IsValidTile(tile)) return false; rubidium@9551: rubidium@9694: return ::IsTileType(tile, MP_ROAD) && ::GetRoadTileType(tile) == ROAD_TILE_DEPOT; rubidium@9551: } rubidium@9551: truebrain@9737: /* static */ bool AIRoad::IsRoadStationTile(TileIndex tile) rubidium@9551: { truebrain@9801: if (!::IsValidTile(tile)) return false; rubidium@9551: rubidium@9551: return ::IsRoadStopTile(tile); rubidium@9551: } rubidium@9551: truebrain@9737: /* static */ bool AIRoad::IsDriveThroughRoadStationTile(TileIndex tile) rubidium@9551: { truebrain@9801: if (!::IsValidTile(tile)) return false; rubidium@9551: rubidium@9551: return ::IsDriveThroughStopTile(tile); rubidium@9551: } rubidium@9551: truebrain@10668: /* static */ bool AIRoad::IsRoadTypeAvailable(RoadType road_type) truebrain@10668: { truebrain@10668: return ::HasRoadTypesAvail(_current_player, ::RoadTypeToRoadTypes((::RoadType)road_type)); truebrain@10668: } truebrain@10668: truebrain@10668: /* static */ AIRoad::RoadType AIRoad::GetCurrentRoadType() truebrain@10668: { truebrain@10668: return (RoadType)AIObject::GetRoadType(); truebrain@10668: } truebrain@10668: truebrain@10668: /* static */ void AIRoad::SetCurrentRoadType(RoadType road_type) truebrain@10668: { truebrain@10668: if (!IsRoadTypeAvailable(road_type)) return; truebrain@10668: truebrain@10668: AIObject::SetRoadType((::RoadType)road_type); truebrain@10668: } truebrain@10668: truebrain@10668: /* static */ bool AIRoad::HasRoadType(TileIndex tile, RoadType road_type) truebrain@10668: { truebrain@10668: if (!AIMap::IsValidTile(tile)) return false; truebrain@10668: if (!IsRoadTypeAvailable(road_type)) return false; truebrain@10668: return ::GetAnyRoadBits(tile, (::RoadType)road_type, false) != ROAD_NONE; truebrain@10668: } truebrain@10668: truebrain@9737: /* static */ bool AIRoad::AreRoadTilesConnected(TileIndex t1, TileIndex t2) rubidium@9551: { truebrain@9801: if (!::IsValidTile(t1)) return false; truebrain@9801: if (!::IsValidTile(t2)) return false; rubidium@9551: rubidium@9551: /* Tiles not neighbouring */ rubidium@9551: if ((abs((int)::TileX(t1) - (int)::TileX(t2)) + abs((int)::TileY(t1) - (int)::TileY(t2))) != 1) return false; rubidium@9551: truebrain@10668: RoadBits r1 = ::GetAnyRoadBits(t1, AIObject::GetRoadType()); truebrain@10668: RoadBits r2 = ::GetAnyRoadBits(t2, AIObject::GetRoadType()); rubidium@9551: truebrain@10975: uint dir_1 = (::TileX(t1) == ::TileX(t2)) ? (::TileY(t1) < ::TileY(t2) ? 2 : 0) : (::TileX(t1) < ::TileX(t2) ? 1 : 3); truebrain@10975: uint dir_2 = 2 ^ dir_1; rubidium@9551: rubidium@9722: return HasBit(r1, dir_1) && HasBit(r2, dir_2); rubidium@9551: } rubidium@9551: rubidium@10993: /* Helper functions for AIRoad::CanBuildConnectedRoadParts(). */ rubidium@10993: rubidium@10993: /** rubidium@10993: * Check whether the given existing bits the start and end part can be build. rubidium@10993: * As the function assumes the bits being build on a slope that does not rubidium@10993: * allow level foundations all of the existing parts will always be in rubidium@10993: * a straight line. This also needs to hold for the start and end parts, rubidium@10993: * otherwise it is for sure not valid. Finally a check will be done to rubidium@10993: * determine whether the existing road parts match the to-be-build parts. rubidium@10993: * As they can only be placed in one direction, just checking the start rubidium@10993: * part with the first existing part is enough. rubidium@10993: * @param existing The existing road parts. rubidium@10993: * @param start The part that should be build first. rubidium@10993: * @param end The part that will be build second. rubidium@10993: * @return True if and only if the road bits can be build. rubidium@10993: */ rubidium@10993: static bool CheckAutoExpandedRoadBits(const Array *existing, int32 start, int32 end) rubidium@10993: { rubidium@10993: return (start + end == 0) && (existing->size == 0 || existing->array[0] == start || existing->array[0] == end); rubidium@10993: } rubidium@10993: rubidium@10993: /** rubidium@10993: * Lookup function for building road parts when building on slopes is disabled. rubidium@10993: * @param slope The slope of the tile to examine. rubidium@10993: * @param existing The existing road parts. rubidium@10993: * @param start The part that should be build first. rubidium@10993: * @param end The part that will be build second. rubidium@10993: * @return 0 when the build parts do not connect, 1 when they do connect once rubidium@10993: * they are build or 2 when building the first part automatically rubidium@10993: * builds the second part. rubidium@10993: */ rubidium@10993: static int32 LookupWithoutBuildOnSlopes(::Slope slope, const Array *existing, int32 start, int32 end) rubidium@10993: { rubidium@10993: switch (slope) { rubidium@10993: /* Flat slopes can always be build. */ rubidium@10993: case SLOPE_FLAT: rubidium@10993: return 1; rubidium@10993: rubidium@10993: /* Only 4 of the slopes can be build upon. Testing the existing bits is rubidium@10993: * necessary because these bits can be something else when the settings rubidium@10993: * in the game have been changed. rubidium@10993: */ rubidium@10993: case SLOPE_NE: case SLOPE_SW: rubidium@10993: return (CheckAutoExpandedRoadBits(existing, start, end) && (start == 1 || end == 1)) ? (existing->size == 0 ? 2 : 1) : 0; rubidium@10993: case SLOPE_SE: case SLOPE_NW: rubidium@10993: return (CheckAutoExpandedRoadBits(existing, start, end) && (start != 1 && end != 1)) ? (existing->size == 0 ? 2 : 1) : 0; rubidium@10993: rubidium@10993: /* Any other tile cannot be built on. */ rubidium@10993: default: rubidium@10993: return 0; rubidium@10993: } rubidium@10993: } rubidium@10993: rubidium@10993: /** rubidium@10993: * Rotate a neighbour bit a single time clockwise. rubidium@10993: * @param neighbour The neighbour. rubidium@10993: * @return The rotate neighbour data. rubidium@10993: */ rubidium@10993: static int32 RotateNeighbour(int32 neighbour) rubidium@10993: { rubidium@10993: switch (neighbour) { rubidium@10993: case -2: return -1; rubidium@10993: case -1: return 2; rubidium@10993: case 1: return -2; rubidium@10993: case 2: return 1; rubidium@10993: default: NOT_REACHED(); rubidium@10993: } rubidium@10993: } rubidium@10993: rubidium@10993: /** rubidium@10993: * Convert a neighbour to a road bit representation for easy internal use. rubidium@10993: * @param neighbour The neighbour. rubidium@10993: * @return The bits representing the direction. rubidium@10993: */ rubidium@10993: static RoadBits NeighbourToRoadBits(int32 neighbour) rubidium@10993: { rubidium@10993: switch (neighbour) { rubidium@10993: case -2: return ROAD_NW; rubidium@10993: case -1: return ROAD_NE; rubidium@10993: case 2: return ROAD_SE; rubidium@10993: case 1: return ROAD_SW; rubidium@10993: default: NOT_REACHED(); rubidium@10993: } rubidium@10993: } rubidium@10993: rubidium@10993: /** rubidium@10993: * Lookup function for building road parts when building on slopes is enabled. rubidium@10993: * @param slope The slope of the tile to examine. rubidium@10993: * @param existing The existing neighbours. rubidium@10993: * @param start The part that should be build first. rubidium@10993: * @param end The part that will be build second. rubidium@10993: * @return 0 when the build parts do not connect, 1 when they do connect once rubidium@10993: * they are build or 2 when building the first part automatically rubidium@10993: * builds the second part. rubidium@10993: */ rubidium@10993: static int32 LookupWithBuildOnSlopes(::Slope slope, Array *existing, int32 start, int32 end) rubidium@10993: { rubidium@10993: if (::IsSteepSlope(slope)) { rubidium@10993: switch (slope) { rubidium@10993: /* On steep slopes one can only build straight roads that will be rubidium@10993: * automatically expanded to a straight road. Just check that the existing rubidium@10993: * road parts are in the same direction. */ rubidium@10993: case SLOPE_STEEP_S: rubidium@10993: case SLOPE_STEEP_W: rubidium@10993: case SLOPE_STEEP_N: rubidium@10993: case SLOPE_STEEP_E: rubidium@10993: return CheckAutoExpandedRoadBits(existing, start, end) ? (existing->size == 0 ? 2 : 1) : 0; rubidium@10993: rubidium@10993: /* All other slopes are invalid slopes!. */ rubidium@10993: default: rubidium@10993: return -1; rubidium@10993: } rubidium@10993: } rubidium@10993: rubidium@10993: /* The slope is not steep. Furthermore lots of slopes are generally the rubidium@10993: * same but are only rotated. So to reduce the amount of lookup work that rubidium@10993: * needs to be done the data is made uniform. This means rotating the rubidium@10993: * existing parts and updating the slope. */ rubidium@10993: static const ::Slope base_slopes[] = { rubidium@10993: SLOPE_FLAT, SLOPE_W, SLOPE_W, SLOPE_SW, rubidium@10993: SLOPE_W, SLOPE_EW, SLOPE_SW, SLOPE_WSE, rubidium@10993: SLOPE_W, SLOPE_SW, SLOPE_EW, SLOPE_WSE, rubidium@10993: SLOPE_SW, SLOPE_WSE, SLOPE_WSE}; rubidium@10993: static const byte base_rotates[] = {0, 0, 1, 0, 2, 0, 1, 0, 3, 3, 2, 3, 2, 2, 1}; rubidium@10993: rubidium@10993: if (slope >= (::Slope)lengthof(base_slopes)) { rubidium@10993: /* This slope is an invalid slope, so ignore it. */ rubidium@10993: return -1; rubidium@10993: } rubidium@10993: byte base_rotate = base_rotates[slope]; rubidium@10993: slope = base_slopes[slope]; rubidium@10993: rubidium@10993: /* Some slopes don't need rotating, so return early when we know we do rubidium@10993: * not need to rotate. */ rubidium@10993: switch (slope) { rubidium@10993: case SLOPE_FLAT: rubidium@10993: /* Flat slopes can always be build. */ rubidium@10993: return 1; rubidium@10993: rubidium@10993: case SLOPE_EW: rubidium@10993: case SLOPE_WSE: rubidium@10993: /* A slope similar to a SLOPE_EW or SLOPE_WSE will always cause rubidium@10993: * foundations which makes them accessible from all sides. */ rubidium@10993: return 1; rubidium@10993: rubidium@10993: case SLOPE_W: rubidium@10993: case SLOPE_SW: rubidium@10993: /* A slope for which we need perform some calculations. */ rubidium@10993: break; rubidium@10993: rubidium@10993: default: rubidium@10993: /* An invalid slope. */ rubidium@10993: return -1; rubidium@10993: } rubidium@10993: rubidium@10993: /* Now perform the actual rotation. */ rubidium@10993: for (int j = 0; j < base_rotate; j++) { rubidium@10993: for (int i = 0; i < existing->size; i++) { rubidium@10993: existing->array[i] = RotateNeighbour(existing->array[i]); rubidium@10993: } rubidium@10993: start = RotateNeighbour(start); rubidium@10993: end = RotateNeighbour(end); rubidium@10993: } rubidium@10993: rubidium@10993: /* Create roadbits out of the data for easier handling. */ rubidium@10993: RoadBits start_roadbits = NeighbourToRoadBits(start); rubidium@10993: RoadBits new_roadbits = start_roadbits | NeighbourToRoadBits(end); rubidium@10993: RoadBits existing_roadbits = ROAD_NONE; rubidium@10993: for (int i = 0; i < existing->size; i++) { rubidium@10993: existing_roadbits |= NeighbourToRoadBits(existing->array[i]); rubidium@10993: } rubidium@10993: rubidium@10993: switch (slope) { rubidium@10993: case SLOPE_W: rubidium@10993: /* A slope similar to a SLOPE_W. */ rubidium@10993: switch (new_roadbits) { rubidium@10993: case 6: // ROAD_SE | ROAD_SW: rubidium@10993: case 9: // ROAD_NE | ROAD_NW: rubidium@10993: case 12: // ROAD_NE | ROAD_SE: rubidium@10993: /* Cannot build anything with a turn from the low side. */ rubidium@10993: return 0; rubidium@10993: rubidium@10993: case 5: // ROAD_SE | ROAD_NW: rubidium@10993: case 10: // ROAD_NE | ROAD_SW: rubidium@10993: /* A 'sloped' tile is going to be build. */ rubidium@10993: if ((existing_roadbits | new_roadbits) != new_roadbits) { rubidium@10993: /* There is already a foundation on the tile, or at least rubidium@10993: * another slope that is not compatible with the new one. */ rubidium@10993: return 0; rubidium@10993: } rubidium@10993: /* If the start is in the low part, it is automatically rubidium@10993: * building the second part too. */ rubidium@10993: return ((start_roadbits & (ROAD_NE | ROAD_SE)) && !(existing_roadbits & (ROAD_SW | ROAD_NW))) ? 2 : 1; rubidium@10993: rubidium@10993: default: rubidium@10993: /* Roadbits causing a foundation are going to be build. rubidium@10993: * When the existing roadbits are slopes (the lower bits rubidium@10993: * are used), this cannot be done. */ rubidium@10993: if ((existing_roadbits | new_roadbits) == new_roadbits) return 1; rubidium@10993: return (existing_roadbits & (ROAD_NE | ROAD_SE)) ? 0 : 1; rubidium@10993: } rubidium@10993: rubidium@10993: case SLOPE_SW: rubidium@10993: /* A slope similar to a SLOPE_SW. */ rubidium@10993: switch (new_roadbits) { rubidium@10993: case 9: // ROAD_NE | ROAD_NW: rubidium@10993: case 12: // ROAD_NE | ROAD_SE: rubidium@10993: /* Cannot build anything with a turn from the low side. */ rubidium@10993: return 0; rubidium@10993: rubidium@10993: case 10: // ROAD_NE | ROAD_SW: rubidium@10993: /* A 'sloped' tile is going to be build. */ rubidium@10993: if ((existing_roadbits | new_roadbits) != new_roadbits) { rubidium@10993: /* There is already a foundation on the tile, or at least rubidium@10993: * another slope that is not compatible with the new one. */ rubidium@10993: return 0; rubidium@10993: } rubidium@10993: /* If the start is in the low part, it is automatically rubidium@10993: * building the second part too. */ rubidium@10993: return ((start_roadbits & ROAD_NE) && !(existing_roadbits & ROAD_SW)) ? 2 : 1; rubidium@10993: rubidium@10993: default: rubidium@10993: /* Roadbits causing a foundation are going to be build. rubidium@10993: * When the existing roadbits are slopes (the lower bits rubidium@10993: * are used), this cannot be done. */ rubidium@10993: return (existing_roadbits & ROAD_NE) ? 0 : 1; rubidium@10993: } rubidium@10993: rubidium@10993: default: rubidium@10993: NOT_REACHED(); rubidium@10993: } rubidium@10993: } rubidium@10993: rubidium@10993: /** rubidium@10993: * Normalise all input data so we can easily handle it without needing rubidium@10993: * to call the API lots of times or create large if-elseif-elseif-else rubidium@10993: * constructs. rubidium@10993: * In this case it means that a TileXY(0, -1) becomes -2 and TileXY(0, 1) rubidium@10993: * becomes 2. TileXY(-1, 0) and TileXY(1, 0) stay respectively -1 and 1. rubidium@10993: * Any other value means that it is an invalid tile offset. rubidium@10993: * @param tile The tile to normalise. rubidium@10993: * @return True if and only if the tile offset is valid. rubidium@10993: */ rubidium@10993: static bool NormaliseTileOffset(int32 *tile) rubidium@10993: { rubidium@10993: if (*tile == 1 || *tile == -1) return true; rubidium@10993: if (*tile == ::TileDiffXY(0, -1)) { rubidium@10993: *tile = -2; rubidium@10993: return true; rubidium@10993: } rubidium@10993: if (*tile == ::TileDiffXY(0, 1)) { rubidium@10993: *tile = 2; rubidium@10993: return true; rubidium@10993: } rubidium@10993: return false; rubidium@10993: } rubidium@10993: rubidium@10993: /* static */ int32 AIRoad::CanBuildConnectedRoadParts(AITile::Slope slope_, Array *existing, TileIndex start_, TileIndex end_) rubidium@10993: { rubidium@10993: ::Slope slope = (::Slope)slope_; rubidium@10993: int32 start = start_; rubidium@10993: int32 end = end_; rubidium@10993: rubidium@10993: /* The start tile and end tile cannot be the same tile either. */ rubidium@10993: if (start == end) return -1; rubidium@10993: rubidium@10993: for (int i = 0; i < existing->size; i++) { rubidium@10993: if (!NormaliseTileOffset(&existing->array[i])) return -1; rubidium@10993: } rubidium@10993: rubidium@10993: if (!NormaliseTileOffset(&start)) return -1; rubidium@10993: if (!NormaliseTileOffset(&end)) return -1; rubidium@10993: rubidium@10993: /* Without build on slopes the characteristics are vastly different, so use rubidium@10993: * a different helper function (one that is much simpler). */ rubidium@10993: return _settings_game.construction.build_on_slopes ? LookupWithBuildOnSlopes(slope, existing, start, end) : LookupWithoutBuildOnSlopes(slope, existing, start, end); rubidium@10993: } rubidium@10993: rubidium@10993: /* static */ int32 AIRoad::CanBuildConnectedRoadPartsHere(TileIndex tile, TileIndex start, TileIndex end) rubidium@10993: { rubidium@10993: if (!::IsValidTile(tile) || !::IsValidTile(start) || !::IsValidTile(end)) return -1; rubidium@10993: if (::DistanceManhattan(tile, start) != 1 || ::DistanceManhattan(tile, end) != 1) return -1; rubidium@10993: rubidium@10993: static const TileIndex neighbours[] = {::TileDiffXY(-1, 0), ::TileDiffXY(1, 0), ::TileDiffXY(0, -1), ::TileDiffXY(0, 1)}; rubidium@10993: Array *existing = (Array*)alloca(sizeof(Array) + lengthof(neighbours) * sizeof(int32)); rubidium@10993: existing->size = 0; rubidium@10993: rubidium@10993: for (uint i = 0; i < lengthof(neighbours); i++) { rubidium@10993: if (AIRoad::AreRoadTilesConnected(tile, tile + neighbours[i])) existing->array[existing->size++] = neighbours[i]; rubidium@10993: } rubidium@10993: rubidium@10993: return AIRoad::CanBuildConnectedRoadParts(AITile::GetSlope(tile), existing, start - tile, end - tile); rubidium@10993: } rubidium@10993: rubidium@10993: truebrain@9737: /* static */ int32 AIRoad::GetNeighbourRoadCount(TileIndex tile) truelight@9617: { truebrain@9801: if (!::IsValidTile(tile)) return false; truelight@9617: truelight@9617: int32 neighbour = 0; truelight@9617: rubidium@9694: if (::IsTileType(tile + ::TileDiffXY(-1, 0), MP_ROAD) && ::GetRoadTileType(tile + ::TileDiffXY(-1, 0)) != ROAD_TILE_DEPOT) neighbour++; rubidium@9694: if (::IsTileType(tile + ::TileDiffXY( 1, 0), MP_ROAD) && ::GetRoadTileType(tile + ::TileDiffXY( 1, 0)) != ROAD_TILE_DEPOT) neighbour++; rubidium@9694: if (::IsTileType(tile + ::TileDiffXY( 0,-1), MP_ROAD) && ::GetRoadTileType(tile + ::TileDiffXY( 0,-1)) != ROAD_TILE_DEPOT) neighbour++; rubidium@9694: if (::IsTileType(tile + ::TileDiffXY( 0, 1), MP_ROAD) && ::GetRoadTileType(tile + ::TileDiffXY( 0, 1)) != ROAD_TILE_DEPOT) neighbour++; truelight@9617: truelight@9617: return neighbour; truelight@9617: } truelight@9617: truebrain@9737: /* static */ TileIndex AIRoad::GetRoadDepotFrontTile(TileIndex depot) rubidium@9551: { truebrain@9737: if (!IsRoadDepotTile(depot)) return INVALID_TILE; rubidium@9551: rubidium@9551: return depot + ::TileOffsByDiagDir(::GetRoadDepotDirection(depot)); rubidium@9551: } rubidium@9551: truebrain@9737: /* static */ TileIndex AIRoad::GetRoadStationFrontTile(TileIndex station) rubidium@9551: { truebrain@9737: if (!IsRoadStationTile(station)) return INVALID_TILE; rubidium@9551: rubidium@9551: return station + ::TileOffsByDiagDir(::GetRoadStopDir(station)); rubidium@9551: } rubidium@9551: truebrain@9737: /* static */ TileIndex AIRoad::GetDriveThroughBackTile(TileIndex station) rubidium@9551: { truebrain@9737: if (!IsDriveThroughRoadStationTile(station)) return INVALID_TILE; rubidium@9551: rubidium@9551: return station + ::TileOffsByDiagDir(::ReverseDiagDir(::GetRoadStopDir(station))); rubidium@9453: } rubidium@9453: truebrain@9737: /* static */ bool AIRoad::BuildRoad(TileIndex start, TileIndex end) rubidium@9453: { rubidium@10091: EnforcePrecondition(false, start != end); rubidium@10091: EnforcePrecondition(false, ::IsValidTile(start)); rubidium@10091: EnforcePrecondition(false, ::IsValidTile(end)); truebrain@10972: EnforcePrecondition(false, ::TileX(start) == ::TileX(end) || ::TileY(start) == ::TileY(end)); rubidium@9453: truebrain@10972: return AIObject::DoCommand(end, start, (::TileY(start) != ::TileY(end) ? 4 : 0) | (start < end ? 1 : 2) | (AIObject::GetRoadType() << 3), CMD_BUILD_LONG_ROAD); rubidium@9453: } rubidium@9453: truebrain@9737: /* static */ bool AIRoad::BuildRoadFull(TileIndex start, TileIndex end) glx@9659: { rubidium@10091: EnforcePrecondition(false, start != end); rubidium@10091: EnforcePrecondition(false, ::IsValidTile(start)); rubidium@10091: EnforcePrecondition(false, ::IsValidTile(end)); truebrain@10972: EnforcePrecondition(false, ::TileX(start) == ::TileX(end) || ::TileY(start) == ::TileY(end)); glx@9659: truebrain@10972: return AIObject::DoCommand(end, start, (::TileY(start) != ::TileY(end) ? 4 : 0) | (start < end ? 2 : 1) | (AIObject::GetRoadType() << 3), CMD_BUILD_LONG_ROAD); glx@9659: } glx@9659: truebrain@9737: /* static */ bool AIRoad::BuildRoadDepot(TileIndex tile, TileIndex front) rubidium@9453: { rubidium@10091: EnforcePrecondition(false, tile != front); rubidium@10091: EnforcePrecondition(false, ::IsValidTile(tile)); rubidium@10091: EnforcePrecondition(false, ::IsValidTile(front)); truebrain@10972: EnforcePrecondition(false, ::TileX(tile) == ::TileX(front) || ::TileY(tile) == ::TileY(front)); rubidium@9453: truebrain@10972: uint entrance_dir = (::TileX(tile) == ::TileX(front)) ? (::TileY(tile) < ::TileY(front) ? 1 : 3) : (::TileX(tile) < ::TileX(front) ? 2 : 0); rubidium@9453: truebrain@10774: return AIObject::DoCommand(tile, entrance_dir | (AIObject::GetRoadType() << 2), 0, CMD_BUILD_ROAD_DEPOT); rubidium@9453: } rubidium@9453: truebrain@9737: /* static */ bool AIRoad::BuildRoadStation(TileIndex tile, TileIndex front, bool truck, bool drive_through) rubidium@9453: { rubidium@10091: EnforcePrecondition(false, tile != front); rubidium@10091: EnforcePrecondition(false, ::IsValidTile(tile)); rubidium@10091: EnforcePrecondition(false, ::IsValidTile(front)); truebrain@10972: EnforcePrecondition(false, ::TileX(tile) == ::TileX(front) || ::TileY(tile) == ::TileY(front)); rubidium@9453: rubidium@9453: uint entrance_dir; rubidium@9453: if (drive_through) { truebrain@10972: entrance_dir = ::TileY(tile) != ::TileY(front); rubidium@9453: } else { truebrain@10972: entrance_dir = (::TileX(tile) == ::TileX(front)) ? (::TileY(tile) < ::TileY(front) ? 1 : 3) : (::TileX(tile) < ::TileX(front) ? 2 : 0); rubidium@9453: } rubidium@9453: truebrain@10668: return AIObject::DoCommand(tile, entrance_dir, (drive_through ? 2 : 0) | (truck ? 1 : 0) | (::RoadTypeToRoadTypes(AIObject::GetRoadType()) << 2), CMD_BUILD_ROAD_STOP); rubidium@9453: } rubidium@9453: truebrain@9737: /* static */ bool AIRoad::RemoveRoad(TileIndex start, TileIndex end) glx@9659: { rubidium@10091: EnforcePrecondition(false, ::IsValidTile(start)); rubidium@10091: EnforcePrecondition(false, ::IsValidTile(end)); truebrain@10972: EnforcePrecondition(false, ::TileX(start) == ::TileX(end) || ::TileY(start) == ::TileY(end)); glx@9659: truebrain@10972: return AIObject::DoCommand(end, start, (::TileY(start) != ::TileY(end) ? 4 : 0) | (start < end ? 1 : 2) | (AIObject::GetRoadType() << 3), CMD_REMOVE_LONG_ROAD); glx@9659: } glx@9659: truebrain@9737: /* static */ bool AIRoad::RemoveRoadFull(TileIndex start, TileIndex end) truebrain@9737: { rubidium@10091: EnforcePrecondition(false, ::IsValidTile(start)); rubidium@10091: EnforcePrecondition(false, ::IsValidTile(end)); truebrain@10972: EnforcePrecondition(false, ::TileX(start) == ::TileX(end) || ::TileY(start) == ::TileY(end)); truebrain@9737: truebrain@10972: return AIObject::DoCommand(end, start, (::TileY(start) != ::TileY(end) ? 4 : 0) | (start < end ? 2 : 1) | (AIObject::GetRoadType() << 3), CMD_REMOVE_LONG_ROAD); truebrain@9737: } truebrain@9737: truebrain@9737: /* static */ bool AIRoad::RemoveRoadDepot(TileIndex tile) rubidium@9453: { rubidium@10091: EnforcePrecondition(false, ::IsValidTile(tile)); rubidium@10094: EnforcePrecondition(false, IsTileType(tile, MP_ROAD)) rubidium@10094: EnforcePrecondition(false, GetRoadTileType(tile) == ROAD_TILE_DEPOT); rubidium@9453: truebrain@9737: return AIObject::DoCommand(tile, 0, 0, CMD_LANDSCAPE_CLEAR); rubidium@9453: } rubidium@9453: truebrain@9737: /* static */ bool AIRoad::RemoveRoadStation(TileIndex tile) rubidium@9453: { rubidium@10091: EnforcePrecondition(false, ::IsValidTile(tile)); rubidium@10094: EnforcePrecondition(false, IsTileType(tile, MP_STATION)); rubidium@10094: EnforcePrecondition(false, IsRoadStop(tile)); rubidium@9453: truebrain@9737: return AIObject::DoCommand(tile, 0, GetRoadStopType(tile), CMD_REMOVE_ROAD_STOP); rubidium@9453: }