예제 #1
0
        public Bitmap MakeTilesetBitmap(TOCEntry entry, bool collisions) // entry can be COL or PIC
        {
            string   picName, palName, colName;
            TOCEntry picEntry, palEntry, colEntry;

            // level number from BLOCK?.PIC or WORLD?.COL file
            if (!int.TryParse(entry.Name.Substring(5, 1), out int levelNumber))
            {
                return(null);
            }

            if (entry.Type == TOCEntryType.CollisionInfo) // get matching block?.pic
            {
                colEntry = entry;
                picName  = $"BLOCK{levelNumber}.PIC";
                if (!assets.Entries.ContainsKey(picName))
                {
                    return(null);
                }
                picEntry = assets.Entries[picName];
            }
            else // get matching world?.col
            {
                if (levelNumber == 6)
                {
                    levelNumber = 5;
                }

                picEntry = entry;

                // collision entry
                colName = $"WORLD{levelNumber}.COL";
                if (!assets.Entries.ContainsKey(colName))
                {
                    return(null);
                }
                colEntry = assets.Entries[colName];
            }

            if (levelNumber == 6)
            {
                levelNumber = 5;
            }

            // palette entry
            palName = $"WORLD{levelNumber}.PAL";
            if (!assets.Entries.ContainsKey(palName))
            {
                return(null);
            }
            palEntry = assets.Entries[palName];

            // read col data
            COLFile colFile = collisions ? new COLFile(colEntry.Data) : null;

            try
            {
                return(FromBitmaps(PICConverter.PICToBitmaps(picEntry.Data, palEntry.Data), colFile));
            }
            catch { return(null); }
        }
예제 #2
0
        public static TOC Load(byte[] exeData, bool gapsAsEntries = false)
        {
            List <TOCEntry> entries = new List <TOCEntry>();

            // locate the packed TOC in the binary
            if (BitConverter.ToInt32(exeData, exeData.Length - 4) != 0x53464945) // "EIFS"
            {
                throw new Exception("error loading toc");
            }
            int packedTocLength = BitConverter.ToUInt16(exeData, exeData.Length - 6);
            int packedTocPos    = exeData.Length - 6 - packedTocLength;

            // unpack the TOC and parse it
            var tocBuffer = new byte[10000];
            int length    = UnpackBlock(tocBuffer, exeData.SubArray(packedTocPos, packedTocLength));

            if (length < 1)
            {
                throw new Exception("error unpacking toc");
            }
            ParseToc(entries, tocBuffer);

            //var fff = new StreamWriter("debug.txt");
            //int numGood = 0;

            // unpack all files
            var buffer = new byte[1024];

            foreach (var entry in entries)
            {
                entry.Data = new byte[entry.Size];

                List <BlockInfo> blockInfos = new List <BlockInfo>();

                // keep reading packed blocks until we reach the end pointer
                // a block produces 1024 bytes of unpacked data at max!
                int readPos       = entry.PackedStart;
                int writePos      = 0;
                int numStreamRead = 0;
                for (; readPos < entry.PackedEnd;)
                {
                    int blockLength = exeData[readPos] + exeData[readPos + 1] * 256;

                    blockInfos.Add(new BlockInfo {
                        Position = readPos, Length = blockLength
                    });

                    var numBytes = UnpackBlock(buffer, exeData.SubArray(readPos, blockLength + 6));
                    Array.Copy(buffer, 0, entry.Data, writePos, numBytes);

                    numStreamRead += blockLength;
                    writePos      += numBytes;
                    readPos       += blockLength + 2;
                }
                blockInfos.Add(new BlockInfo {
                    Position = readPos, Length = 0
                });

                if (writePos != entry.Size)
                {
                    throw new Exception("unpacking error");
                }

                // verify the block-address table:
                for (int i = 0; i < blockInfos.Count; ++i)
                {
                    int address = BitConverter.ToInt32(exeData, readPos);
                    if (address != blockInfos[i].Position)
                    {
                        throw new Exception("bad BAT entry");
                    }
                    readPos += 4;
                }

                entry._BATEnd = readPos;

                // int length2 = BitConverter.ToUInt16(exeData, readPos); readPos += 2;
                //if(BitConverter.ToUInt32(exeData, readPos) != 0x53464945) // "EIFS"
                //    throw new Exception("bad magic id");
            }

            //fff.WriteLine(numGood + " good out of " + entries.Count);

            //fff.Flush();

            if (gapsAsEntries)
            {
                List <TOCEntry> tmp = new List <TOCEntry>(entries);
                tmp.Sort((a, b) => a.PackedStart.CompareTo(b.PackedStart));

                for (int i = 0; i + 1 < tmp.Count; ++i)
                {
                    var gap = new TOCEntry();
                    gap.Name        = tmp[i].Name + ".gap";
                    gap.Index       = tmp[i].Index;
                    gap.PackedStart = tmp[i]._BATEnd;
                    gap.PackedEnd   = tmp[i + 1].PackedStart;

                    gap.Data = exeData.SubArray(tmp[i]._BATEnd, tmp[i + 1].PackedStart - tmp[i]._BATEnd);
                    gap.Size = gap.Data.Length;

                    entries.Add(gap);
                }
            }

            var toc = new TOC();

            toc.Entries = new Dictionary <string, TOCEntry>();
            foreach (var entry in entries)
            {
                toc.Entries.Add(entry.Name, entry);
            }
            return(toc);
        }
예제 #3
0
        public bool Make(TOCEntry entry)
        {
            mapEntry = entry;
            Error    = "";

            // level number
            string mapName = mapEntry.Name;

            if (!int.TryParse(mapName.Substring(1, 1), out int levelNumber))
            {
                Error = $"unable to derive level number from map name {mapName}";
                return(false);
            }

            // tileset
            string tilesetName = $"BLOCK{levelNumber}.PIC";

            if (!assets.Entries.ContainsKey(tilesetName))
            {
                Error = $"tileset {tilesetName} not found";
                return(false);
            }
            tilesetEntry = assets.Entries[tilesetName];

            // entities
            if (levelNumber < 6)
            {
                string eibName = $"WORLD{mapName.Substring(1, 3)}.EIB";
                if (!assets.Entries.ContainsKey(eibName))
                {
                    Error = $"entities {eibName} not found";
                    return(false);
                }
                entitiesEntry = assets.Entries[eibName];
            }
            else
            {
                entitiesEntry = null;
            }

            if (levelNumber == 6)
            {
                levelNumber = 5;                   // level 6 is using palette of level 5
            }
            // collisions
            string collisionsName = $"WORLD{levelNumber}.COL";

            if (!assets.Entries.ContainsKey(collisionsName))
            {
                Error = $"collisions {collisionsName} not found";
                return(false);
            }
            collisionsEntry = assets.Entries[collisionsName];

            // palette
            string palName = $"WORLD{levelNumber}.PAL";

            if (!assets.Entries.ContainsKey(palName))
            {
                Error = $"palette {palName} not found";
                return(false);
            }
            paletteEntry = assets.Entries[palName];

            worker.RunWorkerAsync(); // calls make()
            return(true);
        }