virtual public void Initialize() { Node = null; if (null != Elements) { Elements.Clear(); } Elements = new List <JossData>(); }
virtual public bool PositionAtFirstNodeOfType(string data_type) { JossData result = GetFirstNodeOfType(data_type); if (null != result) { PositionAtNode(result.ID); } return(null != result); }
virtual public bool PositionAtLastNode() { if (Count > 0) { Node = Elements[Count - 1]; } else { return(false); } return(true); }
// MAIN public void 2 //////////////////////////////////// // SPEAK ///////////////////////////////////////////////// // Speak does all the work. It selects the dialogue turns to display, // it tests for redirection, automatically redirects if need be, modifies game keys // if required and sends messages to the parent object if instructed to do so by // the dialogue file. Once the file is loaded, programmers need only call SPEAK // until the dialogue has ended and it will do the rest. // It selects subsets of dialogue text from large turns and continues on to the next // turn when required. string[] LocalizedText(JossData turn) { string[] results; if (Language == string.Empty || turn.String(Language) == string.Empty) { results = new string[turn.data.Count]; turn.data.CopyTo(results); } else { results = turn.String(Language).Replace("\\n", '\n' + string.Empty).Split('\n'); } return(results); }
virtual public bool CopyNode(JossData existing) { JossData copy = existing.Copy(); Elements.Add(new JossData(Elements.Count)); Last.data_type = copy.data_type; foreach (var key in copy.defined) { Last.defined.Add(key.Key, key.Value); } foreach (string s in copy.data) { Last.data.Add(s); } return(true); }
virtual public bool PositionAtID(int id) { if (id < 0) { return(false); } int index = FindNodeByID(id); if (index == -1) { return(false); } Node = Elements[index]; return(true); }
//Josscript files are supposed to have sequential nodes but since the //data author can override this, do a test to see if the specified //node is the one requested or else go look for it. //Since a single file can have multiple sections and each section //could start it's index from 1, you can also provide the section's //node index as an offset from which to start searching virtual public bool PositionAtNode(int index, int offset = 0) { if (index + offset < 0 || index + offset >= Count) { return(false); } if (Elements [index + offset].ID == index) { Node = Elements[index + offset]; return(true); } int found_index = FindNodeByID(index, offset); if (found_index < 0) { return(false); } Node = Elements[found_index]; return(true); }
virtual public bool RemoveNode(int index) { if (Count <= index) { return(false); } //position Node on the next node if (null != Node) { if (Node.ID == index) { if (index < Count - 1) { Node = Elements[index + 1]; } else //if there isn't a "next" node, first check if there is a "previous" node //and go there if there is... if (Node.ID == 0) { Node = null; } else { Node = Elements[index - 1]; } } } Elements.RemoveAt(index); for (int i = index; i < Elements.Count; i++) { Elements[i].ID = i; } return(true); }
virtual public bool InsertNode(int index, string data_type, string add_data = "") { if (data_type == string.Empty) { return(false); } if (Count == 0) { return(AddNode(data_type, add_data)); } Elements.Insert(index, new JossData(index)); Node = Elements[index]; Node.data_type = data_type; Node.ProcessCombinedFields(add_data); for (int i = index + 1; i < Count; i++) { Elements[i].ID = i; } return(true); }
virtual public JossData Copy(JossCopyMode mode = JossCopyMode.no_id, string id_value = "-1") { JossData result = new JossData(); result.data_type = this.data_type; foreach (var data in this.defined) { if (data.Key != "id") { result.Set(data.Key, data.Value); } else { switch (mode) { //keep the original id.... case JossCopyMode.old_id: result.Set("id", data.Value); break; case JossCopyMode.new_id: result.Set("id", id_value); break; case JossCopyMode.no_id: result.Remove("id"); break; } } } foreach (string s in this.data) { result.data.Add(s); } return(result); }
//Josscript files are supposed to have sequential nodes but since the //data author can override this, do a test to see if the specified //node is the one requested or else go look for it. //Since a single file can have multiple sections and each section //could start it's index from 1, you can also provide the section's //node index as an offset from which to start searching public virtual bool PositionAtNode(int index, int offset = 0) { if (index + offset < 0 || index + offset >= Count) return false; if (Elements [ index + offset ].ID == index) { Node = Elements[index + offset]; return true; } int found_index = FindNodeByID(index, offset); if (found_index < 0) return false; Node = Elements[ found_index ]; return true; }
public virtual bool PositionAtLastNode() { if (Count > 0) Node = Elements[Count-1]; else return false; return true; }
public virtual bool PositionAtID(int id) { if (id < 0) return false; int index = FindNodeByID(id); if (index == -1) return false; Node = Elements[index]; return true; }
public virtual bool ParseFile(string data) { if (data == string.Empty) return false; Initialize(); string[] lines = data.Split('\n'); foreach (string line in lines) { //find and remove comments from the parser //take into account URL strings '://' string l = line; int commentIndex = l.IndexOf("//"); if (commentIndex > -1) { int urlIndex = 0; if (commentIndex > 0) { while (l.IndexOf("://", urlIndex) == commentIndex - 1) { urlIndex = commentIndex + 1; commentIndex = l.IndexOf("//", urlIndex); } } if (commentIndex > -1) l = l.Substring(0, commentIndex); } l = l.Trim(); //if the line is empty, do nothing with it... //ignore lines that close off data blocks... if (l == string.Empty //|| l.IndexOf("</") == 0 ) continue; //be default add data to the last datatype created int tagopen = l.IndexOf('['); int tagclose = l.IndexOf(']'); if (tagclose > 1 && tagopen == 0) { if (null != Last) { string keyname = l.Substring(1, tagclose - 1).Trim(); l = l.Substring(tagclose+1, l.Length - (tagclose + 1) ).Trim(); if (null != Last) { Last.Set(keyname, l); } } } else { //check to see if this is the definition of a new datatype's constant fields //or whether this is new data for a particular datatype tagopen = l.IndexOf('<'); tagclose = l.IndexOf('>'); if (tagclose > 1 && tagopen == 0) { string key_name = l.Substring(1, tagclose - 1).Trim(); string key_value = l.Substring(tagclose+1, l.Length - (tagclose + 1) ); AddNode(key_name, key_value); } else { //else add it as raw data... if (null != Last) Last.AddToData(l); } } } Node = (Count > 0) ? First : null; return true; }
public virtual bool InsertNode(int index, string data_type, string add_data="") { if (data_type == string.Empty) return false; if (Count == 0) return AddNode(data_type, add_data); Elements.Insert(index, new JossData( index ) ); Node = Elements[index]; Node.data_type = data_type; Node.ProcessCombinedFields(add_data); for (int i = index + 1; i < Count; i++) Elements[i].ID = i; return true; }
public virtual void Initialize() { Node = null; if (null != Elements) Elements.Clear(); Elements = new List<JossData>(); }
public virtual bool CopyNode(JossData existing) { JossData copy = existing.Copy(); Elements.Add( new JossData( Elements.Count ) ); Last.data_type = copy.data_type; foreach (var key in copy.defined) Last.defined.Add(key.Key, key.Value); foreach (string s in copy.data) Last.data.Add(s); return true; }
virtual public bool ParseFile(string data) { if (data == string.Empty) { return(false); } Initialize(); string[] lines = data.Split('\n'); foreach (string line in lines) { //find and remove comments from the parser //take into account URL strings '://' string l = line; int commentIndex = l.IndexOf("//"); if (commentIndex > -1) { int urlIndex = 0; if (commentIndex > 0) { while (l.IndexOf("://", urlIndex) == commentIndex - 1) { urlIndex = commentIndex + 1; commentIndex = l.IndexOf("//", urlIndex); } } if (commentIndex > -1) { l = l.Substring(0, commentIndex); } } l = l.Trim(); //if the line is empty, do nothing with it... //ignore lines that close off data blocks... if (l == string.Empty //|| l.IndexOf("</") == 0 ) { continue; } //be default add data to the last datatype created int tagopen = l.IndexOf('['); int tagclose = l.IndexOf(']'); if (tagclose > 1 && tagopen == 0) { if (null != Last) { string keyname = l.Substring(1, tagclose - 1).Trim(); l = l.Substring(tagclose + 1, l.Length - (tagclose + 1)).Trim(); if (null != Last) { Last.Set(keyname, l); } } } else { //check to see if this is the definition of a new datatype's constant fields //or whether this is new data for a particular datatype tagopen = l.IndexOf('<'); tagclose = l.IndexOf('>'); if (tagclose > 1 && tagopen == 0) { string key_name = l.Substring(1, tagclose - 1).Trim(); string key_value = l.Substring(tagclose + 1, l.Length - (tagclose + 1)); AddNode(key_name, key_value); } else { //else add it as raw data... if (null != Last) { Last.AddToData(l); } } } } Node = (Count > 0) ? First : null; return(true); }
public virtual bool RemoveNode(int index) { if ( Count <= index) return false; //position Node on the next node if (null != Node) if (Node.ID == index) if (index < Count - 1) Node = Elements[index + 1]; else //if there isn't a "next" node, first check if there is a "previous" node //and go there if there is... if (Node.ID == 0) Node = null; else Node = Elements[index - 1]; Elements.RemoveAt(index); for (int i = index; i < Elements.Count; i++) Elements[i].ID = i; return true; }
public virtual JossData Copy(JossCopyMode mode = JossCopyMode.no_id, string id_value="-1") { JossData result = new JossData(); result.data_type = this.data_type; foreach (var data in this.defined) { if (data.Key != "id") { result.Set(data.Key, data.Value); } else { switch (mode) { //keep the original id.... case JossCopyMode.old_id: result.Set("id", data.Value); break; case JossCopyMode.new_id : result.Set("id", id_value); break; case JossCopyMode.no_id : result.Remove("id"); break; } } } foreach (string s in this.data) result.data.Add(s); return result; }
public int Speak(int id, bool triggerEvent) { if (triggerEvent) { event_data[1].defined.Clear(); _OnSpeakStart(new DlgEvent(event_data), this); } JossData tempLine; int continueFrom = 0; string[] this_turn; try { //if we are instructed to quit the conversation if (id == -1) { EndDialogue (); return -1; } //if no line number is provided, try and determine the line if (id == -3) { //first see if we were reading something the previous turn... if (currentlySpeakingLine > -1) { id = currentlySpeakingLine; } else { //if not, then assign to first ID tempLine = lines [0]; id = tempLine.ID; } //if we are currently speaking the same line as before, continue to show this id if (id == currentlySpeakingLine) { this_turn = LocalizedText(currentLine); startAtIncrement++; if (this_turn.Length > (startAtIncrement * maxLinesToShow)) { continueFrom = id; mustProcessReq = false; } else { continueFrom = IDOfNextLine; startAtIncrement = 0; mustProcessReq = true; } } else { //if not, first determine wether we were speaking at all // and if we were, check what comes next... mustProcessReq = true; startAtIncrement = 0; continueFrom = (currentlySpeakingLine == -1) ? lines[0].ID : IDOfNextLine; } } else { // if ID was given to us, we HAVE to use it // if it is the same as the last ID if (id == currentlySpeakingLine) { //if there is nothing more to read here... This is an error... NAH!!! this_turn = LocalizedText(currentLine); if (this_turn.Length > (startAtIncrement * maxLinesToShow)) { startAtIncrement++; mustProcessReq = false; } else { Debug.LogError ("User provided line number with no dialogue to show: " + id); EndDialogue (); return -1; } } else { //if it is a new ID startAtIncrement = 0; mustProcessReq = true; } continueFrom = id; } //see if we are being redirected to an end of conversation if (continueFrom == -1) { EndDialogue (); return -1; } //now that we know what we want, let's go get it... if (continueFrom != currentlySpeakingLine) { selection = 0; currentLine = Find (continueFrom); currentlySpeakingLine = currentLine.ID; startAtIncrement = 0; } //first process the requirements for this id if (GameKeys != null && mustProcessReq && ( currentLine.defined.ContainsKey("require") )) { string[] requirements = TextReplace(currentLine["require"]).Split(','); for (int x= 0; x < requirements.Length; x++) { string[] tempReq = requirements[x].Trim().Split(' '); if (tempReq.Length != 4) throw new InvalidReqDefinitionException(currentLine.ID +":"+ requirements[x]); switch (tempReq[0]) { case "+": if (GameKeys.DoesNotHave ( tempReq[1], int.Parse(tempReq[2]) ) ) { Speak ( int.Parse( tempReq[3] ), false ); return 0; } break; case "-": if (GameKeys.DoesHave ( tempReq[1], int.Parse(tempReq[2]) )) { Speak ( int.Parse( tempReq[3] ), false ); return 0; } break; case "=": if (!GameKeys.HasExactly ( tempReq[1], int.Parse(tempReq[2]) )) { Speak ( int.Parse( tempReq[3] ), false ); return 0; } break; } } } //now modify the keys if (GameKeys != null && mustProcessReq && (currentLine.defined.ContainsKey("keys"))) { string[] keys = TextReplace(currentLine["keys"]).Split(','); for (int x= 0; x < keys.Length; x++) { string[] tempKey = keys[x].Trim().Split(' '); if (tempKey.Length != 3) throw new InvalidKeyDefinitionException(currentLine.ID +":"+ keys[x]); switch ( tempKey[0] ) { case "+": GameKeys.Add ( tempKey[1], float.Parse (tempKey[2]) ); break; case "-": GameKeys.Subtract ( tempKey[1], float.Parse (tempKey[2]) ); break; case "=": GameKeys.Setf ( tempKey[1], float.Parse (tempKey[2]) ); break; default: parent.BroadcastMessage ("ProcessKeys", keys[x].Trim(), SendMessageOptions.DontRequireReceiver); break; } } } continueFrom = maxLinesToShow * startAtIncrement; this_turn = LocalizedText(currentLine); for (int x=0; x < maxLinesToShow; x++) { linesToShow [x] = (continueFrom < this_turn.Length) ? TextReplace ((string)this_turn[ continueFrom ] ) : ""; continueFrom++; } if ( currentLine.Bool("choice") ) { FormattedText = string.Empty; } else { if (TypewriterMode) GradualDisplay (); else FormattedText = CurrentText; } //prepare the avatar image if (null == WhoIsSpeakingAvatar) Debug.LogWarning("No avatar was set. This should never happen!"); event_data[1].defined.Clear(); event_data[1].Set("turn_id", CurrentLine.ID.ToString()); event_data[1].Set("text", CurrentText); event_data[1].Set("choice", CurrentLine.String("choice")); _OnSpeakEnd(new DlgEvent(event_data), this); return 1; } catch (InvalidReqDefinitionException ex) { Debug.Log("Detected an incorrectly formatted Requirement field on line: " + ex.Message); } catch (InvalidKeyDefinitionException ex) { Debug.Log("Detected an incorrectly formatted Key field on line: " + ex.Message); } catch (Exception ex) { Debug.Log (ex.Message + ".\n" + ex.StackTrace); } return 0; }
public int Speak(int id, bool triggerEvent) { if (triggerEvent) { event_data[1].defined.Clear(); _OnSpeakStart(new DlgEvent(event_data), this); } JossData tempLine; int continueFrom = 0; string[] this_turn; try { //if we are instructed to quit the conversation if (id == -1) { EndDialogue(); return(-1); } //if no line number is provided, try and determine the line if (id == -3) { //first see if we were reading something the previous turn... if (currentlySpeakingLine > -1) { id = currentlySpeakingLine; } else { //if not, then assign to first ID tempLine = lines [0]; id = tempLine.ID; } //if we are currently speaking the same line as before, continue to show this id if (id == currentlySpeakingLine) { this_turn = LocalizedText(currentLine); startAtIncrement++; if (this_turn.Length > (startAtIncrement * maxLinesToShow)) { continueFrom = id; mustProcessReq = false; } else { continueFrom = IDOfNextLine; startAtIncrement = 0; mustProcessReq = true; } } else { //if not, first determine wether we were speaking at all // and if we were, check what comes next... mustProcessReq = true; startAtIncrement = 0; continueFrom = (currentlySpeakingLine == -1) ? lines[0].ID : IDOfNextLine; } } else // if ID was given to us, we HAVE to use it // if it is the same as the last ID { if (id == currentlySpeakingLine) //if there is nothing more to read here... This is an error... NAH!!! { this_turn = LocalizedText(currentLine); if (this_turn.Length > (startAtIncrement * maxLinesToShow)) { startAtIncrement++; mustProcessReq = false; } else { Debug.LogError("User provided line number with no dialogue to show: " + id); EndDialogue(); return(-1); } } else { //if it is a new ID startAtIncrement = 0; mustProcessReq = true; } continueFrom = id; } //see if we are being redirected to an end of conversation if (continueFrom == -1) { EndDialogue(); return(-1); } //now that we know what we want, let's go get it... if (continueFrom != currentlySpeakingLine) { selection = 0; currentLine = Find(continueFrom); currentlySpeakingLine = currentLine.ID; startAtIncrement = 0; } //first process the requirements for this id if (GameKeys != null && mustProcessReq && (currentLine.defined.ContainsKey("require"))) { string[] requirements = TextReplace(currentLine["require"]).Split(','); for (int x = 0; x < requirements.Length; x++) { string[] tempReq = requirements[x].Trim().Split(' '); if (tempReq.Length != 4) { throw new InvalidReqDefinitionException(currentLine.ID + ":" + requirements[x]); } switch (tempReq[0]) { case "+": if (GameKeys.DoesNotHave(tempReq[1], int.Parse(tempReq[2]))) { Speak(int.Parse(tempReq[3]), false); return(0); } break; case "-": if (GameKeys.DoesHave(tempReq[1], int.Parse(tempReq[2]))) { Speak(int.Parse(tempReq[3]), false); return(0); } break; case "=": if (!GameKeys.HasExactly(tempReq[1], int.Parse(tempReq[2]))) { Speak(int.Parse(tempReq[3]), false); return(0); } break; } } } //now modify the keys if (GameKeys != null && mustProcessReq && (currentLine.defined.ContainsKey("keys"))) { string[] keys = TextReplace(currentLine["keys"]).Split(','); for (int x = 0; x < keys.Length; x++) { string[] tempKey = keys[x].Trim().Split(' '); if (tempKey.Length != 3) { throw new InvalidKeyDefinitionException(currentLine.ID + ":" + keys[x]); } switch (tempKey[0]) { case "+": GameKeys.Add(tempKey[1], float.Parse(tempKey[2])); break; case "-": GameKeys.Subtract(tempKey[1], float.Parse(tempKey[2])); break; case "=": GameKeys.Setf(tempKey[1], float.Parse(tempKey[2])); break; default: parent.BroadcastMessage("ProcessKeys", keys[x].Trim(), SendMessageOptions.DontRequireReceiver); break; } } } continueFrom = maxLinesToShow * startAtIncrement; this_turn = LocalizedText(currentLine); for (int x = 0; x < maxLinesToShow; x++) { linesToShow [x] = (continueFrom < this_turn.Length) ? TextReplace((string)this_turn[continueFrom]) : ""; continueFrom++; } if (currentLine.Bool("choice")) { FormattedText = string.Empty; } else { if (TypewriterMode) { GradualDisplay(); } else { FormattedText = CurrentText; } } //prepare the avatar image if (null == WhoIsSpeakingAvatar) { Debug.LogWarning("No avatar was set. This should never happen!"); } event_data[1].defined.Clear(); event_data[1].Set("turn_id", CurrentLine.ID.ToString()); event_data[1].Set("text", CurrentText); event_data[1].Set("choice", CurrentLine.String("choice")); _OnSpeakEnd(new DlgEvent(event_data), this); return(1); } catch (InvalidReqDefinitionException ex) { Debug.Log("Detected an incorrectly formatted Requirement field on line: " + ex.Message); } catch (InvalidKeyDefinitionException ex) { Debug.Log("Detected an incorrectly formatted Key field on line: " + ex.Message); } catch (Exception ex) { Debug.Log(ex.Message + ".\n" + ex.StackTrace); } return(0); }
// MAIN public void 2 //////////////////////////////////// // SPEAK ///////////////////////////////////////////////// // Speak does all the work. It selects the dialogue turns to display, // it tests for redirection, automatically redirects if need be, modifies game keys // if required and sends messages to the parent object if instructed to do so by // the dialogue file. Once the file is loaded, programmers need only call SPEAK // until the dialogue has ended and it will do the rest. // It selects subsets of dialogue text from large turns and continues on to the next // turn when required. string[] LocalizedText(JossData turn) { string[] results; if (Language == string.Empty || turn.String(Language) == string.Empty) { results = new string[turn.data.Count]; turn.data.CopyTo(results); } else { results = turn.String(Language).Replace("\\n",'\n' +string.Empty).Split ('\n'); } return results; }