public void VisitNodeDialogue(NodeDialogue nd) { if (nd.Character == null) { _report.AddMessage(ProjectReportMessage.MessageSeverity.Error, "A dialogue node has no assigned character.", nd); } if (string.IsNullOrWhiteSpace(nd.Text)) { _report.AddMessage(ProjectReportMessage.MessageSeverity.Warning, "A dialogue node has no assigned text.", nd); } if (Regex.IsMatch(nd.Text, @"[^\x00-\x7F]")) { _report.AddMessage(ProjectReportMessage.MessageSeverity.Error, "A dialogue node contains non-ASCII characters.", nd); } if (nd.Text?.Length > 300) { _report.AddMessage(ProjectReportMessage.MessageSeverity.Warning, "A dialogue node has more than 300 characters of text.", nd); } if (nd.Text?.Split('\n').Length > 3) { _report.AddMessage(ProjectReportMessage.MessageSeverity.Warning, "A dialogue node has more than 3 lines of text.", nd); } }
public void InterpretScene(Scene scene, ProjectReport report) { _interpreters[0].Interpreter.Report = report; while (_interpreters.Count(i => i.Running) != 0) { var newStates = new List <InterpreterState>(); foreach (var interpreter in _interpreters) { if (!interpreter.Running) { continue; } if (scene.Nodes.Count == interpreter.Position) { interpreter.Running = false; continue; } var node = scene.Nodes[interpreter.Position++]; node.Accept(interpreter.Interpreter); if (node is NodeJump nj) { if (nj.Target == null) { continue; } var targetIndexJ = scene.Nodes.IndexOf(nj.Target); if (targetIndexJ == -1) { report.AddMessage(ProjectReportMessage.MessageSeverity.Info, "Detected jump outside of current scope, aborting analysis of this branch.", nj); interpreter.Running = false; } else if (targetIndexJ < interpreter.Position) { report.AddMessage(ProjectReportMessage.MessageSeverity.Info, "Detected jump backwards (potential loop), aborting analysis of this branch.", nj); interpreter.Running = false; } interpreter.Position = targetIndexJ; } else if (node is NodeVariableJump nvj) { if (nvj.Target == null) { continue; } bool interpreterState = interpreter.Interpreter.SetVariables.Contains(nvj.Variable); bool requiredState = nvj.Value; if (interpreterState != requiredState) { continue; } var targetIndexVJ = scene.Nodes.IndexOf(nvj.Target); if (targetIndexVJ == -1) { report.AddMessage(ProjectReportMessage.MessageSeverity.Info, "Detected jump outside of current scope, aborting analysis of this branch.", nvj); interpreter.Running = false; } else if (targetIndexVJ < interpreter.Position) { report.AddMessage(ProjectReportMessage.MessageSeverity.Info, "Detected jump backwards (potential loop), aborting analysis of this branch.", nvj); interpreter.Running = false; } interpreter.Position = targetIndexVJ; } else if (node is NodeCall nc) { var targetIndexC = scene.Nodes.IndexOf(nc.Target); if (targetIndexC != -1) { report.AddMessage(ProjectReportMessage.MessageSeverity.Info, "Local call detected, aborting analysis of this branch.", nc); } else { report.AddMessage(ProjectReportMessage.MessageSeverity.Info, "Intermodular call detected, aborting analysis of this branch.", nc); } } else if (node is NodeRet) { interpreter.Running = false; } else if (node is NodeResponseDialogue nrd) { var targetIndex = scene.Nodes.IndexOf(nrd.ResponseMap[0].Target); if (targetIndex == -1) { report.AddMessage(ProjectReportMessage.MessageSeverity.Info, "Detected jump outside of current scope, aborting analysis of this branch.", nrd); interpreter.Running = false; } interpreter.Position = targetIndex; foreach (var response in nrd.ResponseMap.Skip(1)) { var newState = new InterpreterState { Interpreter = (BranchingInterpreterVisitor)interpreter.Interpreter.Clone(), Position = scene.Nodes.IndexOf(response.Target), Running = true }; if (newState.Position == -1) { report.AddMessage(ProjectReportMessage.MessageSeverity.Info, "Detected jump outside of current scope, aborting analysis of this branch.", nrd); } else { newStates.Add(newState); } } } } _interpreters.AddRange(newStates); } }
public async Task Interpret() { while (Running) { if (_scene.Nodes.Count == Position) { Running = false; return; } var node = _scene.Nodes[Position++]; node.Accept(this); if (node is NodeCall nc) { if (nc.Target == null) { continue; } var module = await WaitForModule(nc.Target); var resultStates = module.States.FirstOrDefault(s => OutputState.Matches(s.Key)).Value; if (resultStates == null) { Report.AddMessage(ProjectReportMessage.MessageSeverity.Error, "No overload for this call takes current state.", nc); Running = false; return; } OutputState.Merge(resultStates.First()); foreach (var outputState in resultStates.Skip(1)) { var clone = Clone(); clone.OutputState.Merge(outputState); _parent.AddInterpreter(clone); } } } }