Quest system rolls same ID on duplicate quests

Heya,

Currently making a jailbreak-like quest system, but this system is being annoying. Even ChatGPT can’t fix it, lol.

The problem is that as said, when duplicate quest rolls (which is fine), it gets assigned the same ID, no matter if I set a custom variable, or just use index of the for loop. ChatGPT and I both tried to make a table that stores numbers that have already been used so the game gets forced to skip that number and go to the next one (e.g. 2 is used, force to 3). Even that didn’t work. If anyone could help out that’d mean a lot to me.

Problem can be seen in screenshot.
In screenshot 1 we see that 1 quest has been rolled 3 times ranging at 4-6 so it got the ID 6 for 3 times. The other screenshots are self explanatory and show more information. On the same quest, the id is the same. I want to avoid this and get a simple 1 2 3 4 5 6 order, so if 2 and 5 are the same quest, they still independently get 2 and 5, and not 1, 3, 4, 5, 5, 6 (or 1, 5, 3, 4, 5, 6)



Here’s my code so far, I’ll briefly explain what all functions do.

Print: loops through t: table, and then print the id, name, desc and xpreward.
Sort: sorts the table from low to high (or A to Z), str: string can be set to anything, so if you want to sort on description, you just set str: string to “description”
Assign: this is one of hundred things i tried: loop through table to assign a custom ID to value (quest) and then str:string which is ID, so quest[“id”] == quest.id, we set it to the custom number. when we loop through table we add + 1 each time to ‘number’, but on the same quest it just skips, lol
Randomize: if statement is true we allow duplicate quests, i dont show the ‘false’ part, because that works perfectly fine and doesn’t need adjustments., we loop it for 6 times so we get 6 quests and we put them in a questIndices table so we can insert them into the openQuests table on the next loop, and then we have our 6 randomized (duplicate allowed) quests table. we try to assign id, but that’s the main problem, and print everything (id, name, desc, xpreward) and then return it so we can use it in another script.

function Quests:Print(t)
	local prename = "[Season System]"
	for i, quest in pairs(t) do
		print(prename.." id = "..quest.id.." | name = "..quest.name.." | description = "..quest.description.." | xpreward = "..quest.xpreward)
	end
end

function Quests:Sort(t, str)
	table.sort(t, function(a, b)
		return a[str] < b[str]
	end)
	return t
end

function Quests:Assign(t, str)
	local number = 0
	for i, value in pairs(t) do
		number += 1
		value[str] = number
	end
	return Quests:Sort(t, str)
end

function Quests:Randomize(Player: Player, Statement: boolean)
	--set STATEMENT: boolean to TRUE if duplicate quests are allowed
	--set STATEMENT: boolean to FALSE if duplicate quests are NOT allowed
	if Statement == true then
		local questIndices = {}
		for i = 1, 6 do
			local randomIndex = math.random(1, #PossibleQuests)
			questIndices[i] = randomIndex
		end
		local openQuests = {}
		for i, index in pairs(questIndices) do
			local quest = PossibleQuests[index]
			--quest.id = i [tried this previously, but that just gives the same id if its the same quest]
			table.insert(openQuests, quest)
		end
		Quests:Assign(openQuests, "id")
		Quests:Print(openQuests)
		return openQuests
    end
end

Help is welcome, thanks!

Please try this instead and see if that solve your problem.

for i = 1, 1, 6 do
		local randomIndex = math.random(1, #PossibleQuests)
		questIndices[i] = randomIndex
end

This simply will incrementing the value of i from 1 up to 6, and increment the value of i by 1 for every iteration.

1 Like
for i = 1, 1, 6 do

Gives me 1 quest only, assuming that the 6 is the incrementer. and 1, 1 maxes out at 1 to 1

Switched it up to:

for i = 1, 6, 1 do

But then the issue still continues


That is my mistake, I do apologize. Can I see the value of PossibleQuests?

local randomIndex = math.random(1, #PossibleQuests)
1 Like

No problem. The PossibleQuests variable is a table full of possible quest, each giving a name, description and a math.random(x, y) xpreward value.

I’ll send the entire table, note that only 6 of these quests has to be randomized, and not all of them.

local PossibleQuests = {
	{
		name = "Fall5Seconds",
		description = "Freefall for 5 seconds",
		xpreward = math.random(25, 50),
	},
	{
		name = "Earn1000Money",
		description = "Earn $1,000 Money",
		xpreward = math.random(35, 50),
	},
	{
		name = "Jump5Times",
		description = "Jump 5 times",
		xpreward = math.random(20, 30),
	},
	{
		name = "Walk100Studs",
		description = "Walk 100 Studs",
		xpreward = math.random(20, 30),
	},
	{
		name = "Water1Minute",
		description = "Be in water for 1 minute",
		xpreward = math.random(25, 50),
	},
	{
		name = "PlayWithAFriend",
		description = "Play with a friend",
		xpreward = math.random(40, 50),
	},
	{
		name = "Die10Times",
		description = "Die 10 times",
		xpreward = math.random(10, 20),
	},
	{
		name = "Chat30Times",
		description = "Send a message 30 times",
		xpreward = math.random(10, 20),
	},
}

Edit: if you need to experiment, i have no problem sharing the rbxl file with you in dms

You can try simplifying your for loop from 2 loops to one loop only and see if that solves your problem.

Instead of

for i = 1, 6 do
		local randomIndex = math.random(1, #PossibleQuests)
		questIndices[i] = randomIndex
end
local openQuests = {}
for i, index in pairs(questIndices) do
		local quest = PossibleQuests[index]
		table.insert(openQuests, quest)
end
Quests:Assign(openQuests, "id")
Quests:Print(openQuests)
return openQuests

To this

local openQuests = {}
for i = 1, 6 do
	local randomQuestIndex = math.random(1, #PossibleQuests)
	table.insert(openQuests, PossibleQuests[randomQuestIndex])
end
-- There is no need to use 2 loops here.
local newSortedQuestList = Quests:Assign(openQuests, "id") -- Loops in OpenQuests, changing the value of id
Quests:Print(newSortedQuestList )   -- Print it out
return newSortedQuestList 

Second, in your Assign(t,str) try this instead.

function Quests:Assign(t, str)
	for i, value in ipairs(t) do
		value[str] = i
	end
	return Quests:Sort(t, str)
end

EDIT: Change the first code
EDIT2: Wrong placement.
EDIT3: Change from pairs() to ipairs() in the second code.

1 Like

Same issue, I assume it’s because you didn’t actually change something in the logic of the code, but you just shortened it. Keep in mind you did remove the 1 increment on for i = 1, 6 do

Tried ipairs, but that wouldn’t make much of a difference as we already return a sorted A > Z table

Maybe this extra code will help you out, I stated in my first post that I wouldn’t send the ‘false’ part of the code (aka non duplicate quests), because that works fine. But maybe you see something in here that you can use in the ‘true’ statement. Here is the full Randomize function I currently have.

function Quests:Randomize(Player: Player, Statement: boolean)
	--set STATEMENT: boolean to TRUE if duplicate quests are allowed
	--set STATEMENT: boolean to FALSE if duplicate quests are NOT allowed
	if Statement == true then
		local openQuests = {}
		for i = 1, 6 do
			local randomQuestIndex = math.random(1, #PossibleQuests)
			table.insert(openQuests, PossibleQuests[randomQuestIndex])
		end
		-- There is no need to use 2 loops here.
		local newSortedQuestList = Quests:Assign(openQuests, "id") -- Loops in OpenQuests, changing the value of id
		Quests:Print(newSortedQuestList)   -- Print it out
		return newSortedQuestList 
	elseif Statement == false then
		local questIndices = {}
		for i = 1, 6 do
			local randomIndex
			repeat
				randomIndex = math.random(1, #PossibleQuests)
			until not questIndices[randomIndex]
			questIndices[randomIndex] = true
		end
		local openQuests = {}
		for index, _ in pairs(questIndices) do
			table.insert(openQuests, PossibleQuests[index])
		end
		for i, quest in pairs(openQuests) do
			quest.id = i
		end
		Quests:Sort(openQuests, "id")
		Quests:Print(openQuests)
		return openQuests
	end
end

Edit: the reason the false statement works is because we reroll any duplicate quest, giving it a new number. In the ‘true’ statement when 2 quests get rolled (duplicate) it doesn’t actually change the number

Alright I manage to solve it, please give me one second when I’m typing it in.

1 Like

So, you can solve this problem where the id is not being correctly assigned by simply creating a new table and handcraft it.

local openQuests = {}   -- Continue from this part
for i = 1, 6 do
	local randomQuestIndex = math.random(1, #PossibleQuests)
	table.insert(openQuests, PossibleQuests[randomQuestIndex])
end

-- New Section
local newCraftedQuestTable = {}
for i, v in pairs(openQuest) do
  newCraftedQuestTable[i] = v
end

for i, v in pairs(newCraftedQuestTable) do
  print(i,v.name)
end

Here is the result

WARNING: After putting this code in, it may break you original code, so make sure you fix it properly.

You can see that the even the quest is duplicated, the id is running in sequence properly.

Note 1: openQuest is an array. newCraftedQuestTable is a dictionary. Make sure that your original code accesses this properly to prevent any further problems.

Note 2: This approach’s time compilation is still linear of N, so don’t worry if it will cause any lags, unless you have million quests for a player at once.

1 Like

Thanks. Without adding my complicated code it works.

One thing though, how do I set the actual id? We know we have name, description & xpreward, and we assign the ID by simply doing quest.id, I think I implemented this wrong. Could you take a look at it?

function Quests:Randomize(Player: Player, Statement: boolean)
	--set STATEMENT: boolean to TRUE if duplicate quests are allowed
	--set STATEMENT: boolean to FALSE if duplicate quests are NOT allowed
	if Statement == true then
		local openQuests = {}
		local newCraftedQuestTable = {}
		for i = 1, 6 do
			local randomQuestIndex = math.random(1, #PossibleQuests)
			table.insert(openQuests, PossibleQuests[randomQuestIndex])
		end
		for index, quest in pairs(openQuests) do
			newCraftedQuestTable[index] = quest
		end
		for i, v in pairs(newCraftedQuestTable) do
            print(i, v.name) --does print name under 1,2,3,4,5,6 with duplicate quests! :yay:
			v.id = i --this makes it go crazy again..?
		end
		Quests:Print(openQuests)
    end
end

Remove Quests:Print(openQuests) and try Quests:Print(newCraftedQuestTable) However, you will have to fix that Print function.

To this

function Quests:Print(t)
	local prename = "[Season System]"
	for i, quest in pairs(t) do
		print(prename.." id = "..i.." | name = "..quest.name.." | description = "..quest.description.." | xpreward = "..quest.xpreward)
	end
end

That would be displayed correctly now.

1 Like

Ahh I see!

I’ll note for myself that to access the IDs I can just loop through the returned table and use index (i)

Thank you so much for solving this issue :smiley: Have a good one! Marked it as solution.

1 Like

Yep! and you are very welcome!. I am glad I could help you solved it! Enjoy coding!

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.