Difference between revisions of "A beginner's guide, lesson 7 - Using Scripts in Quests"

Jump to navigation Jump to search
→‎At the Cottage: Changing the scripts
imported>Pyrocow2
m (→‎At the Cottage: clarifying some stuff)
imported>Pyrocow2
(→‎At the Cottage: Changing the scripts)
Line 32: Line 32:
===At the Cottage===
===At the Cottage===


We cannot rely on any information from NPC’s to progress our quest because the courier is dead.
We cannot rely on dialogue to progress our quest because the courier is dead.


We will first of all use the xmarkerheading object we placed in lesson 6 to identify when the PC gets close enough to trigger a stage bump. By placing the marker inside the cottage, you force the player to be in the cell before this gets triggered.  
The next stage bump is done via another addition to the main quest script which will check if the player is inside the cottage or not. We can use the [[GetInCell]] function to do this. If you examine the wiki page, you will see that the usage for that function is:
''[ActorID].''GetInCell CellName
The square brackets indicate that providing an ActorID is optional. In this case, the actor ID will be Player. If you're using the base file provided at the beginning of the tutorial, the cell name will be ''BGModCourierCottage''. If not, it will be whatever you called the cottage cell.


The next stage bump is done via another addition to the quest script. The quest script is used to add small conditional snippets that do useful jobs; In this case we are going to use GetDistance. This in common with all GET functions returns a numerical value. Some Get functions return values which are either 1 (Yes) or 0 (No). For example GetInFaction will return a 1 or 0 depending on whether the reference is in a particular faction or not.
When the character enters the cell we want to move to stage 40. We can use the stage to limit when the active part of the script runs. We first need to add stage 40 in the stage tab. Then add this piece of script to the ''GameMode'' block in ''BGM001QuestScript''.
 
The GetDistance function returns a numerical value which indicates how far away a reference is from a specified point. (Distance is measure in UNITS with one game unit roughly equal to 1.5 cm)
 
We will use the distance 300 which is fairly close to but not necessarily on top of the x marker we made. When the character gets close we want to move to stage 40. We can use the stage to limit when the active part of the script runs. We first need to add stage 40 in the stage tab. Then add this piece of script to the ''GameMode'' block in ''BGM001QuestScript''.


<pre>
<pre>
  If (GetStage BGM001 == 30)
  If (GetStage BGM001 == 30)
   If (Player.GetDistance BGCourierLodgeXMarker <= 300)
   If (Player.GetInCell BGModCourierCottage == 1)
     SetStage BGM001 40
     SetStage BGM001 40
   EndIf
   EndIf
Line 50: Line 48:
</pre>
</pre>


In this case, the quest stage acts as a DoOnce type control.  
In this case, the quest stage acts like a DoOnce type control. During stage 30 of our quest, the game will repeatedly check to see if the player is inside the cottage cell. When the player is finally found inside the cell, the stage will be changed, and this IF block will never be true again (unless the stage is changed back to 30 for some reason).


Now we need to write a bit of script to check if and when the player collects the two clues we left in the cottage.
You can add a journal entry for stage 40 to keep the player updated:
''I found the courier's cottage. I should look around for some clues.''


We have to set up a counter variable which I have called ''QObjectCount'' (a Short). Each time the player adds one of the quest objects to their inventory, we need to bump this counter by one.
Now we need to write a bit of script to handle the two clues we left in the cottage. There's more than one way to do this, but for now we will add a script to each of the clue items, and a couple of new variables to the main quest script.


We also want to know when each item is picked up so we can display a suitable message informing the player to keep looking. Again this is hand holding, and can be left out for a greater challenge and a deeper immersion.
First, add the two new variables into the main quest script:
Short HasAmulet
Short HasPaper


We are going to write some script. Experienced scripters will throw their hands up at the clumsy nature of this bit of the script, but it gets the job done and I believe it is easier to follow the logic of why each line is added in this version.  
Then set up the two Object-type scripts. Open the script editor from the Gameplay menu, and make sure to set the script type before saving.


Perhaps one of the greats will re-write this in a more concise form at some point.
This is the script that will be attached to the torn letter:
<pre>
SCN BGPartialLetterSCRIPT


So we declare the three variables to add to our variable list at the top of the quest script (''BGM001QuestScript''). You will notice that the list keeps growing as we find we need new variables.
Begin OnAdd Player
If (BGM001.HasAmulet == 0)
MessageBox "I found a torn document. I should continue to look for more clues."
Else
SetStage BGM001 50
EndIf
Set BGM001.HasPaper to 1
End
</pre>


Short QObjectCount
And this is the script that will be attached to the amulet:
Short Count1Once
<pre>
Short Count2Once
SCN BGEmbossedAmuletSCRIPT


We will add to the script already inside the current Begin GameMode block. We could always add a new Begin Block, but why add lines that we don’t need. Note the use of indents in an IF statement is purely for clarity and has no bearing on the running of the script.
Begin OnAdd Player
 
If (BGM001.HasPaper == 0)
We want this script to work if the amount of clues (QObjectCount) is less than 2.
MessageBox "I found a strange amulet in the cottage. I should continue to look for more clues."
Once we have both we don’t want it to work.
Else
 
SetStage BGM001 50
So we set an IF condition
EndIf
 
Set BGM001.HasAmulet to 1
If (QObjectCount < 2)
End
 
</pre>
Now we can use a nested IF statement. This is an IF statement within an IF statement. We will also use the && (AND) command. This combines IF conditions so that BOTH must be met for the first bit of script to work. If either or both fail the IF block moves on to any ElseIF, or Else statements. Otherwise it ends that block.
We want to check if the player has a copy of the BGPartialLetter in their inventory (GetItemCount) and that we have never checked this before(Count1Once).
If this is true we add one to the clue counter (QObjectCount) and add one to the DoOnce counter Count1Once.  
This will stop the script from counting this item again the next time it runs (5 secs)
  If (Player.GetItemCount "BGPartialLetter" >= 1) && (Count1Once == 0)
    Set QObjectCount to QObjectCount + 1
    Set Count1Once to 1
  EndIf
 
We repeat this for the second clue item the BGEmbossedAmulet
 
  If (Player.GetItemCount "BGEmbossedAmulet" >= 1) && (Count2Once == 0)
    Set QObjectCount to QObjectCount +1
    Set Count2Once to 1
  EndIf
 
Finally, we add
 
EndIf
 
To finish this whole block
 
It should read.
 
If (QObjectCount < 2)
  If (Player.GetItemCount "BGPartialLetter" >= 1) && (Count1Once == 0)
    Set QObjectCount to QObjectCount + 1
    Set Count1Once to 1
  EndIf
  If (Player.GetItemCount "BGEmbossedAmulet" >= 1) && (Count2Once == 0)
    Set QObjectCount to QObjectCount + 1
    Set Count2Once to 1
  EndIf
EndIf
 
We now have the following bits of info in usable mathematical form.
 
We know when we have both clues - QObjectCount


We know when we have each individual clue - Count1Once and Count2Once
Add these scripts to the appropriate objects by opening up their details window and selecting them from the Script drop-down menu.


We want to display different messages depending on what combination of clues we have. There are four possibilities leading to four simple IF statements.
The scripts are very similar. Here's how they work: [[OnAdd]] is a hook that will be called by the object when it is added to an inventory. If you examine the wiki page for OnAdd, you will see that a parameter can be added so that the block is only triggered when the item is added to a particular inventory. In our case, we want that to be the player's inventory, so we used "OnAdd Player".


The values of the new variable MessageState are just so we can clearly tell them apart.
Then, inside the OnAdd block, we check to see whether or not the player has found the OTHER clue. If the play has NOT found the other clue, we give them a message that tells them to continue looking. If the player DOES have the other clue, they are done looking, and we can bump the quest stage to 50.
I chose 100, 50, 25, and 10. It could be any number you like.
You will need to declare the variable MessageState first.
Do this and then type this script, once again inside the Begin End block.


If (Count1Once == 0) && (Count2Once == 0)
After the check, we change the appropriate quest variable to indicate that the player has found that item.
  Set MessageState to 100
EndIf
If (Count1Once == 0) && (Count2Once == 1)
  Set MessageState to 50
EndIf
If (Count1Once == 1) && (Count2Once == 0)
  Set MessageState to 25
EndIf
If (Count1Once == 1) && (Count2Once == 1)
  Set MessageState to 10
EndIf
 
Now we use the message state to set the on screen message. This part of the script is very clumsy and can be cleaned up. We will do this in lesson eight.
 
Again we need to set some DoOnce variables to stop the messages being displayed again and again. I have called these DoM2Once etc.
 
The first message state can be ignored because we don’t need to prompt them again to search for clues.
 
If (DoM2Once == 0) && (MessageState == 50)
  MessageBox "I have found a strange amulet. I should continue to look for clues"
  Set DoM2Once to 1
EndIf
If (DoM3Once == 0) && (MessageState == 25)
  MessageBox "I have found a torn document. I should look for more clues"
  Set DoM3Once to 1
EndIf
 
The final situation does not require a MessageBox. As the quest journal can convey the message. But we do need to bump the quest stage. Again create stage 50 first.
 
If (DoM4Once == 0) && (MessageState == 10)
  Set DoM4Once to 1
  SetStage BGM001 50
EndIf


This produces a stage bump. Add stage 50 and this journal entry.
Remember to create stage 50, and then add this journal entry for it:


I should now return to see Captain Hubart with these clues
''I found some clues for Captain Hubart to work with. I should return to him in Chorrol.''


Now we can now set up the next bit of interaction with Hubart.  
Now we can now set up the next bit of interaction with Hubart.  
Anonymous user

Navigation menu