diff options
Diffstat (limited to 'src/tunnelbridge_cmd.cpp')
-rw-r--r-- | src/tunnelbridge_cmd.cpp | 111 |
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; |