Jump to content
Mattiewagg

[Graduate Thread] Trivia - Matthiaswagg

Recommended Posts

Arrays

Arrays are an incredibly useful tool  that can save you time, many lines of code, and allow for more dynamic usage of scripts.

An array is a type of variable or property - not in the way an Int is a type. It's a modifier of them, essentially.

  1. Int Variable > Int Variable Array

  2. Weapon Property > Weapon Property Arrar
  3. Float Property > Float Property Array
  4. Bool Variable > Bool Variable Array

Etc. An array is a collection of properties/variables. There are various functions to cycle through them and do something to each element.

Arrays can be declared two ways. One, they can be declared by creating a property in the Properties window of your script and checking the Array box when doing so. Or, the variable/property can be declared like so:

Bool[] BoolArray
;or
ObjectReference[] Property ObjRefArray Auto

You can change any property or variable into an array by adding those brackets.

You can't do things to an array like you normally would for a property or variable, since they consist of more than one property/variable (again, elements). Each element is assigned an index - a number (integer) - which is used to do things to that element. The first element in an array is 0, and counts up by 1 from there. This means that the highest element will have an index 1 less than the length of the array. You call upon elements like so:

ObjectReference[] Property ObjRefArray Auto
 
ObjRefArray[0].Disable(); disables the first ObjectReference element in the array

You can put any number in there and have it work, provided there is an element at that index (else, nothing happens and Papyrus will be sad and possibly angry, but it won't break). You can also put in a variable - so let's say I have a list of random potions I want to give the player when my script is initialized (doesn't matter what the script is on, so I'll leave the scriptname part out). I fill an array with all the potions, and then:

Potion[] Property PotionsArray Auto
 
Event OnInit()
Int x = Utility.RandomInt(0, 20); don't leave out 0, it's an index in the array. I'll just pretend there's 20 elements
Game.GetPlayer().AddItem(PotionsArray[x], 1)
EndEvent

There is another function that will allow you to manipulate arrays. It's not exactly a function in that there's no parameter and you don't even have to use parentheses. It's sort of like Self. It's called Length, and is used to get the number of elements in an array.

PotionsArray.Length

You leave out the brackets on the array because you're just calling it on the property itself, not an element. Length is a function/special function for the whole array.

One way to use Length would be something to improve that little script with the potion array we wrote earlier. Rather than picking a range ending at 20 for our integer, which has the problem of needing to be changed each time I add or remove from the array and me needing to know there are that many elements in the array, which I might not always, I can just use PotionsArray.Length and use that as the parameter for the end of the range:

Int x = Utility.RandomInt(0, PotionsArray.Length)

You can combine this method with a While statement to do something to every element in an array with only a few lines of code.

Whiles

I'm not sure if I've mentioned Whiles to you before, but they're sort of like Ifs. They have blocks (begun by While and ended by EndWhile, like If/EndIf). There needs to be a condition in the While declaration - While x > 10, for example. Then, all code within that While block will be run until that condition is no longer true. Be sure to avoid Whiles that will never end. These are called infinite loops and are quite likely to crash the game. Check your conditions, basically. Don't do something like "If 1 < 2†or anything that will always evaluate to true and never change.

Back to Arrays

So, we can combine Whiles with Length to do something to EVERY element in an array with minimal effort. Let's say we have 100 guards that we want to enable. It'd be a pain to have 100 lines of code that "Guard1.Enable()†"Guard2.Enable()†"Guard3.Enable()â€. Even if copy pasting, you'd still need to change the name for each and it would still be 100 lines of code that you could have achieved in 5:

Actor[] Property Guards Auto
Event OnInit(); can be any event or function
Int index = Guards.Length; doesn't have to be called index but I prefer that
While index; while index doesn't = 0
Index -= 1; take 1 away from index - remember, the highest element in an array is 1 less than the length, so we have to start with 1 less than the length to begin with the last element
Guards[index].Enable()
EndWhile
EndEvent

As long as the index isn't at 0 (done), the while will keep looping - subtract from index, enable guard at the new index number. Repeat.

Whole lot better than 100 lines of code, isn't it?

Write me a script extending anything you like which will Kill every actor in an array (however long you like, in whatever event) UNLESS that actor has health bigger than or equal to 50. I'll leave it up to you to find the appropriate functions - I recommend the CK Wiki, as always.

Hint: (Read after you submit your script, but don't change it once

 

Health is an actor value. Look for functions that do things to actor values. If you can't find it, search the wiki for List of Papyrus Functions and Ctrl + F it for ActorValue.

Hint2:

 

There should be an If block inside your While, after the index -= part, checking If the actor in the array has a health LESS than 50 and killing him if so. Remember - unnecessary Elses aren't good. Elses should only be used if you have two situations you want. So, you're only doing something if the health is NOT bigger than or equal to 50, so you check If it's lower than that and then kill.

 

 

Edited by Mattiewagg

Share this post


Link to post
Share on other sites
Scriptname TriviaArrayPractice extends ObjectReference
Actor[] Property HitList Auto
Event OnEquip()
	Int Index = HitList.Length
	While Index
		Index -=1
		Float TargetHealth = HitList[Index].GetActorValue("Health")
		If TargetHealth < 50.0
			HitList[Index].Kill()
		EndIf
	EndWhile
EndEvent

Is this right?

Share this post


Link to post
Share on other sites

I've spoken with 1shoedpunk and I'm going to have a Cyrodiil misc quest held for you.

When we start on quest design, which should be quite soon, we'll be building that quest as we go. I've not chosen the quest yet but I will once we reach that point. You won't have a particular time limit as long as it's done before summer.

Quest design concepts will go something like this:

Quest Design Concepts

Preparation

Quest Stages

Quest Aliases

Quest Dialogue

Quest Objectives

Quest Journal Entries (this may be right after stages)

Connecting the Dots

Radiance (we may discuss this earlier depending on your quest)

Some waiting for your quest to be merged so we can move on, we'll talk more about concepts and I'll help you with any questions you have had

Voice Implementation

It'll be more fluid because I'll be teaching as you go.

Edited by Matthiaswagg
  • reaction_title_1 1

Share this post


Link to post
Share on other sites

Okay, your script to decipher:

Scriptname testScript extends ObjectReference
ObjectReference[] Property array Auto
Int I
Event OnInit()
i = array.Length
EndEvent
Event OnActivate(ObjectReference akActionRef)
     If akActionRef == Game.GetPlayer()
          If (akActionRef as Actor).IsSneaking()
               array.Disable()
               If i == (array.Length - 1)
                    i = 0
               Else 	
                     i += 1		
               EndIf			
               array.Enable()		
          EndIf	
     EndIf
EndEvent
Tell me, to the best of your ability, what this script does (line by line). Then tell me how it might be used (to the best of your ability).

It's not a test, and most scripts will have better naming of variables and commenting so you can figure them out better. I'll show you one with good naming conventions and commenting next so you can see the difference. But script deciphering is an important skill, because you'll have to do it a lot for vanilla and mod scripts so you can find out what they do.

Share this post


Link to post
Share on other sites

Pretty sure I messed up somewhere...  :X

Scriptname testScript extends ObjectReference
ObjectReference[] Property array Auto ;declares an array of object references named array[] as a property
Int I ;declares an integer variable named I
Event OnInit()
i = array.Length ;make variable i equal the length of array[]
EndEvent
Event OnActivate(ObjectReference akActionRef) ;when the object is activated
     If akActionRef == Game.GetPlayer() ;and the activator is the player
          If (akActionRef as Actor).IsSneaking() ;and the player is sneaking
               array.Disable() ;disable array[]
               If i == (array.Length - 1) ;check if i is equal to one less than array[]'s length (on the last object in the array)
                    i = 0 ;make i equal to 0 to go back to the first object in array[]
               Else 	
                     i += 1	;add 1 to current value of i which will move it to the next object in array[]
               EndIf			
               array.Enable() ; enable array[]
          EndIf	
     EndIf
EndEvent
;if the player activates the object while sneaking, array[] will move to the next object and, if on the last object, will cycle back to the first one
  • reaction_title_1 1

Share this post


Link to post
Share on other sites

Pretty sure I messed up somewhere...  :X

Scriptname testScript extends ObjectReference
ObjectReference[] Property array Auto ;declares an array of object references named array[] as a property
Int I ;declares an integer variable named I
Event OnInit()
i = array.Length ;make variable i equal the length of array[]
EndEvent
Event OnActivate(ObjectReference akActionRef) ;when the object is activated
     If akActionRef == Game.GetPlayer() ;and the activator is the player
          If (akActionRef as Actor).IsSneaking() ;and the player is sneaking
               array.Disable() ;disable array[]
               If i == (array.Length - 1) ;check if i is equal to one less than array[]'s length (on the last object in the array)
                    i = 0 ;make i equal to 0 to go back to the first object in array[]
               Else 	
                     i += 1	;add 1 to current value of i which will move it to the next object in array[]
               EndIf			
               array.Enable() ; enable array[]
          EndIf	
     EndIf
EndEvent
;if the player activates the object while sneaking, array[] will move to the next object and, if on the last object, will cycle back to the first one

Perfect! You're right.

 

What are some possible uses for a script like this that you can think of?

Share this post


Link to post
Share on other sites

Oh, well nevermind then.  ^_^

I'm not really sure of the uses (I think it's mostly the sneaking part that's throwing me off). Maybe something to do with some kind of trap?  :shrug:

In this case, the sneaking is just a way to ensure the player actually wants to make the change. 

In reality, it is used as an upgrade script. It allows you to switch out an object when activated to any object - a bunch of objects placed on top of each other, and then filled in an array. It's being used in my and Galandil's submission for the house modding contest. ;) It's used for the throne to change it to any type of throne or chair.

Share this post


Link to post
Share on other sites
Advanced Properties pt. 2
The information I have gathered is from the CK Wiki, fellow modders, and other sources. It does WORK but I'm no expert so I apologize if I get anything wrong.
 
IMPORTANT LINKS:
Property and Scriptname Flags - look at full properties
 
We'll be going over the more advanced parts of properties (and a bit about scriptnames).
 
First, we'll be talking about adding more than just "auto†to your scriptnames/properties. There are a few other flags you can have on your properties:
 
Hidden
Conditional
AutoReadOnly
 
These also can be added to your scriptname (after the extends ____ part):
scriptname ____ extends ______ [flag(s)]
For properties, you add flags:
____ Property ____ [flag(s)]
 
Hidden means that the property or script will not be visible within the CK. So, if you make a script called "mahScript†and make it a hidden script (Scriptname mahScript extends ObjectReference Hidden), you can't find that script from the CK. So if I click "Add†to add a new script and search for mahScript, that will not show up. It's hidden from the CK. You can still find the script in the folder relative to the Skyrim directory, and you can still reference hidden properties like you can from Part 1 of Advanced Properties.
 
This is automatically used for something like Papyrus fragments, which is code for dialogue, packages, auto-generated quest scripts, etc. as they all have completely random names and are mostly generated by the CK and not written.
 
Conditional on a script means that properties defined as Conditional within that Conditional script can have their values checked with a condition function (a condition function will be used a lot later - they are not script commands, but how you condition things in the CK like magic effects, spells, dialogue, and more. The particular one for a script is GetVMScriptVariable, but it won't work on ReferenceAlias scripts. For quest scripts, you have to use GetVMQuestVariable). If you define a script as conditional but none of it's properties as conditional, then they won't be able to be checked via those condition functions. If you define a property as conditional but not the script, then none of the conditional properties in the script can be checked. It has to be like so:
Scriptname conditionalScript extends WhateverYouWant Conditional
 
WhateverType Property conditionalProperty Auto Conditional
You can have more than one conditional property in a script, or just one. Only ones with the conditional flag will be checkable. When creating a property with "New Property†in the script properties box, you have checkboxes for properties to become hidden/conditional as well as for the script itself when making the script. You can use those or just tack it on/remove it in the script as you like.
 
Auto read only is much like a normal property (Auto), except it CANNOT be set. The value of an AutoReadOnly property can only be "gotâ€, not "set†or changed in any way shape or form:
Int Property autoReadOnlyProp AutoReadOnly
 
;event
     int x = autoReadOnlyProp; this works, you're "getting†the value and making x equal to it
     if (autoReadOnlyProp == 86); this works, you're checking if the value of the property is 86
          ;code
     endif
     autoReadOnlyProp = 99999; this will NOT work because you're not allowed to set your variable
;endevent
This will rarely be used - I myself have never used this, and it is unlikely you will ever need to in the average or even semi-complex script. However, if you happen upon an instance where you need a "constant†and unchangeable value for a property, this is what you would use. The initial value of the property is allowed. You cannot change it anywhere, however. And you can't change flags on the fly either so your property will always be the same.
 
==========
 
Now, this brings us to something more complex. Conditional and Hidden were both supplementary flags, which can be added to a property (or both added to a property). AutoReadOnly replaces Auto. So what exactly is "Auto†doing?
 
Auto is the simplest way to declare a property. It means that you can get the value of a property, AND set the value of the property. You can do this whenever you want, however you want. It's usually how you'll want a property used.
 
However, you can manually define your property as well. This means that you can completely control what happens when your property is set and got. So, you could say that propertyA CANNOT be set but it CAN be gotten (this is AutoReadOnly so you could just use that flag instead). Or, it could be set but not got. OR, and this is where it gets really powerful, you can completely define what happens when a property is "set†or "gotâ€. What value is actually got? IS a value even sent, depending on a variable? Perhaps setting a property actually sets the value to 2x what you said to set it to.
 
This isn't used incredibly often, and I haven't found just cause to use it yet. However, when you get into more complex scripting environments, it may be of tremendous use to you. It's another way Properties one-up variables - variables can't be manipulated in this fashion, or have flags. They're simpler, which is a downfall and a benefit.
 
Each Property actually has two little functions built into it. When you declare a property as Auto, this is what it's really saying:
int myValue = 0
int Property ValueProperty
  Function Set(int newValue)
      myValue = newValue
  EndFunction
  int Function Get()
    return myValue
  EndFunction
EndProperty
Two things to note: the first is that omitting one function or the other means that it can't be written to (if removing set - can't be set) or read, like AutoReadOnly vars, (if removing get - can't be got). Secondly, removing a Set function means you can't see the property in the editor and thus can't give it an initial value.
 
Something else is that you NEED to declare a variable that is the same type as your property, such as myValue, and reference that in your property. If you don't, there will be a compiler error. This variable should equal the initial value of your property. If you set the initial value in the editor to be different than the initial value of your internal variable, the initial value of your property will be the one set in the editor, UNTIL you Set your property.
 
So, we could make a Property that cannot be set and, when got, actually gives the value of itself + 5, like so:
int testValue = 0
int Property testProperty
  int Function Get()
    return myValue += 5
  EndFunction
EndProperty
 
Any property or local variable declared outside of events or functions can be called within your property functions. Functions can be called within your property functions. Unless you've only got a ReadOnly function (Get only), make sure you've got a variable like testValue/myValue referenced before. The name can be whatever.
 
However, you cannot declare anymore parameters for Get() or Set(). They absolutely MUST look like this in your property:
  Function Set(int newValue)
     ;stuff
  EndFunction
  int Function Get()
    ;stuff
  EndFunction
 
You'll get compiler errors if you do. 
 
These full properties CAN be called from other scripts, just like any other. (See Advanced Properties Part I for reference.) They can be any type of property.
 
I want you to write me one script with 4 different properties. Name them as you like. These should be Full Properties (the ones right after here). The 1st Full Property should be one that CANNOT be read, but only Set. The 2nd should return the negative version of the newValue when read, and when Set should add 3 to the value stated. The 3rd should only be readable, not writable. The 4th should be a Bool, readable and writable, with a normal write but when read it should return the opposite bool of what is currently is.
 
Then, paste the script here and we'll be all done with scripting lessons, with a few more scripts to write and questions to ask. Then quest design!
 
Sorry it took me so long to get this one to ya.

Share this post


Link to post
Share on other sites
Scriptname TriviaProperties extends ObjectReference

Int Value1 = 0
Int Property Property1
	Function Set(int SetValue1)
		Value1 = SetValue1
	EndFunction
EndProperty
Int Value2 = 0
Int Property Property2
	Function Set(int SetValue2)
		Value2 +=3
	EndFunction
	Int Function Get()
		return -Value2
	EndFunction
EndProperty
Int Value3 = 0
Int Property Property3
	Int Function Get()
		return Value3
	EndFunction
EndProperty
Bool Value4 = False
Bool Property Property4
	Function Set(Bool SetValue4)
		Value4 = SetValue4
	EndFunction
	Bool Function Get()
		If Value4 == False
			return True
		Else
			return False
		EndIf
	EndFunction
EndProperty

Okay. I'm a little iffy on that set function in the second property (feels like I should have done something with SetValue2), and I'm not sure if there's a more efficient way to do that fourth one, but at the very least it compiles without issues.  :shrug:

Share this post


Link to post
Share on other sites

For the second, it was adding 3 to the newVal. So it should have been:

Value2 = (SetValue2 + 3)

For 4, the most efficient way for the reading is the following:

Return !(Value2)

! Means NOT, and since a bool can only be true or false, this will return the opposite of Value2. You can use ! quite often:

If myInt != 5; if not 5

Or:

If !(MyInt == 5); if not 5

It's useful.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×