Spaghetti Code... I need some help

Hello I’ve been scripting away at this local script for some time and i think i’ve wrote a bunch of nonsense and everything looks like spaghetti code… if anyone has some any idea on how i can be improving this mess I will take it! heres the spaghetti…

local formatNumber = (function (n)
	n = tostring(n)
	return n:reverse():gsub("%d%d%d", "%1,"):reverse():gsub("^,", "")
end)

local plr = game.Players.LocalPlayer

local currentNumber = plr.MultiplierFolder.Multiplier1.Value
local baseCost = 50000
local costMultiplier = 1.25

local function calculateUpgradeCost(currentNumber)
	return baseCost * (costMultiplier ^ currentNumber)
end

local Cost = calculateUpgradeCost(currentNumber)
local wholeNub = math.floor(Cost)

script.Parent.MainFrame.NextPrice.Text = '$'.. formatNumber(wholeNub)
script.Parent.MainFrame.CurrentMulti.Text = 'X '.. plr.MultiplierFolder.Multiplier1.Value
if plr.MultiplierFolder.Multiplier1.Value == 2 then
	script.Parent.MainFrame.NextMulti.Text = 'MAX'
elseif plr.MultiplierFolder.Multiplier1.Value <= 1.95 then
	script.Parent.MainFrame.NextMulti.Text = 'X ' .. plr.MultiplierFolder.Multiplier1.Value + 0.05
end

plr.MultiplierFolder.Multiplier1.Changed:Connect(function(nextval)
	local Costnew = calculateUpgradeCost(nextval)
	local wholeNubnew = math.floor(Costnew)
	script.Parent.MainFrame.NextPrice.Text = '$'.. formatNumber(wholeNubnew)
	script.Parent.MainFrame.CurrentMulti.Text = 'X '.. plr.MultiplierFolder.Multiplier1.Value
	if plr.MultiplierFolder.Multiplier1.Value == 2 then
		script.Parent.MainFrame.NextMulti.Text = 'MAX'
	elseif plr.MultiplierFolder.Multiplier1.Value <= 1.95 then
	script.Parent.MainFrame.NextMulti.Text = 'X ' .. plr.MultiplierFolder.Multiplier1.Value + 0.05
	end
end)

local Event = game.ReplicatedStorage.Remotes:WaitForChild('UpgraderClient')
local EventSend = game.ReplicatedStorage.Remotes:WaitForChild('UpgradeFinal')

script.Parent.MainFrame.CloseButton.Activated:Connect(function()
	script.Parent.Enabled = false
end)

script.Parent.MainFrame.UpgradeButton.Activated:Connect(function()
	if plr.MultiplierFolder.Multiplier1.Value == 2 then return end
	local valToTake = --stuck here
end)

Event.OnClientEvent:Connect(function()
	script.Parent.Enabled = true
end)

Here’s the in-game interface:


and here’s the in-studio GUI stuff:
image

2 Likes

Are you also looking for feeback regarding how to implement something at this line of code toward the end or just wanting to improve organization in general:

1 Like

both would be really helpful, i’m trying to fire a event on a server so i can continue this process

2 Likes

I cleaned up the version of the LocalScript in the original post in the following ways:


  • Declared most of the variables at the top of the script.

    • This helps confirm that those objects exist before referencing them.

    • Also makes the functions more legible / less wordy since there’s a direct reference to each object already.

  • Moved the section of code that initially sets the Text of each TextLabel into its own function that is clearly defined as the function that sets the initial values.

  • Reorganized where the functions are (in particular, the formatNumber and calculateUpgradeCost ones) so that it is clearer that those functions are commonly used by the ones below it.


I haven’t added any more functionality to the valToTake at the end since I’d need more clarification about what you want that to do (I know you mentioned you want to fire an event to the server, but I don’t know if it’s one of the RemoteEvents that were already referenced, such as the “UpgradeFinal” one, or if it’s a completely different one).

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local player = Players.LocalPlayer
local MultiplierFolder = player:WaitForChild("MultiplierFolder")
local Multiplier1 = MultiplierFolder:WaitForChild("Multiplier1")

local ScreenGui = script.Parent
local MainFrame = ScreenGui:WaitForChild("MainFrame")
local NextPrice = MainFrame:WaitForChild("NextPrice")
local CurrentMulti = MainFrame:WaitForChild("CurrentMulti")
local NextMulti = MainFrame:WaitForChild("NextMulti")
local CloseButton = MainFrame:WaitForChild("CloseButton")
local UpgradeButton = MainFrame:WaitForChild("UpgradeButton")


local Remotes = ReplicatedStorage.Remotes
local Event = Remotes:WaitForChild('UpgraderClient')
local EventSend = Remotes:WaitForChild('UpgradeFinal')

---

local currentNumber = Multiplier1.Value
local baseCost = 50000
local costMultiplier = 1.25

---

local formatNumber = (function (n)
	n = tostring(n)
	return n:reverse():gsub("%d%d%d", "%1,"):reverse():gsub("^,", "")
end)

local function calculateUpgradeCost(currentNumber)
	return baseCost * (costMultiplier ^ currentNumber)
end

---

local Cost = calculateUpgradeCost(currentNumber)
local wholeNub = math.floor(Cost)

local function setInitialValues()
	NextPrice.Text = '$'.. formatNumber(wholeNub)
	CurrentMulti.Text = 'X '.. Multiplier1.Value
	if Multiplier1.Value == 2 then
		NextMulti.Text = 'MAX'
	elseif Multiplier1.Value <= 1.95 then
		NextMulti.Text = 'X ' .. Multiplier1.Value + 0.05
	end
end
setInitialValues()

---

Multiplier1.Changed:Connect(function(nextval)
	local Costnew = calculateUpgradeCost(nextval)
	local wholeNubnew = math.floor(Costnew)
	
	NextPrice.Text = '$'.. formatNumber(wholeNubnew)
	CurrentMulti.Text = 'X '.. Multiplier1.Value
	if Multiplier1.Value == 2 then
		NextMulti.Text = 'MAX'
	elseif Multiplier1.Value <= 1.95 then
		NextMulti.Text = 'X ' .. Multiplier1.Value + 0.05
	end
end)

UpgradeButton.Activated:Connect(function()
	if Multiplier1.Value == 2 then return end
	local valToTake = "placeholder" --stuck here
end)


MainFrame.CloseButton.Activated:Connect(function()
	ScreenGui.Enabled = false
end)

Event.OnClientEvent:Connect(function()
	ScreenGui.Enabled = true
end)
2 Likes

it was the ‘UpgradeFinal’ but yes, thats really good, thank you so much. My brain is fried and i couldn’t really bother reorganising seems it was such a spaghetti code. Thank you

2 Likes

one thing tho, i think im in the same position as i was before, i wanted to pass the final required amount (Costnew/Cost) of money onto the event, also the Multiplier1 to a server sided script so i can adjust the player’s data from there. There any tips on how i can adjust it seems theres two variables (Costnew/Cost) instead of one?

2 Likes

I just realized now that the original Cost and wholeNub were only referenced by the section of code that set the initial values. However, I think it could be reused to store the most updated upgrade cost value after Multiplier1 changes so that you wouldn’t have two separate sets of variables.

Before doing that, though, it can be consolidated into a single variable by calling math.floor() on it before calculateUpgradeCost returns the value:

-- Before
local function calculateUpgradeCost(currentNumber)
	return baseCost * (costMultiplier ^ currentNumber)
end

local Cost = calculateUpgradeCost(currentNumber)
local wholeNub = math.floor(Cost)

-- After

local function calculateUpgradeCost(currentNumber)
	return math.floor( baseCost * (costMultiplier ^ currentNumber) )
end

local Cost = calculateUpgradeCost(currentNumber)

Then, instead of creating the Costnew variable for it whenever Multiplier1.Changed activates the function, update the original Cost variable to the value returned from calling the function:

-- Before

Multiplier1.Changed:Connect(function(nextval)
	local Costnew = calculateUpgradeCost(nextval)
	local wholeNubnew = math.floor(Costnew)
-- After
Multiplier1.Changed:Connect(function(nextval)
	Cost = calculateUpgradeCost(nextval)
-- And then the rest of the function will need to be updated to reference "Cost", instead

Lastly, the function that is supposed to fire the RemoteEvent can reference the Cost variable since we know it’s being updated with the newest value:

UpgradeButton.Activated:Connect(function()
	if Multiplier1.Value == 2 then return end
	local valToTake = EventSend:FireServer(Cost)
end)

However, if this RemoteEvent is being used to verify if the player has enough of a certain leaderstat in order to update their data, you could start by checking if they have enough on the client, and if they do, fire the RemoteEvent to the server for it to re-verify that and then update the data there.


Something to keep in mind is that exploiters would be able to send in whatever value they wanted as the Cost, which means that on the server-side, you should be verifying that the calculated Cost value is correct so that they aren’t able to upgrade unless they actually have met the requirements to do so.

In the same vein, don’t send Multiplier1.Value through the RemoteEvent because exploiters may be able to modify that locally, too, and then send through a spoofed value that could result in their stats being increased way more than what was intended.

This means that when you receive the event on the server, you’d need to re-reference Multiplier1 and then update it accordingly:

-- Example

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local EventSend = Remotes:WaitForChild('UpgradeFinal')

EventSend.OnServerEvent:Connect(function(player)
    local MultiplierFolder = player:WaitForChild("MultiplierFolder")
    local Multiplier1 = MultiplierFolder:WaitForChild("Multiplier1")

    -- Sanity checks here to make sure the player has met the requirements for the changes they are requesting to make
end)

In order to calculate the cost on the server, you would probably need the same calculateUpgradeCost function, but that also means you would need to reference the baseCost and currentMultiplier values, too. Since those values were set directly within the LocalScript and the server should not rely on the client to send the intended values through, it may need to be revised a bit to ensure that the server knows the

One example of this could be to create Attributes that store the baseCost and currentMultiplier values on the Player object from the server when the game first starts. Both the LocalScript and the server would be able to reference that with certainty that it’s correct (since it’s being managed by the server).


And lastly, here’s the full version of the LocalScript again after making those revisions (and I’m pretty sure I made all the necessary revisions; but if not, it should be a quick fix):

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local player = Players.LocalPlayer
local MultiplierFolder = player:WaitForChild("MultiplierFolder")
local Multiplier1 = MultiplierFolder:WaitForChild("Multiplier1")

local ScreenGui = script.Parent
local MainFrame = ScreenGui:WaitForChild("MainFrame")
local NextPrice = MainFrame:WaitForChild("NextPrice")
local CurrentMulti = MainFrame:WaitForChild("CurrentMulti")
local NextMulti = MainFrame:WaitForChild("NextMulti")
local CloseButton = MainFrame:WaitForChild("CloseButton")
local UpgradeButton = MainFrame:WaitForChild("UpgradeButton")


local Remotes = ReplicatedStorage.Remotes
local Event = Remotes:WaitForChild('UpgraderClient')
local EventSend = Remotes:WaitForChild('UpgradeFinal')

---

local currentNumber = Multiplier1.Value
local baseCost = 50000
local costMultiplier = 1.25

---

local formatNumber = (function (n)
	n = tostring(n)
	return n:reverse():gsub("%d%d%d", "%1,"):reverse():gsub("^,", "")
end)

local function calculateUpgradeCost(currentNumber)
	return math.floor( baseCost * (costMultiplier ^ currentNumber) )
end

---

local Cost = calculateUpgradeCost(currentNumber)

local function setInitialValues()
	NextPrice.Text = '$'.. formatNumber(Cost)
	CurrentMulti.Text = 'X '.. Multiplier1.Value
	if Multiplier1.Value == 2 then
		NextMulti.Text = 'MAX'
	elseif Multiplier1.Value <= 1.95 then
		NextMulti.Text = 'X ' .. Multiplier1.Value + 0.05
	end
end
setInitialValues()

---

Multiplier1.Changed:Connect(function(nextval)
	Cost = calculateUpgradeCost(nextval)
	
	NextPrice.Text = '$'.. formatNumber(Cost)
	CurrentMulti.Text = 'X '.. Multiplier1.Value
	if Multiplier1.Value == 2 then
		NextMulti.Text = 'MAX'
	elseif Multiplier1.Value <= 1.95 then
		NextMulti.Text = 'X ' .. Multiplier1.Value + 0.05
	end
end)

UpgradeButton.Activated:Connect(function()
	if Multiplier1.Value == 2 then return end
	local valToTake = EventSend:FireServer(Cost)
end)


MainFrame.CloseButton.Activated:Connect(function()
	ScreenGui.Enabled = false
end)

Event.OnClientEvent:Connect(function()
	ScreenGui.Enabled = true
end)
3 Likes

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