Comment on this Guide

Getting Started with DiaQ in plyGame

In this tutorial we will look at how to create a simple quest and how to show the conversation when a player interacts with an NPC. Keep in mind that there are a lot of different ways this can be handled, especially when you work with other GUI solution than OnGUI/ Screens System. This guide will not cover every aspect but should give you a starting point for creating your own Dialogue interaction and Quests.

Create the Interface

The first thing I will do is to create the interface (the GUI) that will pop up when the player interacts with an NPC that has a quest. This will be done in the Screens Editor as a Custom Screen which I named Dialogue.

It will simply show some conversation text and up to 3 buttons that allows the player to respond. Note how I named the label “text” and the 3 buttons “button1”, “button2” and “button3”. The order in which I named the buttons is also important as it will make it easier to decide which to hide. I want to show buttons from bottom up so that if a conversation only has two responses then the top most button will be hidden and not the bottom most one. It will just look better.

I’ve also set that each button will call the event named Dialogue Response and send a numeric value in param1 depending on which button was pressed; that is: 0, 1 or 2. We will look at the event later.

Create the Quest Giver NPC

Now I will create the NPC that can give the quests. I will not yet hook up a DiaQ Graph, I simply want to have her in the scene and test if interaction works. When working on this you need to take things step by step and test, especially when you are new to how a system works.

I’ve given this NPC an “No Move” movement controller since it will not move around. There should also be a collider on it so that the player can right-click on the character to interact with it.

A plyBlox component is added since I need a way to respond to Interact events on this NPC. In the Blox I will respond to the plyRPG > Actor > On Interact and plyRPG > Actor > On Interact Stopped Events. For now I will simply show the Dialogue screen and and when interaction stops I will hide the screen.

[@E:plyRPG > Actor > On Interact:: On Interact@]
[@B:GUI > Screens (plyGame) > Show Custom Screen:: Show Screen: [V:Show Screen:Dialogue:V] [H:AdditiveTrue:H] @]
[@E:plyRPG > Actor > On Interact Stopped:: On Interact Stopped@]
[@B:GUI > Screens (plyGame) > Hide Custom Screen:: Hide Screen: [V:Hide Screen:Dialogue:V] @]

You can now run up to the NPC and interact with it (right-click or E) and the Dialogue window will come up. The default text and buttons are still showing but I will fix that soon. We just needed to make sure that everything is working up to this point. Like I said, take it step by step, test regularly, and when a problem pops up it will be easier to track down.

Create the Quest

The Quest will be a really simple one but will demonstrate how to interact with the Quest Conditions and Rewards options. The quest will ask that the player kill two bears. Open the DiaQ Quest Editor, menu: Tools > PLYoung > DiaQ > Quest Editor and create a new quest. I will rename it to Kill two Bears.

Add some quest text to describe what this quest wants the player to do. Then click on the (+) next to Conditions to add a condition. Conditions describe what goal must be reached before the quest is considered completed.

In this case I want the player to kill two bears, so I will define a key KilledBear and set the TargetValue to 2. This means that each time a condition update is done and the key “KilledBear” is used then this condition will listen to that and update its internal counter, checking it against the target value to see if its goal has been reached and the quest can be considered completed. Note that only “accepted” quests will listen.

While we have the quest editor open, let’s define some rewards. Press (+) next to Rewards, twice. This will add two reward that can now be configured. Click on the button next to key to select the kind of reward. This is mostly how you want to define the key when using plyGame with DiaQ. When using DiaQ standalone you could choose to enter a string value for the key, or better yet, define a data provider that can be used to select the key (but that is an advanced topic).

I will choose to give the player Currency and 30 of it, and Attribute > Experience (XP) and 100 thereof.

Create the Graph (Conversation Flow)

In DiaQ the Dialogue or FLow of Conversation is known as a Graph. You will typically create a Graph for each NPC that the player can interact with. NPCs could also share graphs, especially when it is general filler conversation or perhaps guards who can give directions. NPCs could also have more than one graph since you decide which graph to show when interaction with the NPC is started.

Open the Graph Editor, menu: Tools > PLYoung > DiaQ > Graph Editor and add (+) a new graph. I will rename it to Sample Quest Giver. I will only add the important bits to get started and test the graph.

Add a Dialogue node and hook it up to the Start node. Click on the out of the Start and you should see a line run up to your mouse cursor, now click on the Dialogue node and they should be connected. With the Dialogue node selected you will see its properties in the Inspector. Here you can add text that should be displayed when this node is active and add the responses that the player can choose from.

I will add two responses. The order in which I add them is important. Remember back when I made the Dialogue Screen I created the buttons in a certain order with button 1 at the bottom and button 2 and 3 following above. So, for the response No Thanks to appear at the bottom I need to add it here 1st! This will make more sense once we do the Blocks related to the quest.

The 1st response will simply end the graph but for the second one I want to test what will happen when the player makes a selection. Let’s have the NPC say something else. All this will be changed later on, for now we just want to test if the Blocks are working as expected and show the correct dialogue text and responses. I will link the 2nd response to the other Dialogue node.

I’ll click on the Linked Quest button and choose to Kill two Bears quest. By linking the quest the Dialogue will make the quest’s text available too. It has no other purpose besides this. So do not confuse it with giving the player the quest.

Update NPC Blox to Start the Graph

So far the NPC Blox will simply show the Dialogue Screen. I now need to change it so that the Graph that was just created will run when the NPC is interacted with. By beginning a graph it will start at the Start node and run through the linked nodes until it reaches one that blocks. In this case the Dialogue node will block the flow as it needs to wait for a response. After this the Dialogue Screen can be shown.

[@E:plyRPG > Actor > On Interact:: On Interact@]
[@B:Dialogue and Quest > DiaQ > Begin Graph:: Begin DiaQ Graph: [V:Begin DiaQ GraphSample Quest Giver:V] [H:Begin DiaQ GraphSample Quest Giver:H][H:Cache targetTrue:H]@]
[@B:GUI > Screens (plyGame) > Show Custom Screen:: Show Screen: [H:Show Screen:Dialogue:H][V:Show Screen:Dialogue:V] [H:AdditiveTrue:H]@]
[@E:plyRPG > Actor > On Interact Stopped:: On Interact Stopped@]
[@B:GUI > Screens (plyGame) > Hide Custom Screen:: Hide Screen: [H:Hide Screen:Dialogue:H][V:Hide Screen:Dialogue:V] @]
[@B:Dialogue and Quest > DiaQ > Stop Graph:: Stop DiaQ Graph @]

Updating Dialogue Screen

If you run the game now you will still see the default text and buttons of the Dialogue Screen. We will now look at the changes needed to update this screen. Open the Blox Editor for the Screens System. This can be done by either going to the screens editor, click on a Button element in one of the screens, and then on the Edit button next to the field where you specify the On Click event; or you can click on project: Assets/plyData/System/ongui (this is the Screens System’s prefab) to see its Inspector and the plyBlox component with the Edit button.

I will add a new Custom Event and call it Refresh Dialogue. I do it as a custom event since there are two events from where the Dialogue must be updated and a simple Trigger Event can be used at those spots when needed.

Refresh Dialogue will look at what node is currently active, remember that the Graph will stop and wait at a blocking node (the Dialogue node) so the currently waiting Dialogue node should be the active one. From this active node we take some data and update the Dialogue Screen with it. All buttons are hidden and then with If Blockds I check how many responses there are and enable the correct number of buttons while also updating the text on the buttons.

[@E:Common > Custom:: Refresh Dialogue@]
[@B:GUI > Screens (plyGame) > Set Text:: Set Text of [H:Set Text oftext:H][V:Set Text oftext:V] on [H:onDialogue:H][V:onDialogue:V] to [@B:Dialogue and Quest > DiaQ > Dialogue Text:: DiaQ Dialogue Text@] @]
[@B:GUI > Screens (plyGame) > Set Visible:: Set [H:SetButton1:H][V:SetButton1:V] on [H:onDialogue:H][V:onDialogue:V] to [H:stateHidden:H][V:stateHidden:V] @]
[@B:GUI > Screens (plyGame) > Set Visible:: Set [H:SetButton2:H][V:SetButton2:V] on [H:onDialogue:H][V:onDialogue:V] to [H:stateHidden:H][V:stateHidden:V] @]
[@B:GUI > Screens (plyGame) > Set Visible:: Set [H:SetButton3:H][V:SetButton3:V] on [H:onDialogue:H][V:onDialogue:V] to [H:stateHidden:H][V:stateHidden:V] @]
[@C:Flow > Condition > If:: If [@B:Flow > Comparison > a >= b:: [@B:Dialogue and Quest > DiaQ > Dialogue Response Count:: DiaQ Dialogue Response Count@] >= [@B:Common > Values > Integer:: [H:Value1:H][V:Value1:V] @] @] @]
    [@B:GUI > Screens (plyGame) > Set Text:: Set Text of [H:Set Text ofButton1:H][V:Set Text ofButton1:V] on [H:onDialogue:H][V:onDialogue:V] to [@B:Dialogue and Quest > DiaQ > Dialogue Response Text:: DiaQ Dialogue Response Text# [@B:Common > Values > Integer:: [H:Value0:H][V:Value0:V] @] @] @]
    [@B:GUI > Screens (plyGame) > Set Visible:: Set [H:SetButton1:H][V:SetButton1:V] on [H:onDialogue:H][V:onDialogue:V] to [H:stateVisible:H][V:stateVisible:V] @]
[@C:  end  @]
[@C:Flow > Condition > If:: If [@B:Flow > Comparison > a >= b:: [@B:Dialogue and Quest > DiaQ > Dialogue Response Count:: DiaQ Dialogue Response Count@] >= [@B:Common > Values > Integer:: [H:Value2:H][V:Value2:V] @] @] @]
    [@B:GUI > Screens (plyGame) > Set Text:: Set Text of [H:Set Text ofButton2:H][V:Set Text ofButton2:V] on [H:onDialogue:H][V:onDialogue:V] to [@B:Dialogue and Quest > DiaQ > Dialogue Response Text:: DiaQ Dialogue Response Text# [@B:Common > Values > Integer:: [H:Value1:H][V:Value1:V] @] @] @]
    [@B:GUI > Screens (plyGame) > Set Visible:: Set [H:SetButton2:H][V:SetButton2:V] on [H:onDialogue:H][V:onDialogue:V] to [H:stateVisible:H][V:stateVisible:V] @]
[@C:  end  @]
[@C:Flow > Condition > If:: If [@B:Flow > Comparison > a >= b:: [@B:Dialogue and Quest > DiaQ > Dialogue Response Count:: DiaQ Dialogue Response Count@] >= [@B:Common > Values > Integer:: [H:Value3:H][V:Value3:V] @] @] @]
    [@B:GUI > Screens (plyGame) > Set Text:: Set Text of [H:Set Text ofButton3:H][V:Set Text ofButton3:V] on [H:onDialogue:H][V:onDialogue:V] to [@B:Dialogue and Quest > DiaQ > Dialogue Response Text:: DiaQ Dialogue Response Text# [@B:Common > Values > Integer:: [H:Value2:H][V:Value2:V] @] @] @]
    [@B:GUI > Screens (plyGame) > Set Visible:: Set [H:SetButton3:H][V:SetButton3:V] on [H:onDialogue:H][V:onDialogue:V] to [H:stateVisible:H][V:stateVisible:V] @]
[@C:  end  @]

Still in the Screens System’s Blox the first place to call the refresh event from is when the Dialogue Screen becomes visible. Recall that I first started the graph and then made the call to show the dialogue screen. This will cause the graph to run up to a point where it blocks before the dialogue screen becomes visible. In the On Screen Shown event I will check if it is the Dialogue screen that becomes visible and trigger the refresh event.

[@E:GUI > On Screen Shown:: On Screen Shown@]
[@C:Flow > Condition > If:: If [@B:Flow > Comparison > String: a = b:: [@B:Variables > Temp Variables > Get Temp String:: [H:GetscreenName:H][V:GetscreenName:V] as String @] = [@B:Common > Values > String:: [H:ValueDialogue:H][V:ValueDialogue:V] @] @] @]
    [@B:Flow > System > Trigger Event:: Trigger Event [@B:Common > Values > String:: [H:ValueRefresh Dialogue:H][V:ValueRefresh Dialogue:V] @] in [@B:Self (plyBlox)@] after [@B:-none-@] seconds with param 1= [@B:-none-@] , 2= [@B:-none-@] and 3= [@B:-none-@] @]
[@C:  end  @]

The next spot will be where the player has clicked on a button on the Dialogue Screen as that can potentially lead to a new waiting dialogue node.

Player Response on Dialogue

When making the Dialogue Screen I entered for the On Click field, Dialogue Response and param1 was set to either 0, 1, or 2 depending on which of the 3 buttons it where. The Dialogue Node will expect the number send to start at (0) representing the 1st response. I will now create that Dialogue Response event, inform the active graph of the player’s choice by referring to the value in param1 and then update the Dialogue Screen, just in case a new dialogue node is waiting for a response and I therefore need to show its text and buttons. I’ll also check if the graph did not end and force the player to stop interacting with the NPC so that the Dialogue Screen will close.

The Send Data to Node Block is used to send data to the waiting node. I know it is a Dialogue Node that is waiting and that it is expecting an Integer value, starting at (1) and representing the responses as edited in the Dialogue Node’s Inspector. I’ll simply pass on the value from param1 as an Integer as I’ve entered the correct values for it in each Button Element’s properties.

I’ll use Update Graph to force it to continue running after the response was send to it. This will cause the Graph to run till it ends or encounters another blocking node. This all happens before the rest of the Blocks of this event is called, which is good since I need to know whether to close the dialogue or update it.

Checking is easy, simply check if there is a waiting node and if not, stop interaction. The Has Waiting Node Block will return False if there is no waiting, or more likely, the Graph is done and inactive. The Set Selected Block can be used to clear the Player’s target and thus force interaction with the NPC to stop. This will lead to the On Interact Stopped event being triggered, which will close the Dialogue Screen.

[@E:Common > Custom:: Dialogue Response@]
[@B:Dialogue and Quest > DiaQ > Send Data to Node:: Send Data to DiaQ Node [@B:Variables > Temp Variables > Get Temp Int:: [H:Getparam1:H][V:Getparam1:V] as Integer @] @]
[@B:Dialogue and Quest > DiaQ > Update Graph:: Update DiaQ Graph @]
[@C:Flow > Condition > If:: If [@B:Dialogue and Quest > DiaQ > Has Waiting Node:: DiaQ Has Waiting Node@] @]
    [@B:Flow > System > Trigger Event:: Trigger Event [@B:Common > Values > String:: [H:ValueRefresh Dialogue:H][V:ValueRefresh Dialogue:V] @] in [@B:Self (plyBlox)@] after [@B:-none-@] seconds with param 1= [@B:-none-@] , 2= [@B:-none-@] and 3= [@B:-none-@] @]
[@C:Flow > Condition > Else:: Else @]
    [@B:Character > Control (plyRPG) > Set Selected:: Set selected of [@B:Character > Common (plyRPG) > Player:: Player@] to [@B:-null-@] [H:Cache targetFalse:H]@]
[@C:  end  @]

If I now run the game the dialogue screen should update correctly and close when expected.

Create Bears for the Quest

Now we will look at creating Bears that the Player must kill for the Quest. I’ll create a Bear NPC and make it into a prefab the place two of them in the scene for the player to kill. Creating the monster NPCs are outside the scope of this guide, have a look at the documentation and other guides to learn more.

In the Bear’s On Actor Death event I will send a message to DiaQ to inform it that a Bear was killed. Telling it that the condition with key KilledBear should be updated by (1), meaning, add one to whatever count it has since one bear was killed just now.

[@E:plyRPG > Actor > On Actor Death:: On Actor Death@]
[@B:Dialogue and Quest > DiaQ > Update Quest Condition:: Update Quest Condition [@B:Common > Values > String:: [H:ValueKilledBear:H][V:ValueKilledBear:V] @] with [@B:Common > Values > Integer:: [H:Value1:H][V:Value1:V] @] @]

If the player kill the bears now nothing will happen since there is no way for the player to “get the quest” yet. I need to fix the graph. So back to the graph editor.

The Final Graph

The Quest NPC’s Graph should check if the player has the quest, if not she should ask if he wants the quest and give it to him. If the quest has been completed then the NPC should give the player his reward. If the player returns later and already received the quest reward then the NPC knows there is nothing else to talk about since the payer did all the quests she had for him.

Now the player can receive the quest, kill the bears and receive his rewards. You can check if the XP and Currency updated by checking the debug info in the player character’s inspector at run-time.

Using Inline Values

Since DiaQ 2.0.5 it is now possible to insert variable values into text like the Dialogue text. This allows you to pull data from other sources, like plyBlox, and insert the data into the text. In this quick update I will show you how the initial greeting Dialogue Node can be changed to show the player name.

First we will need a plyBlox Global Variable that the data will come from. Open the plyBlox Settings Window where these are defined. menu: Tools > PLYoung > plyBlox > Settings. Add a new String variable and call it PlayerName. I’ve entered a default value Player for this variable so that I can test it without having to first set the variable’s value at run-time.

Where you set this variable to the player name will not be covered here but it would most likely be when you allow the player to create his character and enter his name.

Now we need to create a link to this variable. Open the DiaQ Settings Window, menu: Tools > PLYoung > DiaQ > Settings. Add a new Inline Value with the (+) button and name is name. The names you enter for values here should be unique from each other and not contain a space or the characters { and }.

Click on the button next to the value so that you can specify where the data comes from. In the window that comes up you select plyBlox as the provider of the data and will then see further options. I’ve selected to get data from a Global Variable and entered the variable’s name, PlayerName.

Now we can use the inline value named name in any DiaQ text that supports inline values. The Dialogue Node text and Quest text as well as Dialogue Node responses supports this. Click on the greeting dialogue node and change the text to now make use of the inline value. Hello {name}, would you like to do a quest?

If I now run a test I should see the text {name} replaced with whatever value is in the plyBlox Global Variable PlayerName.


Comment on this Guide

--eof--