private 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; } }
private 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; // ReSharper disable LoopCanBeConvertedToQuery foreach ( Tree otherTree in treelist ) { Vector3I otherLoc = otherTree.Pos; float otherheight = otherTree.Height; 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 = ( otherheight + height ) * .193f; if ( dist < threshold ) { displaced = true; break; } } // ReSharper restore LoopCanBeConvertedToQuery if ( displaced ) continue; treelist.Add( new RainforestTree { Args = args, Pos = xyz, Height = height } ); i++; } }
private 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 } ); } }
private 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 ) } ); } }
private 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--; } } } }
private 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 ); }
public void Copy( Tree other ) { Args = other.Args; Pos = other.Pos; Height = other.Height; }
public Map GenerateMap() { Map map = new Map(null, args.MapWidth, args.MapLength, args.MapHeight, true); // Match water coverage float desiredWaterLevel = .5f; if (args.MatchWaterCoverage) { ReportProgress(2, "Heightmap Processing: Matching water coverage"); desiredWaterLevel = Noise.FindThreshold(heightmap, args.WaterCoverage); } // Calculate above/below water multipliers float aboveWaterMultiplier = 0; if (desiredWaterLevel != 1) { aboveWaterMultiplier = (args.MaxHeight / (1 - desiredWaterLevel)); } // Apply power functions to above/below water parts of the heightmap if (args.BelowFuncExponent != 1 || args.AboveFuncExponent != 1) { ReportProgress(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, args.BelowFuncExponent) * desiredWaterLevel; } else { float normalizedHeight = (heightmap[x, y] - desiredWaterLevel) / (1 - desiredWaterLevel); heightmap[x, y] = desiredWaterLevel + (float)Math.Pow(normalizedHeight, args.AboveFuncExponent) * (1 - desiredWaterLevel); } } } } // Calculate the slope if (args.CliffSmoothing) { ReportProgress(2, "Heightmap Processing: Smoothing"); slopemap = Noise.CalculateSlope(Noise.GaussianBlur5X5(heightmap)); } else { slopemap = Noise.CalculateSlope(heightmap); } float[,] altmap = null; if (args.MaxHeightVariation != 0 || args.MaxDepthVariation != 0) { ReportProgress(5, "Heightmap Processing: Randomizing"); altmap = new float[map.Width, map.Length]; int blendmapDetailSize = (int)Math.Log(Math.Max(args.MapWidth, args.MapLength), 2) - 2; new Noise(rand.Next(), NoiseInterpolationMode.Cosine).PerlinNoise(altmap, 3, blendmapDetailSize, 0.5f, 0, 0); Noise.Normalize(altmap, -1, 1); } int snowStartThreshold = args.SnowAltitude - args.SnowTransition; int snowThreshold = args.SnowAltitude; ReportProgress(10, "Filling"); 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) { float depth = args.MaxDepth; if (altmap != null) { depth += altmap[x, y] * args.MaxDepthVariation; } slope = slopemap[x, y] * depth; level = args.WaterLevel - (int)Math.Round(Math.Pow(1 - heightmap[x, y] / desiredWaterLevel, args.BelowFuncExponent) * depth); if (args.AddWater) { if (args.WaterLevel - level > 3) { map.SetBlock(x, y, args.WaterLevel, bDeepWaterSurface); } else { map.SetBlock(x, y, args.WaterLevel, bWaterSurface); } for (int i = args.WaterLevel; i > level; i--) { map.SetBlock(x, y, i, bWater); } for (int i = level; i >= 0; i--) { if (level - i < SeaFloorThickness) { map.SetBlock(x, y, i, bSeaFloor); } else { map.SetBlock(x, y, i, bBedrock); } } } else { if (blendmap != null && blendmap[x, y] > .25 && blendmap[x, y] < .75) { map.SetBlock(x, y, level, bCliff); } else { if (slope < args.CliffThreshold) { map.SetBlock(x, y, level, bGroundSurface); } else { map.SetBlock(x, y, level, bCliff); } } for (int i = level - 1; i >= 0; i--) { if (level - i < groundThickness) { if (blendmap != null && blendmap[x, y] > CliffsideBlockThreshold && blendmap[x, y] < (1 - CliffsideBlockThreshold)) { map.SetBlock(x, y, i, bCliff); } else { if (slope < args.CliffThreshold) { map.SetBlock(x, y, i, bGround); } else { map.SetBlock(x, y, i, bCliff); } } } else { map.SetBlock(x, y, i, bBedrock); } } } } else { float height; if (altmap != null) { height = args.MaxHeight + altmap[x, y] * args.MaxHeightVariation; } else { height = args.MaxHeight; } slope = slopemap[x, y] * height; if (height != 0) { level = args.WaterLevel + (int)Math.Round(Math.Pow(heightmap[x, y] - desiredWaterLevel, args.AboveFuncExponent) * aboveWaterMultiplier / args.MaxHeight * height); } else { level = args.WaterLevel; } bool snow = args.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, bCliff); } else { if (slope < args.CliffThreshold) { map.SetBlock(x, y, level, (snow ? Block.White : bGroundSurface)); } else { map.SetBlock(x, y, level, bCliff); } } for (int i = level - 1; i >= 0; i--) { if (level - i < groundThickness) { if (blendmap != null && blendmap[x, y] > CliffsideBlockThreshold && blendmap[x, y] < (1 - CliffsideBlockThreshold)) { map.SetBlock(x, y, i, bCliff); } else { if (slope < args.CliffThreshold) { if (snow) { map.SetBlock(x, y, i, Block.White); } else { map.SetBlock(x, y, i, bGround); } } else { map.SetBlock(x, y, i, bCliff); } } } else { map.SetBlock(x, y, i, bBedrock); } } } } } if (args.AddCaves || args.AddOre) { AddCaves(map); } if (args.AddBeaches) { ReportProgress(5, "Processing: Adding beaches"); AddBeaches(map); } if (args.AddTrees) { ReportProgress(5, "Processing: Planting trees"); if (args.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 * (args.TreeSpacingMax + args.TreeSpacingMin) / 2)), Operation = Forester.ForesterOperation.Add, PlantOn = bGroundSurface }; foresterArgs.BlockPlacing += (sender, e) => outMap.SetBlock(e.Coordinate, e.Block); Forester.Generate(foresterArgs); map = outMap; } GenerateTrees(map); } ReportProgress(0, "Generation complete"); map.Metadata["_Origin", "GeneratorName"] = "fCraft"; map.Metadata["_Origin", "GeneratorVersion"] = Updater.LatestStable.ToString(); map.Metadata["_Origin", "GeneratorParams"] = args.Serialize().ToString(SaveOptions.DisableFormatting); return(map); }