public static Arena Generate(GameAssets gameAssets, int seed, int biome_count)
        {
            // Prepare stuff
            Arena arena = new Arena(WIDTH, HEIGHT);

            arena.Biomes = new Biome[biome_count];
            arena.Seed   = seed;
            List <int>[] biome_tiles_list = new List <int> [biome_count];

            Random    rnd = new Random(seed);
            HaltonSet hlt = new HaltonSet(seed);    // halton sequence is used for generating evenly distributed points

            // generate temperature map
            double[] heatmap = GenerateNoise(seed, 3);
            for (int i = 0; i < arena.Heatmap.Length; i++)
            {
                arena.Heatmap[i] = (int)((heatmap[i] - 0.5) * 30 + 0.8 * (i % arena.Width));
            }

            // set locations of biome pivots
            for (int i = 0; i < biome_count; i++)
            {
                double halton2 = hlt.Seq2(i + 1);
                double halton3 = hlt.Seq3(i + 1);

                arena.Biomes[i]     = new Biome((int)(halton2 * arena.Width), (int)(halton3 * arena.Height));
                biome_tiles_list[i] = new List <int>();
            }

            // calc which tile belongs in which biome
            for (int i = 0; i < arena.Tiles.Length; i++)
            {
                Point tile_pos = new Point(i % arena.Width, i / arena.Width);

                int minDist2 = 40 * 40;
                int owner    = 0;

                // go thru all the pivots and pick the closest to current tile
                for (int p = 0; p < biome_count; p++)
                {
                    Point pivot = new Point(arena.Biomes[p].Pivot.X, arena.Biomes[p].Pivot.Y);

                    // add a bit of noise
                    Point noise = new Point((int)((rnd.NextDouble() - 0.5) * 2.5), (int)((rnd.NextDouble() - 0.5) * 2));
                    pivot += noise;

                    int dist2 = tile_pos.distanceSquared(pivot);
                    if (dist2 < minDist2)
                    {
                        minDist2 = dist2;
                        owner    = p;
                    }
                }

                biome_tiles_list[owner].Add(i);
            }

            // assign the calculated tiles to actual biomes
            for (int i = 0; i < biome_count; i++)
            {
                int pivotPos = arena.Biomes[i].Pivot.X + arena.Biomes[i].Pivot.Y * arena.Width;

                arena.Biomes[i].TilesOwned = biome_tiles_list[i].ToArray();
                arena.Biomes[i].Asset      = gameAssets.PickBiomeAmountBased(rnd, arena.Heatmap[pivotPos]);
            }

            // time to populate   *BIOMES*
            // (with tiles)
            for (int b = 0; b < biome_count; b++)
            {
                Biome      biome       = arena.Biomes[b];
                BiomeAsset biome_asset = gameAssets.BiomeAssets[biome.AssetName];

                List <TileAsset> special_tiles = new List <TileAsset>();
                foreach (TileAsset t in gameAssets.TileAssets.Values)
                {
                    if (t.SpawnDestinations.Length > 0 &&
                        t.SpawnDestinations.Where(a => a.Name == biome_asset.AssetName).Count() > 0)
                    {
                        special_tiles.Add(t);
                    }
                }

                for (int t = 0; t < biome.TilesOwned.Length; t++)
                {
                    Tile tile = biome_asset.GenerateTile(rnd);

                    // test, if current tile shouldn't be special tile
                    foreach (TileAsset ta in special_tiles)
                    {
                        SpawnDestination local = ta.SpawnDestinations.Where(a => a.Name == biome_asset.AssetName).First();

                        int amt = local.Amount.Evaluate(rnd);
                        if (amt > 0)
                        {
                            tile = ta.GenerateTile(rnd);
                        }
                    }

                    arena.Tiles[biome.TilesOwned[t]] = tile;
                }
            }

            // time to populate   *TILES*
            for (int i = 0; i < arena.Tiles.Length; i++)
            {
                Tile  tile      = arena.Tiles[i];
                Asset tileAsset = null;

                // tileAsset can be a regular biome asset or a special tile asset
                tileAsset = gameAssets.GetAssetByName(tile.AssetName);

                foreach (string spwnHere in tileAsset.SpawnsHere)
                {
                    // following asset will be spawned in current tile
                    SpawnableAsset assetToSpawn = (SpawnableAsset)gameAssets.GetAssetByName(spwnHere);

                    SpawnDestination local = assetToSpawn.SpawnDestinations.Where(a => a.Name == tile.AssetName).First();

                    if (assetToSpawn is ItemAsset)
                    {
                        int amt = local.Amount.Evaluate(rnd);
                    }
                }
            }

            return(arena);
        }