(svn r3514) -Codechange: Replace direct fiddling of bits for the ground type and density of clear tiles with symbolic names and accessors.
authortron
Wed, 01 Feb 2006 15:31:21 +0000
changeset 2955 27221592ebbc
parent 2954 5a55071e0b50
child 2956 ea79669b71f9
(svn r3514) -Codechange: Replace direct fiddling of bits for the ground type and density of clear tiles with symbolic names and accessors.
See clear.h for details
clear.h
clear_cmd.c
industry_cmd.c
landscape.c
smallmap_gui.c
terraform_gui.c
tree_cmd.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/clear.h	Wed Feb 01 15:31:21 2006 +0000
@@ -0,0 +1,36 @@
+/* $Id$ */
+
+#ifndef CLEAR_H
+#define CLEAR_H
+
+#include "macros.h"
+
+/* ground type, m5 bits 2...4
+ * valid densities (bits 0...1) in comments after the enum
+ */
+typedef enum ClearGround {
+	CL_GRASS  = 0, // 0-3
+	CL_ROUGH  = 1, // 3
+	CL_ROCKS  = 2, // 3
+	CL_FIELDS = 3, // 3
+	CL_SNOW   = 4, // 0-3
+	CL_DESERT = 5  // 1,3
+} ClearGround;
+
+static inline ClearGround GetClearGround(TileIndex t) { return GB(_m[t].m5, 2, 3); }
+static inline bool IsClearGround(TileIndex t, ClearGround ct) { return GetClearGround(t) == ct; }
+
+static inline void AddClearDensity(TileIndex t, int d) { _m[t].m5 += d; }
+static inline uint GetClearDensity(TileIndex t) { return GB(_m[t].m5, 0, 2); }
+
+static inline void AddClearCounter(TileIndex t, int c) { _m[t].m5 += c << 5; }
+static inline uint GetClearCounter(TileIndex t) { return GB(_m[t].m5, 5, 3); }
+static inline void SetClearCounter(TileIndex t, uint c) { SB(_m[t].m5, 5, 3, c); }
+
+/* Sets type and density in one go, also sets the counter to 0 */
+static inline void SetClearGroundDensity(TileIndex t, ClearGround type, uint density)
+{
+	_m[t].m5 = 0 << 5 | type << 2 | density;
+}
+
+#endif
--- a/clear_cmd.c	Wed Feb 01 09:11:31 2006 +0000
+++ b/clear_cmd.c	Wed Feb 01 15:31:21 2006 +0000
@@ -2,6 +2,7 @@
 
 #include "stdafx.h"
 #include "openttd.h"
+#include "clear.h"
 #include "table/strings.h"
 #include "functions.h"
 #include "map.h"
@@ -413,42 +414,26 @@
 
 static int32 ClearTile_Clear(TileIndex tile, byte flags)
 {
-	static const int32 null = 0;
 	static const int32* clear_price_table[] = {
-		&null,
-		&_price.clear_1,
-		&_price.clear_1,
 		&_price.clear_1,
 		&_price.purchase_land,
-		&_price.purchase_land,
-		&_price.purchase_land,
-		&_price.purchase_land,
-		&_price.clear_2,
 		&_price.clear_2,
-		&_price.clear_2,
-		&_price.clear_2,
-		&_price.clear_3,
-		&_price.clear_3,
-		&_price.clear_3,
 		&_price.clear_3,
 		&_price.purchase_land,
 		&_price.purchase_land,
-		&_price.purchase_land,
-		&_price.purchase_land,
-		&_price.purchase_land,
-		&_price.purchase_land,
-		&_price.purchase_land,
-		&_price.purchase_land,
-		&_price.clear_2,
-		&_price.clear_2,
-		&_price.clear_2,
-		&_price.clear_2,
+		&_price.clear_2, // XXX unused?
 	};
-	const int32 *price = clear_price_table[GB(_m[tile].m5, 0, 5)];
+	int32 price;
+
+	if (IsClearGround(tile, CL_GRASS) && GetClearDensity(tile) == 0) {
+		price = 0;
+	} else {
+		price = *clear_price_table[GetClearGround(tile)];
+	}
 
 	if (flags & DC_EXEC) DoClearSquare(tile);
 
-	return *price;
+	return price;
 }
 
 /** Sell a land area. Actually you only sell one tile, so
@@ -517,29 +502,29 @@
 static void DrawTile_Clear(TileInfo *ti)
 {
 	switch (GB(ti->map5, 2, 3)) {
-	case 0:
-		DrawClearLandTile(ti, GB(ti->map5, 0, 2));
-		break;
-
-	case 1:
-		DrawHillyLandTile(ti);
-		break;
+		case CL_GRASS:
+			DrawClearLandTile(ti, GB(ti->map5, 0, 2));
+			break;
 
-	case 2:
-		DrawGroundSprite(SPR_FLAT_ROCKY_LAND_1 + _tileh_to_sprite[ti->tileh]);
-		break;
+		case CL_ROUGH:
+			DrawHillyLandTile(ti);
+			break;
 
-	case 3:
-		DrawGroundSprite(_clear_land_sprites_1[GB(_m[ti->tile].m3, 0, 4)] + _tileh_to_sprite[ti->tileh]);
-		break;
+		case CL_ROCKS:
+			DrawGroundSprite(SPR_FLAT_ROCKY_LAND_1 + _tileh_to_sprite[ti->tileh]);
+			break;
 
-	case 4:
-		DrawGroundSprite(_clear_land_sprites_2[GB(ti->map5, 0, 2)] + _tileh_to_sprite[ti->tileh]);
-		break;
+		case CL_FIELDS:
+			DrawGroundSprite(_clear_land_sprites_1[GB(_m[ti->tile].m3, 0, 4)] + _tileh_to_sprite[ti->tileh]);
+			break;
 
-	case 5:
-		DrawGroundSprite(_clear_land_sprites_3[GB(ti->map5, 0, 2)] + _tileh_to_sprite[ti->tileh]);
-		break;
+		case CL_SNOW:
+			DrawGroundSprite(_clear_land_sprites_2[GB(ti->map5, 0, 2)] + _tileh_to_sprite[ti->tileh]);
+			break;
+
+		case CL_DESERT:
+			DrawGroundSprite(_clear_land_sprites_3[GB(ti->map5, 0, 2)] + _tileh_to_sprite[ti->tileh]);
+			break;
 	}
 
 	DrawClearLandFence(ti);
@@ -571,26 +556,9 @@
 	byte neighbour;
 	TileIndex dirty = INVALID_TILE;
 
-	switch (GetTileType(tile)) {
-		case MP_CLEAR:
-			self = (GB(_m[tile].m5, 0, 5) == 15);
-			break;
-
-		default:
-			self = 0;
-			break;
-	}
+	self = (IsTileType(tile, MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, 1, 0), CL_FIELDS));
 
-	switch (GetTileType(TILE_ADDXY(tile, 1, 0))) {
-		case MP_CLEAR:
-			neighbour = (GB(_m[TILE_ADDXY(tile, 1, 0)].m5, 0, 5) == 15);
-			break;
-
-		default:
-			neighbour = 0;
-			break;
-	}
-
+	neighbour = (IsTileType(TILE_ADDXY(tile, 1, 0), MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, 1, 0), CL_FIELDS));
 	if (GB(_m[tile].m4, 5, 3) == 0) {
 		if (self != neighbour) {
 			SB(_m[tile].m4, 5, 3, 3);
@@ -603,16 +571,7 @@
 		}
 	}
 
-	switch (GetTileType(TILE_ADDXY(tile, 0, 1))) {
-		case MP_CLEAR:
-			neighbour = (GB(_m[TILE_ADDXY(tile, 0, 1)].m5, 0, 5) == 15);
-			break;
-
-		default:
-			neighbour = 0;
-			break;
-	}
-
+	neighbour = (IsTileType(TILE_ADDXY(tile, 0, 1), MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, 0, 1), CL_FIELDS));
 	if (GB(_m[tile].m4, 2, 3) == 0) {
 		if (self != neighbour) {
 			SB(_m[tile].m4, 2, 3, 3);
@@ -632,78 +591,44 @@
 /* convert into snowy tiles */
 static void TileLoopClearAlps(TileIndex tile)
 {
-	int k;
-	byte m5,tmp;
-
 	/* distance from snow line, in steps of 8 */
-	k = GetTileZ(tile) - _opt.snow_line;
-
-	m5 = _m[tile].m5 & 0x1C;
-	tmp = _m[tile].m5 & 3;
+	int k = GetTileZ(tile) - _opt.snow_line;
 
-	if (k < -8) {
-		/* snow_m2_down */
-		if (m5 != 0x10)
-			return;
-		if (tmp == 0)
-			m5 = 3;
-	} else if (k == -8) {
-		/* snow_m1 */
-		if (m5 != 0x10) {
-			m5 = 0x10;
-		} else if (tmp != 0) {
-			m5 = (tmp - 1) + 0x10;
-		} else
-			return;
-	} else if (k < 8) {
-		/* snow_0 */
-		if (m5 != 0x10) {
-			m5 = 0x10;
-		} else if (tmp != 1) {
-			m5 = 1;
-			if (tmp != 0)
-				m5 = tmp - 1;
-			m5 += 0x10;
-		} else
-			return;
-	} else if (k == 8) {
-		/* snow_p1 */
-		if (m5 != 0x10) {
-			m5 = 0x10;
-		} else if (tmp != 2) {
-			m5 = 2;
-			if (tmp <= 2)
-				m5 = tmp + 1;
-			m5 += 0x10;
-		} else
-			return;
+	if (k < -8) { // well below the snow line
+		if (!IsClearGround(tile, CL_SNOW)) return;
+		if (GetClearDensity(tile) == 0) SetClearGroundDensity(tile, CL_GRASS, 3);
 	} else {
-		/* snow_p2_up */
-		if (m5 != 0x10) {
-			m5 = 0x10;
-		} else if (tmp != 3) {
-			m5 = tmp + 1 + 0x10;
-		} else
-			return;
+		if (!IsClearGround(tile, CL_SNOW)) {
+			SetClearGroundDensity(tile, CL_SNOW, 0);
+		} else {
+			uint density = min((uint)(k + 8) / 8, 3);
+
+			if (GetClearDensity(tile) < density) {
+				AddClearDensity(tile, 1);
+			} else if (GetClearDensity(tile) > density) {
+				AddClearDensity(tile, -1);
+			} else {
+				return;
+			}
+		}
 	}
 
-	_m[tile].m5 = m5;
 	MarkTileDirtyByTile(tile);
 }
 
 static void TileLoopClearDesert(TileIndex tile)
 {
- 	if ((_m[tile].m5 & 0x1C) == 0x14) return;
+	if (IsClearGround(tile, CL_DESERT)) return;
 
 	if (GetMapExtraBits(tile) == 1) {
-		_m[tile].m5 = 0x17;
+		SetClearGroundDensity(tile, CL_DESERT, 3);
 	} else {
 		if (GetMapExtraBits(tile + TileDiffXY( 1,  0)) != 1 &&
 				GetMapExtraBits(tile + TileDiffXY(-1,  0)) != 1 &&
 				GetMapExtraBits(tile + TileDiffXY( 0,  1)) != 1 &&
 				GetMapExtraBits(tile + TileDiffXY( 0, -1)) != 1)
 			return;
-		_m[tile].m5 = 0x15;
+		SetClearGroundDensity(tile, CL_DESERT, 1);
 	}
 
 	MarkTileDirtyByTile(tile);
@@ -711,8 +636,6 @@
 
 static void TileLoop_Clear(TileIndex tile)
 {
-	byte m5,m3;
-
 	TileLoopClearHelper(tile);
 
 	if (_opt.landscape == LT_DESERT) {
@@ -721,41 +644,45 @@
 		TileLoopClearAlps(tile);
 	}
 
-	m5 = _m[tile].m5;
-	if ((m5 & 0x1C) == 0x10 || (m5 & 0x1C) == 0x14) return;
-
-	if ((m5 & 0x1C) != 0xC) {
-		if ((m5 & 3) == 3) return;
+	switch (GetClearGround(tile)) {
+		case CL_GRASS:
+			if (GetClearDensity(tile) == 3) return;
 
-		if (_game_mode != GM_EDITOR) {
-			m5 += 0x20;
-			if (m5 >= 0x20) {
-				// Didn't overflow
-				_m[tile].m5 = m5;
-				return;
+			if (_game_mode != GM_EDITOR) {
+				if (GetClearCounter(tile) < 7) {
+					AddClearCounter(tile, 1);
+					return;
+				} else {
+					SetClearCounter(tile, 0);
+					AddClearDensity(tile, 1);
+				}
+			} else {
+				SetClearGroundDensity(tile, GB(Random(), 0, 8) > 21 ? CL_GRASS : CL_ROUGH, 3);
 			}
-			/* did overflow, so continue */
-		} else {
-			m5 = (GB(Random(), 0, 8) > 21) ? 2 : 6;
+			break;
+
+		case CL_FIELDS: {
+			uint field_type;
+
+			if (_game_mode == GM_EDITOR) return;
+
+			if (GetClearCounter(tile) < 7) {
+				AddClearCounter(tile, 1);
+				return;
+			} else {
+				SetClearCounter(tile, 0);
+			}
+
+			field_type = GB(_m[tile].m3, 0, 4);
+			field_type = (field_type < 8) ? field_type + 1 : 0;
+			SB(_m[tile].m3, 0, 4, field_type);
+			break;
 		}
-		m5++;
-	} else if (_game_mode != GM_EDITOR) {
-		/* handle farm field */
-		m5 += 0x20;
-		if (m5 >= 0x20) {
-			// Didn't overflow
-			_m[tile].m5 = m5;
+
+		default:
 			return;
-		}
-		/* overflowed */
-		m3 = _m[tile].m3 + 1;
-		assert( (m3 & 0xF) != 0);
-		if ( (m3 & 0xF) >= 9) /* NOTE: will not work properly if m3&0xF == 0xF */
-			m3 &= ~0xF;
-		_m[tile].m3 = m3;
 	}
 
-	_m[tile].m5 = m5;
 	MarkTileDirtyByTile(tile);
 }
 
@@ -768,7 +695,7 @@
 	i = ScaleByMapSize(GB(Random(), 0, 10) + 0x400);
 	do {
 		tile = RandomTile();
-		if (IsTileType(tile, MP_CLEAR)) SB(_m[tile].m5, 2, 2, 1);
+		if (IsTileType(tile, MP_CLEAR)) SetClearGroundDensity(tile, CL_ROUGH, 3);
 	} while (--i);
 
 	/* add grey squares */
@@ -781,7 +708,7 @@
 			for (;;) {
 				TileIndex tile_new;
 
-				SB(_m[tile].m5, 2, 2, 2);
+				SetClearGroundDensity(tile, CL_ROCKS, 3);
 				do {
 					if (--j == 0) goto get_out;
 					tile_new = tile + TileOffsByDir(GB(Random(), 0, 2));
@@ -804,24 +731,21 @@
 }
 
 static const StringID _clear_land_str[] = {
+	STR_080D_GRASS,
 	STR_080B_ROUGH_LAND,
 	STR_080A_ROCKS,
 	STR_080E_FIELDS,
 	STR_080F_SNOW_COVERED_LAND,
-	STR_0810_DESERT,
-	0,
-	0,
-	STR_080C_BARE_LAND,
-	STR_080D_GRASS,
-	STR_080D_GRASS,
-	STR_080D_GRASS,
+	STR_0810_DESERT
 };
 
 static void GetTileDesc_Clear(TileIndex tile, TileDesc *td)
 {
-	uint i = GB(_m[tile].m5, 2, 3);
-	if (i == 0) i = GB(_m[tile].m5, 0, 2) + 8;
-	td->str = _clear_land_str[i - 1];
+	if (IsClearGround(tile, CL_GRASS) && GetClearDensity(tile) == 0) {
+		td->str = STR_080C_BARE_LAND;
+	} else {
+		td->str = _clear_land_str[GetClearGround(tile)];
+	}
 	td->owner = GetTileOwner(tile);
 }
 
--- a/industry_cmd.c	Wed Feb 01 09:11:31 2006 +0000
+++ b/industry_cmd.c	Wed Feb 01 15:31:21 2006 +0000
@@ -2,6 +2,7 @@
 
 #include "stdafx.h"
 #include "openttd.h"
+#include "clear.h"
 #include "table/strings.h"
 #include "table/sprites.h"
 #include "functions.h"
@@ -885,32 +886,18 @@
 static bool IsBadFarmFieldTile(TileIndex tile)
 {
 	switch (GetTileType(tile)) {
-		case MP_CLEAR: {
-			byte m5 = _m[tile].m5 & 0x1C;
-			return m5 == 0xC || m5 == 0x10;
-		}
-
-		case MP_TREES:
-			return false;
-
-		default:
-			return true;
+		case MP_CLEAR: return IsClearGround(tile, CL_FIELDS) || IsClearGround(tile, CL_SNOW);
+		case MP_TREES: return false;
+		default:       return true;
 	}
 }
 
 static bool IsBadFarmFieldTile2(TileIndex tile)
 {
 	switch (GetTileType(tile)) {
-		case MP_CLEAR: {
-			byte m5 = _m[tile].m5 & 0x1C;
-			return m5 == 0x10;
-		}
-
-		case MP_TREES:
-			return false;
-
-		default:
-			return true;
+		case MP_CLEAR: return IsClearGround(tile, CL_SNOW);
+		case MP_TREES: return false;
+		default:       return true;
 	}
 }
 
--- a/landscape.c	Wed Feb 01 09:11:31 2006 +0000
+++ b/landscape.c	Wed Feb 01 15:31:21 2006 +0000
@@ -2,6 +2,7 @@
 
 #include "stdafx.h"
 #include "openttd.h"
+#include "clear.h"
 #include "functions.h"
 #include "map.h"
 #include "player.h"
@@ -237,12 +238,13 @@
 
 void DoClearSquare(TileIndex tile)
 {
-	ModifyTile(tile,
-		MP_SETTYPE(MP_CLEAR) |
-		MP_MAP2_CLEAR | MP_MAP3LO_CLEAR | MP_MAP3HI_CLEAR | MP_MAPOWNER | MP_MAP5,
-		OWNER_NONE, /* map_owner */
-		_generating_world ? 3 : 0 /* map5 */
-	);
+	SetTileType(tile, MP_CLEAR);
+	SetTileOwner(tile, OWNER_NONE);
+	_m[tile].m2 = 0;
+	_m[tile].m3 = 0;
+	_m[tile].m4 = 0;
+	SetClearGroundDensity(tile, CL_GRASS, _generating_world ? 3 : 0);
+	MarkTileDirtyByTile(tile);
 }
 
 uint32 GetTileTrackStatus(TileIndex tile, TransportType mode)
@@ -615,7 +617,7 @@
 		for (data = _make_desert_or_rainforest_data;
 				data != endof(_make_desert_or_rainforest_data); ++data) {
 			TileIndex t = TILE_MASK(tile + ToTileIndexDiff(*data));
-			if (IsTileType(t, MP_CLEAR) && (_m[t].m5 & 0x1c) == 0x14) break;
+			if (IsTileType(t, MP_CLEAR) && IsClearGround(t, CL_DESERT)) break;
 		}
 		if (data == endof(_make_desert_or_rainforest_data))
 			SetMapExtraBits(tile, 2);
--- a/smallmap_gui.c	Wed Feb 01 09:11:31 2006 +0000
+++ b/smallmap_gui.c	Wed Feb 01 15:31:21 2006 +0000
@@ -2,6 +2,7 @@
 
 #include "stdafx.h"
 #include "openttd.h"
+#include "clear.h"
 #include "functions.h"
 #include "spritecache.h"
 #include "table/strings.h"
@@ -458,12 +459,8 @@
 }
 
 
-static const uint32 _vegetation_clear_bits[4 + 7] = {
-	MKCOLOR(0x37373737), ///< bare land
-	MKCOLOR(0x37373737), ///< 1/3 grass
-	MKCOLOR(0x37373737), ///< 2/3 grass
+static const uint32 _vegetation_clear_bits[] = {
 	MKCOLOR(0x54545454), ///< full grass
-
 	MKCOLOR(0x52525252), ///< rough land
 	MKCOLOR(0x0A0A0A0A), ///< rocks
 	MKCOLOR(0x25252525), ///< fields
@@ -476,14 +473,15 @@
 static inline uint32 GetSmallMapVegetationPixels(TileIndex tile)
 {
 	TileType t = GetEffectiveTileType(tile);
-	int i;
 	uint32 bits;
 
 	switch (t) {
 		case MP_CLEAR:
-			i = (_m[tile].m5 & 0x1F) - 4;
-			if (i >= 0) i >>= 2;
-			bits = _vegetation_clear_bits[i + 4];
+			if (IsClearGround(tile, CL_GRASS) && GetClearDensity(tile) < 3) {
+				bits = MKCOLOR(0x37373737);
+			} else {
+				bits = _vegetation_clear_bits[GetClearGround(tile)];
+			}
 			break;
 
 		case MP_INDUSTRY:
--- a/terraform_gui.c	Wed Feb 01 09:11:31 2006 +0000
+++ b/terraform_gui.c	Wed Feb 01 15:31:21 2006 +0000
@@ -2,6 +2,7 @@
 
 #include "stdafx.h"
 #include "openttd.h"
+#include "clear.h"
 #include "table/sprites.h"
 #include "table/strings.h"
 #include "functions.h"
@@ -81,7 +82,9 @@
 
 	BEGIN_TILE_LOOP(tile, size_x, size_y, TileXY(sx, sy)) {
 		if (IsTileType(tile, MP_CLEAR) || IsTileType(tile, MP_TREES)) {
-			ModifyTile(tile, MP_SETTYPE(MP_CLEAR) | MP_MAP5, (_m[tile].m5 & ~0x1C) | 0xB);
+			SetTileType(tile, MP_CLEAR);
+			SetClearGroundDensity(tile, CL_ROCKS, 3);
+			MarkTileDirtyByTile(tile);
 			success = true;
 		}
 	} END_TILE_LOOP(tile, size_x, size_y, 0);
--- a/tree_cmd.c	Wed Feb 01 09:11:31 2006 +0000
+++ b/tree_cmd.c	Wed Feb 01 15:31:21 2006 +0000
@@ -2,6 +2,7 @@
 
 #include "stdafx.h"
 #include "openttd.h"
+#include "clear.h"
 #include "table/strings.h"
 #include "table/sprites.h"
 #include "table/tree_land.h"
@@ -73,10 +74,10 @@
 		uint dist = myabs(x) + myabs(y);
 		TileIndex cur_tile = TILE_MASK(tile + TileDiffXY(x, y));
 
-		/* Only on tiles within 13 squares from tile,
-		    on clear tiles, and NOT on farm-tiles or rocks */
-		if (dist <= 13 && IsTileType(cur_tile, MP_CLEAR) &&
-			 (_m[cur_tile].m5 & 0x1F) != 0x0F && (_m[cur_tile].m5 & 0x1C) != 8) {
+		if (dist <= 13 &&
+				IsTileType(cur_tile, MP_CLEAR) &&
+				!IsClearGround(cur_tile, CL_FIELDS) &&
+				!IsClearGround(cur_tile, CL_ROCKS)) {
 			PlaceTree(cur_tile, r, dist <= 6 ? 0xC0 : 0);
 		}
 	}
@@ -98,8 +99,9 @@
 	do {
 		uint32 r = Random();
 		TileIndex tile = RandomTileSeed(r);
-		/* Only on clear tiles, and NOT on farm-tiles or rocks */
-		if (IsTileType(tile, MP_CLEAR) && (_m[tile].m5 & 0x1F) != 0x0F && (_m[tile].m5 & 0x1C) != 8) {
+		if (IsTileType(tile, MP_CLEAR) &&
+				!IsClearGround(tile, CL_FIELDS) &&
+				!IsClearGround(tile, CL_ROCKS)) {
 			PlaceTree(tile, r, 0);
 		}
 	} while (--i);
@@ -182,11 +184,11 @@
 						continue;
 					}
 
-					// it's expensive to clear farmland
-					if ((_m[tile].m5 & 0x1F) == 0xF)
-						cost += _price.clear_3;
-					else if ((_m[tile].m5 & 0x1C) == 8)
-						cost += _price.clear_2;
+					switch (GetClearGround(tile)) {
+						case CL_FIELDS: cost += _price.clear_3; break;
+						case CL_ROCKS:  cost += _price.clear_2; break;
+						default: break;
+					}
 
 					if (flags & DC_EXEC) {
 						int treetype;
@@ -198,18 +200,10 @@
 								ChangeTownRating(t, RATING_TREE_UP_STEP, RATING_TREE_MAXIMUM);
 						}
 
-						switch (_m[tile].m5 & 0x1C) {
-							case 0x04:
-								m2 = 16;
-								break;
-
-							case 0x10:
-								m2 = ((_m[tile].m5 & 3) << 6) | 0x20;
-								break;
-
-							default:
-								m2 = 0;
-								break;
+						switch (GetClearGround(tile)) {
+							case CL_ROUGH: m2 = 16; break;
+							case CL_SNOW:  m2 = GetClearDensity(tile) << 6 | 0x20; break;
+							default:       m2 = 0; break;
 						}
 
 						treetype = p1;
@@ -456,7 +450,6 @@
 static void TileLoop_Trees(TileIndex tile)
 {
 	byte m5;
-	uint16 m2;
 
 	static const TileIndexDiffC _tileloop_trees_dir[] = {
 		{-1, -1},
@@ -504,13 +497,15 @@
 
 				if (!IsTileType(tile, MP_CLEAR)) return;
 
-				if ( (_m[tile].m5 & 0x1C) == 4) {
-					_m[tile].m2 = 0x10;
-				} else if ((_m[tile].m5 & 0x1C) == 16) {
-					_m[tile].m2 = ((_m[tile].m5 & 3) << 6) | 0x20;
-				} else {
-					if ((_m[tile].m5 & 0x1F) != 3) return;
-					_m[tile].m2 = 0;
+				switch (GetClearGround(tile)) {
+					case CL_GRASS:
+						if (GetClearDensity(tile) != 3) return;
+						_m[tile].m2 = 0;
+						break;
+
+					case CL_ROUGH: _m[tile].m2 = 0x10; break;
+					case CL_SNOW:  _m[tile].m2 = GetClearDensity(tile) << 6 | 0x20; break;
+					default: return;
 				}
 
 				_m[tile].m4 = 0;
@@ -532,15 +527,14 @@
 		} else {
 			/* just one tree, change type into MP_CLEAR */
 			SetTileType(tile, MP_CLEAR);
-
-			m5 = 3;
-			m2 = _m[tile].m2;
-			if ((m2 & 0x30) != 0) { // on snow/desert or rough land
-				m5 = (m2 >> 6) | 0x10;
-				if ((m2 & 0x30) != 0x20) // if not on snow/desert, then on rough land
-					m5 = 7;
+			SetTileOwner(tile, OWNER_NONE);
+			switch (_m[tile].m2 & 0x30) {
+				case 0x00: SetClearGroundDensity(tile, CL_GRASS, 3); break;
+				case 0x10: SetClearGroundDensity(tile, CL_ROUGH, 3); break;
+				default:   SetClearGroundDensity(tile, CL_SNOW, GB(_m[tile].m2, 6, 2)); break;
 			}
-			SetTileOwner(tile, OWNER_NONE);
+			MarkTileDirtyByTile(tile);
+			return;
 		}
 	} else {
 		/* in the middle of a transition, change to next */
@@ -555,20 +549,20 @@
 {
 	uint32 r;
 	TileIndex tile;
-	byte m;
+	ClearGround ct;
 	int tree;
 
 	/* place a tree at a random rainforest spot */
 	if (_opt.landscape == LT_DESERT &&
 			(r = Random(), tile = RandomTileSeed(r), GetMapExtraBits(tile) == 2) &&
 			IsTileType(tile, MP_CLEAR) &&
-			(m = _m[tile].m5 & 0x1C, m <= 4) &&
+			(ct = GetClearGround(tile), ct == CL_GRASS || ct == CL_ROUGH) &&
 			(tree = GetRandomTreeType(tile, GB(r, 24, 8))) >= 0) {
 
 		ModifyTile(tile,
 			MP_SETTYPE(MP_TREES) |
 			MP_MAP2 | MP_MAP3LO | MP_MAP3HI | MP_MAP5,
-			(m == 4 ? 0x10 : 0),
+			(ct == CL_ROUGH ? 0x10 : 0),
 			tree,
 			_m[tile].m4 & ~3,
 			0
@@ -582,16 +576,14 @@
 	r = Random();
 	tile = TILE_MASK(r);
 	if (IsTileType(tile, MP_CLEAR) &&
-			(m = _m[tile].m5 & 0x1C, m == 0 || m == 4 || m == 0x10) &&
+			(ct = GetClearGround(tile), ct == CL_GRASS || ct == CL_ROUGH || ct == CL_SNOW) &&
 			(tree = GetRandomTreeType(tile, GB(r, 24, 8))) >= 0) {
 		int m2;
 
-		if (m == 0) {
-			m2 = 0;
-		} else if (m == 4) {
-			m2 = 0x10;
-		} else {
-			m2 = ((_m[tile].m5 & 3) << 6) | 0x20;
+		switch (ct) {
+			case CL_GRASS: m2 = 0;
+			case CL_ROUGH: m2 = 0x10;
+			default:       m2 = (GetClearDensity(tile) << 6) | 0x20;
 		}
 
 		ModifyTile(tile,