Rearrange conditionals in FreeTrainTrackReservation
[openttd/fttd.git] / src / tunnelbridge_cmd.cpp
blobc40a403253a6ef79abd7009432fdbb3070a4b71c
1 /* $Id$ */
3 /*
4 * This file is part of OpenTTD.
5 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8 */
10 /**
11 * @file tunnelbridge_cmd.cpp
12 * This file deals with tunnels and bridges (non-gui stuff)
13 * @todo separate this file into two
16 #include "stdafx.h"
17 #include "newgrf_object.h"
18 #include "viewport_func.h"
19 #include "cmd_helper.h"
20 #include "command_func.h"
21 #include "town.h"
22 #include "train.h"
23 #include "pathfinder/yapf/yapf.h"
24 #include "autoslope.h"
25 #include "map/tunnelbridge.h"
26 #include "map/water.h"
27 #include "map/road.h"
28 #include "strings_func.h"
29 #include "tunnelbridge.h"
30 #include "bridge.h"
31 #include "signal_func.h"
32 #include "cheat_type.h"
33 #include "company_base.h"
34 #include "object_base.h"
35 #include "company_gui.h"
37 #include "table/strings.h"
39 TileIndex _build_tunnel_endtile; ///< The end of a tunnel; as hidden return from the tunnel build command for GUI purposes.
42 extern bool IsValidRoadBridgeBits(Slope tileh, DiagDirection dir, RoadBits bits);
44 /**
45 * Build a road bridge
46 * @param tile_start Start tile
47 * @param tile_end End tile
48 * @param bridge_type Bridge type
49 * @param rts Road types
50 * @param town the town that is building the road (if applicable)
51 * @param flags type of operation
52 * @return the cost of this operation or an error
54 static CommandCost BuildRoadBridge(TileIndex tile_start, TileIndex tile_end, BridgeType bridge_type, RoadTypes rts, TownID town, DoCommandFlag flags)
56 CompanyID company = _current_company;
58 if (!HasExactlyOneBit(rts) || !HasRoadTypesAvail(_current_company, rts)) return CMD_ERROR;
60 if (company == OWNER_DEITY) {
61 const Town *t = CalcClosestTownFromTile(tile_start);
63 /* If we are not within a town, we are not owned by the town */
64 if (t == NULL || DistanceSquare(tile_start, t->xy) > t->cache.squared_town_zone_radius[HZB_TOWN_EDGE]) {
65 company = OWNER_NONE;
66 } else {
67 company = OWNER_TOWN;
68 town = t->index;
70 } else if (company == OWNER_TOWN) {
71 if (!Town::IsValidID(town)) return CMD_ERROR;
72 } else {
73 town = INVALID_TOWN;
76 Axis direction;
77 CommandCost ret = CheckBridgeTiles(tile_start, tile_end, &direction);
78 if (ret.Failed()) return ret;
80 if (tile_end < tile_start) Swap(tile_start, tile_end);
82 /* set and test bridge length, availability */
83 uint bridge_len = GetTunnelBridgeLength(tile_start, tile_end);
84 ret = CheckBridgeAvailability(bridge_type, bridge_len, flags);
85 if (ret.Failed()) return ret;
87 CommandCost cost(EXPENSES_CONSTRUCTION);
89 if (IsRoadBridgeTile(tile_start) && IsRoadBridgeTile(tile_end) &&
90 GetOtherBridgeEnd(tile_start) == tile_end) {
91 /* Replace a current bridge. */
93 /* Special owner check. */
94 Owner owner_road = HasTileRoadType(tile_start, ROADTYPE_ROAD) ? GetRoadOwner(tile_start, ROADTYPE_ROAD) : INVALID_OWNER;
95 Owner owner_tram = HasTileRoadType(tile_start, ROADTYPE_TRAM) ? GetRoadOwner(tile_start, ROADTYPE_TRAM) : INVALID_OWNER;
97 /* You must own one of the roadtypes, or one of the roadtypes must be unowned, or a town must own the road. */
98 if (owner_road != company && owner_road != OWNER_NONE && owner_road != OWNER_TOWN &&
99 owner_tram != company && owner_tram != OWNER_NONE) {
100 return_cmd_error(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
103 /* You must own all of the roadtypes if downgrading. */
104 if (!(flags & DC_QUERY_COST) &&
105 GetBridgeSpec(bridge_type)->speed < GetBridgeSpec(GetRoadBridgeType(tile_start))->speed &&
106 _game_mode != GM_EDITOR) {
107 if (owner_road == OWNER_TOWN) {
108 Town *t = ClosestTownFromTile(tile_start);
110 if (t == NULL) return CMD_ERROR;
112 SetDParam(0, t->index);
113 return_cmd_error(STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS);
115 if (owner_road != company && owner_road != OWNER_NONE && owner_road != INVALID_OWNER) {
116 return_cmd_error(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
118 if (owner_tram != company && owner_tram != OWNER_NONE && owner_tram != INVALID_OWNER) {
119 return_cmd_error(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
123 /* Do not remove road types when upgrading a bridge */
124 rts |= GetRoadTypes(tile_start);
126 /* Do not replace the bridge with the same bridge type. */
127 if (!(flags & DC_QUERY_COST) && (bridge_type == GetRoadBridgeType(tile_start)) && ((rts & ~GetRoadTypes(tile_start)) == 0)) {
128 return_cmd_error(STR_ERROR_ALREADY_BUILT);
131 cost.AddCost((bridge_len + 1) * _price[PR_CLEAR_BRIDGE]); // The cost of clearing the current bridge.
133 /* do the drill? */
134 if (flags & DC_EXEC) {
135 RoadTypes prev_roadtypes = GetRoadTypes(tile_start);
136 /* Also give unowned present roadtypes to new owner */
137 if (HasBit(prev_roadtypes, ROADTYPE_ROAD) && GetRoadOwner(tile_start, ROADTYPE_ROAD) == OWNER_NONE) ClrBit(prev_roadtypes, ROADTYPE_ROAD);
138 if (HasBit(prev_roadtypes, ROADTYPE_TRAM) && GetRoadOwner(tile_start, ROADTYPE_TRAM) == OWNER_NONE) ClrBit(prev_roadtypes, ROADTYPE_TRAM);
139 Company *c = Company::GetIfValid(company);
140 if (c != NULL) {
141 /* Add all new road types to the company infrastructure counter. */
142 RoadType new_rt;
143 FOR_EACH_SET_ROADTYPE(new_rt, rts ^ prev_roadtypes) {
144 /* A full diagonal road tile has two road bits. */
145 c->infrastructure.road[new_rt] += (bridge_len + 2) * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR;
148 DirtyCompanyInfrastructureWindows(company);
150 SetRoadBridgeType(tile_start, bridge_type);
151 SetRoadTypes(tile_start, rts);
152 SetRoadBridgeType(tile_end, bridge_type);
153 SetRoadTypes(tile_end, rts);
155 for (RoadType rt = ROADTYPE_BEGIN; rt < ROADTYPE_END; rt++) {
156 if (!HasBit(prev_roadtypes, rt)) {
157 SetRoadOwner(tile_start, rt, company);
158 SetRoadOwner(tile_end, rt, company);
162 MarkBridgeTilesDirty(tile_start, tile_end, AxisToDiagDir(direction));
164 } else {
165 DiagDirection dir = AxisToDiagDir(direction);
167 bool clear_start = !IsNormalRoadTile(tile_start) ||
168 GetDisallowedRoadDirections(tile_start) != DRD_NONE ||
169 HasRoadWorks(tile_start) ||
170 !IsValidRoadBridgeBits(GetTileSlope(tile_start), dir, GetAllRoadBits(tile_start));
172 if (!clear_start) {
173 RoadType rt;
174 FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(tile_start) & rts) {
175 if (GetRoadOwner(tile_start, rt) != company) clear_start = true;
179 bool clear_end = !IsNormalRoadTile(tile_end) ||
180 GetDisallowedRoadDirections(tile_end) != DRD_NONE ||
181 HasRoadWorks(tile_end) ||
182 !IsValidRoadBridgeBits(GetTileSlope(tile_end), ReverseDiagDir(dir), GetAllRoadBits(tile_end));
184 if (!clear_end) {
185 RoadType rt;
186 FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(tile_end) & rts) {
187 if (GetRoadOwner(tile_end, rt) != company) clear_end = true;
191 /* Build a new bridge. */
192 CommandCost ret = CheckBridgeBuildable(tile_start, tile_end, flags, clear_start, clear_end);
193 if (ret.Failed()) return ret;
194 cost.AddCost(ret);
196 /* do the drill? */
197 if (flags & DC_EXEC) {
198 Company *c = Company::GetIfValid(company);
199 uint num_pieces = 2 * bridge_len;
201 if (clear_start) {
202 MakeRoadBridgeRamp(tile_start, company, company, bridge_type, dir, rts, town != INVALID_TOWN ? town : CalcClosestTownIDFromTile(tile_start));
203 num_pieces += 2;
204 } else {
205 MakeRoadBridgeFromRoad(tile_start, bridge_type, dir);
206 SetRoadTypes(tile_start, GetRoadTypes(tile_start) | rts);
208 RoadBits bits = DiagDirToRoadBits(dir);
209 RoadType new_rt;
210 FOR_EACH_SET_ROADTYPE(new_rt, rts) {
211 RoadBits pieces = GetRoadBits(tile_start, new_rt);
212 uint n = CountBits(pieces);
213 if (c != NULL) c->infrastructure.road[new_rt] += (n + 1) * TUNNELBRIDGE_TRACKBIT_FACTOR - n;
214 SetRoadBits(tile_start, pieces | bits, new_rt);
218 if (clear_end) {
219 MakeRoadBridgeRamp(tile_end, company, company, bridge_type, ReverseDiagDir(dir), rts, town != INVALID_TOWN ? town : CalcClosestTownIDFromTile(tile_end));
220 num_pieces += 2;
221 } else {
222 MakeRoadBridgeFromRoad(tile_end, bridge_type, ReverseDiagDir(dir));
223 SetRoadTypes(tile_end, GetRoadTypes(tile_end) | rts);
225 RoadBits bits = DiagDirToRoadBits(ReverseDiagDir(dir));
226 RoadType new_rt;
227 FOR_EACH_SET_ROADTYPE(new_rt, rts) {
228 RoadBits pieces = GetRoadBits(tile_end, new_rt);
229 uint n = CountBits(pieces);
230 if (c != NULL) c->infrastructure.road[new_rt] += (n + 1) * TUNNELBRIDGE_TRACKBIT_FACTOR - n;
231 SetRoadBits(tile_end, pieces | bits, new_rt);
235 num_pieces *= TUNNELBRIDGE_TRACKBIT_FACTOR;
236 if (c != NULL) {
237 /* Add all new road types to the company infrastructure counter. */
238 RoadType new_rt;
239 FOR_EACH_SET_ROADTYPE(new_rt, rts) {
240 /* A full diagonal road tile has two road bits. */
241 c->infrastructure.road[new_rt] += num_pieces;
245 SetBridgeMiddleTiles(tile_start, tile_end, direction);
246 DirtyCompanyInfrastructureWindows(company);
250 /* for human player that builds the bridge he gets a selection to choose from bridges (DC_QUERY_COST)
251 * It's unnecessary to execute this command every time for every bridge. So it is done only
252 * and cost is computed in "bridge_gui.c". For AI, Towns this has to be of course calculated
254 Company *c = Company::GetIfValid(company);
255 if (!(flags & DC_QUERY_COST) || (c != NULL && c->is_ai)) {
256 bridge_len += 2; // begin and end tiles/ramps
258 cost.AddCost(bridge_len * _price[PR_BUILD_ROAD] * 2 * CountBits(rts));
260 if (c != NULL) bridge_len = CalcBridgeLenCostFactor(bridge_len);
262 cost.AddCost((int64)bridge_len * _price[PR_BUILD_BRIDGE] * GetBridgeSpec(bridge_type)->price >> 8);
265 return cost;
270 * Trackbits to add to a rail tile if a bridge is built on it, or TRACK_BIT_NONE if tile must be cleared
271 * @param tile tile to check
272 * @param dir direction for bridge
273 * @param rt railtype for bridge
274 * @return trackbits to add, or TRACK_BIT_NONE if tile must be cleared
276 static TrackBits RailBridgeAddBits(TileIndex tile, DiagDirection dir, RailType rt)
278 if (!IsNormalRailTile(tile) || !IsTileOwner(tile, _current_company)) return TRACK_BIT_NONE;
280 Slope tileh = GetTileSlope(tile);
281 DiagDirDiff diff = CheckExtendedBridgeHead(tileh, dir);
282 TrackBits present = GetTrackBits(tile);
284 switch (diff) {
285 case DIAGDIRDIFF_REVERSE: return TRACK_BIT_NONE;
287 case DIAGDIRDIFF_SAME: {
288 TrackBits bridgebits = DiagdirReachesTracks(ReverseDiagDir(dir));
289 if ((present & bridgebits) != TRACK_BIT_NONE) return TRACK_BIT_NONE;
291 Track track = FindFirstTrack(present);
293 if (KillFirstBit(present) != TRACK_BIT_NONE) {
294 return (GetRailType(tile, track) == rt) ? bridgebits : TRACK_BIT_NONE;
295 } else if (GetRailType(tile, track) == rt && !HasSignalOnTrack(tile, track)) {
296 return bridgebits & ~TrackToTrackBits(TrackToOppositeTrack(track));
297 } else if (IsDiagonalTrack(track)) {
298 return TRACK_BIT_NONE;
299 } else {
300 return bridgebits & TrackToTrackBits(TrackToOppositeTrack(track));
304 default: {
305 TrackBits allowed = TRACK_BIT_ALL & ~DiagdirReachesTracks(ReverseDiagDir(ChangeDiagDir(dir, diff)));
306 if (present != (allowed & ~DiagdirReachesTracks(ReverseDiagDir(dir)))) {
307 return TRACK_BIT_NONE;
310 Track track = FindFirstTrack(present);
311 assert(present == TrackToTrackBits(track)); // present should have exactly one trackbit
313 if (HasSignalOnTrack(tile, track) || GetRailType(tile, track) != rt) return TRACK_BIT_NONE;
315 return allowed ^ present;
321 * Build a rail bridge
322 * @param tile_start Start tile
323 * @param tile_end End tile
324 * @param bridge_type Bridge type
325 * @param railtype Rail type
326 * @param flags type of operation
327 * @return the cost of this operation or an error
329 static CommandCost BuildRailBridge(TileIndex tile_start, TileIndex tile_end, BridgeType bridge_type, RailType railtype, DoCommandFlag flags)
331 if (!ValParamRailtype(railtype)) return CMD_ERROR;
333 if (_current_company == OWNER_DEITY) return CMD_ERROR;
335 Axis direction;
336 CommandCost ret = CheckBridgeTiles(tile_start, tile_end, &direction);
337 if (ret.Failed()) return ret;
339 if (tile_end < tile_start) Swap(tile_start, tile_end);
341 /* set and test bridge length, availability */
342 uint bridge_len = GetTunnelBridgeLength(tile_start, tile_end);
343 ret = CheckBridgeAvailability(bridge_type, bridge_len, flags);
344 if (ret.Failed()) return ret;
346 CommandCost cost(EXPENSES_CONSTRUCTION);
348 if (IsRailBridgeTile(tile_start) && IsRailBridgeTile(tile_end) &&
349 GetOtherBridgeEnd(tile_start) == tile_end) {
350 /* Replace a current bridge. */
352 /* Make sure the railtypes match. */
353 if (GetBridgeRailType(tile_start) != railtype) {
354 return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
357 /* Do not replace the bridge with the same bridge type. */
358 if (!(flags & DC_QUERY_COST) && bridge_type == GetRailBridgeType(tile_start)) {
359 return_cmd_error(STR_ERROR_ALREADY_BUILT);
362 /* Do not allow replacing another company's bridges. */
363 if (!IsTileOwner(tile_start, _current_company) && !IsTileOwner(tile_start, OWNER_TOWN)) {
364 return_cmd_error(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
367 cost.AddCost((bridge_len + 1) * _price[PR_CLEAR_BRIDGE]); // The cost of clearing the current bridge.
369 /* do the drill? */
370 if (flags & DC_EXEC) {
371 SetRailBridgeType(tile_start, bridge_type);
372 SetRailBridgeType(tile_end, bridge_type);
374 MarkBridgeTilesDirty(tile_start, tile_end, AxisToDiagDir(direction));
376 } else {
377 DiagDirection dir = AxisToDiagDir(direction);
379 TrackBits add_start = RailBridgeAddBits(tile_start, dir, railtype);
380 TrackBits add_end = RailBridgeAddBits(tile_end, ReverseDiagDir(dir), railtype);
382 /* Build a new bridge. */
383 CommandCost ret = CheckBridgeBuildable(tile_start, tile_end, flags, add_start == TRACK_BIT_NONE, add_end == TRACK_BIT_NONE);
384 if (ret.Failed()) return ret;
385 cost.AddCost(ret);
387 /* do the drill? */
388 if (flags & DC_EXEC) {
389 /* Add to company infrastructure count if building a new bridge. */
390 Company *c = Company::Get(_current_company);
391 uint pieces = bridge_len;
393 if (add_start == TRACK_BIT_NONE) {
394 MakeRailBridgeRamp(tile_start, _current_company, bridge_type, dir, railtype);
395 pieces++;
396 } else {
397 TrackBits bits = GetTrackBits(tile_start);
398 MakeRailBridgeFromRail(tile_start, bridge_type, dir);
399 SetTrackBits(tile_start, bits | add_start);
400 SetRailType(tile_start, railtype, FindFirstTrack(add_start));
402 if (HasExactlyOneBit(add_start)) {
403 pieces++;
404 } else {
405 uint n = CountBits(bits);
406 c->infrastructure.rail[railtype] -= n * n;
407 n = CountBits(bits | add_start);
408 pieces += n * n;
412 if (add_end == TRACK_BIT_NONE) {
413 MakeRailBridgeRamp(tile_end, _current_company, bridge_type, ReverseDiagDir(dir), railtype);
414 pieces++;
415 } else {
416 TrackBits bits = GetTrackBits(tile_end);
417 MakeRailBridgeFromRail(tile_end, bridge_type, ReverseDiagDir(dir));
418 SetTrackBits(tile_end, bits | add_end);
419 SetRailType(tile_end, railtype, FindFirstTrack(add_end));
421 if (HasExactlyOneBit(add_end)) {
422 pieces++;
423 } else {
424 uint n = CountBits(bits);
425 c->infrastructure.rail[railtype] -= n * n;
426 n = CountBits(bits | add_end);
427 pieces += n * n;
431 c->infrastructure.rail[railtype] += pieces * TUNNELBRIDGE_TRACKBIT_FACTOR;
432 DirtyCompanyInfrastructureWindows(_current_company);
434 SetBridgeMiddleTiles(tile_start, tile_end, direction);
435 DirtyCompanyInfrastructureWindows(_current_company);
439 if (flags & DC_EXEC) {
440 Track track = AxisToTrack(direction);
441 AddBridgeToSignalBuffer(tile_start, _current_company);
442 YapfNotifyTrackLayoutChange(tile_start, track);
445 /* for human player that builds the bridge he gets a selection to choose from bridges (DC_QUERY_COST)
446 * It's unnecessary to execute this command every time for every bridge. So it is done only
447 * and cost is computed in "bridge_gui.c". For AI, Towns this has to be of course calculated
449 Company *c = Company::Get(_current_company);
450 if (!(flags & DC_QUERY_COST) || c->is_ai) {
451 bridge_len += 2; // begin and end tiles/ramps
453 cost.AddCost(bridge_len * RailBuildCost(railtype));
455 bridge_len = CalcBridgeLenCostFactor(bridge_len);
457 cost.AddCost((int64)bridge_len * _price[PR_BUILD_BRIDGE] * GetBridgeSpec(bridge_type)->price >> 8);
460 return cost;
465 * Build an aqueduct
466 * @param tile_start Start tile
467 * @param tile_end End tile
468 * @param flags type of operation
469 * @return the cost of this operation or an error
471 static CommandCost BuildAqueduct(TileIndex tile_start, TileIndex tile_end, DoCommandFlag flags)
473 if (_current_company == OWNER_DEITY) return CMD_ERROR;
475 Axis direction;
476 CommandCost ret = CheckBridgeTiles(tile_start, tile_end, &direction);
477 if (ret.Failed()) return ret;
479 if (tile_end < tile_start) Swap(tile_start, tile_end);
481 /* set and test bridge length, availability */
482 uint bridge_len = GetTunnelBridgeLength(tile_start, tile_end);
483 if (bridge_len > _settings_game.construction.max_bridge_length) return_cmd_error(STR_ERROR_BRIDGE_TOO_LONG);
485 CommandCost cost(EXPENSES_CONSTRUCTION);
487 if (IsAqueductTile(tile_start) && IsAqueductTile(tile_end) &&
488 GetOtherBridgeEnd(tile_start) == tile_end) {
489 return_cmd_error(STR_ERROR_ALREADY_BUILT);
492 /* Build a new bridge. */
493 ret = CheckBridgeBuildable(tile_start, tile_end, flags, true, true, true);
494 if (ret.Failed()) return ret;
495 cost.AddCost(ret);
497 /* do the drill? */
498 if (flags & DC_EXEC) {
499 DiagDirection dir = AxisToDiagDir(direction);
501 Company *c = Company::GetIfValid(_current_company);
502 if (c != NULL) c->infrastructure.water += (bridge_len + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR;
503 MakeAqueductBridgeRamp(tile_start, _current_company, dir);
504 MakeAqueductBridgeRamp(tile_end, _current_company, ReverseDiagDir(dir));
506 SetBridgeMiddleTiles(tile_start, tile_end, direction);
507 DirtyCompanyInfrastructureWindows(_current_company);
510 /* for human player that builds the bridge he gets a selection to choose from bridges (DC_QUERY_COST)
511 * It's unnecessary to execute this command every time for every bridge. So it is done only
512 * and cost is computed in "bridge_gui.c". For AI, Towns this has to be of course calculated
514 Company *c = Company::GetIfValid(_current_company);
515 if (!(flags & DC_QUERY_COST) || (c != NULL && c->is_ai)) {
516 bridge_len += 2; // begin and end tiles/ramps
518 if (c != NULL) bridge_len = CalcBridgeLenCostFactor(bridge_len);
520 /* Aqueducts use a separate base cost. */
521 cost.AddCost((int64)bridge_len * _price[PR_BUILD_AQUEDUCT]);
524 return cost;
529 * Build a Bridge
530 * @param end_tile end tile
531 * @param flags type of operation
532 * @param p1 packed start tile coords (~ dx)
533 * @param p2 various bitstuffed elements
534 * - p2 = (bit 0- 7) - bridge type (hi bh)
535 * - p2 = (bit 8-11) - rail type or road types.
536 * - p2 = (bit 12-13) - transport type.
537 * - p2 = (bit 16-31) - the town that is building the road (if applicable)
538 * @param text unused
539 * @return the cost of this operation or an error
541 CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
543 /* unpack parameters */
544 BridgeType bridge_type = GB(p2, 0, 8);
546 if (!IsValidTile(p1)) return_cmd_error(STR_ERROR_BRIDGE_THROUGH_MAP_BORDER);
548 /* type of bridge */
549 switch (Extract<TransportType, 12, 2>(p2)) {
550 case TRANSPORT_ROAD:
551 return BuildRoadBridge(p1, end_tile, bridge_type, Extract<RoadTypes, 8, 2>(p2), GB(p2, 16, 16), flags);
553 case TRANSPORT_RAIL:
554 return BuildRailBridge(p1, end_tile, bridge_type, Extract<RailType, 8, 4>(p2), flags);
556 case TRANSPORT_WATER:
557 return BuildAqueduct(p1, end_tile, flags);
559 default:
560 /* Airports don't have bridges. */
561 return CMD_ERROR;
567 * Build Tunnel.
568 * @param start_tile start tile of tunnel
569 * @param flags type of operation
570 * @param p1 bit 0-3 railtype or roadtypes
571 * bit 8-9 transport type
572 * @param p2 unused
573 * @param text unused
574 * @return the cost of this operation or an error
576 CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
578 CompanyID company = _current_company;
580 TransportType transport_type = Extract<TransportType, 8, 2>(p1);
582 RailType railtype = INVALID_RAILTYPE;
583 RoadTypes rts = ROADTYPES_NONE;
584 _build_tunnel_endtile = 0;
585 switch (transport_type) {
586 case TRANSPORT_RAIL:
587 railtype = Extract<RailType, 0, 4>(p1);
588 if (!ValParamRailtype(railtype)) return CMD_ERROR;
589 break;
591 case TRANSPORT_ROAD:
592 rts = Extract<RoadTypes, 0, 2>(p1);
593 if (!HasExactlyOneBit(rts) || !HasRoadTypesAvail(company, rts)) return CMD_ERROR;
594 break;
596 default: return CMD_ERROR;
599 if (company == OWNER_DEITY) {
600 if (transport_type != TRANSPORT_ROAD) return CMD_ERROR;
601 const Town *town = CalcClosestTownFromTile(start_tile);
603 company = OWNER_TOWN;
605 /* If we are not within a town, we are not owned by the town */
606 if (town == NULL || DistanceSquare(start_tile, town->xy) > town->cache.squared_town_zone_radius[HZB_TOWN_EDGE]) {
607 company = OWNER_NONE;
611 int start_z;
612 int end_z;
613 Slope start_tileh = GetTileSlope(start_tile, &start_z);
614 DiagDirection direction = GetInclinedSlopeDirection(start_tileh);
615 if (direction == INVALID_DIAGDIR) return_cmd_error(STR_ERROR_SITE_UNSUITABLE_FOR_TUNNEL);
617 if (HasTileWaterGround(start_tile)) return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER);
619 CommandCost ret = DoCommand(start_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
620 if (ret.Failed()) return ret;
622 /* XXX - do NOT change 'ret' in the loop, as it is used as the price
623 * for the clearing of the entrance of the tunnel. Assigning it to
624 * cost before the loop will yield different costs depending on start-
625 * position, because of increased-cost-by-length: 'cost += cost >> 3' */
627 TileIndexDiff delta = TileOffsByDiagDir(direction);
628 DiagDirection tunnel_in_way_dir;
629 if (DiagDirToAxis(direction) == AXIS_Y) {
630 tunnel_in_way_dir = (TileX(start_tile) < (MapMaxX() / 2)) ? DIAGDIR_SW : DIAGDIR_NE;
631 } else {
632 tunnel_in_way_dir = (TileY(start_tile) < (MapMaxX() / 2)) ? DIAGDIR_SE : DIAGDIR_NW;
635 TileIndex end_tile = start_tile;
637 /* Tile shift coefficient. Will decrease for very long tunnels to avoid exponential growth of price*/
638 int tiles_coef = 3;
639 /* Number of tiles from start of tunnel */
640 int tiles = 0;
641 /* Number of tiles at which the cost increase coefficient per tile is halved */
642 int tiles_bump = 25;
644 CommandCost cost(EXPENSES_CONSTRUCTION);
645 Slope end_tileh;
646 for (;;) {
647 end_tile += delta;
648 if (!IsValidTile(end_tile)) return_cmd_error(STR_ERROR_TUNNEL_THROUGH_MAP_BORDER);
649 end_tileh = GetTileSlope(end_tile, &end_z);
651 if (start_z == end_z) break;
653 if (!_cheats.crossing_tunnels.value && IsTunnelInWayDir(end_tile, start_z, tunnel_in_way_dir)) {
654 return_cmd_error(STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY);
657 tiles++;
658 if (tiles == tiles_bump) {
659 tiles_coef++;
660 tiles_bump *= 2;
663 cost.AddCost(_price[PR_BUILD_TUNNEL]);
664 cost.AddCost(cost.GetCost() >> tiles_coef); // add a multiplier for longer tunnels
667 /* Add the cost of the entrance */
668 cost.AddCost(_price[PR_BUILD_TUNNEL]);
669 cost.AddCost(ret);
671 /* if the command fails from here on we want the end tile to be highlighted */
672 _build_tunnel_endtile = end_tile;
674 if (tiles > _settings_game.construction.max_tunnel_length) return_cmd_error(STR_ERROR_TUNNEL_TOO_LONG);
676 if (HasTileWaterGround(end_tile)) return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER);
678 /* Clear the tile in any case */
679 ret = DoCommand(end_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
680 if (ret.Failed()) return_cmd_error(STR_ERROR_UNABLE_TO_EXCAVATE_LAND);
681 cost.AddCost(ret);
683 /* slope of end tile must be complementary to the slope of the start tile */
684 if (end_tileh != ComplementSlope(start_tileh)) {
685 /* Mark the tile as already cleared for the terraform command.
686 * Do this for all tiles (like trees), not only objects. */
687 ClearedObjectArea *coa = FindClearedObject(end_tile);
688 if (coa == NULL) {
689 coa = _cleared_object_areas.Append();
690 coa->first_tile = end_tile;
691 coa->area = TileArea(end_tile, 1, 1);
694 /* Hide the tile from the terraforming command */
695 TileIndex old_first_tile = coa->first_tile;
696 coa->first_tile = INVALID_TILE;
697 ret = DoCommand(end_tile, end_tileh & start_tileh, 0, flags, CMD_TERRAFORM_LAND);
698 coa->first_tile = old_first_tile;
699 if (ret.Failed()) return_cmd_error(STR_ERROR_UNABLE_TO_EXCAVATE_LAND);
700 cost.AddCost(ret);
702 cost.AddCost(_price[PR_BUILD_TUNNEL]);
704 /* Pay for the rail/road in the tunnel including entrances */
705 switch (transport_type) {
706 case TRANSPORT_ROAD: cost.AddCost((tiles + 2) * _price[PR_BUILD_ROAD] * 2); break;
707 case TRANSPORT_RAIL: cost.AddCost((tiles + 2) * RailBuildCost(railtype)); break;
708 default: NOT_REACHED();
711 if (flags & DC_EXEC) {
712 Company *c = Company::GetIfValid(company);
713 uint num_pieces = (tiles + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR;
714 if (transport_type == TRANSPORT_RAIL) {
715 if (!IsTunnelTile(start_tile) && c != NULL) c->infrastructure.rail[railtype] += num_pieces;
716 MakeRailTunnel(start_tile, company, direction, railtype);
717 MakeRailTunnel(end_tile, company, ReverseDiagDir(direction), railtype);
718 AddTunnelToSignalBuffer(start_tile, company);
719 YapfNotifyTrackLayoutChange(start_tile, DiagDirToDiagTrack(direction));
720 } else {
721 if (c != NULL) {
722 RoadType rt;
723 FOR_EACH_SET_ROADTYPE(rt, rts ^ (IsTunnelTile(start_tile) ? GetRoadTypes(start_tile) : ROADTYPES_NONE)) {
724 c->infrastructure.road[rt] += num_pieces * 2; // A full diagonal road has two road bits.
727 MakeRoadTunnel(start_tile, company, direction, rts);
728 MakeRoadTunnel(end_tile, company, ReverseDiagDir(direction), rts);
730 DirtyCompanyInfrastructureWindows(company);
733 return cost;