(svn r3556) Add accessors for handling tree tiles
authortron
Sun, 05 Feb 2006 14:47:15 +0000
changeset 2981 31760b6a88aa
parent 2980 cd4b945c5517
child 2982 286f69caaf05
(svn r3556) Add accessors for handling tree tiles
See tree.h for details
smallmap_gui.c
tree.h
tree_cmd.c
--- a/smallmap_gui.c	Sun Feb 05 14:18:28 2006 +0000
+++ b/smallmap_gui.c	Sun Feb 05 14:47:15 2006 +0000
@@ -10,6 +10,7 @@
 #include "map.h"
 #include "tile.h"
 #include "gui.h"
+#include "tree.h"
 #include "window.h"
 #include "gfx.h"
 #include "viewport.h"
@@ -489,7 +490,7 @@
 			break;
 
 		case MP_TREES:
-			if ((_m[tile].m2 & 0x30) == 0x20) {
+			if (GetTreeGround(tile) == TR_SNOW_DESERT) {
 				bits = (_opt.landscape == LT_HILLY) ? MKCOLOR(0x98575798) : MKCOLOR(0xC25757C2);
 			} else {
 				bits = MKCOLOR(0x54575754);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tree.h	Sun Feb 05 14:47:15 2006 +0000
@@ -0,0 +1,59 @@
+/* $Id$ */
+
+#ifndef TREE_H
+#define TREE_H
+
+#include "macros.h"
+
+typedef enum TreeType {
+	TR_INVALID      = -1,
+	TR_TEMPERATE    = 0,
+	TR_SUB_ARCTIC   = 12,
+	TR_RAINFOREST   = 20,
+	TR_CACTUS       = 27,
+	TR_SUB_TROPICAL = 28,
+	TR_TOYLAND      = 32
+} TreeType;
+
+enum {
+	TR_COUNT_TEMPERATE    = TR_SUB_ARCTIC   - TR_TEMPERATE,
+	TR_COUNT_SUB_ARCTIC   = TR_RAINFOREST   - TR_SUB_ARCTIC,
+	TR_COUNT_RAINFOREST   = TR_CACTUS       - TR_RAINFOREST,
+	TR_COUNT_SUB_TROPICAL = TR_SUB_TROPICAL - TR_CACTUS,
+	TR_COUNT_TOYLAND      = 9
+};
+
+/* ground type, m2 bits 4...5
+ * valid densities (bits 6...7) in comments after the enum */
+typedef enum TreeGround {
+	TR_GRASS       = 0, // 0
+	TR_ROUGH       = 1, // 0
+	TR_SNOW_DESERT = 2  // 0-3 for snow, 3 for desert
+} TreeGround;
+
+static inline TreeType GetTreeType(TileIndex t) { return _m[t].m3; }
+static inline void SetTreeType(TileIndex t, TreeType r) { _m[t].m3 = r; }
+
+static inline TreeGround GetTreeGround(TileIndex t) { return GB(_m[t].m2, 4, 2); }
+
+static inline uint GetTreeDensity(TileIndex t) { return GB(_m[t].m2, 6, 2); }
+
+static inline void SetTreeGroundDensity(TileIndex t, TreeGround g, uint d)
+{
+	SB(_m[t].m2, 4, 2, g);
+	SB(_m[t].m2, 6, 2, d);
+}
+
+static inline void AddTreeCount(TileIndex t, int c) { _m[t].m5 += c << 6; }
+static inline uint GetTreeCount(TileIndex t) { return GB(_m[t].m5, 6, 2); }
+static inline void SetTreeCount(TileIndex t, uint c) { SB(_m[t].m5, 6, 2, c); }
+
+static inline void AddTreeGrowth(TileIndex t, int a) { _m[t].m5 += a; }
+static inline uint GetTreeGrowth(TileIndex t) { return GB(_m[t].m5, 0, 3); }
+static inline void SetTreeGrowth(TileIndex t, uint g) { SB(_m[t].m5, 0, 3, g); }
+
+static inline void AddTreeCounter(TileIndex t, int a) { _m[t].m2 += a; }
+static inline uint GetTreeCounter(TileIndex t) { return GB(_m[t].m2, 0, 4); }
+static inline void SetTreeCounter(TileIndex t, uint c) { SB(_m[t].m2, 0, 4, c); }
+
+#endif
--- a/tree_cmd.c	Sun Feb 05 14:18:28 2006 +0000
+++ b/tree_cmd.c	Sun Feb 05 14:47:15 2006 +0000
@@ -9,56 +9,53 @@
 #include "functions.h"
 #include "map.h"
 #include "tile.h"
+#include "tree.h"
 #include "viewport.h"
 #include "command.h"
 #include "town.h"
 #include "sound.h"
 #include "variables.h"
 
-static int GetRandomTreeType(TileIndex tile, uint seed)
+static TreeType GetRandomTreeType(TileIndex tile, uint seed)
 {
 	switch (_opt.landscape) {
 		case LT_NORMAL:
-			return seed * 12 >> 8;
+			return seed * TR_COUNT_TEMPERATE / 256 + TR_TEMPERATE;
 
 		case LT_HILLY:
-			return (seed >> 5) + 12;
+			return seed * TR_COUNT_SUB_ARCTIC / 256 + TR_SUB_ARCTIC;
 
 		case LT_DESERT:
 			switch (GetMapExtraBits(tile)) {
-				case 0:  return (seed >> 6) + 28;
-				case 1:  return (seed > 12) ? -1 : 27;
-				default: return (seed * 7 >> 8) + 20;
+				case 0:  return seed * TR_COUNT_SUB_TROPICAL / 256 + TR_SUB_TROPICAL;
+				case 1:  return (seed > 12) ? TR_INVALID : TR_CACTUS;
+				default: return seed * TR_COUNT_RAINFOREST / 256 + TR_RAINFOREST;
 			}
 
 		default:
-			return (seed * 9 >> 8) + 32;
+			return seed * TR_COUNT_TOYLAND / 256 + TR_TOYLAND;
 	}
 }
 
 static void PlaceTree(TileIndex tile, uint32 r)
 {
-	int tree = GetRandomTreeType(tile, GB(r, 24, 8));
-	byte m5;
-
-	if (tree >= 0) {
-		SetTileType(tile, MP_TREES);
+	TreeType tree = GetRandomTreeType(tile, GB(r, 24, 8));
 
-		m5 = GB(r, 16, 8);
-		if (GB(m5, 0, 3) == 7) m5--; // there is no growth state 7
-
-		_m[tile].m5 = m5 & 0x07;	// growth state;
-		_m[tile].m5 |=  m5 & 0xC0;	// amount of trees
-
-		_m[tile].m3 = tree;		// set type of tree
-		_m[tile].m4 = 0;		// no hedge
+	if (tree != TR_INVALID) {
+		SetTileType(tile, MP_TREES);
+		SetTreeType(tile, tree);
+		SetFenceSE(tile, 0);
+		SetFenceSW(tile, 0);
+		SetTreeCount(tile, GB(r, 22, 2));
+		SetTreeGrowth(tile, min(GB(r, 16, 3), 6));
 
 		// above snowline?
 		if (_opt.landscape == LT_HILLY && GetTileZ(tile) > _opt.snow_line) {
-			_m[tile].m2 = 0xE0;	// set land type to snow
-			_m[tile].m2 |= GB(r, 24, 3); // randomize counter
+			SetTreeGroundDensity(tile, TR_SNOW_DESERT, 3);
+			SetTreeCounter(tile, GB(r, 24, 3));
 		} else {
-			_m[tile].m2 = GB(r, 24, 5); // randomize counter and ground
+			SetTreeGroundDensity(tile, GB(r, 28, 1), 0);
+			SetTreeCounter(tile, GB(r, 24, 4));
 		}
 	}
 }
@@ -165,13 +162,13 @@
 			switch (GetTileType(tile)) {
 				case MP_TREES:
 					// no more space for trees?
-					if (_game_mode != GM_EDITOR && (_m[tile].m5 & 0xC0) == 0xC0) {
+					if (_game_mode != GM_EDITOR && GetTreeCount(tile) != 3) {
 						_error_message = STR_2803_TREE_ALREADY_HERE;
 						continue;
 					}
 
 					if (flags & DC_EXEC) {
-						_m[tile].m5 += 0x40;
+						AddTreeCount(tile, 1);
 						MarkTileDirtyByTile(tile);
 					}
 					// 2x as expensive to add more trees to an existing tile
@@ -191,8 +188,7 @@
 					}
 
 					if (flags & DC_EXEC) {
-						int treetype;
-						int m2;
+						TreeType treetype;
 
 						if (_game_mode != GM_EDITOR && _current_player < MAX_PLAYERS) {
 							Town *t = ClosestTownFromTile(tile, _patches.dist_local_authority);
@@ -200,27 +196,27 @@
 								ChangeTownRating(t, RATING_TREE_UP_STEP, RATING_TREE_MAXIMUM);
 						}
 
-						switch (GetClearGround(tile)) {
-							case CL_ROUGH: m2 = 16; break;
-							case CL_SNOW:  m2 = GetClearDensity(tile) << 6 | 0x20; break;
-							default:       m2 = 0; break;
+						treetype = p1;
+						if (treetype == TR_INVALID) {
+							treetype = GetRandomTreeType(tile, GB(Random(), 24, 8));
+							if (treetype == TR_INVALID) treetype = TR_CACTUS;
 						}
 
-						treetype = p1;
-						if (treetype == -1) {
-							treetype = GetRandomTreeType(tile, GB(Random(), 24, 8));
-							if (treetype == -1) treetype = 27;
+						switch (GetClearGround(tile)) {
+							case CL_ROUGH: SetTreeGroundDensity(tile, TR_ROUGH, 0); break;
+							case CL_SNOW:  SetTreeGroundDensity(tile, TR_SNOW_DESERT, GetClearDensity(tile)); break;
+							default:       SetTreeGroundDensity(tile, TR_GRASS, 0); break;
 						}
+						SetTreeCounter(tile, 0);
 
-						ModifyTile(tile,
-							MP_SETTYPE(MP_TREES) |
-							MP_MAP2 | MP_MAP3LO | MP_MAP3HI_CLEAR | MP_MAP5,
-							m2, /* map2 */
-							treetype, /* map3lo */
-							_game_mode == GM_EDITOR ? 3 : 0 /* map5 */
-						);
+						SetTileType(tile, MP_TREES);
+						SetTreeType(tile, treetype);
+						SetFenceSE(tile, 0);
+						SetFenceSW(tile, 0);
+						SetTreeCount(tile, 0);
+						SetTreeGrowth(tile, _game_mode == GM_EDITOR ? 3 : 0);
 
-						if (_game_mode == GM_EDITOR && IS_BYTE_INSIDE(treetype, 0x14, 0x1B))
+						if (_game_mode == GM_EDITOR && IS_INT_INSIDE(treetype, TR_RAINFOREST, TR_CACTUS))
 							SetMapExtraBits(tile, 2);
 					}
 					cost += _price.build_trees;
@@ -243,19 +239,14 @@
 
 static void DrawTile_Trees(TileInfo *ti)
 {
-	uint16 m2;
 	const uint32 *s;
 	const TreePos* d;
 	byte z;
 
-	m2 = _m[ti->tile].m2;
-
-	if ((m2 & 0x30) == 0) {
-		DrawClearLandTile(ti, 3);
-	} else if ((m2 & 0x30) == 0x20) {
-		DrawGroundSprite(_tree_sprites_1[m2 >> 6] + _tileh_to_sprite[ti->tileh]);
-	} else {
-		DrawHillyLandTile(ti);
+	switch (GetTreeGround(ti->tile)) {
+		case TR_GRASS: DrawClearLandTile(ti, 3); break;
+		case TR_ROUGH: DrawHillyLandTile(ti); break;
+		default:       DrawGroundSprite(_tree_sprites_1[GetTreeDensity(ti->tile)] + _tileh_to_sprite[ti->tileh]); break;
 	}
 
 	DrawClearLandFence(ti);
@@ -280,11 +271,14 @@
 
 		d = _tree_layout_xy[GB(tmp, 4, 2)];
 
-		index = GB(tmp, 6, 2) + (_m[ti->tile].m3 << 2);
+		index = GB(tmp, 6, 2) + (GetTreeType(ti->tile) << 2);
 
 		/* different tree styles above one of the grounds */
-		if ((m2 & 0xB0) == 0xA0 && index >= 48 && index < 80)
-			index += 164 - 48;
+		if (GetTreeGround(ti->tile) == TR_SNOW_DESERT &&
+				GetTreeDensity(ti->tile) >= 2 &&
+				IS_INT_INSIDE(index, TR_SUB_ARCTIC << 2, TR_RAINFOREST << 2)) {
+			index += 164 - (TR_SUB_ARCTIC << 2);
+		}
 
 		assert(index < lengthof(_tree_layout_sprite));
 		s = _tree_layout_sprite[index];
@@ -352,8 +346,8 @@
 			ChangeTownRating(t, RATING_TREE_DOWN_STEP, RATING_TREE_MINIMUM);
 	}
 
-	num = GB(_m[tile].m5, 6, 2) + 1;
-	if (IS_INT_INSIDE(_m[tile].m3, 20, 26 + 1)) num *= 4;
+	num = GetTreeCount(tile) + 1;
+	if (IS_INT_INSIDE(GetTreeType(tile), TR_RAINFOREST, TR_CACTUS)) num *= 4;
 
 	if (flags & DC_EXEC) DoClearSquare(tile);
 
@@ -367,16 +361,17 @@
 
 static void GetTileDesc_Trees(TileIndex tile, TileDesc *td)
 {
-	byte b;
-	StringID str;
+	TreeType tt = GetTreeType(tile);
+
+	if (IS_INT_INSIDE(tt, TR_RAINFOREST, TR_CACTUS)) {
+		td->str = STR_280F_RAINFOREST;
+	} else if (tt == TR_CACTUS) {
+		td->str = STR_2810_CACTUS_PLANTS;
+	} else {
+		td->str = STR_280E_TREES;
+	}
 
 	td->owner = GetTileOwner(tile);
-
-	b = _m[tile].m3;
-	(str=STR_2810_CACTUS_PLANTS, b==0x1B) ||
-	(str=STR_280F_RAINFOREST, IS_BYTE_INSIDE(b, 0x14, 0x1A+1)) ||
-	(str=STR_280E_TREES, true);
-	td->str = str;
 }
 
 static void AnimateTile_Trees(TileIndex tile)
@@ -386,71 +381,56 @@
 
 static void TileLoopTreesDesert(TileIndex tile)
 {
-	static const SoundFx forest_sounds[] = {
-		SND_42_LOON_BIRD,
-		SND_43_LION,
-		SND_44_MONKEYS,
-		SND_48_DISTANT_BIRD
-	};
-
-	byte b = GetMapExtraBits(tile);
+	switch (GetMapExtraBits(tile)) {
+		case 1:
+			if (GetTreeGround(tile) != TR_SNOW_DESERT) {
+				SetTreeGroundDensity(tile, TR_SNOW_DESERT, 3);
+				MarkTileDirtyByTile(tile);
+			}
+			break;
 
-	if (b == 2) {
-		uint32 r = Random();
+		case 2: {
+			static const SoundFx forest_sounds[] = {
+				SND_42_LOON_BIRD,
+				SND_43_LION,
+				SND_44_MONKEYS,
+				SND_48_DISTANT_BIRD
+			};
+			uint32 r = Random();
 
-		if (CHANCE16I(1, 200, r)) SndPlayTileFx(forest_sounds[GB(r, 16, 2)], tile);
-	} else if (b == 1) {
-		if (GB(_m[tile].m2, 4, 2) != 2) {
-			SB(_m[tile].m2, 4, 2, 2);
-			SB(_m[tile].m2, 6, 2, 3);
-			MarkTileDirtyByTile(tile);
+			if (CHANCE16I(1, 200, r)) SndPlayTileFx(forest_sounds[GB(r, 16, 2)], tile);
+			break;
 		}
 	}
 }
 
 static void TileLoopTreesAlps(TileIndex tile)
 {
-	byte tmp, m2;
-	int k;
-
-	/* distance from snow line, in steps of 8 */
-	k = GetTileZ(tile) - _opt.snow_line;
-
-	tmp = _m[tile].m2 & 0xF0;
+	int k = GetTileZ(tile) - _opt.snow_line;
 
 	if (k < -8) {
-		if ((tmp & 0x30) != 0x20) return;
-		m2 = 0; // no snow
-	} else if (k == -8) {
-		m2 = 0x20; // 1/4 snow
-		if (tmp == m2) return;
-	} else if (k == 0) {
-		m2 = 0x60;// 1/2 snow
-		if (tmp == m2) return;
-	} else if (k == 8) {
-		m2 = 0xA0; // 3/4 snow
-		if (tmp == m2) return;
+		if (GetTreeGround(tile) != TR_SNOW_DESERT) return;
+		SetTreeGroundDensity(tile, TR_GRASS, 0);
 	} else {
-		if (tmp == 0xE0) {
-			uint32 r = Random();
-			if (CHANCE16I(1, 200, r)) {
-				SndPlayTileFx((r & 0x80000000) ? SND_39_HEAVY_WIND : SND_34_WIND, tile);
+		uint density = min((uint)(k + 8) / 8, 3);
+
+		if (GetTreeGround(tile) != TR_SNOW_DESERT || GetTreeDensity(tile) != density) {
+			SetTreeGroundDensity(tile, TR_SNOW_DESERT, density);
+		} else {
+			if (GetTreeDensity(tile) == 3) {
+				uint32 r = Random();
+				if (CHANCE16I(1, 200, r)) {
+					SndPlayTileFx((r & 0x80000000) ? SND_39_HEAVY_WIND : SND_34_WIND, tile);
+				}
 			}
 			return;
-		} else {
-			m2 = 0xE0; // full snow
 		}
 	}
-
-	_m[tile].m2 &= 0xF;
-	_m[tile].m2 |= m2;
 	MarkTileDirtyByTile(tile);
 }
 
 static void TileLoop_Trees(TileIndex tile)
 {
-	byte m5;
-
 	static const TileIndexDiffC _tileloop_trees_dir[] = {
 		{-1, -1},
 		{ 0, -1},
@@ -462,89 +442,93 @@
 		{ 1,  1}
 	};
 
-	if (_opt.landscape == LT_DESERT) {
-		TileLoopTreesDesert(tile);
-	} else if (_opt.landscape == LT_HILLY) {
-		TileLoopTreesAlps(tile);
+	switch (_opt.landscape) {
+		case LT_DESERT: TileLoopTreesDesert(tile); break;
+		case LT_HILLY:  TileLoopTreesAlps(tile);   break;
 	}
 
 	TileLoopClearHelper(tile);
 
-	/* increase counter */
-	AB(_m[tile].m2, 0, 4, 1);
-	if (GB(_m[tile].m2, 0, 4) != 0) return;
-
-	m5 = _m[tile].m5;
-	if (GB(m5, 0, 3) == 3) {
-		/* regular sized tree */
-		if (_opt.landscape == LT_DESERT && _m[tile].m3 != 0x1B && GetMapExtraBits(tile) == 1) {
-			m5++; /* start destructing */
-		} else {
-			switch (GB(Random(), 0, 3)) {
-			case 0: /* start destructing */
-				m5++;
-				break;
+	if (GetTreeCounter(tile) < 15) {
+		AddTreeCounter(tile, 1);
+		return;
+	}
+	SetTreeCounter(tile, 0);
 
-			case 1: /* add a tree */
-				if (m5 < 0xC0) {
-					m5 = (m5 + 0x40) & ~7;
-					break;
-				}
-				/* fall through */
-
-			case 2: { /* add a neighbouring tree */
-				byte m3 = _m[tile].m3;
-
-				tile += ToTileIndexDiff(_tileloop_trees_dir[Random() & 7]);
-
-				if (!IsTileType(tile, MP_CLEAR)) return;
-
-				switch (GetClearGround(tile)) {
-					case CL_GRASS:
-						if (GetClearDensity(tile) != 3) return;
-						_m[tile].m2 = 0;
+	switch (GetTreeGrowth(tile)) {
+		case 3: /* regular sized tree */
+			if (_opt.landscape == LT_DESERT && GetTreeType(tile) != TR_CACTUS && GetMapExtraBits(tile) == 1) {
+				AddTreeGrowth(tile, 1);
+			} else {
+				switch (GB(Random(), 0, 3)) {
+					case 0: /* start destructing */
+						AddTreeGrowth(tile, 1);
 						break;
 
-					case CL_ROUGH: _m[tile].m2 = 0x10; break;
-					case CL_SNOW:  _m[tile].m2 = GetClearDensity(tile) << 6 | 0x20; break;
-					default: return;
-				}
+					case 1: /* add a tree */
+						if (GetTreeCount(tile) < 3) {
+							AddTreeCount(tile, 1);
+							SetTreeGrowth(tile, 0);
+							break;
+						}
+						/* FALL THROUGH */
 
-				_m[tile].m3 = m3;
-				_m[tile].m4 = 0;
-				SetTileType(tile, MP_TREES);
+					case 2: { /* add a neighbouring tree */
+						TreeType treetype = GetTreeType(tile);
 
-				m5 = 0;
-				break;
-			}
+						tile += ToTileIndexDiff(_tileloop_trees_dir[Random() & 7]);
 
-			default:
-				return;
+						if (!IsTileType(tile, MP_CLEAR)) return;
+
+						switch (GetClearGround(tile)) {
+							case CL_GRASS:
+								if (GetClearDensity(tile) != 3) return;
+								SetTreeGroundDensity(tile, TR_GRASS, 0);
+								break;
+
+							case CL_ROUGH: SetTreeGroundDensity(tile, TR_ROUGH, 0); break;
+							case CL_SNOW:  SetTreeGroundDensity(tile, TR_SNOW_DESERT, GetClearDensity(tile)); break;
+							default: return;
+						}
+						SetTreeCounter(tile, 0);
+
+						SetTileType(tile, MP_TREES);
+						SetTreeType(tile, treetype);
+						SetFenceSE(tile, 0);
+						SetFenceSW(tile, 0);
+						SetTreeCount(tile, 0);
+						SetTreeGrowth(tile, 0);
+						break;
+					}
+
+					default:
+						return;
+				}
 			}
-		}
-	} else if (GB(m5, 0, 3) == 6) {
-		/* final stage of tree destruction */
-		if (GB(m5, 6, 2) != 0) {
-			/* more than one tree, delete it? */
-			m5 = ((m5 - 6) - 0x40) + 3;
-		} else {
-			/* just one tree, change type into MP_CLEAR */
-			SetTileType(tile, MP_CLEAR);
-			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;
+			break;
+
+		case 6: /* final stage of tree destruction */
+			if (GetTreeCount(tile) > 0) {
+				/* more than one tree, delete it */
+				AddTreeCount(tile, -1);
+				SetTreeGrowth(tile, 3);
+			} else {
+				/* just one tree, change type into MP_CLEAR */
+				SetTileType(tile, MP_CLEAR);
+				SetTileOwner(tile, OWNER_NONE);
+				switch (GetTreeGround(tile)) {
+					case TR_GRASS: SetClearGroundDensity(tile, CL_GRASS, 3); break;
+					case TR_ROUGH: SetClearGroundDensity(tile, CL_ROUGH, 3); break;
+					default:       SetClearGroundDensity(tile, CL_SNOW, GetTreeDensity(tile)); break;
+				}
 			}
-			MarkTileDirtyByTile(tile);
-			return;
-		}
-	} else {
-		/* in the middle of a transition, change to next */
-		m5++;
+			break;
+
+		default:
+			AddTreeGrowth(tile, 1);
+			break;
 	}
 
-	_m[tile].m5 = m5;
 	MarkTileDirtyByTile(tile);
 }
 
@@ -560,16 +544,13 @@
 			(r = Random(), tile = RandomTileSeed(r), GetMapExtraBits(tile) == 2) &&
 			IsTileType(tile, MP_CLEAR) &&
 			(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,
-			(ct == CL_ROUGH ? 0x10 : 0),
-			tree,
-			_m[tile].m4 & ~3,
-			0
-		);
+			(tree = GetRandomTreeType(tile, GB(r, 24, 8))) != TR_INVALID) {
+		SetTileType(tile, MP_TREES);
+		SetTreeGroundDensity(tile, ct == CL_ROUGH ? TR_ROUGH : TR_GRASS, 0);
+		SetTreeCounter(tile, 0);
+		SetTreeType(tile, tree);
+		SetTreeCount(tile, 0);
+		SetTreeGrowth(tile, 0);
 	}
 
 	// byte underflow
@@ -580,23 +561,17 @@
 	tile = TILE_MASK(r);
 	if (IsTileType(tile, MP_CLEAR) &&
 			(ct = GetClearGround(tile), ct == CL_GRASS || ct == CL_ROUGH || ct == CL_SNOW) &&
-			(tree = GetRandomTreeType(tile, GB(r, 24, 8))) >= 0) {
-		int m2;
-
+			(tree = GetRandomTreeType(tile, GB(r, 24, 8))) != TR_INVALID) {
 		switch (ct) {
-			case CL_GRASS: m2 = 0; break;
-			case CL_ROUGH: m2 = 0x10; break;
-			default:       m2 = (GetClearDensity(tile) << 6) | 0x20; break;
+			case CL_GRASS: SetTreeGroundDensity(tile, TR_GRASS, 0); break;
+			case CL_ROUGH: SetTreeGroundDensity(tile, TR_ROUGH, 0); break;
+			default:       SetTreeGroundDensity(tile, TR_SNOW_DESERT, GetClearDensity(tile)); break;
 		}
-
-		ModifyTile(tile,
-			MP_SETTYPE(MP_TREES) |
-			MP_MAP2 | MP_MAP3LO | MP_MAP3HI | MP_MAP5,
-			m2,
-			tree,
-			_m[tile].m4 & ~3,
-			0
-		);
+		SetTreeCounter(tile, 0);
+		SetTileType(tile, MP_TREES);
+		SetTreeType(tile, tree);
+		SetTreeCount(tile, 0);
+		SetTreeGrowth(tile, 0);
 	}
 }