Difference between revisions of "Your First Quest"

From RPG Creation Kit
Jump to navigation Jump to search
Line 235: Line 235:


== Implementation - Stage 20: The Quest Script ==
== Implementation - Stage 20: The Quest Script ==
'''This section may look long, but it's because everything is explained meticulously,''' '''so do not be afraid!'''
It's time for a script! We've already seen how to update a quest when an NPC dies, that was in the [[A First Look, Part 1|A First Look]] tutorial, here we will see how to effectively create a new [[Quest Script]] from scratch that detects when an NPC (or more than one NPC) dies and updates the quest if it was meant to be updated.
It's time for a script! We've already seen how to update a quest when an NPC dies, that was in the [[A First Look, Part 1|A First Look]] tutorial, here we will see how to effectively create a new [[Quest Script]] from scratch that detects when an NPC (or more than one NPC) dies and updates the quest if it was meant to be updated.


Line 258: Line 260:
   }
   }
}
}
</pre>The Quest Script has two parts, a '''Start''' and a '''CustomUpdate'''.
</pre>The Quest Script has two parts, a '''Start''' and a '''CustomUpdate'''. Start gets called as soon as this Quest Script runs, hence as soon as the Quest starts.
 
Start gets called as soon as this Quest Script runs, hence as soon as the Quest starts.


CustomUpdate is called every '''''questScriptExecutionDelay''''' seconds, where '''''questScriptExecutionDelay''''' is a just a value that we can set to decide how often the CustomUpdate code will run.
CustomUpdate is called every '''''questScriptExecutionDelay''''' seconds, where '''''questScriptExecutionDelay''''' is a just a value that we can set to decide how often the CustomUpdate code will run.
Line 273: Line 273:
     RunQuestScript();
     RunQuestScript();
   }
   }
</pre>With this line we've decided that the Quest Script will run its update every second, which is a good thresold between performance and result.
</pre>With this line we've decided that the Quest Script will run its update every '''1''' second, which is a good compromise between performance and result.


The "'''''quest"''''' written there is the Quest Object that contains all the information about the quest, like the stage we're at, the questScriptExecutionDelay, the stages we already completed, the ones we failed and other things. If you type '''''"quest."''''' if you're using Visual Studio the Intellisense should let you see all the fields and property of the quest.
The "'''''quest"''''' written there is the Quest Object that contains all the information about the quest, like the stage we're at, the questScriptExecutionDelay, the stages we already completed, the ones we failed and other things. If you type '''''"quest."''''' if you're using Visual Studio the Intellisense should let you see all the fields and property of the quest.
Let's take a step back and add the data we need to run this script. We know we need to access to the two NPCs, so we need two objects that represents them. To create them, simply add in the top part of the script, outside the blocks those two lines:
'''''Rck AI bandit1;'''''
'''''RckAI bandit2;'''''<pre>
public class ToBreakTheQuietQuestScript : QuestScript
{
  RckAI bandit1;
  RckAI bandit2;
  public void Start()
  {
    [...]
  }
  public override void CustomUpdate()
  {
      [...]
  }
}
</pre>We've just created two objects that will store the information of the bandits, and that information is accessible just like we've accessed the ''questScriptExecutionDelay'' before.
Okay now for the substantial part, we need a way to check if the two NPCs are alive, and if they are both dead we should update the quest. This is something we need to check constantly, so that code will go inside the '''CustomUpdate()''' block. Not only, this is something that we need to check constantly but '''only if the current stage of the quest is 20''', so only if the Player's objective is killing the bandits.

Revision as of 22:15, 8 March 2022

In this tutorial we will use the NPC we've created in the NPCs Creation and the Cell we've created in the Creating your First Cell tutorial to create a fairly simple quest step by step.

Designing the quest

The first thing that we are going to do before actually doing anything is to design the quest. It is a good idea to think about the quest you want to make, the stages and how it should proceed before you actually start implement anything.

In this tutorial our quest is titled "To Break The Quiet", and it will go this way:

We'll encounter Uriel, the NPC we've created in the previous tutorial sitting peacefully outside his shack. If the Player goes and talk to him he will ask for our help. He will say that there are some bandits that are bothering him and stealing in his house, and that shortly they will come back. Additionaly, he'll say that they often setup a camp near his shack. If the Player accepts to help him, the quest will start and he will have to go and clear the Bandit camp, then return to Uriel to let him know all the bandits died. Uriel will then reward him with 200 golds.

Creating the skeleton of the Quest

Let's go ahead and start developing our quest. The first thing you have to do is to organize your project, create a folder and name it "To Break The Quiet", we'll insert everything related to this quest inside this folder.

Go ahead and create a New Quest by right clicking in the project window -> Create -> RPG Creation Kit -> Quests -> New Quest and name it "- [QUEST] To Break The Quiet", then open it in the Quest Window by clicking "Configure Quest" in the Inspector.


Set the name, ID and description of the quest, I'll have:

Quest Name: To Break The Quiet

Quest ID: SQ_ToBreakTheQuiet

Quest Description: I met a man named Uriel that asked for my help, it seems that there are some bandits that are bothering him... I should give him my help.


We don't need to move anything else for now, switch to the "Quest Stages" tab and right click in the list on the left, then click "New" to create a new Quest Stage. Insert the ID of this stage to be 10 and now we have to configure the Quest Stage on the right.

The description will be: Learn more about the Bandits that are bothering Uriel, and I will also check Display Log Entry, because I want this Description to show up on the screen.


Then go ahead and create a new Quest Stage, it will have as ID 20 and the description will state: "Kill all the bandits in the camp West to Uriel's shack". I'll still have checked the Display Log Entry because it is an objective I want the Player to see.

For reference, all the settings of the Quest inside the Quest Window.

Create another stage, Stage 30 and set its description to be: Speak to Uriel to collect your reward, again, this will have Display Log Entry set on true. This one will have the checkbox Complete Quest set to true, since when this stage will be completed, the quest will end.


Now if we analyze those three stages, when played sequentially they describe exactly our quest.

We're done creating the Skeleton of the quest and we now have to create the implementation of it.



Implementation - Entry Point and Dialogue Creation

The first thing that we are going to build for this quest, is Uriel's Default Dialogue, more specifically, this is the dialogue that Uriel will have as soon as he gets instantiated, and the first that will run if the Player speaks to him. The reason why we start with the Dialogue, is that it is the Entry Point of the quest, that simply means it is the thing that will make the quest start.

Create a new folder inside the previous one named "To Break The Quiet" and create a new Dialogue by right clicking in the project window -> Create -> RPG Creation Kit -> Dialogues -> New Dialogue Graph.

An empty Window will open, close it for now and let's rename the file to "[DIALOGUE] UrielsDefaultDialogue". In the Inspector we have to insert an ID for this dialogue that must be unique and not shared with any other ID. I'll insert "DIALOGUE_UrielsDefaultDialogue".

Now you need to do the most important thing, which is Updating the Databases. Check for the tool-bar on the upper-left part of the screen, click on "RPG Creation Kit -> Update All Databases". A short loading will happen, and your new dialogue will be included in the Dialogue Database, also check the console for any error. If there's any, you may have inserted an already used ID, so change the ID and try again.

Now you can double-click on the file or click "Edit Graph" from the Inspector to reopen the Dialogue Window and start making the dialogue.

We've seen how Dialogues work in the previous tutorials, every Dialogue must start with an Entry Node, so let's add it.

Right click anywhere in the Window -> Dialogue System -> Entry, and a new Entry node will appear. We don't need further action for it, so let's go ahead and keep creating our Dialogue.

Connecting two Dialogue Nodes.

I want Uriel to greet the Player as soon as the Dialogue start, and then ask for help. We can have the NPC saying a line with the "NPC Dialogue Line" node, so let's add it. Right click anywhere in the Window -> Dialogue System -> NPC Dialogue Line.

That will add the node inside the Graph, now to make this NPC Dialogue Line the first thing that happens when the Dialogue starts, we need to connect the First Node of the Entry to the Input of the NPC Dialogue Node. You can do this by clicking and holding on the blue "First Node" dot and dragging the line to the blue dot "Input".

Now what we need to do is to fill the information inside the "NPC Dialogue Line" node.

The only thing that is currently displayed is the "Line", which represents the text that will be displayed to the Player while the NPC speaks this line.

So let's fill it, I'll write inside:

"Hail stranger, it's good to see a friendly face around here... after all the bad ones that comes more than often..."

Now you can click on "Show/Hide" to unveil hidden settings.

You can ignore most of the things for now, the "Plain Line" will be set to false since we want this dialogue to stop the Player and use the full interface, it will trigger no Events. You may just want to set the "Line Time", which is the time in seconds that will pass before this line is considered spoken.

Click again on "Show/Hide" to make the Node occupy less space,

The first NPC Dialogue Line settings.

What should happen next is that the Player will have to say something, for doing that we can use the After Line of the NPC Dialogue Line node, click on it and select "Player Questions".

More settings will appear, we can ignore everything for now and jump to the "Player Questions" list, click on the + button two times to add two things the Player will be able to say.

You'll notice that Elements will appear in the list with a violet dot right to them.

Let's open Element 0 by clicking on it.

Here you can configure what you want to say and how questions should appear in the UI. For Element 0 I'll have as question "Is there something wrong?" and it will have the Position 0, that means it will always be on the top of the Dialogue Interface.

For Element 1, the Question will be "I need to go" and the position will be 1.

The checkbox "Delete After Answer" is used for deleting the question from the current dialogue interaction after it has been selected, it is not needed for now.

Perfect, what we need to do now is to tie those things the Player says to responses of the NPC and change of state.

In both cases, we want Uriel to reply, so I'll add two more NPC Dialogue Lines and connect each one with a Player Question.

I want to test if everything is good so far, so I'm going to set the After Line for both to "End Dialogue", so that we can have a correct graph (a correct graph is a Graph that doesn't have empty ports or references and generates no error while being executed) without adding more content to it.

The first NPC Dialogue Line will make the NPC say "Well... there are those bandits that are bothering me... but I'm not sure I should tell you" while the second one will make him say "Goodbye.".

If you did everything correctly so far, you should have this situation:


Dy 3.png

Hit CTRL+S and close the Dialogue Window.

What we need to do now is to assign this Dialogue to be the Default one that Uriel will use, so let's open the Rck AI Editor and let's search for "Uriel001".

Let's go straight to the Behaviour tab and let's change his Current Dialogue to the one we just created:


Dy 4.png


Click SAVE and close the Window.

At this point Uriel has the Dialogue we've just created, and if we'll talk to him he will use it.

So we can load the Main Menu scene and load a savegame prior to when we've meet Uriel (or create a new one). If we reach him and speak to him the dialogue will flow just as we would expect. Make sure to make a savegame now, you'll use it later when the Dialogue will be modified in the next steps.


Dy 5.pngDy 6.png


Implementation - Quest Dealer

We've verified that our Dialogue works perfectly, now all we need to do is to keep adding content to it until it satisfies us.

So let's open the Dialogue again in the Dialogue Window.

The Quest Dealer inside the NPC Dialogue Line.

What we should expand is the line that says "Well... there are those bandits that are bothering me... but I'm not sure I should tell you". In particular, I want this line to be the Quest Dealer, that means that as soon as this dialogue starts to get spoken, the Quest will start.

To do that let's expand the NPC Dialogue Line, click on Show/Hide and we are going to add a new Quest Dealer. Selecte the "New Quest" to be the one we've created and leave all the other settings to default.

Try to load the savegame now, if you select "Is there something wrong?" as soon as the NPC will start speaking, the Quest will be added and the objective displayed. Surely, nothing happens after that, the dialogue just ends, and if you keep talking to him you'll have a bug, the quest will be added two times.

We certainly don't want that, so we need to make sure this line gets played only once, and we can do that by continuing building our dialogue.

At this point we really just have to add NPC Dialogue Lines and Player Questions to form the dialogue.



Implementation - Stage 10

The Stage 10 starts as soon as the quest gets added, and it will be completed by continuing to speak with Uriel.

For this stage, I'll have Uriel describing the bandits and how they tried to attack him, after he'll do that, the quest will be updated since we will have completed this Stage 10, which was "Learn more about the bandits that are bothering Uriel" and the current stage will be Stage 20, which asks the player to kill the bandits inside the camp.

To do that change the After Line of this NPC Dialogue Line to be "NPC_DialogueLine", this allows us to make the NPC say multiple lines back to back. Add a new NPC Dialogue Line inside the Graph and connect it with the Next Line dot, then insert the text that you want Uriel to say.

At this point you just have to use NPC Dialogue Lines, After Lines and Player Question until you come up with a situation like this:


Dy 9.png

As you can see the Dialogue is pretty straightforward, and we want the quest to progress as soon as the last NPC Dialogue Line is played.

So what we'll do is adding Quest Updaters to it.

Click on Show/Hide and in Events add 2 Quest Updaters, one will be needed to complete the Stage 10, the other will be needed to set the current Stage to 20:

Dy 10.png


With this done, go back in the game, if everything is setup correctly when you'll go through the dialogue those things will happen:

  • Quest will be added.
  • Stage 10 will be the current stage.
  • Stage 10 will be completed completed while speaking.
  • Stage 20 will be the current stage.


But there's still a problem, when the dialogue ends, if you speak to Uriel again, he will still say us the same thing, and if we keep going on with the dialogue, the quest will be added again causing a bug, or at least a behaviour we certainly don't want.

And it's reasonable, because we've never told Uriel to change his Dialogue.

To solve this, we simply have to make Uriel change his Dialogue as soon as the previous one is completed, we can do this directly in the Dialogue Graph, using the Change Dialogue Node.

Before adding this node, we need to create the Dialogue we want to switch to. Create a new Dialogue Graph, name it "[DIALOGUE] UrielsWaitingForBanditsToBeDead", set the ID to "DIALOGUE_UrielsWaitingForBanditsToBeDead" , update the databases, and then open it. We are going to create this Dialogue propertly later, for now just insert just an Entry Node and one NPC Dialogue Line that says anything and has as After Line "End Dialogue".

Now let's get back to the UrielsDefaultDialogue, the Change Dialogue Node will go after the last NPC Dialogue Line and it will be followed by an End Node. Notice that the Change Dialogue Node is set to change the dialogue of the NPC who's currently speaking to the one we just created (UrielsWaitingForBanditsToBeDead):

Dy 11.png


This is the standard way to make unique dialogues that needs to be trigger only once, you will find this structure in most of the dialogues of the demo.


Boot the game again from the Main Menu, reach Uriel, speak to him and take his quest. If everything was done correctly, he will only give you the quest once. After the Default Dialogue ended, he will just say one dialogue line (the one you created inside the DIALOGUE_UrielsWaitingForBanditsToBeDead) if you keep talking to him.

Implementation - Stage 20: The Bandit Camp

The cell Virrihael(-2,-2), where the Bandit camp will be created.

Great, we now have a quest and a objective, but we don't have the bandits that Uriel is talking about.

We need to create them and place them somewhere. Let's place them in the corner of the Cell "Virrihael(-2,-2)". You can just setup the place, put some props, furniture or whatever you want.

I've setup a nice little camp like this:

A bit of furniture and Items dropped in the cell Virrihael(-2,-2), where the Bandits will be.


Alright great! Now all we need is to create and place the Bandits in the world. You learnt how to do this in the previous tutorial, the process is not different by any means. Create two NPCs and equip them as you please. Set their IDs to be unique and remember it, we'll use it later.

I'll have for the first NPC "UQBandit001" and for the second "UQBandit002". UQ stands for "Uriel Quest", I tend to use those prefix/suffixes to make sure the IDs will always be unique. Sure you can name them just "Bandit001", but in the future you may add a lot more bandits and lose track, or even worse, end up with duplicated IDs. I'll also set their faction to be "BanditFaction", so they will attack the player as soon as they him. You can view the NPCs "BanditInCamp001" inside the Rck AI Editor to see how I've setup the bandits for the demo.

Great, now that you've created the NPCs, let's place them in the scene. Just drag and drop their prefabs into the scene

Note: the prefabs of the NPCs are inside the folder Assets/RPG Creation Kit/Prefab Library/AI - but you can access to a specifc NPC quickly by clicking on the "Select Prefab" button in the Rck AI Editor.


Update the cell, by clicking on the "CellInfo" GameObject and in the Inspector click on "Update Cell". You may notice that after updating the cell the NPCs prefabs go inside the "AI_Container" GameObject.

The white wireframe sphere representing the Bandits sight.

We now have the camp and the NPCs to kill, if you load any savegame and you'll reach that location, the two bandits will be there and if they are in the "Bandits" factions, they will attack you on sight. You may have this behaviour: the Bandits see you from a very far distance and you may want to reduce that distance. To do that, let's return in the cell where we dropped the bandits.

Notice the big white wireframed sphere, that tells us how far the NPCs can see, and they can clearly see too far. Indeed, it's likely that they'll go and attack the player even before he'll have a chance to notice them.

To reduce their sight, just click on the NPC, look in the Inspector for the "Rck AI" Component and click on the "Perception" tab. From there the values we have to edit are: Radius, Sphere Y Offset, Sphere Z Offset.

  • Radius: represents the radius of the sphere, how big it is.
  • Sphere Y Offset: moves the sphere on the Y axis (you should keep the default value):
  • Sphere Z Offset: moves the sphere on the Z axis (you can set it to be 0 if you want the Bandit to be able to see the Player even if he's behind).
The reduced sight of the NPCs after editing the settings.

Play with those settings a bit and see how they modify the wireframe sphere. I'll set them to be:

Radius = 30

Sphere Y Offset = 1.25

Sphere Z Offset = 25

But you can obviously choose yours as you prefer. You can apply the changes to the prefab as well, so that the edit is permanent.


You should be all set now, reach the NPC and see if everything is alright for you.

Obviously if you tried to kill them the quest didn't progressed, because we haven't done that yet.


Implementation - Stage 20: The Quest Script

This section may look long, but it's because everything is explained meticulously, so do not be afraid!

It's time for a script! We've already seen how to update a quest when an NPC dies, that was in the A First Look tutorial, here we will see how to effectively create a new Quest Script from scratch that detects when an NPC (or more than one NPC) dies and updates the quest if it was meant to be updated.

The structure of the script is extremely simple, you could just replace the IDs to yours and it should work, but it is important that you get how scripting works because it is an essential component of the RCK.

Go in the Quest folder, right click in the Project Window and select "Create -> RPG Creation Kit -> C# -> Quests -> QuestScript.

Name it something meaningful, I'll name it "ToBreakTheQuietQuestScript", open it and let's take a look.

public class ToBreakTheQuietQuestScript : QuestScript
{
  // This will start running the CustomUpdate as soon as the quest starts.
  public void Start()
  {
     RunQuestScript();
  }

  / CustomUpdate runs once every (quest.questScriptExecutionDelay) seconds
  public override void CustomUpdate()
  {
     base.CustomUpdate();

     // Your code here
   }
}

The Quest Script has two parts, a Start and a CustomUpdate. Start gets called as soon as this Quest Script runs, hence as soon as the Quest starts.

CustomUpdate is called every questScriptExecutionDelay seconds, where questScriptExecutionDelay is a just a value that we can set to decide how often the CustomUpdate code will run.

As a matter of fact, that is the first thing we are going to do. By default every Quest Script runs every 5 seconds, but that's too much for what we need to do. That means in the worst case scenario the player will have the quest updated 5 seconds after having killed the bandits. Let's change that.

In the Start block type, before the RunQuestScript() call, add the line "quest.QuestScriptExecutionDelay = 1f;"

  // This will start running the CustomUpdate as soon as the quest starts.
  public void Start()
  {
     quest.questScriptExecutionDelay = 1f;
     RunQuestScript();
  }

With this line we've decided that the Quest Script will run its update every 1 second, which is a good compromise between performance and result.

The "quest" written there is the Quest Object that contains all the information about the quest, like the stage we're at, the questScriptExecutionDelay, the stages we already completed, the ones we failed and other things. If you type "quest." if you're using Visual Studio the Intellisense should let you see all the fields and property of the quest.

Let's take a step back and add the data we need to run this script. We know we need to access to the two NPCs, so we need two objects that represents them. To create them, simply add in the top part of the script, outside the blocks those two lines:

Rck AI bandit1;

RckAI bandit2;

public class ToBreakTheQuietQuestScript : QuestScript
{
   RckAI bandit1;
   RckAI bandit2;

   public void Start()
   {
     [...]
   }

   public override void CustomUpdate()
   {
      [...]
   }
}

We've just created two objects that will store the information of the bandits, and that information is accessible just like we've accessed the questScriptExecutionDelay before.

Okay now for the substantial part, we need a way to check if the two NPCs are alive, and if they are both dead we should update the quest. This is something we need to check constantly, so that code will go inside the CustomUpdate() block. Not only, this is something that we need to check constantly but only if the current stage of the quest is 20, so only if the Player's objective is killing the bandits.