So like what script would I do to make a repeatable quest to kill 5 zombies and earn about 200 Candy (My currency, I alr have a leaderstats with candy and money) but you walk up to him and use the in-game dialogue and after selecting ChoiceA which is yes it activates a quest to kill about 5-10 zombies then you earn a badge and 200 candy?
I believe this could work?
local Npc = workspace.NPC
local Players = game:GetService("Players")
Players.PlayerAdded:Connect(function(plr)
local CurrentQuest = Instance.new("StringValue")
CurrentQuest.Name = "Quest"
CurrentQuest.Value = ""
CurrentQuest.Parent = plr
end)
Npc.ClickDetector.MouseClick:Connect(function(plr)
if plr.Quest.Value ~= "Kill 5 Zombies" then
plr.Quest.Value = "Kill 5 Zombies"
local ZombiesKilled = Instance.new("IntValue")
ZombiesKilled.Value = 0
ZombiesKilled.Name = "ZombiesKilled"
ZombiesKilled.Parent = plr
plr.PlayerGui.DialogueGui.Enabled = true -- you would prob have another script to handle this, and also one to handle the quest gui
while wait(0.01) do
if ZombiesKilled.Value >= 5 then -- you're gonna need a script inside the zombies to increase this value when it dies
ZombiesKilled:Destroy()
plr.leaderstats.candy.Value += 200
plr.PlayerGui.QuestGui:Destroy()
break
end
end
end
end)
what would the other scripts be and how would I customize it? to work with like a interaction or whatever and where would I place it
uh…you put it in the npc and add a click detector in the npc too
ok! i’ll try it out. thank you!
Also how would I make this quest repeatable? and what about the Dialogue gui?
@Robo_Supernova
You probably don’t want to do this, the constant polling would really slow the game down. You’d want to connect an event to the value instead.
You’d probably want to create a ModuleScript for this, which I just made!
Code:
--!strict
local Players = game:GetService("Players")
local PlayerQuests = {} -- This stores all the players' progresses and active quests.
local Quests = { -- This stores all the quest information, this is what you'll most likely want to edit
["KillZombies"] = {
Goal = 5;
Reward = 200;
RewardType = "Candy";
}
}
local QuestModule = {}
local Settings = {
AutorunComplete = true; -- Automatically runs QuestCompleted when a quest is finished
AddQuestIfNotPresent = false; -- Automatically add quest if attempting to increment nonexistent quest
}
function QuestModule.AddPlayer(Player)
PlayerQuests[Player] = {}
end
function QuestModule.RemovePlayer(Player)
PlayerQuests[Player] = nil
end
-- Use this to give a player a quest
function QuestModule.IssueQuest(Player,QuestIdentifier: string)
local Quest = Quests[QuestIdentifier]
if Quest then
local PlayerTable = PlayerQuests[Player] -- Aforementioned table that stores quests for players
if PlayerTable and not PlayerTable[QuestIdentifier] then -- Make sure they don't have this quest
PlayerTable[QuestIdentifier] = {
Progress = 0;
--QuestReference = Quest; // Doesn't currently use this, but could be useful later
}
end
end
end
-- Runs automatically when a player finishes a quest
function QuestModule.QuestCompleted(Player, QuestIdentifier: string): boolean
local Quest = Quests[QuestIdentifier] -- Gets server info on quest
local PlayerTable = PlayerQuests[Player]
local PlayerStats = Player:FindFirstChild("leaderstats")
if Quest and PlayerTable and PlayerTable[QuestIdentifier] and PlayerStats then
local Reward = Quest["Reward"]
local RewardType = Quest["RewardType"]
local StatIncrement = PlayerStats:FindFirstChild(RewardType)
if Reward and StatIncrement and typeof(StatIncrement.Value) == "number" then
StatIncrement.Value += Reward
PlayerTable[QuestIdentifier] = nil
return true
else
warn("Attempted to complete quest "..QuestIdentifier.." for "..tostring(Player)..", but either the reward or the increment was invalid!")
end
else
warn("Attempted to complete quest "..QuestIdentifier.." for "..tostring(Player)..", but either the quest was not found, or the player does not have leaderstats!")
end
return false
end
-- Increases quest progress by Increment (Also runs QuestCompleted unless disabled)
function QuestModule.UpdateQuestProgress(Player, QuestIdentifier: string, Increment: number): boolean
local Quest = Quests[QuestIdentifier]
local PlayerTable = PlayerQuests[Player]
local PlrQuest = PlayerTable and PlayerTable[QuestIdentifier]
if Quest then
if PlrQuest and typeof(PlrQuest) == "table" then
local Goal = Quest["Goal"]
local Progress = PlrQuest["Progress"]
local UpdatedProgress = (Progress + Increment)
print(Goal, UpdatedProgress)
if UpdatedProgress >= Goal then
print("Quest "..QuestIdentifier.." has been completed by "..tostring(Player))
if Settings.AutorunComplete then
QuestModule.QuestCompleted(Player, QuestIdentifier)
end
return true
else
PlrQuest["Progress"] = UpdatedProgress
return false
end
else
if Settings.AddQuestIfNotPresent then
QuestModule.IssueQuest(Player, QuestIdentifier)
else
warn("Attempted to increment quest progress for "..tostring(Player).." on quest "..QuestIdentifier..", but player does not have such quest!")
end
end
else
warn("Attempted to increment quest progress for "..tostring(Player).." on quest "..QuestIdentifier..", but no such quest was found!")
end
return false
end
Players.PlayerAdded:Connect(QuestModule.AddPlayer)
Players.PlayerRemoving:Connect(QuestModule.RemovePlayer)
for i,v in pairs(Players:GetPlayers()) do -- Eliminates race condition
QuestModule.AddPlayer(v)
end
return QuestModule
Solution: ModuleScript
. You have to make it server sided so ,presumably, put it in serverstorage. The UI part should be handled by a LocalScript
. To make it more organized, i hav 2 module scripts, one for quest data and another called QuestService
.
QuestData:
local Module = {}
Module.Quests = {
["Kill Zombie"] = {
RequiredKills = 3, --Amount Of zombies to kill to get reward
CurrentKills = 0,
UI = {
Title = {
Text = "smth",
TextColor3 = Color3.fromRGB(0,0,0)
},
Desc = {
Text = "smth",
TextColor3 = Color3.fromRGB(0,0,0)
},
},
Reward = function(player)
player.leaderstats.Coins.Value += 200 --Reward, modify it to ur needs.
end
}
}
return Module
The Text and Desc is made for handling the GUI and u mite notice that their values match the properties of a TextLabel
.
QuestsService:
local QuestData = require(script.QuestData) -- path to above file.
local Module = {}
function Module:AddQuest(datastore, quest)
for questName, questData in pairs(QuestData.Quests) do
if questName == quest and not datastore.Quests[questName] then
table.insert(datastore.Quests, {questName, Kills = 0, RequiredKills = questData.RequiredKills})
break
end
end
end
function Module:AddKills(datastore, questName, killAmount, player)
for index, quest in ipairs(datastore.Quests) do
if table.find(quest, questName) then
quest.Kills += killAmount
if quest.RequiredKills <= quest.Kills then
QuestData[questName].Reward(player)
table.remove(datastore.Quests, index)
With the above script, ahem module script, adding quests and kills are extremely easy. This was implemented with datastores in mind, and u shud use it too to save quests, and it automatically removes the quest if the currentKills matches the requiredKills. You can use this as a base to create further quests and more efficient systems. If u have any questions, feel free to ask them here.
Have a nice day!
ModuleScripts are usually supposed to go in ServerScriptService rather than ServerStorage.
Also, I’m confused about the QuestService part of your module. How is the datastore section supposed to work? Also, why not just use a dictionary instead of a ton of table.insert, table.find, and looping through the quests constantly?
how would I make the quest be activated? if you know things about the in-game dialogue a want the quest to activate after the players choses ChoiceA which is accept the quest.
As for the location of modulescripts, i use a optimized heirarchy, where I place the modules inside serverstorage and use a custom Loader
to require each of them from the server. As for the datastore issye, i agree its not ideal, and thts because its just created from scratch with no testing in studio(i wrote this in mobile), so it is only intended to b a base for a full-on Quests System.
To activate a quest, you require the module and use Module.IssueQuest
. For example:
local QuestModule = require(game:GetService("ServerScriptService").QuestModule)
-- to give a quest
QuestModule.IssueQuest(Player, QuestIdentifier)
QuestIdentifier would be a string corresponding to a ​quest, such as "KillZombies"
there are many great youtube videos on this topic, i recommend you try them before coming here as this place sometimes can be of no help.
Ok! i’ll try one of the youtube videos and if that doesn’t work then i’ll try these.
the videos didn’t work but I changed the quest so basically you interact using a proximity prompt and hold for 2 seconds then a gui would pop up and say “Find the Witches Cat (0/1)” then once you find the cat and click it using a click detector it changes to “You found the witches cat! (1/1)” then it ends and you get a badge and 150 candy? how do I make it do that and what would the script be?
Wdym? Spooks video on it was amazing, i recommend u check this out.
Nevermind this! I found a working video.