Making a drop party script

It’s better than repeatedly using wait(). Also, event connections are relatively inexpensive so there’s nothing wrong with using .Stepped as a loop.

Nope, it uses the cooldown on the first iteration as well but that can easily be changed.

Ok would this code work then?

local RunService = game:GetService("RunService")

local cooldown = 20
local lastSpawnedTime

repeat
	if os.time() == os.time({year = 2020; month = 5; day = 16}) then
		spawnThem()
		lastSpawnedTime = tick()
		RunService.Stepped:Connect(function() -- these parameters aren't needed but i'm just showing that they exist
	    	if tick() - lastSpawnedTime >= cooldown then
	        	spawnThem()
	       		lastSpawnedTime = tick()
	    	end
		end)
		
	end
until os.time() ~= os.time({year = 2020; month = 5; day = 16})

Also what if this happens:
Player joins at like 5:16 or something not on the dot?

you don’t need repeat/until. just the if statement is enough.
also you have to fill in the spawnThem() function

1 Like

Ik. Just was putting pseudocode for the function.

I still need the answer to this question.

Also won’t the if statement only run once?

Ok so here is my code so far:

MAIN SCRIPT:

local RunService = game:GetService("RunService")

local module = require(game.ReplicatedStorage.Modules.CrystalDropParty)

local cooldown = 20
local lastSpawnedTime

local date = os.date("!*t", os.time())
local yday = 137 -- the actual yday, 131 is for testing

if date.yday == 131 and date.year == 2020 then
	module.StartDropParty()
	lastSpawnedTime = tick()
	RunService.Stepped:Connect(function()
	    if tick() - lastSpawnedTime >= cooldown then
	        module.StartDropParty()
	       	lastSpawnedTime = tick()
	    end
	end)
		
end

MODULE SCRIPT:

local module = {}

local RNG = Random.new()
local bases = {
    {Object = workspace.Base, Weight = 3};
    {Object = workspace.Base2, Weight = 4};
}

--local functions
local function random(choices)
	local weightSum = 0
	for i = 1, #choices do
		weightSum = weightSum + choices[i].Weight
	end

	local rand = RNG:NextInteger(0, weightSum)
	for i = 1, #choices do
		if rand <= choices[i].Weight then
			return choices[i].Object
		end
		rand = rand - choices[i].Weight
	end
end

local function setRandomPosition(item)
	local Base = random(bases)

	item.CFrame = CFrame.new(
		RNG:NextInteger((-Base.Size.X / 2), (Base.Size.X / 2)),
		Base.Position.Y + (Base.Size.Y / 2) + (item.Size.Y / 2),
		RNG:NextInteger((-Base.Size.Z / 2), (Base.Size.Z / 2))
	) * CFrame.Angles(0, math.rad(RNG:NextInteger(0, 360)), 0)
end

--public functions
function module.StartDropParty()
	local secs = 60
	repeat
		local waitSeconds = math.random(9,16)
		local randomAmount = math.random(4,7)
		wait(waitSeconds)
		for i = 1, randomAmount do
			local clonedCrystal = script.Crystal:Clone()
			clonedCrystal.Parent = workspace.Crystals
			setRandomPosition(clonedCrystal)
		end
		secs = secs - waitSeconds
	until secs <= 0
end

return module

CRYSTAL TOUCHED SCRIPT:

local function crystalTouched(crystal, hit)
		if hit.Parent:FindFirstChild("Humanoid") then
			local plr = game.Players:GetPlayerFromCharacter(hit.Parent)
			local crystals = plr:WaitForChild('leaderstats').Crystals
			
			crystals.Value = crystals.Value + (1 * plr:WaitForChild("Gamepasses").CrystalsMultiplier.Value)
			
			crystal:Destroy()
		end
end

local function debounce(func)
	local deb = false
	
	return function()
		if not deb then
			deb = true
			print("BEFORE FUNC")
			
			func()
			
			deb = false
			print("AFTER FUNC")
		end
	end
end

script.Parent.Touched:Connect(function(hit)
	debounce(crystalTouched(script.Parent, hit))
end)

I haven’t tested yet since it’s really late but I will soon!

Uhh… So I tested it out and the first drop party went well, and then like a few seconds later there were just a whole bunch of crystals dropping…

local RunService = game:GetService("RunService")

local module = require(game.ReplicatedStorage.Modules.CrystalDropParty)

local cooldown = 20
local lastSpawnedTime

local date = os.date("!*t", os.time())
local yday = 137

if date.yday == 131 and date.year == 2020 then
	module.StartDropParty()
	lastSpawnedTime = tick()
	RunService.Stepped:Connect(function()
	    if tick() - lastSpawnedTime >= cooldown then
	        module.StartDropParty()
	       	lastSpawnedTime = tick()
	    end
	end)
		
end

I’m suspecting it has to do with this:

RunService.Stepped:Connect(function()
	    if tick() - lastSpawnedTime >= cooldown then
	        module.StartDropParty()
	       	lastSpawnedTime = tick()
	    end
	end)

That makes it drop again every 20 seconds

I combined what I learned here and in this topic and came up with this script:

local date = os.date("!*t", os.time())

local crystalModule = require(game.ReplicatedStorage.Modules.CrystalDropParty)
local cocoaModule = require(game.ReplicatedStorage.Modules.CocoaDropParty)

local function crystalDropParty()
	local CurrentSec = date.min * 60 + date.sec
	
	local HalfHourSec = 60 * 20
	
	local TimeToWait = HalfHourSec - CurrentSec
	print(TimeToWait)
	
	if TimeToWait < 0 then
		TimeToWait = 2 * HalfHourSec - CurrentSec 
		print(TimeToWait)
	end

	wait(TimeToWait)
	
	repeat
		crystalModule.StartDropParty()
		wait(HalfHourSec)
	until os.time() ~= os.time({year = 2020; month = 5; day = 10})
end

local function cocoaDropParty()
	local CurrentSec = date.min * 60 + date.sec
	
	local HalfHourSec = 60 * 15
	
	local TimeToWait = HalfHourSec - CurrentSec
	print(TimeToWait)
	
	if TimeToWait < 0 then
		TimeToWait = 2 * HalfHourSec - CurrentSec 
		print(TimeToWait)
	end

	wait(TimeToWait)
	
	repeat
		cocoaModule.StartDropParty()
		wait(HalfHourSec)
	until os.time() ~= os.time({year = 2020; month = 5; day = 10})
end

if date.year == 2020 and date.month == 5 and date.day == 10 then
	coroutine.wrap(crystalDropParty)()
	coroutine.wrap(cocoaDropParty)()
else
	local timeUntilDate = os.time({year = 2020; month = 5; day = 10}) - os.time()
	print(timeUntilDate)
	
	wait(timeUntilDate)
	
	coroutine.wrap(crystalDropParty)()
	coroutine.wrap(cocoaDropParty)()
end

The module and touch handler have not been edited.

Oh but sometimes when the TimeToWait is lower than 0 the new TimeToWait is still lower than 0.

@Quackers337 if you’re there please help!

That’s because you’re multiplying a negative number by 2 so it just gets twice as lower than before. Instead of multiplying by 2, try multiplying by -1.

1 Like

Actually,

So it’s 40 minutes/30 minutes (crystals/cocoa) - the current sec

Idk maybe I’d do *-0.5?

What is halfhoursec for? (30 chars)

HalfHourSec is how long the cooldown is (SecsInAMinute * Minutes) so 60 * 15 would be 15 minutes.

Wait so if TimeToWait is negative, that means the crystal party is already late? In that case, you should just run the function, not add more time.

BUT… that means it could be at 11:13 or something and it would throw the time off since the next time (for crystals) would be at 11:33, then at 11:53, and so on.

Remember: I want to have it ON THE DOT.

try this:

TimeToWait = HalfHourSec + TimeToWait

it adds another 20 minutes and removes the existing negative time from it.

I think you have misunderstood. HalfHourSec is the number of seconds in half an hour, namely 1800. It should be 60 * 30, not 60 * 20, this is why you are getting TimeToWait as lower than 0 even after you add it again.

I want it to be crystals every 20 minutes, and cocoa every 15 minutes, so that’s why I made it 20 and 15. I just didn’t change the variable name.

In that case, you would need to restructure the code a little bit. The example I gave was specifically targeted to reset every half an hour, because the if TimeToWait < 0 statement only checks once. It only needed to check once because 1 hour divided into half hours gives 2 (there are 2 half hours in an hour), so it needed to check once (n - 1, where n is how many times an hour can be divided into the sections of the length you want). If we were going by 20 minutes, we would need to check twice, because 1 hour can be divided into 3 20 minute sections.
The restructured code would look a bit like this:

    local CurrentSec = date.min * 60 + date.sec
	local AlignMinutes = 20 -- align with 20 minute intervals
	local AlignMinutesSec = 60 * AlignMinutes -- the number of seconds in each 20 minute section
	
        -- Align the time to the AlignMinutes intervals
	local TimeToWait = AlignMinutesSec - CurrentSec
	print(TimeToWait)
	
        for i = 1, math.floor(60 / AlignMinutesSec) - 1 do
	        if TimeToWait < 0 then
		        TimeToWait = (i + 1) * HalfHourSec - CurrentSec 
	        	print(TimeToWait)
                else break
	        end
        end

Screen Shot 2020-05-10 at 5.00.45 PM
The TimeToWait is obviously under 0, but somehow this code doesn’t run (I think):

for i = 1, math.floor(60 / AlignMinSecs) - 1 do
		if TimeToWait < 0 then
			TimeToWait = (i + 1) * AlignMinSecs - CurrentSec
			print(TimeToWait)
			else warn("TimeToWait is not under 0") break
		end
	end

I didn’t get the warn message when TimeToWait was over 0 either.