* Build a long piece of road. * @param flags operation to perform * @param end_tile end tile of drag * @param start_tile start tile of drag * @param rt road type * @param axis direction * @param drd set road direction * @param start_half start tile starts in the 2nd half of tile (p2 & 1). Only used if \c is_ai is set or if we are building a single tile * @param end_half end tile starts in
| 964 | * @return the cost of this operation or an error |
| 965 | */ |
| 966 | CommandCost CmdBuildLongRoad(DoCommandFlags flags, TileIndex end_tile, TileIndex start_tile, RoadType rt, Axis axis, DisallowedRoadDirections drd, bool start_half, bool end_half, bool is_ai) |
| 967 | { |
| 968 | if (start_tile >= Map::Size()) return CMD_ERROR; |
| 969 | |
| 970 | if (!ValParamRoadType(rt) || !IsValidAxis(axis) || !IsValidDisallowedRoadDirections(drd)) return CMD_ERROR; |
| 971 | |
| 972 | /* Only drag in X or Y direction dictated by the direction variable */ |
| 973 | if (axis == AXIS_X && TileY(start_tile) != TileY(end_tile)) return CMD_ERROR; // x-axis |
| 974 | if (axis == AXIS_Y && TileX(start_tile) != TileX(end_tile)) return CMD_ERROR; // y-axis |
| 975 | |
| 976 | DiagDirection dir = AxisToDiagDir(axis); |
| 977 | |
| 978 | /* Swap direction, also the half-tile drag vars. */ |
| 979 | if (start_tile > end_tile || (start_tile == end_tile && start_half)) { |
| 980 | dir = ReverseDiagDir(dir); |
| 981 | start_half = !start_half; |
| 982 | end_half = !end_half; |
| 983 | if (drd == DRD_NORTHBOUND || drd == DRD_SOUTHBOUND) drd ^= DRD_BOTH; |
| 984 | } |
| 985 | |
| 986 | /* On the X-axis, we have to swap the initial bits, so they |
| 987 | * will be interpreted correctly in the GTTS. Furthermore |
| 988 | * when you just 'click' on one tile to build them. */ |
| 989 | if ((drd == DRD_NORTHBOUND || drd == DRD_SOUTHBOUND) && (axis == AXIS_Y) == (start_tile == end_tile && start_half == end_half)) drd ^= DRD_BOTH; |
| 990 | |
| 991 | CommandCost cost(EXPENSES_CONSTRUCTION); |
| 992 | CommandCost last_error = CMD_ERROR; |
| 993 | TileIndex tile = start_tile; |
| 994 | bool had_bridge = false; |
| 995 | bool had_tunnel = false; |
| 996 | bool had_success = false; |
| 997 | |
| 998 | /* Start tile is the first tile clicked by the user. */ |
| 999 | for (;;) { |
| 1000 | RoadBits bits = AxisToRoadBits(axis); |
| 1001 | |
| 1002 | /* Determine which road parts should be built. */ |
| 1003 | if (!is_ai && start_tile != end_tile) { |
| 1004 | /* Only build the first and last roadbit if they can connect to something. */ |
| 1005 | if (tile == end_tile && !CanConnectToRoad(tile, rt, dir)) { |
| 1006 | bits = DiagDirToRoadBits(ReverseDiagDir(dir)); |
| 1007 | } else if (tile == start_tile && !CanConnectToRoad(tile, rt, ReverseDiagDir(dir))) { |
| 1008 | bits = DiagDirToRoadBits(dir); |
| 1009 | } |
| 1010 | } else { |
| 1011 | /* Road parts only have to be built at the start tile or at the end tile. */ |
| 1012 | if (tile == end_tile && !end_half) bits &= DiagDirToRoadBits(ReverseDiagDir(dir)); |
| 1013 | if (tile == start_tile && start_half) bits &= DiagDirToRoadBits(dir); |
| 1014 | } |
| 1015 | |
| 1016 | CommandCost ret = Command<CMD_BUILD_ROAD>::Do(flags, tile, bits, rt, drd, TownID::Invalid()); |
| 1017 | if (!is_ai && ret.GetErrorMessage() == STR_ERROR_ALREADY_BUILT) had_success = true; |
| 1018 | if (ret.Failed()) { |
| 1019 | last_error = std::move(ret); |
| 1020 | if (last_error.GetErrorMessage() != STR_ERROR_ALREADY_BUILT) { |
| 1021 | if (is_ai) return last_error; |
| 1022 | if (had_success) break; // Keep going if we haven't constructed any road yet, skipping the start of the drag |
| 1023 | } |
nothing calls this directly
no test coverage detected