* Build a single piece of rail * @param flags operation to perform * @param tile tile to build on * @param railtype railtype of being built piece (normal, mono, maglev) * @param track track-orientation * @param auto_remove_signals false = error on signal in the way, true = auto remove signals when in the way * @return the cost of this operation or an error */
| 421 | * @return the cost of this operation or an error |
| 422 | */ |
| 423 | CommandCost CmdBuildSingleRail(DoCommandFlags flags, TileIndex tile, RailType railtype, Track track, bool auto_remove_signals) |
| 424 | { |
| 425 | CommandCost cost(EXPENSES_CONSTRUCTION); |
| 426 | |
| 427 | if (!ValParamRailType(railtype) || !ValParamTrackOrientation(track)) return CMD_ERROR; |
| 428 | |
| 429 | Slope tileh = GetTileSlope(tile); |
| 430 | TrackBits trackbit = TrackToTrackBits(track); |
| 431 | |
| 432 | switch (GetTileType(tile)) { |
| 433 | case MP_RAILWAY: { |
| 434 | CommandCost ret = CheckTileOwnership(tile); |
| 435 | if (ret.Failed()) return ret; |
| 436 | |
| 437 | if (!IsPlainRail(tile)) return Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile); // just get appropriate error message |
| 438 | |
| 439 | if (!IsCompatibleRail(GetRailType(tile), railtype)) return CommandCost(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION); |
| 440 | |
| 441 | ret = CheckTrackCombination(tile, trackbit); |
| 442 | if (ret.Succeeded()) ret = EnsureNoTrainOnTrack(tile, track); |
| 443 | if (ret.Failed()) return ret; |
| 444 | |
| 445 | ret = CheckRailSlope(tileh, trackbit, GetTrackBits(tile), tile); |
| 446 | if (ret.Failed()) return ret; |
| 447 | cost.AddCost(ret.GetCost()); |
| 448 | |
| 449 | if (HasSignals(tile) && TracksOverlap(GetTrackBits(tile) | TrackToTrackBits(track))) { |
| 450 | /* If adding the new track causes any overlap, all signals must be removed first */ |
| 451 | if (!auto_remove_signals) return CommandCost(STR_ERROR_MUST_REMOVE_SIGNALS_FIRST); |
| 452 | |
| 453 | for (Track track_it = TRACK_BEGIN; track_it < TRACK_END; track_it++) { |
| 454 | if (HasTrack(tile, track_it) && HasSignalOnTrack(tile, track_it)) { |
| 455 | CommandCost ret_remove_signals = Command<CMD_REMOVE_SINGLE_SIGNAL>::Do(flags, tile, track_it); |
| 456 | if (ret_remove_signals.Failed()) return ret_remove_signals; |
| 457 | cost.AddCost(ret_remove_signals.GetCost()); |
| 458 | } |
| 459 | } |
| 460 | } |
| 461 | |
| 462 | /* If the rail types don't match, try to convert only if engines of |
| 463 | * the new rail type are not powered on the present rail type and engines of |
| 464 | * the present rail type are powered on the new rail type. */ |
| 465 | if (GetRailType(tile) != railtype && !HasPowerOnRail(railtype, GetRailType(tile))) { |
| 466 | if (HasPowerOnRail(GetRailType(tile), railtype)) { |
| 467 | ret = Command<CMD_CONVERT_RAIL>::Do(flags, tile, tile, railtype, false); |
| 468 | if (ret.Failed()) return ret; |
| 469 | cost.AddCost(ret.GetCost()); |
| 470 | } else { |
| 471 | return CMD_ERROR; |
| 472 | } |
| 473 | } |
| 474 | |
| 475 | if (flags.Test(DoCommandFlag::Execute)) { |
| 476 | SetRailGroundType(tile, RailGroundType::Barren); |
| 477 | TrackBits bits = GetTrackBits(tile); |
| 478 | SetTrackBits(tile, bits | trackbit); |
| 479 | /* Subtract old infrastructure count. */ |
| 480 | uint pieces = CountBits(bits); |
nothing calls this directly
no test coverage detected