664 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			664 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include "stdafx.h"
 | |
| #include "ttd.h"
 | |
| #include "table/strings.h"
 | |
| #include "map.h"
 | |
| #include "viewport.h"
 | |
| #include "command.h"
 | |
| #include "town.h"
 | |
| #include "sound.h"
 | |
| 
 | |
| static int GetRandomTreeType(uint tile, uint seed)
 | |
| {
 | |
| 	byte i;
 | |
| 
 | |
| 	if (_opt.landscape == LT_NORMAL) {
 | |
| 		return seed * 12 >> 8;
 | |
| 	} else if (_opt.landscape == LT_HILLY) {
 | |
| 		return (seed >> 5) + 12;
 | |
| 	} else if (_opt.landscape == LT_DESERT) {
 | |
| 		i = GetMapExtraBits(tile);
 | |
| 		if (i == 0) {
 | |
| 			return (seed >> 6) + 28;
 | |
| 		} else if (i == 1) {
 | |
| 			if (seed > 12)
 | |
| 				return -1;
 | |
| 			return 27;
 | |
| 		} else {
 | |
| 			return (seed * 7 >> 8) + 20;
 | |
| 		}
 | |
| 	} else {
 | |
| 		return (seed * 9 >> 8) + 32;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void PlaceTree(uint tile, uint32 r, byte m5_or)
 | |
| {
 | |
| 	int tree = GetRandomTreeType(tile, (r >> 24));
 | |
| 	byte m5;
 | |
| 
 | |
| 	if (tree >= 0) {
 | |
| 		m5 = (byte)(r >> 16);
 | |
| 		if ((m5 & 0x7) == 7) m5--; // there is no growth state 7
 | |
| 
 | |
| 		_map5[tile] = m5 & 0x07;	// growth state;
 | |
| 		_map5[tile] |=  m5 & 0xC0;	// amount of trees
 | |
| 
 | |
| 		_map3_lo[tile] = tree;		// set type of tree
 | |
| 		_map3_hi[tile] = 0;		// no hedge
 | |
| 
 | |
| 		// above snowline?
 | |
| 		if( (_opt.landscape == LT_HILLY) && (GetTileZ(tile) - _opt.snow_line > 0) )
 | |
| 		{
 | |
| 			_map2[tile] = 0xE0;	// set land type to snow
 | |
| 			_map2[tile] |= (byte)(r >> 24)&0x07; // randomize counter
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			_map2[tile] = (byte)(r >> 24)&0x1F; // randomize counter and ground
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		// make it tree class
 | |
| 		_map_type_and_height[tile] |= MP_TREES << 4;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void DoPlaceMoreTrees(uint tile)
 | |
| {
 | |
| 	int i = 1000;
 | |
| 	int x,y;
 | |
| 	uint cur_tile;
 | |
| 	int dist;
 | |
| 
 | |
| 	do {
 | |
| 		uint32 r = Random();
 | |
| 		x = (r & 0x1F) - 16;
 | |
| 		y = ((r>>8) & 0x1F) - 16;
 | |
| 
 | |
| 		dist = myabs(x) + myabs(y);
 | |
| 
 | |
| 		cur_tile = TILE_MASK(tile + TILE_XY(x,y));
 | |
| 
 | |
| 		/* Only on tiles within 13 squares from tile,
 | |
| 		    on clear tiles, and NOT on farm-tiles or rocks */
 | |
| 		if (dist <= 13 && IS_TILETYPE(cur_tile, MP_CLEAR) &&
 | |
| 			 (_map5[cur_tile] & 0x1F) != 0x0F && (_map5[cur_tile] & 0x1C) != 8) {
 | |
| 			PlaceTree(cur_tile, r, dist <= 6 ? 0xC0 : 0);
 | |
| 		}
 | |
| 	} while (--i);
 | |
| }
 | |
| 
 | |
| static void PlaceMoreTrees()
 | |
| {
 | |
| 	int i = (Random() & 0x1F) + 25;
 | |
| 	do {
 | |
| 		DoPlaceMoreTrees(TILE_MASK(Random()));
 | |
| 	} while (--i);
 | |
| }
 | |
| 
 | |
| void PlaceTreesRandomly()
 | |
| {
 | |
| 	int i;
 | |
| 	uint32 r;
 | |
| 	uint tile;
 | |
| 
 | |
| 	i = 1000;
 | |
| 	do {
 | |
| 		r = Random();
 | |
| 		tile = TILE_MASK(r);
 | |
| 		/* Only on clear tiles, and NOT on farm-tiles or rocks */
 | |
| 		if (IS_TILETYPE(tile, MP_CLEAR) && (_map5[tile] & 0x1F) != 0x0F && (_map5[tile] & 0x1C) != 8) {
 | |
| 			PlaceTree(tile, r, 0);
 | |
| 		}
 | |
| 	} while (--i);
 | |
| 
 | |
| 	/* place extra trees at rainforest area */
 | |
| 	if (_opt.landscape == LT_DESERT) {
 | |
| 		i = 15000;
 | |
| 
 | |
| 		do {
 | |
| 			r = Random();
 | |
| 			tile = TILE_MASK(r);
 | |
| 			if (IS_TILETYPE(tile, MP_CLEAR) && GetMapExtraBits(tile) == 2) {
 | |
| 				PlaceTree(tile, r, 0);
 | |
| 			}
 | |
| 		} while (--i);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void GenerateTrees()
 | |
| {
 | |
| 	int i;
 | |
| 
 | |
| 	if (_opt.landscape != LT_CANDY) {
 | |
| 		PlaceMoreTrees();
 | |
| 	}
 | |
| 
 | |
| 	i = _opt.landscape == LT_HILLY ? 15 : 6;
 | |
| 	do {
 | |
| 		PlaceTreesRandomly();
 | |
| 	} while (--i);
 | |
| }
 | |
| 
 | |
| /* Plant a tree
 | |
|  * p1 = tree type, -1 means random.
 | |
|  * p2 = end tile
 | |
|  */
 | |
| 
 | |
| int32 CmdPlantTree(int ex, int ey, uint32 flags, uint32 p1, uint32 p2)
 | |
| {
 | |
| 	TileInfo ti;
 | |
| 	int32 cost;
 | |
| 	int sx,sy,x,y;
 | |
| 	int treetype;
 | |
| 
 | |
| 	SET_EXPENSES_TYPE(EXPENSES_OTHER);
 | |
| 
 | |
| 	// make sure sx,sy are smaller than ex,ey
 | |
| 	sx = TileX(p2) * 16;
 | |
| 	sy = TileY(p2) * 16;
 | |
| 	if (ex < sx) intswap(ex, sx);
 | |
| 	if (ey < sy) intswap(ey, sy);
 | |
| 
 | |
| 	cost = 0; // total cost
 | |
| 
 | |
| 	for(x=sx; x<=ex; x+=16) {
 | |
| 		for(y=sy; y<=ey; y+=16) {
 | |
| 			FindLandscapeHeight(&ti, x, y);
 | |
| 			if (!EnsureNoVehicle(ti.tile))
 | |
| 				continue;
 | |
| 
 | |
| 			if (ti.type == MP_TREES) {
 | |
| 				// no more space for trees?
 | |
| 				if (_game_mode != GM_EDITOR && (ti.map5 & 0xC0) == 0xC0) {
 | |
| 					_error_message = STR_2803_TREE_ALREADY_HERE;
 | |
| 					continue;
 | |
| 				}
 | |
| 
 | |
| 				if (flags & DC_EXEC) {
 | |
| 					_map5[ti.tile] = ti.map5 + 0x40;
 | |
| 					MarkTileDirtyByTile(ti.tile);
 | |
| 				}
 | |
| 				// 2x as expensive to add more trees to an existing tile
 | |
| 				cost += _price.build_trees * 2;
 | |
| 			} else {
 | |
| 				if (ti.type != MP_CLEAR || _map_owner[ti.tile] != OWNER_NONE) {
 | |
| 					_error_message = STR_2804_SITE_UNSUITABLE;
 | |
| 					continue;
 | |
| 				}
 | |
| 
 | |
| 				// it's expensive to clear farmland
 | |
| 				if ((ti.map5 & 0x1F) == 0xF) cost += _price.clear_3;
 | |
| 				else if ((ti.map5 & 0x1C) == 8) cost += _price.clear_2;
 | |
| 
 | |
| 				if (flags & DC_EXEC) {
 | |
| 					int m2;
 | |
| 
 | |
| 					if (_game_mode != GM_EDITOR && _current_player < MAX_PLAYERS) {
 | |
| 						Town *t = ClosestTownFromTile(ti.tile, _patches.dist_local_authority);
 | |
| 						if (t != NULL)
 | |
| 							ChangeTownRating(t, RATING_TREE_UP_STEP, RATING_TREE_MAXIMUM);
 | |
| 					}
 | |
| 					m2 = 0;
 | |
| 					if ( (ti.map5 & 0x1C) == 4 ) {
 | |
| 						m2 = 16;
 | |
| 					} else if ( (ti.map5 & 0x1C) == 16 ) {
 | |
| 						m2 = ((ti.map5 & 3) << 6) | 0x20;
 | |
| 					}
 | |
| 
 | |
| 					treetype = p1;
 | |
| 					if (treetype == -1) {
 | |
| 						treetype = GetRandomTreeType(ti.tile, Random()>>24);
 | |
| 						if (treetype==-1) treetype=27;
 | |
| 					}
 | |
| 
 | |
| 					ModifyTile(ti.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 */
 | |
| 					);
 | |
| 
 | |
| 					if (_game_mode == GM_EDITOR && IS_BYTE_INSIDE(treetype, 0x14, 0x1B)) {
 | |
| 						SetMapExtraBits(ti.tile, 2);
 | |
| 					}
 | |
| 				}
 | |
| 				cost += _price.build_trees;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (cost == 0) return CMD_ERROR;
 | |
| 	return cost;
 | |
| }
 | |
| 
 | |
| typedef struct TreeListEnt {
 | |
| 	uint32 image;
 | |
| 	byte x,y;
 | |
| } TreeListEnt;
 | |
| 
 | |
| 
 | |
| #include "table/tree_land.h"
 | |
| 
 | |
| 
 | |
| static void DrawTile_Trees(TileInfo *ti)
 | |
| {
 | |
| 	uint16 m2;
 | |
| 	const uint32 *s;
 | |
| 	const byte *d;
 | |
| 	byte z;
 | |
| 	TreeListEnt te[4];
 | |
| 
 | |
| 	m2 = _map2[ti->tile];
 | |
| 
 | |
| 	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);
 | |
| 	}
 | |
| 
 | |
| 	DrawClearLandFence(ti, _map3_hi[ti->tile] >> 2);
 | |
| 
 | |
| 	z = ti->z;
 | |
| 	if (ti->tileh != 0) {
 | |
| 		z += 4;
 | |
| 		if (ti->tileh & 0x10)
 | |
| 			z += 4;
 | |
| 	}
 | |
| 
 | |
| 	{
 | |
| 		uint16 tmp = ti->x;
 | |
| 		uint index;
 | |
| 
 | |
| 		tmp = (tmp >> 2) | (tmp << 14);
 | |
| 		tmp -= ti->y;
 | |
| 		tmp = (tmp >> 3) | (tmp << 13);
 | |
| 		tmp -= ti->x;
 | |
| 		tmp = (tmp >> 1) | (tmp << 15);
 | |
| 		tmp += ti->y;
 | |
| 
 | |
| 		d = _tree_layout_xy[(tmp & 0x30) >> 4];
 | |
| 
 | |
| 		index = ((tmp>>6)&3) + (_map3_lo[ti->tile]<<2);
 | |
| 
 | |
| 		/* different tree styles above one of the grounds */
 | |
| 		if ((m2 & 0xB0) == 0xA0 && index >= 48 && index < 80)
 | |
| 			index += 164 - 48;
 | |
| 
 | |
| 		assert(index < lengthof(_tree_layout_sprite));
 | |
| 		s = _tree_layout_sprite[index];
 | |
| 	}
 | |
| 
 | |
| 	StartSpriteCombine();
 | |
| 
 | |
| 	if (!(_display_opt & DO_TRANS_BUILDINGS) || !_patches.invisible_trees)
 | |
| 	{
 | |
| 		int i;
 | |
| 
 | |
| 		/* put the trees to draw in a list */
 | |
| 		i = (ti->map5 >> 6) + 1;
 | |
| 		do {
 | |
| 			uint32 image = s[0] + (--i==0 ? (ti->map5 & 7) : 3);
 | |
| 			if (_display_opt & DO_TRANS_BUILDINGS)
 | |
| 				image = (image & 0x3FFF) | 0x3224000;
 | |
| 			te[i].image = image;
 | |
| 			te[i].x = d[0];
 | |
| 			te[i].y = d[1];
 | |
| 			s++;
 | |
| 			d+=2;
 | |
| 		} while (i);
 | |
| 
 | |
| 		/* draw them in a sorted way */
 | |
| 		for(;;) {
 | |
| 			byte min = 0xFF;
 | |
| 			TreeListEnt *tep = NULL;
 | |
| 
 | |
| 			i = (ti->map5 >> 6) + 1;
 | |
| 			do {
 | |
| 				if (te[--i].image!=0 && (byte)(te[i].x + te[i].y) < min) {
 | |
| 					min = te[i].x + te[i].y;
 | |
| 					tep = &te[i];
 | |
| 				}
 | |
| 			} while (i);
 | |
| 
 | |
| 			if (tep == NULL)
 | |
| 				break;
 | |
| 
 | |
| 			AddSortableSpriteToDraw(tep->image, ti->x + tep->x, ti->y + tep->y, 5, 5, 0x10, z);
 | |
| 			tep->image = 0;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	EndSpriteCombine();
 | |
| }
 | |
| 
 | |
| 
 | |
| static uint GetSlopeZ_Trees(TileInfo *ti) {
 | |
| 	return GetPartialZ(ti->x&0xF, ti->y&0xF, ti->tileh) + ti->z;
 | |
| }
 | |
| 
 | |
| static uint GetSlopeTileh_Trees(TileInfo *ti) {
 | |
| 	return ti->tileh;
 | |
| }
 | |
| 
 | |
| static int32 ClearTile_Trees(uint tile, byte flags) {
 | |
| 	int num;
 | |
| 
 | |
| 	if (flags & DC_EXEC && _current_player < MAX_PLAYERS) {
 | |
| 		Town *t = ClosestTownFromTile(tile, _patches.dist_local_authority);
 | |
| 		if (t != NULL)
 | |
| 			ChangeTownRating(t, RATING_TREE_DOWN_STEP, RATING_TREE_MINIMUM);
 | |
| 	}
 | |
| 
 | |
| 	num = (_map5[tile] >> 6) + 1;
 | |
| 	if ( (byte)(_map3_lo[tile]-0x14) <= (0x1A-0x14))
 | |
| 		num <<= 2;
 | |
| 
 | |
| 	if (flags & DC_EXEC)
 | |
| 		DoClearSquare(tile);
 | |
| 
 | |
| 	return num * _price.remove_trees;
 | |
| }
 | |
| 
 | |
| static void GetAcceptedCargo_Trees(uint tile, AcceptedCargo ac)
 | |
| {
 | |
| 	/* not used */
 | |
| }
 | |
| 
 | |
| static void GetTileDesc_Trees(uint tile, TileDesc *td)
 | |
| {
 | |
| 	byte b;
 | |
| 	StringID str;
 | |
| 
 | |
| 	td->owner = _map_owner[tile];
 | |
| 
 | |
| 	b = _map3_lo[tile];
 | |
| 	(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(uint tile)
 | |
| {
 | |
| 	/* not used */
 | |
| }
 | |
| 
 | |
| static SoundFx _desert_sounds[] = {
 | |
| 	SND_42_LOON_BIRD,
 | |
| 	SND_43_LION,
 | |
| 	SND_44_MONKEYS,
 | |
| 	SND_48_DISTANT_BIRD
 | |
| };
 | |
| 
 | |
| static void TileLoopTreesDesert(uint tile)
 | |
| {
 | |
| 	byte b;
 | |
| 
 | |
| 	if ((b=GetMapExtraBits(tile)) == 2) {
 | |
| 		uint32 r;
 | |
| 
 | |
| 		if (CHANCE16I(1,200,r=Random())) {
 | |
| 			SndPlayTileFx(_desert_sounds[(r >> 16) & 3], tile);
 | |
| 		}
 | |
| 	} else if (b == 1) {
 | |
| 		if ((_map2[tile] & 0x30) != 0x20) {
 | |
| 			_map2[tile] &= 0xF;
 | |
| 			_map2[tile] |= 0xE0;
 | |
| 			MarkTileDirtyByTile(tile);
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void TileLoopTreesAlps(uint tile)
 | |
| {
 | |
| 	byte tmp, m2;
 | |
| 	int k;
 | |
| 
 | |
| 	/* distance from snow line, in steps of 8 */
 | |
| 	k = GetTileZ(tile) - _opt.snow_line;
 | |
| 
 | |
| 	tmp = _map5[tile] & 0xF0;
 | |
| 
 | |
| 	if (k < -8) {
 | |
| 		/* snow_m2_down */
 | |
| 		if ((tmp&0x30) != 0x20)
 | |
| 			return;
 | |
| 		m2 = 0;
 | |
| 	} else if (k == -8) {
 | |
| 		/* snow_m1 */
 | |
| 		m2 = 0x20;
 | |
| 		if (tmp == m2)
 | |
| 			return;
 | |
| 	} else if (k < 8) {
 | |
| 		/* snow_0 */
 | |
| 		m2 = 0x60;
 | |
| 		if (tmp == m2)
 | |
| 			return;
 | |
| 	} else if (k == 8) {
 | |
| 		/* snow_p1 */
 | |
| 		m2 = 0xA0;
 | |
| 		if (tmp == m2)
 | |
| 			return;
 | |
| 	} else {
 | |
| 		/* snow_p2_up */
 | |
| 		if (tmp == 0xC0) {
 | |
| 			uint32 r;
 | |
| 			if (CHANCE16I(1,200,r=Random())) {
 | |
| 				SndPlayTileFx((r & 0x80000000) ? SND_39_HEAVY_WIND : SND_34_WIND, tile);
 | |
| 			}
 | |
| 			return;
 | |
| 		} else {
 | |
| 			m2 = 0xE0;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	_map2[tile] &= 0xF;
 | |
| 	_map2[tile] |= m2;
 | |
| 	MarkTileDirtyByTile(tile);
 | |
| }
 | |
| 
 | |
| static void TileLoop_Trees(uint tile)
 | |
| {
 | |
| 	byte m5;
 | |
| 	uint16 m2;
 | |
| 
 | |
| 	static const TileIndexDiffC _tileloop_trees_dir[] = {
 | |
| 		{-1, -1},
 | |
| 		{ 0, -1},
 | |
| 		{ 1, -1},
 | |
| 		{-1,  0},
 | |
| 		{ 1,  0},
 | |
| 		{-1,  1},
 | |
| 		{ 0,  1},
 | |
| 		{ 1,  1}
 | |
| 	};
 | |
| 
 | |
| 	if (_opt.landscape == LT_DESERT) {
 | |
| 		TileLoopTreesDesert(tile);
 | |
| 	} else if (_opt.landscape == LT_HILLY) {
 | |
| 		TileLoopTreesAlps(tile);
 | |
| 	}
 | |
| 
 | |
| 	TileLoopClearHelper(tile);
 | |
| 
 | |
| 	/* increase counter */
 | |
| 	{
 | |
| 		uint16 m2 = _map2[tile];
 | |
| 		_map2[tile] = m2 = (m2 & 0xF0) | ((m2+1)&0xF);
 | |
| 		if (m2 & 0xF)
 | |
| 			return;
 | |
| 	}
 | |
| 
 | |
| 	m5 = _map5[tile];
 | |
| 	if ((m5&7) == 3) {
 | |
| 		/* regular sized tree */
 | |
| 		if (_opt.landscape == LT_DESERT && _map3_lo[tile]!=0x1B && GetMapExtraBits(tile)==1) {
 | |
| 			m5++; /* start destructing */
 | |
| 		} else {
 | |
| 			switch(Random() & 0x7) {
 | |
| 			case 0: /* start destructing */
 | |
| 				m5++;
 | |
| 				break;
 | |
| 
 | |
| 			case 1: /* add a tree */
 | |
| 				if (m5 < 0xC0) {
 | |
| 					m5 = (m5 + 0x40) & ~7;
 | |
| 					break;
 | |
| 				}
 | |
| 				/* fall through */
 | |
| 
 | |
| 			case 2: { /* add a neighbouring tree */
 | |
| 				byte m3 = _map3_lo[tile];
 | |
| 
 | |
| 				tile += ToTileIndexDiff(_tileloop_trees_dir[Random() & 7]);
 | |
| 
 | |
| 				if (!IS_TILETYPE(tile, MP_CLEAR))
 | |
| 					return;
 | |
| 
 | |
| 				if ( (_map5[tile] & 0x1C) == 4) {
 | |
| 					_map2[tile] = 0x10;
 | |
| 				} else if ((_map5[tile] & 0x1C) == 16) {
 | |
| 					_map2[tile] = ((_map5[tile] & 3) << 6) | 0x20;
 | |
| 				} else {
 | |
| 					if ((_map5[tile] & 0x1F) != 3)
 | |
| 						return;
 | |
| 					_map2[tile] = 0;
 | |
| 				}
 | |
| 
 | |
| 				_map3_lo[tile] = m3;
 | |
| 				_map3_hi[tile] = 0;
 | |
| 				_map_type_and_height[tile] &= 0xF;
 | |
| 				_map_type_and_height[tile] |= MP_TREES << 4;
 | |
| 
 | |
| 				m5 = 0;
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 			default:
 | |
| 				return;
 | |
| 			}
 | |
| 		}
 | |
| 	} else if ((m5&7) == 6) {
 | |
| 		/* final stage of tree destruction */
 | |
| 		if (m5 & 0xC0) {
 | |
| 			/* more than one tree, delete it? */
 | |
| 			m5 = ((m5 - 6) - 0x40) + 3;
 | |
| 		} else {
 | |
| 			/* just one tree, change type into MP_CLEAR */
 | |
| 			_map_type_and_height[tile] = (_map_type_and_height[tile]&~0xF0) | (MP_CLEAR<<4);
 | |
| 
 | |
| 			m5 = 3;
 | |
| 			m2 = _map2[tile];
 | |
| 			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;
 | |
| 			}
 | |
| 			_map_owner[tile] = OWNER_NONE;
 | |
| 		}
 | |
| 	} else {
 | |
| 		/* in the middle of a transition, change to next */
 | |
| 		m5++;
 | |
| 	}
 | |
| 
 | |
| 	_map5[tile] = m5;
 | |
| 	MarkTileDirtyByTile(tile);
 | |
| }
 | |
| 
 | |
| void OnTick_Trees()
 | |
| {
 | |
| 	uint32 r;
 | |
| 	uint tile;
 | |
| 	byte m;
 | |
| 	int tree;
 | |
| 
 | |
| 	/* place a tree at a random rainforest spot */
 | |
| 	if (_opt.landscape == LT_DESERT &&
 | |
| 			(r=Random(),tile=TILE_MASK(r),GetMapExtraBits(tile)==2) &&
 | |
| 			IS_TILETYPE(tile, MP_CLEAR) &&
 | |
| 			(m=_map5[tile]&0x1C, m<=4) &&
 | |
| 			(tree=GetRandomTreeType(tile, r>>24)) >= 0) {
 | |
| 
 | |
| 		ModifyTile(tile,
 | |
| 			MP_SETTYPE(MP_TREES) |
 | |
| 			MP_MAP2 | MP_MAP3LO | MP_MAP3HI | MP_MAP5,
 | |
| 			(m == 4 ? 0x10 : 0),
 | |
| 			tree,
 | |
| 			_map3_hi[tile] & ~3,
 | |
| 			0
 | |
| 		);
 | |
| 	}
 | |
| 
 | |
| 	// byte underflow
 | |
| 	if (--_trees_tick_ctr)
 | |
| 		return;
 | |
| 
 | |
| 	/* place a tree at a random spot */
 | |
| 	r = Random();
 | |
| 	tile = TILE_MASK(r);
 | |
| 	if (IS_TILETYPE(tile, MP_CLEAR) &&
 | |
| 			(m=_map5[tile]&0x1C, m==0 || m==4 || m==0x10) &&
 | |
| 			(tree=GetRandomTreeType(tile, r>>24)) >= 0) {
 | |
| 		int m2;
 | |
| 
 | |
| 		if (m == 0) {
 | |
| 			m2 = 0;
 | |
| 		} else if (m == 4) {
 | |
| 			m2 = 0x10;
 | |
| 		} else {
 | |
| 			m2 = ((_map5[tile] & 3) << 6) | 0x20;
 | |
| 		}
 | |
| 
 | |
| 		ModifyTile(tile,
 | |
| 			MP_SETTYPE(MP_TREES) |
 | |
| 			MP_MAP2 | MP_MAP3LO | MP_MAP3HI | MP_MAP5,
 | |
| 			m2,
 | |
| 			tree,
 | |
| 			_map3_hi[tile] & ~3,
 | |
| 			0
 | |
| 		);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void ClickTile_Trees(uint tile)
 | |
| {
 | |
| 	/* not used */
 | |
| }
 | |
| 
 | |
| static uint32 GetTileTrackStatus_Trees(uint tile, TransportType mode)
 | |
| {
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static void ChangeTileOwner_Trees(uint tile, byte old_player, byte new_player)
 | |
| {
 | |
| 	/* not used */
 | |
| }
 | |
| 
 | |
| void InitializeTrees()
 | |
| {
 | |
| 	_trees_tick_ctr = 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| const TileTypeProcs _tile_type_trees_procs = {
 | |
| 	DrawTile_Trees,						/* draw_tile_proc */
 | |
| 	GetSlopeZ_Trees,					/* get_slope_z_proc */
 | |
| 	ClearTile_Trees,					/* clear_tile_proc */
 | |
| 	GetAcceptedCargo_Trees,		/* get_accepted_cargo_proc */
 | |
| 	GetTileDesc_Trees,				/* get_tile_desc_proc */
 | |
| 	GetTileTrackStatus_Trees,	/* get_tile_track_status_proc */
 | |
| 	ClickTile_Trees,					/* click_tile_proc */
 | |
| 	AnimateTile_Trees,				/* animate_tile_proc */
 | |
| 	TileLoop_Trees,						/* tile_loop_clear */
 | |
| 	ChangeTileOwner_Trees,		/* change_tile_owner_clear */
 | |
| 	NULL,											/* get_produced_cargo_proc */
 | |
| 	NULL,											/* vehicle_enter_tile_proc */
 | |
| 	NULL,											/* vehicle_leave_tile_proc */
 | |
| 	GetSlopeTileh_Trees,			/* get_slope_tileh_proc */
 | |
| };
 | 
