summaryrefslogtreecommitdiff
path: root/src/tunnelbridge_cmd.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tunnelbridge_cmd.cpp')
-rw-r--r--src/tunnelbridge_cmd.cpp111
1 files changed, 96 insertions, 15 deletions
diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp
index 5181dfdca..a0e33641d 100644
--- a/src/tunnelbridge_cmd.cpp
+++ b/src/tunnelbridge_cmd.cpp
@@ -40,12 +40,15 @@
#include "water.h"
#include "company_gui.h"
#include "station_func.h"
+#include "station_map.h"
+#include "industry_map.h"
#include "table/strings.h"
#include "table/bridge_land.h"
#include "safeguards.h"
+
BridgeSpec _bridge[MAX_BRIDGES]; ///< The specification of all bridges.
TileIndex _build_tunnel_endtile; ///< The end of a tunnel; as hidden return from the tunnel build command for GUI purposes.
@@ -681,12 +684,6 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1,
* position, because of increased-cost-by-length: 'cost += cost >> 3' */
TileIndexDiff delta = TileOffsByDiagDir(direction);
- DiagDirection tunnel_in_way_dir;
- if (DiagDirToAxis(direction) == AXIS_Y) {
- tunnel_in_way_dir = (TileX(start_tile) < (MapMaxX() / 2)) ? DIAGDIR_SW : DIAGDIR_NE;
- } else {
- tunnel_in_way_dir = (TileY(start_tile) < (MapMaxX() / 2)) ? DIAGDIR_SE : DIAGDIR_NW;
- }
TileIndex end_tile = start_tile;
@@ -694,9 +691,15 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1,
int tiles_coef = 3;
/* Number of tiles from start of tunnel */
int tiles = 0;
+ /* flag for chunnels. */
+ bool is_chunnel = false;
+ /* Number of chunnel head tiles. */
+ int head_tiles = 0;
/* Number of tiles at which the cost increase coefficient per tile is halved */
int tiles_bump = 25;
+ TileIndex found_tunnel_tile = INVALID_TILE;
+
CommandCost cost(EXPENSES_CONSTRUCTION);
Slope end_tileh;
for (;;) {
@@ -704,13 +707,69 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1,
if (!IsValidTile(end_tile)) return_cmd_error(STR_ERROR_TUNNEL_THROUGH_MAP_BORDER);
end_tileh = GetTileSlope(end_tile, &end_z);
- if (start_z == end_z) break;
+ if (start_z == end_z) {
+ _build_tunnel_endtile = found_tunnel_tile != INVALID_TILE ? found_tunnel_tile : end_tile;
+
+ /* Test if we are on a shore. */
+ if (end_z == 0 &&
+ (IsCoastTile(end_tile) ||
+ (IsValidTile(end_tile + delta) && HasTileWaterGround(end_tile + delta)) ||
+ (IsValidTile(end_tile + delta * 2) && HasTileWaterGround(end_tile + delta * 2)))) {
+ if (!is_chunnel) {
+ /*We are about to pass water for the first time so check if not to close to other tunnel */
+ if (tiles + 1 < head_tiles + 4 && found_tunnel_tile != INVALID_TILE) return_cmd_error(STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY_FOR_CHUNNEL);
+ if (tiles + 1 < 4) return_cmd_error(STR_ERROR_TUNNEL_RAMP_TOO_SHORT);
+ }
+ } else {/* We are leaving.*/
+ if (is_chunnel) {
+ /* Check if there is enough ramp space to come up. */
+ if (head_tiles < 4 && found_tunnel_tile != INVALID_TILE) return_cmd_error(STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY_FOR_CHUNNEL);
+ if (head_tiles < 4) return_cmd_error(STR_ERROR_TUNNEL_RAMP_TOO_SHORT);
+ } else {
+ if (found_tunnel_tile != INVALID_TILE) return_cmd_error(STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY);
+ }
+ break;
+ }
- if (!_cheats.crossing_tunnels.value && IsTunnelInWayDir(end_tile, start_z, tunnel_in_way_dir)) {
- return_cmd_error(STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY);
- }
+ /* A shore was found so pass the water and find a proper shore tile that potentially
+ * could have a tunnel portal behind. */
+ for (;;) {
+ if (!IsValidTile(end_tile)) return_cmd_error(STR_ERROR_TUNNEL_THROUGH_MAP_BORDER);
+
+ end_tileh = GetTileSlope(end_tile);
+ if(direction == DIAGDIR_NE && (end_tileh & SLOPE_NE) == SLOPE_NE) break;
+ if(direction == DIAGDIR_SE && (end_tileh & SLOPE_SE) == SLOPE_SE) break;
+ if(direction == DIAGDIR_SW && (end_tileh & SLOPE_SW) == SLOPE_SW) break;
+ if(direction == DIAGDIR_NW && (end_tileh & SLOPE_NW) == SLOPE_NW) break;
+
+ /* No drilling under oil rigs.*/
+ if ((IsTileType(end_tile, MP_STATION) && IsOilRig(end_tile)) ||
+ (IsTileType(end_tile, MP_INDUSTRY) &&
+ GetIndustryGfx(end_tile) >= GFX_OILRIG_1 &&
+ GetIndustryGfx(end_tile) <= GFX_OILRIG_5)) {
+ _build_tunnel_endtile = end_tile;
+ return_cmd_error(STR_ERROR_NO_DRILLING_ABOVE_CHUNNEL);
+ }
+ end_tile += delta;
+ tiles++;
+ }
+ /* The water was passed */
+ is_chunnel = true;
+ head_tiles = 0;
+ found_tunnel_tile = INVALID_TILE;
+ }
+ if (!_cheats.crossing_tunnels.value && IsTunnelInWay(end_tile, start_z, (tiles + 1 < 4 || (is_chunnel && head_tiles < 4) ? false : true))) {
+ if (found_tunnel_tile == INVALID_TILE || is_chunnel) { // Remember the first or the last when we pass a tunnel.
+ found_tunnel_tile = end_tile;
+ head_tiles = 0;
+ }
+ }
+ head_tiles++;
tiles++;
+ }
+ /* The cost of the digging. */
+ for (int i = tiles; i > 0; i--) {
if (tiles == tiles_bump) {
tiles_coef++;
tiles_bump *= 2;
@@ -778,21 +837,32 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1,
default: NOT_REACHED();
}
+ if (is_chunnel) cost.MultiplyCost(2);
+
if (flags & DC_EXEC) {
Company *c = Company::GetIfValid(company);
uint num_pieces = (tiles + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR;
+
+ /* The most northern tile first. */
+ TileIndex tn = start_tile;
+ TileIndex ts = end_tile;
+ if(start_tile > end_tile) Swap(tn, ts);
+
+ if (!Tunnel::CanAllocateItem()) return_cmd_error(STR_ERROR_TUNNEL_TOO_MANY);
+ const Tunnel *t = new Tunnel(tn, ts, is_chunnel);
+
if (transport_type == TRANSPORT_RAIL) {
if (c != nullptr) c->infrastructure.rail[railtype] += num_pieces;
- MakeRailTunnel(start_tile, company, direction, railtype);
- MakeRailTunnel(end_tile, company, ReverseDiagDir(direction), railtype);
+ MakeRailTunnel(start_tile, company, t->index, direction, railtype);
+ MakeRailTunnel(end_tile, company, t->index, ReverseDiagDir(direction), railtype);
AddSideToSignalBuffer(start_tile, INVALID_DIAGDIR, company);
YapfNotifyTrackLayoutChange(start_tile, DiagDirToDiagTrack(direction));
} else {
if (c != nullptr) c->infrastructure.road[roadtype] += num_pieces * 2; // A full diagonal road has two road bits.
RoadType road_rt = RoadTypeIsRoad(roadtype) ? roadtype : INVALID_ROADTYPE;
RoadType tram_rt = RoadTypeIsTram(roadtype) ? roadtype : INVALID_ROADTYPE;
- MakeRoadTunnel(start_tile, company, direction, road_rt, tram_rt);
- MakeRoadTunnel(end_tile, company, ReverseDiagDir(direction), road_rt, tram_rt);
+ MakeRoadTunnel(start_tile, company, t->index, direction, road_rt, tram_rt);
+ MakeRoadTunnel(end_tile, company, t->index, ReverseDiagDir(direction), road_rt, tram_rt);
}
DirtyCompanyInfrastructureWindows(company);
}
@@ -883,6 +953,8 @@ static CommandCost DoClearTunnel(TileIndex tile, DoCommandFlag flags)
}
Money base_cost = TunnelBridgeClearCost(tile, PR_CLEAR_TUNNEL);
+ const bool is_chunnel = Tunnel::GetByTile(tile)->is_chunnel;
+
uint len = GetTunnelBridgeLength(tile, endtile) + 2; // Don't forget the end tiles.
if (flags & DC_EXEC) {
@@ -903,6 +975,8 @@ static CommandCost DoClearTunnel(TileIndex tile, DoCommandFlag flags)
DirtyCompanyInfrastructureWindows(owner);
}
+ delete Tunnel::GetByTile(tile);
+
DoClearSquare(tile);
DoClearSquare(endtile);
@@ -919,12 +993,14 @@ static CommandCost DoClearTunnel(TileIndex tile, DoCommandFlag flags)
UpdateCompanyRoadInfrastructure(GetRoadTypeRoad(tile), GetRoadOwner(tile, RTT_ROAD), -(int)(len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR));
UpdateCompanyRoadInfrastructure(GetRoadTypeTram(tile), GetRoadOwner(tile, RTT_TRAM), -(int)(len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR));
+ delete Tunnel::GetByTile(tile);
+
DoClearSquare(tile);
DoClearSquare(endtile);
}
}
- return CommandCost(EXPENSES_CONSTRUCTION, len * base_cost);
+ return CommandCost(EXPENSES_CONSTRUCTION, len * base_cost * (is_chunnel ? 2 : 1));
}
@@ -1900,6 +1976,7 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
if (frame == _tunnel_visibility_frame[dir]) {
t->tile = tile;
t->track = TRACK_BIT_WORMHOLE;
+ if (Tunnel::GetByTile(tile)->is_chunnel) SetBit(t->gv_flags, GVF_CHUNNEL_BIT);
t->vehstatus |= VS_HIDDEN;
return VETSB_ENTERED_WORMHOLE;
}
@@ -1907,6 +1984,7 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
if (dir == ReverseDiagDir(vdir) && frame == TILE_SIZE - _tunnel_visibility_frame[dir] && z == 0) {
/* We're at the tunnel exit ?? */
+ if (t->tile != tile && GetOtherTunnelEnd(t->tile) != tile) return VETSB_CONTINUE; // In chunnel
t->tile = tile;
t->track = DiagDirToDiagTrackBits(vdir);
assert(t->track);
@@ -1923,6 +2001,7 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
assert(frame == rv->frame + 1);
rv->tile = tile;
rv->state = RVSB_WORMHOLE;
+ if (Tunnel::GetByTile(tile)->is_chunnel) SetBit(rv->gv_flags, GVF_CHUNNEL_BIT);
rv->vehstatus |= VS_HIDDEN;
return VETSB_ENTERED_WORMHOLE;
} else {
@@ -1932,6 +2011,7 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
/* We're at the tunnel exit ?? */
if (dir == ReverseDiagDir(vdir) && frame == TILE_SIZE - _tunnel_visibility_frame[dir] && z == 0) {
+ if (rv->tile != tile && GetOtherTunnelEnd(rv->tile) != tile) return VETSB_CONTINUE; // In chunnel
rv->tile = tile;
rv->state = DiagDirToDiagTrackdir(vdir);
rv->frame = frame;
@@ -1940,6 +2020,7 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
}
}
} else { // IsBridge(tile)
+ if (v->vehstatus & VS_HIDDEN) return VETSB_CONTINUE; // Building bridges between chunnel portals allowed.
if (v->type != VEH_SHIP) {
/* modify speed of vehicle */
uint16 spd = GetBridgeSpec(GetBridgeType(tile))->speed;