summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/landscape.html5
-rw-r--r--src/rail.h2
-rw-r--r--src/rail_cmd.cpp104
-rw-r--r--src/rail_map.h1
-rw-r--r--src/water_cmd.cpp33
5 files changed, 119 insertions, 26 deletions
diff --git a/docs/landscape.html b/docs/landscape.html
index 9f09a4be1..2794b7f7b 100644
--- a/docs/landscape.html
+++ b/docs/landscape.html
@@ -260,6 +260,11 @@
<td nowrap valign=top><tt>C</tt>&nbsp; </td>
<td align=left>on snow or desert</td>
</tr>
+
+ <tr>
+ <td nowrap valign=top><tt>D</tt>&nbsp; </td>
+ <td align=left>on grass with fence and water on the lower halftile</td>
+ </tr>
</table>
</li>
<li>m5 bits 5..0: track layout: bit set = track present:
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
*/