/// <summary> /// Prints custom data to xml element /// </summary> /// <param name="data"></param> /// <param name="parent"></param> /// <param name="idx"></param> /// <param name="type"></param> /// <returns></returns> private bool AnnotateXML(gff3struct data, XElement parent, int idx, string type, bool isSection, ref XElement output) { //Document Settings var Doc = parent.Document; XElement Actors = Doc.Descendants("Settings").First()?.Element("Actors"); XElement Player = Doc.Descendants("Settings").First()?.Element("Player"); List <XAttribute> attributes = new List <XAttribute>(); //attributes.Add(new XAttribute("Idx", idx)); output.Add(new XAttribute("ref", $"{type}_{idx}")); //TEXT CGff3Locstring locstring = (CGff3Locstring)data.GetListObjectByName <CGff3String>("Text"); string Text = ""; if (locstring != null) { CGff3String englishText = locstring.Value.FirstOrDefault(x => x.Language == "6"); if (englishText != null) { Text = englishText.Value; } } attributes.Add(new XAttribute("Text", Text)); //SPEAKER string Speaker = data.GetCommonObjectByName("Speaker").Value.ToString(); if (Speaker == "__player__") { Speaker = "geralt"; } if (Speaker == "__owner__") { Speaker = "npc"; } //write speakers to settings if (Actors == null) { throw new Gff3Exception("No Actors in Database"); //should never go offbut keep it for testing } List <string> ActorList = Actors.Elements().Select(x => x.Value.ToString()).ToList(); //Add actors to actorlist if (!ActorList.Contains(Speaker)) { Actors.Add(new XElement("Actor", Speaker)); } if (Speaker == "geralt" && Player.Value != null) { Player.Value = Speaker; } attributes.Add(new XAttribute("Speaker", Speaker)); // Adding soundfile var string Sound = data.GetCommonObjectByName("Sound").Value.ToString(); attributes.Add(new XAttribute("Sound", Sound)); //OTHER var dsdata = AttributeData(data, ref attributes); //QUESTS //ADD output.Add(attributes.ToArray()); //add section data if (isSection) { //remove special charactersand to lower string sectionname = Text.Split(' ').First(); Regex rgx = new Regex("[^a-zA-Z0-9]"); sectionname = $"section_{rgx.Replace(sectionname, "").ToLower()}_{idx}"; //add to sections list AddToSectionsNoDuplicates(Doc, sectionname, $"{type}_{idx}"); output.Add(new XAttribute("section", sectionname)); } bool isQuestParent = !String.IsNullOrEmpty(dsdata.questfact); if (isQuestParent) { //add to quest list AddToSectionsNoDuplicates(Doc, $"script_setfact_{dsdata.questfact}", $"quest_{idx}"); //add quest xml tags var scriptelement = new XElement("SCRIPT", new XAttribute("function", "AddFact_S"), new XElement("parameter", new XAttribute("factName", $"{dsdata.questfact}"), new XAttribute("value", $"1"), new XAttribute("validFor", $"0") )); var questelement = new XElement("QUEST", new XAttribute("Name", dsdata.questfact), new XAttribute("section", $"script_setfact_{dsdata.questfact}"), new XAttribute("ref", $"quest_{idx}"), scriptelement ); // reshuffle nodes output.Add(questelement); parent.Add(output); output = output.Element("QUEST"); } else { parent.Add(output); } return(isQuestParent); }
/// <summary> /// Recursive writing dialogue tree. /// </summary> /// <param name="gff3"></param> /// <param name="idx"></param> /// <param name="type"></param> private void WriteTree(gff3struct gff3, XElement printparent, int idx, string type, bool isSection) { //HACK //FIXME loop detection string HACK_ref = $"{type}_{idx}"; if (!HACK_Allrefs.Contains(HACK_ref)) { HACK_Allrefs.Add(HACK_ref); } else { throw new Gff3Exception("Looping"); } XElement output = new XElement(type); if (type == "entry") { gff3struct entry = gff3.GetEntryByIndex(idx); //PRINT DATA bool isquest = AnnotateXML(entry, printparent, idx, type, isSection, ref output); //get replies // there can be more than one reply // if there is more than one reply, this marks a CHOICE // and we must label all replys as goto points CGff3ListObject <gff3struct> replies = entry.GetListObjectByName <gff3struct>("RepliesList"); if (replies.Value.Count == 0) { output.Add(new XAttribute("END", "true")); } else if (replies.Value.Count > 1) { output.Add(new XAttribute("CHOICE", "true")); } //handle circular references if (EntryChoices.Contains(idx)) { return; } if (replies.Value.Count > 1) { EntryChoices.Add(idx); } foreach (gff3struct reply in replies.Value) { int newidx = int.Parse(reply.GetCommonObjectByName("Index").Value.ToString()); //if there is a choice, flag the two replies bool ischildSection = replies.Value.Count > 1 || isquest; WriteTree(gff3, output, newidx, "reply", ischildSection); } } else if (type == "reply") { gff3struct reply = gff3.GetReplyByIndex(idx); //PRINT DATA var isquest = AnnotateXML(reply, printparent, idx, type, isSection, ref output); //get entries // there can never be more than two entries // because nps can't choose CGff3ListObject <gff3struct> entries = reply.GetListObjectByName <gff3struct>("EntriesList"); if (entries.Value.Count == 0) { output.Add(new XAttribute("END", "true")); } else if (entries.Value.Count == 1) { int newidx = int.Parse(entries.Value.First().GetCommonObjectByName("Index").Value.ToString()); WriteTree(gff3, output, newidx, "entry", isquest); } else { throw new Gff3Exception("More than one Entry in a Reply"); } } }