public override IEnumerable <ConversationError <T> > Check(IEnumerable <T> nodes, IErrorCheckerUtilities <T> utils) { var filteredNodes = nodes.Where(n => !Clandestine.Util.IsAIBark(n.Data.NodeTypeId, utils) && n.Data.NodeTypeId != SpecialNodes.Random); foreach (var n in filteredNodes) { var outputs = n.Data.Connectors.Where(c => c.Definition.Id == SpecialConnectors.Output.Id); foreach (var transitionOut in outputs) { var connectedNodes = transitionOut.Connections.Select(c => c.Parent).Evaluate(); bool hasOption = connectedNodes.Any(a => a.NodeTypeId == SpecialNodes.Option); int countNonOption = connectedNodes.Count(a => a.NodeTypeId != SpecialNodes.Option); if (countNonOption + (hasOption ? 1 : 0) > 1) { yield return(new NonOptionSiblingsError(n)); } } } }
internal IEnumerable <ConversationError <ConversationNode> > CheckForErrors(IEnumerable <ConversationNode> nodes, IErrorCheckerUtilities <ConversationNode> utils) { m_config.RefreshConfig(m_pluginsConfig); foreach (var assembly in m_config.Assemblies) { foreach (var checker in assembly.GetEnabledErrorCheckers()) { foreach (var error in checker.Check(nodes, utils)) { yield return(error); } } } }
public override IEnumerable <ConversationError <T> > Check(IEnumerable <T> nodes, IErrorCheckerUtilities <T> utils) { var targetnodes = nodes.Where(a => a.Data.NodeTypeId == SpecialNodes.JumpTarget); var jumpnodes = nodes.Where(a => a.Data.NodeTypeId == SpecialNodes.JumpTo); //Find all the jump targets with duplicate ids foreach (var d in targetnodes.GroupBy(GetId, a => a).Where(g => g.Count() > 1)) { yield return(new DuplicatedTargetError(d, d.Key)); } //Find all the jump targets with nothing jumping to them foreach (var node in targetnodes.Where(n => !jumpnodes.Any(nn => GetTarget(nn) == GetId(n)))) { yield return(new PointlessTargetError(node)); } //Find all the jumps to missing targets foreach (var node in jumpnodes.Where(n => !targetnodes.Any(nn => GetId(nn) == GetTarget(n)))) { yield return(new DeadEndJumpError(node)); } }
public void WriteConversation(IConversationFile conversation, StreamWriter sw, bool includeName, IErrorCheckerUtilities <IConversationNode> util) { if (conversation == null) { throw new ArgumentNullException(nameof(conversation)); } var nodes = conversation.Nodes; Stack <IConversationNodeData> startNodes = new Stack <IConversationNodeData>(nodes.Where(n => Viking.Util.IsStartNode(n.Data.NodeTypeId, util)).Select(n => n.Data)); var conversationInfo = conversation.Nodes.Where(n => n.Data.NodeTypeId == CsvData.CONVERSATIONINFO).FirstOrDefault(); var playerSpeechNodes = conversation.Nodes.Where(n => n.Data.NodeTypeId == CsvData.PLAYER_SPEECH).Select(n => new { Key = n, Value = CsvData.GetPlayerSpeechData(n, conversationInfo, m_localize) }); var npcSpeechNodes = conversation.Nodes.Where(n => n.Data.NodeTypeId == CsvData.NPC_SPEECH).Select(n => new { Key = n, Value = CsvData.GetSpeechData(n, conversationInfo, m_localize) }); var radioSpeechNodes = conversation.Nodes.Where(n => n.Data.NodeTypeId == CsvData.RADIO_SPEECH).Select(n => new { Key = n, Value = CsvData.GetSpeechData(n, conversationInfo, m_localize) }); var optionNodes = conversation.Nodes.Where(n => n.Data.NodeTypeId == CsvData.OPTION).Select(n => new { Key = n, Value = CsvData.GetOptionData(n, conversationInfo, m_localize) }); var allcontent = playerSpeechNodes.Concat(npcSpeechNodes).Concat(radioSpeechNodes).Concat(optionNodes).ToDictionary(kvp => kvp.Key.Data, kvp => kvp.Value); HashSet <IConversationNodeData> processed = new HashSet <IConversationNodeData>(); //Depth first iterate through the conversation starting at start nodes while (startNodes.Any()) { var start = startNodes.Pop(); if (!processed.Contains(start)) { foreach (var output in start.Connectors.Where(c => c.Definition.Id == SpecialConnectors.Output.Id)) { foreach (var connection in output.Connections) { var connected = connection.Parent; startNodes.Push(connected); } } if (allcontent.ContainsKey(start)) { var row = allcontent[start]; row.Write(Separator, includeName ? conversation.File.File.Name : null, sw); allcontent.Remove(start); } } processed.Add(start); } //Pick up any leftover nodes that are not connected to a start node foreach (var node in nodes.Select(n => n.Data)) { if (!processed.Contains(node)) { if (allcontent.ContainsKey(node)) { var row = allcontent[node]; row.Write(Separator, includeName ? conversation.File.File.Name : null, sw); allcontent.Remove(node); } processed.Add(node); } } }