/// <summary> /// Loads and parses quest markup data to QuestDocument. /// No additional logical structure checks, use "validate" method for it. /// </summary> /// <param name="markup">Markup source of quest data.</param> public static QuestDocument LoadMarkup(string markup) { if (string.IsNullOrEmpty(markup)) { throw new Exception("Invalid markup data"); } var stream = new QuestStream(markup); var doc = new QuestDocument(); while (!stream.Eof()) { var lineId = stream.pointer; string name; var page = ParsePage(stream, out name); if (doc.pages.ContainsKey(name)) { throw new Exception( string.Format("Error at {0} line : page with name \"{1}\" already declared before", lineId, name)); } doc.pages[name] = page; if (string.IsNullOrEmpty(doc.entry)) { doc.entry = name; } } doc.ResetProgress(); return(doc); }
static void ParsePageLogics(QuestPage page, QuestStream stream) { while (true) { var line = stream.Next(); if (line.Length == 0) { break; } if (line[0] != '{') { stream.Previous(); break; } var matching = Regex.Match(line, "\\{(.+?)\\}"); if (!matching.Success || string.IsNullOrEmpty(matching.Groups[1].Value)) { throw new Exception(string.Format("Invalid logic at line: {0}", stream.pointer)); } var cond = ParseLogic(QuestLogicFilter.State, matching.Groups[1].Value, stream.pointer); if (cond != null) { if (page.logics == null) { page.logics = new List <QuestLogic> (); } page.logics.Add(cond); } } }
static void ParsePageTexts(QuestPage page, QuestStream stream) { _pageTextsBuffer.Length = 0; while (true) { var line = stream.Next(); if (line.Length == 0) { break; } if (line[0] == '*' || line[0] == '-') { stream.Previous(); break; } if (_pageTextsBuffer.Length > 0) { _pageTextsBuffer.Append(" "); } _pageTextsBuffer.Append(line); } if (_pageTextsBuffer.Length == 0) { throw new Exception(string.Format("Invalid page texts at line: {0}", stream.pointer)); } page.texts.AddRange(Regex.Split(_pageTextsBuffer.ToString(), "\\s?\\[br\\]\\s?")); }
static void ParsePageChoices(QuestPage page, QuestStream stream) { var lineId = stream.pointer; while (true) { var line = stream.Next(); if (line.Length == 0) { break; } if (line[0] != '*') { stream.Previous(); break; } var matching = Regex.Match(line, "\\*(.*?)->\\s*?(\\b.+)"); if (!matching.Success) { throw new Exception(string.Format("Invalid choice syntax at line: {0}", lineId)); } lineId = stream.pointer; var choice = new QuestChoice(); choice.link = matching.Groups[2].Value.ToLowerInvariant(); var rawChoiceText = matching.Groups[1].Value; if (!string.IsNullOrEmpty(rawChoiceText)) { var matchingCond = Regex.Match(rawChoiceText, "\\{(.*?)\\}(.+)"); if (!matchingCond.Success) { choice.text = rawChoiceText.Trim(); } else { choice.condition = ParseLogic(QuestLogicFilter.Expression, matchingCond.Groups[1].Value, lineId); choice.text = matchingCond.Groups[2].Value.Trim(); } } page.choices.Add(choice); } if (page.choices.Count == 0) { throw new Exception(string.Format("No choices at line: {0}", lineId)); } if (page.choices.Count == 1 && page.choices[0].condition != null) { throw new Exception(string.Format("Auto choice cant use condition at line: {0}", lineId)); } }
static QuestPage ParsePage(QuestStream stream, out string pageName) { var line = stream.Next(); var matching = Regex.Match(line, "->\\s*?(\\b.+)"); if (!matching.Success) { throw new Exception(string.Format("Invalid page header at line: {0}", stream.pointer)); } var name = matching.Groups[1].Value.ToLowerInvariant(); if (name == "end") { throw new Exception(string.Format("Invalid page name at line: {0}", stream.pointer)); } var page = new QuestPage(); ParsePageLogics(page, stream); ParsePageTexts(page, stream); ParsePageChoices(page, stream); pageName = name; return(page); }