I encountered a bug in my tycoon game. The problem is that the tycoon starts working and accumulating currency before the player becomes its owner. Because of this, when a new player selects the tycoon, they immediately get the money that has already been farmed — sometimes 3-4 thousand or more. This breaks the game logic, as the player should start from scratch.
I would like to implement a smoother and fairer behavior, where:
The currency starts accumulating only after the owner is assigned.
The accumulation happens slowly, by 0.1 per step, with a small delay.
The entire tycoon structure remains stable (button appearance, interaction, and collection).
I already tried making adjustments to the PartCollector script, but they broke other systems, including the appearance of buttons and purchases. Could you please help me figure out how to properly implement delayed currency accumulation with an owner check, so the tycoon works only after the player enters?
Here is a video: https://www.youtube.com/watch?v=XPNnqC6WkKw
here is my script (PurchaseHandler)
--THIS SCRIPT HAS AN ISSUE NEED FIXING
local mpService = game:GetService("MarketplaceService")
local Str = string.sub
local ID2 = game:GetService("ReplicatedStorage"):WaitForChild("GamepassIDs"):WaitForChild("X2Cash").Value
local ID1 = game:GetService("ReplicatedStorage"):WaitForChild("GamepassIDs"):WaitForChild("AutoCollect").Value
--[[
All configurations are located in the "Settings" Module script.
Please don't edit this script unless you know what you're doing.
--]]
-- Добавляем настройки накопления
local accumulationDelay = 0.15 -- Задержка между накоплениями
local accumulationStep = 0.1 -- Шаг накопления
local accumulationRunning = false
local folder = game.ReplicatedStorage:WaitForChild("Events")
local event = folder:WaitForChild("Build")
local Objects = {}
local TeamColor = script.Parent.TeamColor.Value
local Settings = require(script.Parent.Parent.Parent.Settings)
local ProductIds = require(script.Parent.Parent.Parent.DevProductIDS)
local Money = script.Parent.CurrencyToCollect
local Debris = game:GetService('Debris')
local Stealing = Settings.StealSettings
local CanSteal = true -- don't change or else you won't be able to steal currency
script.Parent.Essentials.Spawn.TeamColor = TeamColor
script.Parent.Essentials.Spawn.BrickColor = TeamColor
-- Функция для управления накоплением валюты
local function updateAccumulation()
if script.Parent.Owner.Value ~= nil then
if not accumulationRunning then
accumulationRunning = true
coroutine.wrap(function()
while script.Parent.Owner.Value ~= nil and script.Parent:FindFirstChild("CurrencyToCollect") do
script.Parent.CurrencyToCollect.Value += accumulationStep
wait(accumulationDelay)
end
accumulationRunning = false
end)()
end
else
accumulationRunning = false
end
end
-- Сбрасываем валюту при смене владельца
script.Parent.Owner.Changed:Connect(function()
if script.Parent:FindFirstChild("CurrencyToCollect") then
script.Parent.CurrencyToCollect.Value = 0 -- сбрасываем при заходе
end
updateAccumulation()
end)
function Sound(part,id)
if part:FindFirstChild('Sound') then
return
else
local Sound = Instance.new('Sound',part)
Sound.SoundId = "rbxassetid://"..tostring(id)
Sound:Play()
delay(Sound.TimeLength, function()
Sound:Destroy()
end)
end
end
--Parts that fall into the collector(s) get processed
for i,v in pairs(script.Parent.Essentials:GetChildren()) do
if v.Name == "PartCollector" then
v.Touched:connect(function(Part)
if Part:FindFirstChild('Cash') then
Money.Value = Money.Value + Part.Cash.Value
Debris:AddItem(Part,0.1)
end
end)
end
end
--Player Touched Collector processor
deb = false
script.Parent.Essentials.Giver.Touched:connect(function(hit)
local player = game.Players:GetPlayerFromCharacter(hit.Parent)
if player ~= nil then
if script.Parent.Owner.Value == player then
if hit.Parent:FindFirstChild("Humanoid") then
if hit.Parent.Humanoid.Health > 0 then
if deb == false then
deb = true
local Stats = game.ServerStorage.PlayerMoney:FindFirstChild(player.Name)
if Stats ~= nil then
spawn(function()
if mpService:UserOwnsGamePassAsync(player.UserId, ID2) and not mpService:UserOwnsGamePassAsync(player.UserId, ID2) then
script.Parent.Essentials.Giver.BrickColor = BrickColor.new("Persimmon")
Sound(script.Parent.Essentials, Settings.Sounds.Collect)
game.ReplicatedStorage.PopUp:FireClient(player, "+"..Money.Value.." X2")
local doubleyes = Money.Value *2
Stats.Value = Stats.Value + doubleyes
Money.Value = 0
wait(1)
script.Parent.Essentials.Giver.BrickColor = BrickColor.new("Bright green")
deb = false
else
script.Parent.Essentials.Giver.BrickColor = BrickColor.new("Persimmon")
Sound(script.Parent.Essentials, Settings.Sounds.Collect)
game.ReplicatedStorage.PopUp:FireClient(player, "+"..Money.Value)
Stats.Value = Stats.Value + Money.Value
Money.Value = 0
wait(1)
script.Parent.Essentials.Giver.BrickColor = BrickColor.new("Bright green")
deb = false
end
end)
end
end
end
end
elseif Stealing.Stealing then -- if player isn't owner and stealing is on
if CanSteal == true then
CanSteal = false
delay(Stealing.PlayerProtection, function()
CanSteal = true
end)
if hit.Parent:FindFirstChild("Humanoid") then
if hit.Parent.Humanoid.Health > 0 then
local Stats = game.ServerStorage.PlayerMoney:FindFirstChild(player.Name)
if Stats ~= nil then
local Difference = math.floor(Money.Value * Stealing.StealPrecent)
Sound(script.Parent.Essentials, Settings.Sounds.Collect)
Stats.Value = Stats.Value + Difference
Money.Value = Money.Value - Difference
end
end
end
else
Sound(script.Parent.Essentials, Settings.Sounds.Error)
end
end
end
end)
script.Parent:WaitForChild("Buttons")
for i,v in pairs(script.Parent.Buttons:GetChildren()) do
spawn(function()
if v:FindFirstChild("Head") then
local ThingMade = script.Parent.Purchases:WaitForChild(v.Object.Value)
if ThingMade ~= nil then
Objects[ThingMade.Name] = ThingMade:Clone()
ThingMade:Destroy()
else
--//Button doesn't have object, remove it
error('Object missing for button: '..v.Name..', button has been removed')
v.Head.CanCollide = false
v.Head.Transparency = 1
v.Extra.Transparency = 1
v.Extra.BillboardGui.Enabled = false
end
if v:FindFirstChild("Dependency") then --// if button needs something unlocked before it pops up
v.Head.CanCollide = false
v.Head.Transparency = 1
v.Extra.Transparency = 1
v.Extra.BillboardGui.Enabled = false
coroutine.resume(coroutine.create(function()
if script.Parent.PurchasedObjects:WaitForChild(v.Dependency.Value) then
if Settings['ButtonsFadeIn'] then
for i=1,20 do
wait(Settings['FadeInTime']/20)
v.Head.Transparency = v.Head.Transparency - 0.05
v.Extra.Transparency = v.Extra.Transparency - 0.05
end
end
v.Head.CanCollide = true
v.Head.Transparency = 0
v.Extra.Transparency = 0
v.Extra.BillboardGui.Enabled = true
end
end))
end
v.Head.Touched:connect(function(hit)
local player = game.Players:GetPlayerFromCharacter(hit.Parent)
if v.Head.CanCollide == true then
if player ~= nil then
if script.Parent.Owner.Value == player then
if hit.Parent:FindFirstChild("Humanoid") then
if hit.Parent.Humanoid.Health > 0 then
local PlayerStats = game.ServerStorage.PlayerMoney:FindFirstChild(player.Name)
if PlayerStats ~= nil then
if (v:FindFirstChild('Gamepass')) and (v.Gamepass.Value >= 1) then
if game:GetService("MarketplaceService"):PlayerOwnsAsset(player,v.Gamepass.Value) then
Purchase({[1] = v.Price.Value,[2] = v,[3] = PlayerStats})
else
game:GetService('MarketplaceService'):PromptPurchase(player,v.Gamepass.Value)
end
elseif (v:FindFirstChild('DevProduct')) then
game:GetService('MarketplaceService'):PromptProductPurchase(player,ProductIds[script.Parent.nameValue.Value][v.Object.Value])
elseif PlayerStats.Value >= tonumber(v.Extra.BillboardGui.Price.Text:sub(2)) then
Purchase({[1] = tonumber(v.Extra.BillboardGui.Price.Text:sub(2)),[2] = v,[3] = PlayerStats})
Sound(v, Settings.Sounds.Purchase)
else
Sound(v, Settings.Sounds.ErrorBuy)
end
end
end
end
end
end
end
end)
end
end)
end
function Purchase(tbl)
print(tbl[2])
local cost = tbl[1]
local item = tbl[2]
local stats = tbl[3]
stats.Value = stats.Value - cost
Objects[item.Object.Value].Parent = script.Parent.PurchasedObjects
event:FireAllClients(script.Parent.PurchasedObjects[item.Object.Value],1)
if Settings['ButtonsFadeOut'] then
item.Head.CanCollide = false
coroutine.resume(coroutine.create(function()
for i=1,20 do
wait(Settings['FadeOutTime']/20)
item.Head.Transparency = item.Head.Transparency + 0.05
item.Extra.Transparency = item.Extra.Transparency + 0.05
end
item.Extra.BillboardGui.Enabled = false
end))
else
item.Head.CanCollide = false
item.Head.Transparency = 1
item.Extra.Transparency = 1
item.Extra.BillboardGui.Enabled = false
end
end
function Create(tab)
local x = Instance.new('Model')
Instance.new('NumberValue',x).Value = tab[1]
x.Value.Name = "Cost"
Instance.new('ObjectValue',x).Value = tab[2]
x.Value.Name = "Button"
local Obj = Instance.new('ObjectValue',x)
Obj.Name = "Stats"
Obj.Value = tab[3]
x.Parent = script.Parent.BuyObject
end
--// This was very rushed and is inefficent; if you plan on making something like this don't use a child added listener.
script.Parent:WaitForChild('BuyObject').ChildAdded:connect(function(child)
local tab = {}
tab[1] = child.Cost.Value
tab[2] = child.Button.Value
tab[3] = child.Stats.Value
Purchase(tab)
wait(10)
child:Destroy()
end)
-- Инициализация накопления при запуске
updateAccumulation()