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); } }
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); //} }
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); }
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; } } // skip non-randomized items. if (randomizedResult.Settings.UseCustomItemList) { if (!randomizedResult.Settings.CustomItemList.Contains(ItemUtils.SubtractItemOffset(item.ID))) { continue; } } else { if (randomizedResult.Settings.ExcludeSongOfSoaring && item.Item == Item.SongSoaring) { continue; } if (!randomizedResult.Settings.AddDungeonItems && ItemUtils.IsDungeonItem(item.Item)) { continue; } if (!randomizedResult.Settings.AddShopItems && ItemUtils.IsShopItem(item.Item)) { continue; } if (!randomizedResult.Settings.AddOther && ItemUtils.IsOtherItem(item.Item)) { continue; } if (!randomizedResult.Settings.RandomizeBottleCatchContents && ItemUtils.IsBottleCatchContent(item.Item)) { continue; } if (!randomizedResult.Settings.AddMoonItems && ItemUtils.IsMoonLocation(item.Item)) { continue; } if (!randomizedResult.Settings.AddNutChest && item.Item == Item.ChestPreClocktownDekuNut) { continue; } if (!randomizedResult.Settings.CrazyStartingItems && ItemUtils.IsStartingLocation(item.Item)) { 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); }