The full script is 163 lines long and requires a ton of context within the workspace to understand, but okay.
the script
local cradle = game.Workspace.Cradle.Balls
local ogPos = game.Workspace.Cradle.BallsPos
local sSound = game:GetService("SoundService").Song
local gp
local tempo
local pos
local gPos
local direction
local aDirection
local tim = 0
local tweenInfo
local evenOdd
local ogPos2 = {}
local inputAllowed = false
local contin = 0
local rContin = 0
local keyCodeTable = {Enum.KeyCode.One, Enum.KeyCode.Two, Enum.KeyCode.Three, Enum.KeyCode.Four, Enum.KeyCode.Five}
--Find the original CFrame of a ball in a table
local function findOg(part, model) return ogPos2[table.find(ogPos2, part.Name .. model.Name)+1] end
--Find how many buttons need to be pressed
local function findAm(pattern)
rContin = 0
for _, val in pairs(pattern:GetChildren()) do if val.Value then rContin += 1 end end return rContin
end
--Play the game
local function play(song)
--Set up
sSound.SoundId = "rbxassetid://" .. song.Value
gp = song.Gameplay
tempo = 60 / song.Tempo.Value
pos = 1
repeat game:GetService("RunService").Stepped:Wait() until sSound.IsLoaded
--Play
sSound:Play()
repeat
--Move to starting place
for _, model in pairs(cradle:GetChildren()) do model:SetPrimaryPartCFrame(ogPos:FindFirstChild(model.Name .. "sP").CFrame) end
--Write values
tim = 0
gPos = gp:FindFirstChild(pos)
pos += 1
--Move to proper place
for _, model in pairs(cradle:GetChildren()) do
if gPos.Used:FindFirstChild(3).Value then
model:SetPrimaryPartCFrame(model.PosA.CFrame)
evenOdd = "Odd"
else
model:SetPrimaryPartCFrame(model.PosB.CFrame)
evenOdd = "Even"
end
end
--Allow things to be seen
for uPos = 1, 5 do
if gPos.Used:FindFirstChild(uPos).Value then
for _, part in pairs(cradle:FindFirstChild(uPos):GetChildren()) do
if string.split(part.Name, "_")[1] == "Part" then
game:GetService("TweenService"):Create(part, TweenInfo.new(tempo/2, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut, 0, false, 0), {Transparency = 0}):Play()
end
end
end
end
contin = findAm(gPos.Pattern)
--Start moving
direction = gPos.Direction.Value
repeat
--Reset table
ogPos2 = {}
--Direction
for _, part in pairs(gPos.Pattern:GetChildren()) do
if part.Value and direction then
aDirection = part.Direction.Value
elseif part.Value then
if part.Direction.Value == "R" then aDirection = "L" else aDirection = "R" end
end
end
--Tween Info
tweenInfo = TweenInfo.new(gPos.Switch.Value*tempo/2, Enum.EasingStyle.Quart, Enum.EasingDirection.Out, 0, false, 0)
--Move up
for _, model in pairs(cradle:GetChildren()) do
if gPos.Pattern:FindFirstChild(model.Name).Value then
for _, part in pairs(model:GetChildren()) do
if string.split(part.Name, "_")[1] == "Part" then
--Save CFrame
table.insert(ogPos2, part.Name .. model.Name)
table.insert(ogPos2, part.CFrame)
--Tween
game:GetService("TweenService"):Create(part, tweenInfo,
{CFrame = ogPos:FindFirstChild(evenOdd):FindFirstChild(aDirection):FindFirstChild(model.Name .. "eP"):FindFirstChild(part.Name).CFrame}):Play()
end
end
end
end
wait(song.Window.Value*tempo/2)
if contin ~= findAm(gPos.Pattern) then
print ("fail " .. contin)
else
print "yay"
end
contin = 0
inputAllowed = false
wait(tempo*gPos.Switch.Value/2 - song.Window.Value*tempo/2)
--Tween Info
tweenInfo = TweenInfo.new(gPos.Switch.Value*tempo/2, Enum.EasingStyle.Quart, Enum.EasingDirection.In, 0, false, 0)
--Move down
for _, model in pairs(cradle:GetChildren()) do
if gPos.Pattern:FindFirstChild(model.Name).Value then
for _, part in pairs(model:GetChildren()) do
if string.split(part.Name, "_")[1] == "Part" then
--Tween
game:GetService("TweenService"):Create(part, tweenInfo, {CFrame = findOg(part, model)}):Play()
end
end
end
end
wait(tempo*gPos.Switch.Value/2 - song.Window.Value*tempo/2)
--Change values
inputAllowed = true
tim += gPos.Switch.Value
direction = not direction
--Change which balls are swinging
for _, val in pairs(gPos.Pattern:GetChildren()) do
if val.Value and not val.Keep.Value then
val.Value = false
val = gPos.Pattern:FindFirstChild(6 - val.Name)
val.Keep.Value = true
val.Value = true
--Input
local inputFunc
inputFunc = game:GetService("UserInputService").InputBegan:Connect(function(input)
if input.KeyCode == keyCodeTable[val.Name] and inputAllowed then contin += 1 end
inputFunc:Disconnect()
end)
end
end
--Make sure every instance of keep is false
for _, val in pairs(gPos.Pattern:GetChildren()) do val.Keep.Value = false end
--Wait
wait(song.Window.Value*tempo/2)
until tim == gPos.Length.Value
until pos > #gp:GetChildren()
end
--Find the correct song
local function findSong(num)
if num.Name - 10 < 0 then num = "0" .. num.Name end
for _, song in pairs(game:GetService("ReplicatedStorage").Songs:GetChildren()) do if string.split(song.Name, " ")[1] == num then return song end end
end
--Level activation
for _, level in pairs(script.Parent:GetChildren()) do if level:IsA("TextButton") then level.MouseButton1Click:Connect(function()
play(findSong(level))
script.Parent.Visible = false
for _, lev in pairs(script.Parent:GetChildren()) do
if lev:IsA("TextButton") then
lev.Active = false
end
end
end)
end
end