Vegetation generator for RealisticMapGenState.
Exemple #1
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;
        }
Exemple #2
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);
        }