void ActivateNode(NarrativeNode _node) { currentNode = _node; ActionProcess action = new ActionProcess(this, currentNode); processMgr.Launch(action); }
IEnumerator ActivateNodeRoutine(NarrativeNode _node) { _node.Activate(); yield return(StartCoroutine(waitingRoutine(_node.Duration))); List <NarrativeNode> nexts = _node.Next(); yield return(StartCoroutine(ActivateNodeNextsRoutine(nexts))); }
public override Node Create(Vector2 pos) { NarrativeNode node = CreateInstance <NarrativeNode> (); node.rect = new Rect(pos.x, pos.y, 300, 120); node.name = ID; node.CreateInput("Previous Node", CONNECT_FORWARD_STR, NodeSide.Left, 30); node.CreateOutput("Next Node", CONNECT_FORWARD_STR, NodeSide.Right, 30); return(node); }
public ActionProcess(ActionManager _parent, NarrativeNode _node) { parent = _parent; currentNode = _node; }
void ActivateNode(NarrativeNode _node) { currentNode = _node; StartCoroutine(ActivateNodeRoutine(_node)); }
public NarrativeList Parse(string inputStr) { CurrentNarrativeList = new NarrativeList(); // Automatically add external block statements enclosing whole thing if not present. if (!inputStr.StartsWith($"{OPENBRACKET}{NodeType.Begin}")) { inputStr = $"{OPENBRACKET}{NodeType.Begin} ALL_CONTENT{CLOSEBRACKET}" + inputStr + $"{OPENBRACKET}{NodeType.End} ALL_CONTENT{CLOSEBRACKET}"; } // Trim initial open bracket ("split" on open bracket symbol, discard meaningless empty first element, keep only what comes after). //inputStr.TrimStart(OnOpenBracket); int seqCounter = 0; while (true) { if (String.IsNullOrEmpty(inputStr)) { break; } var currentStr = inputStr.Before(OnOpenBracket); // Should have the form "TypeOrTagName Tag: option, option, option]text|text inputStr = inputStr.After(OnOpenBracket); // Should have the form above, plus zero or more "[(same again)" on the end. if (currentStr == "") { continue; } // Parse out the speech string (always present, if sometimes empty) var speechString = currentStr.After(OnCloseBracket); currentStr = currentStr.Before(OnCloseBracket); PreviousNode = CurrentNode; var firstWord = currentStr.Before(OnSpaceOrColon); if (Enum.TryParse <NodeType>(firstWord, out NodeType nodeWord) && nodeWord != NodeType.Tag) // First word is the name of a node type. { if (nodeWord.IsOneOf(NodeConsts.ConditionOpeners)) // To wit, "Begin", "Check", "Cue", or "Ice". { var nodeTag = currentStr.Split(OnSpaceOrColon)[1].ToLower(); // Second word - likely of more than two! - is therefore the tag. if (NestedTagStructure.Any(ncond => ncond.Tag == nodeTag)) { throw new Exception($"Error parsing input string - tag {nodeTag} already exists and cannot be reused."); } // Specific implementations for each type of condition node NarrativeConditionNode curNode; if (nodeWord == NodeType.Begin) { curNode = new NarrativeLabelNode(); } else if (nodeWord == NodeType.Check) { var argument = currentStr.After(OnColon).Trim(); var varName = argument.Before(OnSpace); // Or should this be the part that's on colon, instead? TBD. var conditionValue = argument.After(OnSpace); curNode = new NarrativeCheckConditionNode() { CheckedVariable = varName, CheckedCondition = conditionValue }; } else if (nodeWord == NodeType.Cue) { var argument = currentStr.After(OnColon).Trim(); var argAsGest = (Gest)Enum.Parse(typeof(Gest), argument, ignoreCase: true); curNode = new NarrativeCueConditionNode() { TargetGesture = argAsGest }; } else if (nodeWord == NodeType.Ice) { curNode = new NarrativeIceConditionNode(); var argumentStr = currentStr.After(OnColon).Trim(); var arguments = argumentStr.Split(',').Select(s => s.Trim()); foreach (var argument in arguments) { if (argument == "") { continue; } var target = argument.Before(OnSpace); var amount = argument.After(OnSpace); // Which variable are they assigning? var targetIndex = NarrativeIceConditionNode.ArgumentNames.ToList().IndexOf(target); if (targetIndex == -1) { throw new Exception($"Cannot parse argument '{target}' - target must be one of {NarrativeIceConditionNode.ArgumentNames.Join()}"); } // What are they assigning it to be? Is it a range (min-max), or a single value (the mean)? double firstAmount; double?secondAmount; try { if (amount.Contains("-")) { firstAmount = double.Parse(amount.Split('-')[0]); var amountMax = double.Parse(amount.Split('-')[1]); secondAmount = amountMax - firstAmount; } else { firstAmount = double.Parse(amount); secondAmount = null; } } catch (Exception) { throw new Exception($"Cannot parse amount '{amount}' - specify either a single value, or a range as 'min-max'."); } // Having parsed that assignment, make it so. (curNode as NarrativeIceConditionNode).AssignArgument(targetIndex, firstAmount, secondAmount); } } else { throw new Exception(); // Should be impossible to hit this but flow control demands that it exist. } // In any of these cases, the current inmost-nested condition set is now this one, and the Tag has been set. curNode.Tag = nodeTag; NestedTagStructure.Push(curNode); CurrentNode = curNode; } else if (nodeWord == NodeType.End) { var nodeTag = currentStr.After(OnSpaceOrColon).ToLower(); // Second word is therefore the tag. if (NestedTagStructure.Peek().Tag != nodeTag) { throw new Exception($"Failure to parse input string - tag {nodeTag} is being closed out of sequence."); } NestedTagStructure.Pop(); CurrentNode = new NarrativeEndNode() { Tag = nodeTag }; } else if (nodeWord == NodeType.Wait) { TimeSpan waitTime; var secondWord = currentStr.After(OnSpaceOrColon).ToLower(); if (double.TryParse(secondWord, out double value)) { waitTime = TimeSpan.FromMilliseconds(value); } else { int numBeats; TimeSpan oneBeat = TimeSpan.FromMilliseconds(400); if (secondWord == "one") { numBeats = 1; } else if (secondWord == "two") { numBeats = 2; } else if (secondWord == "three") { numBeats = 3; } else if (secondWord == "four") { numBeats = 4; } else { throw new Exception($"Do not understand 'Wait {secondWord}' - use milliseconds instead."); } waitTime = oneBeat.MultipliedBy(numBeats); } CurrentNode = new NarrativeWaitNode() { DelayLength = waitTime }; } else if (nodeWord == NodeType.Retry) { var nodeTag = currentStr.After(OnSpaceOrColon).ToLower(); // Second word is therefore the tag. CurrentNode = new NarrativeRetryNode() { Tag = nodeTag }; } else if (nodeWord == NodeType.TransitionBy) { var nodeTag = currentStr.After(OnSpaceOrColon).Replace("by ", "").ToLower(); // Second/third word is therefore the tag. CurrentNode = new NarrativeTransitionNode() { Tag = nodeTag }; } else if (nodeWord == NodeType.Set) { var argument = currentStr.After(OnSpace); var variableName = argument.Before(OnSpaceOrColon); var variableValue = argument.After(OnSpaceOrColon); CurrentNode = new NarrativeSetNode() { Variable = variableName, Value = variableValue }; } else if (nodeWord == NodeType.Disconnect) { CurrentNode = new NarrativeDisconnectNode(); } else if (nodeWord == NodeType.Then) { CurrentNode = new NarrativeNode(); // Absolute plainest type possible, not worth deriving. Basically ends up describing a brief pause and/or simply provides logical structure to the author. } // For all of these, the Type of node is simply the node word. (Type is really only relevant for the Tag type, below.) CurrentNode.Type = nodeWord; } else if (NestedTagStructure.Peek().Tag == firstWord.ToLower()) // First word is the name of our current most-deeply-nested condition; that's acceptable too. { var targetValue = currentStr.After(OnColon).Trim().ToLower(); CurrentNode = new NarrativeTagNode() { Type = NodeType.Tag, Tag = firstWord.ToLower(), Value = targetValue }; NestedTagStructure.Peek().Alternatives.Add(targetValue, CurrentNode); } else { throw new Exception($"Unable to parse '{currentStr}'!"); } // True for all of these is that the position in the sequence is a cumulative counter, they belong in the narrative list, and their speech string is the bit we parsed out way back at the top. CurrentNode.SeqID = seqCounter++; CurrentNarrativeList.Add(CurrentNode); CurrentNode.SpeechString = speechString; } // Go through and assign NextNode based on sequence position, with Tag alterna-nodes redirecting to their associated End node, and a nameless Disconnect node as the final one's NextNode. foreach (var node in CurrentNarrativeList) { if (node == CurrentNarrativeList.Last()) { node.NextNode = new NarrativeDisconnectNode(); } else { var naturalNextNode = CurrentNarrativeList[node.SeqID + 1]; if (naturalNextNode.Type != NodeType.Tag) { node.NextNode = naturalNextNode; } else { var nodesTag = ((NarrativeTagNode)naturalNextNode).Tag; node.NextNode = CurrentNarrativeList.First(n => n is NarrativeEndNode nEnd && nEnd.Tag == nodesTag); } } } return(CurrentNarrativeList); }
//[UnityEditor.MenuItem("CONTEXT/ReadSceneNames/Update Scene Names")] private static void UpdateNames(UnityEditor.MenuCommand command) { NarrativeNode context = (NarrativeNode)command.context; context.scenes = ReadNames(); }
void OnEnable() { t = (NarrativeNode)target; GetTarget = new SerializedObject(t); transitionList = GetTarget.FindProperty("transitionStates"); }