* Convert existing rail to waypoint. Eg build a waypoint station over * piece of rail * @param flags type of operation * @param start_tile northern most tile where waypoint will be built * @param axis orientation (Axis) * @param width width of waypoint * @param height height of waypoint * @param spec_class custom station class * @param spec_index custom station id * @param station_to_join
| 206 | * @return the cost of this operation or an error |
| 207 | */ |
| 208 | CommandCost CmdBuildRailWaypoint(DoCommandFlags flags, TileIndex start_tile, Axis axis, uint8_t width, uint8_t height, StationClassID spec_class, uint16_t spec_index, StationID station_to_join, bool adjacent) |
| 209 | { |
| 210 | if (!IsValidAxis(axis)) return CMD_ERROR; |
| 211 | /* Check if the given station class is valid */ |
| 212 | if (static_cast<uint>(spec_class) >= StationClass::GetClassCount()) return CMD_ERROR; |
| 213 | const StationClass *cls = StationClass::Get(spec_class); |
| 214 | if (!IsWaypointClass(*cls)) return CMD_ERROR; |
| 215 | if (spec_index >= cls->GetSpecCount()) return CMD_ERROR; |
| 216 | |
| 217 | /* The number of parts to build */ |
| 218 | uint8_t count = axis == AXIS_X ? height : width; |
| 219 | |
| 220 | if ((axis == AXIS_X ? width : height) != 1) return CMD_ERROR; |
| 221 | if (count == 0 || count > _settings_game.station.station_spread) return CMD_ERROR; |
| 222 | |
| 223 | bool reuse = (station_to_join != NEW_STATION); |
| 224 | if (!reuse) station_to_join = StationID::Invalid(); |
| 225 | bool distant_join = (station_to_join != StationID::Invalid()); |
| 226 | |
| 227 | if (distant_join && (!_settings_game.station.distant_join_stations || !Waypoint::IsValidID(station_to_join))) return CMD_ERROR; |
| 228 | |
| 229 | TileArea new_location(start_tile, width, height); |
| 230 | |
| 231 | /* only AddCost for non-existing waypoints */ |
| 232 | CommandCost cost(EXPENSES_CONSTRUCTION); |
| 233 | for (TileIndex cur_tile : new_location) { |
| 234 | if (!IsRailWaypointTile(cur_tile)) cost.AddCost(_price[PR_BUILD_WAYPOINT_RAIL]); |
| 235 | } |
| 236 | |
| 237 | /* Make sure the area below consists of clear tiles. (OR tiles belonging to a certain rail station) */ |
| 238 | StationID est = StationID::Invalid(); |
| 239 | |
| 240 | const StationSpec *spec = StationClass::Get(spec_class)->GetSpec(spec_index); |
| 241 | RailStationTileLayout stl{spec, count, 1}; |
| 242 | |
| 243 | /* Check whether the tiles we're building on are valid rail or not. */ |
| 244 | TileIndexDiff offset = TileOffsByAxis(OtherAxis(axis)); |
| 245 | for (auto [i, it, tile] = std::make_tuple(0, stl.begin(), start_tile); i < count; ++i, ++it, tile += offset) { |
| 246 | CommandCost ret = IsValidTileForWaypoint(tile, axis, &est); |
| 247 | if (ret.Failed()) return ret; |
| 248 | |
| 249 | ret = IsRailStationBridgeAboveOk(tile, spec, StationType::RailWaypoint, *it + axis); |
| 250 | if (ret.Failed()) return ret; |
| 251 | } |
| 252 | |
| 253 | Waypoint *wp = nullptr; |
| 254 | CommandCost ret = FindJoiningWaypoint(est, station_to_join, adjacent, new_location, &wp, false); |
| 255 | if (ret.Failed()) return ret; |
| 256 | |
| 257 | /* Check if there is an already existing, deleted, waypoint close to us that we can reuse. */ |
| 258 | TileIndex center_tile = start_tile + (count / 2) * offset; |
| 259 | if (wp == nullptr && reuse) wp = FindDeletedWaypointCloseTo(center_tile, STR_SV_STNAME_WAYPOINT, _current_company, false); |
| 260 | |
| 261 | if (wp != nullptr) { |
| 262 | /* Reuse an existing waypoint. */ |
| 263 | if (wp->owner != _current_company) return CommandCost(STR_ERROR_TOO_CLOSE_TO_ANOTHER_WAYPOINT); |
| 264 | |
| 265 | /* Check if we want to expand an already existing waypoint. */ |
nothing calls this directly
no test coverage detected