src/clear_cmd.cpp
branchNewGRF_ports
changeset 6868 7eb395287b3d
parent 6743 cabfaa4a0295
child 6870 ca3fd1fbe311
equal deleted inserted replaced
6867:a4ad48192617 6868:7eb395287b3d
    22 #include "unmovable_map.h"
    22 #include "unmovable_map.h"
    23 #include "genworld.h"
    23 #include "genworld.h"
    24 #include "industry.h"
    24 #include "industry.h"
    25 #include "water_map.h"
    25 #include "water_map.h"
    26 
    26 
       
    27 /*
       
    28  * In one terraforming command all four corners of a initial tile can be raised/lowered (though this is not available to the player).
       
    29  * The maximal amount of height modifications is archieved when raising a complete flat land from sea level to MAX_TILE_HEIGHT or vice versa.
       
    30  * This affects all corners with a manhatten distance smaller than MAX_TILE_HEIGHT to one of the initial 4 corners.
       
    31  * Their maximal amount is computed to 4 * \sum_{i=1}^{h_max} i  =  2 * h_max * (h_max + 1).
       
    32  */
       
    33 static const int TERRAFORMER_MODHEIGHT_SIZE = 2 * MAX_TILE_HEIGHT * (MAX_TILE_HEIGHT + 1);
       
    34 
       
    35 /*
       
    36  * The maximal amount of affected tiles (i.e. the tiles that incident with one of the corners above, is computed similiar to
       
    37  * 1 + 4 * \sum_{i=1}^{h_max} (i+1)  =  1 + 2 * h_max + (h_max + 3).
       
    38  */
       
    39 static const int TERRAFORMER_TILE_TABLE_SIZE = 1 + 2 * MAX_TILE_HEIGHT * (MAX_TILE_HEIGHT + 3);
       
    40 
    27 struct TerraformerHeightMod {
    41 struct TerraformerHeightMod {
    28 	TileIndex tile;
    42 	TileIndex tile;   ///< Referenced tile.
    29 	byte height;
    43 	byte height;      ///< New TileHeight (height of north corner) of the tile.
    30 };
    44 };
    31 
    45 
    32 struct TerraformerState {
    46 struct TerraformerState {
    33 	int height[4];
    47 	int modheight_count;                                         ///< amount of entries in "modheight".
    34 	uint32 flags;
    48 	int tile_table_count;                                        ///< amount of entries in "tile_table".
    35 
    49 
    36 	int direction;
    50 	TileIndex tile_table[TERRAFORMER_TILE_TABLE_SIZE];           ///< Dirty tiles, i.e. at least one corner changed.
    37 	int modheight_count;
    51 	TerraformerHeightMod modheight[TERRAFORMER_MODHEIGHT_SIZE];  ///< Height modifications.
    38 	int tile_table_count;
       
    39 
       
    40 	CommandCost cost;
       
    41 
       
    42 	TileIndex *tile_table;
       
    43 	TerraformerHeightMod *modheight;
       
    44 
       
    45 };
    52 };
    46 
    53 
    47 static int TerraformAllowTileProcess(TerraformerState *ts, TileIndex tile)
    54 /**
    48 {
    55  * Gets the TileHeight (height of north corner) of a tile as of current terraforming progress.
    49 	TileIndex *t;
    56  *
    50 	int count;
    57  * @param ts TerraformerState.
    51 
    58  * @param tile Tile.
    52 	if (TileX(tile) == MapMaxX() || TileY(tile) == MapMaxY()) return -1;
    59  * @return TileHeight.
    53 
    60  */
    54 	t = ts->tile_table;
       
    55 	for (count = ts->tile_table_count; count != 0; count--, t++) {
       
    56 		if (*t == tile) return 0;
       
    57 	}
       
    58 
       
    59 	return 1;
       
    60 }
       
    61 
       
    62 static int TerraformGetHeightOfTile(TerraformerState *ts, TileIndex tile)
    61 static int TerraformGetHeightOfTile(TerraformerState *ts, TileIndex tile)
    63 {
    62 {
    64 	TerraformerHeightMod *mod = ts->modheight;
    63 	TerraformerHeightMod *mod = ts->modheight;
    65 	int count;
    64 	int count;
    66 
    65 
    67 	for (count = ts->modheight_count; count != 0; count--, mod++) {
    66 	for (count = ts->modheight_count; count != 0; count--, mod++) {
    68 		if (mod->tile == tile) return mod->height;
    67 		if (mod->tile == tile) return mod->height;
    69 	}
    68 	}
    70 
    69 
       
    70 	/* TileHeight unchanged so far, read value from map. */
    71 	return TileHeight(tile);
    71 	return TileHeight(tile);
    72 }
    72 }
    73 
    73 
       
    74 /**
       
    75  * Stores the TileHeight (height of north corner) of a tile in a TerraformerState.
       
    76  *
       
    77  * @param ts TerraformerState.
       
    78  * @param tile Tile.
       
    79  * @param height New TileHeight.
       
    80  */
       
    81 static void TerraformSetHeightOfTile(TerraformerState *ts, TileIndex tile, int height)
       
    82 {
       
    83 	/* Find tile in the "modheight" table.
       
    84 	 * Note: In a normal user-terraform command the tile will not be found in the "modheight" table.
       
    85 	 *       But during house- or industry-construction multiple corners can be terraformed at once. */
       
    86 	TerraformerHeightMod *mod = ts->modheight;
       
    87 	int count = ts->modheight_count;
       
    88 	while ((count > 0) && (mod->tile != tile)) {
       
    89 		mod++;
       
    90 		count--;
       
    91 	}
       
    92 
       
    93 	/* New entry? */
       
    94 	if (count == 0) {
       
    95 		assert(ts->modheight_count < TERRAFORMER_MODHEIGHT_SIZE);
       
    96 		ts->modheight_count++;
       
    97 	}
       
    98 
       
    99 	/* Finally store the new value */
       
   100 	mod->tile = tile;
       
   101 	mod->height = (byte)height;
       
   102 }
       
   103 
       
   104 /**
       
   105  * Adds a tile to the "tile_table" in a TerraformerState.
       
   106  *
       
   107  * @param ts TerraformerState.
       
   108  * @param tile Tile.
       
   109  */
    74 static void TerraformAddDirtyTile(TerraformerState *ts, TileIndex tile)
   110 static void TerraformAddDirtyTile(TerraformerState *ts, TileIndex tile)
    75 {
   111 {
    76 	int count;
   112 	int count;
    77 	TileIndex *t;
   113 	TileIndex *t;
    78 
   114 
    79 	count = ts->tile_table_count;
   115 	count = ts->tile_table_count;
    80 
   116 
    81 	if (count >= 625) return;
       
    82 
       
    83 	for (t = ts->tile_table; count != 0; count--, t++) {
   117 	for (t = ts->tile_table; count != 0; count--, t++) {
    84 		if (*t == tile) return;
   118 		if (*t == tile) return;
    85 	}
   119 	}
    86 
   120 
       
   121 	assert(ts->tile_table_count < TERRAFORMER_TILE_TABLE_SIZE);
       
   122 
    87 	ts->tile_table[ts->tile_table_count++] = tile;
   123 	ts->tile_table[ts->tile_table_count++] = tile;
    88 }
   124 }
    89 
   125 
       
   126 /**
       
   127  * Adds all tiles that incident with the north corner of a specific tile to the "tile_table" in a TerraformerState.
       
   128  *
       
   129  * @param ts TerraformerState.
       
   130  * @param tile Tile.
       
   131  */
    90 static void TerraformAddDirtyTileAround(TerraformerState *ts, TileIndex tile)
   132 static void TerraformAddDirtyTileAround(TerraformerState *ts, TileIndex tile)
    91 {
   133 {
    92 	TerraformAddDirtyTile(ts, tile + TileDiffXY( 0, -1));
   134 	TerraformAddDirtyTile(ts, tile + TileDiffXY( 0, -1));
    93 	TerraformAddDirtyTile(ts, tile + TileDiffXY(-1, -1));
   135 	TerraformAddDirtyTile(ts, tile + TileDiffXY(-1, -1));
    94 	TerraformAddDirtyTile(ts, tile + TileDiffXY(-1,  0));
   136 	TerraformAddDirtyTile(ts, tile + TileDiffXY(-1,  0));
    95 	TerraformAddDirtyTile(ts, tile);
   137 	TerraformAddDirtyTile(ts, tile);
    96 }
   138 }
    97 
   139 
    98 static int TerraformProc(TerraformerState *ts, TileIndex tile, int mode)
   140 /**
    99 {
   141  * Terraform the north corner of a tile to a specific height.
   100 	int r;
   142  *
   101 	CommandCost ret;
   143  * @param ts TerraformerState.
       
   144  * @param tile Tile.
       
   145  * @param height Aimed height.
       
   146  * @param return Error code or cost.
       
   147  */
       
   148 static CommandCost TerraformTileHeight(TerraformerState *ts, TileIndex tile, int height)
       
   149 {
       
   150 	CommandCost total_cost = CommandCost();
   102 
   151 
   103 	assert(tile < MapSize());
   152 	assert(tile < MapSize());
   104 
   153 
   105 	r = TerraformAllowTileProcess(ts, tile);
   154 	/* Check range of destination height */
   106 	if (r <= 0) return r;
   155 	if (height < 0) return_cmd_error(STR_1003_ALREADY_AT_SEA_LEVEL);
   107 
   156 	if (height > MAX_TILE_HEIGHT) return_cmd_error(STR_1004_TOO_HIGH);
   108 	if (IsTileType(tile, MP_RAILWAY)) {
   157 
   109 		static const TrackBits safe_track[] = { TRACK_BIT_LOWER, TRACK_BIT_LEFT, TRACK_BIT_UPPER, TRACK_BIT_RIGHT };
   158 	/*
   110 		static const Slope unsafe_slope[] = { SLOPE_S, SLOPE_W, SLOPE_N, SLOPE_E };
   159 	 * Check if the terraforming has any effect.
   111 
   160 	 * This can only be true, if multiple corners of the start-tile are terraformed (i.e. the terraforming is done by towns/industries etc.).
   112 		Slope tileh;
   161 	 * In this case the terraforming should fail. (Don't know why.)
   113 		uint z;
   162 	 */
   114 
   163 	if (height == TerraformGetHeightOfTile(ts, tile)) return CMD_ERROR;
   115 		/* Nothing could be built at the steep slope - this avoids a bug
   164 
   116 		 * when you have a single diagonal track in one corner on a
   165 	/* Check "too close to edge of map" */
   117 		 * basement and then you raise/lower the other corner. */
   166 	uint x = TileX(tile);
   118 		tileh = GetTileSlope(tile, &z);
   167 	uint y = TileY(tile);
   119 		if (tileh == unsafe_slope[mode] ||
   168 	if ((x <= 1) || (y <= 1) || (x >= MapMaxX() - 1) || (y >= MapMaxY() - 1)) {
   120 				tileh == (SLOPE_STEEP | ComplementSlope(unsafe_slope[mode]))) {
   169 		/*
   121 			_terraform_err_tile = tile;
   170 		 * Determine a sensible error tile
   122 			_error_message = STR_1008_MUST_REMOVE_RAILROAD_TRACK;
   171 		 * Note: If x and y are both zero this will disable the error tile. (Tile 0 cannot be highlighted :( )
   123 			return -1;
   172 		 */
   124 		}
   173 		if ((x == 1) && (y != 0)) x = 0;
   125 
   174 		if ((y == 1) && (x != 0)) y = 0;
   126 		/* If we have a single diagonal track there, the other side of
   175 		_terraform_err_tile = TileXY(x, y);
   127 		 * tile can be terraformed. */
   176 		return_cmd_error(STR_0002_TOO_CLOSE_TO_EDGE_OF_MAP);
   128 		if (IsPlainRailTile(tile) && GetTrackBits(tile) == safe_track[mode]) {
   177 	}
   129 			/* If terraforming downwards prevent damaging a potential tunnel below.
   178 
   130 			 * This check is only necessary for flat tiles, because if the tile is
   179 	/* Mark incident tiles, that are involved in the terraforming */
   131 			 * non-flat, then the corner opposing the rail is raised. Only this corner
   180 	TerraformAddDirtyTileAround(ts, tile);
   132 			 * can be lowered and this is a safe action
   181 
   133 			 */
   182 	/* Store the height modification */
   134 			if (tileh == SLOPE_FLAT &&
   183 	TerraformSetHeightOfTile(ts, tile, height);
   135 					ts->direction == -1 &&
   184 
   136 					IsTunnelInWay(tile, z - TILE_HEIGHT)) {
   185 	/* Increment cost */
   137 				_terraform_err_tile = tile;
   186 	total_cost.AddCost(_price.terraform);
   138 				_error_message = STR_1002_EXCAVATION_WOULD_DAMAGE;
   187 
   139 				return -1;
   188 	/* Recurse to neighboured corners if height difference is larger than 1 */
   140 			}
       
   141 			return 0;
       
   142 		}
       
   143 	}
       
   144 
       
   145 	/* Canals can't be terraformed */
       
   146 	if (IsClearWaterTile(tile) && IsCanal(tile)) {
       
   147 		_terraform_err_tile = tile;
       
   148 		_error_message = STR_MUST_DEMOLISH_CANAL_FIRST;
       
   149 		return -1;
       
   150 	}
       
   151 
       
   152 	ret = DoCommand(tile, 0, 0, ts->flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR);
       
   153 
       
   154 	if (CmdFailed(ret)) {
       
   155 		_terraform_err_tile = tile;
       
   156 		return -1;
       
   157 	}
       
   158 
       
   159 	ts->cost.AddCost(ret.GetCost());
       
   160 
       
   161 	if (ts->tile_table_count >= 625) return -1;
       
   162 	ts->tile_table[ts->tile_table_count++] = tile;
       
   163 
       
   164 	return 0;
       
   165 }
       
   166 
       
   167 static bool TerraformTileHeight(TerraformerState *ts, TileIndex tile, int height)
       
   168 {
       
   169 	int nh;
       
   170 	TerraformerHeightMod *mod;
       
   171 	int count;
       
   172 
       
   173 	assert(tile < MapSize());
       
   174 
       
   175 	if (height < 0) {
       
   176 		_error_message = STR_1003_ALREADY_AT_SEA_LEVEL;
       
   177 		return false;
       
   178 	}
       
   179 
       
   180 	_error_message = STR_1004_TOO_HIGH;
       
   181 
       
   182 	if (height > MAX_TILE_HEIGHT) return false;
       
   183 
       
   184 	nh = TerraformGetHeightOfTile(ts, tile);
       
   185 	if (nh < 0 || height == nh) return false;
       
   186 
       
   187 	if (TerraformProc(ts, tile, 0) < 0) return false;
       
   188 	if (TerraformProc(ts, tile + TileDiffXY( 0, -1), 1) < 0) return false;
       
   189 	if (TerraformProc(ts, tile + TileDiffXY(-1, -1), 2) < 0) return false;
       
   190 	if (TerraformProc(ts, tile + TileDiffXY(-1,  0), 3) < 0) return false;
       
   191 
       
   192 	mod = ts->modheight;
       
   193 	count = ts->modheight_count;
       
   194 
       
   195 	for (;;) {
       
   196 		if (count == 0) {
       
   197 			if (ts->modheight_count >= 576) return false;
       
   198 			ts->modheight_count++;
       
   199 			break;
       
   200 		}
       
   201 		if (mod->tile == tile) break;
       
   202 		mod++;
       
   203 		count--;
       
   204 	}
       
   205 
       
   206 	mod->tile = tile;
       
   207 	mod->height = (byte)height;
       
   208 
       
   209 	ts->cost.AddCost(_price.terraform);
       
   210 
       
   211 	{
   189 	{
   212 		int direction = ts->direction, r;
       
   213 		const TileIndexDiffC *ttm;
   190 		const TileIndexDiffC *ttm;
   214 
   191 
   215 		static const TileIndexDiffC _terraform_tilepos[] = {
   192 		static const TileIndexDiffC _terraform_tilepos[] = {
   216 			{ 1,  0},
   193 			{ 1,  0}, // move to tile in SE
   217 			{-2,  0},
   194 			{-2,  0}, // undo last move, and move to tile in NW
   218 			{ 1,  1},
   195 			{ 1,  1}, // undo last move, and move to tile in SW
   219 			{ 0, -2}
   196 			{ 0, -2}  // undo last move, and move to tile in NE
   220 		};
   197 		};
   221 
   198 
   222 		for (ttm = _terraform_tilepos; ttm != endof(_terraform_tilepos); ttm++) {
   199 		for (ttm = _terraform_tilepos; ttm != endof(_terraform_tilepos); ttm++) {
   223 			tile += ToTileIndexDiff(*ttm);
   200 			tile += ToTileIndexDiff(*ttm);
   224 
   201 
   225 			r = TerraformGetHeightOfTile(ts, tile);
   202 			/* Get TileHeight of neighboured tile as of current terraform progress */
   226 			if (r != height && r - direction != height && r + direction != height) {
   203 			int r = TerraformGetHeightOfTile(ts, tile);
   227 				if (!TerraformTileHeight(ts, tile, r + direction))
   204 			int height_diff = height - r;
   228 					return false;
   205 
   229 			}
   206 			/* Is the height difference to the neighboured corner greater than 1? */
   230 		}
   207 			if (abs(height_diff) > 1) {
   231 	}
   208 				/* Terraform the neighboured corner. The resulting height difference should be 1. */
   232 
   209 				height_diff += (height_diff < 0 ? 1 : -1);
   233 	return true;
   210 				CommandCost cost = TerraformTileHeight(ts, tile, r + height_diff);
       
   211 				if (CmdFailed(cost)) return cost;
       
   212 				total_cost.AddCost(cost);
       
   213 			}
       
   214 		}
       
   215 	}
       
   216 
       
   217 	return total_cost;
   234 }
   218 }
   235 
   219 
   236 /** Terraform land
   220 /** Terraform land
   237  * @param tile tile to terraform
   221  * @param tile tile to terraform
   238  * @param flags for this command type
   222  * @param flags for this command type
   239  * @param p1 corners to terraform.
   223  * @param p1 corners to terraform (SLOPE_xxx)
   240  * @param p2 direction; eg up or down
   224  * @param p2 direction; eg up (non-zero) or down (zero)
   241  * @return error or cost of terraforming
   225  * @return error or cost of terraforming
   242  */
   226  */
   243 CommandCost CmdTerraformLand(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
   227 CommandCost CmdTerraformLand(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
   244 {
   228 {
   245 	TerraformerState ts;
   229 	TerraformerState ts;
   246 	TileIndex t;
   230 	CommandCost total_cost = CommandCost();
   247 	int direction;
   231 	int direction = (p2 != 0 ? 1 : -1);
   248 
       
   249 	TerraformerHeightMod modheight_data[576];
       
   250 	TileIndex tile_table_data[625];
       
   251 
   232 
   252 	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
   233 	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
   253 
   234 
   254 	_terraform_err_tile = 0;
   235 	_terraform_err_tile = 0;
   255 
   236 
   256 	ts.direction = direction = p2 ? 1 : -1;
       
   257 	ts.flags = flags;
       
   258 	ts.modheight_count = ts.tile_table_count = 0;
   237 	ts.modheight_count = ts.tile_table_count = 0;
   259 	ts.cost = CommandCost();
       
   260 	ts.modheight = modheight_data;
       
   261 	ts.tile_table = tile_table_data;
       
   262 
   238 
   263 	/* Make an extra check for map-bounds cause we add tiles to the originating tile */
   239 	/* Make an extra check for map-bounds cause we add tiles to the originating tile */
   264 	if (tile + TileDiffXY(1, 1) >= MapSize()) return CMD_ERROR;
   240 	if (tile + TileDiffXY(1, 1) >= MapSize()) return CMD_ERROR;
   265 
   241 
   266 	if (p1 & 1) {
   242 	/* Compute the costs and the terraforming result in a model of the landscape */
   267 		t = tile + TileDiffXY(1, 0);
   243 	if ((p1 & SLOPE_W) != 0) {
   268 		if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) {
   244 		TileIndex t = tile + TileDiffXY(1, 0);
   269 			return CMD_ERROR;
   245 		CommandCost cost = TerraformTileHeight(&ts, t, TileHeight(t) + direction);
   270 		}
   246 		if (CmdFailed(cost)) return cost;
   271 	}
   247 		total_cost.AddCost(cost);
   272 
   248 	}
   273 	if (p1 & 2) {
   249 
   274 		t = tile + TileDiffXY(1, 1);
   250 	if ((p1 & SLOPE_S) != 0) {
   275 		if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) {
   251 		TileIndex t = tile + TileDiffXY(1, 1);
   276 			return CMD_ERROR;
   252 		CommandCost cost = TerraformTileHeight(&ts, t, TileHeight(t) + direction);
   277 		}
   253 		if (CmdFailed(cost)) return cost;
   278 	}
   254 		total_cost.AddCost(cost);
   279 
   255 	}
   280 	if (p1 & 4) {
   256 
   281 		t = tile + TileDiffXY(0, 1);
   257 	if ((p1 & SLOPE_E) != 0) {
   282 		if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) {
   258 		TileIndex t = tile + TileDiffXY(0, 1);
   283 			return CMD_ERROR;
   259 		CommandCost cost = TerraformTileHeight(&ts, t, TileHeight(t) + direction);
   284 		}
   260 		if (CmdFailed(cost)) return cost;
   285 	}
   261 		total_cost.AddCost(cost);
   286 
   262 	}
   287 	if (p1 & 8) {
   263 
   288 		t = tile + TileDiffXY(0, 0);
   264 	if ((p1 & SLOPE_N) != 0) {
   289 		if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) {
   265 		TileIndex t = tile + TileDiffXY(0, 0);
   290 			return CMD_ERROR;
   266 		CommandCost cost = TerraformTileHeight(&ts, t, TileHeight(t) + direction);
   291 		}
   267 		if (CmdFailed(cost)) return cost;
   292 	}
   268 		total_cost.AddCost(cost);
   293 
   269 	}
       
   270 
       
   271 	/* Check if the terraforming is valid wrt. tunnels, bridges and objects on the surface */
   294 	{
   272 	{
   295 		/* Check if tunnel would take damage */
       
   296 		int count;
   273 		int count;
   297 		TileIndex *ti = ts.tile_table;
   274 		TileIndex *ti = ts.tile_table;
   298 
   275 
   299 		for (count = ts.tile_table_count; count != 0; count--, ti++) {
   276 		for (count = ts.tile_table_count; count != 0; count--, ti++) {
   300 			TileIndex tile = *ti;
   277 			TileIndex tile = *ti;
   301 
   278 
   302 			uint z_min = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 0));
   279 			/* Find new heights of tile corners */
   303 			uint z_max = z_min;
   280 			uint z_N = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 0));
   304 			uint t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 0));
   281 			uint z_W = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 0));
   305 			z_min = min(z_min, t);
   282 			uint z_S = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 1));
   306 			z_max = max(z_max, t);
   283 			uint z_E = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 1));
   307 			t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 1));
   284 
   308 			z_min = min(z_min, t);
   285 			/* Find min and max height of tile */
   309 			z_max = max(z_max, t);
   286 			uint z_min = min(min(z_N, z_W), min(z_S, z_E));
   310 			t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 1));
   287 			uint z_max = max(max(z_N, z_W), max(z_S, z_E));
   311 			z_min = min(z_min, t);
   288 
   312 			z_max = max(z_max, t);
   289 			/* Compute tile slope */
   313 
   290 			uint tileh = (z_max > z_min + 1 ? SLOPE_STEEP : SLOPE_FLAT);
       
   291 			if (z_W > z_min) tileh += SLOPE_W;
       
   292 			if (z_S > z_min) tileh += SLOPE_S;
       
   293 			if (z_E > z_min) tileh += SLOPE_E;
       
   294 			if (z_N > z_min) tileh += SLOPE_N;
       
   295 
       
   296 			/* Check if bridge would take damage */
   314 			if (direction == 1 && MayHaveBridgeAbove(tile) && IsBridgeAbove(tile) &&
   297 			if (direction == 1 && MayHaveBridgeAbove(tile) && IsBridgeAbove(tile) &&
   315 					GetBridgeHeight(GetSouthernBridgeEnd(tile)) <= z_max * TILE_HEIGHT) {
   298 					GetBridgeHeight(GetSouthernBridgeEnd(tile)) <= z_max * TILE_HEIGHT) {
       
   299 				_terraform_err_tile = tile; // highlight the tile under the bridge
   316 				return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
   300 				return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
   317 			}
   301 			}
       
   302 			/* Check if tunnel would take damage */
   318 			if (direction == -1 && IsTunnelInWay(tile, z_min * TILE_HEIGHT)) {
   303 			if (direction == -1 && IsTunnelInWay(tile, z_min * TILE_HEIGHT)) {
       
   304 				_terraform_err_tile = tile; // highlight the tile above the tunnel
   319 				return_cmd_error(STR_1002_EXCAVATION_WOULD_DAMAGE);
   305 				return_cmd_error(STR_1002_EXCAVATION_WOULD_DAMAGE);
   320 			}
   306 			}
       
   307 			/* Check tiletype-specific things, and add extra-cost */
       
   308 			CommandCost cost = _tile_type_procs[GetTileType(tile)]->terraform_tile_proc(tile, flags, z_min * TILE_HEIGHT, (Slope) tileh);
       
   309 			if (CmdFailed(cost)) {
       
   310 				_terraform_err_tile = tile;
       
   311 				return cost;
       
   312 			}
       
   313 			total_cost.AddCost(cost);
   321 		}
   314 		}
   322 	}
   315 	}
   323 
   316 
   324 	if (flags & DC_EXEC) {
   317 	if (flags & DC_EXEC) {
   325 		/* Clear the landscape at the tiles */
       
   326 		{
       
   327 			int count;
       
   328 			TileIndex *ti = ts.tile_table;
       
   329 			for (count = ts.tile_table_count; count != 0; count--, ti++) {
       
   330 				DoCommand(*ti, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
       
   331 			}
       
   332 		}
       
   333 
       
   334 		/* change the height */
   318 		/* change the height */
   335 		{
   319 		{
   336 			int count;
   320 			int count;
   337 			TerraformerHeightMod *mod;
   321 			TerraformerHeightMod *mod;
   338 
   322 
   339 			mod = ts.modheight;
   323 			mod = ts.modheight;
   340 			for (count = ts.modheight_count; count != 0; count--, mod++) {
   324 			for (count = ts.modheight_count; count != 0; count--, mod++) {
   341 				TileIndex til = mod->tile;
   325 				TileIndex til = mod->tile;
   342 
   326 
   343 				SetTileHeight(til, mod->height);
   327 				SetTileHeight(til, mod->height);
   344 				TerraformAddDirtyTileAround(&ts, til);
       
   345 			}
   328 			}
   346 		}
   329 		}
   347 
   330 
   348 		/* finally mark the dirty tiles dirty */
   331 		/* finally mark the dirty tiles dirty */
   349 		{
   332 		{
   352 			for (count = ts.tile_table_count; count != 0; count--, ti++) {
   335 			for (count = ts.tile_table_count; count != 0; count--, ti++) {
   353 				MarkTileDirtyByTile(*ti);
   336 				MarkTileDirtyByTile(*ti);
   354 			}
   337 			}
   355 		}
   338 		}
   356 	}
   339 	}
   357 	return ts.cost;
   340 	return total_cost;
   358 }
   341 }
   359 
   342 
   360 
   343 
   361 /** Levels a selected (rectangle) area of land
   344 /** Levels a selected (rectangle) area of land
   362  * @param tile end tile of area-drag
   345  * @param tile end tile of area-drag
   398 	money.AddCost(GetAvailableMoneyForCommand());
   381 	money.AddCost(GetAvailableMoneyForCommand());
   399 
   382 
   400 	BEGIN_TILE_LOOP(tile2, size_x, size_y, tile) {
   383 	BEGIN_TILE_LOOP(tile2, size_x, size_y, tile) {
   401 		curh = TileHeight(tile2);
   384 		curh = TileHeight(tile2);
   402 		while (curh != h) {
   385 		while (curh != h) {
   403 			ret = DoCommand(tile2, 8, (curh > h) ? 0 : 1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND);
   386 			ret = DoCommand(tile2, SLOPE_N, (curh > h) ? 0 : 1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND);
   404 			if (CmdFailed(ret)) break;
   387 			if (CmdFailed(ret)) break;
   405 
   388 
   406 			if (flags & DC_EXEC) {
   389 			if (flags & DC_EXEC) {
   407 				money.AddCost(-ret.GetCost());
   390 				money.AddCost(-ret.GetCost());
   408 				if (money.GetCost() < 0) {
   391 				if (money.GetCost() < 0) {
   409 					_additional_cash_required = ret.GetCost();
   392 					_additional_cash_required = ret.GetCost();
   410 					return cost;
   393 					return cost;
   411 				}
   394 				}
   412 				DoCommand(tile2, 8, (curh > h) ? 0 : 1, flags, CMD_TERRAFORM_LAND);
   395 				DoCommand(tile2, SLOPE_N, (curh > h) ? 0 : 1, flags, CMD_TERRAFORM_LAND);
   413 			}
   396 			}
   414 
   397 
   415 			cost.AddCost(ret);
   398 			cost.AddCost(ret);
   416 			curh += (curh > h) ? -1 : 1;
   399 			curh += (curh > h) ? -1 : 1;
   417 		}
   400 		}
   431 CommandCost CmdPurchaseLandArea(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
   414 CommandCost CmdPurchaseLandArea(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
   432 {
   415 {
   433 	CommandCost cost;
   416 	CommandCost cost;
   434 
   417 
   435 	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
   418 	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
   436 
       
   437 	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
       
   438 
   419 
   439 	if (IsOwnedLandTile(tile) && IsTileOwner(tile, _current_player)) {
   420 	if (IsOwnedLandTile(tile) && IsTileOwner(tile, _current_player)) {
   440 		return_cmd_error(STR_5807_YOU_ALREADY_OWN_IT);
   421 		return_cmd_error(STR_5807_YOU_ALREADY_OWN_IT);
   441 	}
   422 	}
   442 
   423 
   802 }
   783 }
   803 
   784 
   804 void InitializeClearLand()
   785 void InitializeClearLand()
   805 {
   786 {
   806 	_opt.snow_line = _patches.snow_line_height * TILE_HEIGHT;
   787 	_opt.snow_line = _patches.snow_line_height * TILE_HEIGHT;
       
   788 }
       
   789 
       
   790 static CommandCost TerraformTile_Clear(TileIndex tile, uint32 flags, uint z_new, Slope tileh_new)
       
   791 {
       
   792 	return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
   807 }
   793 }
   808 
   794 
   809 extern const TileTypeProcs _tile_type_clear_procs = {
   795 extern const TileTypeProcs _tile_type_clear_procs = {
   810 	DrawTile_Clear,           ///< draw_tile_proc
   796 	DrawTile_Clear,           ///< draw_tile_proc
   811 	GetSlopeZ_Clear,          ///< get_slope_z_proc
   797 	GetSlopeZ_Clear,          ///< get_slope_z_proc
   818 	TileLoop_Clear,           ///< tile_loop_clear
   804 	TileLoop_Clear,           ///< tile_loop_clear
   819 	ChangeTileOwner_Clear,    ///< change_tile_owner_clear
   805 	ChangeTileOwner_Clear,    ///< change_tile_owner_clear
   820 	NULL,                     ///< get_produced_cargo_proc
   806 	NULL,                     ///< get_produced_cargo_proc
   821 	NULL,                     ///< vehicle_enter_tile_proc
   807 	NULL,                     ///< vehicle_enter_tile_proc
   822 	GetFoundation_Clear,      ///< get_foundation_proc
   808 	GetFoundation_Clear,      ///< get_foundation_proc
       
   809 	TerraformTile_Clear,      ///< terraform_tile_proc
   823 };
   810 };