Jump to content

DOWNLOAD MODS

Are you looking for something shiny for your load order? We have many exclusive mods and resources you won't find anywhere else. Start your search now...

LEARN MODDING

Ready to try your hand at making your own mod creations? Visit the Enclave, the original ES/FO modding school, and learn the tricks of the trade from veteran modders...

JOIN THE ALLIANCE

Membership is free and registering unlocks image galleries, project hosting, live chat, unlimited downloads, & more...

[Sky] Can't get quests to start with scripting


libertasmens
 Share

Recommended Posts

I'm so close to being done with this mod....

All I need to do is have a script start a quest. I've tried everything I can think of, but no matter what I do I can't get a quest to start or change stages via scripting.

What do I need to do, and what am I probably doing wrong?

That's my last question and then I'm all done for a while. :P

Link to comment
Share on other sites

What is your script attached to? They don't run on their own - they need to be attached to some kind of trigger. That's usually a quest that's start game enabled. Another option is an object or an activator. But you need some way for the script to be triggered.

Link to comment
Share on other sites

Might help if you post the script you're using and some details about what you've done that's NOT working and what you want to do. :good:

Here's the debug version of the script I wrote.

It's intended to start the quest if it isn't currently running, set it to active, and set the stage to the property-passed stage.

Every time I enter the trigger zone, the notifications read out "NoStart" then "Nope".

Scriptname theScriptName extends ObjectReference  


Quest property theQuest auto

Int property stage=0 auto



Event onTriggerEnter(ObjectReference akActionRef)

	if(!theQuest.IsRunning()&&akActionRef==Game.getPlayer())

		if(theQuest.Start())

			Debug.Notification("Started")

		Else

			Debug.Notification("NoStart")

		EndIf

		theQuest.SetActive(true)

	Else

		Debug.Notification("AlreadyRunning")

	EndIf


	if((theQuest.getStage()<stage)&&akActionRef==Game.GetPlayer())

		theQuest.setActive(true)

		if(theQuest.setStage(stage))

			Debug.Notification("Done")

		Else

			Debug.Notification("Nope")

		EndIf

	EndIf

EndEvent

Link to comment
Share on other sites

What is your script attached to? They don't run on their own - they need to be attached to some kind of trigger. That's usually a quest that's start game enabled. Another option is an object or an activator. But you need some way for the script to be triggered.

It's just attached to a trigger primitive.

Link to comment
Share on other sites

Scriptname theScriptName extends ObjectReference  


Quest property theQuest auto

Int property stage=0 auto



Event onTriggerEnter(ObjectReference akActionRef)

	if(!theQuest.IsRunning()&&akActionRef==Game.getPlayer())

		if(theQuest.Start()) ;You are not calling for the quest to start here, you are performing a boolean check for if it started.

			Debug.Notification("Started")

		Else

			Debug.Notification("NoStart")

		EndIf

		theQuest.SetActive(true)

	Else

		Debug.Notification("AlreadyRunning")

	EndIf


	if((theQuest.getStage()<stage)&&akActionRef==Game.GetPlayer())

		theQuest.setActive(true)

		if(theQuest.setStage(stage)) ;Again, you are not calling for this to execute, you are calling a boolean check on the operation.

			Debug.Notification("Done")

		Else

			Debug.Notification("Nope")

		EndIf

	EndIf

EndEvent

I have annotated the issues. Here's the corrections:
Scriptname theScriptName extends ObjectReference  


Quest property theQuest auto

Int property stage=0 auto



Event onTriggerEnter(ObjectReference akActionRef)


	if(!theQuest.IsRunning()&&akActionRef==Game.getPlayer())

	     (theQuest.Start()) 

	     Debug.Notification("Started")

             theQuest.SetActive(true)

	ElseIf(TheQuest.IsRunning() && akActionRef == game.getPlayer())

             Debug.Notification("AlreadyRunning")

	Else

             Debug.Notification("NoStart")

	EndIf


	if((theQuest.getStage()<stage)&&akActionRef==Game.GetPlayer())

	     (theQuest.setStage(stage))

	     Debug.Notification("Done")

	Else

	     Debug.Notification("Nope")

	EndIf


EndEvent

Remember: in Papyrus, anything and everything can be cast to a Boolean. If you call a function alongside an If statement as you did, Papyrus will interpret that as you casting the function to a Boolean. Which means, in essence, you are asking the script if the function was performed, not performing the function.

Edited by ThomasKaira
Link to comment
Share on other sites

I have annotated the issues. Here's the corrections:

Scriptname theScriptName extends ObjectReference  


Quest property theQuest auto

Int property stage=0 auto



Event onTriggerEnter(ObjectReference akActionRef)


	if(!theQuest.IsRunning()&&akActionRef==Game.getPlayer())

	     (theQuest.Start()) 

	     Debug.Notification("Started")

             theQuest.SetActive(true)

	ElseIf(TheQuest.IsRunning() && akActionRef == game.getPlayer())

             Debug.Notification("AlreadyRunning")

	Else

             Debug.Notification("NoStart")

	EndIf


	if((theQuest.getStage()<stage)&&akActionRef==Game.GetPlayer())

	     (theQuest.setStage(stage))

	     Debug.Notification("Done")

	Else

	     Debug.Notification("Nope")

	EndIf


EndEvent

Remember: in Papyrus, anything and everything can be cast to a Boolean. If you call a function alongside an If statement as you did, Papyrus will interpret that as you casting the function to a Boolean. Which means, in essence, you are asking the script if the function was performed, not performing the function.

I don't mean this in a rude way, but that doesn't make much sense, and your code doesn't actually debug it. While it may be true that Papyrus "interprets that as you casting the function to a Boolean", a function call logically should A) not be modified by surrounding code, and B) always return something without changing the actual functionality of the code (unless of course the function is a void (or Papyrus equivalent)). Also, your code calls for the quest to start and then reads out "Started" regardless of whether or not it actually started, thus there was no way to identify what occurred. Just in case Papyrus actually acts differently than other programming languages, I modified your snippet so that Start() would be called without any surrounding code, and then checks if it had been started (or was running). Neither were true, and it was not able to start the quest.

It is true that this may be the correct way of calling it, but it doesn't actually solve the problem, leaving me more confused than I started. haha :P

Link to comment
Share on other sites

I don't mean this in a rude way, but that doesn't make much sense, and your code doesn't actually debug it. While it may be true that Papyrus "interprets that as you casting the function to a Boolean", a function call logically should A) not be modified by surrounding code, and B) always return something without changing the actual functionality of the code (unless of course the function is a void (or Papyrus equivalent)). Also, your code calls for the quest to start and then reads out "Started" regardless of whether or not it actually started, thus there was no way to identify what occurred. Just in case Papyrus actually acts differently than other programming languages, I modified your snippet so that Start() would be called without any surrounding code, and then checks if it had been started (or was running). Neither were true, and it was not able to start the quest.

It is true that this may be the correct way of calling it, but it doesn't actually solve the problem, leaving me more confused than I started. haha :P

Let me rephrase: Quest.Start() is a Bool function, which means its behavior will change based on your usage of it. Put it alongside an If statement, and you are asking Papyrus to "read" the function. By that syntax, you are asking if the function is currently returning "true," the "== true" statement is assumed (it's still there even if you didn't put it there). You are not telling Papyrus, "I want this function to return true," you are asking "Is this function currently returning true?"

In laymans terms. Putting a Bool function alongside an If statement is a query. Giving it its own line is a statement.

Edited by ThomasKaira
Link to comment
Share on other sites

Let me rephrase: Quest.Start() is a Bool function, which means its behavior will change based on your usage of it. Put it alongside an If statement, and you are asking Papyrus to "read" the function. By that syntax, you are asking if the function is currently returning "true," the "== true" statement is assumed (it's still there even if you didn't put it there). You are not telling Papyrus, "I want this function to return true," you are asking "Is this function currently returning true?"

In laymans terms. Putting a Bool function alongside an If statement is a query. Giving it its own line is a statement.

Wait, now I'm thoroughly confused. The function is a query, but what does that matter when it comes to the actual functionality? If I make it a statement, the function still returns a boolean value.

Link to comment
Share on other sites

If myQuest.Start()

         ;do stuff

EndIf
You are NOT starting the quest with this code, you are asking if it has started. Because what you are actually putting in is this:
If myQuest.Start() == true

        ;do stuff

EndIf
You are asking for the function to return its current value for the object you are calling it to, you are NOT asking it to change that value. In this case, you are asking if that quest is currently running, you are NOT calling for the quest to start. Papyrus will do what you ask it to and ONLY what you ask it to. You must be explicit when using Bool functions:
If MyQuest.Start() == False

        MyQuest.Start()

EndIf

With that snippet, I ask "has the quest started?" If the game answers "no," I then tell it, "start the quest."

Edited by ThomasKaira
Link to comment
Share on other sites

If myQuest.Start()

         ;do stuff

EndIf
You are NOT starting the quest with this code, you are asking if it has started. Because what you are actually putting in is this:
If myQuest.Start() == true

        ;do stuff

EndIf
You are asking for the function to return its current value for the object you are calling it to, you are NOT asking it to change that value. In this case, you are asking if that quest is currently running, you are NOT calling for the quest to start. Papyrus will do what you ask it to and ONLY what you ask it to. You must be explicit when using Bool functions:
If MyQuest.Start() == False

        MyQuest.Start()

EndIf
With that snippet, I ask "has the quest started?" If the game answers "no," I then tell it, "start the quest."
Ah, I gotcha. I've never run into a programming language that actually does that, so I didn't expect that to happen (C++, Java, Javascript, PHP, Python). And just to be clear, this would not set the stage, correct?
; Sets the side quest stage to 10 - and logs a message if it succeeds

if (SideQuestProperty.SetStage(20))

  Debug.Trace("Side quest successfully set to stage 20!")

endIf

Because this is off of the Creation Kit wiki, and it was written by one of the original Skyrim programmers.

EDIT: Took a break, came back, and realized that the above could sound really condescending, and I definitely didn't mean it to be. Sorry if it seems that way!

Edited by libertasmens
Link to comment
Share on other sites

Ah, I gotcha. I've never run into a programming language that actually does that, so I didn't expect that to happen (C++, Java, Javascript, PHP, Python).

And just to be clear, this would not set the stage, correct?

; Sets the side quest stage to 10 - and logs a message if it succeeds

if (SideQuestProperty.SetStage(20))

  Debug.Trace("Side quest successfully set to stage 20!")

endIf

Ewww... That's a bad example. I wouldn't do that because it is so confusing. SetStage actually sets the stage, so in that case, it sets the stage and if it does it successfully, it prints the trace message. You are better to set the stage separately and then test if the stage is that value.

The difference is the way the functions are set up. The Start() function is set up to be a test to see if the quest has started. But it only takes that form if it used as part of a boolean test, like in an if statement. If you use it as a command, then it will start the quest.

Yeah, I can see why you're confused. The key is the "set" part of the setStage function.

Link to comment
Share on other sites

Ah, I gotcha. I've never run into a programming language that actually does that, so I didn't expect that to happen (C++, Java, Javascript, PHP, Python).

And just to be clear, this would not set the stage, correct?

; Sets the side quest stage to 10 - and logs a message if it succeeds

if (SideQuestProperty.SetStage(20))

  Debug.Trace("Side quest successfully set to stage 20!")

endIf

Because this is off of the Creation Kit wiki, and it was written by one of the original Skyrim programmers.

EDIT: Took a break, came back, and realized that the above could sound really condescending, and I definitely didn't mean it to be. Sorry if it seems that way!

No, no. What I described only really applies to Bool functions (Which Start() is). SetStage() is an Int function, meaning it has separate functions for getting and setting values. Bool function logic combines those two, and which is used depends on where you use it in your script.

You can use the Set function to perform a Bool check, but it's not a very clean way to do so. Best use the equivalent Get function (if available) instead.

Edited by ThomasKaira
Link to comment
Share on other sites

Ewww... That's a bad example. I wouldn't do that because it is so confusing. SetStage actually sets the stage, so in that case, it sets the stage and if it does it successfully, it prints the trace message. You are better to set the stage separately and then test if the stage is that value.

The difference is the way the functions are set up. The Start() function is set up to be a test to see if the quest has started. But it only takes that form if it used as part of a boolean test, like in an if statement. If you use it as a command, then it will start the quest.

Yeah, I can see why you're confused. The key is the "set" part of the setStage function.

Alrighty, thanks! Glad we cleared that up. :)

So anyway, even with that change, it's now coming up with weird results.

I used theQuest.Start(), then passed isStarting(), isRunning(), and Start() into an If statement, all of which returned false.

YET when querying getStage, it returns 0. Not sure if this means anything, but that's what I get.

Link to comment
Share on other sites

Glad you figured it out. I was about to ask to see your quest script, and an image of how the quest is setup. :thumbup:

Now it's not working again. :(

Here's the quest script:

;BEGIN FRAGMENT CODE - Do not edit anything between this and the end comment

;NEXT FRAGMENT INDEX 15

Scriptname QF_theQuest_0101BD4C Extends Quest Hidden


;BEGIN ALIAS PROPERTY EntryLock

;ALIAS PROPERTY TYPE ReferenceAlias

ReferenceAlias Property Alias_EntryLock Auto

;END ALIAS PROPERTY


;BEGIN ALIAS PROPERTY ControlSphere

;ALIAS PROPERTY TYPE ReferenceAlias

ReferenceAlias Property Alias_ControlSphere Auto

;END ALIAS PROPERTY


;BEGIN ALIAS PROPERTY CatacombsTrigger

;ALIAS PROPERTY TYPE ReferenceAlias

ReferenceAlias Property Alias_CatacombsTrigger Auto

;END ALIAS PROPERTY


;BEGIN ALIAS PROPERTY DweRoomElevator

;ALIAS PROPERTY TYPE ReferenceAlias

ReferenceAlias Property Alias_DweRoomElevator Auto

;END ALIAS PROPERTY


;BEGIN ALIAS PROPERTY Lexicon

;ALIAS PROPERTY TYPE ReferenceAlias

ReferenceAlias Property Alias_Lexicon Auto

;END ALIAS PROPERTY


;BEGIN ALIAS PROPERTY DweRoomTrigger

;ALIAS PROPERTY TYPE ReferenceAlias

ReferenceAlias Property Alias_DweRoomTrigger Auto

;END ALIAS PROPERTY


;BEGIN ALIAS PROPERTY CoreActivator

;ALIAS PROPERTY TYPE ReferenceAlias

ReferenceAlias Property Alias_CoreActivator Auto

;END ALIAS PROPERTY


;BEGIN FRAGMENT Fragment_7

Function Fragment_7()

;BEGIN CODE

SetObjectiveCompleted(1,true)

;END CODE

EndFunction

;END FRAGMENT


;BEGIN FRAGMENT Fragment_11

Function Fragment_11()

;BEGIN CODE

SetObjectiveCompleted(30,true)

;END CODE

EndFunction

;END FRAGMENT


;BEGIN FRAGMENT Fragment_9

Function Fragment_9()

;BEGIN CODE

SetObjectiveCompleted(10,true)

;END CODE

EndFunction

;END FRAGMENT


;BEGIN FRAGMENT Fragment_12

Function Fragment_12()

;BEGIN CODE

SetObjectiveCompleted(40,true)

;END CODE

EndFunction

;END FRAGMENT


;BEGIN FRAGMENT Fragment_5

Function Fragment_5()

;BEGIN CODE

SetObjectiveCompleted(0,true)

;END CODE

EndFunction

;END FRAGMENT


;BEGIN FRAGMENT Fragment_13

Function Fragment_13()

;BEGIN CODE

SetObjectiveCompleted(50,true)

;END CODE

EndFunction

;END FRAGMENT


;BEGIN FRAGMENT Fragment_10

Function Fragment_10()

;BEGIN CODE

SetObjectiveCompleted(20,true)

;END CODE

EndFunction

;END FRAGMENT


;END FRAGMENT CODE - Do not edit anything between this and the begin comment

And then I've got this little script that I use to actually set the stage.
Scriptname theScript extends ObjectReference  


Quest property theQuest auto

Int property stage=0 auto



Event onTriggerEnter(ObjectReference akActionRef)

	if(akActionRef==Game.GetPlayer())

        if(!theQuest.IsRunning()&&!theQuest.IsCompleted())

            theQuest.start()

			theQuest.SetStage(stage) 

            if(theQuest.isStarting()||theQuest.IsRunning()||theQuest.Start())

				Debug.Notification("Started")

            Else

				Debug.Notification("NoStart")

			EndIf

			theQuest.SetActive(true)

        EndIf


        if((theQuest.getStage()<stage))

            theQuest.setStage(stage)

            if(theQuest.getStage()==stage)

				Debug.Notification("AttemptedSet. Success!")

			Else

				Debug.Notification("AttemptedSet. Failure.")

			EndIf

        ElseIf(theQuest.getStage()==stage)

            Debug.Notification("StageGood.")

        EndIf

	EndIf

EndEvent

Edited by libertasmens
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...