src/clear_cmd.cpp
changeset 5835 e0ff603ae0b7
parent 5726 8f399788f6c9
child 5650 aefc131bf5ce
equal deleted inserted replaced
5834:7bf92d5a5a0f 5835:e0ff603ae0b7
       
     1 /* $Id$ */
       
     2 
       
     3 #include "stdafx.h"
       
     4 #include "openttd.h"
       
     5 #include "clear_map.h"
       
     6 #include "rail_map.h"
       
     7 #include "table/strings.h"
       
     8 #include "functions.h"
       
     9 #include "map.h"
       
    10 #include "player.h"
       
    11 #include "tile.h"
       
    12 #include "viewport.h"
       
    13 #include "command.h"
       
    14 #include "tunnel_map.h"
       
    15 #include "bridge_map.h"
       
    16 #include "variables.h"
       
    17 #include "table/sprites.h"
       
    18 #include "unmovable_map.h"
       
    19 #include "genworld.h"
       
    20 #include "industry.h"
       
    21 
       
    22 typedef struct TerraformerHeightMod {
       
    23 	TileIndex tile;
       
    24 	byte height;
       
    25 } TerraformerHeightMod;
       
    26 
       
    27 typedef struct TerraformerState {
       
    28 	int height[4];
       
    29 	uint32 flags;
       
    30 
       
    31 	int direction;
       
    32 	int modheight_count;
       
    33 	int tile_table_count;
       
    34 
       
    35 	int32 cost;
       
    36 
       
    37 	TileIndex *tile_table;
       
    38 	TerraformerHeightMod *modheight;
       
    39 
       
    40 } TerraformerState;
       
    41 
       
    42 static int TerraformAllowTileProcess(TerraformerState *ts, TileIndex tile)
       
    43 {
       
    44 	TileIndex *t;
       
    45 	int count;
       
    46 
       
    47 	if (TileX(tile) == MapMaxX() || TileY(tile) == MapMaxY()) return -1;
       
    48 
       
    49 	t = ts->tile_table;
       
    50 	for (count = ts->tile_table_count; count != 0; count--, t++) {
       
    51 		if (*t == tile) return 0;
       
    52 	}
       
    53 
       
    54 	return 1;
       
    55 }
       
    56 
       
    57 static int TerraformGetHeightOfTile(TerraformerState *ts, TileIndex tile)
       
    58 {
       
    59 	TerraformerHeightMod *mod = ts->modheight;
       
    60 	int count;
       
    61 
       
    62 	for (count = ts->modheight_count; count != 0; count--, mod++) {
       
    63 		if (mod->tile == tile) return mod->height;
       
    64 	}
       
    65 
       
    66 	return TileHeight(tile);
       
    67 }
       
    68 
       
    69 static void TerraformAddDirtyTile(TerraformerState *ts, TileIndex tile)
       
    70 {
       
    71 	int count;
       
    72 	TileIndex *t;
       
    73 
       
    74 	count = ts->tile_table_count;
       
    75 
       
    76 	if (count >= 625) return;
       
    77 
       
    78 	for (t = ts->tile_table; count != 0; count--,t++) {
       
    79 		if (*t == tile) return;
       
    80 	}
       
    81 
       
    82 	ts->tile_table[ts->tile_table_count++] = tile;
       
    83 }
       
    84 
       
    85 static void TerraformAddDirtyTileAround(TerraformerState *ts, TileIndex tile)
       
    86 {
       
    87 	TerraformAddDirtyTile(ts, tile + TileDiffXY( 0, -1));
       
    88 	TerraformAddDirtyTile(ts, tile + TileDiffXY(-1, -1));
       
    89 	TerraformAddDirtyTile(ts, tile + TileDiffXY(-1,  0));
       
    90 	TerraformAddDirtyTile(ts, tile);
       
    91 }
       
    92 
       
    93 static int TerraformProc(TerraformerState *ts, TileIndex tile, int mode)
       
    94 {
       
    95 	int r;
       
    96 	int32 ret;
       
    97 
       
    98 	assert(tile < MapSize());
       
    99 
       
   100 	r = TerraformAllowTileProcess(ts, tile);
       
   101 	if (r <= 0) return r;
       
   102 
       
   103 	if (IsTileType(tile, MP_RAILWAY)) {
       
   104 		static const TrackBits safe_track[] = { TRACK_BIT_LOWER, TRACK_BIT_LEFT, TRACK_BIT_UPPER, TRACK_BIT_RIGHT };
       
   105 		static const Slope unsafe_slope[] = { SLOPE_S, SLOPE_W, SLOPE_N, SLOPE_E };
       
   106 
       
   107 		Slope tileh;
       
   108 		uint z;
       
   109 
       
   110 		// Nothing could be built at the steep slope - this avoids a bug
       
   111 		// when you have a single diagonal track in one corner on a
       
   112 		// basement and then you raise/lower the other corner.
       
   113 		tileh = GetTileSlope(tile, &z);
       
   114 		if (tileh == unsafe_slope[mode] ||
       
   115 				tileh == ComplementSlope(unsafe_slope[mode])) {
       
   116 			_terraform_err_tile = tile;
       
   117 			_error_message = STR_1008_MUST_REMOVE_RAILROAD_TRACK;
       
   118 			return -1;
       
   119 		}
       
   120 
       
   121 		// If we have a single diagonal track there, the other side of
       
   122 		// tile can be terraformed.
       
   123 		if (IsPlainRailTile(tile) && GetTrackBits(tile) == safe_track[mode]) {
       
   124 			/* If terraforming downwards prevent damaging a potential tunnel below.
       
   125 			 * This check is only necessary for flat tiles, because if the tile is
       
   126 			 * non-flat, then the corner opposing the rail is raised. Only this corner
       
   127 			 * can be lowered and this is a safe action
       
   128 			 */
       
   129 			if (tileh == SLOPE_FLAT &&
       
   130 					ts->direction == -1 &&
       
   131 					IsTunnelInWay(tile, z - TILE_HEIGHT)) {
       
   132 				_terraform_err_tile = tile;
       
   133 				_error_message = STR_1002_EXCAVATION_WOULD_DAMAGE;
       
   134 				return -1;
       
   135 			}
       
   136 			return 0;
       
   137 		}
       
   138 	}
       
   139 
       
   140 	ret = DoCommand(tile, 0,0, ts->flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR);
       
   141 
       
   142 	if (CmdFailed(ret)) {
       
   143 		_terraform_err_tile = tile;
       
   144 		return -1;
       
   145 	}
       
   146 
       
   147 	ts->cost += ret;
       
   148 
       
   149 	if (ts->tile_table_count >= 625) return -1;
       
   150 	ts->tile_table[ts->tile_table_count++] = tile;
       
   151 
       
   152 	return 0;
       
   153 }
       
   154 
       
   155 static bool TerraformTileHeight(TerraformerState *ts, TileIndex tile, int height)
       
   156 {
       
   157 	int nh;
       
   158 	TerraformerHeightMod *mod;
       
   159 	int count;
       
   160 
       
   161 	assert(tile < MapSize());
       
   162 
       
   163 	if (height < 0) {
       
   164 		_error_message = STR_1003_ALREADY_AT_SEA_LEVEL;
       
   165 		return false;
       
   166 	}
       
   167 
       
   168 	_error_message = STR_1004_TOO_HIGH;
       
   169 
       
   170 	if (height > 15) return false;
       
   171 
       
   172 	nh = TerraformGetHeightOfTile(ts, tile);
       
   173 	if (nh < 0 || height == nh) return false;
       
   174 
       
   175 	if (TerraformProc(ts, tile, 0) < 0) return false;
       
   176 	if (TerraformProc(ts, tile + TileDiffXY( 0, -1), 1) < 0) return false;
       
   177 	if (TerraformProc(ts, tile + TileDiffXY(-1, -1), 2) < 0) return false;
       
   178 	if (TerraformProc(ts, tile + TileDiffXY(-1,  0), 3) < 0) return false;
       
   179 
       
   180 	mod = ts->modheight;
       
   181 	count = ts->modheight_count;
       
   182 
       
   183 	for (;;) {
       
   184 		if (count == 0) {
       
   185 			if (ts->modheight_count >= 576) return false;
       
   186 			ts->modheight_count++;
       
   187 			break;
       
   188 		}
       
   189 		if (mod->tile == tile) break;
       
   190 		mod++;
       
   191 		count--;
       
   192 	}
       
   193 
       
   194 	mod->tile = tile;
       
   195 	mod->height = (byte)height;
       
   196 
       
   197 	ts->cost += _price.terraform;
       
   198 
       
   199 	{
       
   200 		int direction = ts->direction, r;
       
   201 		const TileIndexDiffC *ttm;
       
   202 
       
   203 		static const TileIndexDiffC _terraform_tilepos[] = {
       
   204 			{ 1,  0},
       
   205 			{-2,  0},
       
   206 			{ 1,  1},
       
   207 			{ 0, -2}
       
   208 		};
       
   209 
       
   210 		for (ttm = _terraform_tilepos; ttm != endof(_terraform_tilepos); ttm++) {
       
   211 			tile += ToTileIndexDiff(*ttm);
       
   212 
       
   213 			r = TerraformGetHeightOfTile(ts, tile);
       
   214 			if (r != height && r-direction != height && r+direction != height) {
       
   215 				if (!TerraformTileHeight(ts, tile, r+direction))
       
   216 					return false;
       
   217 			}
       
   218 		}
       
   219 	}
       
   220 
       
   221 	return true;
       
   222 }
       
   223 
       
   224 /** Terraform land
       
   225  * @param tile tile to terraform
       
   226  * @param p1 corners to terraform.
       
   227  * @param p2 direction; eg up or down
       
   228  */
       
   229 int32 CmdTerraformLand(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
       
   230 {
       
   231 	TerraformerState ts;
       
   232 	TileIndex t;
       
   233 	int direction;
       
   234 
       
   235 	TerraformerHeightMod modheight_data[576];
       
   236 	TileIndex tile_table_data[625];
       
   237 
       
   238 	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
       
   239 
       
   240 	_terraform_err_tile = 0;
       
   241 
       
   242 	ts.direction = direction = p2 ? 1 : -1;
       
   243 	ts.flags = flags;
       
   244 	ts.modheight_count = ts.tile_table_count = 0;
       
   245 	ts.cost = 0;
       
   246 	ts.modheight = modheight_data;
       
   247 	ts.tile_table = tile_table_data;
       
   248 
       
   249 	/* Make an extra check for map-bounds cause we add tiles to the originating tile */
       
   250 	if (tile + TileDiffXY(1, 1) >= MapSize()) return CMD_ERROR;
       
   251 
       
   252 	if (p1 & 1) {
       
   253 		t = tile + TileDiffXY(1, 0);
       
   254 		if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) {
       
   255 			return CMD_ERROR;
       
   256 		}
       
   257 	}
       
   258 
       
   259 	if (p1 & 2) {
       
   260 		t = tile + TileDiffXY(1, 1);
       
   261 		if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) {
       
   262 			return CMD_ERROR;
       
   263 		}
       
   264 	}
       
   265 
       
   266 	if (p1 & 4) {
       
   267 		t = tile + TileDiffXY(0, 1);
       
   268 		if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) {
       
   269 			return CMD_ERROR;
       
   270 		}
       
   271 	}
       
   272 
       
   273 	if (p1 & 8) {
       
   274 		t = tile + TileDiffXY(0, 0);
       
   275 		if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) {
       
   276 			return CMD_ERROR;
       
   277 		}
       
   278 	}
       
   279 
       
   280 	{
       
   281 		/* Check if tunnel would take damage */
       
   282 		int count;
       
   283 		TileIndex *ti = ts.tile_table;
       
   284 
       
   285 		for (count = ts.tile_table_count; count != 0; count--, ti++) {
       
   286 			TileIndex tile = *ti;
       
   287 
       
   288 			if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) {
       
   289 				return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
       
   290 			}
       
   291 
       
   292 			if (direction == -1) {
       
   293 				uint z, t;
       
   294 
       
   295 				z = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 0));
       
   296 				t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 0));
       
   297 				if (t <= z) z = t;
       
   298 				t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 1));
       
   299 				if (t <= z) z = t;
       
   300 				t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 1));
       
   301 				if (t <= z) z = t;
       
   302 
       
   303 				if (IsTunnelInWay(tile, z * TILE_HEIGHT)) {
       
   304 					return_cmd_error(STR_1002_EXCAVATION_WOULD_DAMAGE);
       
   305 				}
       
   306 			}
       
   307 		}
       
   308 	}
       
   309 
       
   310 	if (flags & DC_EXEC) {
       
   311 		/* Clear the landscape at the tiles */
       
   312 		{
       
   313 			int count;
       
   314 			TileIndex *ti = ts.tile_table;
       
   315 			for (count = ts.tile_table_count; count != 0; count--, ti++) {
       
   316 				DoCommand(*ti, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
       
   317 			}
       
   318 		}
       
   319 
       
   320 		/* change the height */
       
   321 		{
       
   322 			int count;
       
   323 			TerraformerHeightMod *mod;
       
   324 
       
   325 			mod = ts.modheight;
       
   326 			for (count = ts.modheight_count; count != 0; count--, mod++) {
       
   327 				TileIndex til = mod->tile;
       
   328 
       
   329 				SetTileHeight(til, mod->height);
       
   330 				TerraformAddDirtyTileAround(&ts, til);
       
   331 			}
       
   332 		}
       
   333 
       
   334 		/* finally mark the dirty tiles dirty */
       
   335 		{
       
   336 			int count;
       
   337 			TileIndex *ti = ts.tile_table;
       
   338 			for (count = ts.tile_table_count; count != 0; count--, ti++) {
       
   339 				MarkTileDirtyByTile(*ti);
       
   340 			}
       
   341 		}
       
   342 	}
       
   343 	return ts.cost;
       
   344 }
       
   345 
       
   346 
       
   347 /** Levels a selected (rectangle) area of land
       
   348  * @param tile end tile of area-drag
       
   349  * @param p1 start tile of area drag
       
   350  * @param p2 unused
       
   351  */
       
   352 int32 CmdLevelLand(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
       
   353 {
       
   354 	int size_x, size_y;
       
   355 	int ex;
       
   356 	int ey;
       
   357 	int sx, sy;
       
   358 	uint h, curh;
       
   359 	int32 ret, cost, money;
       
   360 
       
   361 	if (p1 >= MapSize()) return CMD_ERROR;
       
   362 
       
   363 	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
       
   364 
       
   365 	// remember level height
       
   366 	h = TileHeight(p1);
       
   367 
       
   368 	// make sure sx,sy are smaller than ex,ey
       
   369 	ex = TileX(tile);
       
   370 	ey = TileY(tile);
       
   371 	sx = TileX(p1);
       
   372 	sy = TileY(p1);
       
   373 	if (ex < sx) intswap(ex, sx);
       
   374 	if (ey < sy) intswap(ey, sy);
       
   375 	tile = TileXY(sx, sy);
       
   376 
       
   377 	size_x = ex-sx+1;
       
   378 	size_y = ey-sy+1;
       
   379 
       
   380 	money = GetAvailableMoneyForCommand();
       
   381 	cost = 0;
       
   382 
       
   383 	BEGIN_TILE_LOOP(tile2, size_x, size_y, tile) {
       
   384 		curh = TileHeight(tile2);
       
   385 		while (curh != h) {
       
   386 			ret = DoCommand(tile2, 8, (curh > h) ? 0 : 1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND);
       
   387 			if (CmdFailed(ret)) break;
       
   388 			cost += ret;
       
   389 
       
   390 			if (flags & DC_EXEC) {
       
   391 				if ((money -= ret) < 0) {
       
   392 					_additional_cash_required = ret;
       
   393 					return cost - ret;
       
   394 				}
       
   395 				DoCommand(tile2, 8, (curh > h) ? 0 : 1, flags, CMD_TERRAFORM_LAND);
       
   396 			}
       
   397 
       
   398 			curh += (curh > h) ? -1 : 1;
       
   399 		}
       
   400 	} END_TILE_LOOP(tile2, size_x, size_y, tile)
       
   401 
       
   402 	return (cost == 0) ? CMD_ERROR : cost;
       
   403 }
       
   404 
       
   405 /** Purchase a land area. Actually you only purchase one tile, so
       
   406  * the name is a bit confusing ;p
       
   407  * @param tile the tile the player is purchasing
       
   408  * @param p1 unused
       
   409  * @param p2 unused
       
   410  */
       
   411 int32 CmdPurchaseLandArea(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
       
   412 {
       
   413 	int32 cost;
       
   414 
       
   415 	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
       
   416 
       
   417 	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
       
   418 
       
   419 	if (IsOwnedLandTile(tile) && IsTileOwner(tile, _current_player)) {
       
   420 		return_cmd_error(STR_5807_YOU_ALREADY_OWN_IT);
       
   421 	}
       
   422 
       
   423 	cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
       
   424 	if (CmdFailed(cost)) return CMD_ERROR;
       
   425 
       
   426 	if (flags & DC_EXEC) {
       
   427 		MakeOwnedLand(tile, _current_player);
       
   428 		MarkTileDirtyByTile(tile);
       
   429 	}
       
   430 
       
   431 	return cost + _price.purchase_land * 10;
       
   432 }
       
   433 
       
   434 
       
   435 static int32 ClearTile_Clear(TileIndex tile, byte flags)
       
   436 {
       
   437 	static const int32* clear_price_table[] = {
       
   438 		&_price.clear_1,
       
   439 		&_price.purchase_land,
       
   440 		&_price.clear_2,
       
   441 		&_price.clear_3,
       
   442 		&_price.purchase_land,
       
   443 		&_price.purchase_land,
       
   444 		&_price.clear_2, // XXX unused?
       
   445 	};
       
   446 	int32 price;
       
   447 
       
   448 	if (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) == 0) {
       
   449 		price = 0;
       
   450 	} else {
       
   451 		price = *clear_price_table[GetClearGround(tile)];
       
   452 	}
       
   453 
       
   454 	if (flags & DC_EXEC) DoClearSquare(tile);
       
   455 
       
   456 	return price;
       
   457 }
       
   458 
       
   459 /** Sell a land area. Actually you only sell one tile, so
       
   460  * the name is a bit confusing ;p
       
   461  * @param tile the tile the player is selling
       
   462  * @param p1 unused
       
   463  * @param p2 unused
       
   464  */
       
   465 int32 CmdSellLandArea(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
       
   466 {
       
   467 	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
       
   468 
       
   469 	if (!IsOwnedLandTile(tile)) return CMD_ERROR;
       
   470 	if (!CheckTileOwnership(tile) && _current_player != OWNER_WATER) return CMD_ERROR;
       
   471 
       
   472 
       
   473 	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
       
   474 
       
   475 	if (flags & DC_EXEC) DoClearSquare(tile);
       
   476 
       
   477 	return - _price.purchase_land * 2;
       
   478 }
       
   479 
       
   480 
       
   481 #include "table/clear_land.h"
       
   482 
       
   483 
       
   484 void DrawClearLandTile(const TileInfo *ti, byte set)
       
   485 {
       
   486 	DrawGroundSprite(SPR_FLAT_BARE_LAND + _tileh_to_sprite[ti->tileh] + set * 19);
       
   487 }
       
   488 
       
   489 void DrawHillyLandTile(const TileInfo *ti)
       
   490 {
       
   491 	if (ti->tileh != SLOPE_FLAT) {
       
   492 		DrawGroundSprite(SPR_FLAT_ROUGH_LAND + _tileh_to_sprite[ti->tileh]);
       
   493 	} else {
       
   494 		DrawGroundSprite(_landscape_clear_sprites[GB(ti->x ^ ti->y, 4, 3)]);
       
   495 	}
       
   496 }
       
   497 
       
   498 void DrawClearLandFence(const TileInfo *ti)
       
   499 {
       
   500 	byte z = ti->z;
       
   501 
       
   502 	if (ti->tileh & SLOPE_S) {
       
   503 		z += TILE_HEIGHT;
       
   504 		if (ti->tileh == SLOPE_STEEP_S) z += TILE_HEIGHT;
       
   505 	}
       
   506 
       
   507 	if (GetFenceSW(ti->tile) != 0) {
       
   508 		DrawGroundSpriteAt(_clear_land_fence_sprites_1[GetFenceSW(ti->tile) - 1] + _fence_mod_by_tileh[ti->tileh], ti->x, ti->y, z);
       
   509 	}
       
   510 
       
   511 	if (GetFenceSE(ti->tile) != 0) {
       
   512 		DrawGroundSpriteAt(_clear_land_fence_sprites_1[GetFenceSE(ti->tile) - 1] + _fence_mod_by_tileh_2[ti->tileh], ti->x, ti->y, z);
       
   513 	}
       
   514 }
       
   515 
       
   516 static void DrawTile_Clear(TileInfo *ti)
       
   517 {
       
   518 	switch (GetClearGround(ti->tile)) {
       
   519 		case CLEAR_GRASS:
       
   520 			DrawClearLandTile(ti, GetClearDensity(ti->tile));
       
   521 			break;
       
   522 
       
   523 		case CLEAR_ROUGH:
       
   524 			DrawHillyLandTile(ti);
       
   525 			break;
       
   526 
       
   527 		case CLEAR_ROCKS:
       
   528 			DrawGroundSprite(SPR_FLAT_ROCKY_LAND_1 + _tileh_to_sprite[ti->tileh]);
       
   529 			break;
       
   530 
       
   531 		case CLEAR_FIELDS:
       
   532 			DrawGroundSprite(_clear_land_sprites_1[GetFieldType(ti->tile)] + _tileh_to_sprite[ti->tileh]);
       
   533 			break;
       
   534 
       
   535 		case CLEAR_SNOW:
       
   536 			DrawGroundSprite(_clear_land_sprites_2[GetClearDensity(ti->tile)] + _tileh_to_sprite[ti->tileh]);
       
   537 			break;
       
   538 
       
   539 		case CLEAR_DESERT:
       
   540 			DrawGroundSprite(_clear_land_sprites_3[GetClearDensity(ti->tile)] + _tileh_to_sprite[ti->tileh]);
       
   541 			break;
       
   542 	}
       
   543 
       
   544 	DrawClearLandFence(ti);
       
   545 	DrawBridgeMiddle(ti);
       
   546 }
       
   547 
       
   548 static uint GetSlopeZ_Clear(TileIndex tile, uint x, uint y)
       
   549 {
       
   550 	uint z;
       
   551 	uint tileh = GetTileSlope(tile, &z);
       
   552 
       
   553 	return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
       
   554 }
       
   555 
       
   556 static Slope GetSlopeTileh_Clear(TileIndex tile, Slope tileh)
       
   557 {
       
   558 	return tileh;
       
   559 }
       
   560 
       
   561 static void GetAcceptedCargo_Clear(TileIndex tile, AcceptedCargo ac)
       
   562 {
       
   563 	/* unused */
       
   564 }
       
   565 
       
   566 static void AnimateTile_Clear(TileIndex tile)
       
   567 {
       
   568 	/* unused */
       
   569 }
       
   570 
       
   571 void TileLoopClearHelper(TileIndex tile)
       
   572 {
       
   573 	byte self;
       
   574 	byte neighbour;
       
   575 	TileIndex dirty = INVALID_TILE;
       
   576 
       
   577 	self = (IsTileType(tile, MP_CLEAR) && IsClearGround(tile, CLEAR_FIELDS));
       
   578 
       
   579 	neighbour = (IsTileType(TILE_ADDXY(tile, 1, 0), MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, 1, 0), CLEAR_FIELDS));
       
   580 	if (GetFenceSW(tile) == 0) {
       
   581 		if (self != neighbour) {
       
   582 			SetFenceSW(tile, 3);
       
   583 			dirty = tile;
       
   584 		}
       
   585 	} else {
       
   586 		if (self == 0 && neighbour == 0) {
       
   587 			SetFenceSW(tile, 0);
       
   588 			dirty = tile;
       
   589 		}
       
   590 	}
       
   591 
       
   592 	neighbour = (IsTileType(TILE_ADDXY(tile, 0, 1), MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, 0, 1), CLEAR_FIELDS));
       
   593 	if (GetFenceSE(tile) == 0) {
       
   594 		if (self != neighbour) {
       
   595 			SetFenceSE(tile, 3);
       
   596 			dirty = tile;
       
   597 		}
       
   598 	} else {
       
   599 		if (self == 0 && neighbour == 0) {
       
   600 			SetFenceSE(tile, 0);
       
   601 			dirty = tile;
       
   602 		}
       
   603 	}
       
   604 
       
   605 	if (dirty != INVALID_TILE) MarkTileDirtyByTile(dirty);
       
   606 }
       
   607 
       
   608 
       
   609 /* convert into snowy tiles */
       
   610 static void TileLoopClearAlps(TileIndex tile)
       
   611 {
       
   612 	int k = GetTileZ(tile) - _opt.snow_line + TILE_HEIGHT;
       
   613 
       
   614 	if (k < 0) { // well below the snow line
       
   615 		if (!IsClearGround(tile, CLEAR_SNOW)) return;
       
   616 		if (GetClearDensity(tile) == 0) SetClearGroundDensity(tile, CLEAR_GRASS, 3);
       
   617 	} else {
       
   618 		if (!IsClearGround(tile, CLEAR_SNOW)) {
       
   619 			SetClearGroundDensity(tile, CLEAR_SNOW, 0);
       
   620 		} else {
       
   621 			uint density = min((uint)k / TILE_HEIGHT, 3);
       
   622 
       
   623 			if (GetClearDensity(tile) < density) {
       
   624 				AddClearDensity(tile, 1);
       
   625 			} else if (GetClearDensity(tile) > density) {
       
   626 				AddClearDensity(tile, -1);
       
   627 			} else {
       
   628 				return;
       
   629 			}
       
   630 		}
       
   631 	}
       
   632 
       
   633 	MarkTileDirtyByTile(tile);
       
   634 }
       
   635 
       
   636 static void TileLoopClearDesert(TileIndex tile)
       
   637 {
       
   638 	if (IsClearGround(tile, CLEAR_DESERT)) return;
       
   639 
       
   640 	if (GetTropicZone(tile) == TROPICZONE_DESERT) {
       
   641 		SetClearGroundDensity(tile, CLEAR_DESERT, 3);
       
   642 	} else {
       
   643 		if (GetTropicZone(tile + TileDiffXY( 1,  0)) != TROPICZONE_DESERT &&
       
   644 				GetTropicZone(tile + TileDiffXY(-1,  0)) != TROPICZONE_DESERT &&
       
   645 				GetTropicZone(tile + TileDiffXY( 0,  1)) != TROPICZONE_DESERT &&
       
   646 				GetTropicZone(tile + TileDiffXY( 0, -1)) != TROPICZONE_DESERT)
       
   647 			return;
       
   648 		SetClearGroundDensity(tile, CLEAR_DESERT, 1);
       
   649 	}
       
   650 
       
   651 	MarkTileDirtyByTile(tile);
       
   652 }
       
   653 
       
   654 static void TileLoop_Clear(TileIndex tile)
       
   655 {
       
   656 	TileLoopClearHelper(tile);
       
   657 
       
   658 	switch (_opt.landscape) {
       
   659 		case LT_DESERT: TileLoopClearDesert(tile); break;
       
   660 		case LT_HILLY:  TileLoopClearAlps(tile);   break;
       
   661 	}
       
   662 
       
   663 	switch (GetClearGround(tile)) {
       
   664 		case CLEAR_GRASS:
       
   665 			if (GetClearDensity(tile) == 3) return;
       
   666 
       
   667 			if (_game_mode != GM_EDITOR) {
       
   668 				if (GetClearCounter(tile) < 7) {
       
   669 					AddClearCounter(tile, 1);
       
   670 					return;
       
   671 				} else {
       
   672 					SetClearCounter(tile, 0);
       
   673 					AddClearDensity(tile, 1);
       
   674 				}
       
   675 			} else {
       
   676 				SetClearGroundDensity(tile, GB(Random(), 0, 8) > 21 ? CLEAR_GRASS : CLEAR_ROUGH, 3);
       
   677 			}
       
   678 			break;
       
   679 
       
   680 		case CLEAR_FIELDS: {
       
   681 			uint field_type;
       
   682 
       
   683 			if (_game_mode == GM_EDITOR) return;
       
   684 
       
   685 			if (GetClearCounter(tile) < 7) {
       
   686 				AddClearCounter(tile, 1);
       
   687 				return;
       
   688 			} else {
       
   689 				SetClearCounter(tile, 0);
       
   690 			}
       
   691 
       
   692 			if (GetIndustryIndexOfField(tile) == INVALID_INDUSTRY && GetFieldType(tile) >= 7) {
       
   693 				/* This farmfield is no longer farmfield, so make it grass again */
       
   694 				MakeClear(tile, CLEAR_GRASS, 2);
       
   695 			} else {
       
   696 				field_type = GetFieldType(tile);
       
   697 				field_type = (field_type < 8) ? field_type + 1 : 0;
       
   698 				SetFieldType(tile, field_type);
       
   699 			}
       
   700 			break;
       
   701 		}
       
   702 
       
   703 		default:
       
   704 			return;
       
   705 	}
       
   706 
       
   707 	MarkTileDirtyByTile(tile);
       
   708 }
       
   709 
       
   710 void GenerateClearTile(void)
       
   711 {
       
   712 	uint i, gi;
       
   713 	TileIndex tile;
       
   714 
       
   715 	/* add rough tiles */
       
   716 	i = ScaleByMapSize(GB(Random(), 0, 10) + 0x400);
       
   717 	gi = ScaleByMapSize(GB(Random(), 0, 7) + 0x80);
       
   718 
       
   719 	SetGeneratingWorldProgress(GWP_ROUGH_ROCKY, gi + i);
       
   720 	do {
       
   721 		IncreaseGeneratingWorldProgress(GWP_ROUGH_ROCKY);
       
   722 		tile = RandomTile();
       
   723 		if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_DESERT)) SetClearGroundDensity(tile, CLEAR_ROUGH, 3);
       
   724 	} while (--i);
       
   725 
       
   726 	/* add rocky tiles */
       
   727 	i = gi;
       
   728 	do {
       
   729 		uint32 r = Random();
       
   730 		tile = RandomTileSeed(r);
       
   731 
       
   732 		IncreaseGeneratingWorldProgress(GWP_ROUGH_ROCKY);
       
   733 		if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_DESERT)) {
       
   734 			uint j = GB(r, 16, 4) + 5;
       
   735 			for (;;) {
       
   736 				TileIndex tile_new;
       
   737 
       
   738 				SetClearGroundDensity(tile, CLEAR_ROCKS, 3);
       
   739 				do {
       
   740 					if (--j == 0) goto get_out;
       
   741 					tile_new = tile + TileOffsByDiagDir(GB(Random(), 0, 2));
       
   742 				} while (!IsTileType(tile_new, MP_CLEAR) || IsClearGround(tile_new, CLEAR_DESERT));
       
   743 				tile = tile_new;
       
   744 			}
       
   745 get_out:;
       
   746 		}
       
   747 	} while (--i);
       
   748 }
       
   749 
       
   750 static void ClickTile_Clear(TileIndex tile)
       
   751 {
       
   752 	/* not used */
       
   753 }
       
   754 
       
   755 static uint32 GetTileTrackStatus_Clear(TileIndex tile, TransportType mode)
       
   756 {
       
   757 	return 0;
       
   758 }
       
   759 
       
   760 static const StringID _clear_land_str[] = {
       
   761 	STR_080D_GRASS,
       
   762 	STR_080B_ROUGH_LAND,
       
   763 	STR_080A_ROCKS,
       
   764 	STR_080E_FIELDS,
       
   765 	STR_080F_SNOW_COVERED_LAND,
       
   766 	STR_0810_DESERT
       
   767 };
       
   768 
       
   769 static void GetTileDesc_Clear(TileIndex tile, TileDesc *td)
       
   770 {
       
   771 	if (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) == 0) {
       
   772 		td->str = STR_080C_BARE_LAND;
       
   773 	} else {
       
   774 		td->str = _clear_land_str[GetClearGround(tile)];
       
   775 	}
       
   776 	td->owner = GetTileOwner(tile);
       
   777 }
       
   778 
       
   779 static void ChangeTileOwner_Clear(TileIndex tile, PlayerID old_player, PlayerID new_player)
       
   780 {
       
   781 	return;
       
   782 }
       
   783 
       
   784 void InitializeClearLand(void)
       
   785 {
       
   786 	_opt.snow_line = _patches.snow_line_height * TILE_HEIGHT;
       
   787 }
       
   788 
       
   789 const TileTypeProcs _tile_type_clear_procs = {
       
   790 	DrawTile_Clear,           /* draw_tile_proc */
       
   791 	GetSlopeZ_Clear,          /* get_slope_z_proc */
       
   792 	ClearTile_Clear,          /* clear_tile_proc */
       
   793 	GetAcceptedCargo_Clear,   /* get_accepted_cargo_proc */
       
   794 	GetTileDesc_Clear,        /* get_tile_desc_proc */
       
   795 	GetTileTrackStatus_Clear, /* get_tile_track_status_proc */
       
   796 	ClickTile_Clear,          /* click_tile_proc */
       
   797 	AnimateTile_Clear,        /* animate_tile_proc */
       
   798 	TileLoop_Clear,           /* tile_loop_clear */
       
   799 	ChangeTileOwner_Clear,    /* change_tile_owner_clear */
       
   800 	NULL,                     /* get_produced_cargo_proc */
       
   801 	NULL,                     /* vehicle_enter_tile_proc */
       
   802 	GetSlopeTileh_Clear,      /* get_slope_tileh_proc */
       
   803 };