示例#1
0
        private static void InitGetBottleList()
        {
            RomData.BottleList = new Dictionary <int, BottleCatchEntry>();
            int f        = RomUtils.GetFileIndexForWriting(BOTTLE_CATCH_TABLE);
            int baseaddr = BOTTLE_CATCH_TABLE - RomData.MMFileList[f].Addr;
            var fileData = RomData.MMFileList[f].Data;

            foreach (var getBottleItemIndex in ItemUtils.AllGetBottleItemIndices())
            {
                int offset = getBottleItemIndex * 6 + baseaddr;
                RomData.BottleList[getBottleItemIndex] = new BottleCatchEntry
                {
                    ItemGained = fileData[offset + 3],
                    Index      = fileData[offset + 4],
                    Message    = fileData[offset + 5]
                };
            }
        }
示例#2
0
        private static void InitGetItemList()
        {
            RomData.GetItemList = new Dictionary <int, GetItemEntry>();
            int f        = RomUtils.GetFileIndexForWriting(GET_ITEM_TABLE);
            int baseaddr = GET_ITEM_TABLE - RomData.MMFileList[f].Addr;
            var fileData = RomData.MMFileList[f].Data;

            foreach (var getItemIndex in ItemUtils.AllGetItemIndices())
            {
                int offset = (getItemIndex - 1) * 8 + baseaddr;
                RomData.GetItemList[getItemIndex] = new GetItemEntry
                {
                    ItemGained = fileData[offset],
                    Flag       = fileData[offset + 1],
                    Index      = fileData[offset + 2],
                    Type       = fileData[offset + 3],
                    Message    = (short)((fileData[offset + 4] << 8) | fileData[offset + 5]),
                    Object     = (short)((fileData[offset + 6] << 8) | fileData[offset + 7])
                };
            }
        }
示例#3
0
        public static void WriteNewBottle(int location, int item)
        {
            System.Diagnostics.Debug.WriteLine($"Writing {Items.ITEM_NAMES[item]} --> {Items.ITEM_NAMES[location]}");

            location = ItemUtils.SubtractItemOffset(location);
            item     = ItemUtils.SubtractItemOffset(item);

            int f        = RomUtils.GetFileIndexForWriting(BOTTLE_CATCH_TABLE);
            int baseaddr = BOTTLE_CATCH_TABLE - RomData.MMFileList[f].Addr;
            var fileData = RomData.MMFileList[f].Data;

            for (int i = 0; i < RomData.BottleIndices[location].Length; i++)
            {
                int offset    = RomData.BottleIndices[location][i] * 6 + baseaddr;
                var newBottle = RomData.BottleList[item][0];
                var data      = new byte[]
                {
                    newBottle.ItemGained,
                    newBottle.Index,
                    newBottle.Message,
                };
                ReadWriteUtils.Arr_Insert(data, 0, data.Length, fileData, offset + 3);
            }
        }
示例#4
0
        public static List <MessageEntry> MakeGossipQuotes(RandomizedResult randomizedResult)
        {
            if (randomizedResult.Settings.GossipHintStyle == GossipHintStyle.Default)
            {
                return(new List <MessageEntry>());
            }

            var randomizedItems  = new List <ItemObject>();
            var competitiveHints = new List <string>();
            var itemsInRegions   = new Dictionary <string, List <ItemObject> >();

            foreach (var item in randomizedResult.ItemList)
            {
                if (item.NewLocation == null)
                {
                    continue;
                }

                if (randomizedResult.Settings.ClearHints)
                {
                    // skip free items
                    if (ItemUtils.IsStartingLocation(item.NewLocation.Value))
                    {
                        continue;
                    }
                }

                if (!item.IsRandomized)
                {
                    continue;
                }

                var itemName = item.Item.Name();
                if (randomizedResult.Settings.GossipHintStyle != GossipHintStyle.Competitive &&
                    (itemName.Contains("Heart") || itemName.Contains("Rupee")) &&
                    (randomizedResult.Settings.ClearHints || randomizedResult.Random.Next(8) != 0))
                {
                    continue;
                }

                if (randomizedResult.Settings.GossipHintStyle == GossipHintStyle.Competitive)
                {
                    var preventRegions = new List <string> {
                        "The Moon", "Bottle Catch", "Misc"
                    };
                    var itemRegion = item.NewLocation.Value.Region();
                    if (!string.IsNullOrWhiteSpace(itemRegion) && !preventRegions.Contains(itemRegion) && (randomizedResult.Settings.AddSongs || !ItemUtils.IsSong(item.Item)))
                    {
                        if (!itemsInRegions.ContainsKey(itemRegion))
                        {
                            itemsInRegions[itemRegion] = new List <ItemObject>();
                        }
                        itemsInRegions[itemRegion].Add(item);
                    }

                    if (!Gossip.GuaranteedLocationHints.Contains(item.NewLocation.Value))
                    {
                        continue;
                    }
                }

                randomizedItems.Add(item);
            }

            var unusedItems = randomizedItems.ToList();

            if (randomizedResult.Settings.GossipHintStyle == GossipHintStyle.Competitive)
            {
                unusedItems.AddRange(randomizedItems);
                var requiredHints    = new List <string>();
                var nonRequiredHints = new List <string>();
                foreach (var kvp in itemsInRegions)
                {
                    bool regionHasRequiredItem;
                    if (kvp.Value.Any(io => randomizedResult.ItemsRequiredForMoonAccess.Contains(io.Item)))
                    {
                        regionHasRequiredItem = true;
                    }
                    else if (!kvp.Value.Any(io => randomizedResult.AllItemsOnPathToMoon.Contains(io.Item)))
                    {
                        regionHasRequiredItem = false;
                    }
                    else
                    {
                        continue;
                    }

                    ushort soundEffectId = 0x690C; // grandma curious
                    string start         = Gossip.MessageStartSentences.Random(randomizedResult.Random);

                    string sfx             = $"{(char)((soundEffectId >> 8) & 0xFF)}{(char)(soundEffectId & 0xFF)}";
                    var    locationMessage = kvp.Key;
                    var    mid             = "is";
                    var    itemMessage     = regionHasRequiredItem
                        ? "on the Way of the Hero"
                        : "a foolish choice";
                    var list = regionHasRequiredItem
                        ? requiredHints
                        : nonRequiredHints;

                    list.Add($"\x1E{sfx}{start} \x01{locationMessage}\x00 {mid} \x06{itemMessage}\x00...\xBF".Wrap(35, "\x11"));
                }

                var numberOfRequiredHints    = 3;
                var numberOfNonRequiredHints = 2;

                for (var i = 0; i < numberOfRequiredHints; i++)
                {
                    var chosen = requiredHints.RandomOrDefault(randomizedResult.Random);
                    if (chosen != null)
                    {
                        requiredHints.Remove(chosen);
                        competitiveHints.Add(chosen);
                        competitiveHints.Add(chosen);
                    }
                }

                for (var i = 0; i < numberOfNonRequiredHints; i++)
                {
                    var chosen = nonRequiredHints.RandomOrDefault(randomizedResult.Random);
                    if (chosen != null)
                    {
                        nonRequiredHints.Remove(chosen);
                        competitiveHints.Add(chosen);
                        competitiveHints.Add(chosen);
                    }
                }
            }

            List <MessageEntry> finalHints = new List <MessageEntry>();

            foreach (var gossipQuote in Enum.GetValues(typeof(GossipQuote)).Cast <GossipQuote>().OrderBy(gq => randomizedResult.Random.Next()))
            {
                var        isMoonGossipStone     = gossipQuote.ToString().StartsWith("Moon");
                var        restrictionAttributes = gossipQuote.GetAttributes <GossipRestrictAttribute>().ToList();
                ItemObject item       = null;
                var        forceClear = false;
                while (item == null)
                {
                    if (restrictionAttributes.Any() && (isMoonGossipStone || randomizedResult.Settings.GossipHintStyle == GossipHintStyle.Relevant))
                    {
                        var chosen        = restrictionAttributes.Random(randomizedResult.Random);
                        var candidateItem = chosen.Type == GossipRestrictAttribute.RestrictionType.Item
                            ? randomizedResult.ItemList.Single(io => io.Item == chosen.Item)
                            : randomizedResult.ItemList.Single(io => io.NewLocation == chosen.Item);
                        if (isMoonGossipStone || unusedItems.Contains(candidateItem))
                        {
                            item       = candidateItem;
                            forceClear = chosen.ForceClear;
                        }
                        else
                        {
                            restrictionAttributes.Remove(chosen);
                        }
                    }
                    else if (unusedItems.Any())
                    {
                        item = unusedItems.Random(randomizedResult.Random);
                    }
                    else
                    {
                        break;
                    }
                }

                if (!isMoonGossipStone)
                {
                    unusedItems.Remove(item);
                }

                string messageText = null;
                if (item != null)
                {
                    ushort soundEffectId = 0x690C; // grandma curious
                    string itemName      = null;
                    string locationName  = null;
                    if (forceClear || randomizedResult.Settings.ClearHints)
                    {
                        itemName     = item.Item.Name();
                        locationName = item.NewLocation.Value.Location();
                    }
                    else
                    {
                        if (isMoonGossipStone || randomizedResult.Settings.GossipHintStyle == GossipHintStyle.Competitive || randomizedResult.Random.Next(100) >= 5) // 5% chance of fake/junk hint if it's not a moon gossip stone or competitive style
                        {
                            itemName     = item.Item.ItemHints().Random(randomizedResult.Random);
                            locationName = item.NewLocation.Value.LocationHints().Random(randomizedResult.Random);
                        }
                        else
                        {
                            if (randomizedResult.Random.Next(2) == 0) // 50% chance for fake hint. otherwise default to junk hint.
                            {
                                soundEffectId = 0x690A;               // grandma laugh
                                itemName      = item.Item.ItemHints().Random(randomizedResult.Random);
                                locationName  = randomizedItems.Random(randomizedResult.Random).Item.LocationHints().Random(randomizedResult.Random);
                            }
                        }
                    }
                    if (itemName != null && locationName != null)
                    {
                        messageText = BuildGossipQuote(soundEffectId, locationName, itemName, randomizedResult.Random);
                    }
                }
                if (messageText == null)
                {
                    if (competitiveHints.Any())
                    {
                        messageText = competitiveHints.Random(randomizedResult.Random);
                        competitiveHints.Remove(messageText);
                    }
                    else
                    {
                        messageText = Gossip.JunkMessages.Random(randomizedResult.Random);
                    }
                }

                finalHints.Add(new MessageEntry()
                {
                    Id      = (ushort)gossipQuote,
                    Message = messageText,
                    Header  = MessageHeader.ToArray()
                });
            }

            return(finalHints);
        }
示例#5
0
        public static void CreateSpoilerLog(RandomizedResult randomized, SettingsObject settings)
        {
            var itemList = randomized.ItemList
                           .Where(io => !io.Item.IsFake())
                           .Select(u => new SpoilerItem(u, ItemUtils.IsRequired(u.Item, randomized), ItemUtils.IsImportant(u.Item, randomized)));
            var settingsString = settings.ToString();

            var directory = Path.GetDirectoryName(settings.OutputROMFilename);
            var filename  = $"{Path.GetFileNameWithoutExtension(settings.OutputROMFilename)}";

            var     plainTextRegex = new Regex("[^a-zA-Z0-9' .\\-]+");
            Spoiler spoiler        = new Spoiler()
            {
                Version                      = MainForm.AssemblyVersion.Substring(26),
                SettingsString               = settingsString,
                Seed                         = settings.Seed,
                RandomizeDungeonEntrances    = settings.RandomizeDungeonEntrances,
                ItemList                     = itemList.Where(u => !u.Item.IsFake()).ToList(),
                NewDestinationIndices        = randomized.NewDestinationIndices,
                Logic                        = randomized.Logic,
                CustomItemListString         = settings.UseCustomItemList ? settings.CustomItemListString : null,
                CustomStartingItemListString = settings.CustomStartingItemList.Any() ? settings.CustomStartingItemListString : null,
                CustomJunkLocationsString    = settings.CustomJunkLocationsString,
                GossipHints                  = randomized.GossipQuotes?.ToDictionary(me => (GossipQuote)me.Id, (me) =>
                {
                    var message     = me.Message.Substring(1);
                    var soundEffect = message.Substring(0, 2);
                    message         = message.Substring(2);
                    if (soundEffect == "\x69\x0C")
                    {
                        // real
                    }
                    else if (soundEffect == "\x69\x0A")
                    {
                        // fake
                        message = "FAKE - " + message;
                    }
                    else
                    {
                        // junk
                        message = "JUNK - " + message;
                    }
                    return(plainTextRegex.Replace(message.Replace("\x11", " "), ""));
                }),
            };

            if (settings.GenerateHTMLLog)
            {
                filename += "_SpoilerLog.html";
                using (StreamWriter newlog = new StreamWriter(Path.Combine(directory, filename)))
                {
                    Templates.HtmlSpoiler htmlspoiler = new Templates.HtmlSpoiler(spoiler);
                    newlog.Write(htmlspoiler.TransformText());
                }
            }
            else
            {
                filename += "_SpoilerLog.txt";
                CreateTextSpoilerLog(spoiler, Path.Combine(directory, filename));
            }
        }
示例#6
0
        public static void WriteNewItem(int location, int item)
        {
            System.Diagnostics.Debug.WriteLine($"Writing {Items.ITEM_NAMES[item]} --> {Items.ITEM_NAMES[location]}");

            bool isRepeatable      = Items.REPEATABLE.Contains(item);
            bool isCycleRepeatable = Items.CYCLE_REPEATABLE.Contains(item);

            location = ItemUtils.SubtractItemOffset(location);
            item     = ItemUtils.SubtractItemOffset(item);

            int f            = RomUtils.GetFileIndexForWriting(GET_ITEM_TABLE);
            int baseaddr     = GET_ITEM_TABLE - RomData.MMFileList[f].Addr;
            var getItemIndex = RomData.GetItemIndices[location];

            if (location == Items.ItemGoldDust)
            {
                getItemIndex = 0x6A; // Place items intended for Gold Dust at the Goron Race Bottle location.
            }
            int offset   = (getItemIndex - 1) * 8 + baseaddr;
            var newItem  = RomData.GetItemList[item];
            var fileData = RomData.MMFileList[f].Data;

            var data = new byte[]
            {
                newItem.ItemGained,
                newItem.Flag,
                newItem.Index,
                newItem.Type,
                (byte)(newItem.Message >> 8),
                (byte)(newItem.Message & 0xFF),
                (byte)(newItem.Object >> 8),
                (byte)(newItem.Object & 0xFF),
            };

            ReadWriteUtils.Arr_Insert(data, 0, data.Length, fileData, offset);

            if (isCycleRepeatable)
            {
                ReadWriteUtils.WriteToROM(cycle_repeat, (ushort)getItemIndex);
                cycle_repeat += 2;
            }

            if (!isRepeatable)
            {
                SceneUtils.UpdateSceneFlagMask(getItemIndex);
            }

            if (item == Items.ItemBottleWitch)
            {
                ReadWriteUtils.WriteToROM(0xB49982, (ushort)getItemIndex);
                ReadWriteUtils.WriteToROM(0xC72B42, (ushort)getItemIndex);
            }

            if (item == Items.ItemBottleMadameAroma)
            {
                ReadWriteUtils.WriteToROM(0xB4999A, (ushort)getItemIndex);
                ReadWriteUtils.WriteToROM(0xC72B4E, (ushort)getItemIndex);
            }

            if (item == Items.ItemBottleAliens)
            {
                ReadWriteUtils.WriteToROM(0xB499A6, (ushort)getItemIndex);
                ReadWriteUtils.WriteToROM(0xC72B5A, (ushort)getItemIndex);
            }
            // Goron Race Bottle now rewards a plain Gold Dust, so this is unnecessary until a proper fix for Goron Dust is found.
            //if (NewItem == Items.ItemBottleGoronRace)
            //{
            //    WriteToROM(0xB499B2, (ushort)getItemIndex);
            //    WriteToROM(0xC72B66, (ushort)getItemIndex);
            //}
        }
示例#7
0
        public static List <MessageEntry> MakeGossipQuotes(SettingsObject settings, List <ItemObject> items, Random random)
        {
            if (!settings.EnableGossipHints)
            {
                return(new List <MessageEntry>());
            }

            var hints      = new List <string>();
            var GossipList = settings.ClearHints
                ? items
                             .Where(io => !ItemUtils.IsFakeItem(io.ID))
                             .Select(io => new Gossip
            {
                SourceMessage      = new string[] { Items.LOCATION_NAMES[io.ID] },
                DestinationMessage = new string[] { Items.ITEM_NAMES[io.ID] },
            }).ToList()
                : GetGossipList();

            foreach (var item in items)
            {
                if (!item.ReplacesAnotherItem)
                {
                    continue;
                }

                // Skip hints for vanilla bottle content
                if ((!settings.RandomizeBottleCatchContents) &&
                    ItemUtils.IsBottleCatchContent(item.ID))
                {
                    continue;
                }

                // Skip hints for vanilla shop items
                if ((!settings.AddShopItems) &&
                    ItemUtils.IsShopItem(item.ID))
                {
                    continue;
                }

                // Skip hints for vanilla dungeon items
                if (!settings.AddDungeonItems &&
                    ItemUtils.IsDungeonItem(item.ID))
                {
                    continue;
                }

                int sourceItemId = ItemUtils.SubtractItemOffset(item.ReplacesItemId);
                int toItemId     = ItemUtils.SubtractItemOffset(item.ID);

                ushort soundEffectId = 0x690C;
                if (!settings.ClearHints)
                {
                    // 5% chance of being fake
                    bool isFake = random.Next(100) < 5;
                    if (isFake)
                    {
                        sourceItemId  = random.Next(GossipList.Count);
                        soundEffectId = 0x690A;
                    }
                }

                if (IsBadMessage(GossipList[toItemId].DestinationMessage[0]) && (settings.ClearHints || random.Next(8) != 0))
                {
                    continue;
                }

                int sourceMessageLength = GossipList[sourceItemId]
                                          .SourceMessage
                                          .Length;

                int destinationMessageLength = GossipList[toItemId]
                                               .DestinationMessage
                                               .Length;

                // Randomize messages
                string sourceMessage = GossipList[sourceItemId]
                                       .SourceMessage[random.Next(sourceMessageLength)];

                string destinationMessage = GossipList[toItemId]
                                            .DestinationMessage[random.Next(destinationMessageLength)];

                var quote = BuildGossipQuote(soundEffectId, sourceMessage, destinationMessage, random);

                hints.Add(quote);
            }

            if (!settings.ClearHints)
            {
                for (int i = 0; i < Gossip.JunkMessages.Count; i++)
                {
                    hints.Add(Gossip.JunkMessages[i]);
                }
            }

            //trim the pool of messages
            List <MessageEntry> finalHints = new List <MessageEntry>();

            for (ushort textId = GOSSIP_START_ID; textId < GOSSIP_END_ID; textId++)
            {
                if (GossipExclude.Contains(textId))
                {
                    continue;
                }

                int    selectedIndex = random.Next(hints.Count);
                string selectedHint  = hints[selectedIndex];

                MessageEntry message = new MessageEntry()
                {
                    Id      = textId,
                    Message = selectedHint,
                    Header  = MessageHeader.ToArray()
                };


                finalHints.Add(message);
                hints.RemoveAt(selectedIndex);
            }
            return(finalHints);
        }
示例#8
0
        public static List <MessageEntry> MakeGossipQuotes(RandomizedResult randomizedResult)
        {
            if (randomizedResult.Settings.GossipHintStyle == GossipHintStyle.Default)
            {
                return(new List <MessageEntry>());
            }

            var randomizedItems  = new List <ItemObject>();
            var competitiveHints = new List <string>();
            var itemsInRegions   = new Dictionary <Region, List <ItemObject> >();

            foreach (var item in randomizedResult.ItemList)
            {
                if (item.NewLocation == null)
                {
                    continue;
                }

                if (randomizedResult.Settings.ClearHints)
                {
                    // skip free items
                    if (ItemUtils.IsStartingLocation(item.NewLocation.Value))
                    {
                        continue;
                    }
                }

                if (!item.IsRandomized)
                {
                    continue;
                }

                var itemName = item.Item.Name();
                if (randomizedResult.Settings.GossipHintStyle != GossipHintStyle.Competitive &&
                    (itemName.Contains("Heart") || itemName.Contains("Rupee")) &&
                    (randomizedResult.Settings.ClearHints || randomizedResult.Random.Next(8) != 0))
                {
                    continue;
                }

                if (randomizedResult.Settings.GossipHintStyle == GossipHintStyle.Competitive)
                {
                    var preventRegions = new List <Region> {
                        Region.TheMoon, Region.BottleCatch, Region.Misc
                    };
                    var itemRegion = item.NewLocation.Value.Region();
                    if (itemRegion.HasValue &&
                        !preventRegions.Contains(itemRegion.Value) &&
                        !randomizedResult.Settings.CustomJunkLocations.Contains(item.NewLocation.Value))
                    {
                        if (!itemsInRegions.ContainsKey(itemRegion.Value))
                        {
                            itemsInRegions[itemRegion.Value] = new List <ItemObject>();
                        }
                        itemsInRegions[itemRegion.Value].Add(item);
                    }

                    var competitiveHintInfo = item.NewLocation.Value.GetAttribute <GossipCompetitiveHintAttribute>();
                    if (competitiveHintInfo == null)
                    {
                        continue;
                    }

                    if (randomizedResult.Settings.CustomJunkLocations.Contains(item.NewLocation.Value))
                    {
                        continue;
                    }

                    if (competitiveHintInfo.Condition != null && competitiveHintInfo.Condition(randomizedResult.Settings))
                    {
                        continue;
                    }
                }

                randomizedItems.Add(item);
            }

            var unusedItems = randomizedItems.ToList();

            if (randomizedResult.Settings.GossipHintStyle == GossipHintStyle.Competitive)
            {
                unusedItems.AddRange(randomizedItems);
                var requiredHints    = new List <string>();
                var nonRequiredHints = new List <string>();
                foreach (var kvp in itemsInRegions)
                {
                    var numberOfRequiredItems  = kvp.Value.Count(io => ItemUtils.IsRequired(io.Item, randomizedResult));
                    var numberOfImportantItems = kvp.Value.Count(io => ItemUtils.IsImportant(io.Item, randomizedResult));

                    if (numberOfRequiredItems == 0 && numberOfImportantItems > 0)
                    {
                        continue;
                    }

                    ushort soundEffectId = 0x690C; // grandma curious
                    string start         = Gossip.MessageStartSentences.Random(randomizedResult.Random);

                    string sfx             = $"{(char)((soundEffectId >> 8) & 0xFF)}{(char)(soundEffectId & 0xFF)}";
                    var    locationMessage = kvp.Key.Name();
                    //var mid = "is";
                    //var itemMessage = numberOfRequiredItems > 0
                    //    ? "on the Way of the Hero"
                    //    : "a foolish choice";
                    List <string> list;
                    char          color;
                    if (numberOfRequiredItems > 0)
                    {
                        list  = requiredHints;
                        color = TextCommands.ColorYellow;
                    }
                    else
                    {
                        list  = nonRequiredHints;
                        color = TextCommands.ColorSilver;
                    }

                    //list.Add($"\x1E{sfx}{start} \x01{locationMessage}\x00 {mid} \x06{itemMessage}\x00...\xBF".Wrap(35, "\x11"));

                    var mid = "has";
                    list.Add($"\x1E{sfx}{start} {TextCommands.ColorRed}{locationMessage}{TextCommands.ColorWhite} {mid} {color}{NumberToWords(numberOfImportantItems)} important item{(numberOfImportantItems == 1 ? "" : "s")}{TextCommands.ColorWhite}...\xBF".Wrap(35, "\x11"));
                }

                var numberOfRequiredHints    = 2;
                var numberOfNonRequiredHints = 3;

                for (var i = 0; i < numberOfRequiredHints; i++)
                {
                    var chosen = requiredHints.RandomOrDefault(randomizedResult.Random);
                    if (chosen != null)
                    {
                        requiredHints.Remove(chosen);
                        competitiveHints.Add(chosen);
                        competitiveHints.Add(chosen);
                    }
                }

                for (var i = 0; i < numberOfNonRequiredHints; i++)
                {
                    var chosen = nonRequiredHints.RandomOrDefault(randomizedResult.Random);
                    if (chosen != null)
                    {
                        nonRequiredHints.Remove(chosen);
                        competitiveHints.Add(chosen);
                        competitiveHints.Add(chosen);
                    }
                }
            }

            List <MessageEntry> finalHints = new List <MessageEntry>();

            foreach (var gossipQuote in Enum.GetValues(typeof(GossipQuote)).Cast <GossipQuote>().OrderBy(gq => randomizedResult.Random.Next()))
            {
                string messageText       = null;
                var    isMoonGossipStone = gossipQuote.ToString().StartsWith("Moon");
                if (!isMoonGossipStone && competitiveHints.Any())
                {
                    messageText = competitiveHints.Random(randomizedResult.Random);
                    competitiveHints.Remove(messageText);
                }

                if (messageText == null)
                {
                    var        restrictionAttributes = gossipQuote.GetAttributes <GossipRestrictAttribute>().ToList();
                    ItemObject item       = null;
                    var        forceClear = false;
                    while (item == null)
                    {
                        if (restrictionAttributes.Any() && (isMoonGossipStone || randomizedResult.Settings.GossipHintStyle == GossipHintStyle.Relevant))
                        {
                            var chosen        = restrictionAttributes.Random(randomizedResult.Random);
                            var candidateItem = chosen.Type == GossipRestrictAttribute.RestrictionType.Item
                                ? randomizedResult.ItemList.Single(io => io.Item == chosen.Item)
                                : randomizedResult.ItemList.Single(io => io.NewLocation == chosen.Item);
                            if (isMoonGossipStone || unusedItems.Contains(candidateItem))
                            {
                                item       = candidateItem;
                                forceClear = chosen.ForceClear;
                            }
                            else
                            {
                                restrictionAttributes.Remove(chosen);
                            }
                        }
                        else if (unusedItems.Any())
                        {
                            if (randomizedResult.Settings.GossipHintStyle == GossipHintStyle.Competitive)
                            {
                                item = unusedItems.FirstOrDefault(io => unusedItems.Count(x => x.Item == io.Item) == 1);
                                if (item == null)
                                {
                                    item = unusedItems.GroupBy(io => io.NewLocation.Value.GetAttribute <GossipCompetitiveHintAttribute>().Priority)
                                           .OrderByDescending(g => g.Key)
                                           .First()
                                           .ToList()
                                           .Random(randomizedResult.Random);
                                }
                            }
                            else
                            {
                                item = unusedItems.Random(randomizedResult.Random);
                            }
                        }
                        else
                        {
                            break;
                        }
                    }

                    if (!isMoonGossipStone)
                    {
                        unusedItems.Remove(item);
                    }

                    if (item != null)
                    {
                        ushort soundEffectId = 0x690C; // grandma curious
                        string itemName      = null;
                        string locationName  = null;
                        if (forceClear || randomizedResult.Settings.ClearHints)
                        {
                            itemName     = item.Item.Name();
                            locationName = item.NewLocation.Value.Location();
                        }
                        else
                        {
                            if (isMoonGossipStone || randomizedResult.Settings.GossipHintStyle == GossipHintStyle.Competitive || randomizedResult.Random.Next(100) >= 5) // 5% chance of fake/junk hint if it's not a moon gossip stone or competitive style
                            {
                                itemName     = item.Item.ItemHints().Random(randomizedResult.Random);
                                locationName = item.NewLocation.Value.LocationHints().Random(randomizedResult.Random);
                            }
                            else
                            {
                                if (randomizedResult.Random.Next(2) == 0) // 50% chance for fake hint. otherwise default to junk hint.
                                {
                                    soundEffectId = 0x690A;               // grandma laugh
                                    itemName      = item.Item.ItemHints().Random(randomizedResult.Random);
                                    locationName  = randomizedItems.Random(randomizedResult.Random).Item.LocationHints().Random(randomizedResult.Random);
                                }
                            }
                        }
                        if (itemName != null && locationName != null)
                        {
                            messageText = BuildGossipQuote(soundEffectId, locationName, itemName, randomizedResult.Random);
                        }
                    }
                }

                if (messageText == null)
                {
                    messageText = Gossip.JunkMessages.Random(randomizedResult.Random);
                }

                finalHints.Add(new MessageEntry()
                {
                    Id      = (ushort)gossipQuote,
                    Message = messageText,
                    Header  = MessageHeader.ToArray()
                });
            }

            return(finalHints);
        }