Jump to content

HeirOfTheSeptims

Recommended Posts

I am having a problem getting my script to work using GetDiabled

Script:

 

 

Scriptname aaaAkaviriSpawnBrazierScript extends ObjectReference
Keyword Property Flame1Key Auto
Keyword Property Flame2Key Auto
Keyword Property Flame3Key Auto
Keyword Property SpawnKey Auto

Keyword Property Ghost1Key Auto
Keyword Property Ghost2Key Auto
Keyword Property Ghost3Key Auto
ObjectReference Property Ghost01 auto hidden
ObjectReference Property Ghost02 auto hidden
ObjectReference Property Ghost03 auto hidden

ObjectReference Property Flame01 auto hidden
ObjectReference Property Flame02 auto hidden
ObjectReference Property Flame03 auto hidden
ObjectReference Property SpawnPoint auto hidden

ActorBase Property GhostEndSpawn Auto

Event OnActivate(ObjectReference Brazier)

Flame01 = GetLinkedRef(Flame1Key)
Flame02 = GetLinkedRef(Flame2Key)
Flame03 = GetLinkedRef(Flame3Key)
SpawnPoint = GetLinkedRef(SpawnKey)
Ghost01 = GetLinkedRef(Ghost1Key)
Ghost02 = GetLinkedRef(Ghost2Key)
Ghost03 = GetLinkedRef(Ghost3Key)

Utility.Wait(1.0)
Ghost01.Enable()
GhostyFunction()
EndEvent

Function GhostyFunction()
If Flame01.GetDisabled() == 0 && Ghost02.GetDisabled() == 1
Utility.Wait(1.0)
Ghost02.Enable()
Else
Endif

If Flame02.GetDisabled() == 0 && Ghost03.GetDisabled() == 1
Utility.Wait(1.0)
Ghost03.Enable()
Else
Endif

If Flame01.GetDisabled() == 0 && Flame02.GetDisabled() == 0 && Flame03.GetDisabled() == 0
Utility.Wait(5.0)
SpawnPoint.Placeatme(GhostEndSpawn, 1)
Else
EndIf

If Brazier.GetDisabled() == 0
GhostyFunction()
Else
EndIf
EndFunction

 

 

 

Output:

 

 

Starting 1 compile threads for 1 files...
Compiling "aaaAkaviriSpawnBrazierScript"...
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\aaaAkaviriSpawnBrazierScript.psc(39,17): GetDisabled is not a function or does not exist
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\aaaAkaviriSpawnBrazierScript.psc(39,31): cannot compare a none to a int (cast missing or types unrelated)
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\aaaAkaviriSpawnBrazierScript.psc(39,47): GetDisabled is not a function or does not exist
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\aaaAkaviriSpawnBrazierScript.psc(39,61): cannot compare a none to a int (cast missing or types unrelated)
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\aaaAkaviriSpawnBrazierScript.psc(45,14): GetDisabled is not a function or does not exist
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\aaaAkaviriSpawnBrazierScript.psc(45,28): cannot compare a none to a int (cast missing or types unrelated)
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\aaaAkaviriSpawnBrazierScript.psc(45,44): GetDisabled is not a function or does not exist
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\aaaAkaviriSpawnBrazierScript.psc(45,58): cannot compare a none to a int (cast missing or types unrelated)
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\aaaAkaviriSpawnBrazierScript.psc(51,14): GetDisabled is not a function or does not exist
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\aaaAkaviriSpawnBrazierScript.psc(51,28): cannot compare a none to a int (cast missing or types unrelated)
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\aaaAkaviriSpawnBrazierScript.psc(51,44): GetDisabled is not a function or does not exist
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\aaaAkaviriSpawnBrazierScript.psc(51,58): cannot compare a none to a int (cast missing or types unrelated)
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\aaaAkaviriSpawnBrazierScript.psc(51,74): GetDisabled is not a function or does not exist
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\aaaAkaviriSpawnBrazierScript.psc(51,88): cannot compare a none to a int (cast missing or types unrelated)
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\aaaAkaviriSpawnBrazierScript.psc(57,6): variable Brazier is undefined
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\aaaAkaviriSpawnBrazierScript.psc(57,14): none is not a known user-defined type
C:\Program Files (x86)\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\aaaAkaviriSpawnBrazierScript.psc(57,28): cannot compare a none to a int (cast missing or types unrelated)
No output generated for aaaAkaviriSpawnBrazierScript, compilation failed.

Batch compile of 1 files finished. 0 succeeded, 1 failed.
Failed on aaaAkaviriSpawnBrazierScript

 

 

 

It doesn't seem to like GetDisabled, but I've seen it used elsewhere. Does anybody know whats wrong?

Link to comment
Share on other sites

Hello. Just a few thoughts at first, if you do not mind (not necessary to consider, potentially just me nitpicking, but just some thoughts :laugh: ):

  • Consider double-checking your If-statements, they are currently NOT what they should be like, for example you have useless Else-thingies everywhere, and you could consider grouping all your checks to one If-ElseIf-ElseIf-...-Else-EndIf statement for easier recognition by the reader.
  • Consider removing the last part of your GhostyFunction, the one which would seem to have it call itself repeatedly (if that is the case, because it definitely looks like it, and it is certainly not something you should be doing).
  • If your GetLinkedRef calls are only intended to fill an ObjectReference property, consider filling the ObjectReference properties straight away in the CK to reduce the amount of function calls, properties and keywords.
  • If there is the Enable Parent scheme also in Skyrim (it was in Oblivion), you can use it to reduce both property count and function calls (again), by linking ghosts and flames, then only enabling one, while the Enable Parent scheme makes sure other one gets automatically enabled as well.
  • Do you really need all those properties???? If you manage to do those two ones I mentioned, you can cut down your property count to five (5) from the current fifteen (15), which would only be 1/3 of the current count. :ohmy:
  • What is "Brazier" in your OnActivate event exactly, are you using a script to have an activator activate another activator (or something)? You do know it is local to that single event, your GhostyFunction will not have access to it, and anyway, it is a parameter that contains the ref that activated your... thingy that script is attached to (which means using Brazier in your GhostyFunction fails at compiler, because it is not defined).

As for the GetDisabled, have you tried IsDisabled instead? Like this (exclamation mark equals NOT, or "the opposite", or such):

If(!(SomeRef.IsDisabled()) && (SomeOtherRef.IsDisabled()))
    ...
EndIf

I tried using GetDisabled myself again, out of curiosity, but it did not work. Maybe it is a console command? In Oblivion, it actually is a command, but perhaps you could use IsDisabled() in Skyrim. The wiki page is here: http://www.creationkit.com/index.php?title=IsDisabled_-_ObjectReference

 

Hopefully that helps a little. What is it that you are trying to achieve? Just curious. :thumbsup:

 

Edit: Whoooooops. Corrected the link. And actually, the GetDisabled wiki page linked to "Papyrus version", which was IsDisabled, so GetDisabled is either some odd remnant in the wiki or a console command.

 

Edit 2: If you need help with scripting, I could see if there is something I can do. For example I can try tidying up that script if you can tell exactly what it is that it's supposed to do. For example, is that recursive function call intentional (the "GhostyFunction()" at the bottom of GhostyFunction, which might have the potential to cause some seriously huge call stacks).

Edited by Contrathetix
Link to comment
Share on other sites

Thanks, everywhere I looked it said GetDisabled :smile:

 

If you can tell me how to make a loop without telling it to run itself, that'd be great, but this is the only way I could get it to continually run. Right now the script never terminates, but I haven't added the last event yet, The plan is to disable the object when it is hit, then the script should terminate.

 

As for the properties, This script needs to be modular, so I have to base it on linked objects, and to identify the separate objects I need keywords. The flames are enabled when the ghosts die, not at the same time as they are enabled (by a separate script on the ghosts).

 

My If statements are used in such a way that they can't be made as one statement. each one serves a separate function, they have to be able to run at the same time, not one or the other.

 

The intention of the script is to create a spawning point that will spawn 3 specific enemies, keeping track of the ones you've killed with fires, then spawning a generic npc every 5 seconds until you destroy the object by hitting it (I haven't added that part of the script yet, but it won't be a problem).

 

Edit: Fyi, The script is now working as intended, Thanks!

Edited by HeirOfTheSeptems
Link to comment
Share on other sites

You can have properties and just fill them on a per object basis instead of linking them as keyworded linked refs, same result, instead of setting a linked ref, you fill a property.

 

Anyway, if you are going with linked refs no need to make them properties unless you are accesing them from other script, they can be variables and only have them pointing at the object for as long as its needed to not keep them persistent if it's not needed. And, why set the properties on the onactivate block? do you expect to change the linked refs at runtime? if not, you can do it on an on init event so it only runs once, sets the variables to the linked refs from then on just uses the stored variables.

 

As for the loop, calling it itself seems problematic, why not http://www.creationkit.com/index.php?title=RegisterForSingleUpdate_-_Form (on the end of the Onupdate event you call it again) it avoids stacking.

Link to comment
Share on other sites

As I said, it needs to be modular, and I am using quite a few of them. I'd rather not have to modify the properties to specify six objects each time if I can just make it dynamic.

 

I have multiple linked references, and different things need to happen to each one, the script needs a way to tell the difference between them.

 

What problems supposedly actually happen when I loop it? Its accomplishing exactly what I want with no issue that I have seen. It enables the right enemies at the right times, then spawns generic enemies until it is destroyed and disabled, at which point the script stops running.

 

Edit: I got it working with the update, but I would still like to know what would have happened with the loop for reference.

Edited by HeirOfTheSeptems
Link to comment
Share on other sites

You wouldn't loose any "modularity" by using properties, you can set them for each object, same as linked refs, and you can even change then on runtime if you wish. For each of the objects in the world using the script you have had to go the linked refs tab and point it to the references. With properties you'd do the same, but in the scripts tab instead which is the last in an object, that's the thing about properties, you don't need to change the script to make it point to different stuff for each object using the script.

It's literally the same result and less function calls. The only reason to use multiple linked refs with keywords instead of properties is to not keep those references persistent (always and forever loaded) but you are making properties for them to store the result of GetLinkedRef so where's the benefit?

 

For example, for Flame1 you have all this:

ObjectReference Property Flame01 auto hidden
Keyword Property Flame1Key  Auto 

Event OnActivate(ObjectReference Brazier)
Flame01 = GetLinkedRef(Flame1Key)
..
EndEvent

When the same result would be just, it's equaly persistent than yours and it's quicker.

ObjectReference Property Flame01 auto ; filled on ck on each object reference, not in the base object.

Or if you still want to use linked refs make them variables, unset them when the thing is done so bye bye persistence, and maybe initialize them on an oninit event only once not every time the item is activated, which i guess might happen more than once?, if activation happens only once then it's fine there, the rest still applies.

ObjectReference Flame01; a variable is enough, you are only going to access it on this script, right?
Keyword Property Flame1Key  Auto 

Event OnInit()
; set all the variables to the linked refs just once, not everytime the item is activated
Flame01 = GetLinkedRef(Flame1Key)
...
EndEvent

Event OnActivate(ObjectReference Brazier)
; use those variables for the stuff you want to do to them
​EndEvent

; whenever the thing is done and this object doesn't need to do anything else, clean the variables:
Flame01 = None
Flame02 = None
etc

As for the looping, yeah calling itself works, but if the above conditions are not met it is going to run A LOT of times per second non-stop, that's unnecessary, I mean the system should probably be smooth with it checking checking just once a second or if you wish every half second with registerforsingleupdate and replacing your function with an onupdate event. Cleaner, safer, equally functional.

Event OnActivate(ObjectReference Brazier)
;some other stuff, initialize the variables if this only runs once for example
RegisterForSingleUpdate(1.0) ;start the recursive function
​EndEvent

Event OnUpdate()
; Do stuff
If we need to keep runing
RegisterForSingleUpdate(1.0) ;continue the chain
endif ; if we don't need to update anymore, don't do anything, it's "Single" update unless called again.
EndEvent
Edited by FrankFamily
Link to comment
Share on other sites

I can duplicate my set up and directly swap items (Ctrl F) by using linked reference, if I used selected properties I would have to reselect everything for each group of enemies, its the difference between dungeon population taking a day vs. an hour. My way is much less work and much faster.

Link to comment
Share on other sites

Valid reason to use linked refs over properties didnt know you were placing enough of this so that setup time matters. Still your way, in my opinion, however fast it may be, has some performance flaws. Specially if you are populating a dungeon with it. So if you want something that in addition to "working" and being fast doesnt harm performance for no reason the stuff below "Or if you still want to use linked refs..." still applies.
Link to comment
Share on other sites

Okay, FrankFamily seems to have done what I intended to do. Thank you! :tongue:

 

As for the question about repeatedly calling a function: recursion is not the same as repeatedly calling a function! Calling a function every, for example, one second, is that one function getting called once every one second, and only one function call is made. Recursion is basically a function calling itself, and recursion always stacks! Never implement repeated calling of a function using recursion! It always stacks, and keeps piling up until it meets the codition that has it return back up the call chain. If you call a function in a function like that, you can easily pile up a huge stack of function calls.

 

You had a function like this:

Function GhostyFunction()
    ....
    If(condition)
        GhostyFunction()
    EndIf
EndFunction

What your call to GhostyFunction actually does is this:

  • you call GhostyFunction (first one)
  • the GhostyFunction calls GhostyFunction (second one)
  • the GhostyFunction called by GhostyFunction calls GhostyFunction (third)
  • ...

And each time GhostyFunction calls GhostyFunction, the calling GhostyFunction starts waiting for the GhostyFunction it just called to return a value and/or exit (in this case, just exit). The same happens inside the GhostyFunction it just called, so there is then one function waiting for one function waiting for one function...

 

Just for illustrative purposes, let's imagine what your script would look like if the call to GhostyFunction would be written open for, let's say, three first calls:

Function GhostyFunction()
    ..do stuff..
    If(condition)
        ..do stuff..
        If(condition)
            ..do stuff..
            If(Condition)
                <condition is false, returns back upwards>
            EndIf
        EndIf
    EndIf
EndFunction

And you can see the issue? It is not a repeated calling of function as it is, it is recursion! It stacks on each call. For as long as the condition is true, you keep getting basically a new block of that function copied inside the if-statement (for illustrative purposes, not really). It might work, if you one day manage to have the condition result to false, in which case the function chain starts to return back to original caller. It is a first-in-last-out stack. Each call adds one function to it. If you have a hundred recursive calls, it goes like this:

  • number 1 waits for number 2 to finish (number 1 called number 2)
  • number 2 waits for number 3 to finish (number 2 called number 3)
  • number 3 waits for number 4 to finish (number 3 called number 4)
  • number 4 waits for number 5 to finish (number 4 called number 5)
  • number 5 waits for number 6 to finish (number 5 called number 6)
  • number 6 waits for number 7 to finish (number 6 called number 7)
  • ...
  • number 99 waits for number 100 to finish (number 99 called numbr 100)

And when number 100 meets a false condition, it does not make a function call, and exits, returning to number 99. Number 99 stops waiting for number 100, finishes, exits, and returns to 98... So the stack piles up, and after the last called one hits the wall (no longer calls itself), and exits, only then will all the other functions be able to finish and exit (because each function has stopped there, to wait for the one it called to finish). The call chain returns through all the 99 functions until it reaches your original one.

 

Recursion for repeatedly calling a function can work with Papyrus, because Papyrus allows each script/call/something a specific amount of time/resources, stopping them when time is up, continuing them when their next turn is up, and thus as your extensive recursion stack keeps piling up, time also passes, so your condition check thingy has the time to change its state by the time an nth recursive call happens, which causes the call chain to start returning.

 

I think you can find a lot more info on recursion online. But generally, do not use recursion unless you have a good reason to. Especially do not use it to repeatedly call a function, it is not meant for that and is terribly inefficient at it. That is, if you want to call a function every, for example, one second. Recursion is intended for another sort of work (like searching a binary tree or something).

 

Hopefully that helps a little. Not trying to be smart-butt, just pointing that out in case you have accidentally used it elsewhere. Apologies if it does not help, I am bad at explaining things, as you can see. Also, I am still in the process of studying all that at the uni, so if anyone spots mistakes, please correct me (also for my own sake). :whistling:

 

Edit: Typos... :facepalm:

Edited by Contrathetix
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...