/// <summary> /// After adding all elements, this will process the script into a more readable format /// </summary> public void InitScript() { // we keep track of the index into the ScriptLines all the way through the entire method int nIndex = END_BASE_INDEXES + 1; // have we encountered a label yet? //bool labelEncountered = false; string question; // we are going to add name, job and bye to all scripts by default. We use the QuestionAnswer objects to make it seamless List <string> nameQuestion = new List <string>(1) { "name" }; _scriptQuestionAnswers.Add(new ScriptQuestionAnswer(nameQuestion, _scriptLines[(int)TalkConstants.Name])); List <string> jobQuestion = new List <string>(2) { "job", "work" }; _scriptQuestionAnswers.Add(new ScriptQuestionAnswer(jobQuestion, _scriptLines[(int)TalkConstants.Job])); List <string> byeQuestion = new List <string>(1) { "bye" }; _scriptQuestionAnswers.Add(new ScriptQuestionAnswer(byeQuestion, _scriptLines[(int)TalkConstants.Bye])); // repeat through the question/answer components until we hit a label - then we know to move onto the label section do { List <string> currQuestions = new List <string>(); ScriptLine line = _scriptLines[nIndex]; // if we just hit a label, then it's time to jump out of this loop and move onto the label reading loop if (line.GetScriptItem(0).Command == TalkCommand.StartLabelDefinition) { //labelEncountered = true; break; } // first time around we KNOW there is a first question, all NPCs have at least one question question = line.GetScriptItem(0).Str; // dumb little thing - there are some scripts that have the same keyword multiple times // the game favours the one it sees first (see "Camile" in West Brittany as an example) if (!_scriptQuestionAnswers.QuestionAnswers.ContainsKey(question)) { currQuestions.Add(question); } // if we peek ahead and the next command is an <or> then we will just skip it and continue to add to the questions list while (_scriptLines[nIndex + 1].ContainsCommand(TalkCommand.Or)) { nIndex += 2; line = _scriptLines[nIndex]; question = line.GetScriptItem(0).Str; // just in case they try to add the same question twice - this is kind of a bug in the data since the game just favours the first question it sees if (!_scriptQuestionAnswers.QuestionAnswers.ContainsKey(question)) { currQuestions.Add(question); } } ScriptLine nextLine = _scriptLines[nIndex + 1]; _scriptQuestionAnswers.Add(new ScriptQuestionAnswer(currQuestions, nextLine)); nIndex += 2; } while (true); // a little hack - it's easy to end the conversation if it always ends with the end conversation tag _scriptLines[(int)TalkConstants.Bye].AddScriptItem(new ScriptItem(TalkCommand.EndCoversation)); // time to process labels!! the nIndex that the previous routine left with is the beginning of the label section int count = 0; do // begin the label processing loop - pretty sure this is dumb and doesn't do anything - but everything messes up when I remove it { // this is technically a loop, but it should never actually loop. Kind of dumb, but fragile Debug.Assert(count++ == 0); ScriptLine line = _scriptLines[nIndex]; ScriptLine nextLine; // if there are two script items, and those two script items identify an end of label section then let's break out // this should only actually occur if there are no labels at all if (line.NumberOfScriptItems == 2 && line.IsEndOfLabelSection) { // all done. we either had no labels or reached the end of them // assert that we are on the last line of the script Debug.Assert(nIndex == _scriptLines.Count - 1); break; } // i expect that this line will always indicate a new label is being defined Debug.Assert(line.GetScriptItem(0).Command == TalkCommand.StartLabelDefinition); // I don't like this, it's inelegant, but it works... // at this point we know: // This is a multi line message bool nextCommandDefaultMessage = false; do // called for each label # { // Debug code for narrowing down to a single NPC //if (scriptLines[0].GetScriptItem(0).Str.ToLower().Trim() == "sutek".ToLower()) //if (scriptLines[0].GetScriptItem(0).Str.ToLower().Trim() == "sir arbuthnot") //{ // Console.WriteLine("AH"); //} line = _scriptLines[nIndex]; // let's make sure there are actually labels to look at if (line.IsEndOfLabelSection) { nextCommandDefaultMessage = true; break; } // create the shell for the label ScriptTalkLabel scriptTalkLabel = new ScriptTalkLabel(line.GetScriptItem(1).LabelNum, line); // save the new label to the label collection _scriptTalkLabels.AddLabel(scriptTalkLabel); // it's a single line only, so we skip this tom foolery below if (_scriptLines[nIndex + 1].GetScriptItem(0).Command == TalkCommand.StartLabelDefinition) { // do nothing, the ScriptTalkLabel will simply have no DefaultAnswer indicating that only the primary label line is read nIndex++; continue; } // with a single answer below the label, we will always use the default answer ScriptLine defaultAnswer = _scriptLines[++nIndex]; scriptTalkLabel.DefaultAnswers.Add(defaultAnswer); // it's a default only answer, and no additional line of dialog, then we skip this tom foolery below if (_scriptLines[nIndex + 1].GetScriptItem(0).Command == TalkCommand.StartLabelDefinition) { nIndex++; continue; } do // go through the question/answer and <or> { // Debug code to stop at given index //if (nIndex == 22) { Console.WriteLine(""); } List <string> currQuestions = new List <string>(); // if the next line is an <or> then process the <or> if (_scriptLines[nIndex + 2].ContainsCommand(TalkCommand.Or)) { while (_scriptLines[nIndex + 2].ContainsCommand(TalkCommand.Or)) { line = _scriptLines[nIndex + 1]; Debug.Assert(line.IsQuestion); question = line.GetScriptItem(0).Str; // just in case they try to add the same question twice - this is kind of a bug in the data since the game just favours the first question it sees if (!_scriptQuestionAnswers.QuestionAnswers.ContainsKey(question)) { currQuestions.Add(question); } nIndex += 2; } line = _scriptLines[++nIndex]; Debug.Assert(line.IsQuestion); question = line.GetScriptItem(0).Str; // just in case they try to add the same question twice - this is kind of a bug in the data since the game just favours the first question it sees if (!_scriptQuestionAnswers.QuestionAnswers.ContainsKey(question)) { currQuestions.Add(question); } } // is this a question that the player would ask an NPC? else if (_scriptLines[nIndex + 1].GetScriptItem(0).IsQuestion()) { // get the Avatar's response line line = _scriptLines[++nIndex]; question = line.GetScriptItem(0).Str; Debug.Assert(ScriptItem.IsQuestion(question)); currQuestions.Add(question); } // the NPC has tricked me - this is a second line of dialog for the given // that dastardly LB has put an extra response line in.... else //if (scriptLines[nIndex + 1].GetScriptItem(0).Str.Trim().Length > 4) { line = _scriptLines[++nIndex]; Debug.Assert(!line.IsQuestion); scriptTalkLabel.DefaultAnswers.Add(line); nIndex++; // let's make double sure that we only have a single additional line of text Debug.Assert(_scriptLines[nIndex].GetScriptItem(0).Command == TalkCommand.StartLabelDefinition); nextLine = _scriptLines[nIndex]; continue; } // get your answer and store it ScriptLine npcResponse = _scriptLines[++nIndex]; // we are ready to create a Q&A object and add it the label specific Q&A script scriptTalkLabel.AddScriptQuestionAnswer(new ScriptQuestionAnswer(currQuestions, npcResponse)); // we are at the end of the label section of the file, so we are done. nextLine = _scriptLines[++nIndex]; // does the next line indicate end of all of the label sections, then let's get out of this loop if (nextLine.IsEndOfLabelSection) { nIndex--; nextCommandDefaultMessage = true; break; } // is the next line a label definition? is so, let's exit this label and move on if (!nextLine.IsLabelDefinition()) { nIndex--; continue; } // while we know the next line is not a new label or end of label, then let's keep reading by moving to our next loop } while (nextLine.GetScriptItem(0).Command != TalkCommand.StartLabelDefinition); // while we haven't encountered an end of label section } while (!nextCommandDefaultMessage); nIndex++; // while we haven't read every last line, then let's keep reading } while (nIndex < (_scriptLines.Count - 1)); }
/// <summary> /// is this script item a question that the player asks an NPC? /// </summary> /// <returns></returns> public bool IsQuestion() { return(ScriptItem.IsQuestion(Str)); }