Example #1
0
        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
                });
            }
        }
Example #2
0
        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++;
            }
        }
Example #3
0
        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();
                }
            }
        }
Example #4
0
 public void Copy([NotNull] Tree other)
 {
     if (other == null)
     {
         throw new ArgumentNullException("other");
     }
     Args   = other.Args;
     Pos    = other.Pos;
     Height = other.Height;
 }
Example #5
0
        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--;
                    }
                }
            }
        }
Example #6
0
        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));
        }
Example #7
0
        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)
                });
            }
        }
Example #8
0
        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();
                }
            }
        }
Example #9
0
        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;
        }
Example #10
0
        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
                });
            }
        }
Example #11
0
 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);
 }
Example #12
0
        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
                } );
            }
        }
Example #13
0
        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--;
                    }
                }
            }
        }
Example #14
0
        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;
        }
Example #15
0
 public void Copy(Tree other)
 {
     Args   = other.Args;
     Pos    = other.Pos;
     Height = other.Height;
 }
Example #16
0
        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;
            }
        }
Example #17
0
        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++;
            }
        }
Example #18
0
 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;
 }
Example #19
0
        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);
        }
Example #20
0
        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 )
                } );
            }
        }
Example #21
0
        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;
            }
        }
Example #22
0
 public void Copy( Tree other ) {
     Args = other.Args;
     Pos = other.Pos;
     Height = other.Height;
 }
Example #23
0
 public void Copy([NotNull] Tree other) {
     if (other == null) throw new ArgumentNullException("other");
     Args = other.Args;
     Pos = other.Pos;
     Height = other.Height;
 }