From 2c67320bae6eb048a1fafbcda79c58d4f49260d5 Mon Sep 17 00:00:00 2001 From: rubidium Date: Sat, 20 Oct 2007 21:05:18 +0000 Subject: (svn r11320) -Codechange: make lower halftiles at coast floodable. Patch by frosch. --- src/rail.h | 2 ++ src/rail_cmd.cpp | 104 ++++++++++++++++++++++++++++++++++++++++++++++++------ src/rail_map.h | 1 + src/water_cmd.cpp | 33 +++++++++-------- 4 files changed, 114 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/rail.h b/src/rail.h index 36aa83f99..de1d1d82d 100644 --- a/src/rail.h +++ b/src/rail.h @@ -821,6 +821,8 @@ void DrawCatenaryOnTunnel(const TileInfo *ti); Foundation GetRailFoundation(Slope tileh, TrackBits bits); +void FloodHalftile(TileIndex t); + int32 SettingsDisableElrail(int32 p1); ///< _patches.disable_elrail callback #endif /* RAIL_H */ diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index 7c7409e5d..630671af3 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -284,7 +284,7 @@ Foundation GetRailFoundation(Slope tileh, TrackBits bits) static CommandCost CheckRailSlope(Slope tileh, TrackBits rail_bits, TrackBits existing, TileIndex tile) { /* don't allow building on the lower side of a coast */ - if (IsTileType(tile, MP_WATER)) { + if (IsTileType(tile, MP_WATER) || (IsTileType(tile, MP_RAILWAY) && (GetRailGroundType(tile) == RAIL_GROUND_WATER))) { if (!IsSteepSlope(tileh) && ((~_valid_tracks_on_leveled_foundation[tileh] & (rail_bits | existing)) != 0)) return_cmd_error(STR_3807_CAN_T_BUILD_ON_WATER); } @@ -405,6 +405,8 @@ CommandCost CmdBuildSingleRail(TileIndex tile, uint32 flags, uint32 p1, uint32 p /* FALLTHROUGH */ default: + bool water_ground = IsTileType(tile, MP_WATER) && !IsSteepSlope(tileh) && HasSlopeHighestCorner(tileh); + ret = CheckRailSlope(tileh, trackbit, TRACK_BIT_NONE, tile); if (CmdFailed(ret)) return ret; cost.AddCost(ret); @@ -413,7 +415,15 @@ CommandCost CmdBuildSingleRail(TileIndex tile, uint32 flags, uint32 p1, uint32 p if (CmdFailed(ret)) return ret; cost.AddCost(ret); - if (flags & DC_EXEC) MakeRailNormal(tile, _current_player, trackbit, railtype); + if (water_ground) { + cost.AddCost(-_price.clear_water); + cost.AddCost(_price.purchase_land); + } + + if (flags & DC_EXEC) { + MakeRailNormal(tile, _current_player, trackbit, railtype); + if (water_ground) SetRailGroundType(tile, RAIL_GROUND_WATER); + } break; } @@ -479,7 +489,11 @@ CommandCost CmdRemoveSingleRail(TileIndex tile, uint32 flags, uint32 p1, uint32 if (flags & DC_EXEC) { present ^= trackbit; if (present == 0) { - DoClearSquare(tile); + if (GetRailGroundType(tile) == RAIL_GROUND_WATER) { + MakeShore(tile); + } else { + DoClearSquare(tile); + } } else { SetTrackBits(tile, present); } @@ -511,6 +525,41 @@ CommandCost CmdRemoveSingleRail(TileIndex tile, uint32 flags, uint32 p1, uint32 } +/** + * Called from water_cmd if a non-flat rail-tile gets flooded and should be converted to shore. + * The function floods the lower halftile, if the tile has a halftile foundation. + * + * @param t The tile to flood. + */ +void FloodHalftile(TileIndex t) +{ + if (GetRailGroundType(t) == RAIL_GROUND_WATER) return; + + Slope tileh = GetTileSlope(t, NULL); + TrackBits rail_bits = GetTrackBits(t); + + if (!IsSteepSlope(tileh) && HasSlopeHighestCorner(tileh)) { + TrackBits lower_track = CornerToTrackBits(OppositeCorner(GetHighestSlopeCorner(tileh))); + + TrackBits to_remove = lower_track & rail_bits; + if (to_remove != 0) { + _current_player = OWNER_WATER; + if (CmdFailed(DoCommand(t, 0, FIND_FIRST_BIT(to_remove), DC_EXEC, CMD_REMOVE_SINGLE_RAIL))) return; // not yet floodable + rail_bits = rail_bits & ~to_remove; + if (rail_bits == 0) { + MakeShore(t); + MarkTileDirtyByTile(t); + return; + } + } + + if (IsNonContinuousFoundation(GetRailFoundation(tileh, rail_bits))) { + SetRailGroundType(t, RAIL_GROUND_WATER); + MarkTileDirtyByTile(t); + } + } +} + static const TileIndexDiffC _trackdelta[] = { { -1, 0 }, { 0, 1 }, { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, 1 }, { 0, 0 }, @@ -1244,6 +1293,8 @@ static CommandCost ClearTile_Track(TileIndex tile, byte flags) switch (GetRailTileType(tile)) { case RAIL_TILE_SIGNALS: case RAIL_TILE_NORMAL: { + bool water_ground = (GetRailGroundType(tile) == RAIL_GROUND_WATER); + TrackBits tracks = GetTrackBits(tile); while (tracks != TRACK_BIT_NONE) { Track track = RemoveFirstTrack(&tracks); @@ -1251,6 +1302,13 @@ static CommandCost ClearTile_Track(TileIndex tile, byte flags) if (CmdFailed(ret)) return CMD_ERROR; cost.AddCost(ret); } + + if (water_ground) { + /* The track was removed, and left a coast tile. Now also clear the water. */ + if (flags & DC_EXEC) DoClearSquare(tile); + cost.AddCost(_price.clear_water); + } + return cost; } @@ -1438,6 +1496,15 @@ static void DrawTrackDetails(const TileInfo* ti) case RAIL_GROUND_FENCE_VERT2: DrawTrackFence_NS_2(ti); break; case RAIL_GROUND_FENCE_HORIZ1: DrawTrackFence_WE_1(ti); break; case RAIL_GROUND_FENCE_HORIZ2: DrawTrackFence_WE_2(ti); break; + case RAIL_GROUND_WATER: + switch (GetHalftileSlopeCorner(ti->tileh)) { + case CORNER_W: DrawTrackFence_NS_1(ti); break; + case CORNER_S: DrawTrackFence_WE_2(ti); break; + case CORNER_E: DrawTrackFence_NS_2(ti); break; + case CORNER_N: DrawTrackFence_WE_1(ti); break; + default: NOT_REACHED(); + } + break; default: break; } } @@ -1473,12 +1540,16 @@ static void DrawTrackBits(TileInfo* ti, TrackBits track) /* Select the sprite to use. */ if (track == 0) { /* Clear ground (only track on halftile foundation) */ - switch (rgt) { - case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break; - case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOWY_TILE; break; - default: image = SPR_FLAT_GRASS_TILE; break; + if (rgt == RAIL_GROUND_WATER) { + image = SPR_FLAT_WATER_TILE; + } else { + switch (rgt) { + case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break; + case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOWY_TILE; break; + default: image = SPR_FLAT_GRASS_TILE; break; + } + image += _tileh_to_sprite[ti->tileh]; } - image += _tileh_to_sprite[ti->tileh]; } else { if (ti->tileh != SLOPE_FLAT) { /* track on non-flat ground */ @@ -1507,6 +1578,7 @@ static void DrawTrackBits(TileInfo* ti, TrackBits track) switch (rgt) { case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break; case RAIL_GROUND_ICE_DESERT: image += rti->snow_offset; break; + case RAIL_GROUND_WATER: NOT_REACHED(); default: break; } } @@ -2031,6 +2103,11 @@ static void TileLoop_Track(TileIndex tile) RailGroundType old_ground = GetRailGroundType(tile); RailGroundType new_ground; + if (old_ground == RAIL_GROUND_WATER) { + TileLoop_Water(tile); + return; + } + switch (_opt.landscape) { case LT_ARCTIC: if (GetTileZ(tile) > GetSnowLine()) { @@ -2346,10 +2423,14 @@ static CommandCost TestAutoslopeOnRailTile(TileIndex tile, uint flags, uint z_ol if ((tileh_new & track_corner) != 0) z_new += TILE_HEIGHT; if (z_old != z_new) return CMD_ERROR; + bool was_water = GetRailGroundType(tile) == RAIL_GROUND_WATER; + /* Make the ground dirty, if surface slope has changed */ if ((tileh_old != tileh_new) && ((flags & DC_EXEC) != 0)) SetRailGroundType(tile, RAIL_GROUND_BARREN); - return _price.terraform; + CommandCost cost = CommandCost(_price.terraform); + if (was_water) cost.AddCost(_price.clear_water); + return cost; } static CommandCost TerraformTile_Track(TileIndex tile, uint32 flags, uint z_new, Slope tileh_new) @@ -2358,6 +2439,7 @@ static CommandCost TerraformTile_Track(TileIndex tile, uint32 flags, uint z_new, Slope tileh_old = GetTileSlope(tile, &z_old); if (IsPlainRailTile(tile)) { TrackBits rail_bits = GetTrackBits(tile); + bool was_water = GetRailGroundType(tile) == RAIL_GROUND_WATER; _error_message = STR_1008_MUST_REMOVE_RAILROAD_TRACK; @@ -2388,8 +2470,8 @@ static CommandCost TerraformTile_Track(TileIndex tile, uint32 flags, uint z_new, /* Make the ground dirty */ if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN); - /* allow terraforming, no extra costs */ - return CommandCost(); + /* allow terraforming */ + return (was_water ? CommandCost(_price.clear_water) : CommandCost()); } else { if (_patches.build_on_slopes && AutoslopeEnabled()) { switch (GetRailTileType(tile)) { diff --git a/src/rail_map.h b/src/rail_map.h index b20230dcd..364394cff 100644 --- a/src/rail_map.h +++ b/src/rail_map.h @@ -394,6 +394,7 @@ enum RailGroundType { RAIL_GROUND_FENCE_HORIZ1 = 10, ///< Grass with a fence at the southern side RAIL_GROUND_FENCE_HORIZ2 = 11, ///< Grass with a fence at the northern side RAIL_GROUND_ICE_DESERT = 12, ///< Icy or sandy + RAIL_GROUND_WATER = 13, ///< Grass with a fence and water on the lower halftile }; static inline void SetRailGroundType(TileIndex t, RailGroundType rgt) diff --git a/src/water_cmd.cpp b/src/water_cmd.cpp index edaf1660a..ff69c1a61 100644 --- a/src/water_cmd.cpp +++ b/src/water_cmd.cpp @@ -538,6 +538,16 @@ static void AnimateTile_Water(TileIndex tile) /* not used */ } +/** + * Floods neighboured floodable tiles + * + * @param tile The water source tile that causes the flooding. + * @param offs[0] Destination tile to flood. + * @param offs[1] First corner of edge between source and dest tile. + * @param offs[2] Second corder of edge between source and dest tile. + * @param offs[3] Third corner of dest tile. + * @param offs[4] Fourth corner of dest tile. + */ static void TileLoopWaterHelper(TileIndex tile, const TileIndexDiffC *offs) { TileIndex target = TILE_ADD(tile, ToTileIndexDiff(offs[0])); @@ -545,36 +555,27 @@ static void TileLoopWaterHelper(TileIndex tile, const TileIndexDiffC *offs) /* type of this tile mustn't be water already. */ if (IsTileType(target, MP_WATER)) return; + /* Are both corners of the edge between source and dest on height 0 ? */ if (TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[1]))) != 0 || TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[2]))) != 0) { return; } + /* Is any corner of the dest tile raised? (First two corners already checked above. */ if (TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[3]))) != 0 || TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[4]))) != 0) { /* make coast.. */ switch (GetTileType(target)) { case MP_RAILWAY: { - TrackBits tracks; - Slope slope; - if (!IsPlainRailTile(target)) break; - tracks = GetTrackBits(target); - slope = GetTileSlope(target, NULL); - if (!( - (slope == SLOPE_W && tracks == TRACK_BIT_RIGHT) || - (slope == SLOPE_S && tracks == TRACK_BIT_UPPER) || - (slope == SLOPE_E && tracks == TRACK_BIT_LEFT) || - (slope == SLOPE_N && tracks == TRACK_BIT_LOWER) - )) { - break; - } + FloodHalftile(target); Vehicle *v = FindFloodableVehicleOnTile(target); if (v != NULL) FloodVehicle(v); + + break; } - /* FALLTHROUGH */ case MP_CLEAR: case MP_TREES: @@ -589,11 +590,13 @@ static void TileLoopWaterHelper(TileIndex tile, const TileIndexDiffC *offs) break; } } else { + /* Flood vehicles */ _current_player = OWNER_WATER; Vehicle *v = FindFloodableVehicleOnTile(target); if (v != NULL) FloodVehicle(v); + /* flood flat tile */ if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) { MakeWater(target); MarkTileDirtyByTile(target); @@ -711,7 +714,7 @@ static void FloodVehicle(Vehicle *v) /** * Let a water tile floods its diagonal adjoining tiles - * called from tunnelbridge_cmd, and by TileLoop_Industry() + * called from tunnelbridge_cmd, and by TileLoop_Industry() and TileLoop_Track() * * @param tile the water/shore tile that floods */ -- cgit v1.2.3-54-g00ecf