A First Look, Part 2
We've left Part I of this Tutorial while being in Stage 20, with the Thief approaching and forcing us to dialogue with him, and we've seen that this happened because of the Thief's Behaviour.
We are at the highlight of the quest, from now on the next stage will be determined by the Player's actions. This reveals the fact that Quest Stages are not always to be executed in order, some of them can be skipped or ignored, and you are free to set and branch you quests as you want.
The conversation the Player will have with the Thief is the Current Dialogue the Thief has, and it is called "TheThiefOfTheDeadDefaultDialogue". To view it you can search it in the Rck Object Viewer or in the Rck AI Editor (Behaviour tab) while having "TheThiefOfTheDead001" selected.
Open it up in the Node Editor and let's take a look.
You should be able to get an idea on what happens, the Dialogue starts with the Entry Node that redirects to an NPC Dialogue Line, the NPC speaks its line and then the player is prompted to say something (After Line = Player Questions).
The quest branches from there, in base of what the player will pick the quest can end in three ways, as we've seen in the beginning of this article. We will analyze every possible outcome that will let the player complete the quest.
1. Stage 30 - Player Kills the Thief
The Player can decide to kill the Thief by selecting the dialogue option "[Attack] Your crimes are unforgivable". Find the option in the Dialogue, and let's analyze what happens next. The end of the question is connected to a NPC Dialogue Line Node, so the Thief will speak a line "This is not your grave, but you are welcome in it". What should happen next, is that the Thief will attack the player, and this is achived via Events in the configuration of the node. Click on "Show/Hide" to reveal the hidden properties and settings, then open the Events.
You will see that there is a Consequence of type "RckAI Add In Faction" which pretty much explains itself, it allows to set an NPC to a determined Faction. The Consequence is configured to Add the NPC with ID "ThiefOfTheDead001" to the Faction with ID "AgainstPlayer".
Setting an NPC to the "AgainstPlayer" Faction will make the NPC attack the Player at sight, which is exactly what we're looking for.
The Dialogue continues with a special Node, which is the Dialogue AI Invoke, this node allows you to call AI Functions from within the Dialogue, the AI that will be changed is obviously the AI that is talking to the Player. Just as we've changed the Behaviour the last time (going from DefaultBehaviour to FollowPlayer) here we are switching Behavior again, this time to the EmptyStatePurpose that will make the NPC standing still. We want him to stand still because as soon as he detects the Player, he switch in Combat and will attack him, because we've set him in the "AgainstPlayer" Faction.
The Dialogue ends with an End Node, which has two Quest Updaters that lets the Player complete the Stage 20 and set the Current Quest Stage to 30.
The Stage 30, if looked in the Quest Editor, doesn't have anything special but the description.
So what happens now is that the Current Quest Stage is 30, the Player has as the current objective "Kill the looter", and the Thief NPC is attacking the Player.
Perfect, now the last thing that we need is to update the quest when the Thief dies.
To do that, we utilize the Quest Script we've seen in the Quest Editor.
A Quest Script is very similiar to the Quest Stage Script we've seen and used before, but it has one big difference. A Quest Stage Script is designed to execute some lines of code and then get destroyed, while the Quest Script runs periodically while a quest is active.
That means that throughout the whole mission, and still right now, every X seconds the Quest Script assigned to this quest was being executed.
The Quest Scripts are useful in the occasion when you don't really know when something needs to happen, while with the case of the Quest Stage Scripts we always knew when something had to happen (we knew for example that the Thief had to spawn after speaking to Mother Nebivia).
So a Quest Script is perfect for our case, since we don't really know at which time the Player will kill the Thief, or if he will at all.
The script we're talking about is "EveryDeadMansNightmareQuestScript" and it is fundamentally very simple, altrough it is a little bit longer. If you've understood the previous Scripts, you shold have no problem getting this too, and once you got it, we're done.
Open the script and let's analyze it.
The first thing that you'll notice is that it utilizes four variables:
bool doonce = false; bool doonce1 = false; bool doonce2 = false; RckAI thiefofthedead = null;
"doonce(1,2)" are booleans, they are used to ensure that some things only happen once, we will set those variables to true as soon as we execute the lines we want to be executed only once.
"thiefoftheidead" instead, is a reference to the NPC. It let us access to every aspect of the NPC, in our case we will use it to check if the NPC died.
Quest Scripts always have at least two functions:
public void Start()
And
public override void CustomUpdate()
Let's analyze both of them. The first one will allow you to set the value of the questScriptExecutionDelay, which is the X amount of seconds that have to pass for the "CustomUpdate" function to be executed. Not only, the Start calls the function "RunQuestScript()" that will make the script run.
public void Start() { quest.questScriptExecutionDelay = 1f; // CustomUpdate runs every 1 second. RunQuestScript(); // Starts the CustomUpdate }
Let's take a look at the CustomUpdate(): This may look a intimidating at first, but it's actually very simple as well. The first two lines:
if (thiefofthedead == null) CellInformation.TryToGetAI("ThiefOfTheDead001", out thiefofthedead);
Says: if the reference of the NPC is null, try to get it. The code will not go forward this point reference is found and set. The reference will be available to the Quest Script when the Thief NPC will be loaded in the scenes, at the next call of the CustomUpdate() the function "TryToGetAI" will finally get the reference. This is the standard way to get NPC references and it is used widely throughout the whole Demo.
The "else" block runs only if the reference is set, for now ignore the first and last block and focus at the one at the center:
else if(quest.currentQuestStage == 30 && !thiefofthedead.isAlive && !doonce1) { // Progress with quest RCKFunctions.SetQuestStage(quest.questID, 40); RCKFunctions.CompleteQuestStage(quest.questID, 30); doonce1 = true; }
The If condition states "If the Current Quest Stage" (of SQ_EveryDeadMansNightmare obviously) is equal to 30 and "thethiefofthedead" is NOT alive and "doonce1" is false, execute the block below (the "!" means NOT).
What the block below does? Exactly, it lets us continue with the quest. It sets as Current Quest Stage the Stage 40, it completes the Stage 30, and it sets the variable "doonce1" to true to ensure that it will only get executed once.
And that's it. That's this Quest Scripts is all about. We will analyze the other two blocks but you should see that they do pretty much the same thing as this one, but under different conditions.