Example #1
0
        public void Deserialize(Stream input)
        {
            var header = input.ReadStructure<Level.Header>();

            this.Width = header.Width;
            this.Height = header.Height;

            this.OffsetX = header.OffsetX;
            this.OffsetY = header.OffsetY;

            if (Enumerable.Any(header.Padding, t => t != 0) == true)
            {
                throw new FormatException("non-zero data in padding");
            }

            Array.Copy(header.TerrainIds, this.TerrainIds, header.TerrainIds.Length);
            for (int i = 0; i < this.TerrainIds.Length; i++)
            {
                this.TerrainIds[i] %= 16;
            }

            if (header.Version >= 4)
            {
                this.LightColorWhite = header.LightColorWhite;
                this.LightColorRed = header.LightColorRed;
                this.LightColorGreen = header.LightColorGreen;
                this.LightColorBlue = header.LightColorBlue;

                Array.Copy(header.PhysicsLow, this.PhysicsLow, header.PhysicsLow.Length);
                Array.Copy(header.PhysicsHigh, this.PhysicsHigh, header.PhysicsHigh.Length);
            }
            else
            {
                this.SetDefaults();
            }

            var objects = new Level.BlobReference[header.ObjectCount];
            for (int i = 0; i < objects.Length; i++)
            {
                if (header.Version >= 6)
                {
                    objects[i] = input.ReadStructure<Level.BlobReference>();
                }
                else
                {
                    objects[i] = new Level.BlobReference
                    {
                        FileName = null,
                        Id = string.Format("o{0}.cfs", i),
                    };
                }
            }
            this.Objects = new List<Level.BlobReference>();
            this.Objects.AddRange(objects);

            var floors = new Level.BlobReference[header.FloorCount];
            for (int i = 0; i < floors.Length; i++)
            {
                if (header.Version >= 6)
                {
                    floors[i] = input.ReadStructure<Level.BlobReference>();
                }
                else
                {
                    floors[i] = new Level.BlobReference
                    {
                        FileName = null,
                        Id = string.Format("f{0}.cfs", i),
                    };
                }
            }
            this.Floors = new List<Level.BlobReference>();
            this.Floors.AddRange(floors);

            this.Tiles = new Level.Tile[this.Width * this.Height];

            var tileData = input.ReadRLE(3, this.Tiles.Length, true);
            for (int i = 0, j = 0; i < this.Tiles.Length; i++, j += 3)
            {
                this.Tiles[i].BitsA = tileData[j + 0];
                this.Tiles[i].BitsB = tileData[j + 1];
                this.Tiles[i].BitsC = tileData[j + 2];
            }

            if (header.Version < 4)
            {
                var magic = new byte[]
                {
                    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x1A, 0x1B,
                    0x1C, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x06, 0x07, 0x08, 0x09, 0x10, 0x1A, 0x1B,
                    0x1C, 0x1D, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00,
                };

                for (int i = 0; i < this.Tiles.Length; i++)
                {
                    var a = this.Tiles[i].BitsC;
                    var b = (byte)((magic[a & 0x1F] ^ a) & 0x1F);
                    this.Tiles[i].BitsC ^= b;
                }
            }

            var entities = new Level.Entity[header.EntityCount];

            if (header.Version >= 3)
            {
                for (int i = 0; i < header.EntityCount; i++)
                {
                    entities[i] = input.ReadStructure<Level.Entity>();
                }
            }
            else
            {
                using (var entityData =
                    new MemoryStream(input.ReadRLE(14, header.EntityCount, true)))
                {
                    for (int i = 0; i < header.EntityCount; i++)
                    {
                        var oldEntity = entityData.ReadStructure<Level.OldEntity>();

                        //entities[i] = new Level.Entity();
                        entities[i].X = oldEntity.X;
                        entities[i].Y = oldEntity.Y;
                        entities[i].BitsA = oldEntity.BitsA & 0x3FFFFFFFu;
                        entities[i].BitsB = oldEntity.BitsB & 0x7FFFFFFFu;
                        entities[i].BitsC = (oldEntity.BitsD & 0x7Fu) << 23;
                        entities[i].BitsD = oldEntity.BitsC;
                    }
                }
            }

            if (header.Version < 5)
            {
                for (int i = 0; i < header.EntityCount; i++)
                {
                    entities[i].BitsC &= 0xBFFFFFFFu;
                }
            }

            this.Entities = new List<Level.Entity>();
            this.Entities.AddRange(entities);

            if (input.Position != input.Length)
            {
                throw new FormatException();
            }
        }
Example #2
0
        public static void Main(string[] args)
        {
            bool showHelp = false;
            int width = 500;
            int height = 500;

            var options = new OptionSet()
            {
                {
                    "?|help",
                    "show this message and exit",
                    v => showHelp = v != null
                    },
                {
                    "w|width=",
                    "set level width",
                    v => width = v != null ? int.Parse(v) : width
                    },
                {
                    "h|height=",
                    "set level height",
                    v => height = v != null ? int.Parse(v) : height
                    },
            };

            List<string> extras;

            try
            {
                extras = options.Parse(args);
            }
            catch (OptionException e)
            {
                Console.Write("{0}: ", GetExecutableName());
                Console.WriteLine(e.Message);
                Console.WriteLine("Try `{0} --help' for more information.", GetExecutableName());
                return;
            }

            if (extras.Count < 0 || extras.Count > 1 || showHelp == true)
            {
                Console.WriteLine("Usage: {0} [OPTIONS]+ [output_map]", GetExecutableName());
                Console.WriteLine();
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return;
            }

            var outputPath = extras.Count > 0 ? extras[0] : "space.map";

            var templates = LoadEntities();

            int cx = width / 2;
            int cy = height / 2;
            // ReSharper disable UnusedVariable
            var radius = (int)(Math.Min(width, height) / 2.0);
            // ReSharper restore UnusedVariable
            var range = Math.Min(width, height) / 2.5;

            var rng = new MersenneTwister();
            var noise = PerlinNoise.Generate(
                width, height, 0.0325f, 1.0f, 0.5f, 16, rng);

            var physics = new bool[width,height];
            var vision = new bool[width,height];

            var entities = new List<Entity>();

            for (int x = 8; x < width - 8; x++)
            {
                for (int y = 8; y < height - 8; y++)
                {
                    var distance = GetDistance(cx, cy, x, y);
                    if (distance > range &&
                        rng.Next(100) > 2)
                    {
                        continue;
                    }

                    var magic = noise[x, y];

                    if (magic >= 200)
                    {
                    }
                    else if (magic >= 180)
                    {
                        if (rng.Next(100) >= 60 &&
                            (x % 2) == 0 &&
                            (y % 2) == 0)
                        {
                            var template = templates
                                .Where(t => t.Category == "asteroid")
                                .OrderBy(t => rng.Next())
                                .FirstOrDefault();

                            if (template != null &&
                                template.CanPlaceWithPhysics(x, y, physics, width, height) == true)
                            {
                                var entity = new Entity(x, y, template);

                                int speed = rng.Next(100);

                                if (speed < 60)
                                {
                                    entity.AnimationTime = 0;
                                }
                                else if (speed < 70)
                                {
                                    entity.AnimationTime = 100;
                                }
                                else if (speed < 80)
                                {
                                    entity.AnimationTime = 200;
                                }
                                else if (speed < 85)
                                {
                                    entity.AnimationTime = 250;
                                }
                                else if (speed < 90)
                                {
                                    entity.AnimationTime = 350;
                                }
                                else if (speed < 95)
                                {
                                    entity.AnimationTime = 400;
                                }
                                else
                                {
                                    entity.AnimationTime = 450;
                                }

                                template.BlockPhysics(x, y, physics);
                                entities.Add(entity);
                            }
                        }
                    }
                    else if (magic >= 100)
                    {
                    }
                    else if (magic >= 15)
                    {
                    }
                    else
                    {
                        if (rng.Next(100) >= 80)
                        {
                            var template = templates
                                .Where(t => t.Category == "nebula")
                                .OrderBy(t => rng.Next())
                                .FirstOrDefault();

                            if (template != null &&
                                template.CanPlaceWithVision(x, y, vision, width, height) == true)
                            {
                                var entity = new Entity(x, y, template)
                                {
                                    AnimationTime = 50
                                };

                                template.BlockVision(x, y, vision);
                                entities.Add(entity);
                            }
                        }
                    }
                }
            }

            var tiles = new Level.Tile[width,height];

            foreach (var entity in entities)
            {
                for (int rx = 0; rx < entity.Template.Width; rx++)
                {
                    for (int ry = 0; ry < entity.Template.Height; ry++)
                    {
                        if (entity.Template.Physics[rx, ry] > 0)
                        {
                            tiles[entity.X + rx, entity.Y + ry].Physics =
                                entity.Template.Physics[rx, ry];
                        }

                        if (entity.Template.Vision[rx, ry] > 0)
                        {
                            tiles[entity.X + rx, entity.Y + ry].Vision =
                                entity.Template.Vision[rx, ry];
                        }
                    }
                }
            }

            var floors = new List<Map.BlobReference>
            {
                new Map.BlobReference()
                {
                    Path = "f_default.blo,default.cfs"
                },
            };
            //floors.Add(new Map.BlobReference() { Path = "f_colors.blo,color3.cfs" });

            using (var output = File.Create(outputPath))
            {
                var header = new Map.Header
                {
                    Version = 9,
                    Width = width,
                    Height = height,
                    EntityCount = entities.Count,
                    LightColorWhite = 0xFFFFFF00u,
                    LightColorRed = 0x0000FF00u,
                    LightColorGreen = 0x00FF0000u,
                    LightColorBlue = 0xFF000000u,
                    PhysicsLow = new short[32],
                    PhysicsHigh = new short[32],
                };

                header.PhysicsHigh[0] = 0;
                header.PhysicsHigh[1] = 1024;
                header.PhysicsHigh[2] = 1024;
                header.PhysicsHigh[3] = 1024;
                header.PhysicsHigh[4] = 1024;
                header.PhysicsHigh[5] = 1024;
                header.PhysicsHigh[6] = 16;
                header.PhysicsHigh[7] = 16;
                header.PhysicsHigh[8] = 16;
                header.PhysicsHigh[9] = 16;
                header.PhysicsHigh[10] = 16;
                header.PhysicsHigh[11] = 32;
                header.PhysicsHigh[12] = 32;
                header.PhysicsHigh[13] = 32;
                header.PhysicsHigh[14] = 32;
                header.PhysicsHigh[15] = 32;
                header.PhysicsHigh[16] = 64;
                header.PhysicsHigh[17] = 64;
                header.PhysicsHigh[18] = 64;
                header.PhysicsHigh[19] = 64;
                header.PhysicsHigh[20] = 64;
                header.PhysicsHigh[21] = 128;
                header.PhysicsHigh[22] = 128;
                header.PhysicsHigh[23] = 128;
                header.PhysicsHigh[24] = 128;
                header.PhysicsHigh[25] = 128;
                header.PhysicsHigh[26] = 1024;
                header.PhysicsHigh[27] = 1024;
                header.PhysicsHigh[29] = 1024;
                header.PhysicsHigh[28] = 1024;
                header.PhysicsHigh[30] = 1024;
                header.PhysicsHigh[31] = 1024;

                output.WriteStructure(header);

                for (int i = 0; i < 8192; i++)
                {
                    if (i < 16)
                    {
                        output.WriteValueU8((byte)i);
                    }
                    else
                    {
                        output.WriteValueU8(0);
                    }
                }

                for (int i = 0; i < 2048; i++)
                {
                    if (i < floors.Count)
                    {
                        output.WriteStructure(floors[i]);
                    }
                    else
                    {
                        output.Seek(64, SeekOrigin.Current);
                    }
                }

                var buffer = new byte[width * height * 4];
                for (int y = 0, offset = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++, offset += 4)
                    {
                        buffer[offset + 0] = tiles[x, y].BitsA;
                        buffer[offset + 1] = 0;
                        buffer[offset + 2] = tiles[x, y].BitsC;
                        buffer[offset + 3] = tiles[x, y].BitsB;
                    }
                }

                using (var rle = new MemoryStream())
                {
                    rle.WriteRLE(buffer, 4, width * height, false);
                    rle.Position = 0;

                    output.WriteValueS32((int)rle.Length);
                    output.WriteFromStream(rle, rle.Length);
                }

                foreach (var source in entities)
                {
                    var entity = new Level.Entity
                    {
                        X = (short)((source.X - source.Template.OffsetX) * 16),
                        Y = (short)((source.Y - source.Template.OffsetY) * 16),
                        AnimationTime = source.AnimationTime,
                    };
                    output.WriteStructure(entity);

                    var reference = new Map.BlobReference
                    {
                        Path = string.Format("{0},{1}", source.Template.BloName, source.Template.CfsName),
                    };
                    output.WriteStructure(reference);
                }
            }
        }
Example #3
0
        public void Deserialize(Stream input)
        {
            var header = input.ReadStructure <Level.Header>();

            this.Width  = header.Width;
            this.Height = header.Height;

            this.OffsetX = header.OffsetX;
            this.OffsetY = header.OffsetY;

            if (Enumerable.Any(header.Padding, t => t != 0) == true)
            {
                throw new FormatException("non-zero data in padding");
            }

            Array.Copy(header.TerrainIds, this.TerrainIds, header.TerrainIds.Length);
            for (int i = 0; i < this.TerrainIds.Length; i++)
            {
                this.TerrainIds[i] %= 16;
            }

            if (header.Version >= 4)
            {
                this.LightColorWhite = header.LightColorWhite;
                this.LightColorRed   = header.LightColorRed;
                this.LightColorGreen = header.LightColorGreen;
                this.LightColorBlue  = header.LightColorBlue;

                Array.Copy(header.PhysicsLow, this.PhysicsLow, header.PhysicsLow.Length);
                Array.Copy(header.PhysicsHigh, this.PhysicsHigh, header.PhysicsHigh.Length);
            }
            else
            {
                this.SetDefaults();
            }

            var objects = new Level.BlobReference[header.ObjectCount];

            for (int i = 0; i < objects.Length; i++)
            {
                if (header.Version >= 6)
                {
                    objects[i] = input.ReadStructure <Level.BlobReference>();
                }
                else
                {
                    objects[i] = new Level.BlobReference
                    {
                        FileName = null,
                        Id       = string.Format("o{0}.cfs", i),
                    };
                }
            }
            this.Objects = new List <Level.BlobReference>();
            this.Objects.AddRange(objects);

            var floors = new Level.BlobReference[header.FloorCount];

            for (int i = 0; i < floors.Length; i++)
            {
                if (header.Version >= 6)
                {
                    floors[i] = input.ReadStructure <Level.BlobReference>();
                }
                else
                {
                    floors[i] = new Level.BlobReference
                    {
                        FileName = null,
                        Id       = string.Format("f{0}.cfs", i),
                    };
                }
            }
            this.Floors = new List <Level.BlobReference>();
            this.Floors.AddRange(floors);

            this.Tiles = new Level.Tile[this.Width * this.Height];

            var tileData = input.ReadRLE(3, this.Tiles.Length, true);

            for (int i = 0, j = 0; i < this.Tiles.Length; i++, j += 3)
            {
                this.Tiles[i].BitsA = tileData[j + 0];
                this.Tiles[i].BitsB = tileData[j + 1];
                this.Tiles[i].BitsC = tileData[j + 2];
            }

            if (header.Version < 4)
            {
                var magic = new byte[]
                {
                    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x1A, 0x1B,
                    0x1C, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x06, 0x07, 0x08, 0x09, 0x10, 0x1A, 0x1B,
                    0x1C, 0x1D, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00,
                };

                for (int i = 0; i < this.Tiles.Length; i++)
                {
                    var a = this.Tiles[i].BitsC;
                    var b = (byte)((magic[a & 0x1F] ^ a) & 0x1F);
                    this.Tiles[i].BitsC ^= b;
                }
            }

            var entities = new Level.Entity[header.EntityCount];

            if (header.Version >= 3)
            {
                for (int i = 0; i < header.EntityCount; i++)
                {
                    entities[i] = input.ReadStructure <Level.Entity>();
                }
            }
            else
            {
                using (var entityData =
                           new MemoryStream(input.ReadRLE(14, header.EntityCount, true)))
                {
                    for (int i = 0; i < header.EntityCount; i++)
                    {
                        var oldEntity = entityData.ReadStructure <Level.OldEntity>();

                        //entities[i] = new Level.Entity();
                        entities[i].X     = oldEntity.X;
                        entities[i].Y     = oldEntity.Y;
                        entities[i].BitsA = oldEntity.BitsA & 0x3FFFFFFFu;
                        entities[i].BitsB = oldEntity.BitsB & 0x7FFFFFFFu;
                        entities[i].BitsC = (oldEntity.BitsD & 0x7Fu) << 23;
                        entities[i].BitsD = oldEntity.BitsC;
                    }
                }
            }

            if (header.Version < 5)
            {
                for (int i = 0; i < header.EntityCount; i++)
                {
                    entities[i].BitsC &= 0xBFFFFFFFu;
                }
            }

            this.Entities = new List <Level.Entity>();
            this.Entities.AddRange(entities);

            if (input.Position != input.Length)
            {
                throw new FormatException();
            }
        }
Example #4
0
        public static void Main(string[] args)
        {
            bool showHelp = false;
            int  width    = 500;
            int  height   = 500;

            var options = new OptionSet()
            {
                {
                    "?|help",
                    "show this message and exit",
                    v => showHelp = v != null
                },
                {
                    "w|width=",
                    "set level width",
                    v => width = v != null?int.Parse(v) : width
                },
                {
                    "h|height=",
                    "set level height",
                    v => height = v != null?int.Parse(v) : height
                },
            };

            List <string> extras;

            try
            {
                extras = options.Parse(args);
            }
            catch (OptionException e)
            {
                Console.Write("{0}: ", GetExecutableName());
                Console.WriteLine(e.Message);
                Console.WriteLine("Try `{0} --help' for more information.", GetExecutableName());
                return;
            }

            if (extras.Count < 0 || extras.Count > 1 || showHelp == true)
            {
                Console.WriteLine("Usage: {0} [OPTIONS]+ [output_map]", GetExecutableName());
                Console.WriteLine();
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return;
            }

            var outputPath = extras.Count > 0 ? extras[0] : "space.map";

            var templates = LoadEntities();

            int cx = width / 2;
            int cy = height / 2;
            // ReSharper disable UnusedVariable
            var radius = (int)(Math.Min(width, height) / 2.0);
            // ReSharper restore UnusedVariable
            var range = Math.Min(width, height) / 2.5;

            var rng   = new MersenneTwister();
            var noise = PerlinNoise.Generate(
                width, height, 0.0325f, 1.0f, 0.5f, 16, rng);

            var physics = new bool[width, height];
            var vision  = new bool[width, height];

            var entities = new List <Entity>();

            for (int x = 8; x < width - 8; x++)
            {
                for (int y = 8; y < height - 8; y++)
                {
                    var distance = GetDistance(cx, cy, x, y);
                    if (distance > range &&
                        rng.Next(100) > 2)
                    {
                        continue;
                    }

                    var magic = noise[x, y];

                    if (magic >= 200)
                    {
                    }
                    else if (magic >= 180)
                    {
                        if (rng.Next(100) >= 60 &&
                            (x % 2) == 0 &&
                            (y % 2) == 0)
                        {
                            var template = templates
                                           .Where(t => t.Category == "asteroid")
                                           .OrderBy(t => rng.Next())
                                           .FirstOrDefault();

                            if (template != null &&
                                template.CanPlaceWithPhysics(x, y, physics, width, height) == true)
                            {
                                var entity = new Entity(x, y, template);

                                int speed = rng.Next(100);

                                if (speed < 60)
                                {
                                    entity.AnimationTime = 0;
                                }
                                else if (speed < 70)
                                {
                                    entity.AnimationTime = 100;
                                }
                                else if (speed < 80)
                                {
                                    entity.AnimationTime = 200;
                                }
                                else if (speed < 85)
                                {
                                    entity.AnimationTime = 250;
                                }
                                else if (speed < 90)
                                {
                                    entity.AnimationTime = 350;
                                }
                                else if (speed < 95)
                                {
                                    entity.AnimationTime = 400;
                                }
                                else
                                {
                                    entity.AnimationTime = 450;
                                }

                                template.BlockPhysics(x, y, physics);
                                entities.Add(entity);
                            }
                        }
                    }
                    else if (magic >= 100)
                    {
                    }
                    else if (magic >= 15)
                    {
                    }
                    else
                    {
                        if (rng.Next(100) >= 80)
                        {
                            var template = templates
                                           .Where(t => t.Category == "nebula")
                                           .OrderBy(t => rng.Next())
                                           .FirstOrDefault();

                            if (template != null &&
                                template.CanPlaceWithVision(x, y, vision, width, height) == true)
                            {
                                var entity = new Entity(x, y, template)
                                {
                                    AnimationTime = 50
                                };

                                template.BlockVision(x, y, vision);
                                entities.Add(entity);
                            }
                        }
                    }
                }
            }

            var tiles = new Level.Tile[width, height];

            foreach (var entity in entities)
            {
                for (int rx = 0; rx < entity.Template.Width; rx++)
                {
                    for (int ry = 0; ry < entity.Template.Height; ry++)
                    {
                        if (entity.Template.Physics[rx, ry] > 0)
                        {
                            tiles[entity.X + rx, entity.Y + ry].Physics =
                                entity.Template.Physics[rx, ry];
                        }

                        if (entity.Template.Vision[rx, ry] > 0)
                        {
                            tiles[entity.X + rx, entity.Y + ry].Vision =
                                entity.Template.Vision[rx, ry];
                        }
                    }
                }
            }

            var floors = new List <Map.BlobReference>
            {
                new Map.BlobReference()
                {
                    Path = "f_default.blo,default.cfs"
                },
            };

            //floors.Add(new Map.BlobReference() { Path = "f_colors.blo,color3.cfs" });

            using (var output = File.Create(outputPath))
            {
                var header = new Map.Header
                {
                    Version         = 9,
                    Width           = width,
                    Height          = height,
                    EntityCount     = entities.Count,
                    LightColorWhite = 0xFFFFFF00u,
                    LightColorRed   = 0x0000FF00u,
                    LightColorGreen = 0x00FF0000u,
                    LightColorBlue  = 0xFF000000u,
                    PhysicsLow      = new short[32],
                    PhysicsHigh     = new short[32],
                };

                header.PhysicsHigh[0]  = 0;
                header.PhysicsHigh[1]  = 1024;
                header.PhysicsHigh[2]  = 1024;
                header.PhysicsHigh[3]  = 1024;
                header.PhysicsHigh[4]  = 1024;
                header.PhysicsHigh[5]  = 1024;
                header.PhysicsHigh[6]  = 16;
                header.PhysicsHigh[7]  = 16;
                header.PhysicsHigh[8]  = 16;
                header.PhysicsHigh[9]  = 16;
                header.PhysicsHigh[10] = 16;
                header.PhysicsHigh[11] = 32;
                header.PhysicsHigh[12] = 32;
                header.PhysicsHigh[13] = 32;
                header.PhysicsHigh[14] = 32;
                header.PhysicsHigh[15] = 32;
                header.PhysicsHigh[16] = 64;
                header.PhysicsHigh[17] = 64;
                header.PhysicsHigh[18] = 64;
                header.PhysicsHigh[19] = 64;
                header.PhysicsHigh[20] = 64;
                header.PhysicsHigh[21] = 128;
                header.PhysicsHigh[22] = 128;
                header.PhysicsHigh[23] = 128;
                header.PhysicsHigh[24] = 128;
                header.PhysicsHigh[25] = 128;
                header.PhysicsHigh[26] = 1024;
                header.PhysicsHigh[27] = 1024;
                header.PhysicsHigh[29] = 1024;
                header.PhysicsHigh[28] = 1024;
                header.PhysicsHigh[30] = 1024;
                header.PhysicsHigh[31] = 1024;

                output.WriteStructure(header);

                for (int i = 0; i < 8192; i++)
                {
                    if (i < 16)
                    {
                        output.WriteValueU8((byte)i);
                    }
                    else
                    {
                        output.WriteValueU8(0);
                    }
                }

                for (int i = 0; i < 2048; i++)
                {
                    if (i < floors.Count)
                    {
                        output.WriteStructure(floors[i]);
                    }
                    else
                    {
                        output.Seek(64, SeekOrigin.Current);
                    }
                }

                var buffer = new byte[width * height * 4];
                for (int y = 0, offset = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++, offset += 4)
                    {
                        buffer[offset + 0] = tiles[x, y].BitsA;
                        buffer[offset + 1] = 0;
                        buffer[offset + 2] = tiles[x, y].BitsC;
                        buffer[offset + 3] = tiles[x, y].BitsB;
                    }
                }

                using (var rle = new MemoryStream())
                {
                    rle.WriteRLE(buffer, 4, width * height, false);
                    rle.Position = 0;

                    output.WriteValueS32((int)rle.Length);
                    output.WriteFromStream(rle, rle.Length);
                }

                foreach (var source in entities)
                {
                    var entity = new Level.Entity
                    {
                        X             = (short)((source.X - source.Template.OffsetX) * 16),
                        Y             = (short)((source.Y - source.Template.OffsetY) * 16),
                        AnimationTime = source.AnimationTime,
                    };
                    output.WriteStructure(entity);

                    var reference = new Map.BlobReference
                    {
                        Path = string.Format("{0},{1}", source.Template.BloName, source.Template.CfsName),
                    };
                    output.WriteStructure(reference);
                }
            }
        }