function chunkSO::getTerrainHeight( %this, %x, %y )
{
	if ( strLen( %height = %this.terrainHeight[ %x, %y ] ) )
	{
		return %height;
	}
	
	%height = 64;
	
	if ( %height > 119 )
	{
		%height = 119;
	}
	
	%this.terrainHeight[ %x, %y ] = %height;
	return %height;
	
	%max = %height;
	%min = %height;
	
	for ( %nx = -1 ; %nx <= 1 ; %nx++ )
	{
		for ( %ny = -1 ; %ny <= 1 ; %ny++ )
		{
			%nb = "";
			%rx = %x + %nx;
			%ry = %y + %ny;
			
			if ( %rx >= 0 && %ry >= 0 && %rx <= 15 && %ry <= 15 )
			{
				%nb = %this.terrainHeight[ %rx, %ry ];
			}
			else
			{
				%cx = getWord( %this.position, 0 );
				%cy = getWord( %this.position, 1 );
				
				if ( %rx < 0 )
				{
					%cx -= 1;
					%rx += 16;
				}
				
				if ( %rx > 15 )
				{
					%cx += 1;
					%rx -= 16;
				}
				
				if ( %ry < 0 )
				{
					%cy -= 1;
					%ry += 16;
				}
				
				if ( %ry > 15 )
				{
					%cy += 1;
					%ry -= 16;
				}
				
				%nb = chunkSO( %cx, %cy ).terrainHeight[ %rx, %ry ];
			}
			
			if ( !strLen( %nb ) )
			{
				continue;
			}
			
			if ( %nb > %max )
			{
				%max = %nb;
			}
			
			if ( %nb < %min )
			{
				%min = %nb;
			}
		}
	}
	
	if ( false ) // First formula
	{
		// Rise
		%max++;
		
		// Run
		%min--;
		
		%height = getRandom( %min, %max );
	}
	
	if ( true ) // Second formula
	{
		%avg = mFloatLength( ( %min + %max ) / 2, 0 );
		%rnd = getRandom( -8, 8 );
		
		if ( %rnd == -8 )
		{
			%height = %avg - 1;
		}
		else if ( %rnd == 8 )
		{
			%height = %avg + 1;
		}
		else
		{
			%height = %avg;
		}
	}
	
	%this.terrainHeight[ %x, %y ] = %height;
	return %height;
}

function chunkSO::generateContent( %this, %callBack )
{
	// return;
	
	if ( vectorDist( "0 0 0", %this.position ) > 4 )
	{
		// return;
	}
	
	if ( $MC::Clearing )
	{
		return;
	}
	
	if ( %this.generated )
	{
		if ( strLen( %callBack ) )
		{
			eval( %this @ "." @ %callBack @ "();" );
		}
		
		return;
	}
	
	if ( isEventPending( %this.generateTick ) )
	{
		return;
	}
	
	for ( %x = 0 ; %x < 16 ; %x++ )
	{
		for ( %y = 0 ; %y < 16 ; %y++ )
		{
			%height = %this.getTerrainHeight( %x, %y );
			%this.setBlock( %x, %y, %height, "grass" );
			
			if ( %height < 62 )
			{
				for ( %z = %height + 1 ; %z <= 62 ; %z++ )
				{
					if ( %z < 48 )
					{
						continue;
					}
					
					%id = %this.setBlock( %x, %y, %z, "water" );
				}
				
				%water[ %x, %y ] = false;
			}
		}
	}
	
	// if ( getRandom( 0, 15 ) == 0 )
	if ( false )
	{
		%pondx = getRandom( 5, 11 );
		%pondy = getRandom( 5, 11 );
		%pondw = getRandom( 2, 7 );
		
		%this.generatePond( %pondx, %pondy, %pondw );
	}
	else
	{
		%tree_count = getRandom( -5, 3 );
		
		for ( %i = 0 ; %i < %tree_count ; %i++ )
		{
			%x = getRandom( 4, 12 );
			%y = getRandom( 4, 12 );
			
			%x = mFloor( %x / 2 ) * 2;
			%y = mFloor( %y / 2 ) * 2;
			
			if ( %water[ %x, %y ] )
			{
				continue;
			}
			
			if ( %madeTree[ %x, %y ] )
			{
				continue;
			}
			
			%madeTree[ %x, %y ] = true;
			
			%this.generateTree( %x, %y );
		}
		
		%mob_count = getRandom( -12, 1 );
		
		for ( %i = 0 ; %i < %mob_count ; %i++ )
		{
			%x = getRandom( 1, 15 );
			%y = getRandom( 1, 15 );
			
			%r = getRandom( 0, 5 );
			
			switch ( %r )
			{
				case 0: %type = "slime";
				case 1: %type = "slime";
				case 2: %type = "slime";
				case 3: %type = "slime_small";
				case 4: %type = "slime_small";
				case 5: %type = "slime_tiny";
			}
			
			%this.generateMob( %x, %y, %type );
		}
	}
	
	%this.generated = true;
	
	if ( strLen( %callBack ) )
	{
		eval( %this @ "." @ %callBack @ "();" );
	}
	
	// %this.generateTick = %this.schedule( 0, "generateTick", 0, %callBack );
}

function chunkSO::generateBelowTerrain( %px, %py, %pz, %bl, %th, %obj )
{
	if ( $MC::Clearing )
	{
		return;
	}
	
	// px: generate 1 block out from this starting point
	// py: generate 1 block out from this starting point
	// pz: generate 1 block out from this starting point
	// bl: the starting point is this amount of blocks below ground level
	// th: ground level at starting point
	// obj: an object at starting point
	
	for ( %x = -1 ; %x <= 1 ; %x++ )
	{
		for ( %y = -1 ; %y <= 1 ; %y++ )
		{
			for ( %z = -1 ; %z <= 1 ; %z++ )
			{
				%rx = %px + %x;
				%ry = %py + %y;
				%rz = %pz + %z;
				
				if ( %x == 0 && %y == 0 && %z == 0 )
				{
					continue;
				}
				
				if ( %rz > %th )  // Does this cause us to arrive on ground?
				{
					continue; // If so, don't screw with ground level; go to next iteration.
				}
				
				if ( %rz < 0 )     // Does this cause us to arrive below bedrock?
				{
					continue; // If so, don't cause index errors; go to next iteration.
				}
				
				if ( %rz > 255 )   // Does this cause us to arrive above world?
				{		  // (note: I'm not sure how this could happen)
					continue; // If so, don't cause index errors; go to next iteration.
				}
				
				if ( strLen( getBlock( %rx, %ry, %rz ) ) ) // Is there already something here?
				{
					continue;			// If so, don't overwrite it; go to next iteration.
				}
				
				if ( generatedBelowPoint( %rx, %ry, %rz ) ) // Did we already generate something here ..
				{					 // .. which was destroyed by some force?
					continue;			 // If so, don't generate it again; go to next iteration.
				}
				
				%dp = %bl - %z; // Determine distance to ground at current point.
				setGeneratedBelowPoint( %rx, %ry, %rz ); // Register that we're generating here.
				
				%block = "";
				
				if ( %dp < 3 )
				{
					%block = "dirt";
					
					if ( getRandom() <= 0.15 )
					{
						%block = "gravel";
					}
				}
				else
				{
					if ( %rz <= 7 )
					{
						%block = "smoothstone";
					}
					else if ( %rz <= 10 )
					{
						%block = "lava";
					}
					else
					{
						%block = "smoothstone";
						
						if ( getRandom() <= 0.1 )
						{
							%block = "gravel";
						}
						else
						{
							if ( %rz <= 63 && getRandom() <= 0.05 )
							{
								%block = "ironOre";
							}
							else if ( %rz <= 31 && getRandom() <= 0.05 )
							{
								%block = "goldOre";
							}
						}
					}
				}
				
				setBlock( %rx, %ry, %rz, %block );
			}
		}
	}
}

function chunkSO::generatePond( %this, %x, %y, %w )
{
	%min = 255;
	
	// Get lowest height.
	for ( %xi = %x - %w ; %xi < %x + %w ; %xi++ )
	{
		for ( %yi = %y - %w ; %yi < %y + %w ; %yi++ )
		{
			%height = %this.getTerrainHeight( %xi, %yi );
			
			if ( %height < %min || !strLen( %min ) )
			{
				%min = %height;
			}
		}
	}
	
	// Modify world.
	for ( %xi = %x - %w ; %xi < %x + %w ; %xi++ )
	{
		for ( %yi = %y - %w ; %yi < %y + %w ; %yi++ )
		{
			if ( vectorDist( %x SPC %y SPC 0, %xi SPC %yi SPC 0 ) > %w )
			{
				continue;
			}
			
			%height = %this.getTerrainHeight( %xi, %yi );
			
			%this.generatedBelowPoint[ %xi, %yi, %height - 1 ] = true;
			%this.setBlock( %xi, %yi, %height - 1, "sand" );
			
			if ( %height > %min )
			{
				%this.setBlock( %xi, %yi, %height, "sand" );
			}
			else
			{
				%this.setBlock( %xi, %yi, %height, "water" );
			}
		}
	}
}

function chunkSO::generateMob( %this, %x, %y, %type )
{
	%data = %x * 2 SPC %y * 2 SPC ( %this.getTerrainHeight( %x, %y ) + 1 ) * 2;
	%data = %data TAB "entitySO_playerData_mc_" @ %type @ "Mob";
	%data = %data TAB eulerToAxis( "0 0" SPC getRandom( -180, 180 ) );
	%data = %data TAB 0;
	
	%id = %this.addMobByData( %data );
}

function chunkSO::generateTree( %this, %x, %y )
{
	%terr = %this.getTerrainHeight( %x, %y );
	
	%height = getRandom( 3, 6 );
	%width = getRandom( ( %height - 3 < 1 ? %height - 2 : %height - 3 ), %height - 1 );
	
	// if ( %width >= %height - 1 )
	// {
	// 	%width = %height - 1;
	// 	
	// 	if ( %width > 5 )
	// 	{
	// 		%width = 5;
	// 	}
	// }
	
	for ( %z = 1 ; %z <= %height ; %z++ )
	{
		%this.setBlock( %x, %y, %terr + %z, "trunk" );
	}
	
	%trp = %x SPC %y SPC %terr + %height;
	
	//echo( "---" );
	//echo( %trp );
	//echo( %x - %width SPC %x + %width );
	//echo( %y - %width SPC %y + %width );
	//echo( 3 SPC 2 + %height );
	
	for ( %xi = %x - 4 ; %xi <= %x + 4 ; %xi++ )
	{
		for ( %yi = %y - 4 ; %yi <= %y + 4 ; %yi++ )
		{
			for ( %zi = %terr + 1 ; %zi <= %terr + 6 ; %zi++ )
			{
				if ( %xi == %x && %yi == %y && %zi <= %terr + %height )
				{
					continue;
				}
				
				if ( vectorDist( %xi SPC %yi SPC %zi, %trp ) > %width )
				{
					continue;
				}
				
				%this.setBlock( %xi, %yi, %zi, "leaves" );
			}
		}
	}
}

return;

function isInt(%string)
{
	return ( %str $= mFloatLength( %str, 0 ) );
}

$TPX::MinTerrainLevel = -4;
$TPX::Height = 7;		//determines how laggy this will be
$TPX::Maxchange = 1;		//determines how hilly a terrain will be, dont be a fag and make this 0
$TPX::Smooth = 3;		//determines how unhilly a terrain will be, dont be a fag and make this negative

function getMCTerrainHeight( %x, %y, %obj )
{
	%group = chunkGroup();
	
	// If it is already generated, just return it's height value.
	if ( %group.generated[ %x, %y ] )
	{
		return %group.height[ %x, %y ];
	}
	
	// return getField( strReplace( getWord( getDateTime(), 1 ), ":", "\t" ), 2 );
	// return %x + %y;
	
	// if ( isObject( %obj ) && isObject( %cl = %obj.client ) )
	// {
	// 	return mFloatLength( ( %cl.getPing() / 10 ) / 4, 0 );
	// }
	
	%maxChange = $TPX::MaxChange;
	%cmax = $TPX::Height - 1;
	%smooth = $TPX::Smooth;
	
	%cmin = 0;
	%dist = mCeil( ( %cmax + 1 ) / %maxChange );

	for ( %a = %dist * -1 ; %a <= %dist ; %a++ )
	{
		for ( %b = ( %dist - mAbs( %a ) ) *-1 ; %b <= %dist - mAbs( %a ) ; %b++ )
		{
			if ( strLen( %rise = %group.height[ %x + %a, %y + %b ] ) )
			{
				%run = mAbs( %a ) + mAbs( %b );
				%max = %rise + %run*%maxchange; //rise over run is for weaklings
				%min = %rise - %run*%maxchange;

				if(%max < %cmax)
					%cmax = %max;

				if(%min > %cmin)
					%cmin = %min;

				if(%cmax == %cmin) //why bother continuing?
				{
					%c = true;
					break;
				}
			}
		}

		if(%c)
			break;
	}

	if(%cmax < %cmin) //someone is fucking around
		%cmax = %cmin;
	%z = getrandom(%cmin, %cmax + %smooth);
	%avg = (%cmin + %cmax)/2; //oh lol i just got realized... cmin

	if(%z < %avg || !%smooth)
		%height = %z;
	else if(%z > %avg + %smooth) //like a boss
		%height = %z - %smooth;
	else
	{
		if(!isint(%avg))
			%avg = mfloor(%avg) + getrandom(0, 1);
		%height = %avg;
	}
	
	return %height;
}

function generateTerrainRow( %chunk, %group, %x, %y )
{
	// %cube_x = %x * 2;
	// %cube_y = %y * 2;
	
	// %height = getMCTerrainHeight( %x, %y );
	
	// if ( %height < 0 )
	// {
		%height = 0;
	// }
	
	// %group.height[ %x, %y ] = %height;
	
	// for ( %i = %height ; %i >= 0 ; %i-- )
	// {
		%data = %x SPC %y SPC 0;
		%data = %data TAB entitySO_fxDTSBrickData_mc_grassBlock;
		%data = %data TAB "";
		%data = %data TAB "";
		%data = %data TAB entitySO_fxDTSBrickData_mc_grassBlock.forceColor;
		%data = %data TAB "";
		%data = %data TAB "";
	// }
	
	%id = %chunk.addBlockByData( %data );
}