1,482
edits
imported>Matthiaswagg No edit summary |
m (Convert source tags to syntaxhighlight) |
||
| Line 8: | Line 8: | ||
Essentially, functions are processes that you declare, enclosed within function tags, like so: | Essentially, functions are processes that you declare, enclosed within function tags, like so: | ||
< | <syntaxhighlight lang="Papyrus"> | ||
Function MyFunctionName(Parameters) | Function MyFunctionName(Parameters) | ||
| Line 14: | Line 14: | ||
EndFunction | EndFunction | ||
</ | </syntaxhighlight> | ||
As you can see, their structure is pretty similar to an event. Just like an event, you must declare the beginning and end of an event. Just like an event, you may declare parameters (for example, the OnDeath event has the parameter Actor akKiller). However, function parameters generally function a bit differently than events. Event parameters are usually pre-declared or set to a certain value, which can then be used within the event. An example, again using the OnDeath event: | As you can see, their structure is pretty similar to an event. Just like an event, you must declare the beginning and end of an event. Just like an event, you may declare parameters (for example, the OnDeath event has the parameter Actor akKiller). However, function parameters generally function a bit differently than events. Event parameters are usually pre-declared or set to a certain value, which can then be used within the event. An example, again using the OnDeath event: | ||
< | <syntaxhighlight lang="Papyrus"> | ||
Event OnDeath(Actor akKiller); akKiller is pre-defined as the actor who killed the actor who died | Event OnDeath(Actor akKiller); akKiller is pre-defined as the actor who killed the actor who died | ||
| Line 26: | Line 26: | ||
EndEvent | EndEvent | ||
</ | </syntaxhighlight> | ||
Where's function parameters usually have to be defined when calling the function, like so: | Where's function parameters usually have to be defined when calling the function, like so: | ||
< | <syntaxhighlight lang="Papyrus"> | ||
Event OnInit() | Event OnInit() | ||
| Line 40: | Line 40: | ||
EndFunction | EndFunction | ||
</ | </syntaxhighlight> | ||
Now lets talk about creating your own functions. | Now lets talk about creating your own functions. | ||
| Line 46: | Line 46: | ||
= Basic Custom Functions = | = Basic Custom Functions = | ||
As you may have noticed earlier, function declarations are fairly simple. The structure looks like this: | As you may have noticed earlier, function declarations are fairly simple. The structure looks like this: | ||
< | <syntaxhighlight lang="Papyrus"> | ||
Function FunctionName(Type Parameter) | Function FunctionName(Type Parameter) | ||
| Line 52: | Line 52: | ||
EndFunction | EndFunction | ||
</ | </syntaxhighlight> | ||
So let's break it up really quick. You have to start and end the function with two words - Function to begin it, and EndFunction to end the function. Then, much like a property name, you have the function name. This is how you refer to the function within scripts. Then, you have any parameters enclosed within parentheses, in variable form (since they are variables) - Type VariableName. If you have no parameters, then you simply end the function with parentheses. When you call the function, you'll call it like this: | So let's break it up really quick. You have to start and end the function with two words - Function to begin it, and EndFunction to end the function. Then, much like a property name, you have the function name. This is how you refer to the function within scripts. Then, you have any parameters enclosed within parentheses, in variable form (since they are variables) - Type VariableName. If you have no parameters, then you simply end the function with parentheses. When you call the function, you'll call it like this: | ||
< | <syntaxhighlight lang="Papyrus"> | ||
FunctionName(Parameter) | FunctionName(Parameter) | ||
</ | </syntaxhighlight> | ||
But you won't put in the Type Parameter for parameters. You'll put in what you want the parameter to be. Yet another example, where I have a function called WhatFunction and a string parameter: | But you won't put in the Type Parameter for parameters. You'll put in what you want the parameter to be. Yet another example, where I have a function called WhatFunction and a string parameter: | ||
< | <syntaxhighlight lang="Papyrus"> | ||
Scriptname MyFuncScript Extends Quest; or whatever extension | Scriptname MyFuncScript Extends Quest; or whatever extension | ||
| Line 74: | Line 74: | ||
EndFunction | EndFunction | ||
</ | </syntaxhighlight> | ||
So some of you might be wondering what the purpose of this is. Well, the most basic of custom functions can be used to enclose certain bits of code that you use often in a script, so you can later call on them. So instead of typing this needlessly long script: | So some of you might be wondering what the purpose of this is. Well, the most basic of custom functions can be used to enclose certain bits of code that you use often in a script, so you can later call on them. So instead of typing this needlessly long script: | ||
< | <syntaxhighlight lang="Papyrus"> | ||
Scriptname ThatScript Extends Quest | Scriptname ThatScript Extends Quest | ||
{This script is soo much longer than it should be.} | {This script is soo much longer than it should be.} | ||
| Line 125: | Line 125: | ||
EndEvent | EndEvent | ||
</ | </syntaxhighlight> | ||
You can just add a function to the script to shorten it significantly: | You can just add a function to the script to shorten it significantly: | ||
< | <syntaxhighlight lang="Papyrus">Scriptname ThatOtherScript Extends Quest | ||
Int Count | Int Count | ||
| Line 165: | Line 165: | ||
EndFunction | EndFunction | ||
</ | </syntaxhighlight> | ||
The size of that is significantly reduced, as you can see. However, you could use some parameters to make it more custom. So if you wanted something different to be printed to the screen based on a variable, you could try something like this: | The size of that is significantly reduced, as you can see. However, you could use some parameters to make it more custom. So if you wanted something different to be printed to the screen based on a variable, you could try something like this: | ||
< | <syntaxhighlight lang="Papyrus"> | ||
Scriptname ThatBetterScript Extends Quest | Scriptname ThatBetterScript Extends Quest | ||
| Line 227: | Line 227: | ||
EndFunction | EndFunction | ||
</ | </syntaxhighlight> | ||
Hopefully you understand how this works. When you call the new CountFunction, then you can define the parameter for CountFunction. It exists when you declare it, but it doesn't really have any meaning. When you call CountFunction and set the parameter, then the parameter will equal what you called for that function call. Then, within the function, it checks for the value of PrintWhat, and depending on what you inputted (a word?), it will print a different notification to your game. So that's how you might use the functions - simply to clean up your scripts and save yourself some time. But there are a lot of other ways to use them too. | Hopefully you understand how this works. When you call the new CountFunction, then you can define the parameter for CountFunction. It exists when you declare it, but it doesn't really have any meaning. When you call CountFunction and set the parameter, then the parameter will equal what you called for that function call. Then, within the function, it checks for the value of PrintWhat, and depending on what you inputted (a word?), it will print a different notification to your game. So that's how you might use the functions - simply to clean up your scripts and save yourself some time. But there are a lot of other ways to use them too. | ||
= Returning Functions = | = Returning Functions = | ||
One of the functions you may see more often is a type I call "returning functions". These functions return a value you can use, be it an integer, a form, or even a string. Their structure is a tad different from the ones before. They look like this: | One of the functions you may see more often is a type I call "returning functions". These functions return a value you can use, be it an integer, a form, or even a string. Their structure is a tad different from the ones before. They look like this: | ||
< | <syntaxhighlight lang="Papyrus"> | ||
ReturnType Function FunctionName(Parameters) | ReturnType Function FunctionName(Parameters) | ||
| Line 238: | Line 238: | ||
EndFunction | EndFunction | ||
</ | </syntaxhighlight> | ||
Everything is identical to the prior function structure, except for the ReturnType bit you see. Here, you'll put in the type of value the function will return - the value you'll "get". For example, a function like GetStage would have a ReturnType of Int, since it returns an integer value. Likewise, IsBeingRidden is a bool function, since it returns a value of true or false. Here's one of the examples I seem to love: | Everything is identical to the prior function structure, except for the ReturnType bit you see. Here, you'll put in the type of value the function will return - the value you'll "get". For example, a function like GetStage would have a ReturnType of Int, since it returns an integer value. Likewise, IsBeingRidden is a bool function, since it returns a value of true or false. Here's one of the examples I seem to love: | ||
< | <syntaxhighlight lang="Papyrus"> | ||
Bool Function IsActorCool(Actor WhatActor);tell the function which actor you're calling the function on | Bool Function IsActorCool(Actor WhatActor);tell the function which actor you're calling the function on | ||
| Line 253: | Line 253: | ||
EndFunction | EndFunction | ||
</ | </syntaxhighlight> | ||
The function IsActorCool will return true if the actor I'm calling it on is the player's lover, and false if they are not. This is a pretty common application of returning functions. (No, not getting if an actor is the player's lover, but a bool function like this is pretty common.) Now I'm going to give an example of a more complex function. This function will enable every ObjectReference in an array if it is called at night time (anywhere between 10 PM and 6 AM), and disable all of the ObjectReferences in the array if it is called at day time (anywhere within the range of 6 AM-10 PM). It returns true if it was day time, and false if it was night time. The most common use for this function would be to turn on and off lights, but it could be applied however you want it: | The function IsActorCool will return true if the actor I'm calling it on is the player's lover, and false if they are not. This is a pretty common application of returning functions. (No, not getting if an actor is the player's lover, but a bool function like this is pretty common.) Now I'm going to give an example of a more complex function. This function will enable every ObjectReference in an array if it is called at night time (anywhere between 10 PM and 6 AM), and disable all of the ObjectReferences in the array if it is called at day time (anywhere within the range of 6 AM-10 PM). It returns true if it was day time, and false if it was night time. The most common use for this function would be to turn on and off lights, but it could be applied however you want it: | ||
< | <syntaxhighlight lang="Papyrus"> | ||
Bool Function LightSwitch(ObjectReference[] kArray) | Bool Function LightSwitch(ObjectReference[] kArray) | ||
| Line 285: | Line 285: | ||
EndFunction | EndFunction | ||
</ | </syntaxhighlight> | ||
So hopefully you can see how this works. You call the function, declare the parameter as an ObjectReference array, and the function commences. If the current value of GameHour (a global - you'll have to declare a property for it somewhere else in the script for this function) is more than or equal to 22, which is the equivalent of 10 PM on a 24 hour clock, and if GameHour is less than 6, then it will enable all the lights, fading them in. It does this by cycling through an array. It then returns False, since it was night time. If the global GameHour doesn't meet those conditions, then the lights are disabled, fading out. This is done with the same method as in the other If statement. It then returns True, since it was day time. | So hopefully you can see how this works. You call the function, declare the parameter as an ObjectReference array, and the function commences. If the current value of GameHour (a global - you'll have to declare a property for it somewhere else in the script for this function) is more than or equal to 22, which is the equivalent of 10 PM on a 24 hour clock, and if GameHour is less than 6, then it will enable all the lights, fading them in. It does this by cycling through an array. It then returns False, since it was night time. If the global GameHour doesn't meet those conditions, then the lights are disabled, fading out. This is done with the same method as in the other If statement. It then returns True, since it was day time. | ||
= Global and Native Functions = | = Global and Native Functions = | ||
There are two other tags you can add to functions. The first is "native". It's added like this: | There are two other tags you can add to functions. The first is "native". It's added like this: | ||
< | <syntaxhighlight lang="Papyrus"> | ||
ReturnType FunctionName(Parameters) native | ReturnType FunctionName(Parameters) native | ||
| Line 296: | Line 296: | ||
FunctionName(Parameters) native | FunctionName(Parameters) native | ||
</ | </syntaxhighlight> | ||
A native function means that the function is hard-coded into the game. Functions like GetStage, Kill, and BlockActivation are all native, along with hundreds of others. A native function also means that you can't see the content of the function, because it was hard-coded in and defined elsewhere. The only way to create your own native functions is by making your own SKSE plugin. | A native function means that the function is hard-coded into the game. Functions like GetStage, Kill, and BlockActivation are all native, along with hundreds of others. A native function also means that you can't see the content of the function, because it was hard-coded in and defined elsewhere. The only way to create your own native functions is by making your own SKSE plugin. | ||
Then, there is a global function. A global function is one that can be called from any script, without having to define a property or cast to the script the function is in. For example, EnablePlayerControls is a global function, as is RandomInt. However, you do have to prefix global functions with the name of the script they came from, and a dot when calling them, like so: | Then, there is a global function. A global function is one that can be called from any script, without having to define a property or cast to the script the function is in. For example, EnablePlayerControls is a global function, as is RandomInt. However, you do have to prefix global functions with the name of the script they came from, and a dot when calling them, like so: | ||
< | <syntaxhighlight lang="Papyrus"> | ||
;how you call EnablePlayerControls | ;how you call EnablePlayerControls | ||
Game.EnablePlayerControls() | Game.EnablePlayerControls() | ||
</ | </syntaxhighlight> | ||
EnablePlayerControls is a global (and native) function in the Game script. Therefore, you have to call EnablePlayerControls in Game to use it. However, you don't have to define a property for the Game script. Alternatively, you can import the owning script of the function, like so: | EnablePlayerControls is a global (and native) function in the Game script. Therefore, you have to call EnablePlayerControls in Game to use it. However, you don't have to define a property for the Game script. Alternatively, you can import the owning script of the function, like so: | ||
< | <syntaxhighlight lang="Papyrus"> | ||
;how you call EnablePlayerControls, with Game imported | ;how you call EnablePlayerControls, with Game imported | ||
Import Game | Import Game | ||
EnablePlayerControls() | EnablePlayerControls() | ||
</ | </syntaxhighlight> | ||
I don't recommend importing an outside script unless you are constantly using global functions in that script, since it's not really worth it. As far as I know there's no real speed impact or anything like that when importing, I just think it's only necessary to import when you've got several global functions or multiple instances of one global function in your script. The structure of global functions is like so: | I don't recommend importing an outside script unless you are constantly using global functions in that script, since it's not really worth it. As far as I know there's no real speed impact or anything like that when importing, I just think it's only necessary to import when you've got several global functions or multiple instances of one global function in your script. The structure of global functions is like so: | ||
< | <syntaxhighlight lang="Papyrus"> | ||
ReturnType FunctionName(Parameters) global; you can tack on a native flag after the global, but it wouldn't have a function body then | ReturnType FunctionName(Parameters) global; you can tack on a native flag after the global, but it wouldn't have a function body then | ||
| Line 319: | Line 319: | ||
EndFunction | EndFunction | ||
</ | </syntaxhighlight> | ||
Now, there's one important caveat to global functions: All of the variables used in the function must be defined within the global function. You cannot access any properties from the script that declares the global function, or from any other script. Since you cannot declare properties inside functions, you are limited to using variables from within the function and the parameters of the function. So if we made our LightSwitch function from earlier global, it wouldn't work correctly, since it relies on GameHour being defined outside of the function. There are two ways to rectify this: | Now, there's one important caveat to global functions: All of the variables used in the function must be defined within the global function. You cannot access any properties from the script that declares the global function, or from any other script. Since you cannot declare properties inside functions, you are limited to using variables from within the function and the parameters of the function. So if we made our LightSwitch function from earlier global, it wouldn't work correctly, since it relies on GameHour being defined outside of the function. There are two ways to rectify this: | ||
| Line 327: | Line 327: | ||
So here's how we would achieve method one - just add a very simple parameter so the function declaration looks like this: | So here's how we would achieve method one - just add a very simple parameter so the function declaration looks like this: | ||
< | <syntaxhighlight lang="Papyrus"> | ||
Bool Function LightSwitch(ObjectReference[] kArray, GlobalVariable kGameHour) global | Bool Function LightSwitch(ObjectReference[] kArray, GlobalVariable kGameHour) global | ||
</ | </syntaxhighlight> | ||
Everything else would be the same. Then, when you call the function, it would look something like this: | Everything else would be the same. Then, when you call the function, it would look something like this: | ||
< | <syntaxhighlight lang="Papyrus"> | ||
GlobalVariable Property GameHour Auto; fill this property | GlobalVariable Property GameHour Auto; fill this property | ||
ObjectReference[] Property MyObjects Auto; fill this array property | ObjectReference[] Property MyObjects Auto; fill this array property | ||
| Line 370: | Line 370: | ||
EndFunction | EndFunction | ||
</ | </syntaxhighlight> | ||
= Function Design Tips = | = Function Design Tips = | ||
I'd like to touch upon one last thing before I finish: It's important to be as all-encompassing with your functions as possible. Properties are great because you can have the same script and have the property values differ for that script depending on what it is attached to. Therefore, doing this: | I'd like to touch upon one last thing before I finish: It's important to be as all-encompassing with your functions as possible. Properties are great because you can have the same script and have the property values differ for that script depending on what it is attached to. Therefore, doing this: | ||
< | <syntaxhighlight lang="Papyrus"> | ||
Quest Property MyQuest Auto | Quest Property MyQuest Auto | ||
Int Property StageToSet Auto | Int Property StageToSet Auto | ||
| Line 383: | Line 383: | ||
EndEvent | EndEvent | ||
</ | </syntaxhighlight> | ||
Is better than doing this: | Is better than doing this: | ||
< | <syntaxhighlight lang="Papyrus"> | ||
Quest Property MyQuest Auto | Quest Property MyQuest Auto | ||
| Line 393: | Line 393: | ||
EndEvent | EndEvent | ||
</ | </syntaxhighlight> | ||
Why? Because then, rather than creating dozens of scripts almost identical to the second script with different stages that are being set, you can use one script (the first script) dozens of times with the property StageToSet at a different value for each. | Why? Because then, rather than creating dozens of scripts almost identical to the second script with different stages that are being set, you can use one script (the first script) dozens of times with the property StageToSet at a different value for each. | ||
The same applies to functions, especially global ones that you intend to use in lots of places. So, for example, I'd probably change LightSwitch to a far more versatile version that looks like this: | The same applies to functions, especially global ones that you intend to use in lots of places. So, for example, I'd probably change LightSwitch to a far more versatile version that looks like this: | ||
< | <syntaxhighlight lang="Papyrus"> | ||
Bool Function LightSwitch(ObjectReference[] kArray, GlobalVariable kGameTime, Int LowTime, Int HighTime) global | Bool Function LightSwitch(ObjectReference[] kArray, GlobalVariable kGameTime, Int LowTime, Int HighTime) global | ||
| Line 427: | Line 427: | ||
EndFunction | EndFunction | ||
</ | </syntaxhighlight> | ||
Now, rather than having a set range that the lights or objects will be switched on and off with, or even a set time interval, you can now choose between many different options. You can change the GameHour to GameMonth if you like, or GameYear. Or even any other global, if you felt like it. You could change it to PlayerFollowerCount, though that would be pretty unproductive. And, you can change the hours (or years, or months, etc.) range at which the lights are disabled and enabled. Furthermore, remember that it doesn't have to be lights. Any ObjectReference array will be proccessed. | Now, rather than having a set range that the lights or objects will be switched on and off with, or even a set time interval, you can now choose between many different options. You can change the GameHour to GameMonth if you like, or GameYear. Or even any other global, if you felt like it. You could change it to PlayerFollowerCount, though that would be pretty unproductive. And, you can change the hours (or years, or months, etc.) range at which the lights are disabled and enabled. Furthermore, remember that it doesn't have to be lights. Any ObjectReference array will be proccessed. | ||
There's one last thing: You can have default parameters. For example, the Disable function has a default parameter: | There's one last thing: You can have default parameters. For example, the Disable function has a default parameter: | ||
< | <syntaxhighlight lang="Papyrus"> | ||
Function Disable(bool abFadeOut = False) native | Function Disable(bool abFadeOut = False) native | ||
; the parameter checks if you want the object to fade out of existence rather than just blink out | ; the parameter checks if you want the object to fade out of existence rather than just blink out | ||
</ | </syntaxhighlight> | ||
Usually when disabling objects, you simply call Disable on them like so: | Usually when disabling objects, you simply call Disable on them like so: | ||
< | <syntaxhighlight lang="Papyrus"> | ||
MyObject.Disable() | MyObject.Disable() | ||
</ | </syntaxhighlight> | ||
This will automatically execute your code as if you had called the function like this: | This will automatically execute your code as if you had called the function like this: | ||
< | <syntaxhighlight lang="Papyrus"> | ||
MyObject.Disable(false) | MyObject.Disable(false) | ||
</ | </syntaxhighlight> | ||
It's pretty simple. You just set the variable to a certain value in the parameters like in the above example, and then that will be the default value of that parameter. The structure of the function: | It's pretty simple. You just set the variable to a certain value in the parameters like in the above example, and then that will be the default value of that parameter. The structure of the function: | ||
< | <syntaxhighlight lang="Papyrus"> | ||
ReturnType FunctionName(Parameter = DefaultValue); tack on the global and native flags here if you want | ReturnType FunctionName(Parameter = DefaultValue); tack on the global and native flags here if you want | ||
| Line 451: | Line 451: | ||
FunctionName(Parameter = DefaultValue) | FunctionName(Parameter = DefaultValue) | ||
</ | </syntaxhighlight> | ||
And remember that not all of the parameters have to have default values, you can decide which ones when you declare the function. Example: | And remember that not all of the parameters have to have default values, you can decide which ones when you declare the function. Example: | ||
< | <syntaxhighlight lang="Papyrus"> | ||
Bool Function LightSwitch(ObjectReference[] kArray, GlobalVariable kGameTime, Int LowTime = 6, Int HighTime = 10) | Bool Function LightSwitch(ObjectReference[] kArray, GlobalVariable kGameTime, Int LowTime = 6, Int HighTime = 10) | ||
</ | </syntaxhighlight> | ||
= Some Common Functions = | = Some Common Functions = | ||
| Line 462: | Line 462: | ||
== Disable Array == | == Disable Array == | ||
This is a DisableArray function. It will disable all objects an array of your choice, and fade them out depending on what you input in place of kFadeObject, though by default it won't fade out. It's a global function, though you can delete the global flag, so whichever script you put this function in will be the prefix to the function (i.e. you need to call it like OwningScriptName.DisableArray(MyArray, true) to disable all the objects in MyArray, fading them out.) You could also replace all instances where I used Disable and instead replace it with Enable, if you want this to enable objects rather than disable them. | This is a DisableArray function. It will disable all objects an array of your choice, and fade them out depending on what you input in place of kFadeObject, though by default it won't fade out. It's a global function, though you can delete the global flag, so whichever script you put this function in will be the prefix to the function (i.e. you need to call it like OwningScriptName.DisableArray(MyArray, true) to disable all the objects in MyArray, fading them out.) You could also replace all instances where I used Disable and instead replace it with Enable, if you want this to enable objects rather than disable them. | ||
< | <syntaxhighlight lang="Papyrus"> | ||
Function DisableArray(ObjectReference[] kArray, bool kFadeObject = false) global | Function DisableArray(ObjectReference[] kArray, bool kFadeObject = false) global | ||
| Line 475: | Line 475: | ||
EndFunction | EndFunction | ||
</ | </syntaxhighlight> | ||
== Set Hostile == | == Set Hostile == | ||
This is a SetHostile function. While you can usually use StartCombat, or SetRelationshipRank, sometimes individually they won't work. So SetHostile will set all of these to something that should make an actor target and attack another actor. This is also a global function, so whichever script you put this function in will be the prefix to the function (i.e. you need to call it like OwningScriptName.SetHostile(Actor1, Actor2) to make Actor1 hostile towards Actor2). | This is a SetHostile function. While you can usually use StartCombat, or SetRelationshipRank, sometimes individually they won't work. So SetHostile will set all of these to something that should make an actor target and attack another actor. This is also a global function, so whichever script you put this function in will be the prefix to the function (i.e. you need to call it like OwningScriptName.SetHostile(Actor1, Actor2) to make Actor1 hostile towards Actor2). | ||
< | <syntaxhighlight lang="Papyrus"> | ||
Function SetHostile(Actor kActor, Actor kTarget) global | Function SetHostile(Actor kActor, Actor kTarget) global | ||
| Line 486: | Line 486: | ||
EndFunction | EndFunction | ||
</ | </syntaxhighlight> | ||