Quest Complete or In Progress Detection

Hello everyone, to keep it quite simple… I made a quest system where the player has to interact with an NPC to enable a quest. However, I do NOT want the quest to be redoable or be given to the player if the player is already in progress with ANOTHER quest. How exactly would I achieve this?

I have tried using Collection Service to tag the player with “Quest” whenever they receive a quest, and when they try to do it again, it checks to see if they have that tag or not, and responds respectively. However, for some reason it didn’t quite work out.

Here is my code:

local player = game.Players.LocalPlayer
local remote = game:GetService("ReplicatedStorage"):WaitForChild("Remotes"):WaitForChild("QuestRemote")
local remote2 = game:GetService("ReplicatedStorage"):WaitForChild("Remotes"):WaitForChild("QuestGUI")
local remote3 = game:GetService("ReplicatedStorage"):WaitForChild("Remotes"):WaitForChild("QuestRetake")
local AcceptQuest = script.Parent:WaitForChild("Accept")
local DeclineQuest = script.Parent:WaitForChild("Decline")
local DialogueQuest = script.Parent:WaitForChild("Dialogue")
local mainFrame = script.Parent



local function TypeWrite(textlabel, text)
	for i = 1, #text do
		textlabel.Text = string.sub(text, 1, i)
		wait(0.010)
	end
end

remote2.OnClientEvent:Connect(function(player)
	if mainFrame.Position == UDim2.new(0.291, 0,0.765, 0) then
		if DialogueQuest.Text == "This village might seem peaceful and harmonious from the outisde, but it is filled with wealth-lust bandits. Do you think you can help bring peace? Kill 2 Bandits." or DialogueQuest.Text == "You already have a quest in progress..." then
			closeDialogue()
		end
	elseif mainFrame.Position == UDim2.new(0.291, 0,1.2, 0) then
		openDialogue()
		
		--if the player hasn't already done the quest then...
		
		TypeWrite(DialogueQuest, "This village might seem peaceful and harmonious from the outisde, but it is filled with wealth-lust bandits. Do you think you can help bring peace? Kill 2 Bandits.")
		AcceptQuest.Visible = true
		DeclineQuest.Visible = true
		for i = 1, 0.4, -0.09 do
			AcceptQuest.Transparency = i
			AcceptQuest.TextTransparency = i
			DeclineQuest.Transparency = i
			DeclineQuest.TextTransparency = i
			wait()
		end
		AcceptQuest.MouseButton1Click:Connect(function()
			remote3:FireServer()
			closeDialogue()
		end)
		DeclineQuest.MouseButton1Click:Connect(function()
			TypeWrite(DialogueQuest, "Alright then.. scram!!")
			wait(1)
			closeDialogue()
		end)
		
		--and if the player already did the quest then..
		--DialogueQuest.Text = ""
		--TypeWrite(DialogueQuest, "You already have a quest in progress...")
		
		
	end
end)



function closeDialogue()
	mainFrame:TweenPosition(
		UDim2.new(0.291, 0,1.2, 0), 
		"Out",
		"Quad", 
		1,
		false 
	)
end

function openDialogue()
	mainFrame:TweenPosition(
		UDim2.new(0.291, 0,0.765, 0),
		"Out",
		"Quad", 
		1, 
		false
	)
end

You put the function at the very end, which doesn’t make sense because you called the function before it was made.

Alright there are alot of ways to do that! Let me show you some!

1. Module scripts!

You could make a dictionary inside a module script which contains each players name or uuid, then either set them to true or false you can also make some functions to make that easier! Like that you can also easily save them with datastores! Another way would be to just add their uuid to a table and check if they’re in the table or not, although I like the dictionary approach more!

2. Boolean Values in Workspace

Make a boolean value and parent it to the player, if it’s true then don’t allow the player to take quests, if its false then allow him! Save the value when the player is leaving and give it to him on join!

Note: I listed some possibilities without Collection Service

1 Like

Hello thank you for replying, I have another question, I had a boolean value saved under the player’s “QuestInformation” folder, however, I wasn’t able to access it through the local script in my PlayerGui service. How can I fix that?

Can you show me the code of how you were trying to do it?

Sure. First of all, here is a picture of the “QuestInformation” folder I have under the player…
image

Next, inside the same script I sent before I wrote this:

local player = game.Players.LocalPlayer
local remote = game:GetService("ReplicatedStorage"):WaitForChild("Remotes"):WaitForChild("QuestRemote")
local remote2 = game:GetService("ReplicatedStorage"):WaitForChild("Remotes"):WaitForChild("QuestGUI")
local remote3 = game:GetService("ReplicatedStorage"):WaitForChild("Remotes"):WaitForChild("QuestRetake")
local AcceptQuest = script.Parent:WaitForChild("Accept")
local DeclineQuest = script.Parent:WaitForChild("Decline")
local DialogueQuest = script.Parent:WaitForChild("Dialogue")
local mainFrame = script.Parent



local function TypeWrite(textlabel, text)
	for i = 1, #text do
		textlabel.Text = string.sub(text, 1, i)
		wait(0.010)
	end
end

remote2.OnClientEvent:Connect(function(player)
	if mainFrame.Position == UDim2.new(0.291, 0,0.765, 0) then
		if DialogueQuest.Text == "This village might seem peaceful and harmonious from the outisde, but it is filled with wealth-lust bandits. Do you think you can help bring peace? Kill 2 Bandits." or DialogueQuest.Text == "You already have a quest in progress..." then
			closeDialogue()
		end
	elseif mainFrame.Position == UDim2.new(0.291, 0,1.2, 0) then
		openDialogue()
				
		if player:WaitForChild("QuestInformation"):WaitForChild("QuestStatus").Value == false then
			TypeWrite(DialogueQuest, "This village might seem peaceful and harmonious from the outisde, but it is filled with wealth-lust bandits. Do you think you can help bring peace? Kill 2 Bandits.")
			AcceptQuest.Visible = true
			DeclineQuest.Visible = true
			for i = 1, 0.4, -0.09 do
				AcceptQuest.Transparency = i
				AcceptQuest.TextTransparency = i
				DeclineQuest.Transparency = i
				DeclineQuest.TextTransparency = i
				wait()
			end
			AcceptQuest.MouseButton1Click:Connect(function()
				remote3:FireServer()
				closeDialogue()
			end)
			DeclineQuest.MouseButton1Click:Connect(function()
				TypeWrite(DialogueQuest, "Alright then.. scram!!")
				wait(1)
				closeDialogue()
			end)
			
		else
			DialogueQuest.Text = ""
			TypeWrite(DialogueQuest, "You already have a quest in progress...")
		end
		
	end
end)



function closeDialogue()
	mainFrame:TweenPosition(
		UDim2.new(0.291, 0,1.2, 0), 
		"Out",
		"Quad", 
		1,
		false 
	)
end

function openDialogue()
	mainFrame:TweenPosition(
		UDim2.new(0.291, 0,0.765, 0),
		"Out",
		"Quad", 
		1, 
		false
	)
end

However, it gives me a nil → waitforchild error.

Try out removing the second waitforchild as usually iirc if you wait for a parent the children also get waited for. (Probably not the right words to describe it but yeah)
So:
player:WaitForChild(“QuestInformation”).QuestStatus.Value

Okay, so I just read that post… it says that I will need to move my script to ServerScriptService which was what I was thinking the issue was as well. But can you tell me how I can make the dialogues (which are in PlayerGui) function respectively if the player has a quest or not from Server Script Service? I appreciate your help a lot, and it it’s fine if you are not sure.

IntValue.Changed. Does this help? You could maybe start the dialogue once the values change

I will go and try using this, or remotes and notify any updates I find.

Yup, that sounds like a good way to do it, lemme know if you need more help

1 Like

Yo, sorry for replying quite late, but I found the issue to me not being able to access the player’s values since I was actually accessing the player’s model in workspace and not the player in the Players service. To fix that, I just had to create a variable…

local Player = game.Players.LocalPlayer

After that, I just checked to see if the player was in possession of the bool value and whether it was true or not, and the quest would perform accordingly.