Issue getting a set value within a complicated table using a pairs loop

ok so this is kind of a big script, however the issue is only a small portion.
before i start to describe the issue it is worth noting that the script is being updated, and that the version of the script before hand worked perfectly fine. restating that the script has been fully tested and fully working before these new updates, of which caused an issue.

Ok so i am currently trying to loop through a more complicatedly structured table. the said table is stored within the following module script and looks like so:

  • Module script / Table to loop through
local SpawnAssets = game.ServerStorage.ItemAssets
local Loot = SpawnAssets.LootDrops
local LootSettings = {
	["WEAPONS"]= {
		["Pistol"] = {["Loot"] = Loot.Pistol, ["Chance"] = 100},
		["Revolver"] = {["Loot"] = Loot.Revolver, ["Chance"] = 75},
	},

	["AMMO"] = {
		["Light Ammo"] = {["Loot"] = Loot.LightAmmo, ["Chance"] = 125},
		["Medium Ammo"] = {["Loot"] = Loot.MediumAmmo, ["Chance"] = 100}, 
		["Heavy Ammo"] = {["Loot"] = Loot.HeavyAmmo, ["Chance"] = 0}, --gun unadded
		["Shotgun Ammo"] = {["Loot"] = Loot.ShotgunAmmo, ["Chance"] = 0}, --gun unadded
	},

	["FOOD"] = {
		["Apple"] = {["Loot"] = Loot.Apple, ["Chance"] = 300},
		["Cheez Burger"] = {["Loot"] = Loot.CheezBurger, ["Chance"] = 200},
		["Bloxy Cola"] = {["Loot"] = Loot.BloxyCola, ["Chance"] = 300},
		["Water"] = {["Loot"] = Loot.Water, ["Chance"] = 200},
	},

	["COMMON"] = {
		["Bottle"] = {["Loot"] = Loot.Bottle, ["Chance"] = 300},
		["Light Bulb"] = {["Loot"] = Loot.LightBulb, ["Chance"] = 300},
		["Rubber Duck"] = {["Loot"] = Loot.RubberDuck, ["Chance"] = 300},
		["Can"] = {["Loot"] = Loot.Can, ["Chance"] = 300},
		["Worn Tire"] = {["Loot"] = Loot.WornTire, ["Chance"] = 200},
		["Cat Picture"] = {["Loot"] = Loot.CatPicture, ["Chance"] = 200},
	},

	["UNCOMMON"] = {
		["BrokenWatch"] = {["Loot"] = Loot.BrokenWatch, ["Chance"] = 150},
		["Car Battery"] = {["Loot"] = Loot.CarBattery, ["Chance"] = 150},
		["Vintage lighter"] = {["Loot"] = Loot.Lighter, ["Chance"] = 100},
	},

	["RARE"] = {
		["Award"] = {["Loot"] = Loot.Award, ["Chance"] = 30},
		["Gold"] = {["Loot"] = Loot.Gold, ["Chance"] = 15},
		["Diamond"] = {["Loot"] = Loot.Diamond, ["Chance"] = 5}
	}
}

return LootSettings

My goal is to go through [Item] = {[Loot] = Instance, [Chance] = Number} with the goal of getting the “Chance” for every single category.

Heres a print statement printing my table in its entirety (of what i could actually fit in the capture, but you get the idea.):

In my attempt to do as previously stated, however, it appears that im not getting the whole table.
image
ive observed that for some odd reason, it seems to only be returning the “UNCOMMON” portion of the table.

because of unexpected behavior i get an obvious error:

heres the full script:

--local Assets = script.Parent.UnitSpawnAssets
local Sys = script.Parent
local ATTC = Sys:GetAttribute("AbsenceTimeToClose")
local Cooldown = Sys:GetAttribute("Cooldown")
local LootModule = require(Sys.LootSettings)
local SpawnsModule = require(Sys.SpawnSettings)
local Event = Sys.StorageOpened

for i,Unit in Sys.Parent["Storage Units"]:GetChildren() do
	if Unit.Name == "StorageUnit" then
		local Prompt = Unit.Door.Base.PromptPart.OpenPrompt
		Prompt.HoldDuration = Sys:GetAttribute("TimeToOpen")
		Prompt.MaxActivationDistance = Sys:GetAttribute("DistanceToOpen")
	end
end

------LOOT SPAWNS------------
local function PickLootByChance(SpawnerType) -- >>>THIS IS WHERE THE ISSUE IS!!!<<<<
	local function randomItem(ItemTable)
		local LootTable = {}
		for i,v in pairs(ItemTable) do
			table.insert(LootTable, v) --the table should look like this {COMMON, UNCOMMON, RARE..etc}
		end

		local totalProbability = 0
		
		warn(LootTable) --shown in image 1 (prints numbers instead. i didnt think much of it but it might have something to do with the issue idk)
		
		for _, v in pairs(LootTable) do
			warn(v) --shown in image 2
			totalProbability += v.Chance --error line
		end

		local randomNumber = math.random(1, totalProbability)
		local cumulativeProbability = 0

		for key, v in pairs(LootTable) do
			cumulativeProbability += v.Chance --would also error
			if randomNumber <= cumulativeProbability then
				return v
			end
		end
	end
	
	warn(SpawnerType)

	if SpawnerType == "Universal" then
		local chosenItem = randomItem(LootModule)
		warn(chosenItem, chosenItem.Loot)
		return chosenItem.Loot
	end
end

------UNIT SPAWNS-----------
local function PickSpawnByChance()
	local function randomSpawn(SpawnTable)
		local totalProbability = 0

		for _, v in pairs(SpawnTable) do
			totalProbability += v.Chance
		end

		local randomNumber = math.random(1, totalProbability)
		local cumulativeProbability = 0


		for key, v in pairs(SpawnTable) do
			cumulativeProbability += v.Chance
			if randomNumber <= cumulativeProbability then
				return v
			end
		end
	end

	local chosenSpawn = randomSpawn(SpawnsModule)
	return chosenSpawn.Unit
end

local function AnimateDoor(Unit, Open)
	local TweenService = game:GetService("TweenService")
	local Door = Unit.Door.Base

	local tweenInfoOpen = TweenInfo.new(1, Enum.EasingStyle.Cubic, Enum.EasingDirection.Out)
	local tweenInfoClose = TweenInfo.new(1.5, Enum.EasingStyle.Bounce, Enum.EasingDirection.Out)

	local OpenGoal = {CFrame = Door.PrimaryPart.CFrame * CFrame.new(0, 8, 0)}
	local CloseGoal = {CFrame = Door.PrimaryPart.CFrame * CFrame.new(0, -8, 0)}
	local Goal = nil
	local tweenInfo = nil

	local OpenSound = Door.BasePart.Open
	local CloseSound = Door.BasePart.Close

	if Open == true then
		Goal = OpenGoal
		tweenInfo = tweenInfoOpen
		OpenSound:Play()
	elseif Open == false then
		Goal = CloseGoal
		tweenInfo = tweenInfoClose
		CloseSound:Play()
	end

	local Tween = TweenService:Create(Door.PrimaryPart, tweenInfo, Goal)
	Tween:Play()
end

local function UnitOpened(Plr, Unit, Prompt)
	if #Unit.SpawnedUnit:GetChildren() ~= 0 then
		warn("Storage already in use, spawn aborted.")
		return
	end

	local ChosenUnit = PickSpawnByChance():Clone()
	local Occupied = Unit:GetAttribute("Occupied")

	Prompt.Enabled = false
	AnimateDoor(Unit, true)

	ChosenUnit.Parent = Unit.SpawnedUnit
	ChosenUnit:PivotTo(Unit:GetPivot() - Vector3.new(0, 1.5, 0)) --1.5 distance needed to be on floor

	for i,v in ChosenUnit:GetChildren() do
		local LootToSpawn
		task.spawn(function()
			--spawner types--
			if v.Name == "UniversalSpawner" then
				LootToSpawn = PickLootByChance("Universal"):Clone()
				print("is universal")
			elseif v.Name == "CommonSpawner" then
				LootToSpawn = PickLootByChance("Common"):Clone()
			elseif v.Name == "UncommonSpawner" then
				LootToSpawn = PickLootByChance("Uncommon"):Clone()
			elseif v.Name == "RareSpawner" then
				LootToSpawn = PickLootByChance("Rare"):Clone()
			elseif v.Name == "FoodSpawner" then
				LootToSpawn = PickLootByChance("Food"):Clone()
			elseif v.Name == "WeaponSpawner" then
				LootToSpawn = PickLootByChance("Weapon"):Clone()
			elseif v.Name == "AmmoSpawner" then
				LootToSpawn = PickLootByChance("Ammo"):Clone()
			end
			------------------
			print(`Loot: {LootToSpawn}`)

			v.Transparency = 1
			if LootToSpawn.PrimaryPart == nil then
				error(`MISSING PRIMARY PART FOR LOOT DROP: {LootToSpawn}. also ensure instance is collidabe and unanchored.`)
			end
			LootToSpawn:SetPrimaryPartCFrame(v.CFrame)
			LootToSpawn.Parent = ChosenUnit
		end)
	end

	local function IsOccupied()
		local OccupiedParts = game.Workspace:GetPartsInPart(Unit.IsPresentHitbox)

		local Updater = task.spawn(function()
			while task.wait(1) do
				OccupiedParts = game.Workspace:GetPartsInPart(Unit.IsPresentHitbox)
			end
		end)

		for _, v in ipairs(OccupiedParts) do
			if game.Players:GetPlayerFromCharacter(v.Parent) then
				task.cancel(Updater)
				return true
			end
		end

		task.cancel(Updater)
		return false
	end

	local restart = true
	while restart do
		restart = false
		for i = 1, ATTC + 1 do
			task.wait(1)
			if IsOccupied() == true then 
				restart = true
				break
			end
			if IsOccupied() == false then
				if i == ATTC + 1 then
					AnimateDoor(Unit, false)
					task.wait(1) --time it takes for door to close
					ChosenUnit:Destroy()
					task.wait(Cooldown)
					Prompt.Enabled = true
				end
			end
		end
	end
end

Event.Event:Connect(function(Plr, Unit, Prompt)
	UnitOpened(Plr, Unit, Prompt)
end)

just as a reminder, before the edits made to this script of which is causing issues. the script was at a fully functional state. reminding you that everything else about this script works fine.

It’s not - it’s simply erroring before it gets to the latest portions of the table.

The reason it is erroring is because you are trying to access the chance property of
image
, when you meant to access the chance properties of the items.

Consider replacing

for _, v in pairs(LootTable) do
	warn(v) --shown in image 2
	totalProbability += v.Chance --error line
end

with

for _, v in pairs(LootTable) do
	for _, x in v do	
		totalProbability += x.Chance
	end
end
1 Like

I also recommend naming things in a way that is readable. Most people are told to use: [for i, v] or [for _, v] or [for i, _]

Try to put exactly what you want, to make it easier to read. [for index, items] [for item, config] [for item, dropchance] etc…

In large codes when you need to change something, you will need to read the codes again and I guarantee that without correct naming you will spend MUCH more time than you should.

2 Likes

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