Example #1
0
        /// <summary>
        /// Reads all the messages from the message byte code.
        /// </summary>
        /// <param name="messageData">Message byte code.</param>
        /// <param name="encodedMessages">True if messages are encoded.</param>
        /// <returns>Collection of messages.</returns>
        private static List <string> DecompileMessages(byte[] messageData, bool encodedMessages)
        {
            var messages = new List <string>();

            int messagesOffset = 0;

            ////////////////
            // Messages header

            // [0] = Number of messages
            int numMessages = messageData[messagesOffset];

            messagesOffset += 1;

            // [1][2] = Offset of end of messages
            messagesOffset += 2;

            // [3+] = Offset of each message (as per number of messages)

            // [x+] = Message data
            int messageDataOffset = messagesOffset + (numMessages * 2);

            if (numMessages > 0)
            {
                if (encodedMessages)
                {
                    // decrypt the data in-place, this modifies the buffer passed as input
                    var xform = new XorTransform(Key);
                    xform.TransformBlock(messageData, messageDataOffset, messageData.Length - messageDataOffset, messageData, messageDataOffset);
                }

                // Go back to array of offset of each message
                for (int i = 0; i < numMessages; i++)
                {
                    // [0][1] = Offset of message
                    int messageOffset = (messageData[messagesOffset + 1] * 0x100) + messageData[messagesOffset];
                    messagesOffset += 2;

                    string msg;

                    if ((messageOffset - 2) >= 0)
                    {
                        msg = StringDecoder.GetNullTerminatedString(messageData, messageOffset + 1);
                    }
                    else
                    {
                        msg = string.Empty;
                    }

                    messages.Add(msg);
                }
            }

            return(messages);
        }
Example #2
0
        /// <summary>
        /// Decode the inventory resource from byte array.
        /// </summary>
        /// <param name="data">Source array (data should NOT be encrypted).</param>
        /// <param name="padded">Inventory data is padded.</param>
        /// <returns>Inventory resource.</returns>
        private static InventoryResource ReadInventory(byte[] data, bool padded)
        {
            int offset = 0;

            // [0][1] = Offset of the start of inventory item names
            int namesOffset = (data[offset + 1] * 0x100) + data[offset];

            offset += 2;

            // [2] = Maximum number of animated objects (not sure what this is for)
            byte maxAnimatedObjects = data[offset];

            offset += 1;

            if (padded)
            {
                offset++;
            }

            var items = new List <InventoryItem>();

            // [3+] = three byte entry for each inventory item all of which conform to the following format
            while (offset <= namesOffset)
            {
                // [0][1] = Offset of inventory item name i
                int nameOffset = (data[offset + 1] * 0x100) + data[offset];
                offset += 2;

                // [2] = Starting room number for inventory item i or 255 carried
                byte room = data[offset];
                offset += 1;

                if (padded)
                {
                    offset++;
                }

                // [offset + 3]
                string name = StringDecoder.GetNullTerminatedString(data, nameOffset + (padded ? 4 : 3));

                items.Add(new InventoryItem(name, room));
            }

            return(new InventoryResource(items.ToArray(), maxAnimatedObjects));
        }
Example #3
0
        /// <summary>
        /// Decode the view resource from byte array.
        /// </summary>
        /// <param name="resourceIndex">Resource index.</param>
        /// <param name="viewData">View data.</param>
        /// <returns>View resource.</returns>
        public static ViewResource ReadView(byte resourceIndex, byte[] viewData)
        {
            var mapLoopHeaderPosToLoopNum = new Dictionary <int, int>();

            // View header
            int viewOffset = 0;

            // [0] = unknown
            byte unknown1 = viewData[viewOffset];

            viewOffset += 1;

            // [1] = unknown
            byte unknown2 = viewData[viewOffset];

            viewOffset += 1;

            // [2] = number of loops
            int numLoops = viewData[viewOffset];

            viewOffset += 1;

            // [3][4] = position of description
            int descPos = (viewData[viewOffset + 1] * 0x100) + viewData[viewOffset];

            viewOffset += 2;

            string description = string.Empty;

            if (descPos > 0)
            {
                description = StringDecoder.GetNullTerminatedString(viewData, descPos);
            }

            var loops = new ViewLoop[numLoops];

            for (int loop = 0; loop < numLoops; loop++)
            {
                var cels          = new ViewCel[0];
                int mirrorOfIndex = -1;

                // [0][1] = position of loop header
                int loopHeaderPos = (viewData[viewOffset + 1] * 0x100) + viewData[viewOffset];
                viewOffset += 2;

                if (mapLoopHeaderPosToLoopNum.ContainsKey(loopHeaderPos))
                {
                    // We have already seen this loop, looks like this is a mirror
                    mirrorOfIndex = mapLoopHeaderPosToLoopNum[loopHeaderPos];
                }
                else
                {
                    mapLoopHeaderPosToLoopNum.Add(loopHeaderPos, loop);

                    // Loop header
                    int loopOffset = loopHeaderPos;

                    // [0] = number of cels in loop
                    int numCels = viewData[loopOffset];
                    loopOffset += 1;

                    cels = new ViewCel[numCels];
                    for (int cel = 0; cel < numCels; cel++)
                    {
                        // [0][1] = position of first cel header, relative to start of loop
                        int celHeaderPos = (viewData[loopOffset + 1] * 0x100) + viewData[loopOffset];
                        loopOffset += 2;

                        // Cel header
                        int celOffset = loopHeaderPos + celHeaderPos;

                        // [0] = width of cel in pixels (1 agi pixels = 2 ega pixels)
                        byte celWidth = viewData[celOffset];
                        celOffset += 1;

                        // [1] = height of cel
                        byte celHeight = viewData[celOffset];
                        celOffset += 1;

                        // [2] = transparency and cel mirroring
                        // (high 4 bits are mirror info, low 4 bits are transparent color)
                        byte transparentColor = (byte)(viewData[celOffset] & 0x0f);
                        byte mirrorInfo       = (byte)((viewData[celOffset] & 0xf0) >> 4);
                        bool mirror           = (mirrorInfo & 0x08) != 0;
                        byte mirrorLoopNumber = (byte)(mirrorInfo & 0x07);
                        celOffset += 1;

                        // [+] = RLE encoding of pixels
                        byte[] pixels = RleCompression.Decompress(viewData, celOffset, celWidth, celHeight, transparentColor);

                        cels[cel] = new ViewCel(celWidth, celHeight, transparentColor, mirror, mirrorLoopNumber, pixels);
                    }
                }

                loops[loop] = new ViewLoop(cels, mirrorOfIndex);
            }

            // Go through all the loops and process the ones that are marked as mirrors
            for (int loop = 0; loop < loops.Length; loop++)
            {
                if (loops[loop].IsMirror)
                {
                    // Create the mirrored cels for this loop
                    var originalLoop = loops[loops[loop].MirrorOfIndex];

                    var cels = new ViewCel[originalLoop.Cels.Length];
                    for (int cel = 0; cel < cels.Length; cel++)
                    {
                        ViewCel originalCel = originalLoop.Cels[cel];
                        cels[cel] = new ViewCel(originalCel.Width, originalCel.Height, originalCel.TransparentColor, originalCel.Mirror, originalCel.MirrorLoopNumber, originalCel.MirrorPixels());
                    }

                    loops[loop] = new ViewLoop(cels, -1);
                }
            }

            return(new ViewResource(resourceIndex, loops, description, unknown1, unknown2));
        }