for difficulty, data in StageDifficulties do
-- 'data' is the table
if PlrStage >= data[1] or PlrStage <= data[2] then
return difficulty -- return the key, "Easy", "Medium", etc
end
end

local function FindPlayerDifficulty(PlrStage)
for i,v in pairs(StageDifficulties) do
if PlrStage >= v[1] and PlrStage <= v[2] then
return v[3]
end
end
end

local plrDifficulty = "Unknown" -- default
for difficulty, data in StageDifficulties do
if math.clamp(PlrStage, data[1], data[2]) == PlrStage then
plrDifficulty = difficulty -- sets the variable as the current difficulty that matches the condition
end
end
return plrDifficulty

local StageDifficulties = {
Easy = {1,4,"Easy"};
Medium = {5,9,"Medium"};
Hard = {10,14,"Hard"};
Insane = {15,18,"Insane"};
}
local function FindPlayerDifficulty(PlrStage)
local ascendingOrder = {"Easy", "Medium", "Hard", "Insane"}
for _, difficulty in ascendingOrder do
local data = StageDifficulties[difficulty]
if PlrStage <= data[2] then
return difficulty
end
end
return "Unknown"
end

Itâ€™s a bit tricky because Luaâ€™s dictionaries arenâ€™t ordered, which means when you iterate (loop) through it, itâ€™ll give us a random order, so we define an ascending order of the difficulties and lie upon them.

As we are already making the difficulty check from the smallest to the largest (relative to the playerâ€™s level), you donâ€™t need the minimum level for such difficulty & the keys for the StageDifficulties can already be used, so thereâ€™s no need for the values to be tables but rather just a number, but as I donâ€™t know if youâ€™re using these for something else Iâ€™d preferred to separate this solutions

local StageDifficulties = {
Easy = 4;
Medium = 9;
Hard = 14;
Insane = 18;
}
local function FindPlayerDifficulty(PlrStage)
local ascendingOrder = {"Easy", "Medium", "Hard", "Insane"}
for _, difficulty in ascendingOrder do
local data = StageDifficulties[difficulty]
if PlrStage <= data then
return difficulty
end
end
return "Unknown"
end

This locks the value between the first and second value in the table, if the actual value of PlrStage is the locked value, the user is at the current difficulty:

-- another example
local value = 12
local max = 8
local min = 3
local lockedValue = math.clamp(value, min, max)
print(lockedValue == realValue)
-- Prints 'false' because 12 is not in between 8 and 3

math.clamp returns a number that is either in between the minimum or maximum value, or if the number is the minimum or maximum, it returns that instead:

local n = 20
local max = 40
local min = 35
local value = math.clamp(n, min, max)
print(value, n)
-- Since 'n' is 20 and is not in between 40 and 35, 'value' would be 35 since that's the minimum value

I love your explanation on math.clamp, but i noticed you stated one thing twice:

These statements in the sentence are the exact same.

EDIT â€”
You could also edit it to be like this:

math.clamp returns a number that is either in between the minimum or maximum value, or if the value is the minimum or maximum, then it returns that instead:

local player = game.Players.LocalPlayer
local leaderstats = player:WaitForChild("leaderstats")
local stage = leaderstats.Stage
local DifficultyDisplay = script.Parent.DifficultyDisplay
local StageDifficulties = {
["Easy"] = {1,4,Color3.fromRGB(71, 213, 0)};
["Medium"] = {5,9,Color3.fromRGB(223, 104, 0)};
["Hard"] = {10,14,Color3.fromRGB(240, 40, 0)};
["Insane"] = {15,18,Color3.fromRGB(182, 78, 241)};
}
local function DifficultyInfo(PlrStage, Objective)
if Objective == "Difficulty" then
for difficulty, data in StageDifficulties do
if math.clamp(PlrStage, data[1], data[2]) == PlrStage then
return difficulty
end
end
else
for difficulty, data in StageDifficulties do
if math.clamp(PlrStage, data[1], data[2]) == PlrStage then
return data[3]
end
end
end
end
stage:GetPropertyChangedSignal("Value"):Connect(function()
DifficultyDisplay.Text = DifficultyInfo(stage.Value, "Difficulty")
DifficultyDisplay.TextColor3 = DifficultyInfo(stage.Value, "Difficulty Color")
end)
DifficultyDisplay.Text = DifficultyInfo(stage.Value, "Difficulty")
DifficultyDisplay.TextColor3 = DifficultyInfo(stage.Value, "Difficulty Color")

Line #55 is: DifficultyDisplay.Text = DifficultyInfo(stage.Value, â€śDifficultyâ€ť)

This is because neither of the loops returned a value, just add

return "Unknown"

To the bottom of the DifficultyInfo function. Though, I propose this as a better function:

local function DifficultyInfo(PlrStage)
for difficulty, data in StageDifficulties do
if math.clamp(PlrStage, data[1], data[2]) == PlrStage then
return difficulty, data[3] -- returns the name and the color
end
end
return "", Color3.fromRGB() -- return 2 default values
end
local difficulty, color = DifficultyInfo(stage.Value)

If you have data that is being set to the value in leaderstats, that may be causing the issue; Sometimes the data may have been loaded when the script runs, or other times it hasnâ€™t.

Since the default value for an IntValue is 0 and 0 doesnâ€™t exist as a level, that could be your issue