diff options
-rw-r--r-- | src/clear_cmd.cpp | 158 |
1 files changed, 63 insertions, 95 deletions
diff --git a/src/clear_cmd.cpp b/src/clear_cmd.cpp index 73ab18937..c6b2be0c1 100644 --- a/src/clear_cmd.cpp +++ b/src/clear_cmd.cpp @@ -46,28 +46,6 @@ struct TerraformerState { }; /** - * Tests if a tile has already been terraformed. - * - * @param ts TerraformerState. - * @param tile Tile. - * @return Tile not yet terraformed (1), tile already terraformed (0), void land (-1). - */ -static int TerraformAllowTileProcess(TerraformerState *ts, TileIndex tile) -{ - TileIndex *t; - int count; - - if (TileX(tile) == MapMaxX() || TileY(tile) == MapMaxY()) return -1; - - t = ts->tile_table; - for (count = ts->tile_table_count; count != 0; count--, t++) { - if (*t == tile) return 0; - } - - return 1; -} - -/** * Gets the TileHeight (height of north corner) of a tile as of current terraforming progress. * * @param ts TerraformerState. @@ -124,25 +102,15 @@ static void TerraformAddDirtyTileAround(TerraformerState *ts, TileIndex tile) } /** - * Checks if a tile can be terraformed. - * Extra costs for terraforming (like clearing the tile) are added to ts->cost. + * Checks if a tile can be terraformed, perform tiletype specific things (like clearing the tile) and compute their extra-cost. * * @param ts TerraformerState. * @param tile Tile. * @param mode Affected corner: 0 = north, 1 = east, 2 = south, 3 = west. - * @return 0 on success, else -1 + * @return Error message or extra-cost. */ -static int TerraformProc(TerraformerState *ts, TileIndex tile, int mode) +static CommandCost TerraformProc(TerraformerState *ts, TileIndex tile, int mode) { - int r; - CommandCost ret; - - assert(tile < MapSize()); - - /* Check for void land, and if the tile was already involved in a terraforming step, (i.e. is already cleared). */ - r = TerraformAllowTileProcess(ts, tile); - if (r <= 0) return r; - /* Check if a tile can be terraformed. */ if (IsTileType(tile, MP_RAILWAY)) { static const TrackBits safe_track[] = { TRACK_BIT_LOWER, TRACK_BIT_LEFT, TRACK_BIT_UPPER, TRACK_BIT_RIGHT }; @@ -159,29 +127,14 @@ static int TerraformProc(TerraformerState *ts, TileIndex tile, int mode) tileh == (SLOPE_STEEP | ComplementSlope(unsafe_slope[mode]))) { _terraform_err_tile = tile; _error_message = STR_1008_MUST_REMOVE_RAILROAD_TRACK; - return -1; + return CMD_ERROR; } /* If we have a single diagonal track there, the other side of * tile can be terraformed. */ if (IsPlainRailTile(tile) && GetTrackBits(tile) == safe_track[mode]) { - /* If terraforming downwards prevent damaging a potential tunnel below. - * This check is only necessary for flat tiles, because if the tile is - * non-flat, then the corner opposing the rail is raised. Only this corner - * can be lowered and this is a safe action - */ - if (tileh == SLOPE_FLAT && - ts->direction == -1 && - IsTunnelInWay(tile, z - TILE_HEIGHT)) { - _terraform_err_tile = tile; - _error_message = STR_1002_EXCAVATION_WOULD_DAMAGE; - return -1; - } - /* Allow terraforming. - * The tile is not added to the "dirty"-list, because it needs to be checked again in further terraforming steps. - * However in the end it is missing in the list, so we have to add it later. - */ - return 0; + /* Allow terraforming. */ + return CommandCost(); } } @@ -189,24 +142,11 @@ static int TerraformProc(TerraformerState *ts, TileIndex tile, int mode) if (IsClearWaterTile(tile) && IsCanal(tile)) { _terraform_err_tile = tile; _error_message = STR_MUST_DEMOLISH_CANAL_FIRST; - return -1; + return CMD_ERROR; } /* Try to clear the tile. If the tile can be cleared, add the cost to the terraforming cost, else the terraforming fails. */ - ret = DoCommand(tile, 0, 0, ts->flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR); - - if (CmdFailed(ret)) { - _terraform_err_tile = tile; - return -1; - } - - ts->cost.AddCost(ret.GetCost()); - - /* Add the tile to the "dirty" list. We know already that it is not there, so append it at the end. */ - assert(ts->tile_table_count < TERRAFORMER_TILE_TABLE_SIZE); - ts->tile_table[ts->tile_table_count++] = tile; - - return 0; + return DoCommand(tile, 0, 0, ts->flags, CMD_LANDSCAPE_CLEAR); } /** @@ -238,11 +178,23 @@ static bool TerraformTileHeight(TerraformerState *ts, TileIndex tile, int height */ if (height == TerraformGetHeightOfTile(ts, tile)) return false; - /* Check if the incident tiles of the corner can be terraformed. Compute extra costs (like tile clearing) */ - if (TerraformProc(ts, tile, 0) < 0) return false; - if (TerraformProc(ts, tile + TileDiffXY( 0, -1), 1) < 0) return false; - if (TerraformProc(ts, tile + TileDiffXY(-1, -1), 2) < 0) return false; - if (TerraformProc(ts, tile + TileDiffXY(-1, 0), 3) < 0) return false; + /* Check "too close to edge of map" */ + uint x = TileX(tile); + uint y = TileY(tile); + if ((x <= 1) || (y <= 1) || (x >= MapMaxX() - 1) || (y >= MapMaxY() - 1)) { + /* + * Determine a sensible error tile + * Note: If x and y are both zero this will disable the error tile. (Tile 0 cannot be highlighted :( ) + */ + if ((x == 1) && (y != 0)) x = 0; + if ((y == 1) && (x != 0)) y = 0; + _terraform_err_tile = TileXY(x, y); + _error_message = STR_0002_TOO_CLOSE_TO_EDGE_OF_MAP; + return false; + } + + /* Mark incident tiles, that are involved in the terraforming */ + TerraformAddDirtyTileAround(ts, tile); /* Store the height modification */ @@ -354,7 +306,7 @@ CommandCost CmdTerraformLand(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) } } - /* Check if the terraforming is valid wrt. tunnels and bridges */ + /* Check if the terraforming is valid wrt. tunnels, bridges and objects on the surface */ { int count; TileIndex *ti = ts.tile_table; @@ -362,18 +314,15 @@ CommandCost CmdTerraformLand(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) for (count = ts.tile_table_count; count != 0; count--, ti++) { TileIndex tile = *ti; + /* Find new heights of tile corners */ + uint z_N = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 0)); + uint z_W = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 0)); + uint z_S = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 1)); + uint z_E = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 1)); + /* Find min and max height of tile */ - uint z_min = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 0)); - uint z_max = z_min; - uint t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 0)); - z_min = min(z_min, t); - z_max = max(z_max, t); - t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 1)); - z_min = min(z_min, t); - z_max = max(z_max, t); - t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 1)); - z_min = min(z_min, t); - z_max = max(z_max, t); + uint z_min = min(min(z_N, z_W), min(z_S, z_E)); + uint z_max = max(max(z_N, z_W), max(z_S, z_E)); /* Check if bridge would take damage */ if (direction == 1 && MayHaveBridgeAbove(tile) && IsBridgeAbove(tile) && @@ -386,19 +335,39 @@ CommandCost CmdTerraformLand(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) _terraform_err_tile = *ti; // highlight the tile above the tunnel return_cmd_error(STR_1002_EXCAVATION_WOULD_DAMAGE); } + /* Check tiletype-specific things, and add extra-cost */ + /* Start of temporary solution until TerraformProc() gets replaced with a TileTypeProc */ + _terraform_err_tile = tile; + CommandCost cost_N = CommandCost(); + CommandCost cost_W = CommandCost(); + CommandCost cost_S = CommandCost(); + CommandCost cost_E = CommandCost(); + + if (z_N != TileHeight(tile)) cost_N = TerraformProc(&ts, tile, 0); + if (CmdFailed(cost_N)) return cost_N; + + if (z_E != TileHeight(tile + TileDiffXY(0, 1))) cost_E = TerraformProc(&ts, tile, 1); + if (CmdFailed(cost_E)) return cost_E; + + if (z_S != TileHeight(tile + TileDiffXY(1, 1))) cost_S = TerraformProc(&ts, tile, 2); + if (CmdFailed(cost_S)) return cost_S; + + if (z_W != TileHeight(tile + TileDiffXY(1, 0))) cost_W = TerraformProc(&ts, tile, 3); + if (CmdFailed(cost_W)) return cost_W; + + _terraform_err_tile = 0; // no error, reset error tile. + /* Add extra cost. Currently this may only be for clearing the tile. And we only want to clear it once. */ + CommandCost cost = CommandCost(); + cost.AddCost(cost_N); + if (cost.GetCost() == 0) cost.AddCost(cost_W); + if (cost.GetCost() == 0) cost.AddCost(cost_S); + if (cost.GetCost() == 0) cost.AddCost(cost_E); + ts.cost.AddCost(cost); + /* End of temporary solution */ } } if (flags & DC_EXEC) { - /* Clear the landscape at the tiles */ - { - int count; - TileIndex *ti = ts.tile_table; - for (count = ts.tile_table_count; count != 0; count--, ti++) { - DoCommand(*ti, 0, 0, flags, CMD_LANDSCAPE_CLEAR); - } - } - /* change the height */ { int count; @@ -409,7 +378,6 @@ CommandCost CmdTerraformLand(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) TileIndex til = mod->tile; SetTileHeight(til, mod->height); - TerraformAddDirtyTileAround(&ts, til); // add the dirty tiles, we forgot above } } |