Loading

Paste #pawn8ypdk

  1. /**
  2.  * Build a Bridge
  3.  * @param end_tile end tile
  4.  * @param flags type of operation
  5.  * @param p1 packed start tile coords (~ dx)
  6.  * @param p2 various bitstuffed elements
  7.  * - p2 = (bit  0- 7) - bridge type (hi bh)
  8.  * - p2 = (bit  8-11) - rail type or road types.
  9.  * - p2 = (bit 15-16) - transport type.
  10.  * @param text unused
  11.  * @return the cost of this operation or an error
  12.  */
  13. CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
  14. {
  15.     CompanyID company = _current_company;
  16.  
  17.     RailType railtype = INVALID_RAILTYPE;
  18.     RoadTypes roadtypes = ROADTYPES_NONE;
  19.  
  20.     /* unpack parameters */
  21.     BridgeType bridge_type = GB(p2, 0, 8);
  22.  
  23.     if (!IsValidTile(p1)) return_cmd_error(STR_ERROR_BRIDGE_THROUGH_MAP_BORDER);
  24.  
  25.     TransportType transport_type = Extract<TransportType, 15, 2>(p2);
  26.  
  27.     /* type of bridge */
  28.     switch (transport_type) {
  29.         case TRANSPORT_ROAD:
  30.             roadtypes = Extract<RoadTypes, 8, 2>(p2);
  31.             if (!HasExactlyOneBit(roadtypes) || !HasRoadTypesAvail(company, roadtypes)) return CMD_ERROR;
  32.             break;
  33.  
  34.         case TRANSPORT_RAIL:
  35.             railtype = Extract<RailType, 8, 4>(p2);
  36.             if (!ValParamRailtype(railtype)) return CMD_ERROR;
  37.             break;
  38.  
  39.         case TRANSPORT_WATER:
  40.             break;
  41.  
  42.         default:
  43.             /* Airports don't have bridges. */
  44.             return CMD_ERROR;
  45.     }
  46.     TileIndex tile_start = p1;
  47.     TileIndex tile_end = end_tile;
  48.  
  49.     if (company == OWNER_DEITY) {
  50.         if (transport_type != TRANSPORT_ROAD) return CMD_ERROR;
  51.         const Town *town = CalcClosestTownFromTile(tile_start);
  52.  
  53.         company = OWNER_TOWN;
  54.  
  55.         /* If we are not within a town, we are not owned by the town */
  56.         if (town == NULL || DistanceSquare(tile_start, town->xy) > town->cache.squared_town_zone_radius[HZB_TOWN_EDGE]) {
  57.             company = OWNER_NONE;
  58.         }
  59.     }
  60.  
  61.     if (tile_start == tile_end) {
  62.         return_cmd_error(STR_ERROR_CAN_T_START_AND_END_ON);
  63.     }
  64.  
  65.     Axis direction;
  66.     if (TileX(tile_start) == TileX(tile_end)) {
  67.         direction = AXIS_Y;
  68.     } else if (TileY(tile_start) == TileY(tile_end)) {
  69.         direction = AXIS_X;
  70.     } else {
  71.         return_cmd_error(STR_ERROR_START_AND_END_MUST_BE_IN);
  72.     }
  73.  
  74.     if (tile_end < tile_start) Swap(tile_start, tile_end);
  75.  
  76.     uint bridge_len = GetTunnelBridgeLength(tile_start, tile_end);
  77.     if (transport_type != TRANSPORT_WATER) {
  78.         /* set and test bridge length, availability */
  79.         CommandCost ret = CheckBridgeAvailability(bridge_type, bridge_len, flags);
  80.         if (ret.Failed()) return ret;
  81.     } else {
  82.         if (bridge_len > _settings_game.construction.max_bridge_length) return_cmd_error(STR_ERROR_BRIDGE_TOO_LONG);
  83.     }
  84.  
  85.     int z_start;
  86.     int z_end;
  87.     Slope tileh_start = GetTileSlope(tile_start, &z_start);
  88.     Slope tileh_end = GetTileSlope(tile_end, &z_end);
  89.     bool pbs_reservation = false;
  90.  
  91.     CommandCost terraform_cost_north = CheckBridgeSlopeNorth(direction, &tileh_start, &z_start);
  92.     CommandCost terraform_cost_south = CheckBridgeSlopeSouth(direction, &tileh_end,   &z_end);
  93.  
  94.     /* Aqueducts can't be built of flat land. */
  95.     if (transport_type == TRANSPORT_WATER && (tileh_start == SLOPE_FLAT || tileh_end == SLOPE_FLAT)) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
  96.     if (z_start != z_end) return_cmd_error(STR_ERROR_BRIDGEHEADS_NOT_SAME_HEIGHT);
  97.  
  98.     CommandCost cost(EXPENSES_CONSTRUCTION);
  99.     Owner owner;
  100.     bool is_new_owner;
  101.     if (IsBridgeTile(tile_start) && IsBridgeTile(tile_end) &&
  102.             GetOtherBridgeEnd(tile_start) == tile_end &&
  103.             GetTunnelBridgeTransportType(tile_start) == transport_type) {
  104.         /* Replace a current bridge. */
  105.  
  106.         /* If this is a railway bridge, make sure the railtypes match. */
  107.         if (transport_type == TRANSPORT_RAIL && GetRailType(tile_start) != railtype) {
  108.             return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
  109.         }
  110.  
  111.         /* Do not replace town bridges with lower speed bridges, unless in scenario editor. */
  112.         if (!(flags & DC_QUERY_COST) && IsTileOwner(tile_start, OWNER_TOWN) &&
  113.                 GetBridgeSpec(bridge_type)->speed < GetBridgeSpec(GetBridgeType(tile_start))->speed &&
  114.                 _game_mode != GM_EDITOR) {
  115.             Town *t = ClosestTownFromTile(tile_start, UINT_MAX);
  116.  
  117.             if (t == NULL) {
  118.                 return CMD_ERROR;
  119.             } else {
  120.                 SetDParam(0, t->index);
  121.                 return_cmd_error(STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS);
  122.             }
  123.         }
  124.  
  125.         /* Do not replace the bridge with the same bridge type. */
  126.         if (!(flags & DC_QUERY_COST) && (bridge_type == GetBridgeType(tile_start)) && (transport_type != TRANSPORT_ROAD || (roadtypes & ~GetRoadTypes(tile_start)) == 0)) {
  127.             return_cmd_error(STR_ERROR_ALREADY_BUILT);
  128.         }
  129.  
  130.         /* Do not allow replacing another company's bridges. */
  131.         if (!IsTileOwner(tile_start, company) && !IsTileOwner(tile_start, OWNER_TOWN) && !IsTileOwner(tile_start, OWNER_NONE)) {
  132.             return_cmd_error(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
  133.         }
  134.  
  135.         cost.AddCost((bridge_len + 1) * _price[PR_CLEAR_BRIDGE]); // The cost of clearing the current bridge.
  136.         owner = GetTileOwner(tile_start);
  137.  
  138.         /* If bridge belonged to bankrupt company, it has a new owner now */
  139.         is_new_owner = (owner == OWNER_NONE);
  140.         if (is_new_owner) owner = company;
  141.  
  142.         switch (transport_type) {
  143.             case TRANSPORT_RAIL:
  144.                 /* Keep the reservation, the path stays valid. */
  145.                 pbs_reservation = HasTunnelBridgeReservation(tile_start);
  146.                 break;
  147.  
  148.             case TRANSPORT_ROAD:
  149.                 /* Do not remove road types when upgrading a bridge */
  150.                 roadtypes |= GetRoadTypes(tile_start);
  151.                 break;
  152.  
  153.             default: break;
  154.         }
  155.     } else {
  156.         /* Build a new bridge. */
  157.  
  158.         bool allow_on_slopes = (_settings_game.construction.build_on_slopes && transport_type != TRANSPORT_WATER);
  159.  
  160.         /* Try and clear the start landscape */
  161.         CommandCost ret = DoCommand(tile_start, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
  162.         if (ret.Failed()) return ret;
  163.         cost = ret;
  164.  
  165.         if (transport_type != TRANSPORT_WATER) {
  166.             if (terraform_cost_north.Failed() || (terraform_cost_north.GetCost() != 0 && !allow_on_slopes)) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
  167.             cost.AddCost(terraform_cost_north);
  168.         } else {
  169.             Slope tileh_north_aqueduct = GetTileSlope(tile_start);
  170.             if (tileh_north_aqueduct != ComplementSlope(tileh_end)) {
  171.                 if (!IsInclinedSlope(tileh_north_aqueduct) && !IsInclinedSlope(GetTileSlope(tile_end))) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
  172.                 if (IsSteepSlope(tileh_north_aqueduct)) {
  173.                     tileh_north_aqueduct = SlopeWithOneCornerRaised(OppositeCorner(GetHighestSlopeCorner((tileh_north_aqueduct ^ (SLOPE_ELEVATED | SLOPE_STEEP)) ^ tileh_end)));
  174.                 } else {
  175.                     tileh_north_aqueduct = ComplementSlope(tileh_end) ^ tileh_north_aqueduct;
  176.                 }
  177.  
  178.                 /* Mark the tile as already cleared for the terraform command.
  179.                 * Do this for all tiles (like trees), not only objects. */
  180.                 ClearedObjectArea *coa = FindClearedObject(tile_start);
  181.                 if (coa == NULL) {
  182.                     coa = _cleared_object_areas.Append();
  183.                     coa->first_tile = tile_start;
  184.                     coa->area = TileArea(tile_start, 1, 1);
  185.                 }
  186.  
  187.                 /* Hide the tile from the terraforming command */
  188.                 TileIndex old_first_tile = coa->first_tile;
  189.                 coa->first_tile = INVALID_TILE;
  190.                 ret = DoCommand(tile_start, tileh_north_aqueduct, 1, flags, CMD_TERRAFORM_LAND);
  191.                 coa->first_tile = old_first_tile;
  192.                 if (ret.Failed()) return_cmd_error(STR_ERROR_UNABLE_TO_SMOOTH_LAND_AQUEDUCT);
  193.                 cost.AddCost(ret);
  194.             }
  195.         }
  196.  
  197.         /* Try and clear the end landscape */
  198.         ret = DoCommand(tile_end, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
  199.         if (ret.Failed()) return ret;
  200.         cost.AddCost(ret);
  201.  
  202.         /* false - end tile slope check */
  203.         if (transport_type != TRANSPORT_WATER) {
  204.             if (terraform_cost_south.Failed() || (terraform_cost_south.GetCost() != 0 && !allow_on_slopes)) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
  205.             cost.AddCost(terraform_cost_south);
  206.         } else {
  207.             Slope tileh_south_aqueduct = GetTileSlope(tile_end);
  208.             if (tileh_south_aqueduct != ComplementSlope(tileh_start)) {
  209.                 if (!IsInclinedSlope(tileh_south_aqueduct) && !IsInclinedSlope(GetTileSlope(tile_start))) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
  210.                 if (IsSteepSlope(tileh_south_aqueduct)) {
  211.                     tileh_south_aqueduct = SlopeWithOneCornerRaised(OppositeCorner(GetHighestSlopeCorner((tileh_south_aqueduct ^ (SLOPE_ELEVATED | SLOPE_STEEP)) ^ tileh_start)));
  212.                 } else {
  213.                     tileh_south_aqueduct = ComplementSlope(tileh_start) ^ tileh_south_aqueduct;
  214.                 }
  215.  
  216.                 /* Mark the tile as already cleared for the terraform command.
  217.                 * Do this for all tiles (like trees), not only objects. */
  218.                 ClearedObjectArea *coa = FindClearedObject(tile_end);
  219.                 if (coa == NULL) {
  220.                     coa = _cleared_object_areas.Append();
  221.                     coa->first_tile = tile_end;
  222.                     coa->area = TileArea(tile_end, 1, 1);
  223.                 }
  224.  
  225.                 /* Hide the tile from the terraforming command */
  226.                 TileIndex old_first_tile = coa->first_tile;
  227.                 coa->first_tile = INVALID_TILE;
  228.                 ret = DoCommand(tile_end, tileh_south_aqueduct, 1, flags, CMD_TERRAFORM_LAND);
  229.                 coa->first_tile = old_first_tile;
  230.                 if (ret.Failed()) return_cmd_error(STR_ERROR_UNABLE_TO_SMOOTH_LAND_AQUEDUCT);
  231.                 cost.AddCost(ret);
  232.             }
  233.         }
  234.  
  235.         const TileIndex heads[] = {tile_start, tile_end};
  236.         for (int i = 0; i < 2; i++) {
  237.             if (IsBridgeAbove(heads[i])) {
  238.                 TileIndex north_head = GetNorthernBridgeEnd(heads[i]);
  239.  
  240.                 if (direction == GetBridgeAxis(heads[i])) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
  241.  
  242.                 if (z_start + 1 == GetBridgeHeight(north_head)) {
  243.                     return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
  244.                 }
  245.             }
  246.         }
  247.  
  248.         TileIndexDiff delta = (direction == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
  249.         for (TileIndex tile = tile_start + delta; tile != tile_end; tile += delta) {
  250.             if (GetTileMaxZ(tile) > z_start) return_cmd_error(STR_ERROR_BRIDGE_TOO_LOW_FOR_TERRAIN);
  251.  
  252.             if (z_start >= (GetTileZ(tile) + _settings_game.construction.max_bridge_height)) {
  253.                 /*
  254.                  * Disallow too high bridges.
  255.                  * Properly rendering a map where very high bridges (might) exist is expensive.
  256.                  * See http://www.tt-forums.net/viewtopic.php?f=33&t=40844&start=980#p1131762
  257.                  * for a detailed discussion. z_start here is one heightlevel below the bridge level.
  258.                  */
  259.                 return_cmd_error(STR_ERROR_BRIDGE_TOO_HIGH_FOR_TERRAIN);
  260.             }
  261.  
  262.             if (IsBridgeAbove(tile)) {
  263.                 /* Disallow crossing bridges for the time being */
  264.                 return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
  265.             }
  266.  
  267.             switch (GetTileType(tile)) {
  268.                 case MP_WATER:
  269.                     if (!IsWater(tile) && !IsCoast(tile)) goto not_valid_below;
  270.                     break;
  271.  
  272.                 case MP_RAILWAY:
  273.                     if (!IsPlainRail(tile)) goto not_valid_below;
  274.                     break;
  275.  
  276.                 case MP_ROAD:
  277.                     if (IsRoadDepot(tile)) goto not_valid_below;
  278.                     break;
  279.  
  280.                 case MP_TUNNELBRIDGE:
  281.                     if (IsTunnel(tile)) break;
  282.                     if (direction == DiagDirToAxis(GetTunnelBridgeDirection(tile))) goto not_valid_below;
  283.                     if (z_start < GetBridgeHeight(tile)) goto not_valid_below;
  284.                     break;
  285.  
  286.                 case MP_OBJECT: {
  287.                     const ObjectSpec *spec = ObjectSpec::GetByTile(tile);
  288.                     if ((spec->flags & OBJECT_FLAG_ALLOW_UNDER_BRIDGE) == 0) goto not_valid_below;
  289.                     if (GetTileMaxZ(tile) + spec->height > z_start) goto not_valid_below;
  290.                     break;
  291.                 }
  292.  
  293.                 case MP_CLEAR:
  294.                     break;
  295.  
  296.                 default:
  297.     not_valid_below:;
  298.                     /* try and clear the middle landscape */
  299.                     ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
  300.                     if (ret.Failed()) return ret;
  301.                     cost.AddCost(ret);
  302.                     break;
  303.             }
  304.  
  305.             if (flags & DC_EXEC) {
  306.                 /* We do this here because when replacing a bridge with another
  307.                  * type calling SetBridgeMiddle isn't needed. After all, the
  308.                  * tile already has the has_bridge_above bits set. */
  309.                 SetBridgeMiddle(tile, direction);
  310.             }
  311.         }
  312.  
  313.         owner = company;
  314.         is_new_owner = true;
  315.     }
  316.  
  317.     /* do the drill? */
  318.     if (flags & DC_EXEC) {
  319.         DiagDirection dir = AxisToDiagDir(direction);
  320.  
  321.         Company *c = Company::GetIfValid(company);
  322.         switch (transport_type) {
  323.             case TRANSPORT_RAIL:
  324.                 /* Add to company infrastructure count if required. */
  325.                 if (is_new_owner && c != NULL) c->infrastructure.rail[railtype] += (bridge_len + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR;
  326.                 MakeRailBridgeRamp(tile_start, owner, bridge_type, dir,                 railtype);
  327.                 MakeRailBridgeRamp(tile_end,   owner, bridge_type, ReverseDiagDir(dir), railtype);
  328.                 SetTunnelBridgeReservation(tile_start, pbs_reservation);
  329.                 SetTunnelBridgeReservation(tile_end,   pbs_reservation);
  330.                 break;
  331.  
  332.             case TRANSPORT_ROAD: {
  333.                 RoadTypes prev_roadtypes = IsBridgeTile(tile_start) ? GetRoadTypes(tile_start) : ROADTYPES_NONE;
  334.                 if (is_new_owner) {
  335.                     /* Also give unowned present roadtypes to new owner */
  336.                     if (HasBit(prev_roadtypes, ROADTYPE_ROAD) && GetRoadOwner(tile_start, ROADTYPE_ROAD) == OWNER_NONE) ClrBit(prev_roadtypes, ROADTYPE_ROAD);
  337.                     if (HasBit(prev_roadtypes, ROADTYPE_TRAM) && GetRoadOwner(tile_start, ROADTYPE_TRAM) == OWNER_NONE) ClrBit(prev_roadtypes, ROADTYPE_TRAM);
  338.                 }
  339.                 if (c != NULL) {
  340.                     /* Add all new road types to the company infrastructure counter. */
  341.                     RoadType new_rt;
  342.                     FOR_EACH_SET_ROADTYPE(new_rt, roadtypes ^ prev_roadtypes) {
  343.                         /* A full diagonal road tile has two road bits. */
  344.                         c->infrastructure.road[new_rt] += (bridge_len + 2) * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR;
  345.                     }
  346.                 }
  347.                 Owner owner_road = HasBit(prev_roadtypes, ROADTYPE_ROAD) ? GetRoadOwner(tile_start, ROADTYPE_ROAD) : company;
  348.                 Owner owner_tram = HasBit(prev_roadtypes, ROADTYPE_TRAM) ? GetRoadOwner(tile_start, ROADTYPE_TRAM) : company;
  349.                 MakeRoadBridgeRamp(tile_start, owner, owner_road, owner_tram, bridge_type, dir,                 roadtypes);
  350.                 MakeRoadBridgeRamp(tile_end,   owner, owner_road, owner_tram, bridge_type, ReverseDiagDir(dir), roadtypes);
  351.                 break;
  352.             }
  353.  
  354.             case TRANSPORT_WATER:
  355.                 if (is_new_owner && c != NULL) c->infrastructure.water += (bridge_len + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR;
  356.                 MakeAqueductBridgeRamp(tile_start, owner, dir);
  357.                 MakeAqueductBridgeRamp(tile_end,   owner, ReverseDiagDir(dir));
  358.                 break;
  359.  
  360.             default:
  361.                 NOT_REACHED();
  362.         }
  363.  
  364.         /* Mark all tiles dirty */
  365.         MarkBridgeDirty(tile_start, tile_end, AxisToDiagDir(direction), z_start);
  366.         DirtyCompanyInfrastructureWindows(company);
  367.     }
  368.  
  369.     if ((flags & DC_EXEC) && transport_type == TRANSPORT_RAIL) {
  370.         Track track = AxisToTrack(direction);
  371.         AddSideToSignalBuffer(tile_start, INVALID_DIAGDIR, company);
  372.         YapfNotifyTrackLayoutChange(tile_start, track);
  373.     }
  374.  
  375.     /* for human player that builds the bridge he gets a selection to choose from bridges (DC_QUERY_COST)
  376.      * It's unnecessary to execute this command every time for every bridge. So it is done only
  377.      * and cost is computed in "bridge_gui.c". For AI, Towns this has to be of course calculated
  378.      */
  379.     Company *c = Company::GetIfValid(company);
  380.     if (!(flags & DC_QUERY_COST) || (c != NULL && c->is_ai)) {
  381.         bridge_len += 2; // begin and end tiles/ramps
  382.  
  383.         switch (transport_type) {
  384.             case TRANSPORT_ROAD: cost.AddCost(bridge_len * _price[PR_BUILD_ROAD] * 2 * CountBits(roadtypes)); break;
  385.             case TRANSPORT_RAIL: cost.AddCost(bridge_len * RailBuildCost(railtype)); break;
  386.             default: break;
  387.         }
  388.  
  389.         if (c != NULL) bridge_len = CalcBridgeLenCostFactor(bridge_len);
  390.  
  391.         if (transport_type != TRANSPORT_WATER) {
  392.             cost.AddCost((int64)bridge_len * _price[PR_BUILD_BRIDGE] * GetBridgeSpec(bridge_type)->price >> 8);
  393.         } else {
  394.             /* Aqueducts use a separate base cost. */
  395.             cost.AddCost((int64)bridge_len * _price[PR_BUILD_AQUEDUCT]);
  396.         }
  397.  
  398.     }
  399.  
  400.     return cost;
  401. }

Comments