Exemplo n.º 1
0
        public static Dictionary <int, byte[]> GetMateriaStrings(string materiaStringsFilePath)
        {
            FileStream fs = File.OpenRead(materiaStringsFilePath);

            try
            {
                int r = 0; // Navigates byte[] currentItem
                int o = 0; // Iterates through headers
                int c = 0; // Materia ID
                int k = 0; // Navigates byte[] data

                bool terminate    = false;
                var  materiaNames = new Dictionary <int, byte[]>();

                byte[]   stringHeader   = new byte[2];
                byte[][] currentMateria = new byte[96][];
                byte[]   data           = new byte[fs.Length];

                fs.Read(data, 0, Convert.ToInt32(fs.Length));
                fs.Close();

                while (!terminate)
                {
                    stringHeader[0] = data[o];
                    stringHeader[1] = data[o + 1];
                    k = EndianMethods.GetLittleEndianIntTwofer(stringHeader, 0);

                    currentMateria[c] = new byte[40];
                    // Read string until terminator FF is hit
                    while (data[k + r] != 0xFF)
                    {
                        currentMateria[c][r] = data[k + r];
                        r++;
                    }
                    currentMateria[c][r] = 0xFF;
                    materiaNames.Add(c, currentMateria[c]);

                    // Check if we've hit end of file; if next byte is FF then we have
                    if (data[k + r + 1] == 0xFF)
                    {
                        terminate = true;
                    }
                    else
                    {
                        o += 2; // Next header
                        c++;    // Next Materia ID
                        r = 0;  // Reset for next Materia string reading
                    }
                }
                return(materiaNames);
            }
            finally
            {
                fs.Close();
            }
        }
Exemplo n.º 2
0
        public static int GetItemID(List <byte> oldItemName)
        {
            if (oldItemName.Count == 0)
            {
                Trace.WriteLine("Empty item name was received");
                return(0);
            }

            byte[] terminator     = { 0xFF };
            byte[] firstCharacter = new byte[] { oldItemName[0] };
            int    itemID         = 0;
            bool   falsePositive  = false;

            FileStream item = File.OpenRead(Directory.GetCurrentDirectory() + "\\Kernel Strings\\kernel.bin19");

            byte[] dataItem = new byte[item.Length];
            item.Read(dataItem, 0, Convert.ToInt32(item.Length));
            item.Close();

            byte[] itemOffset = new byte[2];
            itemOffset[0] = dataItem[0];
            itemOffset[1] = dataItem[1];
            int itemOffsetInt = EndianMethods.GetLittleEndianIntTwofer(itemOffset, 0);

            FileStream weapon = File.OpenRead(Directory.GetCurrentDirectory() + "\\Kernel Strings\\kernel.bin20");

            byte[] dataWeapon = new byte[weapon.Length];
            weapon.Read(dataWeapon, 0, Convert.ToInt32(weapon.Length));
            weapon.Close();

            byte[] weaponOffset = new byte[2];
            weaponOffset[0] = dataWeapon[0];
            weaponOffset[1] = dataWeapon[1];
            int weaponOffsetInt = EndianMethods.GetLittleEndianIntTwofer(weaponOffset, 0);

            FileStream armour = File.OpenRead(Directory.GetCurrentDirectory() + "\\Kernel Strings\\kernel.bin21");

            byte[] dataArmour = new byte[armour.Length];
            armour.Read(dataArmour, 0, Convert.ToInt32(armour.Length));
            armour.Close();

            byte[] armourOffset = new byte[2];
            armourOffset[0] = dataArmour[0];
            armourOffset[1] = dataArmour[1];
            int armourOffsetInt = EndianMethods.GetLittleEndianIntTwofer(armourOffset, 0);

            FileStream accessory = File.OpenRead(Directory.GetCurrentDirectory() + "\\Kernel Strings\\kernel.bin22");

            byte[] dataAccessory = new byte[accessory.Length];
            accessory.Read(dataAccessory, 0, Convert.ToInt32(accessory.Length));
            accessory.Close();

            byte[] accessoryOffset = new byte[2];
            accessoryOffset[0] = dataAccessory[0];
            accessoryOffset[1] = dataAccessory[1];
            int accessoryOffsetInt = EndianMethods.GetLittleEndianIntTwofer(accessoryOffset, 0);

            try
            {
                for (int r = itemOffsetInt; r < dataItem.Length; r++)
                {
                    if (dataItem.Skip(r).Take(terminator.Length).SequenceEqual(terminator))
                    {
                        itemID++;
                        // Prevents out of range
                        if ((r + 1) < dataItem.Length)
                        {
                            // Some Item names appear within other Item names
                            // This checks the first character after a terminator for a match and if it isn't it will
                            // prevent the sequenceEqual from returning true.
                            if (dataItem[r + 1] != firstCharacter[0])
                            {
                                falsePositive = true;
                            }
                            else
                            {
                                falsePositive = false;
                                r++;
                            }
                        }
                    }
                    if (!falsePositive)
                    {
                        if (dataItem.Skip(r).Take(oldItemName.Count).SequenceEqual(oldItemName))
                        {
                            return(itemID);
                        }
                    }
                }

                itemID = 128;
                for (int o = weaponOffsetInt; o < dataWeapon.Length; o++)
                {
                    if (dataWeapon.Skip(o).Take(terminator.Length).SequenceEqual(terminator))
                    {
                        itemID++;
                        // Prevents out of range
                        if ((o + 1) < dataWeapon.Length)
                        {
                            // Some Item names appear within other Item names
                            // This checks the first character after a terminator for a match and if it isn't it will
                            // prevent the sequenceEqual from returning true.
                            if (dataWeapon[o + 1] != firstCharacter[0])
                            {
                                falsePositive = true;
                            }
                            else
                            {
                                falsePositive = false;
                                o++;
                            }
                        }
                    }
                    if (!falsePositive)
                    {
                        if (dataWeapon.Skip(o).Take(oldItemName.Count).SequenceEqual(oldItemName))
                        {
                            return(itemID);
                        }
                    }
                }

                itemID = 256;
                for (int c = armourOffsetInt; c < dataArmour.Length; c++)
                {
                    if (dataArmour.Skip(c).Take(terminator.Length).SequenceEqual(terminator))
                    {
                        itemID++;
                        // Prevents out of range
                        if ((c + 1) < dataArmour.Length)
                        {
                            // Some Item names appear within other Item names
                            // This checks the first character after a terminator for a match and if it isn't it will
                            // prevent the sequenceEqual from returning true.
                            if (dataArmour[c + 1] != firstCharacter[0])
                            {
                                falsePositive = true;
                            }
                            else
                            {
                                falsePositive = false;
                                c++;
                            }
                        }
                    }
                    if (!falsePositive)
                    {
                        if (dataArmour.Skip(c).Take(oldItemName.Count).SequenceEqual(oldItemName))
                        {
                            return(itemID);
                        }
                    }
                }

                itemID = 288;
                for (int k = accessoryOffsetInt; k < dataAccessory.Length; k++)
                {
                    if (dataAccessory.Skip(k).Take(terminator.Length).SequenceEqual(terminator))
                    {
                        itemID++;
                        // Prevents out of range
                        if ((k + 1) < dataAccessory.Length)
                        {
                            // Some Item names appear within other Item names
                            // This checks the first character after a terminator for a match and if it isn't it will
                            // prevent the sequenceEqual from returning true.
                            if (dataAccessory[k + 1] != firstCharacter[0])
                            {
                                falsePositive = true;
                            }
                            else
                            {
                                falsePositive = false;
                                k++;
                            }
                        }
                    }
                    if (!falsePositive)
                    {
                        if (dataAccessory.Skip(k).Take(oldItemName.Count).SequenceEqual(oldItemName))
                        {
                            return(itemID);
                        }
                    }
                }
                Trace.WriteLine("No matches in getting old Item ID - Used 0 as fallback");
                return(0);
            }
            catch
            {
                Trace.WriteLine("Error in getting old Item ID");
                return(0);
            }
        }
Exemplo n.º 3
0
        public static byte[] SwapFieldModels(byte[] data)
        {
            int r = 0; // Iteration through model entries
            int o = 0; // Array index
            int c = 0; // Iteration through model's anims

            // Model Loader header
            // 0x00: Always 0
            // 0x02: Model Count
            // 0x04: Model Scale (unused)
            // 0x06: Model Loader Data starts

            try
            {
                // Get the number of models in this field
                byte[] modelCountByte = new byte[2];
                modelCountByte[0] = data[o + 2];
                modelCountByte[1] = data[o + 3];
                int    modelCount = EndianMethods.GetLittleEndianIntTwofer(modelCountByte, 0);
                Random rnd        = new Random();
                o += 6; // Skip data position past the header

                while (r < modelCount)
                {
                    // Take size of model name and convert it into an int for array index
                    byte[] modelNameSizeByte = new byte[2];
                    modelNameSizeByte[0] = data[o];
                    modelNameSizeByte[1] = data[o + 1];
                    int modelNameSize = EndianMethods.GetLittleEndianIntTwofer(modelNameSizeByte, 0);
                    o += 2;

                    // Skip 2-byte unknown value
                    o += 2;

                    // Jump past model name string to HRC location
                    o += modelNameSize;

                    // Read the current .HRC ID
                    byte[] currentHRCBytes = new byte[4];
                    currentHRCBytes[0] = data[o];
                    currentHRCBytes[1] = data[o + 1];
                    currentHRCBytes[2] = data[o + 2];
                    currentHRCBytes[3] = data[o + 3];

                    // ASCII conversion - string from .HRC bytes - Output: "AAAA"
                    string currentHRC = @"" + Encoding.ASCII.GetString(currentHRCBytes, 0, currentHRCBytes.Length) + @"";

                    // If no options on, the current HRC will be used
                    string newHRC = currentHRC;

                    // temp var for testing, will be fed through to method from Form later
                    bool rndModelSwap = true;

                    // Complete Random Swap
                    if (rndModelSwap)
                    {
                        newHRC = FieldModels.RandomModelSwap(rnd);
                    }

                    // Converts the returned string into bytes
                    byte[] newHRCBytes = ConvertString.GetNameBytes(newHRC);

                    // Writes the new bytes to the .HRC
                    data[o]     = newHRCBytes[0];
                    data[o + 1] = newHRCBytes[1];
                    data[o + 2] = newHRCBytes[2];
                    data[o + 3] = newHRCBytes[3];
                    o          += 8; // Skip the .HRC part of the string


                    // Model Scale - Definitely have this as an option
                    // This is actually a string; '512' but written in ascii. Bear that in mind.
                    o += 4;

                    // Count the number of anims for this model
                    byte[] animCountByte = new byte[2];
                    animCountByte[0] = data[o];
                    animCountByte[1] = data[o + 1];
                    int animCount = EndianMethods.GetLittleEndianIntTwofer(animCountByte, 0);
                    o += 2;

                    // Light/Shading data - Will probably not be modifying these values
                    o += 30;

                    // Anims - Each anim has the following:
                    // 0x00: Size of anim name string
                    // 0x02: Anim name string
                    // 0x02 + Size: Unknown, 2-byte value
                    while (c < animCount)
                    {
                        // Take size of anim name and convert it into an int for array index
                        byte[] animNameSizeByte = new byte[2];
                        animNameSizeByte[0] = data[o];
                        animNameSizeByte[1] = data[o + 1];
                        int animNameSize = EndianMethods.GetLittleEndianIntTwofer(animNameSizeByte, 0);
                        o += 2;

                        // Read the current .HRC ID
                        byte[] currentAnimBytes = new byte[4];
                        currentAnimBytes[0] = data[o];
                        currentAnimBytes[1] = data[o + 1];
                        currentAnimBytes[2] = data[o + 2];
                        currentAnimBytes[3] = data[o + 3];

                        // ASCII conversion - string from .HRC bytes - Output: "AAAA"
                        string currentAnim = @"" + Encoding.ASCII.GetString(currentAnimBytes, 0, currentAnimBytes.Length) + @"";

                        // If no options on, the current Anim will be used
                        string newAnim = currentAnim;

                        bool rndAnimSwap = false;
                        // Changes the Anim string - Matches it to current HRC's anim pool
                        if (rndAnimSwap == true)
                        {
                            newAnim = FieldModels.MatchedAnimSwap(currentAnim, newHRC);
                        }

                        bool animTest = true;
                        // Complete Random
                        if (animTest == true)
                        {
                            newAnim = FieldModels.RandomAnimSwap(rnd);
                        }

                        // Converts the string into bytes
                        byte[] newAnimBytes = ConvertString.GetNameBytes(newAnim);

                        // Writes the new bytes
                        data[o]     = newAnimBytes[0];
                        data[o + 1] = newAnimBytes[1];
                        data[o + 2] = newAnimBytes[2];
                        data[o + 3] = newAnimBytes[3];
                        o          += animNameSize; // Move past the anim name

                        // Unknown 2 bytes, skipped
                        o += 2;

                        c++;
                    }
                    c = 0;
                    r++;
                }
            }
            catch
            {
                MessageBox.Show("Flevel Chunk #3 (Model Loader) has encountered an issue; skipping current field");
            }
            return(data);
        }
Exemplo n.º 4
0
        public static byte[] ChangeItemsMateria(byte[] data, string name)
        {
            // Get the start of the text section offset
            byte[] textStart = new byte[2];

            textStart[0] = data[4];
            textStart[1] = data[5];
            int textOffset = EndianMethods.GetLittleEndianIntTwofer(textStart, 0);

            if (name == "qd")
            {
                // Breakpoint sink to analyse qd's allocation of items
            }

            // Prevents an out of bounds exception and returns data unaltered
            if (textOffset >= data.Length)
            {
                return(data);
            }
            int textCount = data[textOffset];

            // Now iterate through the event script to find references to used dialog
            // We have very little security available for a 3-byte opcode in which 2
            // of the bytes are unknown, so anything available has been added to help
            // reduce possibility of false positives.
            var        maxSearchRangeDialogue = data.Length - 3;
            var        currentDialogue        = new byte[1];
            var        searchDialogue         = new byte[] { 0x40 }; // This is the opcode, the only 1 of the 3 bytes that is static
            List <int> usedTexts = new List <int>();

            for (int k = 0; k < maxSearchRangeDialogue; k++)
            {
                // OpCode 0x40
                currentDialogue[0] = data[k];

                // If a match is found, we can call a method to change the string
                if (searchDialogue.SequenceEqual(currentDialogue))
                {
                    // Check that next part of opcode is a valid value of 0-3
                    if (data[k + 1] < 4)
                    {
                        // Then check that the dialogue ID is a valid value
                        if (data[k + 2] < textCount)
                        {
                            // Add the text ID set to this opcode to our list of used texts
                            // Exclude duplicates
                            if (!usedTexts.Contains(data[k + 2]))
                            {
                                usedTexts.Add(data[k + 2]);
                            }
                        }
                    }
                }
            }

            // Exceptions List
            // A number of texts aren't uniformly formatted; some have extra spaces, some omit the Key Item part, etc.
            // This removes them from the pool so that their strings aren't swapped.
            if (name == "blin62_1")
            {
                // Removes Keycard 65 reference from the pool
                usedTexts.Remove(19);
            }
            if (name == "bonevil")
            {
                // Removes Mop reference from the pool, as this can have its string size exceeded by certain items
                usedTexts.Remove(12);
            }
            if (name == "bugin1b")
            {
                // Master Magic/Command/Summon texts have false positives, prune them
                usedTexts.Remove(14);
                usedTexts.Remove(16);
                usedTexts.Remove(17);
            }
            if (name == "eals_1")
            {
                // Received texts on this field start with 2 spaces, throwing it off
                // TODO: Add logic to handle this field
                return(data);
            }
            if (name == "games-2")
            {
                // Removes Ink reference from the pool, as this can have its string size exceeded by certain items
                usedTexts.Remove(37);
            }
            if (name == "mkt_w")
            {
                // Removes Batteries reference from the pool
                usedTexts.Remove(13);
            }
            if (name == "zz1")
            {
                // Removes Mythril reference from pool
                usedTexts.Remove(5);
            }
            if (name == "zz6")
            {
                // Has no 'Materia!' at the end of its Materia string, gets flagged as an item instead.
                // TODO: Add logic to handle this case.
                return(data);
            }
            if (name == "zz8")
            {
                // Name of Materia differs to Kernel-stored name (KOTR)
                // TODO: Add logic to handle this case.
                return(data);
            }


            Random rnd = new Random();
            int    r   = 0; // Iterates new item string
            string itemFileLocation = "";
            //var itemNames = MateriaStrings.GetMateriaStrings(Directory.GetCurrentDirectory() + "\\Kernel Strings\\kernel.bin19");
            //var weaponNames = MateriaStrings.GetMateriaStrings(Directory.GetCurrentDirectory() + "\\Kernel Strings\\kernel.bin20");
            //var armourNames = MateriaStrings.GetMateriaStrings(Directory.GetCurrentDirectory() + "\\Kernel Strings\\kernel.bin21");
            //var accessoryNames = MateriaStrings.GetMateriaStrings(Directory.GetCurrentDirectory() + "\\Kernel Strings\\kernel.bin22");
            var materiaNames = MateriaStrings.GetMateriaStrings(Directory.GetCurrentDirectory() + "\\Kernel Strings\\kernel.bin23");

            var terminator           = new byte[1];
            int offset               = 0;
            var currentString        = new byte[10];
            var maxSearchRangeString = data.Length - 9;

            var maxSearchRangeItem = data.Length - 5;

            var currentMateria = new byte[7];
            var currentItem    = new byte[5];
            var finalItem      = new byte[3];

            List <byte> oldName      = new List <byte>();
            int         oldMateriaID = 0;
            int         oldItemID    = 0;

            // Searches for final items to update them back to 01 quantity
            var searchFinalItem = new byte[] { 0x58, 0x00, 0xFE };

            // Searches for string 'Received "' for items
            var searchString = new byte[] { 0x32, 0x45, 0x43, 0x45, 0x49, 0x56, 0x45, 0x44, 0x00, 0x02 };

            // Checks for '" Materia!' for Materia
            var appendSearchMateria = new byte[] { 0x02, 0x00, 0x2D, 0x41, 0x54, 0x45, 0x52, 0x49, 0x41, 0x01 };

            // Tracks the current Text ID based on how many terminators have been read; compared to List of Used Text IDs
            int textID = 0;

            // Checks for Materia first, then Items; Received will be overwritten by Materia check so no overlap should occur.

            // If materia option is on
            for (var y = textOffset + (textCount * 2); y < maxSearchRangeString; y++)
            {
                terminator[0] = data[y];

                currentString[0] = data[y];
                currentString[1] = data[y + 1];
                currentString[2] = data[y + 2];
                currentString[3] = data[y + 3];
                currentString[4] = data[y + 4];
                currentString[5] = data[y + 5];
                currentString[6] = data[y + 6];
                currentString[7] = data[y + 7];
                currentString[8] = data[y + 8];
                currentString[9] = data[y + 9];

                // Tracks location of the terminator, and moves up 1 to start of next string
                if (terminator[0] == 0xFF)
                {
                    textID++;
                    offset = y + 1;
                }

                if (appendSearchMateria.SequenceEqual(currentString))
                {
                    if (usedTexts.Contains(textID))
                    {
                        // Selects new Item ID
                        int newMateriaID = rnd.Next(91);

                        // Re-rolls until ID is valid
                        while (newMateriaID == 22 ||
                               newMateriaID == 38 ||
                               newMateriaID == 45 ||
                               newMateriaID == 46 ||
                               newMateriaID == 47 ||
                               newMateriaID == 63 ||
                               newMateriaID == 66 ||
                               newMateriaID == 67)
                        {
                            newMateriaID = rnd.Next(91);
                            if (newMateriaID == 91)
                            {
                                // break
                            }
                        }

                        // Skips past the Receieved " part of the string to the Materia Name
                        int countCharacters = offset + 10;

                        // Get old Materia name and match it to its ID; 0x02 is the terminator (")
                        while (data[countCharacters] != 0x02)
                        {
                            oldName.Add(data[countCharacters]);
                            countCharacters++;
                        }

                        // Figure out the Materia ID by matching the name in the kernel strings
                        oldMateriaID = MateriaStrings.GetMateriaID(oldName);
                        oldName.Clear();

                        // Replace string with new Materia name
                        while (materiaNames[newMateriaID][r] != 0xFF)
                        {
                            // Sets position to start of string
                            data[offset] = materiaNames[newMateriaID][r]; offset++; r++;
                        }
                        // Blank the rest of the string with 00s until the terminator FF
                        while (data[offset] != 0xFF)
                        {
                            data[offset] = 0x00; offset++;
                        }
                        Trace.WriteLine("Rewrote Materia String");
                        y++;
                        r = 0;

                        // Now to find the Materia opcode; assuming they are in same order as text.
                        // When a string is found, a search is conducted to find the next Materia opcode.
                        var searchMateria = new byte[] { 0x5B, 0x00, 0x00, (byte)oldMateriaID, 0x00, 0x00, 0x00 };
                        maxSearchRangeItem = data.Length - 6;

                        // You know you've hit rock bottom when you have to start assigning the value of a variable to itself.
                        for (int c = 0; c < maxSearchRangeItem; c++)
                        {
                            currentMateria[0] = data[c];       // Always 0x5B
                            currentMateria[1] = data[c + 1];   // Always 0x00
                            currentMateria[2] = data[c + 2];   // Always 0x00
                            currentMateria[3] = data[c + 3];   // Old Materia ID
                            currentMateria[4] = data[c + 4];   // Always 0x00
                            currentMateria[5] = data[c + 5];   // Always 0x00
                            currentMateria[6] = data[c + 6];   // Always 0x00

                            // If a match is found, we can call a method to change the string
                            if (searchMateria.SequenceEqual(currentMateria))
                            {
                                data[c] = 0x5B; c++;
                                data[c] = 0x00; c++;
                                data[c] = 0x00; c++;
                                data[c] = (byte)newMateriaID; c++; // Materia ID
                                data[c] = 0x00; c++;
                                data[c] = 0x00; c++;
                                data[c] = 0x00; c++;
                                Trace.WriteLine("A Materia was rewritten successfully");
                            }
                        }
                        usedTexts.Remove(textID);
                    }
                }
            }
            offset = 0;
            r      = 0;
            textID = 0;

            // If item option is on
            for (var o = textOffset + (textCount * 2); o < maxSearchRangeString; o++)
            {
                terminator[0] = data[o];

                currentString[0] = data[o];
                currentString[1] = data[o + 1];
                currentString[2] = data[o + 2];
                currentString[3] = data[o + 3];
                currentString[4] = data[o + 4];
                currentString[5] = data[o + 5];
                currentString[6] = data[o + 6];
                currentString[7] = data[o + 7];
                currentString[8] = data[o + 8];
                currentString[9] = data[o + 9];

                // Tracks location of the terminator, and moves up 1 to start of next string
                if (terminator[0] == 0xFF)
                {
                    textID++;
                    offset = o + 1;
                }

                if (textID == 10)
                {
                    // break
                }

                // Match found for the string in this chunk
                if (searchString.SequenceEqual(currentString))
                {
                    if (usedTexts.Contains(textID))
                    {
                        // Rolls a new Item ID; will re-roll if it picks an empty item ID
                        int newItemID = rnd.Next(0, 319);
                        while (newItemID > 104 && newItemID < 128)
                        {
                            newItemID = rnd.Next(0, 319); // Selects new Item ID
                        }

                        if (newItemID < 128)
                        {
                            itemFileLocation = Directory.GetCurrentDirectory() + "\\Kernel Strings\\kernel.bin19";
                        }
                        else if (newItemID < 256)
                        {
                            itemFileLocation = Directory.GetCurrentDirectory() + "\\Kernel Strings\\kernel.bin20";
                        }
                        else if (newItemID < 288)
                        {
                            itemFileLocation = Directory.GetCurrentDirectory() + "\\Kernel Strings\\kernel.bin21";
                        }
                        else if (newItemID < 320)
                        {
                            itemFileLocation = Directory.GetCurrentDirectory() + "\\Kernel Strings\\kernel.bin22";
                        }

                        // Skips past the Receieved " part of the string to the Item Name
                        int countItemCharacters = offset + 10;

                        // Get old Item name and match it to its ID; 0x02 is the terminator (")
                        while (data[countItemCharacters] != 0x02)
                        {
                            oldName.Add(data[countItemCharacters]);
                            countItemCharacters++;
                        }

                        // Figure out the Item ID by matching the name in the kernel strings
                        oldItemID = ItemStrings.GetItemID(oldName);
                        oldName.Clear();

                        var itemNames = ItemStrings.GetItemStrings(itemFileLocation, newItemID);

                        // Replace string with new item name
                        while (itemNames[newItemID][r] != 0xFF)
                        {
                            data[o] = itemNames[newItemID][r]; o++; r++;
                        }
                        // Blank the rest of the string with 00s until the terminator FF
                        while (data[o] != 0xFF)
                        {
                            data[o] = 0x00; o++;
                        }
                        Trace.WriteLine("Rewrote Item String");
                        r = 0;

                        // Now to find the item opcode; assuming they are in same order as text.
                        // When a string is found, a search is conducted to find the next item Opcode.

                        ulong  convertOldItemID = (ulong)oldItemID;
                        byte[] oldItemIDByte    = EndianMethods.GetLittleEndianConvert(convertOldItemID);

                        var searchItem = new byte[] { 0x58, 0x00, oldItemIDByte[0], oldItemIDByte[1], 0x01 };

                        // You know you've hit rock bottom when you have to start assigning the value of a variable to itself.
                        for (int c = 0; c < maxSearchRangeItem; c++)
                        {
                            currentItem[0] = data[c];       // Always 0x58
                            currentItem[1] = data[c + 1];   // Always 0x00
                            currentItem[2] = data[c + 2];   // Old Item ID - 2 Bytes
                            currentItem[3] = data[c + 3];
                            currentItem[4] = data[c + 4];   // Always 0x01, but may be rare cases where it is higher number like Mt. Corel

                            // If a match is found, we can call a method to change the string
                            if (searchItem.SequenceEqual(currentItem))
                            {
                                // Convert item ID into a 2 byte endian value
                                ulong  convertItemID   = (ulong)newItemID;
                                byte[] convertedItemID = EndianMethods.GetLittleEndianConvert(convertItemID);

                                data[c]     = 0x58;
                                data[c + 1] = 0x00;
                                data[c + 2] = convertedItemID[0]; // Item ID 1st byte
                                data[c + 3] = convertedItemID[1]; // Item ID 2nd byte
                                data[c + 4] = 0xFE;               // Quantity
                                Trace.WriteLine("An item ID was rewritten");
                            }
                        }
                        usedTexts.Remove(textID);
                    }
                }
            }

            // Final Pass to revert items back to 01 quantity (or vary it)
            for (int f = 0; f < maxSearchRangeItem; f++)
            {
                finalItem[0] = data[f];       // Always 0x58
                finalItem[1] = data[f + 1];   // Always 0x00
                                              // Two bytes are skipped as they can vary (Item ID)
                finalItem[2] = data[f + 4];   // Always 0x01, but may be rare cases where it is higher number like Mt. Corel

                // If a match is found, we can call a method to change the string
                if (searchFinalItem.SequenceEqual(finalItem))
                {
                    data[f + 4] = 0x01; // Can change this if user specified it
                }
            }
            return(data);
        }