-
Notifications
You must be signed in to change notification settings - Fork 18
Papyrus Scripts
<header line>
(<import>|<variable definition>|<struct definition>|<custom event definition>
|<property definition>|<group definition>|<state definition>
|<function definition>|<event definition>)*
A Papyrus script is a text file with the extension ".psc
" that consists of a header line at the beginning of the file, followed by
a collection of imports, Variables, Structures, Properties,
Property Groups, States, Functions, Events, and
Custom Event definitions.
The order of these elements is not important as long as the header line is the first non-comment line in the file.
<Header Line> ::= 'ScriptName' <identifier> ['extends' <identifier>] ['Native'] (<flags>)*
The header line of the script consists of the Language Keyword ScriptName
followed by the Identifier of the script.
The ScriptName
identifier must match the name of the script file.
If the script extends another script, then the name of the script is followed by the Extends
Language Keyword and the name of the script it extends.
And finally, by any Flags.
Scripts can be specified as native by adding the Native
keyword to the script name line.
This signals that the object is defined as a native object in game, allows the script to define new events, define native functions, and does not allow it to contain any variables or auto properties.
Scripts can be specified as constant by adding the Const
keyword to the script name line.
This signals that the object does not contain any data and the game can throw it away at will.
Const
scripts may not contain any non-constant auto properties, states, or any variables.
They may also not be stored in object-level variables.
Scripts can be specified as debug only by adding the DebugOnly
keyword to the script name line.
This signals that all functions defined by this script are only for use in debug scripts and they will be removed from release scripts.
Extending another script will let you override its functions and events to do something different, or add additional functionality while keeping the functionality of the older script. The only limitations are that any function or event in the child script whose name matches one in the parent script must have the same return type and parameter list.
; MyScript.psc
ScriptName MyScript
; HiddenScript.psc This script is hidden from the editor's normal script list, and extends ParentScript
ScriptName HiddenScript Extends ParentScript Hidden
The rest of the file, after the header, consists of imports, Variables, Custom Events, Properties, Property Groups, States, Functions, and Event in any order. You do not have to define script variables, custom events, properties, functions, states, and events before you use them in the script. Variables in functions and events, however, must be defined before use.
'Import' <identifier>
The "Import" keyword lets you use global functions and structs in a script without prefixing them with the name of the script they are in. It can also be used to let you use scripts in namespaces without having to prefix them with their namespace. Simply use "Import" followed by the name of the script or namespace to import. If a function, struct, or script name then becomes ambiguous, then you will still have to prefix it with the name of the script or namespace which contains the version you want.
; Call MyGlobal() in Utility, with no import
Function MyFunction()
Utility.MyGlobal()
EndFunction
; Call MyGlobal() in Utility, with import
import Utility
Function MyFunction()
MyGlobal()
EndFunction
; Get at MyScript inside the MyNamespace folder, with no import
MyNamespace:MyScript Property MyProp Auto
; Get at MyScript inside the MyNamespace folder, with import
import MyNamespace
MyScript Property MyProp Auto
; Get at MyStruct inside MyScript, which is inside MyNamespace without import
MyNamespace:MyScript:MyStruct Property MyProp Auto
; Get at MyStruct inside MyScript, which is inside MyNamespace, but with import
import MyNamespace:MyScript
MyStruct Property MyProp Auto
Whitespace in Papyrus is unimportant, with the exception of line terminators which are explained below. Whitespace may be inserted anywhere as long as it doesn't split up a Language Keyword, Operator, Literal or similar.
; Valid use of white space (if perhaps not as readable)
x = (10+1* 2 ) as float
; Whitespace between the two equals signs in an equality operator will be interpreted as two equals signs, and fail to compile
x = = 1
; Whitespace between the 10 and 12 is interpreted as two numbers, 10 and 12, and not a single number 1012, and fail to compile
10 12
Papyrus scripts are delineated into lines which determine where one statement ends and another begins.
However, if you have a particularly long statement that you want to put on multiple lines, then you can add a "\
" character to the end of the line and continue it on the next line.
Slash characters inside comments are ignored (because everything in a comment is ignored), but you can put a comment after the slash if you wish
; Two statements separated by a line terminator
x = 1 + 2
y = 2 * 3
; One long statement broken into two lines
x = 1 + 2 \
+ 3 + 4
; Slash in this line is ignored, because it is in a comment \
x = 1 + 2 ; This line isn't inside the above comment
Comments in Papyrus come in three forms: Single line, multi-line, and documentation
<single line comment> ::= ';' <any text> <end of line>
Single line comments start with ";" and go until the end of the line. They consume all text after the semicolon, including any backslash characters that would otherwise let you continue onto the following line.
; A simple single line comment
<multi-line comment> ::= ';/' <any text> '/;'
Multi-line comments start with ";/" and consume any text (including newlines) until it finds "/;"
;/ A simple
Multi-line comment /;
;/ You can also have code in here, if you want to comment it out:
x = 2 * 1
y.DoCoolStuff()
/;
<documentation comment> ::= '{' <any text> '}'
Documentation comments are special and can only appear on the line following a script header, property definition, group definition, struct member definition, or function definition. Documentation comments start at a "{" character and go until the terminating "}" character, including eating newlines and such. These comments show up as tooltips in the editor when you mouse over the script in the script picker, or when mousing over a property or struct member in the property editor.
ScriptName MyCoolScript
{Documentation for my cool script here!
I can even use more then one line...}
int Property MyProperty Auto
{This property is fun, if you set it to 1, watch cool stuff happen!}
Flags are words that can be applied to a Script Specification itself, Properties, Variables, or [Functions. The flags may change how something compiles and provide additional information to the game or Creation Kit.
- Conditional: Flags this script as viewable by the condition system. The Creation Kit will not let you attach more then one conditional script to the same object.
- Const: Flags this script as const. Const scripts may not contain non-const variables, non-const auto properties, or states. Const scripts cannot be stored in script variables.
- DebugOnly: Flags this script as debug-only. All functions in this script will be compiled out in release builds when used in other scripts.
- BetaOnly: Flags this script as beta-only. All functions in this script will be compiled out in final builds when used in other scripts.
- Hidden: Hides this script from the normal list of scripts in the Creation Kit that shows when someone wants to attach a script to an object. This is usually used for things that aren't intended to be attached to anything by the user (like fragments), or by base scripts that don't do anything on their own except to be extended by a non-hidden script.
- Native: Flags this script as native. Native scripts may not contain data or states. Non-native scripts may not define new events or native functions.
- Default: Flags this script as a "default" script. Has no effect other then to be classified as such in the Creation Kit's add script window for ease of finding it.
- Conditional: (Auto properties only) Flags the hidden variable of an auto property to be visible to the condition system. The script must also have the conditional flag. The reason property names are mangled in the Creation Kit is because the Condition System is looking at the hidden variable of an auto property. These backing fields can be viewed in Papyrus Assembly.
- Const: (Auto properties only) Flags this property's value as const. The property's value can only be changed in the editor and will not be loaded from save games (so the editor-given value will always be used, even if saved with a different one)
- Hidden: Hides this property from the property window. Usually used for values you don't want the Creation Kit to change, but which you want other scripts to view.
- Mandatory: Causes the editor to issue a warning if this property isn't filled. Will also show unfilled mandatory properties as red in the property window, and warn the user if they attempt to close the property window without filling said properties.
- Conditional: Flags the variable to be visible to the condition system. The script must also have the conditional flag.
- Const: (non-struct members only): Flags this variable's value as const. The variable's value must be set on the same line it is defined in the script and will not be loaded from save games (so the script-given initial value will always be used, even if saved with a different one)
- Hidden: (struct members only): Hides this variable from the property window. Usually used for values you don't want the Creation Kit to change, but which you want other scripts to view.
- CollapsedOnRef: The group will appear collapsed by default when the properties window is viewed on a reference.
- CollapsedOnBase: The group will appear collapsed by default when the properties window is viewed on a base object.
- Collapsed: The group will always appear collapsed by default
- DebugOnly: Flags this function as debug-only. This function will be compiled out in release builds when called.
- BetaOnly: Flags this function as beta-only. This function will be compiled out in final builds when called.
Functions are units of work that are larger then a single expression, and may take various parameters and return a value to their caller.
<function> ::= <function header>
[<function block>
'endFunction']
Function headers must always be followed by a block and an "EndFunction
" Language Keyword, unless they are native functions (which are exposed by the game).
<function header> ::= [<type>] 'Function' <identifier> '(' [<parameters>] ')' ('global' | 'native')* <flags>*
A function header starts (optionally) with the return type of the function, and is then followed by the name of the function, its parameters (if any), and any modifiers and flags.
The Identifier used to name the function cannot conflict with any other function in the current script. If the identifier matches a function in the parent script, then the return type and parameters much match the parent script's version of the function - and the function will override the parent's function.
The "Global
" flag indicates a function that does not actually run on an in-game object, and has no "Self
" variable.
The "Native
" flag indicates a function that does not have a function body, because the function is implemented by the game itself.
If you add the native flag to a function the game does not expose, the compiler won't complain, but the game will error at you.
The same flag cannot be specified more then once.
- Native functions may not be defined in non-native scripts
- Debug-only functions may be defined by adding "
DebugOnly
" to the end of the function definition line. Any calls to these functions will be removed in release script builds. - Beta-only functions may be defined by adding "
BetaOnly
" to the end of the function definition line. Any calls to these functions will be removed in final script builds.
<parameters> ::= <parameter> (',' <parameter>)*
<parameter> ::= <type> <identifier> ['=' <constant>]
The parameter list is a comma-separated list of types and identifiers that indicate the various parameters that a function takes. Each parameter may be optionally followed by an equals sign and a constant, which indicates that the parameter has a default value. If a parameter has a default value, every parameter after it must also have a default value.
Parameters are essentially Variables the function has access to that the caller gives initial values to.
All three of these "types" will only accept raw string literals and no variables. The compiler will then check the value against some part of the type passed as the previous parameter or, if there is no previous parameter, the type the function was called on.
- ScriptEventName: The compiler will check the string against the list of events that could be sent by the object.
- CustomEventName: The compiler will check the string against the list of custom events that could be sent by the object.
- StructVarName: The compiler will check the string against the list of variable names in the struct.
<function block> ::= <statement>*
The function block contains zero or more Statements. This performs the actual work of the function.
; A simple function that adds the two values together and returns the result
; Global, because it doesn't need a self variable
int Function AddTwo(int a, int b) global
return a + b
endFunction
; A function that increments a value on this script by the specified amount.
; The amount has a default value of 1 (so the caller doesn't have to pass it)
Function IncrementValue(int howMuch = 1)
myValue += howMuch
endFunction
There are two special variables in a function, but only in a non-global one. "Self" refers to the instance of the script that the function is running on, and is useful if you want to pass yourself off to another function somewhere else.
"Parent" is only used to call a parent script's version of a function, in the case where you extend the parent.
; Pass our self off to another function
SomeObject.OtherFunction(self)
; Call the parent's version of DoStuff, ignoring our local definition
Parent.DoStuff()
- Global function:
[<scriptType> '.'] <identifier> '(' [<parameters>] ')'
- Non-global function:
[<expression> '.'] <identifier> '(' [<parameters>] ')'
Calling a function simply involves using the function's Identifier, followed by parenthesis, and any parameters that the function takes. The return value of the function is the result of the function call and can be assigned to a variable, or used to call another function or property.
If you are calling a global function and the function's owning script isn't the current script or isn't imported, then you must prefix it with the name of the script the function resides in.
If you are calling a non-global function and it isn't on yourself, then you must prefix it with the object you want to call it on.
<parameters> ::= <parameter> (',' <parameter>)*
<parameter> ::= [<identifier> '='] <expression>
The parameter list is a comma-separated list of expressions in the same order as the parameters are listed in the function definition. If a parameter is optional, it does not have to be passed (the default value is inserted by the compiler into the call location). You may specify parameters out of order by prefixing the expression with the identifier of the parameter (matching the name of the parameter in the definition) followed by an equals sign.
; Call the function: MyFunction(int a, int b) and get the result and put it in x
x = MyFunction(1, 2)
; Call the function DefaultFunction(float a, float b, float c = 0.0, float d = 1.0) on MyObject,
; but only pass in the first three parameters
MyObject.DefaultFunction(4.0, 2.0, 1.0)
; Call the function DefaultFunction(float a, float b, float c = 0.0, float d = 1.0), but specify
; argument d out of order because we want c to keep the default it has
DefaultFunction(5.0, 2.4, d = 2.0)
; Call the global function MyGlobal() in the Utility script
Utility.MyGlobal()
; Call the global function MyGlobal() in the Utility script in the MyMod namespace
MyMod:Utility.MyGlobal()
Events are special Functions that the game will call when something happens. Note that simply defining an event won't make the game call it, you must follow the name and argument list of an event that the game Category:Events|already sends you
New events may not be defined in non-native objects to avoid typos being recognized as new events.
<event> ::= (<event header> | <remote event header>)
[<function block>
'endEvent']
Function headers must always be followed by a standard Function Block and "EndEvent
", unless they are native (which are handled by the game).
<event header> ::= 'Event' <identifier> '(' [<parameters>] ')' ['Native'] <flags>*
The event header is identical to the Function Header, but does not allow for return types or allow for the "Global
" flag.
<remote event header> ::= 'Event' <object type> '.' <identifier> '(' <sender parameter> [',' <parameters>] ')' ['Native'] <flags>*
The sender parameter must be the same type as the type specified in the event name, and it is followed by the parameters that the event on the remote object sends. The Identifier must be the name of an event defined on the object type, and it must not be defined in a parent object type. In other words, the object type must be the least-derived type that contains the event.
<custom event header> ::= 'Event' <object type> '.' <identifier> '(' <sender parameter> ',' <args parameter> ')' ['Native'] <flags>*
The sender parameter must be the same type as the type specified in the event name, and must be followed by an arguments parameter of type "var[]
".
The Identifier must be the name of the custom event defined in the object type.
The parameters are identical to the function parameter list, but should match the data that the game will send to the event.
A simple activate event handler
Event OnActivate(ObjectReference akActivator)
PlayAnimation("CoolStuff")
endEvent
An example of a remote event handler:
Event ObjectReference.OnActivate(ObjectReference akSender, ObjectReference akActivator)
PlayAnimation("CoolStuff")
endEvent
An example of a custom event handler:
Event MyQuestScript.MyCustomEvent(MyQuestScript akSender, Var[] akArgs)
Debug.Trace("Got MyCustomEvent from " + akSender + " with arguments " + akArgs)
endEvent
'CustomEvent' <identifier>
The "CustomEvent" keyword defines a new custom event that this script can send, kind of like a variable. Whenever someone defines a custom event receiver function, or passes a custom event name to a function, it is checked against this particular element. You cannot define a custom event with the same name as any other function or event in your script, or your parent script.
; Define a MyCustomEvent event
CustomEvent MyCustomEvent
Event special variables are identical to a non-global Function Reference#Special Variables.
Calling events is identical to calling a Function. Remote and custom events may not be directly called. Directly calling an event will not trigger remote events on other scripts.
A "state" is a mode that a script can be put in which will cause different versions of Functions or Events to be called.
<state> ::= ['Auto'] 'State' <identifier>
<function or event>*
'EndState'
A state is defined by using the "State
" Language Keyword (optionally prefixed with "Auto
"), followed by the Identifier that represents the state.
It then contains zero or more functions or events, and ends with the "EndState
" keyword.
By prefixing the state with "Auto
" the script will start in that state (And no OnBeginState will be sent).
Only one state may be auto in a script.
A child script's auto state takes precedence over a parent's, but if the child has no auto state, the parent's will be used.
Any function or event defined outside of a state block is said to be in the "empty state". This is the version of the function that is used when the script is not in any state, or when the current state does not implement an override for a function.
Every function implemented in a state must also be implemented (with an identical name, return type, and parameter list) in the empty state in either the current script or a parent.
To switch a script's state, call GotoState - All Scripts, passing in the name of the state to switch to as a string. The state does not have to exist on the destination script. To switch to the empty state, pass in the empty string.
To get the current state, call GetState - All Scripts. It will return the current state name as a string.
The function or event that is picked to run is determined by the following algorithm.
- Check current script's state for the function.
- Check parent script's state for the function.
- Check current script's empty state for the function.
- Check parent script's state for the function.
; Define a function and a state with an override
int Function MyFunction()
Return 1
EndFunction
State MyState
int Function MyFunction() ; Name, parameters, and return type must match empty state version
Return 2
EndFunction
EndState
Function CallMyFunction()
int x = MyFunction() ; Gets 1 when the script first starts up (not in a state)
GotoState("MyState")
x = MyFunction() ; Gets 2
GotoState("WrongState")
x = MyFunction() ; Gets 1 (fallback because state doesn't exist in this script, but might in a child)
GotoState("")
x = MyFunction() ; Gets 1 (empty state)
EndFunction
; Changing the state in the above example to have MyState be the auto state
Auto State MyState
int Function MyFunction() ; Name, parameters, and return type must match empty state version
Return 2
EndFunction
EndState
; Now x in CallMyFunction() will get 2, 2, 1, 1 because the script starts in MyState
![](media/icon-small.png)
Extension
Features
- Language Definition
- IntelliSense
- Code Navigation
- Refactoring
- Compilation
-
Debugging
- Debug View
- [Debug Console](Debug Console)
- [Assembly View](Assembly View)
Creation Engine
Language
Help