Jump to content

[LE] Q>About Quest Script Casting and linking Function()


utofaery

Recommended Posts

I need help understanding this.

The thing or part I want it to run is

 

TestLinkFunction() on Activator attach with Script2

How should I properly call it from activator?

 

 

 

Script1

ScriptName ScriptQuest Extends Quest

Quest Property Quest1 Auto

Function TestLinkFunction()
		Debug.Notification("TestLinkFunction Runs Hooray!!!")
EndFunction

Script2

Attach to Activator to call TestLinkFunction()

from Script1 which did happen not working
ScriptName ScriptObject Extends ObjectReference

Quest LocalQuest

Event OnActivate(ObjectReference akActionRef)
		Quest KmyQuest1 = ( LocalQuest as ScriptQuest).Quest1
		ScriptQuest kmyQuest2 = KmyQuest1 as ScriptQuest
		kmyQuest2.TestLinkFunction()
EndEvent
Link to comment
Share on other sites

Your syntax will compile, but if I am parsing it correctly, it is attempting to run TestLinkFuction on whatever quest you have filling the Quest1 property in the ScriptQuest script on LocalQuest. If that is intentional, check to make sure both of those properties are filled, and filled with quests that has the ScriptQuest script attached to them.

EDIT: Wait, LocalQuest is defined as a variable, not a property, and then never initialized. That'll fail the script right there.

Edited by foamyesque
Link to comment
Share on other sites

You might want to rethink your script names before continuing too far. Those names are atrociously ambiguous. In the case of "ScriptObject" that name is even reserved in Fallout 4 (and probably additional games going forward). I realize this is for Skyrim and is not currently an issue. But it's always good practice to keep your names of things descriptive so they're not confusing and ambiguous. It's also good practice to use descriptive variables and property names. Ok rant done.

I think you're going about something the wrong way. I get the activator has the "ScriptObject" script on it.

  • How are you planning to get your quest as a useable object? You need to set it as a property. Or get it by some other means like GetForm or GetFormFromFile.
  • Does the property Quest1 on ScriptQuest point to the same quest it is attached to? If so, why? You don't need a property to point to itself.

Your stated code is failing because:

  • In ScriptObject your "LocalQuest" is undefined so therefore "NONE". When you try to set kmyQuest1 it will produce a papyrus error in the log (if you turn it on you'll see it) about casting a NONE and then it can't find the property you try to reference.
  • The second line where you try to set kmyQuest2 will then fail because kmyQuest1 is NONE.
  • Then of course trying to call "NONE".TestLinkFunction() is invalid.

In the interest of time something like this would probably be what you want:

ScriptName ScriptQuest Extends Quest
 
Function TestLinkFunction()
    Debug.Notification("TestLinkFunction Runs Hooray!!!")
EndFunction


You will need to statically assign the property on the activator with the following script to point to your quest.

ScriptName ScriptObject Extends ObjectReference
 
Quest Property LocalQuest Auto
 
Event OnActivate(ObjectReference akActionRef)
    ; always good to validate the player is activating. unless you want npcs to also activate it.
    if akActionRef != Game.GetPlayer()
        return
    endif

    ScriptQuest kmyQuest = (LocalQuest as ScriptQuest)
    kmyQuest.TestLinkFunction()
EndEvent

You could even pre-cast the property so it only shows you quests that are of the script type you want.

ScriptName ScriptObject Extends ObjectReference
 
ScriptQuest Property kmyQuest Auto
 
Event OnActivate(ObjectReference akActionRef)
    ; always good to validate the player is activating. unless you want npcs to also activate it.
    if akActionRef != Game.GetPlayer()
        return
    endif

    kmyQuest.TestLinkFunction()
EndEvent
Edited by BigAndFlabby
Link to comment
Share on other sites

In your code there are no actual link to the objects you are using.

You cannot use simple variables you need to use properties.

 

ScriptName ScriptObject Extends ObjectReference

ScriptQuest Property LocalQuestScript Auto

Event OnActivate(ObjectReference akActionRef)
    LocalQuestScript.TestLinkFunction()
EndEvent

And remember to fill the property with the quest.

 

In case the script extends an object that is owned by the quest (ReferenceAliases for example) then you can just use GetOwningQuest() and cast it to the script name to use its functions.

Link to comment
Share on other sites


Question 1 :

If I want to reuse something from another script

I would set it as properties

eg. MiscObject Property exampleMO Auto

so I could use it in another script by

scriptexample.exampleMO

I am correct doing it this way?




Problem 1 :

After reading all the post above, the following test was conducted.

and Test3 is not working



ScriptName ScriptQuest Extends Quest

Function TestLinkFunction()
Debug.Notification("TestLinkFunction Runs Hooray!!!")
EndFunction



ScriptName ScriptObject Extends ObjectReference ;;;; Test1 Runs ok

Quest Property LocalQuest Auto

Event OnActivate(ObjectReference akActionRef)
if akActionRef != Game.GetPlayer() ;; <<< Does this same as if akActionRef == PlayerRef
;; Question : What's the difference in using PlayerRef and Game.GetPlayer()
;; which one's faster or better use in scripting papyrus??
Return
endif

ScriptQuest kmyQuest = (LocalQuest as ScriptQuest)
If kmyQuest == NONE
Debug.Notification("kmyQuest1 is NONE")
Else
kmyQuest.TestLinkFunction() ;; <<< This part Runs
EndIf
EndEvent



ScriptName ScriptObject Extends ObjectReference ;;;; Test2 Runs ok
Quest Property LocalQuest Auto
Event OnActivate(ObjectReference akActionRef)
if akActionRef != Game.GetPlayer()
return
endif
ScriptQuest kmyQuest = (LocalQuest as ScriptQuest)
If kmyQuest == None
Debug.Notification("KmyQuest2 is NONE")
Else
kmyQuest.TestLinkFunction() ;; <<< This part Runs
EndIf
EndEvent






ScriptName ScriptObject Extends ObjectReference ;;;; Test 3 Not running TestLinkFunction() and kmyQuest is NONE
ScriptQuest Property kmyQuest Auto

Event OnActivate(ObjectReference akActionRef)
if akActionRef != Game.GetPlayer()
return
endif

If kmyQuest == None
Debug.Notification("KmyQuest3 is NONE") ;; <<< This One runs , Why?
Else
kmyQuest.TestLinkFunction()
EndIf
EndEvent



Edited by utofaery
Link to comment
Share on other sites

Correction to test 3

ScriptName ScriptQuest Extends Quest
 
Function TestLinkFunction()
		Debug.Notification("TestLinkFunction Runs Hooray!!!")
EndFunction
ScriptName ScriptObject Extends ObjectReference ;;;; Test 3
ScriptQuest Property myScriptQuest Auto 
 
Event OnActivate(ObjectReference akActionRef)
	if akActionRef != Game.GetPlayer()
		return
	endif

	If myScriptQuest == None
			Debug.Notification("myScriptQuest is NONE") 
	Else
			myScriptQuest.TestLinkFunction()
	EndIf
EndEvent

kmyQuest is a reserved variable name for certain instances. Best to not use it. This is probably the hang up.

When you fill the "myScriptQuest" property, assign it the quest that the script is attached to.

 

PlayerRef vs Game.GetPlayer()

PlayerRef is faster as the data is stored in a variable and does not need to pause the script like the GetPlayer() function does.

You can use an actor property and PlayerRef will auto fill

You can use a local actor variable and assign PlayerRef the Game.GetPlayer() result.

Or if the event you are working on has an actor or objectreference that you want to compare for the player, a single compare with Game.GetPlayer() followed up by using the event variable will work. OnActivate is a good example i.e.

Event OnActivate(ObjectReference akActionRef)
  If akActionRef != Game.GetPlayer()
    Debug.Trace(akActionRef+" is not the player")
  Else
    Debug.Trace(akActionRef+" is the player")
  EndIf
EndEvent
Link to comment
Share on other sites

I should have been more detailed about the use of Game.GetPlayer(). The end functionality wise is the same as setting a property. Like @IsharaMeradin said, getting the object from a property or a variable is faster than calling out to Game.GetPlayer(). However, I recall reading somewhere that the more properties scripts use, the more strings tables it enters into the save game. There is a limit and eventually it will cause a save game to be unusable. I did a quick search and I believe this is a relevant page to the issue https://forums.nexusmods.com/index.php?/topic/3924850-corrupt-saves-strcount-0xffff-ctd-on-load/ Reusing the same variable/property names does sort of work around the potential of the issue.

 

If you look at vanilla Bethesda scripts they use Game.GetPlayer() always exclusively. If they need to use it multiple times they set a local function variable and use that. A good simple example is DLC2SV01ClawPickupScript.psc.

 

Because it is slower to use Game.GetPlayer(), and requires pausing your script when going to get the value, if you need to use the player reference multiple times it is recommended to set a local variable and call it once.

Function SomeRoutine()
    Actor PlayerREF = Game.GetPlayer()
    ; insert lots of code that accesses PlayerREF instead of calling Game.GetPlayer() each time.
EndFunction
Edited by BigAndFlabby
Link to comment
Share on other sites

utofaery wrote: "I want to reuse something from another script, .. Test3 is not working!"

 

Make sure you understand the different between :

- script properties Quest PROPERTY myQuest auto

- script variables Quest myQuest

- local variables

FUNCTION TestFunction()

quest q = myQuest

ENDFUNCTION

Certainly you forgot to fill the property. By the way test 1 and 2 seems to be equal papyrus source code.
I think BigAndFlabby has given you very good explanation to make it right.

IsharaMeradin wrote: "kmyQuest is a reserved variable name for certain instances."
Not really there is no reason for not using "kmyQuest" in own scripts. But as she also wrote "Best to not use it.", because it could be confusing for scripter.

Test 3

 

ScriptName ScriptObject extends ObjectReference
;;;; Test 3 Not running TestLinkFunction() and kmyQuest is NONE

  ScriptQuest PROPERTY kmyQuest auto         ; you have to fill this script property by CK, otherwise this is None

; -- EVENT --

EVENT OnActivate(ObjectReference akActionRef)
IF (akActionRef == Game.GetPlayer() as ObjectReference)   ; actor player = Game.GetPlayer()
ELSE
    RETURN    ; not the player
ENDIF
;--------- from here akActionRef is the same as the Player and can be used 
    IF ( kmyQuest )
        kmyQuest.TestLinkFunction()

;;;    ELSEIF (kmyQuest == None)
    ELSE
        Debug.Notification("KmyQuest3 is NONE") ;; <<< This One runs , Why?
    ENDIF
ENDEVENT

 

 

Edited by ReDragon2013
Link to comment
Share on other sites

The only place I've ever seen kmyQuest actually used previously is within Quest stage fragments. For the less advanced that may be reading this, the Creation Kit UI assists the developer by giving you a simple dropdown list to set a casting on the open quest to any script attached to it. Thus setting a visually hidden variable kmyQuest = (self as <chosen script from dropdown>). Visually hidden from the fragment window in Creation Kit anyway. The actual code it produces looks something like this from QF_C00_0004B2D9.psc varying depending on the chosen script.

 

;BEGIN AUTOCAST TYPE companionshousekeepingscript
Quest __temp = self as Quest
companionshousekeepingscript kmyQuest = __temp as companionshousekeepingscript
;END AUTOCAST
Link to comment
Share on other sites

  • Recently Browsing   0 members

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