static void PlantTrees(ForesterArgs args, ICollection <Tree> treeList) { int treeHeight = args.Height; int attempts = 0; while (treeList.Count < args.TreeCount && attempts < MaxTries) { attempts++; int height = args.Rand.Next(treeHeight - args.HeightVariation, treeHeight + args.HeightVariation + 1); Vector3I treeLoc = FindRandomTreeLocation(args, height); if (treeLoc.Y < 0) { continue; } else { treeLoc.Y++; } treeList.Add(new Tree { Args = args, Height = height, Pos = treeLoc }); } }
static void PlantRainForestTrees(ForesterArgs args, ICollection <Tree> treeList) { int treeHeight = args.Height; int existingTreeNum = treeList.Count; int remainingTrees = args.TreeCount - existingTreeNum; const int shortTreeFraction = 6; int attempts = 0; for (int i = 0; i < remainingTrees && attempts < MaxTries; attempts++) { float randomFac = (float)((Math.Sqrt(args.Rand.NextDouble()) * 1.618 - .618) * args.HeightVariation + .5); int height; if (i % shortTreeFraction == 0) { height = (int)(treeHeight + randomFac); } else { height = (int)(treeHeight - randomFac); } Vector3I xyz = FindRandomTreeLocation(args, height); if (xyz.Y < 0) { continue; } xyz.Y++; bool displaced = false; foreach (Tree otherTree in treeList) { Vector3I otherLoc = otherTree.Pos; int tallX = otherLoc[0]; int tallZ = otherLoc[2]; float dist = (float)Math.Sqrt(Sqr(tallX - xyz.X + .5) + Sqr(tallZ - xyz.Z + .5)); float threshold = (otherTree.Height + height) * .193f; if (dist < threshold) { displaced = true; break; } } if (displaced) { continue; } treeList.Add(new RainforestTree { Args = args, Pos = xyz, Height = height }); i++; } }
public static void Generate([NotNull] ForesterArgs args) { if (args == null) { throw new ArgumentNullException("args"); } args.Validate(); List <Tree> treeList = new List <Tree>(); if (args.Operation == ForesterOperation.Conserve) { FindTrees(args, treeList); } if (args.TreeCount > 0 && treeList.Count > args.TreeCount) { treeList = treeList.Take(args.TreeCount).ToList(); } if (args.Operation == ForesterOperation.Replant || args.Operation == ForesterOperation.Add) { switch (args.Shape) { case TreeShape.Rainforest: PlantRainForestTrees(args, treeList); break; case TreeShape.Mangrove: PlantMangroves(args, treeList); break; default: PlantTrees(args, treeList); break; } } if (args.Operation == ForesterOperation.ClearCut) { return; } ProcessTrees(args, treeList); if (args.Foliage) { foreach (Tree tree in treeList) { tree.MakeFoliage(); } } if (args.Wood) { foreach (Tree tree in treeList) { tree.MakeTrunk(); } } }
public void Copy([NotNull] Tree other) { if (other == null) { throw new ArgumentNullException("other"); } Args = other.Args; Pos = other.Pos; Height = other.Height; }
static void FindTrees([NotNull] ForesterArgs args, [NotNull] ICollection <Tree> treeList) { if (args == null) { throw new ArgumentNullException("args"); } if (treeList == null) { throw new ArgumentNullException("treeList"); } int treeHeight = args.Height; for (int x = 0; x < args.Map.Width; x++) { for (int z = 0; z < args.Map.Length; z++) { int y = args.Map.Height - 1; while (true) { int foliageTop = args.Map.SearchColumn(x, z, args.FoliageBlock, y); if (foliageTop < 0) { break; } y = foliageTop; Vector3I trunkTop = new Vector3I(x, y - 1, z); int height = DistanceToBlock(args.Map, new Vector3F(trunkTop), Vector3F.Down, args.TrunkBlock, true); if (height == 0) { y--; continue; } y -= height; if (args.Height > 0) { height = args.Rand.Next(treeHeight - args.HeightVariation, treeHeight + args.HeightVariation + 1); } treeList.Add(new Tree { Args = args, Pos = new Vector3I(x, y, z), Height = height }); y--; } } } }
static Vector3I FindRandomTreeLocation(ForesterArgs args, int height) { int padding = (int)(height / 3f + 1); int minDim = Math.Min(args.Map.Width, args.Map.Length); if (padding > minDim / 2.2) { padding = (int)(minDim / 2.2); } int x = args.Rand.Next(padding, args.Map.Width - padding - 1); int z = args.Rand.Next(padding, args.Map.Length - padding - 1); int y = args.Map.SearchColumn(x, z, args.PlantOn); return(new Vector3I(x, y, z)); }
static void PlantMangroves([NotNull] ForesterArgs args, [NotNull] ICollection <Tree> treeList) { if (args == null) { throw new ArgumentNullException("args"); } if (treeList == null) { throw new ArgumentNullException("treeList"); } int treeHeight = args.Height; int attempts = 0; while (treeList.Count < args.TreeCount && attempts < MaxTries) { attempts++; int height = args.Rand.Next(treeHeight - args.HeightVariation, treeHeight + args.HeightVariation + 1); int padding = (int)(height / 3f + 1); int minDim = Math.Min(args.Map.Width, args.Map.Length); if (padding > minDim / 2.2) { padding = (int)(minDim / 2.2); } int x = args.Rand.Next(padding, args.Map.Width - padding - 1); int z = args.Rand.Next(padding, args.Map.Length - padding - 1); int top = args.Map.Height - 1; int y = top - DistanceToBlock(args.Map, new Vector3F(x, z, top), Vector3F.Down, Block.Air, true); int dist = DistanceToBlock(args.Map, new Vector3F(x, z, y), Vector3F.Down, Block.Water, true); if (dist > height * .618 || dist == 0) { continue; } y += (int)Math.Sqrt(height - dist) + 2; treeList.Add(new Tree { Args = args, Height = height, Pos = new Vector3I(x, y, z) }); } }
public static void Plant([NotNull] ForesterArgs args, Vector3I treeCoordinate) { List <Tree> treeList = new List <Tree> { new Tree { Args = args, Height = args.Height, Pos = treeCoordinate } }; switch (args.Shape) { case TreeShape.Rainforest: PlantRainForestTrees(args, treeList); break; case TreeShape.Mangrove: PlantMangroves(args, treeList); break; default: PlantTrees(args, treeList); break; } ProcessTrees(args, treeList); if (args.Foliage) { foreach (Tree tree in treeList) { tree.MakeFoliage(); } } if (args.Wood) { foreach (Tree tree in treeList) { tree.MakeTrunk(); } } }
void PlantGiantTrees() { if (genParams.GiantTreeDensity <= 0) { return; } Map outMap = new Map(null, map.Width, map.Length, map.Height, false) { Blocks = (byte[])map.Blocks.Clone() }; int plantableBlocks = ComputeSurfaceCoverage(Block.Grass); var foresterArgs = new ForesterArgs { Map = map, Rand = rand, TreeCount = (int)(plantableBlocks * genParams.GiantTreeDensity / BaseGiantTreeDensity), Operation = Forester.ForesterOperation.Add, PlantOn = Block.Grass }; foresterArgs.BlockPlacing += (sender, e) => outMap.SetBlock(e.Coordinate, e.Block); Forester.Generate(foresterArgs); map = outMap; }
static void PlantTrees([NotNull] ForesterArgs args, [NotNull] ICollection <Tree> treeList) { if (args == null) { throw new ArgumentNullException("args"); } if (treeList == null) { throw new ArgumentNullException("treeList"); } int treeHeight = args.Height; int attempts = 0; while (treeList.Count < args.TreeCount && attempts < MaxTries) { attempts++; int height = args.Rand.Next(treeHeight - args.HeightVariation, treeHeight + args.HeightVariation + 1); Vector3I treeLoc = FindRandomTreeLocation(args, height); if (treeLoc.Y < 0) { continue; } else { treeLoc.Y++; } treeList.Add(new Tree { Args = args, Height = height, Pos = treeLoc }); } }
static Vector3I FindRandomTreeLocation( ForesterArgs args, int height ) { int padding = (int)(height / 3f + 1); int minDim = Math.Min( args.Map.Width, args.Map.Length ); if( padding > minDim / 2.2 ) { padding = (int)(minDim / 2.2); } int x = args.Rand.Next( padding, args.Map.Width - padding - 1 ); int z = args.Rand.Next( padding, args.Map.Length - padding - 1 ); int y = args.Map.SearchColumn( x, z, args.PlantOn ); return new Vector3I( x, y, z); }
static void PlantTrees( ForesterArgs args, ICollection<Tree> treeList ) { int treeHeight = args.Height; int attempts = 0; while( treeList.Count < args.TreeCount && attempts < MaxTries ) { attempts++; int height = args.Rand.Next( treeHeight - args.HeightVariation, treeHeight + args.HeightVariation + 1 ); Vector3I treeLoc = FindRandomTreeLocation( args, height ); if( treeLoc.Y < 0 ) continue; else treeLoc.Y++; treeList.Add( new Tree { Args = args, Height = height, Pos = treeLoc } ); } }
static void FindTrees( ForesterArgs args, ICollection<Tree> treeList ) { int treeHeight = args.Height; for( int x = 0; x < args.Map.Width; x++ ) { for( int z = 0; z < args.Map.Length; z++ ) { int y = args.Map.Height - 1; while( true ) { int foliageTop = args.Map.SearchColumn( x, z, args.FoliageBlock, y ); if( foliageTop < 0 ) break; y = foliageTop; Vector3I trunkTop = new Vector3I( x, y - 1, z ); int height = DistanceToBlock( args.Map, new Vector3F( trunkTop ), Vector3F.Down, args.TrunkBlock, true ); if( height == 0 ) { y--; continue; } y -= height; if( args.Height > 0 ) { height = args.Rand.Next( treeHeight - args.HeightVariation, treeHeight + args.HeightVariation + 1 ); } treeList.Add( new Tree { Args = args, Pos = new Vector3I( x, y, z ), Height = height } ); y--; } } } }
Map GenerateMap() { Map map = new Map( null, genParams.MapWidth, genParams.MapLength, genParams.MapHeight, true ); theme = genParams.Theme; // scale features vertically based on map height double verticalScale = (genParams.MapHeight / 96.0) / 2 + 0.5; maxHeightScaled = (int)Math.Round( genParams.MaxHeight * verticalScale ); maxDepthScaled = (int)Math.Round( genParams.MaxDepth * verticalScale ); snowAltitudeScaled = (int)Math.Round( genParams.SnowAltitude * verticalScale ); // Match water coverage float desiredWaterLevel = .5f; if( genParams.MatchWaterCoverage ) { ReportRelativeProgress( 2, "Heightmap Processing: Matching water coverage" ); // find a number between 0 and 1 ("desiredWaterLevel") for the heightmap such that // the fraction of heightmap coordinates ("blocks") that are below this threshold ("underwater") // match the specified WaterCoverage desiredWaterLevel = Noise.FindThreshold( heightmap, genParams.WaterCoverage ); } // Calculate above/below water multipliers float aboveWaterMultiplier = 0; if( desiredWaterLevel < 1 ) { aboveWaterMultiplier = (maxHeightScaled / (1 - desiredWaterLevel)); } // Apply power functions to above/below water parts of the heightmap if( Math.Abs( genParams.BelowFuncExponent - 1 ) > float.Epsilon || Math.Abs( genParams.AboveFuncExponent - 1 ) > float.Epsilon ) { ReportRelativeProgress( 5, "Heightmap Processing: Adjusting slope" ); for( int x = heightmap.GetLength( 0 ) - 1; x >= 0; x-- ) { for( int y = heightmap.GetLength( 1 ) - 1; y >= 0; y-- ) { if( heightmap[x, y] < desiredWaterLevel ) { float normalizedDepth = 1 - heightmap[x, y]/desiredWaterLevel; heightmap[x, y] = desiredWaterLevel - (float)Math.Pow( normalizedDepth, genParams.BelowFuncExponent )* desiredWaterLevel; } else { float normalizedHeight = (heightmap[x, y] - desiredWaterLevel)/(1 - desiredWaterLevel); heightmap[x, y] = desiredWaterLevel + (float)Math.Pow( normalizedHeight, genParams.AboveFuncExponent )* (1 - desiredWaterLevel); } } } } // Calculate the slope if( genParams.CliffSmoothing ) { ReportRelativeProgress( 2, "Heightmap Processing: Smoothing" ); slopemap = Noise.CalculateSlope( Noise.GaussianBlur5X5( heightmap ) ); } else { slopemap = Noise.CalculateSlope( heightmap ); } // Randomize max height/depth float[,] altmap = null; if( genParams.MaxHeightVariation != 0 || genParams.MaxDepthVariation != 0 ) { ReportRelativeProgress( 5, "Heightmap Processing: Randomizing" ); altmap = new float[map.Width,map.Length]; int blendmapDetailSize = (int)Math.Log( Math.Max( genParams.MapWidth, genParams.MapLength ), 2 ) - 2; new Noise( rand.Next(), NoiseInterpolationMode.Cosine ) .PerlinNoise( altmap, Math.Min( blendmapDetailSize, 3 ), blendmapDetailSize, 0.5f, 0, 0 ); Noise.Normalize( altmap, -1, 1 ); } int snowStartThreshold = snowAltitudeScaled - genParams.SnowTransition; int snowThreshold = snowAltitudeScaled; ReportRelativeProgress( 10, "Filling" ); if( theme.AirBlock != Block.Air ) { map.Blocks.MemSet( (byte)theme.AirBlock ); } for( int x = heightmap.GetLength( 0 ) - 1; x >= 0; x-- ) { for( int y = heightmap.GetLength( 1 ) - 1; y >= 0; y-- ) { int level; float slope; if( heightmap[x, y] < desiredWaterLevel ) { // for blocks below "sea level" float depth = maxDepthScaled; if( altmap != null ) { depth += altmap[x, y] * genParams.MaxDepthVariation; } slope = slopemap[x, y] * depth; level = genParams.WaterLevel - (int)Math.Round( Math.Pow( 1 - heightmap[x, y] / desiredWaterLevel, genParams.BelowFuncExponent ) * depth ); if( genParams.AddWater ) { if( genParams.WaterLevel - level > 3 ) { map.SetBlock( x, y, genParams.WaterLevel, theme.DeepWaterSurfaceBlock ); } else { map.SetBlock( x, y, genParams.WaterLevel, theme.WaterSurfaceBlock ); } for( int i = genParams.WaterLevel; i > level; i-- ) { map.SetBlock( x, y, i, theme.WaterBlock ); } for( int i = level; i >= 0; i-- ) { if( level - i < theme.SeaFloorThickness ) { map.SetBlock( x, y, i, theme.SeaFloorBlock ); } else { map.SetBlock( x, y, i, theme.BedrockBlock ); } } } else { if( blendmap != null && blendmap[x, y] > .25 && blendmap[x, y] < .75 ) { map.SetBlock( x, y, level, theme.CliffBlock ); } else { if( slope < genParams.CliffThreshold ) { map.SetBlock( x, y, level, theme.GroundSurfaceBlock ); } else { map.SetBlock( x, y, level, theme.CliffBlock ); } } for( int i = level - 1; i >= 0; i-- ) { if( level - i < theme.GroundThickness ) { if( blendmap != null && blendmap[x, y] > CliffsideBlockThreshold && blendmap[x, y] < (1 - CliffsideBlockThreshold) ) { map.SetBlock( x, y, i, theme.CliffBlock ); } else { if( slope < genParams.CliffThreshold ) { map.SetBlock( x, y, i, theme.GroundBlock ); } else { map.SetBlock( x, y, i, theme.CliffBlock ); } } } else { map.SetBlock( x, y, i, theme.BedrockBlock ); } } } } else { // for blocks above "sea level" float height; if( altmap != null ) { height = maxHeightScaled + altmap[x, y] * genParams.MaxHeightVariation; } else { height = maxHeightScaled; } slope = slopemap[x, y] * height; if( height != 0 ) { level = genParams.WaterLevel + (int)Math.Round( Math.Pow( heightmap[x, y] - desiredWaterLevel, genParams.AboveFuncExponent )* aboveWaterMultiplier/maxHeightScaled*height ); } else { level = genParams.WaterLevel; } bool snow = genParams.AddSnow && (level > snowThreshold || (level > snowStartThreshold && rand.NextDouble() < (level - snowStartThreshold) / (double)(snowThreshold - snowStartThreshold))); if( blendmap != null && blendmap[x, y] > .25 && blendmap[x, y] < .75 ) { map.SetBlock( x, y, level, theme.CliffBlock ); } else { if( slope < genParams.CliffThreshold ) { map.SetBlock( x, y, level, (snow ? theme.SnowBlock : theme.GroundSurfaceBlock) ); } else { map.SetBlock( x, y, level, theme.CliffBlock ); } } for( int i = level - 1; i >= 0; i-- ) { if( level - i < theme.GroundThickness ) { if( blendmap != null && blendmap[x, y] > CliffsideBlockThreshold && blendmap[x, y] < (1 - CliffsideBlockThreshold) ) { map.SetBlock( x, y, i, theme.CliffBlock ); } else { if( slope < genParams.CliffThreshold ) { if( snow ) { map.SetBlock( x, y, i, theme.SnowBlock ); } else { map.SetBlock( x, y, i, theme.GroundBlock ); } } else { map.SetBlock( x, y, i, theme.CliffBlock ); } } } else { map.SetBlock( x, y, i, theme.BedrockBlock ); } } } } } if( genParams.AddCaves || genParams.AddOre ) { AddCaves( map ); } if( genParams.AddBeaches ) { ReportRelativeProgress( 5, "Processing: Adding beaches" ); AddBeaches( map ); } if( genParams.AddTrees ) { ReportRelativeProgress( 5, "Processing: Planting trees" ); if( genParams.AddGiantTrees ) { Map outMap = new Map( null, map.Width, map.Length, map.Height, false ) { Blocks = (byte[])map.Blocks.Clone() }; var foresterArgs = new ForesterArgs { Map = map, Rand = rand, TreeCount = (int)(map.Width * map.Length * 4 / (1024f * (genParams.TreeSpacingMax + genParams.TreeSpacingMin) / 2)), Operation = Forester.ForesterOperation.Add, PlantOn = theme.GroundSurfaceBlock }; foresterArgs.BlockPlacing += ( sender, e ) => outMap.SetBlock( e.Coordinate, e.Block ); Forester.Generate( foresterArgs ); map = outMap; } GenerateTrees( map ); } if( genParams.AddFloodBarrier ) { MakeFloodBarrier( map ); } return map; }
public void Copy(Tree other) { Args = other.Args; Pos = other.Pos; Height = other.Height; }
static void ProcessTrees( ForesterArgs args, IList<Tree> treeList ) { TreeShape[] shapeChoices; switch( args.Shape ) { case TreeShape.Stickly: shapeChoices = new[]{ TreeShape.Normal, TreeShape.Bamboo, TreeShape.Palm }; break; case TreeShape.Procedural: shapeChoices = new[]{ TreeShape.Round, TreeShape.Cone }; break; default: shapeChoices = new[] { args.Shape }; break; } for( int i = 0; i < treeList.Count; i++ ) { TreeShape newShape = shapeChoices[args.Rand.Next( 0, shapeChoices.Length )]; Tree newTree; switch( newShape ) { case TreeShape.Normal: newTree = new NormalTree(); break; case TreeShape.Bamboo: newTree = new BambooTree(); break; case TreeShape.Palm: newTree = new PalmTree(); break; case TreeShape.Round: newTree = new RoundTree(); break; case TreeShape.Cone: newTree = new ConeTree(); break; case TreeShape.Rainforest: newTree = new RainforestTree(); break; case TreeShape.Mangrove: newTree = new MangroveTree(); break; default: throw new ArgumentException( "Unknown tree shape type" ); } newTree.Copy( treeList[i] ); if( args.MapHeightLimit ) { int height = newTree.Height; int yBase = newTree.Pos[1]; int mapHeight = args.Map.Height; int foliageHeight; if( args.Shape == TreeShape.Rainforest ) { foliageHeight = 2; } else { foliageHeight = 4; } if( yBase + height + foliageHeight > mapHeight ) { newTree.Height = mapHeight - yBase - foliageHeight; } } if( newTree.Height < 1 ) newTree.Height = 1; newTree.Prepare(); treeList[i] = newTree; } }
static void PlantRainForestTrees( ForesterArgs args, ICollection<Tree> treeList ) { int treeHeight = args.Height; int existingTreeNum = treeList.Count; int remainingTrees = args.TreeCount - existingTreeNum; const int shortTreeFraction = 6; int attempts = 0; for( int i = 0; i < remainingTrees && attempts < MaxTries; attempts++ ) { float randomFac = (float)( ( Math.Sqrt( args.Rand.NextDouble() ) * 1.618 - .618 ) * args.HeightVariation + .5 ); int height; if( i % shortTreeFraction == 0 ) { height = (int)( treeHeight + randomFac ); } else { height = (int)( treeHeight - randomFac ); } Vector3I xyz = FindRandomTreeLocation( args, height ); if( xyz.Y < 0 ) continue; xyz.Y++; bool displaced = false; foreach( Tree otherTree in treeList ) { Vector3I otherLoc = otherTree.Pos; int tallX = otherLoc[0]; int tallZ = otherLoc[2]; float dist = (float)Math.Sqrt( Sqr( tallX - xyz.X + .5 ) + Sqr( tallZ - xyz.Z + .5 ) ); float threshold = ( otherTree.Height + height ) * .193f; if( dist < threshold ) { displaced = true; break; } } if( displaced ) continue; treeList.Add( new RainforestTree { Args = args, Pos = xyz, Height = height } ); i++; } }
void PlantGiantTrees() { if( genParams.GiantTreeDensity <= 0 ) return; Map outMap = new Map( null, map.Width, map.Length, map.Height, false ) { Blocks = (byte[])map.Blocks.Clone() }; int plantableBlocks = ComputeSurfaceCoverage( Block.Grass ); var foresterArgs = new ForesterArgs { Map = map, Rand = rand, TreeCount = (int)(plantableBlocks*genParams.GiantTreeDensity/BaseGiantTreeDensity), Operation = Forester.ForesterOperation.Add, PlantOn = Block.Grass }; foresterArgs.BlockPlacing += ( sender, e ) => outMap.SetBlock( e.Coordinate, e.Block ); Forester.Generate( foresterArgs ); map = outMap; }
Map GenerateMap() { Map map = new Map(null, genParams.MapWidth, genParams.MapLength, genParams.MapHeight, true); theme = genParams.Theme; // scale features vertically based on map height double verticalScale = (genParams.MapHeight / 96.0) / 2 + 0.5; maxHeightScaled = (int)Math.Round(genParams.MaxHeight * verticalScale); maxDepthScaled = (int)Math.Round(genParams.MaxDepth * verticalScale); snowAltitudeScaled = (int)Math.Round(genParams.SnowAltitude * verticalScale); // Match water coverage float desiredWaterLevel = .5f; if (genParams.MatchWaterCoverage) { ReportRelativeProgress(2, "Heightmap Processing: Matching water coverage"); // find a number between 0 and 1 ("desiredWaterLevel") for the heightmap such that // the fraction of heightmap coordinates ("blocks") that are below this threshold ("underwater") // match the specified WaterCoverage desiredWaterLevel = Noise.FindThreshold(heightMap, genParams.WaterCoverage); } // Calculate above/below water multipliers float aboveWaterMultiplier = 0; if (desiredWaterLevel < 1) { aboveWaterMultiplier = (maxHeightScaled / (1 - desiredWaterLevel)); } // Apply power functions to above/below water parts of the heightmap if (Math.Abs(genParams.BelowFuncExponent - 1) > float.Epsilon || Math.Abs(genParams.AboveFuncExponent - 1) > float.Epsilon) { ReportRelativeProgress(5, "Heightmap Processing: Adjusting slope"); for (int x = heightMap.GetLength(0) - 1; x >= 0; x--) { for (int y = heightMap.GetLength(1) - 1; y >= 0; y--) { if (heightMap[x, y] < desiredWaterLevel) { float normalizedDepth = 1 - heightMap[x, y] / desiredWaterLevel; heightMap[x, y] = desiredWaterLevel - (float)Math.Pow(normalizedDepth, genParams.BelowFuncExponent) * desiredWaterLevel; } else { float normalizedHeight = (heightMap[x, y] - desiredWaterLevel) / (1 - desiredWaterLevel); heightMap[x, y] = desiredWaterLevel + (float)Math.Pow(normalizedHeight, genParams.AboveFuncExponent) * (1 - desiredWaterLevel); } } } } // Calculate the slope if (genParams.CliffSmoothing) { ReportRelativeProgress(2, "Heightmap Processing: Smoothing"); slopeMap = Noise.CalculateSteepness(Noise.GaussianBlur5X5(heightMap)); } else { slopeMap = Noise.CalculateSteepness(heightMap); } // Randomize max height/depth float[,] altMap = null; if (genParams.MaxHeightVariation != 0 || genParams.MaxDepthVariation != 0) { ReportRelativeProgress(5, "Heightmap Processing: Randomizing"); altMap = new float[map.Width, map.Length]; int blendMapDetailSize = (int)Math.Log(Math.Max(genParams.MapWidth, genParams.MapLength), 2) - 2; new Noise(rand.Next(), NoiseInterpolationMode.Cosine) .PerlinNoise(altMap, Math.Min(blendMapDetailSize, 3), blendMapDetailSize, 0.5f, 0, 0); Noise.Normalize(altMap, -1, 1); } int snowStartThreshold = snowAltitudeScaled - genParams.SnowTransition; int snowThreshold = snowAltitudeScaled; ReportRelativeProgress(10, "Filling"); if (theme.AirBlock != Block.Air) { map.Blocks.MemSet((byte)theme.AirBlock); } for (int x = heightMap.GetLength(0) - 1; x >= 0; x--) { for (int y = heightMap.GetLength(1) - 1; y >= 0; y--) { int level; float slope; if (heightMap[x, y] < desiredWaterLevel) { // for blocks below "sea level" float depth = maxDepthScaled; if (altMap != null) { depth += altMap[x, y] * genParams.MaxDepthVariation; } slope = slopeMap[x, y] * depth; level = genParams.WaterLevel - (int) Math.Round( Math.Pow(1 - heightMap[x, y] / desiredWaterLevel, genParams.BelowFuncExponent) * depth); if (genParams.AddWater) { if (genParams.WaterLevel - level > 3) { map.SetBlock(x, y, genParams.WaterLevel, theme.DeepWaterSurfaceBlock); } else { map.SetBlock(x, y, genParams.WaterLevel, theme.WaterSurfaceBlock); } for (int i = genParams.WaterLevel; i > level; i--) { map.SetBlock(x, y, i, theme.WaterBlock); } for (int i = level; i >= 0; i--) { if (level - i < theme.SeaFloorThickness) { map.SetBlock(x, y, i, theme.SeaFloorBlock); } else { map.SetBlock(x, y, i, theme.BedrockBlock); } } } else { if (blendMap != null && blendMap[x, y] > .25 && blendMap[x, y] < .75) { map.SetBlock(x, y, level, theme.CliffBlock); } else { if (slope < genParams.CliffThreshold) { map.SetBlock(x, y, level, theme.GroundSurfaceBlock); } else { map.SetBlock(x, y, level, theme.CliffBlock); } } for (int i = level - 1; i >= 0; i--) { if (level - i < theme.GroundThickness) { if (blendMap != null && blendMap[x, y] > CliffsideBlockThreshold && blendMap[x, y] < (1 - CliffsideBlockThreshold)) { map.SetBlock(x, y, i, theme.CliffBlock); } else { if (slope < genParams.CliffThreshold) { map.SetBlock(x, y, i, theme.GroundBlock); } else { map.SetBlock(x, y, i, theme.CliffBlock); } } } else { map.SetBlock(x, y, i, theme.BedrockBlock); } } } } else { // for blocks above "sea level" float height; if (altMap != null) { height = maxHeightScaled + altMap[x, y] * genParams.MaxHeightVariation; } else { height = maxHeightScaled; } slope = slopeMap[x, y] * height; if (height != 0) { level = genParams.WaterLevel + (int) Math.Round( Math.Pow(heightMap[x, y] - desiredWaterLevel, genParams.AboveFuncExponent) * aboveWaterMultiplier / maxHeightScaled * height); } else { level = genParams.WaterLevel; } bool snow = genParams.AddSnow && (level > snowThreshold || (level > snowStartThreshold && rand.NextDouble() < (level - snowStartThreshold) / (double)(snowThreshold - snowStartThreshold))); if (blendMap != null && blendMap[x, y] > .25 && blendMap[x, y] < .75) { map.SetBlock(x, y, level, theme.CliffBlock); } else { if (slope < genParams.CliffThreshold) { map.SetBlock(x, y, level, (snow ? theme.SnowBlock : theme.GroundSurfaceBlock)); } else { map.SetBlock(x, y, level, theme.CliffBlock); } } for (int i = level - 1; i >= 0; i--) { if (level - i < theme.GroundThickness) { if (blendMap != null && blendMap[x, y] > CliffsideBlockThreshold && blendMap[x, y] < (1 - CliffsideBlockThreshold)) { map.SetBlock(x, y, i, theme.CliffBlock); } else { if (slope < genParams.CliffThreshold) { if (snow) { map.SetBlock(x, y, i, theme.SnowBlock); } else { map.SetBlock(x, y, i, theme.GroundBlock); } } else { map.SetBlock(x, y, i, theme.CliffBlock); } } } else { map.SetBlock(x, y, i, theme.BedrockBlock); } } } } } if (genParams.AddCaves || genParams.AddOre) { AddCaves(map); } if (genParams.AddBeaches) { ReportRelativeProgress(5, "Processing: Adding beaches"); AddBeaches(map); } if (genParams.AddTrees) { ReportRelativeProgress(5, "Processing: Planting trees"); if (genParams.AddGiantTrees) { Map outMap = new Map(null, map.Width, map.Length, map.Height, false) { Blocks = (byte[])map.Blocks.Clone() }; var foresterArgs = new ForesterArgs { Map = map, Rand = rand, TreeCount = (int) (map.Width * map.Length * 4 / (1024f * (genParams.TreeSpacingMax + genParams.TreeSpacingMin) / 2)), Operation = Forester.ForesterOperation.Add, PlantOn = theme.GroundSurfaceBlock }; foresterArgs.BlockPlacing += (sender, e) => outMap.SetBlock(e.Coordinate, e.Block); Forester.Generate(foresterArgs); map = outMap; } GenerateTrees(map); } if (genParams.AddFloodBarrier) { MakeFloodBarrier(map); } return(map); }
static void PlantMangroves( ForesterArgs args, ICollection<Tree> treeList ) { int treeHeight = args.Height; int attempts = 0; while( treeList.Count < args.TreeCount && attempts < MaxTries ) { attempts++; int height = args.Rand.Next( treeHeight - args.HeightVariation, treeHeight + args.HeightVariation + 1 ); int padding = (int)(height / 3f + 1); int minDim = Math.Min( args.Map.Width, args.Map.Length ); if( padding > minDim / 2.2 ) { padding = (int)(minDim / 2.2); } int x = args.Rand.Next( padding, args.Map.Width - padding - 1 ); int z = args.Rand.Next( padding, args.Map.Length - padding - 1 ); int top = args.Map.Height - 1; int y = top - DistanceToBlock( args.Map, new Vector3F( x, z, top ), Vector3F.Down, Block.Air, true ); int dist = DistanceToBlock( args.Map, new Vector3F( x, z, y ), Vector3F.Down, Block.Water, true ); if( dist > height * .618 || dist == 0 ) { continue; } y += (int)Math.Sqrt( height - dist ) + 2; treeList.Add( new Tree { Args = args, Height = height, Pos = new Vector3I( x, y, z ) } ); } }
static void ProcessTrees(ForesterArgs args, IList <Tree> treeList) { TreeShape[] shapeChoices; switch (args.Shape) { case TreeShape.Stickly: shapeChoices = new[] { TreeShape.Normal, TreeShape.Bamboo, TreeShape.Palm }; break; case TreeShape.Procedural: shapeChoices = new[] { TreeShape.Round, TreeShape.Cone }; break; default: shapeChoices = new[] { args.Shape }; break; } for (int i = 0; i < treeList.Count; i++) { TreeShape newShape = shapeChoices[args.Rand.Next(0, shapeChoices.Length)]; Tree newTree; switch (newShape) { case TreeShape.Normal: newTree = new NormalTree(); break; case TreeShape.Bamboo: newTree = new BambooTree(); break; case TreeShape.Palm: newTree = new PalmTree(); break; case TreeShape.Round: newTree = new RoundTree(); break; case TreeShape.Cone: newTree = new ConeTree(); break; case TreeShape.Rainforest: newTree = new RainforestTree(); break; case TreeShape.Mangrove: newTree = new MangroveTree(); break; default: throw new ArgumentException("Unknown tree shape type"); } newTree.Copy(treeList[i]); if (args.MapHeightLimit) { int height = newTree.Height; int yBase = newTree.Pos[1]; int mapHeight = args.Map.Height; int foliageHeight; if (args.Shape == TreeShape.Rainforest) { foliageHeight = 2; } else { foliageHeight = 4; } if (yBase + height + foliageHeight > mapHeight) { newTree.Height = mapHeight - yBase - foliageHeight; } } if (newTree.Height < 1) { newTree.Height = 1; } newTree.Prepare(); treeList[i] = newTree; } }
public void Copy( Tree other ) { Args = other.Args; Pos = other.Pos; Height = other.Height; }
public void Copy([NotNull] Tree other) { if (other == null) throw new ArgumentNullException("other"); Args = other.Args; Pos = other.Pos; Height = other.Height; }