Jump to content
Mattiewagg

[Student Thread] Paulibobo - Matthiaswagg

Recommended Posts

Alright. Let's get this started. I believe you have but if you haven't please install the Creation Kit (found under Library>Tools in Steam).
We'll be covering scripting first, as it'll make creation of small and large scriots for use in quests easier, and has a variety of applications not just for quests but also dungeons, NPCs, bosses (unique boss fights), etc.
Now, please read thesetwo tutorials on scripting I linked, if you haven't already. It should help you understand the basics, so what I say should be a little bit comprehensible.   :P
Part 1
Part 2
For scripting, I don't recommend using the built in Creation Kit script editor. It's not all that fun to work with. Especially because if the CK crashes during your writing of a 500 line script, you'll lose all that. If the CK built in editor even lets you write that much. Often it won't. The majority of scripting is done in an exterior program from the CK, except for hooking up your scripts to the game.
Also, syntax highlighting (pretty colors for your code) and auto complete (as you start to write a function or something it'll allow you to autocomplete it, including parameters) and quick compiling will save your life.
So I'm going to highly recommend you install a good text editor for this. Notepad++ and SublimeText 2 are the most well supported editors for Papyrus (Skyrim's scripting language). They're both absolutely free. Sublime Text will ask for you to verify and pay after a free trial, every month or so, but it's not needed to actually pay ever. It's not at all annoying and just a quick Ok every month. I'll briefly outline the pros and cons for you. I'm currently using ST2 though I used NP++ in the past:
Notepad++:
Pros:
- Good support for Skyrim scripting, as well as SKSE functions and SkyUI
- Easy to use
- Nice interface, clean look and good syntax highlighting
- Auto complete is great. Also includes definitions of functions - so it will autocomplete, tell you which mod/script the function is from, what it does (not all definitions are complete but many), and possibly how it's used. This feature is mainly what I miss for NP.
Cons:
- Sort of a pain to set up the quick compiler, which allows you to compile directly from NP++ rather than writing there and then pasting in CK and then compiling there. Note it may just be because I suck really really bad at using the command line/stuff you need to set it up. Some people find it very was, I didnt.
- Can't change color scheme - a few syntax colors to choose from but none radically different
- No extra plugins
Set it up for the CK here: Linky
SublimeText 2:
Pros:
- Super easy to set up
- Support for SKSE, SkyUI, and almost all other SKSE plugins (syntax and autocomplete)
- Changeable color themes
- Autocomplete
- Syntax
- Plugins and more color themes are downloadable with the (free) Package Control. Plugins can be helpful for greater editing of scripts, and color themes are fun to play around with.
Cons:
- Autocomplete doesn't support definitions.
Setup for Sublime Text 2: Linky

I also highly recommend SSE (Skyrim Script Editor). It's newer than the others, but it's got way more features and is easier to set up. It's got all the same features as ST except plugins, and many more:

- Edit existing script
- Create new script from within the editor
- Quick compile with Ctrl+S
- Compilation error/success window
- Filter for opening script with options of "Starts with" and "Contains"
- Auto complete (SKSE support as well)
- Syntax highlighting
- Customization of highlighting colors from within the editor
- Clean, professional look
- Extreme customization of all features
- Easy to use
- Resizable/minimizable code and compilation result windows
- Highlighting of words that are the same as selected
- FileDiff tool to show differences between two scripts
- Bookmarking line feature
- Mark line as green/yellow/red
- Multilanguage support (currently English/French)
- Comment out current line feature
- Line cloning
- Column selecting
- Custom autocompletes
- "Draft" save (save without compiling)
- Code folding
- Macro recording
- Line numbers (toggleable)
- Export to "rtf" or "html"
- Various hotkeys for functions, like Go To Line, Replace, and many more
- Auto update feature or update from within editor (Help>About)
- Online help and support
- Tab functionality, including tab all selected lines
- Copy and paste functionality
- Spellcheck on commented out areas and strings in progress

Whenever you've got that set up, tell me (along with which text editor you've decided to use). Be sure to associate .psc files, which can be found in Data/Scripts/Source with your text editor of choice and when we do begin be sure to create your scripts and then edit by right clicking and selecting Open in External Editor.
Then tell me anything you were confused about on the tutorials and we'll begin from there. I'll explain what was confusing and we'll begin on a task of sorts - your first script. If you have any preference on what you want the script to do (unrelated to quests for now), please tell me. I'll take it into account as a first or later script to do, depending on complexity. Examples are a series of messageboxes w/ choices, a script on an activator to spawn a creature, a trigger box that when entered will disable a wall (or move the wall if we use a hidden door, but it has to contain the animations for this). There are many more, just tell me what comes to mind.

Edited by Mattiewagg
  • reaction_title_1 1

Share this post


Link to post
Share on other sites

Ok, I read the tuturials carefully, but now I encountered a problem. I decided to use SSE, because it seemed to be the one you recomended the most, but after I download it with no problems, I can't launch it. When I try to, it deletes the SkyrimScriptCompilerPro.exe. I've tried repairing it and delting everything and downloaing again, but nothing seems to work. What do I do?

Share this post


Link to post
Share on other sites

Ok, I read the tuturials carefully, but now I encountered a problem. I decided to use SSE, because it seemed to be the one you recomended the most, but after I download it with no problems, I can't launch it. When I try to, it deletes the SkyrimScriptCompilerPro.exe. I've tried repairing it and delting everything and downloaing again, but nothing seems to work. What do I do?

When you run it (the exe) an installer should pop up allowing you to install the program somewhere. Is that not what happens for you?

Share this post


Link to post
Share on other sites

Yea

Ok, I read the tuturials carefully, but now I encountered a problem. I decided to use SSE, because it seemed to be the one you recomended the most, but after I download it with no problems, I can't launch it. When I try to, it deletes the SkyrimScriptCompilerPro.exe. I've tried repairing it and delting everything and downloaing again, but nothing seems to work. What do I do?


When you run it (the exe) an installer should pop up allowing you to install the program somewhere. Is that not what happens for you?

Yeah that happens. But then I install it where it says, and try to open it throught the shortcut that appears on the desktop, (or through the actuall program) and It just does nothing... I'll delte all the files and try again... for the Fifth time...

Share this post


Link to post
Share on other sites

Yea

Ok, I read the tuturials carefully, but now I encountered a problem. I decided to use SSE, because it seemed to be the one you recomended the most, but after I download it with no problems, I can't launch it. When I try to, it deletes the SkyrimScriptCompilerPro.exe. I've tried repairing it and delting everything and downloaing again, but nothing seems to work. What do I do?

When you run it (the exe) an installer should pop up allowing you to install the program somewhere. Is that not what happens for you?

Yeah that happens. But then I install it where it says, and try to open it throught the shortcut that appears on the desktop, (or through the actuall program) and It just does nothing... I'll delte all the files and try again... for the Fifth time...

I'll speak with the author. Just use NP++. It's very strange because it was working for me. I'll test out your issue.

Share this post


Link to post
Share on other sites

After you run SublimeText2 again, go to your Documents folder and open up SublimePapyrus.ini. Make sure all the file paths are correct. If they are, you're all done.

SOmetimes, ST2 may not recognize a Papyrus file. If that is the case, just go to View>Syntax and set it to the proper language (will be called Papyrus or Skyrim).

Share this post


Link to post
Share on other sites

annnnd I apparently did this wrong. I'm sorry. I had installed ST2 before but the latest update had to be installed in a different manner and the instructions in the thread of SublimePapyrus were not updated yet.

They are now. Please delete the Skyrim folder from the Packages folder, and then follow the instructions for loose files here:

http://forums.bethsoft.com/topic/1501719-rel-sublimepapyrus-a-papyrus-package-for-sublime-text-2/

Sorry for the inconvenience. ;)

Share this post


Link to post
Share on other sites

Riddle activator tutorial

Apologies for length, tried to explain thoroughly for this first one at least. Tell me if it's too much or two little so I can adjust the following lessons. When I'm sure you've got a good grasp of scripting,  near the end, I'll have you make this a whole lot more complex so you can see the progress you've made. ;)

EDIT: This one ran incredibly long. Sorry. Still tell me if it was too long or if you prefer this intense level of detail. Again, oops and sorry for the various walls of text. They are important though.

  1. First, we need to create our riddler. This will just be an activator of some sort. I suggest we begin with WETempActivator (open the CK, search in the filter in the category All for WETempActivator). Once you've found it, open up a cell in the Cell View (overview on cell view and other windows). Any cell, just remember the editorID as this is the COC location. Drag the record WETempActivator in after double clicking the cell to open it
  2. Now, we'll create a script. Double click on the WETempActivator IN YOUR CELL VIEW, and DO NOT click the View/Edit Base Object. Instead, keep pressing the right arrow on the little window in the Cell View until you get to Scripts. Press Add, and in the window that pops up, Select [New Script]. Give it a scriptname, and it should extend ObjectReference. Ignore the other parts now, we'll go over those in a later lesson or they may have been covered in the tut you read. If you're curious about the other options, though we will go over most later, feel free to ask.
  3. After you've added your new script, right click it and press Open in External Editor. This should open it in ST2. Paste in the following script (please read it and try to understand, there is an explanation below!):
  4. Scriptname PutTheScriptNameYouChoseHere Extends ObjectReference 
    Message Property RiddleMessage Auto
    MiscObject Property Gold001 Auto
    Spell Property ParalyzeSpell Auto
    Actor Property PlayerREF Auto; if you are going to reference the player more than once, do NOT use Game.GetPlayer but instead use an actor property. It's 1000x faster and best for a variety of reasons to be explained later
    Event OnActivate(ObjectReference akActionRef)       
        Int Choice = RiddleMessage.Show()
        
        If Choice == 0 || Choice == 1; choice first or second choice in list, will be incorrect
        
            ParalyzeSpell.Cast(Self, PlayerREF)
            
        Else;isn't first or second, thus third as we only will define 3 buttons
        
            PlayerREF.AddItem(Gold001, 5000000)
            
        EndIf
        
    EndEvent
    
  5. Pretend this is 4, stupid forum Now I'll explain the script. I'm also going to stop numbering because the forum formatting is stupid.

First off, you've got your scriptname. This is like an editor ID, etc. It's just how your script is identified. The scriptname must be identical to the file name of the script .pex, so make sure you switch out the scriptname in the above script with the one you chose when doing [New Script].

Then we define our properties. You should know what properties are from the tutorials you read earlier - we've got one for our messagebox (type Message); one for our gold (type MiscObject, which is of Book/Armor/Weapon/etc. and is basically an item that doesn't fit into other categories - stuff like little dolls from HF fit into this category); one for our Paralyze spell (type Spell) and one for our player (type Actor, see comment behind colon for explanation why we used that and not Game.GetPlayer - we could have used GetPlayer but wanted to mention this early on).

We will fill these properties after we create the actual things to fill them with.

Then we have our Event. OnActivate is an event sent anytime an activator (container, door, something like WETempActivator, etc.) is activated by ANYTHING. The parameter is a variable that you can access from your script - it's basically info sent along with the event. You don't have to use it but it can often be useful (say doing one thing if the actionRef/thing to activate is the player VS a dog). Everything within our event will be code called when our event is sent. So first, we define a variable of type int (integer = whole number of any type). Because it is defined WITHIN our event, it will ONLY be accessible within that particular event. If I had another event in that script, say OnInit() (called when the object the script is on initializes/loads for the first time), and I tried to access the var Choice, there would be errors. You can declare a variable outside of an event and have it accessible within all events, but if it's declared in one event then it is only accessible in that one event

Now, Message.Show (in this case we replace Message with our Message property) is a function that will show the messagebox or notification that a message property points to. However, it also has a return value. A return value is what value that function gives back when you call it - so you can say THIS VARIABLE = Message.Show, which means that not only will it show the notification, it will ALSO make THIS VARIABLE = to the return value of Show. Show's return value is the choice that the player chose, in the value of an integer. It's a little tricky to get your head around, but once the player chooses a button on the messagebox, the return value will equal the index (explained later when we create our Message) of the button they chose. Using this value, we can do different stuff depending on what the PC chooses. So, we've defined Choice.

We then use conditional phrases (If/ElseIf/Else) to check what the player choice. Firstly, we have If. This means that IF the condition declared after the If evaluates to True, then the code within that If block should be executed. (An If block is from the first If to EndIf. If you have an If/ElseIf thing, then If Conditonal1 is true the first If will be done. Even if ElseIf was also true, only the first If will be chosen. ElseIfs are for multiple choices doing different things. If you want something to happen for everything true, create a set of If blocks.) Our first If condition also uses a LOGICAL OR. A logical or is basically saying If Conditional1 OR Conditional2. So this changes the If - now, if either Conditional1 or Conditional2 is true, then the If will execute. In ours, we check if Choice is 1 or 2. I'll be having the first two buttons be incorrect for you, so this is right. 

Inside that If, we cast the Paralyze spell on the player. Cast is a function to be called on a spell. Calling says that whatever is before the period (.) when you have a function afterwards is what the function is being called on. It's the accusative - if I'm calling Kill ON PlayerREF, that kills the Player. If I'm calling AddItem ON the Donkey, that will add an item to the donkey. The calling reference is not always the same, like with Cast. Cast doesn't have the calling reference as what it should be cast on, but rather what the spell is. So be sure to check (see CreationKit.com). Cast will cast the calling reference (spell) on the person in the second part of the parantheses. These parentheses are parameters that you pass in as direct values or variables. 

The first parameter (must be declared in order, with a small exception) is ObjectReference akSource. Any ObjectReference or type of ObjectReference like an Actor, can be passed in. akSource should equal what is casting the spell. I put in Self because this will say that the activator casts the spell. Self is the value of the reference the script is on in EVERY SCRIPT and does not require variable or property declarations to use. akTarget is what the spell should be cast on. I put in PlayerREF, since I want it cast on the player. (You could also pass in akActionRef but only the Player can see messageboxes so only the player will have this affect them). 

Then we have our Else. An else has no need for clarification with Conditionals. It's just - If nothing else worked out, here I am! So we use Else for if the player chose the correct option, since it's the less likely one here. We call the function AddItem on PlayerREF, to add the item in parentheses to the player. It's parameters are:

(Form akItemToAdd, Int aiCount = 1, Bool abSilent = false)

The little = signs mean it's a default parameter. These will automatically have the value of what is after the = unless you declare otherwise by passing in values. This means you can just ignore them and just pass in akItemToAdd if you're interested. We pass in the form AND the count. The form is our gold, and the count is a random really high number I put in. Then we make sure to close our EndIf block so as not to confuse the engine, and end our event the same way. Compile with Ctrl + B in ST2 and return to the CK.

=============

Ugh. That was real longwinded, sorry.

So, now we need to hook up the properties. This is setting it up for the game world - making these properties actually mean something, because currently they reference nothing and as such will DO nothing.

Let's start with our Message property. Go to Miscellaneous>Message in the Obj Window Filter. Create a new one (always right click>new) and give it a unique editor ID (see Naming Conventions). Ignore title. All you have to be concerned with is ticking Messagebox (else buttons won't work), and the Message Text. Put in what you want your riddle to be here. Example:

What howls when the moon is out and is the only thing as fast as wind?

You can put in whatever you want. Then, create 3 new entries under Buttons. As you can see, each is given an index. This index is what correlates to our int variable Choice. Make sure 0 and 1 are incorrect and 2 is correct, since that's how we set up our script to percieve the buttons (0-1/first and second are incorrect, 2/third is correct). Press OK to save your Message. Now, return to our script. This time, highlight your script and instead of pressing Add or Open in External Editor, press Properties. Now you can fill your properties. Press Auto Fill All at the bottom. This will automatically associate properties that have the same property name as the objects editorID. This can be useful, but if you're going to use a property a lot, keep the name length down to save you from arthritis. :P

Those that don't auto-fill, click on and select the proper thing from the dropdown (sorted by EditorID, begin typing in the ID to skip to that section of the dropdown). ParalyzeSpell can be whatever you want, actually. Just choose any spell from the drop down as I can't currently remember the ID of the spell.

=================

You're all done! Save, load your .esp with your mod manager or launcher and go find your activator. Test it out and tell me what you think.

We'll be having less tutorial like lessons in a little, much shorter, and you'll get a chance to actually make your own first script. I wrote this when I was tired and went on for longer than i needed to, hence the ridiculous length. If the length bothers you tlel me so I can fix it in future lessons. If I miss anything sorry, just tell me and I'll get it fixed so you can get your first script working.

Edited by Mattiewagg

Share this post


Link to post
Share on other sites

I have a problem. I was pressing Ctr+build and nothing happened, and then I went to tools and build was faded out so i couldn't press it. If I select another build system I can try to do Ctr+B, but it jus says [Decode error - output not utf-8]. What can I do about it? (All the rest worked fine btw XD)

PS:I don't care about the length of what you write as long as it's complete and informative.

Edited by Paulibobo

Share this post


Link to post
Share on other sites

Hmm. Make sure the syntax chosen is Skyrim under View>Syntax and you've opened a precreated .psc from within the CK with Open in External Editor.

If that fails reinstall SublimePapyrus and if that fails reinstall ST. If you just want to get it working then just right click Edit/Open Source in the CK and the CK's built in editor will open. You can use that as well (Ctrl+S to compile).

I believe I had a similar problem with ST once. Can you confirm it doesn't work on vanilla .pscs either?

Share this post


Link to post
Share on other sites

Actually, I think you made a mistake. I'm not blaming you, it happens, but in the ParalyzeSpell.Cast(Self, PlayerREF))  you have two parethesis )) and I think that's the problem. Once I removed one, it worked for me. Could that be it? I filled the porpreties, and all that stuff, and it works. I tested all the three dialogue buttons and everything went fine! So what's next? 

Edited by Paulibobo

Share this post


Link to post
Share on other sites

Lesson on Functions and Events

Resources:

All About Functions (highly recommend you read, as I'm going to have the functions part of this shorter since this is very extensive + examples and written by myself before)

Events Reference

Functions

As you probably know by now, functions make up a lot of your scripts. They make stuff happen, for the most part. Moving things, changing things, getting values, etc. Those are ALL functions. 

A function consists of 5 parts:

Type Function FunctionName(Parameters)
EndFunction

The function type is used for functions that return values, not functions that only DO things and don't return values (if you have one that returns values and does stuff, it should have a function type). As you know, Show is a returning function. It returns an integer - the button chosen. Thus, it is an Int function.  If it weren't a native function (to be explained later), then it's function declaration would have looked like this:

Int Function Show(float afArg1 = 0, float afArg2 = 0, float afArg3 = 0, float afArg4 = 0, float afArg5 = 0, float afArg6 = 0, float afArg7 = 0, float afArg8 = 0, float afArg9 = 0)
     ;what the function does and returns
EndFunction

The function part is just a function declaration, telling the code that THIS is a function. It's just like the "Property" part of property declarations. The FunctionName part is just like the PropertyName. The Parameters are variables that are passed into the function - so you can have an Actor parameter, Int parameter, etc. This parameter can be used within the code of the function, no matter WHERE you call it from, unlike with global functions (discussed later); which can only use the parameters and nothing from within the script they were declared in. So if I have the function HealthierActor, and it compares the healths of two actors, then I'd have to pass in the two actors as parameters:

Function HealthierActor(Actor actorA, Actor actorB); parameters can be named whatever you like
     If actorA.GetActorValue("Health") > actorB.GetActorValue("Health")
          ;whatever code you want here
     ElseIf actorA.GetActorValue("Health") < actorB.GetActorValue("Health")
          ;whatever code you want here
     Else; is equal
          ;whatever code you want here
     EndIf
EndFunction

And then, you must close it off with an EndFunction, just like you would close off an event with EndEvent.

Now let's talk about Return values. You can have your function Return a value, which you can then use. You could assign an integer to the return value of a function that returns an int (or float, or bool, for that matter - see Casting though we'll talk more about it later if you want). Examples of Returning functions are functions like Game.GetPlayer(), which returns the Actor of the player so you can easily use the player in a script. You must have a function type if you want your function to return a value. So, while this will NOT work:

Function ThisIsAFunction()
    Return 10 + 10
    
EndFunction 

But this WILL:

Int Function ThisIsAFunction()
    Return 10 + 10
    
EndFunction 

You can also return the value of a parameter, global, variable declared within a function, or a property within a script (IF it is not a global function).

Read the Resource All About Functions for more examples, and info on Native and Global functions. 

Note that if you have a convenience function which is just there so you don't have to retype code a lot, it doesn't mean the code isn't still happening. If you call a function with 30 lines of code in it 100 times in a script, that's still 3000 lines of code being called (not necessarily a bad thing). It's just you typing out only 30ish lines. So it's not more performance friendly, but it's also not less so. It's the same as if you had typed out all the lines, except the file size is smaller and you don't have to type as much.

Events

Events are a bit simpler than functions. As I've said before, they're called when an event in the game happens. They often, but not always, include parameters. Parameters are variables sent along with the event, which you can manipulate within that event. (If you want to use a parameter throughout a script and not just in the event, then you can assign the value of one variable to the value of a parameter.) Events look like this:

Event EventName(Parameter)
EndEvent

There's not a much that you don't already know about events, to be honest. If you have any questions about them, feel free to ask. There are a few exceptions/things to note, however:

- Don't pile up too much in an OnInit event. It can overload it. It's a rather fragile event, though I know of no others like it. If there's more than a few function/code being called in there, use a RegisterForSingleUpdate(0.1) and then put all that code in the OnUpdate event.

- You can call an event directly. So, you could just call OnUpdate() like it were a function, rather than RegisterForSingleUpdate, if you wanted. Or, you could call any other event and pass in it's parameters. Etc. I've not experimented with this much but I've heard from others more experienced than I, that it is possible.

That's all I can think of for now. If you have any questions whatsoever, want me to clarify on anything, etc. don't hesitate to ask. :D

Also, I'll probably have you be making your own first script next, but if you'd prefer to have a lesson on say, Casting (how a Boolean turns into an Integer, etc.) or on Advanced Properties (accessing properties from other scripts, properties that can be set but not "got" - value of the property gotten) then we could do that instead. Whichever you prefer. We'd end up doing those lessons later on anyway and then making another or improving your first script to use those concepts. After that we'll do Arrays/Formlists and maybe a few other lessons on advanced concepts with you creating scripts scattered in between.

EDIT: Don't ask me why I used that color. That yellow is... not easy on the eyes. Sorry.

Edited by Matthiaswagg

Share this post


Link to post
Share on other sites

Ok, I think I got it! So first I would prefer to create a Script,  we can have further lessons on Castings and Advanced Propreties later. What do you suggest? I don't want something to basic... What about maybe a door where you have to solve a puzzle with butons chains and levers to get through? Like, if you pull the right ones it opens, Else you get killed/hit by a trap. I am working on a dungeon and that would be a cool addition to it!

If you had somethng else in mind, please tell me about it! 

Edited by Paulibobo

Share this post


Link to post
Share on other sites

Ok, I think I got it! So first I would prefer to create a Script,  we can have further lessons on Castings and Advanced Propreties later. What do you suggest? I don't want something to basic... What about maybe a door where you have to solve a puzzle with butons chains and levers to get through? Like, if you pull the right ones it opens, Else you get killed/hit by a trap. I am working on a dungeon and that would be a cool addition to it!

If you had somethng else in mind, please tell me about it! 

Well, that would require a script on each lever/chain, but it IS entirely possible. I even have a thread bookmarked with a script for it.

If you'd like to try it, go ahead. I will give a few hints, as it's your first script:

You should use a Global to track the value of what has currently been chosen is, which is property type GlobalVariable. (Create one by going to Miscellaneous>Global, right click, make sure it is NOT constant and is short, give it an EditorID you like,) You could also use a property in this case, but that requires Advanced Properties and wouldn't necessarily be prudent in this situation anyway.

A Global has special functions related to it to Set and Get it's values, rather than just = and direct value "getting" access. We'll go over this in Casting later, but the value of a global should be a float (decimal) value, both Getting and Setting. So if you intended to SetValue to 1 use 1.0 instead.

=====================

This is a more complex script, and will require the use of a few properties. At some point in the script, you will need to have the door be opened. This can be done using Activate

====================

I could provide more hints, and I will if you want more. However, you seem to be interested in trying out a more complex script on your own, so I'll back off unless you need more help.

The Creation Kit Wiki is your friend, and I am happy to answer any questions you have. Unless you specifically ask for a hint or just can't figure it out and want to see what the script should be and have me walk you through it, for the most part I'll answer your question in a more "guided" manner so I don't just straight up give you the answer.

Share this post


Link to post
Share on other sites

Ok, I am starting to get an idea of what I am going to do. The plan is that there are 9 levers, and the door opens if you pull three of them. If you pull any of the wrong ones and try to open the doors you get hit with a spell or arrows or something. I am thinking about the script, and there are two options I thouht of:

1-When you activate the door, it checks which levers are active and which arent. If any of the wrong ones are, it activates a trap. Else, the door opens. I guess I would have to create a srcipt for the door but I am not sure how to make it diferentiate between the levers.

2-Every right lever you pull adds 1 to your count. Every wrong one subtracts one. The door only opens if your count is three, which means it'll only open if you only have the right ones.  This creating three scripts. One for the wrong levers, one for the right ones, and a big script fot the door which all those other scripts relate to. 

I have some questions: Does this make any sense?

Which option would you go with.

Share this post


Link to post
Share on other sites

Ok, I am starting to get an idea of what I am going to do. The plan is that there are 9 levers, and the door opens if you pull three of them. If you pull any of the wrong ones and try to open the doors you get hit with a spell or arrows or something. I am thinking about the script, and there are two options I thouht of:

1-When you activate the door, it checks which levers are active and which arent. If any of the wrong ones are, it activates a trap. Else, the door opens. I guess I would have to create a srcipt for the door but I am not sure how to make it diferentiate between the levers.

2-Every right lever you pull adds 1 to your count. Every wrong one subtracts one. The door only opens if your count is three, which means it'll only open if you only have the right ones.  This creating three scripts. One for the wrong levers, one for the right ones, and a big script fot the door which all those other scripts relate to. 

I have some questions: Does this make any sense?

Which option would you go with.

Ah, okay. So you have to pull 3 in the right order. I was under the impression you had all of them necessary to be pulled.

More like the second, but rather than subtracting one, you set to 0. For the right ones, you could add 1 to it depending on which have been pulled already (I can let you figure out how to do that if needed). If the value is 3 for the right lever (the 3rd), then you just use Activate to open the door. No need for a script on the door.

You can reuse scripts and just change properties BTW. You shouldn't need too many scripts.

Share this post


Link to post
Share on other sites

What would be more efficient, three booleans of 0/1 or one int of 0-3?

Pauli don't read unless you want) hints. :P

The integer. But we're not using an integer. We're using a global, which is a float. This will allow Pauli to access the value from all scripts, and change it. So, if Lever1 is pressed and no other levers have been pressed, set Global to 1. If lever 3 is then pressed and global is not equal to the proper number (you can use an integer property so you only need two scriots and can just reuse the "good" lever script and change properties), then set it back to 0. DEFINITELY/ an integer, basically.

Share this post


Link to post
Share on other sites

I didn't mean tou have to pull them in any particuallar order, only the right three, and if any of the others are pulled, nothing happens. I just want to make sure that of the wrong ones (or not all the right ones) are pulled the door won't open. That's why i came up wit the count idea.

That works then. Your 2nd method should work just fine. There is a way to "mod" (+= is the method for counting up a property or variable, it's a different method for Globals, using a function) a global. I recommend looking for it on the CK Wiki.

And I'll leave the rest to you. So yeah, your second method should work. Just use a global, and figure out the structure of things.

No door script is needed. Look at the Activate link I gave you. If the door is locked, there's also a function to unlock which you can find if needed. And if Activate isn't working you can try SetOpen. You can find all these functions on the CK wiki if you search.

Share this post


Link to post
Share on other sites

What would be more efficient, three booleans of 0/1 or one int of 0-3?

Pauli don't read unless you want) hints. :P

The integer. But we're not using an integer. We're using a global, which is a float. This will allow Pauli to access the value from all scripts, and change it. So, if Lever1 is pressed and no other levers have been pressed, set Global to 1. If lever 3 is then pressed and global is not equal to the proper number (you can use an integer property so you only need two scriots and can just reuse the "good" lever script and change properties), then set it back to 0. DEFINITELY/ an integer, basically.

Why not just use an integer and set the levers up as akAcktionRef? So you can just use a single script instead of 4.

Share this post


Link to post
Share on other sites

What would be more efficient, three booleans of 0/1 or one int of 0-3?

Pauli don't read unless you want) hints. :P

The integer. But we're not using an integer. We're using a global, which is a float. This will allow Pauli to access the value from all scripts, and change it. So, if Lever1 is pressed and no other levers have been pressed, set Global to 1. If lever 3 is then pressed and global is not equal to the proper number (you can use an integer property so you only need two scriots and can just reuse the "good" lever script and change properties), then set it back to 0. DEFINITELY/ an integer, basically.

Why not just use an integer and set the levers up as akAcktionRef? So you can just use a single script instead of 4.

:P

Okay, you'll have to explain better. You can't use an integer, because globals are float values no matter what. You COULD use a property but it would be much harder to set up, and more tedious. And why would you be able to use akActionRef? There's only one akActionRef and I'm not sure when you'd receive it. In which event, I mean.

Sorry Pauli... ;)

Share this post


Link to post
Share on other sites

What would be more efficient, three booleans of 0/1 or one int of 0-3?

Pauli don't read unless you want) hints. :P

The integer. But we're not using an integer. We're using a global, which is a float. This will allow Pauli to access the value from all scripts, and change it. So, if Lever1 is pressed and no other levers have been pressed, set Global to 1. If lever 3 is then pressed and global is not equal to the proper number (you can use an integer property so you only need two scriots and can just reuse the "good" lever script and change properties), then set it back to 0. DEFINITELY/ an integer, basically.

Why not just use an integer and set the levers up as akAcktionRef? So you can just use a single script instead of 4.

:P

Okay, you'll have to explain better. You can't use an integer, because globals are float values no matter what. You COULD use a property but it would be much harder to set up, and more tedious. And why would you be able to use akActionRef? There's only one akActionRef and I'm not sure when you'd receive it. In which event, I mean.

Sorry Pauli... ;)

event onActivate (akActionRef)

Share this post


Link to post
Share on other sites

What would be more efficient, three booleans of 0/1 or one int of 0-3?

Pauli don't read unless you want) hints. :P

The integer. But we're not using an integer. We're using a global, which is a float. This will allow Pauli to access the value from all scripts, and change it. So, if Lever1 is pressed and no other levers have been pressed, set Global to 1. If lever 3 is then pressed and global is not equal to the proper number (you can use an integer property so you only need two scriots and can just reuse the "good" lever script and change properties), then set it back to 0. DEFINITELY/ an integer, basically.

Why not just use an integer and set the levers up as akAcktionRef? So you can just use a single script instead of 4.

:P

Okay, you'll have to explain better. You can't use an integer, because globals are float values no matter what. You COULD use a property but it would be much harder to set up, and more tedious. And why would you be able to use akActionRef? There's only one akActionRef and I'm not sure when you'd receive it. In which event, I mean.

Sorry Pauli... ;)

event onActivate (akActionRef)

The akActionRef is the player. That wouldn't help, I'm afraid. We'll be using OnActivate to check the value of whether or not the levers have been activated, but you need a global to check which have been activated thus far. 

Share this post


Link to post
Share on other sites

One question. So I make it so that the right levers increase the count and the wrong ones decrease it, but how do I make it so that when it's at 3 it opens the door and when not you ge hit by a spell? I was thinking about placing a script on the door so that when it was activated it would check if the count was 3; If it was it'd oen, if not you would get hit by a spell. Whithout a script on the door I don't think I can do that.

Share this post


Link to post
Share on other sites

Ok, here is the Script I have made so far for the first right lever. What do you think? PMRightLever is the name of the script, the Global is OpenSesame. Tell me if I did anything wrong, but now I think what i have to do is make the second lever check if the Value of OpenSesame is 1 and if it is set it to 2, and the same for the thrid only it sets it from 2 to 3. Then I was thinking about putting a script on te gate so that if  OpenSesame is 3 it opens, else you get hit by a spell. The wrong ones i'll just make the same script but with OpenSesame.SetValue(0.0) instead. Does this make any sense?

 
Scriptname PMRightLever extends ObjectReference
GlobalVariable Property OpenSesame auto
float OpenSesame
Event OnActivate (ObjectReference akActionRef)
OpenSesame.SetValue(1.0) 
EndEvent
 
 
PS: I wanted to put the script in a spoiler but I don't know how, could you please explain that to me?

Share this post


Link to post
Share on other sites

Ok, here is the Script I have made so far for the first right lever. What do you think? PMRightLever is the name of the script, the Global is OpenSesame. Tell me if I did anything wrong, but now I think what i have to do is make the second lever check if the Value of OpenSesame is 1 and if it is set it to 2, and the same for the thrid only it sets it from 2 to 3. Then I was thinking about putting a script on te gate so that if OpenSesame is 3 it opens, else you get hit by a spell. The wrong ones i'll just make the same script but with OpenSesame.SetValue(0.0) instead. Does this make any sense?

Scriptname PMRightLever extends ObjectReference

GlobalVariable Property OpenSesame auto

float OpenSesame

Event OnActivate (ObjectReference akActionRef)

OpenSesame.SetValue(1.0)

EndEvent

PS: I wanted to put the script in a spoiler but I don't know how, could you please explain that to me?

You've got the right idea, but the script itself is not quite right. For the Script on the right levers, you have a float variable. I'm not sure what you were using that for - the Global is all you were setting. Setting it to 1.0 doesn't require a variable. You can set to 1.0, 282991.00001, etc. Without a variable.

Now, if you don't care about the levers being pushed in the right order, then all you need to do is ADD to the global value and chdck when it is 3. So, youd make an ObjectReference property for your door, inside your lever script, and then put the following in your OnActivate:

IF OpenSesame.GetValue() == 3.0

MyDoor.Activate(Game.GetPlayer());or, you could use Unlock which I linked earlier if you were just trying to unlock the door, or Unlock and THEN activate

Else

OpenSesame.Mod(1.0)

EndIf

Then you'd have another script on your bad levers which would set the global to 0 and Cast (find it on the CK Wiki!) the spell on the player, with a Spell property.

If you want to have to activate the door before anything happens, then yes. You need a script on the door. I didn't realize that was what you wanted - usually you just have to pull the levers and the correct combination opens the door, the incorrect hurts you. Since you're not doing a combination, bad levers would be incorrect and good ones correct.

Spoiler tags:

;put your text inside

Code tags:
;put code in here


			
				

	Edited  by Matthiaswagg
	
	

			
		

Share this post


Link to post
Share on other sites

Ok, here's my second lever script:

Scriptname PMRightLever2 extends ObjectReference  

GlobalVariable Property OpenSesame auto
Event OnActivate (ObjectReference akActionRef)
if OpenSesame.GetValue() == 1.0
OpenSesame.Mod(1.0)
else
OpenSesame.SetValue(0.0)
EndIf
EndEvent
Edited by Paulibobo

Share this post


Link to post
Share on other sites

Here's what I figured out for the door script. Now only the wrong lever scripts are left to do, and that's the easy part.

Scriptname PMOpenDoor extends ObjectReference  
GlobalVariable Property OpenSesame auto
Spell Property FireSpell Auto
Actor Property PlayerREF Auto
ObjectReference property MyDoor auto
Event OnActivate (ObjectReference akActionRef)
if OpenSesame.GetValue() == 3.0
MyDoor.Activate(Game.GetPlayer())
else  
FireSpell.Cast(Self, PlayerREF)
EndIf

Share this post


Link to post
Share on other sites

Here's what I figured out for the door script. Now only the wrong lever scripts are left to do, and that's the easy part.

Scriptname PMOpenDoor extends ObjectReference  
GlobalVariable Property OpenSesame auto
Spell Property FireSpell Auto
Actor Property PlayerREF Auto
ObjectReference property MyDoor auto
Event OnActivate (ObjectReference akActionRef)
if OpenSesame.GetValue() == 3.0
MyDoor.Activate(Game.GetPlayer())
else  
FireSpell.Cast(Self, PlayerREF)
EndIf

Since you've defined PlayerREF, you should use PlayerREF instead of Game.GetPlayer().

You can use Self instead of defining a property for MyDoor.

Self is not a property, but sort of like a variable that will be the reference the script is on. So you can do:

Self.Activate(PlayerREF)
  • reaction_title_1 1

Share this post


Link to post
Share on other sites

The Script is working, after some minor changes. What's next?

Now I show you the streamlined version of the script and you try to understand it. ;)

GlobalVariable Property kCounter Auto
Int Property iExpectedValue Auto
ObjectReference Property kTarget Auto
Event OnActivate(ObjectReference akActionRef)
    Int iCounter = kCounter.GetValueInt()
    If(iCounter == iExpectedValue)
        kCounter.SetValue(iCounter + 1)
        If(kTarget != None)
            kTarget.Activate(akActionRef)
                        kTarget = None ;This is optional, but it stops the target from being activated again and should stop the target from being persistent
        EndIf
    Else
        kCounter.SetValue(0)
    EndIf
EndEvent 

This script is attached to each lever (create new the first time then Add and change properties for subsequent levers) and iExpectedValue is the zero-based index of the button in the order of buttons to press. So the first button's iExpectedValue is 0 and the 3nd button's is 2. The last button is the only one that should have the kTarget property filled - kTarget is the door to open. If a button is pressed in the wrong order, then the GlobalVariable is reset to 0 and the player has to start from the beginning.

Now that was the original script. To have it as you would've liked, needing to open the door, would've required two scripts, the abovel ike so:

GlobalVariable Property OpenSesame Auto
Int Property iExpectedValue Auto
Event OnActivate(ObjectReference akActionRef)
    Int iCounter = OpenSesame.GetValueInt();same as GetValue but in integer form
    If(iCounter == iExpectedValue)
        OpenSesame.Mod(1.0)
    Else
        OpenSesame.SetValue(0)
    EndIf
EndEvent 

And the door script is the same as the one you created before (you said you changed it, hence why I'm not using the one you used before). You would have the wrong lever script the same too - or you could add the above script and change the iExpectedValue property to an impossible number, which would be more efficient as you would keep only 2 scripts.

Do you understand the more streamlined script?

Edited by Matthiaswagg
  • reaction_title_1 1

Share this post


Link to post
Share on other sites

Ok, here is the Script I have made so far for the first right lever. What do you think? PMRightLever is the name of the script, the Global is OpenSesame. Tell me if I did anything wrong, but now I think what i have to do is make the second lever check if the Value of OpenSesame is 1 and if it is set it to 2, and the same for the thrid only it sets it from 2 to 3. Then I was thinking about putting a script on te gate so that if OpenSesame is 3 it opens, else you get hit by a spell. The wrong ones i'll just make the same script but with OpenSesame.SetValue(0.0) instead. Does this make any sense?

Scriptname PMRightLever extends ObjectReference

GlobalVariable Property OpenSesame auto

float OpenSesame

Event OnActivate (ObjectReference akActionRef)

OpenSesame.SetValue(1.0)

EndEvent

PS: I wanted to put the script in a spoiler but I don't know how, could you please explain that to me?

you start your quote with [spoil.er....] and end with [/...spoiler....]

Share this post


Link to post
Share on other sites

Oh I forot to explain myself.

Event onactivate(akActionRef )

if (akActionRef == lever01)

If (lever01== TRUE)

Levers = levers-1

Elseif (lever01 == FALSE)

Levers = levers+1

Elseif (akActionRef == lever02)

ETC ETC

Elseif (akActionRef == playerREF)

If (levers ==3)

"Activate door"

Elseif (levers != 3 )

"activate trap"

Here is levers an int for the right levers that have been pulled, lever01-03 worldobjects and bools that change from 0 to 1 if the lever hets pulled.

see what I mean?

Edited by magicspook

Share this post


Link to post
Share on other sites

Oh I forot to explain myself.

Event onactivate(akActionRef )

if (akActionRef == lever01)

If (lever01== TRUE)

Levers = levers-1

Elseif (lever01 == FALSE)

Levers = levers+1

Elseif (akActionRef == lever02)

ETC ETC

Elseif (akActionRef == playerREF)

If (levers ==3)

"Activate door"

Elseif (levers != 3 )

"activate trap"

see what I mean?

Not particularly, no. You don't have any properties or variables defined so I can't really see what you're attempting to do. And the lever doesn't activate the door. The player does. The lever is activated by the player but the lever cannot activate the door unless said to in the script on the lever, which would be required.

  • reaction_title_1 1

Share this post


Link to post
Share on other sites

The Script is working, after some minor changes. What's next?

Now I show you the streamlined version of the script and you try to understand it. ;)

GlobalVariable Property kCounter Auto
Int Property iExpectedValue Auto
ObjectReference Property kTarget Auto
Event OnActivate(ObjectReference akActionRef)
    Int iCounter = kCounter.GetValueInt()
    If(iCounter == iExpectedValue)
        kCounter.SetValue(iCounter + 1)
        If(kTarget != None)
            kTarget.Activate(akActionRef)
                        kTarget = None ;This is optional, but it stops the target from being activated again and should stop the target from being persistent
        EndIf
    Else
        kCounter.SetValue(0)
    EndIf
EndEvent 

This script is attached to each lever (create new the first time then Add and change properties for subsequent levers) and iExpectedValue is the zero-based index of the button in the order of buttons to press. So the first button's iExpectedValue is 0 and the 3nd button's is 2. The last button is the only one that should have the kTarget property filled - kTarget is the door to open. If a button is pressed in the wrong order, then the GlobalVariable is reset to 0 and the player has to start from the beginning.

Now that was the original script. To have it as you would've liked, needing to open the door, would've required two scripts, the abovel ike so:

GlobalVariable Property OpenSesame Auto
Int Property iExpectedValue Auto
Event OnActivate(ObjectReference akActionRef)
    Int iCounter = OpenSesame.GetValueInt();same as GetValue but in integer form
    If(iCounter == iExpectedValue)
        OpenSesame.Mod(1.0)
    Else
        OpenSesame.SetValue(0)
    EndIf
EndEvent 

And the door script is the same as the one you created before (you said you changed it, hence why I'm not using the one you used before). You would have the wrong lever script the same too - or you could add the above script and change the iExpectedValue property to an impossible number, which would be more efficient as you would keep only 2 scripts.

Do you understand the more streamlined script?

Yes, this makes sense to me, I just tought of it in a diferent way and ended up with a diferent script.  Is there any diference between the way that and mine work? The result is bound to be pretty much the same, no?

Share this post


Link to post
Share on other sites

The Script is working, after some minor changes. What's next?

Now I show you the streamlined version of the script and you try to understand it. ;)

GlobalVariable Property kCounter Auto
Int Property iExpectedValue Auto
ObjectReference Property kTarget Auto
Event OnActivate(ObjectReference akActionRef)
    Int iCounter = kCounter.GetValueInt()
    If(iCounter == iExpectedValue)
        kCounter.SetValue(iCounter + 1)
        If(kTarget != None)
            kTarget.Activate(akActionRef)
                        kTarget = None ;This is optional, but it stops the target from being activated again and should stop the target from being persistent
        EndIf
    Else
        kCounter.SetValue(0)
    EndIf
EndEvent 

This script is attached to each lever (create new the first time then Add and change properties for subsequent levers) and iExpectedValue is the zero-based index of the button in the order of buttons to press. So the first button's iExpectedValue is 0 and the 3nd button's is 2. The last button is the only one that should have the kTarget property filled - kTarget is the door to open. If a button is pressed in the wrong order, then the GlobalVariable is reset to 0 and the player has to start from the beginning.

Now that was the original script. To have it as you would've liked, needing to open the door, would've required two scripts, the abovel ike so:

GlobalVariable Property OpenSesame Auto
Int Property iExpectedValue Auto
Event OnActivate(ObjectReference akActionRef)
    Int iCounter = OpenSesame.GetValueInt();same as GetValue but in integer form
    If(iCounter == iExpectedValue)
        OpenSesame.Mod(1.0)
    Else
        OpenSesame.SetValue(0)
    EndIf
EndEvent 

And the door script is the same as the one you created before (you said you changed it, hence why I'm not using the one you used before). You would have the wrong lever script the same too - or you could add the above script and change the iExpectedValue property to an impossible number, which would be more efficient as you would keep only 2 scripts.

Do you understand the more streamlined script?

Yes, this makes sense to me, I just tought of it in a diferent way and ended up with a diferent script.  Is there any diference between the way that and mine work? The result is bound to be pretty much the same, no?

Yep, they work just about the same. However, yours requires multiple scripts - one for each lever. This one requires only 1 script for all the levers. Both ways work, but this one is more efficient and requires less work.

Share this post


Link to post
Share on other sites

Huh, this is weird. I decided to try to install Skyrim Script Editor again, you know, just seeing if it had decided to start working, and it did. Autocomplete's pretty cool, I might use this one from now on. What is the compile hotkey though?

Yeah, he's had about 100 updates since then. Big and small. That was an issue of the far past.

Ctrl+S

We'll be doing the advanced properties lesson next.

  • reaction_title_1 1

Share this post


Link to post
Share on other sites

Advanced Properties pt. 1

This will go over accessing properties from other scripts.

As you already know properties need to be set externally. Or rather, from within the Creation Kit. This means that they're the only way to reference items, objects, or references that are in game. They can also contain values of integers, floats, bools, etc. However, so can variables, and they do not need to be set externally and they take up (slightly) more memory. 

There's a reason for this. Properties can be accessed from other scripts, unlike variables. This way, you can share information between scripts, as well as changing the values of properties from other scripts. You can even set the value of a property from scriptB with a variable or another property from scriptA. We have 2 ways of doing this, though both are not always viable.

Through script property You can create a property for another script, and then reference that property to reference the other script through it. That sounds rather confusing, but you're essentially creating a property that is filled with the value of another script. So, like how you can fill a Weapon property with a Weapon entry, you can create a property that is the TYPE (a type is something like ObjectReference) of your script. Then you fill the property with your script, and it allows you to access any properties and functions in the other script, just like how you can access and set information on an ObjectReference.

Here's an example:

Scriptname scriptA extends ObjectReference; can extend anything, it can be any type of script
Int Property myAccessibleProperty Auto; could be any type of property
Event OnInit()
     ;codey code
EndEvent
Function SillyFunction()
     ;silly function stuff
EndFunction
Event OnActivate(ObjectReference akActionRef)
     ;moar code
EndEvent
Scriptname scriptB extends ActiveMagicEffect; again, can extend anything
scriptA Property anythingHere Auto; the TYPE of property is the exact name of the script, and anythingHere is just like any property name - it can be ANYTHING
Event OnEffectStart(Actor akTarget, Actor akCaster)
     anythingHere.myAccessibleProperty = 29; setting the value of myAccessibleProperty in scriptA from scriptB
​     anythingHere.SillyFunction()
EndEvent

Whenever doing this, you have to make sure you use the proper name for the properties in the other script. Sometimes, you will run into compilation errors when referencing another script, but you can't find anything wrong in scriptB (or the equivalent of it). It always pays to check the other script. Every time you compile scriptB, it will check over scriptA, since scriptB is using info from scriptA.

You DO need to fill the property. There will be a few choices in the dropdown, or just one. Each one is for the object the script is on. So if scriptA is on 100 different references in the game - 100 different weapon entries, for example - you'll have 100 choices in the dropdown. The property refers to a SPECIFIC script each time, so you have to choose a specific one. Just like any other property, leaving it unfilled will ensure the property doesn't work.

By getting the reference the script is on Alternatively, you can get the reference your script is on through function or property, and CAST to your script from that object. So, if you have two scripts on myObjectReference, objScriptA and objScriptB, you could reference objScriptA from objScriptB like so:

Scriptname objScriptA Extends ObjectReference
Bool Property LetSetIt Auto 
Event OnActivate(ObjectReference akActionRef)
     ;do some stuff
EndEvent
Scriptname objScriptB Extends ObjectReference; script is on the object that objScriptA is on 
Event OnInit()
    (Self as objScriptA).LetSetIt = True
EndEvent

Self is not a function, but sort of like a variable. It automatically contains the reference that the script it is called in is on.

So, what you do is you call Self, and then you CAST to the value of your script. It's a little confusing, but simple in practice. You use a function (other examples are GetOwningQuest(), which we'll use for a lot of quests and returns the value of the quest that a dialogue option or alias is contained within) or "special function" like Self to get the value of the object that has the script to reference on it. Then, you cast to the exact name of your script, and call functions from within that script, or set properties, etc.

MAKE SURE YOU USE THOSE PARENTHESES WITH THIS METHOD! 

Self as objScriptA

Will NOT work. 

(Self as objScriptA)

WILL work.

This method is not always possible if you can't use a function to get the reference of the object the script you're accessing is on. However, it stops you from needing to fill properties, which can save you time. It really depends when you should use one or the other, but you can generally figure it out.

Part 2 will be coming soon and going over the other functions of properties. Part 2 is less useful stuff, but definitely important to know about anyway. I really wanted to get this one out because you've been waiting a while. Tell me if you have any questions. ;)

  • reaction_title_1 1

Share this post


Link to post
Share on other sites

Ok, here are my two scripts. I think this was what I was supposed to do. When I pull a lever the second script is attached to, the first script is executed as a part of te second one.

The first one:

Scriptname PMtestScript1 extends ObjectReference

Int Property Coolstuff Auto     
Actor Property PlayerREF Auto
MiscObject Property Gold001 Auto
Function GoldFunction()     
if coolstuff == 1           
PlayerREF.AddItem(Gold001, 13)
Else
  EndIf 
EndFunction

The second one (attached to an actual lever):

Scriptname PMtestScript2 extends ObjectReference
PMtestScript1 Property stuff Auto
Event OnActivate(ObjectReference akActionRef)
     stuff.coolstuff = 1
     stuff.GoldFunction()
EndEvent            
 

Something about this script looks off to me for some reason, but it works. Forgot to post this earlier, sorry about that. I have the impression I did something wrong, what is it?

Edited by Paulibobo
  • reaction_title_1 1

Share this post


Link to post
Share on other sites

Ok, here are my two scripts. I think this was what I was supposed to do. When I pull a lever the second script is attached to, the first script is executed as a part of te second one.

The first one:

Scriptname PMtestScript1 extends ObjectReference

Int Property Coolstuff Auto     
Actor Property PlayerREF Auto
MiscObject Property Gold001 Auto
Function GoldFunction()     
if coolstuff == 1           
PlayerREF.AddItem(Gold001, 13)
Else
  EndIf 
EndFunction

The second one (attached to an actual lever):

Scriptname PMtestScript2 extends ObjectReference
PMtestScript1 Property stuff Auto
Event OnActivate(ObjectReference akActionRef)
     stuff.coolstuff = 1
     stuff.GoldFunction()
EndEvent            
 

Something about this script looks off to me for some reason, but it works. Forgot to post this earlier, sorry about that. I have the impression I did something wrong, what is it?

You didn't do anything wrong. However, the first script does not require the Else.

If you don't declare an Else in an If block (even one with Ifs AND ElseIfs), then it is assumed that Else does nothing. You don't need to declare it.

So, 

if coolstuff == 1           
     PlayerREF.AddItem(Gold001, 13)
EndIf

Is cleaner.

  • reaction_title_1 1

Share this post


Link to post
Share on other sites

Ok, I think what I didn't like about that script, was that the first one extended an Objectreference, without it actually doing anything. I placed the script on a random wall and that's that. I didn't know what to extend with it and it just seems weird to have it extend something without actually changing or adding anything to it. Does the first script even need to extend anything? Would the second script have worked if I hadn't placed the first script somewhere?

Edited by Paulibobo

Share this post


Link to post
Share on other sites

Ok, I think what I didn't like about that script, was that the first one extended an Objectreference, without it actually doing anything. I placed the script on a random wall and that's that. I didn't know what to extend with it and it just seems weird to have it extend something without actually changing or adding anything to it. Does the first script even need to extend anything? Would the second script have worked if I hadn't placed the first script somewhere?

You always need to place a script on something for it to truly exist. If it's not on something, then it's not "active".

A script must ALWAYS extend something. We'll get more into advanced extensions later, but yes - you always need to extend.

Share this post


Link to post
Share on other sites

But I could've extended an

Ok, I think what I didn't like about that script, was that the first one extended an Objectreference, without it actually doing anything. I placed the script on a random wall and that's that. I didn't know what to extend with it and it just seems weird to have it extend something without actually changing or adding anything to it. Does the first script even need to extend anything? Would the second script have worked if I hadn't placed the first script somewhere?

You always need to place a script on something for it to truly exist. If it's not on something, then it's not "active".

A script must ALWAYS extend something. We'll get more into advanced extensions later, but yes - you always need to extend.

But I could've extended anything, right? My problem was I was wondering if I was extending the right thing...

Edited by Paulibobo

Share this post


Link to post
Share on other sites

But I could've extended an

Ok, I think what I didn't like about that script, was that the first one extended an Objectreference, without it actually doing anything. I placed the script on a random wall and that's that. I didn't know what to extend with it and it just seems weird to have it extend something without actually changing or adding anything to it. Does the first script even need to extend anything? Would the second script have worked if I hadn't placed the first script somewhere?

You always need to place a script on something for it to truly exist. If it's not on something, then it's not "active".

A script must ALWAYS extend something. We'll get more into advanced extensions later, but yes - you always need to extend.

But I could've extended anything, right? My problem was I was wondering if I was extending the right thing...

ything, right? My problem was I was wondering if I was extending the right thing...

You should have extended an ObjectReference, here. Activators (triggers), statics and such are all ObjectRefs. It's the most common form.

Share this post


Link to post
Share on other sites

I am going on a vacation to visit family tomorrow and will return home in a week.  I'll tell you when I'm back. Meanwhile, I'll have internet access, so if you write out a tutorial I'll be able to read it and learn, but I can't actually write out any scripts. I'll tell you when I'm back home.
 

Edited by Paulibobo

Share this post


Link to post
Share on other sites

I am going on a vacation to visit family tomorrow and will return home in a week. I'll tell you when I'm back. Meanwhile, I'll have internet access, so if you write out a tutorial I'll be able to read it and learn, but I can't actually write out any scripts. I'll tell you when I'm back home.

I'm leaving tomorrow and will be back in a week too. Perfect timing. :P

I'll see about writing one then but doubt I'll get to it.

Edited by Matthiaswagg

Share this post


Link to post
Share on other sites

We're going to begin moving onto more advanced things now. First, Importing and Inheritance, which is a key concept for Papyrus. Casting next, which is another very important concept. Then we'll have a lesson on something you'll put into use far more often - Arrays. I'll have you write a short sample function/script to put Arrays into practice, as well as a little bit of Casting, which is relatively simple.

Finally, we'll wrap up with Advanced Properties pt. II because it's pretty boring and will rarely be used - I've never used the method we'll discuss in there once, but it's still good to know as it will allow you to manipulate properties to a much greater extent.

After that, I'll let you loose on writing a few scripts so I can help you figure out things you don't understand and make sure you've got a good grasp on the concepts. I'll have you go through some vanilla scripts and tell me what they mean, and let you ask any questions you may have. Once we're all through with that, we'll move onto quest design.

(This will be a barrage of lessons because I wrote them on two 14 hour plane flights. 28 hours of time dawdling tends to be good motivation. Just not for the Advanced Properties one because I had no internet and couldn't properly remember it, having never used it.)

Importing and Inheritance

Important Links:

INHERITANCE HIERARCHY

Extending Scripts

Inheritance

As you may know, functions are INHERITED. That little part after "extends†in a scriptname says that a script is a descendant of that extended script. There is a script called ObjectReference in the game, and when you extend ObjectReference, you're really saying that yourScript inherits all functions from ObjectReference.

Generally, you're extending a native script. As you learned in the functions lesson, native functions are defined in C++, and just declared in scripts. These scripts are ones like ObjectReference.psc, or Form.psc.

ObjectReference inherits functions from Form, so it has access to ALL Form functions and ALL ObjectReference functions. This means that yourScript inherits all ObjectReference and Form functions, as well as any functions declared within yourScript.

You could then create yourSecondScript which extends yourScript (would look like Scriptname yourSecondScript extends yourScript in the declaration), and has access to all Form, ObjectReference, yourScript, and yourSecondScript functions. You won't need to use this often, but it's good to know. As seen in Advanced Properties pt. I, you can use properties to access functions as well. You shouldn't inherit from a script if it isn't the right "typeâ€. Like, I shouldn't have a script that would normally extend Quest extend yourScript instead, since yourScript extends ObjectReference.

Importing

You can also import from scripts. Importing is a convenience tool used with global functions (learned about in the functions lesson).

Normally, when you call a global function, you call it like so:

functionScript.functionName()
functionScript being the script the global function is contained in, and functionName being the name of the global function. Two common examples of global functions are Wait and GetPlayer. They are usually called like:
Utility.Wait(float afSeconds); replacing the parameter appropriately
Game.GetPlayer(); returning the player actor
Game and Utility are two scripts in the game with functions declared in non-Papyrus code (C++). Wait and GetPlayer are just two of many globalnative functions declared within them. If you're using Game.GetPlayer() a bazillion times in your script (which you shouldn't do for efficiency reasons - will discuss later), it would save you a decent amount of time to forego that "Game.†part, wouldn't it?

So, you could can instead Import a script, like Game or Utility, and then not need that prefix. You import like so:

Import Game;event or function here, all functions must be called inside them of course
GetPlayer()
With Wait:
Import Utility;event or function here, all functions must be called inside of them
Wait(1.0)
There is absolutely no difference in performance for either method. As said, it's entirely a convenience function. Edited by Matthiaswagg
  • reaction_title_1 1

Share this post


Link to post
Share on other sites