Пример #1
0
        public async Task <ItemStrings> GetStringListsOfItemDictionary(SortedDictionary <string, object> dictionary)
        {
            ItemStrings itemStringLists = new ItemStrings();

            foreach (var item in dictionary)
            {
                string itemKey = item.Key;
                if (itemKey == "name" || itemKey == "created" || itemKey == "edited" || itemKey == "url" || itemKey == "title" || itemKey == "vehicle_class")
                {
                    continue;
                }
                itemKey = char.ToUpper(itemKey[0]) + itemKey.Substring(1).Replace("_", " ");
                itemStringLists.PropertyNames.Add(itemKey);

                if (item.Value == null)
                {
                    itemStringLists.PropertyValues.Add("unknown");
                }
                else if (item.Value.GetType() == typeof(List <string>))
                {
                    List <string> stringList = new List <string>();

                    foreach (var listItem in (List <string>)item.Value)
                    {
                        string category = listItem.Substring(21).TrimEnd('/', '1', '2', '3', '4', '5', '6', '7', '8', '9');
                        category = char.ToUpper(category[0]) + category.Substring(1);
                        switch (category)
                        {
                        case ("Planets"):
                            Planet planetResult = await GetSingleByUrl <Planet>(listItem);

                            stringList.Add(planetResult.name);
                            break;

                        case ("People"):
                            People peopleResult = await GetSingleByUrl <People>(listItem);

                            stringList.Add(peopleResult.name);
                            break;

                        case ("Films"):
                            Film filmResult = await GetSingleByUrl <Film>(listItem);

                            await Task.Delay(100);

                            stringList.Add(filmResult.title);
                            break;

                        case ("Species"):
                            Specie speciesResult = await GetSingleByUrl <Specie>(listItem);

                            stringList.Add(speciesResult.name);
                            break;

                        case ("Starships"):
                            Starship starshipResult = await GetSingleByUrl <Starship>(listItem);

                            stringList.Add(starshipResult.name);
                            break;

                        case ("Vehicles"):
                            Vehicle vehicleResult = await GetSingleByUrl <Vehicle>(listItem);

                            stringList.Add(vehicleResult.name);
                            break;
                        }
                    }
                    string listToString = string.Join(", ", stringList);

                    if (stringList.Count == 0)
                    {
                        listToString = "unknown";
                    }

                    itemStringLists.PropertyValues.Add(listToString);
                }
                else if (item.Value.ToString().StartsWith("https://swapi.co/api/"))
                {
                    string category = item.Value.ToString().Substring(21).TrimEnd('/', '1', '2', '3', '4', '5', '6', '7', '8', '9');
                    category = char.ToUpper(category[0]) + category.Substring(1);
                    switch (category)
                    {
                    case ("Planets"):
                        Planet planetResult = await GetSingleByUrl <Planet>(item.Value.ToString());

                        itemStringLists.PropertyValues.Add(planetResult.name);
                        break;

                    case ("People"):
                        People peopleResult = await GetSingleByUrl <People>(item.Value.ToString());

                        itemStringLists.PropertyValues.Add(peopleResult.name);
                        break;

                    case ("Films"):
                        Film filmResult = await GetSingleByUrl <Film>(item.Value.ToString());

                        itemStringLists.PropertyValues.Add(filmResult.title);
                        break;

                    case ("Species"):
                        Specie speciesResult = await GetSingleByUrl <Specie>(item.Value.ToString());

                        itemStringLists.PropertyValues.Add(speciesResult.name);
                        break;

                    case ("Starships"):
                        Starship starshipResult = await GetSingleByUrl <Starship>(item.Value.ToString());

                        itemStringLists.PropertyValues.Add(starshipResult.name);
                        break;

                    case ("Vehicles"):
                        Vehicle vehicleResult = await GetSingleByUrl <Vehicle>(item.Value.ToString());

                        itemStringLists.PropertyValues.Add(vehicleResult.name);
                        break;
                    }
                }
                else
                {
                    itemStringLists.PropertyValues.Add(item.Value.ToString());
                }
            }

            return(itemStringLists);
        }
Пример #2
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);
        }