Example #1
0
    void Start()

    {
        town = new Town();
        peop = new Peop();
        terr = new Terr();
        server();
    }
        /// <summary>
        /// Decompresses the passed Terr block.
        /// </summary>
        /// <param name="terr">Terr block to decompress</param>
        /// <returns>Decompressed version</returns>
        public static Terr Decompress(this Terr oldTerr)
        {
            Terr newTerr = new Terr();
            newTerr.Width = oldTerr.Width;
            newTerr.Height = oldTerr.Height;

            foreach (Terrblock block in oldTerr.BlocksHmap1)
            {
                decompressBlock(oldTerr, newTerr, block, true);
            }
            foreach (Terrblock block in oldTerr.BlocksHmap2)
            {
                decompressBlock(oldTerr, newTerr, block, false);
            }

            return newTerr;
        }
        /// <summary>
        /// Does the dirty work
        /// </summary>
        /// <param name="reader"></param>
        private void Parse(BinaryReader prjReader)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                BinaryWriter prjBegin = new BinaryWriter(ms);

                // check that this is a PRJ file
                string idString = ASCIIEncoding.ASCII.GetString(prjReader.ReadBytes(32));
                string header = "Dark Omen Battle file 1.10      ";
                if (idString != header)
                    throw new IOException("Not a PRJ File");
                prjBegin.Write(Encoding.ASCII.GetBytes(header));

                // ignore the BASE block
                prjBegin.Write(prjReader.ReadInt32());
                int size = prjReader.ReadInt32();
                prjBegin.Write(size);
                prjBegin.Write(prjReader.ReadBytes(size));

                // ignore the WATR block
                prjBegin.Write(prjReader.ReadInt32());
                size = prjReader.ReadInt32();
                prjBegin.Write(size);
                prjBegin.Write(prjReader.ReadBytes(size));

                // ignore the FURN block
                prjBegin.Write(prjReader.ReadInt32());
                size = prjReader.ReadInt32();
                int fixup = prjReader.ReadInt32();
                prjBegin.Write(size);
                prjBegin.Write(fixup);
                prjBegin.Write(prjReader.ReadBytes(size + fixup * 4 - 4));

                // ignore the INST block
                prjBegin.Write(prjReader.ReadInt32());
                size = prjReader.ReadInt32();
                fixup = 8;
                prjBegin.Write(size);
                prjBegin.Write(prjReader.ReadBytes(size + fixup));

                this.prjBegin = ms.ToArray();
            }

            // Read the TERR Block
            Terr = new Terr(prjReader);

            // Read until EOF
            using (MemoryStream ms = new MemoryStream())
            {
                BinaryWriter prjEnd = new BinaryWriter(ms);

                try
                {
                    for (;;)
                    {
                        prjEnd.Write(prjReader.ReadByte());
                    }
                }
                catch (EndOfStreamException)
                {
                    // Not very smart
                }

                this.prjEnd = ms.ToArray();
            }
        }
        private static void PrintStatistic(Terr terr)
        {
            // Map dimension
            Console.Error.WriteLine("Dimension: " + terr.Width + "x" + terr.Height);

            // Min/Max Heightmap Value (1st hmap)
            int min = int.MaxValue;
            int max = int.MinValue;
            foreach (Terrblock block in terr.BlocksHmap1)
            {
                min = Math.Min(min, block.Minimum);
                max = Math.Max(min, block.Minimum);
            }
            Console.Error.WriteLine("Min/Max (Hmap1): " + min + "/" + max);

            // Min/Max Heightmap Value (2nd hmap)
            min = int.MaxValue;
            max = int.MinValue;
            foreach (Terrblock block in terr.BlocksHmap2)
            {
                min = Math.Min(min, block.Minimum);
                max = Math.Max(min, block.Minimum);
            }
            Console.Error.WriteLine("Min/Max (Hmap2): " + min + "/" + max);

            // Block count (Macro and Micro blocks) + Compression ratio
            Console.Error.WriteLine("Blocks: " + terr.BlocksHmap1.Count * 2 + "/" + terr.Offsets.Count);
            String ratio = (100 - (float)terr.Offsets.Count / (terr.BlocksHmap1.Count * 2) * 100).ToString("0.00");
            Console.Error.WriteLine("Compression: " + ratio + "%");
        }
        /// <summary>
        /// Creates a Terr heightmap from a Bitmap
        /// </summary>
        /// <param name="oldTerr">Source terr</param>
        /// <param name="heightmap">Heightmap Bitmap</param>
        /// <param name="targetHmaps">Flags to determine which Heightmaps shall be changed</param>
        /// <returns></returns>
        public static Terr FromBitmap(this Terr oldTerr, Bitmap heightmap, TargetHeightmaps targetHmaps)
        {
            if (heightmap.Width != oldTerr.Width || heightmap.Height != oldTerr.Height)
            {
                throw new ArgumentException(
                    "Heightmap measures wrong. Expected: " + oldTerr.Width + "x" + oldTerr.Height +
                    " (Image: " + heightmap.Width + "x" + heightmap.Height + ")");
            }
            if ((targetHmaps & (TargetHeightmaps.FirstHeightmap | TargetHeightmaps.SecondHeightmap)) == TargetHeightmaps.None)
            {
                throw new ArgumentException("No valid TargetHeightmap specified");
            }

            oldTerr = oldTerr.Decompress();

            bool keepFirstHmap = (targetHmaps & TargetHeightmaps.FirstHeightmap) == TargetHeightmaps.None;
            bool keepSecondHmap = (targetHmaps & TargetHeightmaps.SecondHeightmap) == TargetHeightmaps.None;

            Terr newTerr = new Terr();
            newTerr.Width = oldTerr.Width;
            newTerr.Height = oldTerr.Height;

            if (keepFirstHmap)
            {
                oldTerr.CopyFirstHmap(newTerr);
            }

            // This scary loop iterates row by row over all 8x8 blocks
            for (int h = 0; h < heightmap.Height; h += 8)
            {
                for (int w = 0; w < heightmap.Width; w += 8)
                {
                    // Single 8x8 Block
                    Terrblock block = new Terrblock();
                    if (!keepFirstHmap)
                    {
                        newTerr.BlocksHmap1.Add(block);
                    }
                    if (!keepSecondHmap)
                    {
                        newTerr.BlocksHmap2.Add(block);
                    }
                    int minHeight = int.MaxValue;
                    byte[] newOffsets = new byte[64];
                    for (int y = 0; y < 8; ++y)
                    {
                        if (h + y >= heightmap.Height)
                        {   // Image height not multiple of 8
                            break;
                        }
                        for (int x = 0; x < 8; ++x)
                        {
                            if (w + x >= heightmap.Width)
                            {   // Image width not multiple of 8
                                break;
                            }
                            int height = heightmap.GetPixel(w + x, h + y).R;
                            minHeight = Math.Min(minHeight, height);
                            newOffsets[x + y * 8] = (byte)height;
                        }
                    }
                    // Adjust offsets based on minimum
                    for (int i = 0; i < 64; ++i)
                    {
                        newOffsets[i] -= (byte)(minHeight);
                    }
                    // Scale to 65535 (65535 / 255 = 257)
                    minHeight *= 257;

                    newTerr.Offsets.Add(newOffsets);
                    block.Minimum = minHeight;
                    block.OffsetIndex = newTerr.Offsets.Count - 1;
                }
            }

            if (keepSecondHmap)
            {
                oldTerr.CopySecondHmap(newTerr);
            }

            return newTerr;
        }
        private static void decompressBlock(Terr oldTerr, Terr newTerr, Terrblock block, bool firstHmap)
        {
            Terrblock newBlock = new Terrblock();
            newBlock.Minimum = block.Minimum;
            newBlock.OffsetIndex = newTerr.BlocksHmap1.Count + newTerr.BlocksHmap2.Count;

            byte[] newOffsets = new byte[64];
            byte[] oldOffsets = oldTerr.Offsets[block.OffsetIndex];

            Array.Copy(oldOffsets, newOffsets, 64);

            if (firstHmap)
            {
                newTerr.BlocksHmap1.Add(newBlock);
            }
            else
            {
                newTerr.BlocksHmap2.Add(newBlock);
            }

            newTerr.Offsets.Add(newOffsets);
        }
 /// <summary>
 /// Takes the 2nd heightmap of the old Terr item and writes it into the new.
 /// Assumes that old Terr is uncompressed and new Terr has no 2nd heightmap yet.
 /// </summary>
 /// <param name="oldTerr"></param>
 /// <param name="newTerr"></param>
 private static void CopySecondHmap(this Terr oldTerr, Terr newTerr)
 {
     foreach (Terrblock block in oldTerr.BlocksHmap2)
     {
         Terrblock newBlock = new Terrblock(block);
         newTerr.BlocksHmap2.Add(newBlock);
     }
     // It's decompressed, so the second half of the offsets references the second hmap
     for (int i = oldTerr.BlocksHmap1.Count; i < oldTerr.Offsets.Count; ++i)
     {
         byte[] newOffsets = new byte[64];
         Array.Copy(oldTerr.Offsets[i], newOffsets, 64);
         newTerr.Offsets.Add(newOffsets);
     }
 }
        /// <summary>
        /// Simply search through all offsets and check if any of them is a
        /// 100% match, in this case reference the same offset block.
        /// Naive algorithm, but fast enough in practise...
        /// </summary>
        private static void compressBlock(Terr oldTerr, Terr newTerr, Terrblock block, bool firstHmap)
        {
            Terrblock newBlock = new Terrblock();
            newBlock.Minimum = block.Minimum;

            if (firstHmap)
            {
                newTerr.BlocksHmap1.Add(newBlock);
            }
            else
            {
                newTerr.BlocksHmap2.Add(newBlock);
            }

            byte[] oldOffsets = oldTerr.Offsets[block.OffsetIndex];

            int count = 0;
            foreach (var newOffset in newTerr.Offsets) // outer
            {
                for (int i = 0; i < 64; ++i)
                {
                    if (newOffset[i] != oldOffsets[i])
                    {
                        goto next; // outer continue
                    }
                }

                // Block matches
                newBlock.OffsetIndex = count;
                return;

            next:
                ++count;
            }

            // No Block matches
            byte[] newOffsets = new byte[64];
            Array.Copy(oldOffsets, newOffsets, 64);
            newTerr.Offsets.Add(newOffsets);

            newBlock.OffsetIndex = newTerr.Offsets.Count - 1;
        }
        /// <summary>
        /// Swaps the content of the two heightmaps in a terr block
        /// </summary>
        /// <param name="oldTerr">Source terr</param>
        /// <returns>New terr with swapped heightmaps</returns>
        public static Terr Swap(this Terr oldTerr)
        {
            Terr newTerr = new Terr();
            newTerr.Width = oldTerr.Width;
            newTerr.Height = oldTerr.Height;

            foreach (Terrblock block in oldTerr.BlocksHmap1)
            {
                Terrblock newBlock = new Terrblock(block);
                newTerr.BlocksHmap2.Add(newBlock);
            }
            foreach (Terrblock block in oldTerr.BlocksHmap2)
            {
                Terrblock newBlock = new Terrblock(block);
                newTerr.BlocksHmap1.Add(newBlock);
            }

            foreach (byte[] oldOffsets in oldTerr.Offsets)
            {
                byte[] newOffsets = new byte[64];
                Array.Copy(oldOffsets, newOffsets, 64);
                newTerr.Offsets.Add(newOffsets);
            }

            return newTerr;
        }