diff --git a/NewHorizons/Builder/Props/DialogueBuilder.cs b/NewHorizons/Builder/Props/DialogueBuilder.cs index 429626e5..93898e6d 100644 --- a/NewHorizons/Builder/Props/DialogueBuilder.cs +++ b/NewHorizons/Builder/Props/DialogueBuilder.cs @@ -8,6 +8,7 @@ using OWML.Common; using System.Collections.Generic; using System.IO; using System.Xml; +using System.Xml.Linq; using UnityEngine; namespace NewHorizons.Builder.Props @@ -118,6 +119,8 @@ namespace NewHorizons.Builder.Props } } + DoDialogueOptionsListReplacement(existingDialogueTree); + var newTextAsset = new TextAsset(existingDialogueDoc.OuterXml) { name = existingDialogue._xmlCharacterDialogueAsset.name @@ -132,6 +135,51 @@ namespace NewHorizons.Builder.Props return existingDialogue; } + private static string DoDialogueOptionsListReplacement(string xmlString) + { + var dialogueDoc = new XmlDocument(); + dialogueDoc.LoadXml(xmlString); + var xmlNode = dialogueDoc.SelectSingleNode("DialogueTree"); + DoDialogueOptionsListReplacement(xmlNode); + return xmlNode.OuterXml; + } + + private static void DoDialogueOptionsListReplacement(XmlNode dialogueTree) + { + var optionsListsByName = new Dictionary(); + var dialogueNodes = dialogueTree.GetChildNodes("DialogueNode"); + foreach (XmlNode dialogueNode in dialogueNodes) + { + var optionsList = dialogueNode.GetChildNode("DialogueOptionsList"); + if (optionsList != null) + { + var name = dialogueNode.GetChildNode("Name").InnerText; + optionsListsByName[name] = optionsList; + } + } + foreach (var (name, optionsList) in optionsListsByName) + { + var replacement = optionsList.GetChildNode("ReuseDialogueOptionsListFrom"); + if (replacement != null) + { + if (optionsListsByName.TryGetValue(replacement.InnerText, out var replacementOptionsList)) + { + if (replacementOptionsList.GetChildNode("ReuseDialogueOptionsListFrom") != null) + { + NHLogger.LogError($"Can not target a node with ReuseDialogueOptionsListFrom that also reuses options when making dialogue. Node {name} cannot reuse the list from {replacement.InnerText}"); + } + var dialogueNode = optionsList.ParentNode; + dialogueNode.RemoveChild(optionsList); + dialogueNode.AppendChild(replacementOptionsList.Clone()); + } + else + { + NHLogger.LogError($"Could not reuse dialogue options list from node with Name {replacement.InnerText} to node with Name {name}"); + } + } + } + } + private static RemoteDialogueTrigger MakeRemoteDialogueTrigger(GameObject planetGO, Sector sector, DialogueInfo info, CharacterDialogueTree dialogue) { var conversationTrigger = GeneralPropBuilder.MakeNew("ConversationTrigger", planetGO, sector, info.remoteTrigger, defaultPosition: info.position, defaultParentPath: info.pathToAnimController); @@ -187,6 +235,8 @@ namespace NewHorizons.Builder.Props var dialogueTree = conversationZone.AddComponent(); + xml = DoDialogueOptionsListReplacement(xml); + var text = new TextAsset(xml) { // Text assets need a name to be used with VoiceMod diff --git a/NewHorizons/Utility/NewHorizonExtensions.cs b/NewHorizons/Utility/NewHorizonExtensions.cs index c34182e1..7a2ba5b0 100644 --- a/NewHorizons/Utility/NewHorizonExtensions.cs +++ b/NewHorizons/Utility/NewHorizonExtensions.cs @@ -348,7 +348,7 @@ namespace NewHorizons.Utility public static XmlNode GetChildNode(this XmlNode parentNode, string tagName) { - return parentNode.ChildNodes.Cast().First(node => node.LocalName == tagName); + return parentNode.ChildNodes.Cast().FirstOrDefault(node => node.LocalName == tagName); } public static string TruncateWhitespaceAndToLower(this string text)