Updating Dialogue Text by retrieving Variables from a Scriptable Object Database
Updating Dialogue Text by retrieving Variables from a Scriptable Object Database
Here's what I'd like to do:
Problem 1:
I have a text that reads: "You seem to have X gold coins with you. Did you talk to your associates A, B, C and D about getting a loan?"
Now what I want to do is fill in X, A, B, C and D with respective variables from my Scriptable Object Database. I don't want to use any of the Quest, Item, Location etc. stuff that comes with the system because they don't seem like what I need and I can't seem to find a comfortable way of editing them through code(Maybe I'm missing info on this? help!). My database is of a certain shape and is accessible by code since it's a singleton but I don't know how to access it via the Lua commands.
I just need a method that says: UpdatePartOfText(string remove, string replace).
Problem 2:
I want to present replies depending on my database as well. For example let's say after asking "You seem to have X gold coins with you. Did you talk to your associates A, B, C and D about getting a loan?" I want to put possible answers as the following:
- I talked to A.
- I talked to B.
- I talked to C.
- I talked to D.
So if there was a 5th guy in my database I would add -I talked to E as another option.
Could someone kindly guide me in the right direction?
TL;DR
-How do I update Dialogue Text in a Node of a Conversation of a Dialogue Database (Jesus...)?
-How do I update the aforementioned text with a database of my own making or through variables I save in other instances of classes?\
-Heeeeeeeeeeeeeeeeeeeeeeelp!
Problem 1:
I have a text that reads: "You seem to have X gold coins with you. Did you talk to your associates A, B, C and D about getting a loan?"
Now what I want to do is fill in X, A, B, C and D with respective variables from my Scriptable Object Database. I don't want to use any of the Quest, Item, Location etc. stuff that comes with the system because they don't seem like what I need and I can't seem to find a comfortable way of editing them through code(Maybe I'm missing info on this? help!). My database is of a certain shape and is accessible by code since it's a singleton but I don't know how to access it via the Lua commands.
I just need a method that says: UpdatePartOfText(string remove, string replace).
Problem 2:
I want to present replies depending on my database as well. For example let's say after asking "You seem to have X gold coins with you. Did you talk to your associates A, B, C and D about getting a loan?" I want to put possible answers as the following:
- I talked to A.
- I talked to B.
- I talked to C.
- I talked to D.
So if there was a 5th guy in my database I would add -I talked to E as another option.
Could someone kindly guide me in the right direction?
TL;DR
-How do I update Dialogue Text in a Node of a Conversation of a Dialogue Database (Jesus...)?
-How do I update the aforementioned text with a database of my own making or through variables I save in other instances of classes?\
-Heeeeeeeeeeeeeeeeeeeeeeelp!
Re: Updating Dialogue Text by retrieving Variables from a Scriptable Object Database
Hi,
1. Consider using Dialogue System variables after all. It makes the dialogue writing much easier: "You seem to have [var=gold] gold coins with you. Did you talk to your associates [var=npcA], [var=npcB], [var=npcC] and [var=npcD] about getting a loan?"
Use DialogueLua.SetVariable() to set Dialogue System variables in your code:
You can use an OnConversationStart method to set the Dialogue System variables based on the current values in your database.
2. Or, register your C# code with Lua, and use the [lua] markup tag: "You seem to have [lua(GetInt("gold"))] gold coins with you. Did you talk to your associates [lua(GetString("A"))], [lua(GetString("B"))], [lua(GetString("C"))] and [lua(GetString("D"))] about getting a loan?"
Add something like this to your singleton script:
This is a totally made-up example since I don't know your singleton code. I just guessed that there might be functions called GetInt(), GetString(), and GetBool().
3. Or, taking a completely different approach, add a script to the Dialogue Manager that has an OnConversationLine method. The Dialogue System calls this method before showing a subtitle. It gives you a chance to modify the text first. For example, say you decide to use angle brackets to specify code to substitute: "You seem to have <X> gold coins with you. Did you talk to your associates <A>, <B>, <C> and <D> about getting a loan?"
Then make the OnConversationLine(Subtitle) method look something like this:
You could once again define variables in the Dialogue Editor such as "talkedToA", "talkedToB", etc. Then set each dialogue entry node like this:
Here are three ideas:tuncturel wrote:Problem 1:
I have a text that reads: "You seem to have X gold coins with you. Did you talk to your associates A, B, C and D about getting a loan?"
Now what I want to do is fill in X, A, B, C and D with respective variables from my Scriptable Object Database. I don't want to use any of the Quest, Item, Location etc. stuff that comes with the system because they don't seem like what I need and I can't seem to find a comfortable way of editing them through code(Maybe I'm missing info on this? help!). My database is of a certain shape and is accessible by code since it's a singleton but I don't know how to access it via the Lua commands.
I just need a method that says: UpdatePartOfText(string remove, string replace).
1. Consider using Dialogue System variables after all. It makes the dialogue writing much easier: "You seem to have [var=gold] gold coins with you. Did you talk to your associates [var=npcA], [var=npcB], [var=npcC] and [var=npcD] about getting a loan?"
Use DialogueLua.SetVariable() to set Dialogue System variables in your code:
Code: Select all
using PixelCrushers.DialogueSystem;
...
DialogueLua.SetVariable("gold", MyScriptableObjectSingleton.GetNumGold()); //(example)
2. Or, register your C# code with Lua, and use the [lua] markup tag: "You seem to have [lua(GetInt("gold"))] gold coins with you. Did you talk to your associates [lua(GetString("A"))], [lua(GetString("B"))], [lua(GetString("C"))] and [lua(GetString("D"))] about getting a loan?"
Add something like this to your singleton script:
Code: Select all
using PixelCrushers.DialogueSystem;
...
public class MySingletonClass : MonoBehaviour {
void Start() {
// If your singleton is a MonoBehaviour, you can register your code here.
// Otherwise you can add a constructor method.
Lua.RegisterFunction("GetInt", this, typeof(MySingletonClass).GetMethod("GetInt"));
Lua.RegisterFunction("GetString", this, typeof(MySingletonClass).GetMethod("GetString"));
Lua.RegisterFunction("GetBool", this, typeof(MySingletonClass).GetMethod("GetBool"));
}
}
3. Or, taking a completely different approach, add a script to the Dialogue Manager that has an OnConversationLine method. The Dialogue System calls this method before showing a subtitle. It gives you a chance to modify the text first. For example, say you decide to use angle brackets to specify code to substitute: "You seem to have <X> gold coins with you. Did you talk to your associates <A>, <B>, <C> and <D> about getting a loan?"
Then make the OnConversationLine(Subtitle) method look something like this:
Code: Select all
void OnConversationLine(Subtitle subtitle) {
subtitle.formattedText.text = FillInVariables(subtitle.formattedText.text);
}
string FillInVariables(string s) {
// Put your code here to process the string and return the result.
}
It's easiest if you can add E when you're writing the conversation, and then at runtime make it visible or not based on a condition. In this reply, I'll assume you can do that. (If you need to be able to add new responses at runtime, let me know. Otherwise I'll spare you the wall of text.)tuncturel wrote:Problem 2:
I want to present replies depending on my database as well. For example let's say after asking "You seem to have X gold coins with you. Did you talk to your associates A, B, C and D about getting a loan?" I want to put possible answers as the following:
- I talked to A.
- I talked to B.
- I talked to C.
- I talked to D.
So if there was a 5th guy in my database I would add -I talked to E as another option.
Could someone kindly guide me in the right direction?
You could once again define variables in the Dialogue Editor such as "talkedToA", "talkedToB", etc. Then set each dialogue entry node like this:
- Menu Text: I talked to A.
- Conditions: Variable["talkedToA"] == true
(You can use the Lua wizard; you don't need to type this manually.)
- Dialogue Text: Hi, I'm A!
- Script: Variable["talkedToA"] = true
- Menu Text: I talked to A.
- Conditions: GetBool("TalkedToA") == true
(You can't use the Lua wizard in this case because it doesn't know about your custom-registered functions.)
- Dialogue Text: Hi, I'm A!
- Script: SetBool("TalkedToA", true)
Re: Updating Dialogue Text by retrieving Variables from a Scriptable Object Database
This is some lightning speed response right there Tony, much appreciated. I'm working in the day and it's almost bed time for me so I'll give this stuff a try as soon as I can. I'll reply once I've wrapped my head around your response.
Re: Updating Dialogue Text by retrieving Variables from a Scriptable Object Database
Hi Tony!
I've got to say it again... what an awesome reply you have given to me. I spent some time digesting the text and then I picked the 2nd solution and used the code to register my Lua functions. After a couple minutes I got it working perfectly! Now I can register any function I want and it'll give me the info/variable I need at will. This helps me quite a bit since I don't also have to register existing variables from my Database inside the Dialogu Database one more time.
Now comes the fancy part.
I need to be able add/remove answers depending on the amount of Persons (Person.cs is a class) within a branch. So if a branch has, let's say 5 Persons in there. I want the conversation to go as follows.
- Hi there Tony! It seems you have 3 Persons in your branch. Currently the Persons in your branch are John, Terry and Will. Would you like to hear about what they're up to?
* Yes. Tell me about Johny.
* Yes. Tell me about Terry.
* Yes. Tell me about Will.
Let's say you pick to learn about Terry.
+Yes. Tell me about Terry.
-Terry is a botanist and he's busy picking flowers. What would you like him to do?
* Terry should keep picking flowers.
* Terry should go and treat the weeds in his field.
* Terry should start planting potatoes.
So to explain in a nut shell I want to be able to generate answers on the fly depending first on amount of Persons in a branch. Then I need to be able to generate answers depending on possible things a Botanist can do. Of course I have the respective data again in my Database. I can draw it at will, but I'm not sure how to edit dialogue text and create answers on the fly.
Much appreciate your valuable support.
I've got to say it again... what an awesome reply you have given to me. I spent some time digesting the text and then I picked the 2nd solution and used the code to register my Lua functions. After a couple minutes I got it working perfectly! Now I can register any function I want and it'll give me the info/variable I need at will. This helps me quite a bit since I don't also have to register existing variables from my Database inside the Dialogu Database one more time.
Now comes the fancy part.
I need to be able add/remove answers depending on the amount of Persons (Person.cs is a class) within a branch. So if a branch has, let's say 5 Persons in there. I want the conversation to go as follows.
- Hi there Tony! It seems you have 3 Persons in your branch. Currently the Persons in your branch are John, Terry and Will. Would you like to hear about what they're up to?
* Yes. Tell me about Johny.
* Yes. Tell me about Terry.
* Yes. Tell me about Will.
Let's say you pick to learn about Terry.
+Yes. Tell me about Terry.
-Terry is a botanist and he's busy picking flowers. What would you like him to do?
* Terry should keep picking flowers.
* Terry should go and treat the weeds in his field.
* Terry should start planting potatoes.
So to explain in a nut shell I want to be able to generate answers on the fly depending first on amount of Persons in a branch. Then I need to be able to generate answers depending on possible things a Botanist can do. Of course I have the respective data again in my Database. I can draw it at will, but I'm not sure how to edit dialogue text and create answers on the fly.
Much appreciate your valuable support.
Re: Updating Dialogue Text by retrieving Variables from a Scriptable Object Database
Once again, here are two options:
Option 1: If you know the maximum number of Persons and maximum number of activities that a Person can do, build your conversation with those numbers in mind. For example, make the NPC line:
"Hi there [lua(GetPlayerName())]! It seems you have [lua(GetNumPersons())] Persons in your branch. Currently the Persons in your branch are [lua(GetPersonList())]. Would you like to hear about what they're up to?"
where:
Link all of these responses to the same NPC line:
Option 2: Construct the conversation on the fly. Here's the overview:
1. Create a new dialogue database.
2. Create a new conversation and add it to the dialogue database.
3. Add the dialogue database to the Dialogue Manager.
4. Run the conversation.
5. Remove the dialogue database from the Dialogue Manager and destroy it.
To create a new dialogue database:
To create a new conversation (pseudocode):
To add the conversation to the database:
To add the database to the Dialogue Manager:
To start the conversation:
To remove the database from the Dialogue Manager and destroy it:
To save steps, you could keep the database around and add and remove dynamically-built conversations as needed. But you must remove the database from the Dialogue Manager (i.e., detach it) before manipulating the list of conversations. Then add it back to the Dialogue Manager when you're done creating/modifying conversations.
There are other options, such as making a subclass of UnityUIDialogueUI and overriding the ShowSubtitle and ShowResponses methods. But in the end that's probably messier since you're just manipulating the UI part rather than the underlying data. Unfortunately you can't just write an OnConversationResponseMenu method. In this method you can manipulate the contents of each response, but you can't add or remove responses. The number of responses has to remain the same.
Option 1: If you know the maximum number of Persons and maximum number of activities that a Person can do, build your conversation with those numbers in mind. For example, make the NPC line:
"Hi there [lua(GetPlayerName())]! It seems you have [lua(GetNumPersons())] Persons in your branch. Currently the Persons in your branch are [lua(GetPersonList())]. Would you like to hear about what they're up to?"
where:
- GetPlayerName() returns the player's name (e.g., "Tony").
- GetNumPersons() returns the amount of Persons (e.g., 3).
- GetPersonList() returns a string listing the Persons (e.g., "John, Terry and Will").
- Menu Text: "Yes. Tell me about [lua(GetPersonName(5))]."
- Conditions: GetNumPersons() <= 5
- Script: current = 5
Link all of these responses to the same NPC line:
- Dialogue Text: "[lua(GetPersonName(current))] is a [lua(GetPersonJob(current))] and [lua(GetPersonCurrentActivity(current))]. What would you like [lua(GetPersonGender(current))] to do?"
- Menu Text: "[lua(GetPersonName(current))] should [lua(GetPersonActivity(current, 3))]."
- Conditions: GetNumActivities(current) <= 3
- Script: DoActivity(current, 3)
- GetNumActivities(personNumber) returns the number of activities that the specified person can do.
- GetPersonActivity(personNumber, activityNumber) returns the name of an activity available to a person.
- DoActivity(personNumber, activityNumber) makes a person do an activity.
Option 2: Construct the conversation on the fly. Here's the overview:
1. Create a new dialogue database.
2. Create a new conversation and add it to the dialogue database.
3. Add the dialogue database to the Dialogue Manager.
4. Run the conversation.
5. Remove the dialogue database from the Dialogue Manager and destroy it.
To create a new dialogue database:
Code: Select all
var database = ScriptableObject.CreateInstance<DialogueDatabase>();
Code: Select all
var conversation = new Conversation();
conversation.id = ???; //assign a unique ID number.
// Add as many dialogue entries as you need. Assign a unique ID to each one.
// Link your dialogue entries by adding Link objects to each dialogue entry's outgoingLinks list.
Code: Select all
database.conversations.Add(conversation);
Code: Select all
DialogueManager.AddDatabase(database);
Code: Select all
DialogueManager.StartConversation(...); // Parameters vary.
Code: Select all
DialogueManager.RemoveDatabase(database);
Destroy(database);
There are other options, such as making a subclass of UnityUIDialogueUI and overriding the ShowSubtitle and ShowResponses methods. But in the end that's probably messier since you're just manipulating the UI part rather than the underlying data. Unfortunately you can't just write an OnConversationResponseMenu method. In this method you can manipulate the contents of each response, but you can't add or remove responses. The number of responses has to remain the same.
Re: Updating Dialogue Text by retrieving Variables from a Scriptable Object Database
Hey Tony,
I just got back from work and read your post. Option 1 seems to be the simpler one indeed. I'm going to weigh the situation and let you know of the outcome.
I just got back from work and read your post. Option 1 seems to be the simpler one indeed. I'm going to weigh the situation and let you know of the outcome.
Re: Updating Dialogue Text by retrieving Variables from a Scriptable Object Database
Hi Tony,
I'm implementing the first option already.
I had an issue though and wanted to ask you.
My Dialogue Text reads:
Yes. Tell me about [lua(GetPerson(2))].
And I get this error:
Dialogue System: Lua code 'return GetPerson(2)' threw exception 'failed to convert parameters'
Would you happen to have any headers?
I'm implementing the first option already.
I had an issue though and wanted to ask you.
My Dialogue Text reads:
Yes. Tell me about [lua(GetPerson(2))].
And I get this error:
Dialogue System: Lua code 'return GetPerson(2)' threw exception 'failed to convert parameters'
Would you happen to have any headers?
Re: Updating Dialogue Text by retrieving Variables from a Scriptable Object Database
Hi,
In your C# script, use double for your number parameters. I noticed the formatting of the Data Types Allowed in Lua Functions table was broken. Sorry if this threw you for a loop. I just fixed the manual. Strings and bools work as normal. Numbers are the only unusual case. Lua uses doubles for all numbers. Typecast them in your C# methods. For example:
If you don't want to modify your existing C# method, you can write a tiny wrapper:
You can still register the function in Lua as "GetPerson" yet make it call the C# LuaGetPerson() method:
In your C# script, use double for your number parameters. I noticed the formatting of the Data Types Allowed in Lua Functions table was broken. Sorry if this threw you for a loop. I just fixed the manual. Strings and bools work as normal. Numbers are the only unusual case. Lua uses doubles for all numbers. Typecast them in your C# methods. For example:
Code: Select all
string GetPerson(double personNumber) {
return people[(int)personNumber].name;
}
Code: Select all
string LuaGetPerson(double personNumber) {
return GetPerson((int)personNumber); // Cast parameter as int, and call the real GetPerson method.
}
Code: Select all
Lua.RegisterFunction("GetPerson", this, typeof(MySingletonClass).GetMethod("LuaGetPerson"));
Re: Updating Dialogue Text by retrieving Variables from a Scriptable Object Database
Sounds good. It's a bit of a work around and extra code lying within the method casting the double to int but it works like a charm.
Thanks again for the lightning speed response. I've made considerable headway today!
Thanks again for the lightning speed response. I've made considerable headway today!