* Build a piece of road. * @param flags operation to perform * @param tile tile where to build road * @param pieces road pieces to build (RoadBits) * @param rt road type * @param toggle_drd disallowed directions to toggle * @param town_id the town that is building the road (TownID::Invalid() if not applicable) * @return the cost of this operation or an error */
| 597 | * @return the cost of this operation or an error |
| 598 | */ |
| 599 | CommandCost CmdBuildRoad(DoCommandFlags flags, TileIndex tile, RoadBits pieces, RoadType rt, DisallowedRoadDirections toggle_drd, TownID town_id) |
| 600 | { |
| 601 | CompanyID company = _current_company; |
| 602 | CommandCost cost(EXPENSES_CONSTRUCTION); |
| 603 | |
| 604 | RoadBits existing = ROAD_NONE; |
| 605 | RoadBits other_bits = ROAD_NONE; |
| 606 | |
| 607 | /* Road pieces are max 4 bitset values (NE, NW, SE, SW) and town can only be non-zero |
| 608 | * if a non-company is building the road */ |
| 609 | if ((Company::IsValidID(company) && town_id != TownID::Invalid()) || (company == OWNER_TOWN && !Town::IsValidID(town_id)) || (company == OWNER_DEITY && town_id != TownID::Invalid())) return CMD_ERROR; |
| 610 | if (company != OWNER_TOWN) { |
| 611 | const Town *town = CalcClosestTownFromTile(tile); |
| 612 | town_id = (town != nullptr) ? town->index : TownID::Invalid(); |
| 613 | |
| 614 | if (company == OWNER_DEITY) { |
| 615 | company = OWNER_TOWN; |
| 616 | |
| 617 | /* If we are not within a town, we are not owned by the town */ |
| 618 | if (town == nullptr || DistanceSquare(tile, town->xy) > town->cache.squared_town_zone_radius[to_underlying(HouseZone::TownEdge)]) { |
| 619 | company = OWNER_NONE; |
| 620 | } |
| 621 | } |
| 622 | } |
| 623 | |
| 624 | /* do not allow building 'zero' road bits, code wouldn't handle it */ |
| 625 | if (pieces == ROAD_NONE || !IsValidRoadBits(pieces) || !IsValidDisallowedRoadDirections(toggle_drd)) return CMD_ERROR; |
| 626 | if (!ValParamRoadType(rt)) return CMD_ERROR; |
| 627 | |
| 628 | Slope tileh = GetTileSlope(tile); |
| 629 | RoadTramType rtt = GetRoadTramType(rt); |
| 630 | |
| 631 | bool need_to_clear = false; |
| 632 | switch (GetTileType(tile)) { |
| 633 | case MP_ROAD: |
| 634 | switch (GetRoadTileType(tile)) { |
| 635 | case RoadTileType::Normal: { |
| 636 | if (HasRoadWorks(tile)) return CommandCost(STR_ERROR_ROAD_WORKS_IN_PROGRESS); |
| 637 | |
| 638 | other_bits = GetRoadBits(tile, OtherRoadTramType(rtt)); |
| 639 | if (!HasTileRoadType(tile, rtt)) break; |
| 640 | |
| 641 | existing = GetRoadBits(tile, rtt); |
| 642 | bool crossing = !IsStraightRoad(existing | pieces); |
| 643 | if (rtt == RTT_ROAD && (GetDisallowedRoadDirections(tile) != DRD_NONE || toggle_drd != DRD_NONE) && crossing) { |
| 644 | /* Junctions cannot be one-way */ |
| 645 | return CommandCost(STR_ERROR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION); |
| 646 | } |
| 647 | if ((existing & pieces) == pieces) { |
| 648 | /* We only want to set the (dis)allowed road directions */ |
| 649 | if (toggle_drd != DRD_NONE && rtt == RTT_ROAD) { |
| 650 | Owner owner = GetRoadOwner(tile, rtt); |
| 651 | if (owner != OWNER_NONE) { |
| 652 | CommandCost ret = CheckOwnership(owner, tile); |
| 653 | if (ret.Failed()) return ret; |
| 654 | } |
| 655 | |
| 656 | DisallowedRoadDirections dis_existing = GetDisallowedRoadDirections(tile); |
nothing calls this directly
no test coverage detected