Difference between revisions of "Scripting tutorial lever"

489 bytes added ,  09:09, 2 April 2014
m
imported>Fg109
imported>Karea
 
(3 intermediate revisions by one other user not shown)
Line 1: Line 1:
[[Category:Tutorials]]
[[Category:Community Tutorials]]
[[Category:Scripting]]
[[Category:Papyrus]]
=Lever Scripting Tutorial=
=Lever Scripting Tutorial=


In this tutorial, we will be scripting a lever to open one of three doors.  This is my first tutorial, and practically first time editing a wiki, so it's probably not as good as it could be.
In this tutorial, we will be scripting a lever to open one of three doors.  This is my first tutorial, and practically first time editing a wiki, so it's probably not as good as it could be. Please leave comments on the talk page so I know how to make this better.  Is it too long?  Too short?  Not descriptive enough?  Filled with too much unnecessary information?  Did you learn anything about scripting, or did you only learn that you could put this script onto a lever to control 3 doors?


===Lever Design===
===Lever Design===


All levers in the game are basically the same.  Let's take a look at the Dwemer Lever 01.
All levers in the game are basically the same.  Let's take a look at the Dwemer Lever 01 (DweLever01).


[[Image:DwemerLever01.jpg]]
[[Image:DwemerLever01.jpg]]


In the render window, it's shown with the lever in a central position pointing straight up.  However, once it's loaded in the game, the default position is actually pulled down, all the way to the right.  Levers have animations, and these animations can be called by using the scripting functions [[PlayAnimation_-_ObjectReference|PlayAnimation]] or [[PlayAnimationAndWait_-_ObjectReference|PlayAnimation]].  From what I can tell, levers have six animations:
In the render window, it's shown with the lever in a central position pointing straight up.  However, once it's loaded in the game, the default position is actually pulled down, all the way to the right.  Levers have animations, and these animations can be called by using the scripting functions [[PlayAnimation_-_ObjectReference|PlayAnimation]] or [[PlayAnimationAndWait_-_ObjectReference|PlayAnimationAndWait]].  From what I can tell, levers have six animations:


*PushDown
*PushDown
Line 34: Line 39:


<source lang="Papyrus">Scriptname fg109TutorialLeverScript extends ObjectReference</source>
<source lang="Papyrus">Scriptname fg109TutorialLeverScript extends ObjectReference</source>


I put my name in there, because it makes it easier to filter through all the scripts in the scripts folder in order to find my own.  I suggest you do the same.
I put my name in there, because it makes it easier to filter through all the scripts in the scripts folder in order to find my own.  I suggest you do the same.
Line 41: Line 47:
<source lang="Papyrus">Scriptname fg109TutorialLeverScript extends ObjectReference
<source lang="Papyrus">Scriptname fg109TutorialLeverScript extends ObjectReference
{A script that will activate one of three doors, depending on the position of the lever.}</source>
{A script that will activate one of three doors, depending on the position of the lever.}</source>


===Properties and Variables===
===Properties and Variables===
Line 58: Line 65:
ObjectReference property Door03 auto
ObjectReference property Door03 auto
{The last of the doors we can activate.}</source>
{The last of the doors we can activate.}</source>


Obviously, the properties here are to reference the doors that we want to be able to open.  The reason we declared these as properties is because in Papyrus, we aren't allowed to reference anything directly.  Instead, we use properties as placeholders for the things that we actually want to manipulate, and then afterwards we set the values of these properties outside of the script.  This is to make it possible to reuse the same script for multiple items and purposes.
Obviously, the properties here are to reference the doors that we want to be able to open.  The reason we declared these as properties is because in Papyrus, we aren't allowed to reference anything directly.  Instead, we use properties as placeholders for the things that we actually want to manipulate, and then afterwards we set the values of these properties outside of the script.  This is to make it possible to reuse the same script for multiple items and purposes.
Line 71: Line 79:
;The previous position of the lever.</source>
;The previous position of the lever.</source>


Note that comments in curly braces are only allowed for properties and the first line of the script.  For comments in the rest of a script, you need to use semicolons.  We will be using these variables to keep track of the position of the lever.  You might notice that the declaration for the variable "LeverPosition" is different than for "LeverPositionOld".
 
We will be using these variables to keep track of the position of the lever.  You might notice that the declaration for the variable "LeverPosition" is different than for "LeverPositionOld".


What we have done is assign a default value to "LeverPosition".  This means that even before anything has happened, the value of "LeverPosition" has already been changed to 1, instead of the default of 0.  The reason for this is because of what I said in the previous section on levers.
What we have done is assign a default value to "LeverPosition".  This means that even before anything has happened, the value of "LeverPosition" has already been changed to 1, instead of the default of 0.  The reason for this is because of what I said in the previous section on levers.
Line 78: Line 87:


That is it for the properties and variables.  Now we move onto the actual work of the script.
That is it for the properties and variables.  Now we move onto the actual work of the script.
{{WarningBox|Comments in curly braces are only allowed for properties and the first line of the script.  For comments in the rest of a script, you need to use semicolons.}}


===Events and Functions===
===Events and Functions===
Line 86: Line 99:


Let's start by defining our functions.  Our events are going to be calling on our functions, so I feel it's a better idea to put these first.
Let's start by defining our functions.  Our events are going to be calling on our functions, so I feel it's a better idea to put these first.


<source lang="Papyrus">Function SetDefaultState()
<source lang="Papyrus">Function SetDefaultState()
Line 115: Line 129:
endif</source>
endif</source>


check to see if the lever is in position -1 (pushed to the left) and returns it to the middle position if so.  The OpenDoor is calling a function that we're going to put into the script further down.
check to see if the lever is in position -1 (pushed to the left) and returns it to the middle position if so.  The OpenDoor line is calling a function that we're going to put into the script further down.
 
 
{{InDepth|If you want to learn scripting, you must understand the structure of if-elseif-endif statements.  Basically, you start with "if" to check if a condition is true.  If it is true, then every line after it is executed until you come to either an "elseif" or "endif".  The "elseif" conditional is optional.  It is useful if you want to check for a new condition when you know the previous condition(s) were not true.  Like "if", if the "elseif" condition is true, all the lines after it are executed until you come to another "elseif" or "endif".  The "endif" is used to wrap up all if-elseif-endif structures.  For every "if", you must have an "endif" or else the script won't compile.}}


If you want to learn scripting, you must understand the structure of if-elseif-endif statements.  Basically, you start with "if" to check if a condition is true.  If it is true, then every line after it is executed until you come to either an "elseif" or "endif".  The "elseif" conditional is optional.  It is useful if you want to check for a new condition when you know the previous condition(s) were not true.  Like "if", if the "elseif" condition is true, all the lines after it are executed until you come to another "elseif" or "endif".  The "endif" is used to wrap up all if-elseif-endif structures.  For every "if", you must have an "endif" or else the script won't compile.


This is our next function:
This is our next function:
Line 130: Line 146:


The DisableDoors function is used when we want to disable the doors from normal activation.  Using [[BlockActivation_-_ObjectReference|BlockActivation]] will stop you from opening the door, even though you will still see the open door prompt.  There are other commands we could have used to even disable the activation prompt, but we are trying to keep this as simple as possible.
The DisableDoors function is used when we want to disable the doors from normal activation.  Using [[BlockActivation_-_ObjectReference|BlockActivation]] will stop you from opening the door, even though you will still see the open door prompt.  There are other commands we could have used to even disable the activation prompt, but we are trying to keep this as simple as possible.


<source lang="Papyrus">Function CloseDoors()
<source lang="Papyrus">Function CloseDoors()
Line 154: Line 171:


we close the door by using [[SetOpen_-_ObjectReference|SetOpen]].  We do the same thing for the other two doors.
we close the door by using [[SetOpen_-_ObjectReference|SetOpen]].  We do the same thing for the other two doors.


<source lang="Papyrus">Function OpenDoor()
<source lang="Papyrus">Function OpenDoor()
Line 172: Line 190:


Events are things that happen in the game.  When an event occurs, the script will receive news of it, and if there is code written in the script dealing with the event, it will be carried out.
Events are things that happen in the game.  When an event occurs, the script will receive news of it, and if there is code written in the script dealing with the event, it will be carried out.


<source lang="Papyrus">Event OnReset()
<source lang="Papyrus">Event OnReset()
Line 179: Line 198:


Here we are seeing the code for an [[OnReset_-_Quest|OnReset]] event.  It is received when the object that the script is attached to, or the cell that said object is in, is reset.  When this event is received, the script executes two of the functions we created earlier, SetDefaultState and DisableDoors.
Here we are seeing the code for an [[OnReset_-_Quest|OnReset]] event.  It is received when the object that the script is attached to, or the cell that said object is in, is reset.  When this event is received, the script executes two of the functions we created earlier, SetDefaultState and DisableDoors.


<source lang="Papyrus">Event OnLoad()
<source lang="Papyrus">Event OnLoad()
Line 186: Line 206:


The next event we are looking out for is the [[OnLoad_-_ObjectReference|OnLoad]] event.  It is received when the 3D model of the object that the script is attached to gets redrawn in by the graphics engine.  We tell it to do the same thing as the OnReset event.
The next event we are looking out for is the [[OnLoad_-_ObjectReference|OnLoad]] event.  It is received when the 3D model of the object that the script is attached to gets redrawn in by the graphics engine.  We tell it to do the same thing as the OnReset event.


<source lang="Papyrus">Auto State Inactive
<source lang="Papyrus">Auto State Inactive
Line 216: Line 237:
State Active
State Active
EndState</source>
EndState</source>


And now we have come to the final part of our script, the [[OnActivate_-_ObjectReference|OnActivate]] event.  This event is received when someone tries to activate our lever.
And now we have come to the final part of our script, the [[OnActivate_-_ObjectReference|OnActivate]] event.  This event is received when someone tries to activate our lever.


You might be wondering what are these states that you see.  I'm not sure I can accurately describe them, so it's probably best to check the [[http://www.creationkit.com/States_%28Papyrus%29|States]] page.  Simply put, all scripts/objects have a state.  If there are no states defined in the script, then the object is in the "null" state.
You might be wondering what are these states that you see.  I'm not sure I can accurately describe them, so it's probably best to check the [[States_%28Papyrus%29|States]] page.  Simply put, all scripts/objects have a state.  If there are no states defined in the script, then the object is in the "null" state.


In our script, we had
In our script, we had
Line 236: Line 258:


tells the lever that it is now in the "Active" state as soon as we activate it.  That doesn't mean that the script will stop processing the rest of the code in the "Inactive" state, it just means that subsequent activations don't trigger the code.
tells the lever that it is now in the "Active" state as soon as we activate it.  That doesn't mean that the script will stop processing the rest of the code in the "Inactive" state, it just means that subsequent activations don't trigger the code.


<source lang="Papyrus">CloseDoors()
<source lang="Papyrus">CloseDoors()
if (LeverPosition != 0)
if (LeverPosition != 0)
SetDefaultState()</source>
SetDefaultState()</source>


If you've followed what's been going on so far, this should be easy.  We call the CloseDoors function to make sure all the doors have closed.  If the lever is not in the middle position, we change it to the middle position.
If you've followed what's been going on so far, this should be easy.  We call the CloseDoors function to make sure all the doors have closed.  If the lever is not in the middle position, we change it to the middle position.


<source lang="Papyrus">else
<source lang="Papyrus">else
Line 255: Line 280:
endif</source>
endif</source>


Otherwise, the lever must have been in the middle position.  This is where we check our LeverPositionOld variable to figure out what was the previous position.  Obviously, we don't want to go from right, to middle, back to right.  So if the old lever position was 1 (right), then we now go to the left position.  If the old position was -1 (left), we now go to the right position.
 
If the previous condition wasn't true, then the lever must have been in the middle position.  This is where we check our LeverPositionOld variable to figure out what was the previous position.  Obviously, we don't want to go from right, to middle, back to right.  So if the old lever position was 1 (right), then we now go to the left position.  If the old position was -1 (left), we now go to the right position.


Then we set the value of LeverPositionOld to 0, and call the OpenDoor function.  We didn't have these two lines after
Then we set the value of LeverPositionOld to 0, and call the OpenDoor function.  We didn't have these two lines after
Line 261: Line 287:
<source lang="Papyrus">if (LeverPosition != 0)</source>
<source lang="Papyrus">if (LeverPosition != 0)</source>


because they're already part of the SetDefaultState function. And our final bit of code
because they're already part of the SetDefaultState function.
 
Our final bit of code


<source lang="Papyrus">Utility.Wait(1)
<source lang="Papyrus">Utility.Wait(1)
Line 267: Line 295:


is telling our script to stop processing anything for 1 second (in order to let the animations play out) and then go back to the "Inactive" state (so that activating the lever again will do something).
is telling our script to stop processing anything for 1 second (in order to let the animations play out) and then go back to the "Inactive" state (so that activating the lever again will do something).
===Wrapping Up===


So put all that together, and your script should look something like this:
So put all that together, and your script should look something like this:


<source lang="Papyrus">Scriptname fg109TutorialLeverScript extends ObjectReference
<source lang="Papyrus">Scriptname fg109TutorialLeverScript extends ObjectReference
Line 398: Line 430:
State Active
State Active
EndState</source>
EndState</source>


So save your script and it should compile successfully.  Then you can try it out by putting down a lever somewhere, double-clicking it to edit it, and go to its right-most tab.  You should remove the two scripts that are already on it and replace them with the script you just wrote.  It should look like this:
So save your script and it should compile successfully.  Then you can try it out by putting down a lever somewhere, double-clicking it to edit it, and go to its right-most tab.  You should remove the two scripts that are already on it and replace them with the script you just wrote.  It should look like this:
Anonymous user