(svn r11320) -Codechange: make lower halftiles at coast floodable. Patch by frosch.

This commit is contained in:
rubidium 2007-10-20 21:05:18 +00:00
parent ef9e037c2a
commit 2c67320bae
5 changed files with 119 additions and 26 deletions

View File

@ -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:

View File

@ -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 */

View File

@ -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)) {

View File

@ -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)

View File

@ -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
*/