How to increase odds of rare items based on players item

I want a players fishing rod to determine the kinds of fish they can catch. Higher skill the fishing rod has, the more rare fish are added. The FishData has a value called ‘Rarity’ and I basically add however much the Rarity is of each fish into a table. Like so

-- Go through all the fish
for fish, v in pairs(WaterType) do
	-- Loop through fish rarity
	for i = 1, v.Rarity do
		table.insert(AllFish, fish)
	end
end

So the higher the Rarity value is, the more likely you are to catch that fish, as it gets added into the table more times.

How can I incoprorate the rods skill to increase the rarities of lower rarity fish? At first I thought something like

-- Go through all the fish
for fish, v in pairs(WaterType) do
	-- Loop through fish rarity
	for i = 1, v.Rarity * RodSkill do
		table.insert(AllFish, fish)
	end
end

But that’d also increase the more common fish, and would actually make it harder to catch the rarer fish.

The rod data

return {
	Rods = {
		-- Skill determines rarity of fish
		['Basic Rod'] = {
			Skill = 1,
		},
		
		['Iron Rod'] = {
			Cost = 150,
			Skill = 2,
		},
		
		['Special Rod'] = {
			ID = 12345678,
			Skill = 10,
		},
	},
}

And the FishData

return {
	['Freshwater'] = {
	-- Common
		['Smelt'] = {
			Rarity = 20,
			Cash = 1,
			Difficulty = 1,
		},
		['Goby'] = {
			Rarity = 20,
			Cash = 1,
			Difficulty = 1,
		},
		['Ito'] = {
			Rarity = 20,
			Cash = 1,
			Difficulty = 1,
		},
	-- Uncommon
		['Eel'] = {
			Rarity = 15,
			Cash = 1,
			Difficulty = 2,
		},
		['Bowfin'] = {
			Rarity = 15,
			Cash = 1,
			Difficulty = 2,
		},
		['Catfish'] = {
			Rarity = 15,
			Cash = 1,
			Difficulty = 2,
		},
		['Kokanee'] = {
			Rarity = 15,
			Cash = 1,
			Difficulty = 2,
		},
	-- Rare
		['Carp'] = {
			Rarity = 10,
			Cash = 1,
			Difficulty = 3,
		},
		['Black Bass'] = {
			Rarity = 10,
			Cash = 1,
			Difficulty = 3,
		},
		['Trout'] = {
			Rarity = 10,
			Cash = 1,
			Difficulty = 3,
		},
	-- 
		['Alligator Gar'] = {
			Rarity = 5,
			Cash = 1,
			Difficulty = 4,
		},
	-- Legendary
		['Arapaima'] = {
			Rarity = 1,
			Cash = 1,
			Difficulty = 5,
		},
	},
}
2 Likes

A possible solution would be to have a maximum difficulty, such as 100. What you would do is subtract the “diffuculty” from the “max diffuculty” and you will be left with a number between 0-100 representing how easy it should be to catch that fish.

For example:
Difficulty = 5
MaxDifficulty = 100

100 - 5 = 95

Add it to the array 95 times

There is no real other way to do this without a maximum value because then it’s impossible to logically determine how many times you want it to be added. An alternative you could do is make a “Chance” property instead of “Difficulty”, and the value of “Chance” would simply represent how many times you would insert it into the array.

Hope this helps!

1 Like

The ‘Chance’ property is already in palce, I have Rarity. That number basically is how many times that fish gets put into the array

1 Like

Your approach to generating random loot isn’t bad, but adding items to a list makes it relatively difficult to change probabilities later, and locks you into probability ‘increments’; say for example you have an array of 100 elements with each type of loot added some number of times. This has the following pitfalls:

  1. Your probabilities must be a multiple of 1%
  2. You can only have a maximum of 100 unique loot items on the list
  3. Once you generate a “loot array”, this essentially locks you in to the probabilities you’ve set. To change the probabilities you have to re-create the array from scratch.

To solve your issue, you’ll want a function that can handle picking an element from a list based on any weight, and allows you to change the weight of specific items. The easiest way to achieve the latter is to add a ‘RarityModifier’ property to each possible item, which determines how much a higher skill affects its rarity value - an item with a Rarity of 5 and a RarityModifier of 3 would have an effective rarity of 5 with a skill level of 0, an effective rarity of 8 with a skill level of 1, an effective rarity of 11 with a skill level of 2, and so on.

The advantage of this approach is that it allows you to easily fine-tune your items to become more or less likely depending on the type of rod used, and that you’re no longer locked into quantized probabilities.

So to finalize, I’d suggest a function like this:

function getLoot(waterType, rodSkill)
	--Cumulative rarity; this is the rarity of all items added together
	local totalRarity = 0
	for k, v in pairs(waterType) do
		--Calculate effective rarity of the item
		local rarity = math.max(0, v.Rarity + (v.RarityModifier or 0) * rodSkill)
		totalRarity = totalRarity + rarity
	end

	--Generate a random number in the range [0, totalRarity)
	local pick = math.random() * totalRarity

	--Iterate again until we figure out what was picked
	local totalRarity = 0
	for k, v in pairs(waterType) do
		--Calculate effective rarity of the item
		local rarity = math.max(0, v.Rarity + (v.RarityModifier or 0) * rodSkill)
		totalRarity = totalRarity + rarity

		--Check if the total rarity is larger than the 'pick' value; the first time this happens means we hit the item that was picked
		if (totalRarity >= pick) then 
			return v
		end
	end
end

Hope this helps! :slight_smile:

(Re-posted this because I accidentally replied to a previous post)

1 Like

Sorry for the late response! :grimacing:

I’m a little confused. Does this just return the 1 fish? Like so

ChosenFish = getLoot(waterType, rodSkill)

or is it returning the table of fish or what?

1 Like

Heya, no worries! It’ll return a single fish like you said in your example. If you want more than one you’ll have to call the function multiple times.

And so the basic rod skill would have to be to 0? Is there anyway to have it default as 1, not 0?

The basic rod would have a skill of 0, yes. The default could be whatever you want it to be, but this would make the skill mapping less intuitive - is there any particular reason you can’t change the default rod’s skill level to 0?

It’s more a visual thing I wanna do. I wanna have like 5 stars, and be able to divide those stars into like

1 skill = 1/2 star
2 skill = 1 star
3 skill = 1 1/2 star
--etc.

EDIT nvm im assuming i could just have 0 skill = 1/2 star, 1 skill = 1 star, etc.

Ah, that makes sense. :slight_smile:

This would be what I’d have suggested as well. Hope your development goes well!

One last thing while testing, if I do

local WaterType = FishData[fishingSpot.Parent.Name]
local RandomFish = GetRandomFish(WaterType, RodData.Skill)
print(RandomFish)

It prints a table. I want it to print the actual fish tho, like the name of the fish, not a table of its content

Ah, that’s a simple fix. The function just needs to return both the key and the value for the picked item:

function getLoot(waterType, rodSkill)
	--Cumulative rarity; this is the rarity of all items added together
	local totalRarity = 0
	for k, v in pairs(waterType) do
		--Calculate effective rarity of the item
		local rarity = math.max(0, v.Rarity + (v.RarityModifier or 0) * rodSkill)
		totalRarity = totalRarity + rarity
	end

	--Generate a random number in the range [0, totalRarity)
	local pick = math.random() * totalRarity

	--Iterate again until we figure out what was picked
	local totalRarity = 0
	for k, v in pairs(waterType) do
		--Calculate effective rarity of the item
		local rarity = math.max(0, v.Rarity + (v.RarityModifier or 0) * rodSkill)
		totalRarity = totalRarity + rarity

		--Check if the total rarity is larger than the 'pick' value; the first time this happens means we hit the item that was picked
		if (totalRarity >= pick) then 
			return k, v
		end
	end
end

With that, you can get the name and the table with its information:

local name, data = getLoot(waterType, rodSkill)
1 Like