utofaery Posted September 28, 2018 Share Posted September 28, 2018 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 Script2Attach 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 More sharing options...
foamyesque Posted September 28, 2018 Share Posted September 28, 2018 (edited) 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 September 28, 2018 by foamyesque Link to comment Share on other sites More sharing options...
JonathanOstrus Posted September 28, 2018 Share Posted September 28, 2018 (edited) 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() EndEventYou 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 September 28, 2018 by BigAndFlabby Link to comment Share on other sites More sharing options...
CPU Posted September 29, 2018 Share Posted September 29, 2018 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 More sharing options...
utofaery Posted September 30, 2018 Author Share Posted September 30, 2018 (edited) 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 September 30, 2018 by utofaery Link to comment Share on other sites More sharing options...
IsharaMeradin Posted September 30, 2018 Share Posted September 30, 2018 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 fillYou 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 More sharing options...
JonathanOstrus Posted September 30, 2018 Share Posted September 30, 2018 (edited) 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 September 30, 2018 by BigAndFlabby Link to comment Share on other sites More sharing options...
ReDragon2013 Posted September 30, 2018 Share Posted September 30, 2018 (edited) 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 ENDFUNCTIONCertainly 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 September 30, 2018 by ReDragon2013 Link to comment Share on other sites More sharing options...
JonathanOstrus Posted September 30, 2018 Share Posted September 30, 2018 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 More sharing options...
Recommended Posts