Jump to content

DOWNLOAD MODS

Are you looking for something shiny for your load order? We have many exclusive mods and resources you won't find anywhere else. Start your search now...

LEARN MODDING

Ready to try your hand at making your own mod creations? Visit the Enclave, the original ES/FO modding school, and learn the tricks of the trade from veteran modders...

JOIN THE ALLIANCE

Membership is free and registering unlocks image galleries, project hosting, live chat, unlimited downloads, & more...

Class #2 - Properties


ThomasKaira
 Share

Recommended Posts

 

 

Papyrus 101 Class 2: Properties

 

 

 

Properties are, to put it very briefly, how Papyrus communicates with both the game and itself. The most common usage is to provide the script information on game objects which are themselves provided by the editor, but they can also go well beyond that. Using properties, it is also possible to create shortcuts for groups of functions, allowing for you to perform more using fewer lines of code, and even set up your scripts to talk to each other.

 

Property Basics:

 

The most basic use of Properties is to provide your scripts with references to game objects. Papyrus on its own is blind to everything in the game, and relies entirely on the Creation Kit for which game objects the script is supposed to use.

 

Adding and Filling a Property:

 

In order to set up a script to perform functions and receive data from a game object, you must declare it as a Property. There are two ways to do this; the first is to add the Properties through the Creation Kit, which is much easier for beginners and a good way to get a handle on how the Creation Kit interacts with properties. This is accomplished via the following steps:

 

1. Attach your script to an object in the game (see the Papyrus Basics tutorial for instructions on how to do this). Your script will then be displayed in the Papyrus Scripts list with a large + sign beside it. This means the script currently contains no defined Properties.

 

Zudhf.jpg

 

2. Select your script, then click the Properties button just to the right of the script.

 

uQxTT.jpg

 

3. With the Properties window open, press the button "Add Property."

 

EUYNu.jpg

 

4. Set up your Property by filling in the provided parameters:

 

a. Type is what type of object or variable your property will be.

 

IqsJ5.jpg

 

b. Name is what you will identify the Property by.

 

SNKR9.jpg

 

c. Documentation String will provide a comment in {} symbols for your property.

 

p5K0p.jpg

 

There are also three checkboxes:

 

a. Array: flags your Property as an Array, meaning you can reference multiple objects with it instead of just one.

b. Hidden will hide the property from the Creation Kit.

c. Conditional will allow you to reference the property in conditions. More on this later.

 

gHTqT.jpg

 

 

:smarty: Smarty says: Do you want to know how to differentiate between your properties and properties added by the Creation Kit? Well, normally, most scripters place their manually created properties at the top of the script. The Creation Kit, however, places its Properties at the bottom. This is fine, unlike in the previous scripting languages; where you declare your variables and properties in Papyrus is not nearly as rigid.

 

The second way is to simply fill in the property manually, which once you gain experience, is much faster than using the Creation Kit's auto-setup. We'll also take the time to explain what exactly you were doing with the settings above. A property is declared like so (this is also what you will see in your script if you ask the Creation Kit to create the Property):

 

<ObjectType> Property <Name> = <OptionalValue> <Flags>

 

Example declaration: ObjectReference property MyObject Auto

 

Whichever way you do it, you will end up with something like this in your actual script:

 

3Cr03.jpg

 

And this in the Properties window in the Creation Kit:

 

i57h9.jpg

 

Once our property has been added to the Script, we must give it a value. In the Creation Kit, this is accomplished by going to the Properties window, selecting the Edit Value button, and choosing what game object we want the property to point to.

 

xOWmz.jpg

 

Notice that a Pencil symbol will appear next to your property once you have defined it.

 

9fb8h.jpg

 

:smarty: Smarty says: Or, if you are feeling lazy, you can name your properties with identical names to the game objects you want to reference with them. If you do this, you can press a button down at the bottom of the window titled "Auto-Fill all" and for every property the Creation Kit finds an equivalent game object for, it will set your property to point to that object automatically.

 

Finally, once you have defined at least one property, you will notice a Pencil symbol has appeared next to your script. This means that your script has defined properties and is ready to be used by the game.

 

RdSKH.jpg

 

:smarty: Smarty says: There are rare cases where you won't need any properties in a script, but you will almost never encounter such a scenario. It is not essential to define properties, or even for your script to contain any properties. 95% of the time, however, you will want them.

 

Property details:

 

To elaborate on the above annotation of a Property:

 

<ObjectType> is the type of game object we want this property to point to, and valid types for this setting can be seen by scrolling through the Object Window in the Creation Kit. So, things like Globals, Weapons, Sounds, Imagespace Modifiers, all of them can be referred to in your script by setting your property to use their Object type. So, a property of the Object type Weapon, for example, would tell Papyrus that you are referring to a Weapon object from the game. The Creation Kit will also filter out any non-weapon objects from the list it provides for you to give the property a specific value (a specific item, in this case). The ObjectType setting also does a lot more than simply tell the Creation Kit what objects to use as potential candidates to fill this property, it also tells the scripting language what functions can be called on the object. Certain functions will be made available and unavailable to you based on what you input as your property's Object type. You can also declare variables as properties. Declaring a variable as a property will allow other scripts to reference and change the value of the property, as opposed to simply declaring the variable, which makes it exclusive to your script.

 

:smarty: Smarty says: Does your property have two brackets ([]) after its object type? That means the property is an array, and when you go to the Creation Kit to add objects to it, you will be presented with a list instead of the normal drop-down. You place up to 128 separate items into this list.

 

<Name> can be anything you want. Make it something easily identified so you can easily tell what this property is.

 

= <OptionalValue> is an optional parameter. It is used to give the property a specific default value inside the script. This is only used for Variable properties.

 

<Flags>; there are four flags available for you to use on your properties: Auto, AutoReadOnly, Hidden and Conditional.

 

Auto is the most common flag for properties, and is used for almost every property you add to your script. There is a lot going on in the background with properties, but when you flag yours as Auto, Papyrus will fill in all that nasty stuff for you. Auto flagged properties will also take advantage of some optimizations, so the game will handle them slightly quicker.

 

AutoReadOnly properties are similar to Auto properties in that, again, Papyrus will do the nasty background stuff for you, but with a couple extras:

 

1. You must provide a default value inside the script by filling in the <Optional Value> parameter, you cannot supply a value through the Creation Kit. Consequently, this means you cannot declare properties that point to game objects as AutoReadOnly, only Variable properties.

2. The property is read-only, meaning its value cannot be changed ever (with one exception).

3. That one exception: normally once the game loads a property, its value is permanently stored in your save. AutoReadOnly properties, however, do not get saved.

 

Example declaration: Bool property MyBool = False AutoReadOnly

 

:smarty: Smarty says: Because the game does not save the values of AutoReadOnly properties, they are one of the few items in your script that are okay to change after the script has been loaded by the game (and therefore saved). They can be quite useful if you are setting up default values for certain items and you want to be able to make changes to them later when you update your mod.

 

Hidden: This flags the property as invisible to the Creation Kit, so it won't show up in the Properties window. If you have a property you have no intention of defining through the Creation Kit, this flag can help keep the list clutter down.

 

Example declaration: Float property MyProperty Auto Hidden

 

Conditional: Conditional properties are properties that you can reference in the Creation Kit's Condition system through the GetVMQuestVariable condition. Useful for passing on information from a script to a quest, you can set up the script to prepare the condition you want to use and feed it to the quest, which can use that information for filtering dialogue, running new AI packages, and so on. It also allows you to change the conditions on-the-fly. There are a few rules in how you use a Conditional property, though:

 

1. Only Auto properties may be flagged Conditional.

2. You must also include a "Conditional" flag in your script"s header, as such: "scriptname myscript extends Quest Conditional."

3. Only one Conditional script may be attached to a game object at any given time.

 

Example declaration: Int property MyProperty Auto Conditional

 

Full Properties:

 

Outside of the above Properties, there is also the Full Property. These are what the game is writing for you in the background with Auto properties. The difference between them and Full Properties is that Full Properties are a bit more flexible with what you can do with them.

 

Full properties are set up as so:

 

 

 
<ObjectType> property <name>

	<ObjectType> Function Get()

		Return Value

	EndFunction

	Function Set(<ObjectType> NewValue)

		Value = NewValue

	EndFunction

EndProperty

:smarty: Smarty says: Remember , you must follow this pattern to the letter with your properties, they are very strict about this. So, what does all the above mean? Well, we've already gone over the stuff on the top line, so let's move into the nitty-gritty. All properties contain at most two basic functions: a Get function and a Set function. You can omit one or the other (but obviously not both) and change the way your property works. Without a Get function, your property is write-only, so you can change value of the property (feed the property on its own a value so it will do what you want it to), but you cannot reference that value, so it is blind to whatever changes are made. It's up to you to make sure it doesn't try to do Bad Things. On the other side, a property without a Set function is read-only. So it can reference other properties, but it can't change them. They are good referencing tools, as you can use them to look at the property values of your script and do things with them without risking changing anything. :smarty: Smarty says: Properties are not just limited to your script. Remember, Properties are public variables, meaning any script can reference any other script's Properties given you follow the correct procedure. We will go over how to do this later. Now, how about the functions themselves? How do we use them? Get() Function: The Get function is meant to take properties and other variables, do stuff with them, then return the results. Example:

 
 Int Function Get()

	If !GetData

		GetData = True

		ReturnVal = <what we want> as Int

	EndIf

	return ReturnVal

EndFunction

This fairly simple Get function is doing the following: If, when it is called, it has not obtained any data (GetData == False), we then tell it that it has obtained data (GetData = True) with the ReturnVal variable being set to what we wanted to grab cast to the function’s return type, in this case, an Int (very important you do this, otherwise your script won't compile). Afterwards, we tell the script to return the value of ReturnVal, so that when we call the property as such: <myvar> = <myfullproperty> Example (using above Get function): Debug.Trace(<MyFullProperty>) The property will spit out what we want. ReturnVal is defined outside of the property, and again, it must match the return type for the property else the compiler will complain. For read-only functions, it is usually not pre-defined. That's really the only thing special about this variable. Other than that, it is treated just like any other variable. :smarty: Smarty says: Getters and read-only properties are a good way to perform mathematical operations that you can easily reference back to later on in the script. If you have a math evaluation you want most of your script to share, for instance, you can set up a read-only property to do that math and supply the results for the rest of the script. You can then easily reference back to that evaluation using the property, and even modify the variables in the math if you want to have different results calculated. Set() Function: The Set function is meant to change data, doing other stuff in between if you so desire. You can also set up your property (usually a write-only) to be isolated, so you can supply it values that the Set function will use to do stuff without actually changing anything else. Here's an example set function:

 
 Function Set(Int NewValue)

	If !SetData

		SetData = True

		ReturnVal = NewValue

	EndIf

EndFunction

Again, same logic as the Get function, if the function has not changed something, tell it that it has now changed something and set the ReturnVal variable to a new value. This will, in turn, change the value of whatever the ReturnVal variable was previously pointing at (if the Property had an equivalent Get function) to the new value. :smarty: Smarty says: A nifty way of using write-only functions is to isolate them from other properties and have your provided value changes adjust internal variables inside the property, allowing you to do different things based on what you set the property's value to. Something like this:

 
Bool property MyProperty

Function Set(Bool NewValue)

	If NewValue

		WhatToDo = True

		;Do something

	Else

		WhatToDo = False

		;Do something  else

	EndIf

EndFunction

EndProperty

Bool WhatToDo = False


<<<break>>>


Function StuffDoDo()

	If(ConditionA)

		MyProperty = True

	Else

		MyProperty = False

	EndIf

EndFunction

Basically, the property checks an internal variable that you supply it in other places in your script (such as the example Function). If this variable returns one value (or, to be more specific, you set the variable to one value), it does something, and if it returns the other value, it does something else. Advanced Property usage: Importing properties from one script to another: A not-very-well-known trick with Properties, building on the fact that they are public variables, it is possible to set up one property to reference and modify the properties of another script without going through an intermediary. This is accomplished by setting the property's return type to the script you want to reference properties from. You then attach the two scripts to the same object, and voila! :smarty: Smarty says: This is a very nifty way to set up inter-script communication. The property would look like this (if you were attaching to a Quest):

 
 ScriptToReference property MyProperty

	ScriptToReference Function Get()

		If !GetData

			GetData = True

			ReturnVal = (Self as Quest) as ScriptToReference

		EndIf

		return ReturnVal

	EndFunction

	Function Set(ScriptToReference NewValue)

		If !SetData

			SetData = True

			ReturnVal = NewValue

		EndIf

	EndFunction

Endproperty

Bool GetData = False

Bool SetData = False

ScriptToReference ReturnVal

The above is perfectly valid. Using it, you can import Property data from one script to another for it to use and modify as needed quickly and efficiently. Setting up a catch-all script to accommodate multiple unique objects: If you want to limit the number of scripts you write for you mod, you can set one up to accommodate several functions (or variants of) for several items, attach it to all the items you want it to work with, and use the Creation Kit's Properties window to tell the script which object is which. Example:

 
scriptname myscript extends ObjectReference

Int property WhatAmI Auto

Event OnActivate(Actor akActionRef)

	If WhatAmI == 1

		;Do Stuff

	ElseIf WhatAmI == 2

		;Do other stuff

	ElseIf WhatAmI == 3

		:Do something completely different

	EndIf

EndEvent

You can then tell the script which object is which by setting the WhatAmI property to 1, 2, or 3 in the Creation Kit depending on which object you want to do what. You can also use Booleans, if that strikes your fancy, but Ints save typing. ;)Performing a global calculation:

 
Int property MyProperty

	Int Function Get()

		ReturnVal = <my math here>

		Return ReturnVal

	EndFunction

EndProperty

 

 

In this case, when the Property's Get function is called, it will perform a mathematical calculation and give you the results. You can even redefine the variables in the math if you want to change the calculations. Very handy if you want to perform a large number of the same math calculation in one script.

 

If you read this far, congrats! Hopefully your head didn't explode. If you have any questions, feel free to post them, and the team here at TESA will try to answer them as best we can.

Link to comment
Share on other sites

  • 10 months later...

Thank you thank you THANK YOU! I've spent hours trying to figure out HOW to make my script run correctly but just couldn't figure it out. What I wanted to do is create a reference to a crafting station located in another cell that could be called upon when the player tries to use an item from their inventory. I got it to work but nothing happened until I realized I needed to use the properties to apply it. I noticed that in the information here and so I tried it, sure enough it worked! Using the item calls upon the crafting menu and it works flawlessly. I so wish I came here before trying the Skyrim Nexus. Good place but honestly people really aren't very helpful even when you ask nicely...

 

So again a big thank you!

Link to comment
Share on other sites

  • 2 years later...
  • 3 months later...
  • 2 years later...
On 24/05/2012 at 3:10 AM, ThomasKaira said:

 

Full Properties:

Outside of the above Properties, there is also the Full Property. These are what the game is writing for you in the background with Auto properties. The difference between them and Full Properties is that Full Properties are a bit more flexible with what you can do with them.

Full properties are set up as so:


<ObjectType> property <name>

	<ObjectType> Function Get()

		Return Value

	EndFunction

	Function Set(<ObjectType> NewValue)

		Value = NewValue

	EndFunction

EndProperty

 

@DarkRiderI know this is a very old thread, but maybe someone will be able to answer my question.

How do you create new types of properties, like skse does? If they did it, we can do it; we just need to know how. :)

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...