示例#1
0
        public bool CanBeSolid(int seed3, int seed4, int seed5, int x, int y, int z, SimpleBiome biome)
        {
            // TODO: better non-simplex code?!
            double val = SimplexNoise.Generate((double)seed3 + (x / SolidityMapSize), (double)seed4 + (y / SolidityMapSize), (double)seed5 + (z / SolidityMapSize));

            return(val < biome.AirDensity());
        }
示例#2
0
 public bool CanBeSolid(int seed3, int seed4, int seed5, int x, int y, int z, SimpleBiome biome)
 {
     // TODO: better non-simplex code?!
     double val = SimplexNoise.Generate((double)seed3 + (x / SolidityMapSize), (double)seed4 + (y / SolidityMapSize), (double)seed5 + (z / SolidityMapSize));
     //SysConsole.Output(OutputType.INFO, seed3 + "," + seed4 + "," + seed5 + " -> " + x + ", " + y + ", " + z + " -> " + val);
     return val < biome.AirDensity();
 }
        public bool CanBeSolid(int seed3, int seed4, int seed5, int x, int y, int z, SimpleBiome biome)
        {
            // TODO: better non-simplex code?!
            double val = SimplexNoise.Generate((double)seed3 + (x / SolidityMapSize), (double)seed4 + (y / SolidityMapSize), (double)seed5 + (z / SolidityMapSize));

            //SysConsole.Output(OutputType.INFO, seed3 + "," + seed4 + "," + seed5 + " -> " + x + ", " + y + ", " + z + " -> " + val);
            return(val < biome.AirDensity());
        }
示例#4
0
 public override byte[] GetLODSix(int seed, int seed2, int seed3, int seed4, int seed5, Vector3i cpos)
 {
     byte[] b = new byte[5 * 5 * 5 * 2];
     if (cpos.Z > MaxNonAirHeight)
     {
         // AIR
         return(b);
     }
     else if (cpos.Z < 0)
     {
         // STONE
         Material enf  = Material.STONE;
         ushort   enfu = (ushort)enf;
         for (int i = 0; i < b.Length; i += 2)
         {
             b[i]     = (byte)(enfu & 0xFF);
             b[i + 1] = (byte)((enfu >> 8) & 0xFF);
         }
         return(b);
     }
     for (int x = 0; x < 5; x++)
     {
         for (int y = 0; y < 5; y++)
         {
             double      hheight = GetHeight(seed, seed2, seed3, seed4, seed5, cpos.X * Chunk.CHUNK_SIZE + Chunk.CHUNK_SIZE * 0.25 * x, cpos.Y * Chunk.CHUNK_SIZE + Chunk.CHUNK_SIZE * 0.25 * y, cpos.Z * Chunk.CHUNK_SIZE + Chunk.CHUNK_SIZE * 0.5, out Biome biomeOrig);
             SimpleBiome biome   = biomeOrig as SimpleBiome;
             double      topf    = (hheight - cpos.Z * Chunk.CHUNK_SIZE) / 5.0;
             int         top     = (int)Math.Round(topf);
             for (int z = 0; z < Math.Min(top - 5, 5); z++)
             {
                 ushort lowType = (ushort)biome.BaseBlock();
                 int    loc     = Chunk.ApproxBlockIndex(x, y, z, 5) * 2;
                 b[loc]     = (byte)(lowType & 0xFF);
                 b[loc + 1] = (byte)((lowType >> 8) & 0xFF);
             }
             for (int z = Math.Max(top - 5, 0); z < Math.Min(top - 1, 5); z++)
             {
                 ushort lowType = (ushort)biome.SecondLayerBlock();
                 int    loc     = Chunk.ApproxBlockIndex(x, y, z, 5) * 2;
                 b[loc]     = (byte)(lowType & 0xFF);
                 b[loc + 1] = (byte)((lowType >> 8) & 0xFF);
             }
             for (int z = Math.Max(top - 1, 0); z < Math.Min(top, 5); z++)
             {
                 ushort lowType = (ushort)biome.SurfaceBlock();
                 int    loc     = Chunk.ApproxBlockIndex(x, y, z, 5) * 2;
                 b[loc]     = (byte)(lowType & 0xFF);
                 b[loc + 1] = (byte)((lowType >> 8) & 0xFF);
             }
         }
     }
     return(b);
 }
        private void PopulateInternal(int Seed, int seed2, int seed3, int seed4, int seed5, Chunk chunk)
        {
#endif
            if (chunk.OwningRegion.TheWorld.Flat)
            {
                if (chunk.WorldPosition.Z == 0)
                {
                    for (int i = 0; i < chunk.BlocksInternal.Length; i++)
                    {
                        chunk.BlocksInternal[i] = new BlockInternal((ushort)Material.STONE, 0, 0, 0);
                    }
                    for (int x = 0; x < Chunk.CHUNK_SIZE; x++)
                    {
                        for (int y = 0; y < Chunk.CHUNK_SIZE; y++)
                        {
                            chunk.BlocksInternal[chunk.BlockIndex(x, y, Chunk.CHUNK_SIZE - 1)] = new BlockInternal((ushort)Material.GRASS_PLAINS, 0, 0, 0);
                            chunk.BlocksInternal[chunk.BlockIndex(x, y, Chunk.CHUNK_SIZE - 2)] = new BlockInternal((ushort)Material.DIRT, 0, 0, 0);
                            chunk.BlocksInternal[chunk.BlockIndex(x, y, Chunk.CHUNK_SIZE - 3)] = new BlockInternal((ushort)Material.DIRT, 0, 0, 0);
                        }
                    }
                }
                else if (chunk.WorldPosition.Z < 0)
                {
                    for (int i = 0; i < chunk.BlocksInternal.Length; i++)
                    {
                        chunk.BlocksInternal[i] = new BlockInternal((ushort)Material.STONE, 0, 0, 0);
                    }
                }
                else
                {
                    for (int i = 0; i < chunk.BlocksInternal.Length; i++)
                    {
                        chunk.BlocksInternal[i] = BlockInternal.AIR;
                    }
                }
                return;
            }
            if (chunk.WorldPosition.Z > MaxNonAirHeight)
            {
                for (int i = 0; i < chunk.BlocksInternal.Length; i++)
                {
                    chunk.BlocksInternal[i] = BlockInternal.AIR;
                }
                return;
            }
            // TODO: Special case for too far down as well.
            for (int x = 0; x < Chunk.CHUNK_SIZE; x++)
            {
                for (int y = 0; y < Chunk.CHUNK_SIZE; y++)
                {
                    Location cpos = chunk.WorldPosition.ToLocation() * Chunk.CHUNK_SIZE;
                    // Prepare basics
                    int         cx = (int)cpos.X + x;
                    int         cy = (int)cpos.Y + y;
                    Biome       biomeOrig;
                    double      hheight = GetHeight(Seed, seed2, seed3, seed4, seed5, cx, cy, (double)cpos.Z, out biomeOrig);
                    SimpleBiome biome   = (SimpleBiome)biomeOrig;
                    //Biome biomeOrig2;
                    /*double hheight2 = */

                    /*GetHeight(Seed, seed2, seed3, seed4, seed5, cx + 7, cy + 7, (double)cpos.Z + 7, out biomeOrig2);
                     * SimpleBiome biome2 = (SimpleBiome)biomeOrig2;*/
                    Material surf  = biome.SurfaceBlock();
                    Material seco  = biome.SecondLayerBlock();
                    Material basb  = biome.BaseBlock();
                    Material water = biome.WaterMaterial();

                    /*Material surf2 = biome2.SurfaceBlock();
                     * Material seco2 = biome2.SecondLayerBlock();
                     * Material basb2 = biome2.BaseBlock();*/
                    // TODO: Make this possible?: hheight = (hheight + hheight2) / 2f;
                    int    hheightint = (int)Math.Round(hheight);
                    double topf       = hheight - (double)(chunk.WorldPosition.Z * Chunk.CHUNK_SIZE);
                    int    top        = (int)Math.Round(topf);
                    // General natural ground
                    for (int z = 0; z < Math.Min(top - 5, Chunk.CHUNK_SIZE); z++)
                    {
                        if (CanBeSolid(seed3, seed4, seed5, cx, cy, (int)cpos.Z + z, biome))
                        {
                            Material typex = GetMatType(seed2, seed3, seed4, seed5, cx, cy, (int)cpos.Z + z);
                            byte     shape = 0;
                            if (typex != Material.AIR)
                            {
                                shape = OreShapes[new Random((int)((hheight + cx + cy + cpos.Z + z) * 5)).Next(OreShapes.Length)];
                            }
                            //bool choice = SimplexNoise.Generate(cx / 10f, cy / 10f, ((double)cpos.Z + z) / 10f) >= 0.5f;
                            chunk.BlocksInternal[chunk.BlockIndex(x, y, z)] = new BlockInternal((ushort)(typex == Material.AIR ? (/*choice ? basb2 : */ basb) : typex), shape, 0, 0);
                        }
                        else if ((CanBeSolid(seed3, seed4, seed5, cx, cy, (int)cpos.Z + z - 1, biome) || (CanBeSolid(seed3, seed4, seed5, cx, cy, (int)cpos.Z + z + 1, biome))) &&
                                 (CanBeSolid(seed3, seed4, seed5, cx + 1, cy, (int)cpos.Z + z, biome) || CanBeSolid(seed3, seed4, seed5, cx, cy + 1, (int)cpos.Z + z, biome) ||
                                  CanBeSolid(seed3, seed4, seed5, cx - 1, cy, (int)cpos.Z + z, biome) || CanBeSolid(seed3, seed4, seed5, cx, cy - 1, (int)cpos.Z + z, biome)))
                        {
                            //bool choice = SimplexNoise.Generate(cx / 10f, cy / 10f, ((double)cpos.Z + z) / 10f) >= 0.5f;
                            chunk.BlocksInternal[chunk.BlockIndex(x, y, z)] = new BlockInternal((ushort)(/*choice ? basb2 : */ basb), 3, 0, 0);
                        }
                    }
                    for (int z = Math.Max(top - 5, 0); z < Math.Min(top - 1, Chunk.CHUNK_SIZE); z++)
                    {
                        if (CanBeSolid(seed3, seed4, seed5, cx, cy, (int)cpos.Z + z, biome))
                        {
                            //bool choice = SimplexNoise.Generate(cx / 10f, cy / 10f, ((double)cpos.Z + z) / 10f) >= 0.5f;
                            chunk.BlocksInternal[chunk.BlockIndex(x, y, z)] = new BlockInternal((ushort)(/*choice ? seco2 :*/ seco), 0, 0, 0);
                        }
                    }
                    for (int z = Math.Max(top - 1, 0); z < Math.Min(top, Chunk.CHUNK_SIZE); z++)
                    {
                        //bool choice = SimplexNoise.Generate(cx / 10f, cy / 10f, ((double)cpos.Z + z) / 10f) >= 0.5f;
                        chunk.BlocksInternal[chunk.BlockIndex(x, y, z)] = new BlockInternal((ushort)(/*choice ? surf2 : */ surf), 0, 0, 0);
                    }
                    // Smooth terrain cap
                    Biome  tempb;
                    double heightfxp = GetHeight(Seed, seed2, seed3, seed4, seed5, cx + 1, cy, (double)cpos.Z, out tempb);
                    double heightfxm = GetHeight(Seed, seed2, seed3, seed4, seed5, cx - 1, cy, (double)cpos.Z, out tempb);
                    double heightfyp = GetHeight(Seed, seed2, seed3, seed4, seed5, cx, cy + 1, (double)cpos.Z, out tempb);
                    double heightfym = GetHeight(Seed, seed2, seed3, seed4, seed5, cx, cy - 1, (double)cpos.Z, out tempb);
                    double topfxp    = heightfxp - (double)chunk.WorldPosition.Z * Chunk.CHUNK_SIZE;
                    double topfxm    = heightfxm - (double)chunk.WorldPosition.Z * Chunk.CHUNK_SIZE;
                    double topfyp    = heightfyp - (double)chunk.WorldPosition.Z * Chunk.CHUNK_SIZE;
                    double topfym    = heightfym - (double)chunk.WorldPosition.Z * Chunk.CHUNK_SIZE;
                    for (int z = Math.Max(top, 0); z < Math.Min(top + 1, Chunk.CHUNK_SIZE); z++)
                    {
                        //bool choice = SimplexNoise.Generate(cx / 10f, cy / 10f, ((double)cpos.Z + z) / 10f) >= 0.5f;
                        ushort tsf = (ushort)(/*choice ? surf2 : */ surf);
                        if (topf - top > 0f)
                        {
                            bool xp = topfxp > topf && topfxp - Math.Round(topfxp) <= 0;
                            bool xm = topfxm > topf && topfxm - Math.Round(topfxm) <= 0;
                            bool yp = topfyp > topf && topfyp - Math.Round(topfyp) <= 0;
                            bool ym = topfym > topf && topfym - Math.Round(topfym) <= 0;
                            if (xm && xp) /* Fine as-is */ } {
示例#6
0
 public override byte[] GetSuperLOD(int seed, int seed2, int seed3, int seed4, int seed5, Vector3i cpos)
 {
     byte[] b = new byte[2 * 2 * 2 * 2];
     if (cpos.Z > MaxNonAirHeight)
     {
         // AIR
         return(b);
     }
     else if (cpos.Z < 0)
     {
         // STONE
         Material enf  = Material.STONE;
         ushort   enfu = (ushort)enf;
         for (int i = 0; i < b.Length; i += 2)
         {
             b[i]     = (byte)(enfu & 0xFF);
             b[i + 1] = (byte)((enfu >> 8) & 0xFF);
         }
         return(b);
     }
     for (int x = 0; x < 2; x++)
     {
         for (int y = 0; y < 2; y++)
         {
             double      hheight = GetHeight(seed, seed2, seed3, seed4, seed5, cpos.X * Chunk.CHUNK_SIZE + Chunk.CHUNK_SIZE * 0.25 * x, cpos.Y * Chunk.CHUNK_SIZE + Chunk.CHUNK_SIZE * 0.25 * y, cpos.Z * Chunk.CHUNK_SIZE + Chunk.CHUNK_SIZE * 0.5, out Biome biomeOrig);
             SimpleBiome biome   = biomeOrig as SimpleBiome;
             if (hheight > cpos.Z * Chunk.CHUNK_SIZE)
             {
                 if (hheight > (cpos.Z + 1) * Chunk.CHUNK_SIZE)
                 {
                     ushort lowType = (ushort)biome.BaseBlock();
                     for (int z = 0; z < 2; z++)
                     {
                         int loc = Chunk.ApproxBlockIndex(x, y, z, 2) * 2;
                         b[loc]     = (byte)(lowType & 0xFF);
                         b[loc + 1] = (byte)((lowType >> 8) & 0xFF);
                     }
                 }
                 else if (hheight > (cpos.Z + 0.5) * Chunk.CHUNK_SIZE)
                 {
                     ushort lowTypeA = (ushort)biome.BaseBlock();
                     int    locA     = Chunk.ApproxBlockIndex(x, y, 0, 2) * 2;
                     b[locA]     = (byte)(lowTypeA & 0xFF);
                     b[locA + 1] = (byte)((lowTypeA >> 8) & 0xFF);
                     ushort lowTypeB = (ushort)biome.SurfaceBlock();
                     int    locB     = Chunk.ApproxBlockIndex(x, y, 1, 2) * 2;
                     b[locB]     = (byte)(lowTypeB & 0xFF);
                     b[locB + 1] = (byte)((lowTypeB >> 8) & 0xFF);
                 }
                 else
                 {
                     ushort lowTypeB = (ushort)biome.SurfaceBlock();
                     int    locB     = Chunk.ApproxBlockIndex(x, y, 0, 2) * 2;
                     b[locB]     = (byte)(lowTypeB & 0xFF);
                     b[locB + 1] = (byte)((lowTypeB >> 8) & 0xFF);
                 }
             }
         }
     }
     return(b);
 }
示例#7
0
        private void PopulateInternal(int Seed, int seed2, int seed3, int seed4, int seed5, Chunk chunk)
        {
#endif
            if (chunk.OwningRegion.TheWorld.Settings.GeneratorFlat)
            {
                if (chunk.WorldPosition.Z == 0)
                {
                    chunk.SetBlockAt(0, 0, 0, BlockInternal.AIR);
                    for (int i = 0; i < Constants.CHUNK_BLOCK_COUNT; i++)
                    {
                        chunk.BlocksInternal[i] = new BlockInternal((ushort)Material.STONE, 0, 0, 0);
                    }
                    for (int x = 0; x < Chunk.CHUNK_SIZE; x++)
                    {
                        for (int y = 0; y < Chunk.CHUNK_SIZE; y++)
                        {
                            chunk.BlocksInternal[chunk.BlockIndex(x, y, Chunk.CHUNK_SIZE - 1)] = new BlockInternal((ushort)Material.GRASS_PLAINS, 0, 0, 0);
                            chunk.BlocksInternal[chunk.BlockIndex(x, y, Chunk.CHUNK_SIZE - 2)] = new BlockInternal((ushort)Material.DIRT, 0, 0, 0);
                            chunk.BlocksInternal[chunk.BlockIndex(x, y, Chunk.CHUNK_SIZE - 3)] = new BlockInternal((ushort)Material.DIRT, 0, 0, 0);
                        }
                    }
                }
                else if (chunk.WorldPosition.Z < 0)
                {
                    chunk.SetBlockAt(0, 0, 0, BlockInternal.AIR);
                    for (int i = 0; i < Constants.CHUNK_BLOCK_COUNT; i++)
                    {
                        chunk.BlocksInternal[i] = new BlockInternal((ushort)Material.STONE, 0, 0, 0);
                    }
                }
                // else: air!
                return;
            }
            if (chunk.WorldPosition.Z > MaxNonAirHeight)
            {
                // AIR!
                return;
            }
            Location cpos            = chunk.WorldPosition.ToLocation() * Chunk.CHUNK_SIZE;
            double   EstimatedHeight = GetHeight(Seed, seed2, seed3, seed4, seed5, cpos.X + Constants.CHUNK_WIDTH / 2, cpos.Y + Constants.CHUNK_WIDTH / 2, null, false);
            if (Math.Max(0, EstimatedHeight + MaxSuddenSlope) < cpos.Z)
            {
                // TODO: Special case for the chunk being too far down as well? No height map in that case!
                return;
            }
            // About to be populated: ensure chunk has a valid block set.
            chunk.SetBlockAt(0, 0, 0, BlockInternal.AIR);
            HeightMap hm      = GetHeightMap(chunk.WorldPosition, Seed, seed2, seed3, seed4, seed5);
            int[]     toppers = new int[Chunk.CHUNK_SIZE * Chunk.CHUNK_SIZE]; // TODO: Reusable pool? This will generate trash!
            for (int x = 0; x < Chunk.CHUNK_SIZE; x++)
            {
                for (int y = 0; y < Chunk.CHUNK_SIZE; y++)
                {
                    // Prepare basics
                    int         cx      = (int)cpos.X + x;
                    int         cy      = (int)cpos.Y + y;
                    double      hheight = hm.Heights[y * Chunk.CHUNK_SIZE + x];
                    SimpleBiome biome   = Biomes.BiomeFor(seed2, seed3, seed4, cx, cy, cpos.Z, hheight) as SimpleBiome;
                    //Biome biomeOrig2;
                    /*double hheight2 = */

                    /*GetHeight(Seed, seed2, seed3, seed4, seed5, cx + 7, cy + 7, (double)cpos.Z + 7, out biomeOrig2);
                     * SimpleBiome biome2 = (SimpleBiome)biomeOrig2;*/
                    Material surf  = biome.SurfaceBlock();
                    Material seco  = biome.SecondLayerBlock();
                    Material basb  = biome.BaseBlock();
                    Material water = biome.WaterMaterial();

                    /*Material surf2 = biome2.SurfaceBlock();
                     * Material seco2 = biome2.SecondLayerBlock();
                     * Material basb2 = biome2.BaseBlock();*/
                    // TODO: Make this possible?: hheight = (hheight + hheight2) / 2f;
                    int    hheightint = (int)Math.Round(hheight);
                    double topf       = hheight - (double)(chunk.WorldPosition.Z * Chunk.CHUNK_SIZE);
                    int    top        = (int)Math.Round(topf);
                    // General natural ground
                    for (int z = 0; z < Math.Min(top - 5, Chunk.CHUNK_SIZE); z++)
                    {
                        if (CanBeSolid(seed3, seed4, seed5, cx, cy, (int)cpos.Z + z, biome))
                        {
                            Material typex = GetMatType(seed2, seed3, seed4, seed5, cx, cy, (int)cpos.Z + z);
                            byte     shape = 0;
                            if (typex != Material.AIR)
                            {
                                shape = OreShapes[new MTRandom(39, (ulong)((hheight + cx + cy + cpos.Z + z) * 5)).Next(OreShapes.Length)];
                            }
                            //bool choice = SimplexNoise.Generate(cx / 10f, cy / 10f, ((double)cpos.Z + z) / 10f) >= 0.5f;
                            chunk.BlocksInternal[chunk.BlockIndex(x, y, z)] = new BlockInternal((ushort)(typex == Material.AIR ? (/*choice ? basb2 : */ basb) : typex), shape, 0, 0);
                        }
                        else if ((CanBeSolid(seed3, seed4, seed5, cx, cy, (int)cpos.Z + z - 1, biome) || (CanBeSolid(seed3, seed4, seed5, cx, cy, (int)cpos.Z + z + 1, biome))) &&
                                 (CanBeSolid(seed3, seed4, seed5, cx + 1, cy, (int)cpos.Z + z, biome) || CanBeSolid(seed3, seed4, seed5, cx, cy + 1, (int)cpos.Z + z, biome) ||
                                  CanBeSolid(seed3, seed4, seed5, cx - 1, cy, (int)cpos.Z + z, biome) || CanBeSolid(seed3, seed4, seed5, cx, cy - 1, (int)cpos.Z + z, biome)))
                        {
                            //bool choice = SimplexNoise.Generate(cx / 10f, cy / 10f, ((double)cpos.Z + z) / 10f) >= 0.5f;
                            chunk.BlocksInternal[chunk.BlockIndex(x, y, z)] = new BlockInternal((ushort)(/*choice ? basb2 : */ basb), 3, 0, 0);
                        }
                    }
                    for (int z = Math.Max(top - 5, 0); z < Math.Min(top - 1, Chunk.CHUNK_SIZE); z++)
                    {
                        if (CanBeSolid(seed3, seed4, seed5, cx, cy, (int)cpos.Z + z, biome))
                        {
                            //bool choice = SimplexNoise.Generate(cx / 10f, cy / 10f, ((double)cpos.Z + z) / 10f) >= 0.5f;
                            chunk.BlocksInternal[chunk.BlockIndex(x, y, z)] = new BlockInternal((ushort)(/*choice ? seco2 :*/ seco), 0, 0, 0);
                        }
                    }
                    for (int z = Math.Max(top - 1, 0); z < Math.Min(top, Chunk.CHUNK_SIZE); z++)
                    {
                        //bool choice = SimplexNoise.Generate(cx / 10f, cy / 10f, ((double)cpos.Z + z) / 10f) >= 0.5f;
                        chunk.BlocksInternal[chunk.BlockIndex(x, y, z)] = new BlockInternal((ushort)(/*choice ? surf2 : */ surf), 0, 0, 0);
                    }
                    // Smooth terrain cap
                    double heightfxp = GetHeightRel(hm, Seed, seed2, seed3, seed4, seed5, cx + 1, cy, (double)cpos.Z, x + 1, y);
                    double heightfxm = GetHeightRel(hm, Seed, seed2, seed3, seed4, seed5, cx - 1, cy, (double)cpos.Z, x - 1, y);
                    double heightfyp = GetHeightRel(hm, Seed, seed2, seed3, seed4, seed5, cx, cy + 1, (double)cpos.Z, x, y + 1);
                    double heightfym = GetHeightRel(hm, Seed, seed2, seed3, seed4, seed5, cx, cy - 1, (double)cpos.Z, x, y - 1);
                    double topfxp    = heightfxp - (double)chunk.WorldPosition.Z * Chunk.CHUNK_SIZE;
                    double topfxm    = heightfxm - (double)chunk.WorldPosition.Z * Chunk.CHUNK_SIZE;
                    double topfyp    = heightfyp - (double)chunk.WorldPosition.Z * Chunk.CHUNK_SIZE;
                    double topfym    = heightfym - (double)chunk.WorldPosition.Z * Chunk.CHUNK_SIZE;
                    for (int z = Math.Max(top, 0); z < Math.Min(top + 1, Chunk.CHUNK_SIZE); z++)
                    {
                        //bool choice = SimplexNoise.Generate(cx / 10f, cy / 10f, ((double)cpos.Z + z) / 10f) >= 0.5f;
                        ushort tsf = (ushort)(/*choice ? surf2 : */ surf);
                        if (topf - top > 0f)
                        {
                            bool xp = topfxp > topf && topfxp - Math.Round(topfxp) <= 0;
                            bool xm = topfxm > topf && topfxm - Math.Round(topfxm) <= 0;
                            bool yp = topfyp > topf && topfyp - Math.Round(topfyp) <= 0;
                            bool ym = topfym > topf && topfym - Math.Round(topfym) <= 0;
                            if (xm && xp) /* Fine as-is */ } {