/// <summary> /// Process an individual line. /// The method evaluates each scriptitem within the line, adding items and text to the output buffer as required. /// Mega function /// </summary> /// <remarks>If you do not SPLIT the line ahead of time then it is going to act wonky...</remarks> /// <param name="scriptLine"></param> /// <param name="nTalkLineIndex"></param> /// <param name="nSplitLine"></param> /// <returns></returns> async private Task ProcessLine(TalkScript.ScriptLine scriptLine, int nTalkLineIndex, int nSplitLine) { // if they already know the avatar then they aren't going to ask again if (scriptLine.ContainsCommand(TalkScript.TalkCommand.AskName) && Npc.KnowTheAvatar) { currentSkipInstruction = SkipInstruction.DontSkip; return; } int nItem = 0; int nItems = scriptLine.NumberOfScriptItems; do { TalkScript.ScriptItem item = scriptLine.GetScriptItem(nItem); // if this is the very first position of conversation // we must describe what we "see" if (nTalkLineIndex == (int)TalkScript.TalkConstants.Description && nSplitLine == 0 && nItem == 0) { EnqueToOutputBuffer(new TalkScript.ScriptItem(TalkScript.TalkCommand.PlainString, GetConversationStr(DataOvlReference.CHUNK__PHRASES_CONVERSATION.YOU_SEE) + " ")); } switch (item.Command) { case TalkScript.TalkCommand.IfElseKnowsName: Debug.Assert(nItems == 1); if (Npc.KnowTheAvatar) { // we continue to the next block, but skip the one after currentSkipInstruction = SkipInstruction.SkipAfterNext; return; } else { // we skip the next block because it is the line used when we actually know the Avatar currentSkipInstruction = SkipInstruction.SkipNext; return; } case TalkScript.TalkCommand.AvatarsName: // we should already know if they know the avatars name.... Debug.Assert(Npc.KnowTheAvatar); EnqueToOutputBuffer(new TalkScript.ScriptItem(TalkScript.TalkCommand.PlainString, TextProcessItem(item))); break; case TalkScript.TalkCommand.AskName: EnqueToOutputBuffer(new TalkScript.ScriptItem(TalkScript.TalkCommand.PlainString, GetConversationStr(DataOvlReference.CHUNK__PHRASES_CONVERSATION.WHATS_YOUR_NAME))); EnqueToOutputBuffer(item); // we actually wait in the function for the user to respond await AwaitResponse(); string avatarNameResponse = GetResponse(); // did they actually provide the Avatars name? if (avatarNameResponse.ToLower() == gameStateRef.AvatarsName.ToLower()) { // i met them gameStateRef.SetMetNPC(Npc); EnqueToOutputBuffer(new TalkScript.ScriptItem(TalkScript.TalkCommand.PlainString, GetConversationStr(DataOvlReference.CHUNK__PHRASES_CONVERSATION.PLEASURE))); break; } else { EnqueToOutputBuffer(new TalkScript.ScriptItem(TalkScript.TalkCommand.PlainString, GetConversationStr(DataOvlReference.CHUNK__PHRASES_CONVERSATION.IF_SAY_SO))); } break; case TalkScript.TalkCommand.CallGuards: EnqueToOutputBuffer(item); break; case TalkScript.TalkCommand.Change: EnqueToOutputBuffer(item); break; case TalkScript.TalkCommand.DefineLabel: // if I find a goto label, then i expect I have no further conversation lines left //Debug.Assert(nConversationIndex == conversationOrderScriptLines.Count - 1); // we are going to add the GotoLabel to the script conversationOrder.Add((int)script.GetScriptLineLabelIndex(item.LabelNum)); conversationOrderScriptLines.Add(script.GetScriptLine(script.GetScriptLineLabelIndex(item.LabelNum))); currentSkipInstruction = SkipInstruction.SkipToLabel; return; //return SkipInstruction.SkipToLabel; case TalkScript.TalkCommand.EndCoversation: EnqueToOutputBuffer(item); ConversationEnded = true; break; case TalkScript.TalkCommand.Gold: EnqueToOutputBuffer(item); break; case TalkScript.TalkCommand.JoinParty: if (gameStateRef.IsFullParty()) { string noJoinResponse = GetConversationStr(DataOvlReference.CHUNK__PHRASES_CONVERSATION.CANT_JOIN_1) + GetConversationStr(DataOvlReference.CHUNK__PHRASES_CONVERSATION.CANT_JOIN_2); EnqueToOutputBuffer(new TalkScript.ScriptItem(TalkScript.TalkCommand.PlainString, noJoinResponse)); //"Thou hast no room for me in thy party! Seek me again if one of thy members doth leave thee.\n")); } else { EnqueToOutputBuffer(item); ConversationEnded = true; } break; case TalkScript.TalkCommand.KarmaMinusOne: EnqueToOutputBuffer(item); break; case TalkScript.TalkCommand.KarmaPlusOne: EnqueToOutputBuffer(item); break; case TalkScript.TalkCommand.KeyWait: EnqueToOutputBuffer(item); break; case TalkScript.TalkCommand.NewLine: EnqueToOutputBuffer(new TalkScript.ScriptItem(TalkScript.TalkCommand.PlainString, TextProcessItem(item))); break; case TalkScript.TalkCommand.Pause: EnqueToOutputBuffer(item); break; case TalkScript.TalkCommand.PlainString: // we put it through the processor to change the text around if we are wrapped in a rune tag EnqueToOutputBuffer(new TalkScript.ScriptItem(TalkScript.TalkCommand.PlainString, TextProcessItem(item))); break; case TalkScript.TalkCommand.Rune: EnqueToOutputBuffer(new TalkScript.ScriptItem(TalkScript.TalkCommand.PlainString, TextProcessItem(item))); break; case TalkScript.TalkCommand.UserInputNotRecognized: EnqueToOutputBuffer(new TalkScript.ScriptItem(TalkScript.TalkCommand.PlainString, GetConversationStr(DataOvlReference.CHUNK__PHRASES_CONVERSATION.CANNOT_HELP) + "\n")); break; case TalkScript.TalkCommand.Unknown_Enter: break; case TalkScript.TalkCommand.DoNothingSection: // appears to signify an empty section break; case TalkScript.TalkCommand.StartLabelDefinition: // dirty - advance past the label that it will sink in... nItem++; break; case TalkScript.TalkCommand.Or: case TalkScript.TalkCommand.StartNewSection: throw new Exception("We should never see the <OR> or <A2> code in conversation"); default: throw new Exception("Recieved TalkCommand I wasn't expecting during conversation"); } nItem++; // while we still have more items in the current split line } while (nItem < nItems); currentSkipInstruction = SkipInstruction.DontSkip; return; //return SkipInstruction.DontSkip; }
/// <summary> /// Super function - Processes a list of ScriptLines. It evaluates each line and makes logical determinations to skip /// some lines if required /// </summary> /// <param name="scriptLines">the script line to process</param> /// <param name="nTalkLineIndex">where we are in the conversation - it really only cares if you are on the first line of conversation</param> async private Task ProcessMultipleLines(List <TalkScript.SplitScriptLine> scriptLines, int nTalkLineIndex) { // how many items shall we skip? if == -1, then don't skip int skipCounter = -1; for (int i = 0; i < scriptLines.Count; i++) { // if we still have some counts on the skipCounter, then decrement and skip if (skipCounter != -1 && skipCounter == 0) { --skipCounter; continue; } // if the line refers to the Avatar, but the NPC doesn't know the Avatar then just skip the line if (scriptLines[i].ContainsCommand(TalkScript.TalkCommand.AvatarsName) && !Npc.KnowTheAvatar) { continue; } // If there are no script items, then just skip // todo: this shouldn't really happen, but it does, so maybe one day find out why they are being added if (scriptLines[i].NumberOfScriptItems == 0) { continue; } // process the individual line // it will return a skip instruction, telling us how to to handle subsequent calls await ProcessLine(scriptLines[i], nTalkLineIndex, i); SkipInstruction skipInstruction = currentSkipInstruction; if (skipCounter != -1) { --skipCounter; } // process our new skip instruction switch (skipInstruction) { case SkipInstruction.SkipToLabel: // if I get a hop to a label instruction then we don't process the rest return; case SkipInstruction.SkipAfterNext: skipCounter = 1; break; case SkipInstruction.SkipNext: // skips next instruction i++; Debug.Assert(i < scriptLines.Count); break; case SkipInstruction.DontSkip: // do nothing break; } } }