Advertisement
Zulkin

Funky Friday Autoplay [Modded]

Jan 15th, 2023 (edited)
1,901
3
Never
2
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 30.97 KB | None | 3 0
  1. -- updated by Rex. E#0001 because it has some bugs and issues I'd like to be changed
  2. local start = tick()
  3. local client = game:GetService('Players').LocalPlayer;
  4. local set_identity = (type(syn) == 'table' and syn.set_thread_identity) or setidentity or setthreadcontext
  5. local executor = identifyexecutor and identifyexecutor() or 'Unknown'
  6.  
  7. local function fail(r) return client:Kick(r) end
  8.  
  9. -- gracefully handle errors when loading external scripts
  10. -- added a cache to make hot reloading a bit faster
  11. local usedCache = shared.__urlcache and next(shared.__urlcache) ~= nil
  12.  
  13. shared.__urlcache = shared.__urlcache or {}
  14. local function urlLoad(url)
  15.     local success, result
  16.  
  17.     if shared.__urlcache[url] then
  18.         success, result = true, shared.__urlcache[url]
  19.     else
  20.         success, result = pcall(game.HttpGet, game, url)
  21.     end
  22.  
  23.     if (not success) then
  24.         return fail(string.format('Failed to GET url %q for reason: %q', url, tostring(result)))
  25.     end
  26.  
  27.     local fn, err = loadstring(result)
  28.     if (type(fn) ~= 'function') then
  29.         return fail(string.format('Failed to loadstring url %q for reason: %q', url, tostring(err)))
  30.     end
  31.  
  32.     local results = { pcall(fn) }
  33.     if (not results[1]) then
  34.         return fail(string.format('Failed to initialize url %q for reason: %q', url, tostring(results[2])))
  35.     end
  36.  
  37.     shared.__urlcache[url] = result
  38.     return unpack(results, 2)
  39. end
  40.  
  41. -- attempt to block imcompatible exploits
  42. -- rewrote because old checks literally did not work
  43. if type(set_identity) ~= 'function' then return fail('Unsupported exploit (missing "set_thread_identity")') end
  44. if type(getconnections) ~= 'function' then return fail('Unsupported exploit (missing "getconnections")') end
  45. if type(getloadedmodules) ~= 'function' then return fail('Unsupported exploit (misssing "getloadedmodules")') end
  46. if type(getgc) ~= 'function' then   return fail('Unsupported exploit (misssing "getgc")') end
  47.  
  48. local getinfo = debug.getinfo or getinfo;
  49. local getupvalue = debug.getupvalue or getupvalue;
  50. local getupvalues = debug.getupvalues or getupvalues;
  51. local setupvalue = debug.setupvalue or setupvalue;
  52.  
  53. if type(setupvalue) ~= 'function' then return fail('Unsupported exploit (misssing "debug.setupvalue")') end
  54. if type(getupvalue) ~= 'function' then return fail('Unsupported exploit (misssing "debug.getupvalue")') end
  55. if type(getupvalues) ~= 'function' then return fail('Unsupported exploit (missing "debug.getupvalues")') end
  56.  
  57. -- free exploit bandaid fix
  58. if type(getinfo) ~= 'function' then
  59.     local debug_info = debug.info;
  60.     if type(debug_info) ~= 'function' then
  61.         -- if your exploit doesnt have getrenv you have no hope
  62.         if type(getrenv) ~= 'function' then return fail('Unsupported exploit (missing "getrenv")') end
  63.         debug_info = getrenv().debug.info
  64.     end
  65.     getinfo = function(f)
  66.         assert(type(f) == 'function', string.format('Invalid argument #1 to debug.getinfo (expected %s got %s', 'function', type(f)))
  67.         local results = { debug.info(f, 'slnfa') }
  68.         local _, upvalues = pcall(getupvalues, f)
  69.         if type(upvalues) ~= 'table' then
  70.             upvalues = {}
  71.         end
  72.         local nups = 0
  73.         for k in next, upvalues do
  74.             nups = nups + 1
  75.         end
  76.         -- winning code
  77.         return {
  78.             source      = '@' .. results[1],
  79.             short_src   = results[1],
  80.             what        = results[1] == '[C]' and 'C' or 'Lua',
  81.             currentline = results[2],
  82.             name        = results[3],
  83.             func        = results[4],
  84.             numparams   = results[5],
  85.             is_vararg   = results[6], -- 'a' argument returns 2 values :)
  86.             nups        = nups,    
  87.         }
  88.     end
  89. end
  90.  
  91. local UI = urlLoad("https://raw.githubusercontent.com/wally-rblx/LinoriaLib/main/Library.lua")
  92. local themeManager = urlLoad("https://raw.githubusercontent.com/wally-rblx/LinoriaLib/main/addons/ThemeManager.lua")
  93.  
  94. local metadata = urlLoad("https://pastebin.com/raw/ESF98Z8F")
  95. local httpService = game:GetService('HttpService')
  96.  
  97. local framework, scrollHandler, network
  98. local counter = 0
  99.  
  100. while true do
  101.     for _, obj in next, getgc(true) do
  102.         if type(obj) == 'table' then
  103.             if rawget(obj, 'GameUI') then
  104.                 framework = obj;
  105.             elseif type(rawget(obj, 'Server')) == 'table' then
  106.                 network = obj;    
  107.             end
  108.         end
  109.  
  110.         if network and framework then break end
  111.     end
  112.  
  113.     for _, module in next, getloadedmodules() do
  114.         if module.Name == 'ScrollHandler' then
  115.             scrollHandler = module;
  116.             break;
  117.         end
  118.     end
  119.  
  120.     if (type(framework) == 'table' and typeof(scrollHandler) == 'Instance' and type(network) == 'table') then
  121.         break
  122.     end
  123.  
  124.     counter = counter + 1
  125.     if counter > 6 then
  126.         fail(string.format('Failed to load game dependencies. Details: %s, %s, %s', type(framework), typeof(scrollHandler), type(network)))
  127.     end
  128.     wait(1)
  129. end
  130.  
  131. local runService = game:GetService('RunService')
  132. local userInputService = game:GetService('UserInputService')
  133. local virtualInputManager = game:GetService('VirtualInputManager')
  134.  
  135. local random = Random.new()
  136.  
  137. local task = task or getrenv().task;
  138. local fastWait, fastSpawn = task.wait, task.spawn;
  139.  
  140. -- firesignal implementation
  141. -- hitchance rolling
  142. local fireSignal, rollChance do
  143.     -- updated for script-ware or whatever
  144.     -- attempted to update for krnl
  145.  
  146.     function fireSignal(target, signal, ...)
  147.         -- getconnections with InputBegan / InputEnded does not work without setting Synapse to the game's context level
  148.         set_identity(2)
  149.         local didFire = false
  150.         for _, signal in next, getconnections(signal) do
  151.             if type(signal.Function) == 'function' and islclosure(signal.Function) then
  152.                 local scr = rawget(getfenv(signal.Function), 'script')
  153.                 if scr == target then
  154.                     didFire = true
  155.                     pcall(signal.Function, ...)
  156.                 end
  157.             end
  158.         end
  159.         -- if not didFire then fail"couldnt fire input signal" end
  160.         set_identity(7)
  161.     end
  162.  
  163.     -- uses a weighted random system
  164.     -- its a bit scuffed rn but it works good enough
  165.  
  166.     function rollChance()
  167.         -- if (//library.flags.autoPlayerMode == 'Manual') then
  168.         if Options.AutoplayerMode.Value == 'Manual' then
  169.             if (Options.SickBind:GetState()) then return 'Sick' end
  170.             if (Options.GoodBind:GetState()) then return 'Good' end
  171.             if (Options.OkayBind:GetState()) then return 'Ok' end
  172.             if (Options.BadBind:GetState()) then return 'Bad' end
  173.  
  174.             return 'Sick' -- incase if it cant find one
  175.         end
  176.  
  177.         local chances = {
  178.             { 'Sick', Options.SickChance.Value },
  179.             { 'Good', Options.GoodChance.Value },
  180.             { 'Ok', Options.OkChance.Value },
  181.             { 'Bad', Options.BadChance.Value },
  182.             { 'Miss' , Options.MissChance.Value },
  183.         }
  184.  
  185.         table.sort(chances, function(a, b)
  186.             return a[2] > b[2]
  187.         end)
  188.  
  189.         local sum = 0;
  190.         for i = 1, #chances do
  191.             sum += chances[i][2]
  192.         end
  193.  
  194.         if sum == 0 then
  195.             return chances[random:NextInteger(1, #chances)][1]
  196.         end
  197.  
  198.         local initialWeight = random:NextInteger(0, sum)
  199.         local weight = 0;
  200.  
  201.         for i = 1, #chances do
  202.             weight = weight + chances[i][2]
  203.  
  204.             if weight > initialWeight then
  205.                 return chances[i][1]
  206.             end
  207.         end
  208.  
  209.         return 'Sick'
  210.     end
  211. end
  212.  
  213. -- autoplayer
  214. local chanceValues do
  215.     chanceValues = {
  216.         Sick = 90,
  217.         Good = 10,
  218.         Ok = 0,
  219.         Bad = 0,
  220.     }
  221.  
  222.     local keyCodeMap = {}
  223.     for _, enum in next, Enum.KeyCode:GetEnumItems() do
  224.         keyCodeMap[enum.Value] = enum
  225.     end
  226.  
  227.     if shared._unload then
  228.         pcall(shared._unload)
  229.     end
  230.  
  231.     function shared._unload()
  232.         if shared._id then
  233.             pcall(runService.UnbindFromRenderStep, runService, shared._id)
  234.         end
  235.  
  236.         UI:Unload()
  237.  
  238.         for i = 1, #shared.threads do
  239.             coroutine.close(shared.threads[i])
  240.         end
  241.  
  242.         for i = 1, #shared.callbacks do
  243.             task.spawn(shared.callbacks[i])
  244.         end
  245.     end
  246.  
  247.     shared.threads = {}
  248.     shared.callbacks = {}
  249.  
  250.     shared._id = httpService:GenerateGUID(false)
  251.  
  252.     local function pressKey(keyCode, state)
  253.         if Options.PressMode.Value == 'virtual input' then
  254.             virtualInputManager:SendKeyEvent(state, keyCode, false, nil)
  255.         else
  256.             fireSignal(scrollHandler, userInputService[state and 'InputBegan' or 'InputEnded'], { KeyCode = keyCode, UserInputType = Enum.UserInputType.Keyboard }, false)
  257.         end
  258.     end
  259.  
  260.     local rng = Random.new()
  261.     runService:BindToRenderStep(shared._id, 1, function()
  262.         --if (not library.flags.autoPlayer) then return end
  263.        
  264.         if (not Toggles.Autoplayer) or (not Toggles.Autoplayer.Value) then
  265.             return
  266.         end
  267.  
  268.         local currentlyPlaying = framework.SongPlayer.CurrentlyPlaying
  269.  
  270.         if typeof(currentlyPlaying) ~= 'Instance' or not currentlyPlaying:IsA('Sound') then
  271.             return
  272.         end
  273.  
  274.         local arrows = framework.UI:GetNotes()
  275.         local count = framework.SongPlayer:GetKeyCount()
  276.         local mode = count .. 'Key'
  277.  
  278.         local arrowData = framework.ArrowData[mode].Arrows
  279.         for i, arrow in next, arrows do
  280.             -- todo: switch to this (https://i.imgur.com/pEVe6Tx.png)
  281.             local ignoredNoteTypes = { Death = true, Mechanic = true, Poison = true }
  282.  
  283.             if type(arrow.NoteDataConfigs) == 'table' then
  284.                 if ignoredNoteTypes[arrow.NoteDataConfigs.Type] then
  285.                     continue
  286.                 end
  287.             end
  288.  
  289.             if (arrow.Side == framework.UI.CurrentSide) and (not arrow.Marked) then -- originally would not play if the song's timepos was 0.
  290.                 local position = (arrow.Data.Position % count) .. ''
  291.  
  292.                 local hitboxOffset = 0
  293.                 do
  294.                     local settings = framework.Settings;
  295.                     local offset = type(settings) == 'table' and settings.HitboxOffset;
  296.                     local value = type(offset) == 'table' and offset.Value;
  297.  
  298.                     if type(value) == 'number' then
  299.                         hitboxOffset = value;
  300.                     end
  301.  
  302.                     hitboxOffset = hitboxOffset / 1000
  303.                 end
  304.  
  305.                 local songTime = framework.SongPlayer.CurrentTime
  306.                 do
  307.                     local configs = framework.SongPlayer.CurrentSongConfigs
  308.                     local playbackSpeed = type(configs) == 'table' and configs.PlaybackSpeed
  309.  
  310.                     if type(playbackSpeed) ~= 'number' then
  311.                         playbackSpeed = 1
  312.                     end
  313.  
  314.                     songTime = songTime /  playbackSpeed
  315.                 end
  316.  
  317.                 local noteTime = math.clamp((1 - math.abs(arrow.Data.Time - (songTime + hitboxOffset))) * 100, 0, 100)
  318.  
  319.                 local result = rollChance()
  320.                 arrow._hitChance = arrow._hitChance or result;
  321.  
  322.                 local hitChance = (Options.AutoplayerMode.Value == 'Manual' and result or arrow._hitChance)
  323.                 if hitChance ~= "Miss" and noteTime >= chanceValues[arrow._hitChance] then
  324.                     fastSpawn(function()
  325.                         arrow.Marked = true;
  326.                         local keyCode = keyCodeMap[arrowData[position].Keybinds.Keyboard[1]]
  327.  
  328.                         pressKey(keyCode, true)
  329.  
  330.                         local arrowLength = arrow.Data.Length or 0
  331.                         local isHeld = arrowLength > 0
  332.  
  333.                         local delayMode = Options.DelayMode.Value
  334.  
  335.                         local minDelay = isHeld and Options.HeldDelayMin or Options.NoteDelayMin;
  336.                         local maxDelay = isHeld and Options.HeldDelayMax or Options.NoteDelayMax;
  337.                         local noteDelay = isHeld and Options.HeldDelay or Options.ReleaseDelay
  338.  
  339.                         local delay = delayMode == 'Random' and rng:NextNumber(minDelay.Value, maxDelay.Value) or noteDelay.Value
  340.                         task.wait(arrowLength + (delay / 1000))
  341.  
  342.                         pressKey(keyCode, false)
  343.                         arrow.Marked = nil;
  344.                     end)
  345.                 end
  346.             end
  347.         end
  348.     end)
  349. end
  350.  
  351. local ActivateUnlockables do
  352.     -- Note: I know you can do this with UserId but it only works if you run it before opening the notes menu
  353.     -- My script should work no matter the order of which you run things :)
  354.  
  355.     local loadStyle = nil
  356.     local function loadStyleProxy(...)
  357.         -- This forces the styles to reload every time
  358.            
  359.         local upvalues = getupvalues(loadStyle)
  360.         for i, upvalue in next, upvalues do
  361.             if type(upvalue) == 'table' and rawget(upvalue, 'Style') then
  362.                 rawset(upvalue, 'Style', nil);
  363.                 setupvalue(loadStyle, i, upvalue)
  364.             end
  365.         end
  366.  
  367.         return loadStyle(...)
  368.     end
  369.  
  370.     local function applyLoadStyleProxy(...)
  371.         local gc = getgc()
  372.         for i = 1, #gc do
  373.             local obj = gc[i]
  374.             if type(obj) == 'function' then
  375.                 -- goodbye nups numeric loop because script-ware is weird
  376.                 local upvalues = getupvalues(obj)
  377.                 for i, upv in next, upvalues do
  378.                     if type(upv) == 'function' and getinfo(upv).name == 'LoadStyle' then
  379.                         -- ugly but it works, we don't know every name for is_synapse_function and similar
  380.                         local function isGameFunction(fn)
  381.                             return getinfo(fn).source:match('%.ArrowSelector%.Customize$')
  382.                         end
  383.  
  384.                         if isGameFunction(obj) and isGameFunction(upv) then
  385.                             -- avoid non-game functions :)
  386.                             loadStyle = loadStyle or upv
  387.                             setupvalue(obj, i, loadStyleProxy)
  388.  
  389.                             table.insert(shared.callbacks, function()
  390.                                 assert(pcall(setupvalue, obj, i, loadStyle))
  391.                             end)
  392.                         end
  393.                     end
  394.                 end
  395.             end
  396.         end
  397.     end
  398.  
  399.     local success, error = pcall(applyLoadStyleProxy)
  400.     if not success then
  401.         return fail(string.format('Failed to hook LoadStyle function. Error(%q)\nExecutor(%q)\n', error, executor))
  402.     end
  403.  
  404.     function ActivateUnlockables()
  405.         local idx = table.find(framework.SongsWhitelist, client.UserId)
  406.         if idx then return end
  407.  
  408.         UI:Notify('Developer arrows have been unlocked!', 3)
  409.         table.insert(framework.SongsWhitelist, client.UserId)
  410.     end
  411. end
  412.  
  413. -- UpdateScore hook
  414. do
  415.     while type(roundManager) ~= 'table' do
  416.         task.wait()
  417.         roundManager = network.Server.RoundManager
  418.     end
  419.  
  420.     local oldUpdateScore = roundManager.UpdateScore;
  421.     function roundManager.UpdateScore(...)
  422.         local args = { ... }
  423.         local score = args[2]
  424.  
  425.         if type(score) == 'number' and Options.ScoreModifier then
  426.         --    table.foreach(args, warn)
  427.             if Options.ScoreModifier.Value == 'No decrease on miss' then
  428.                 args[2] = 0
  429.             elseif Options.ScoreModifier.Value == 'Increase score on miss' then
  430.                 args[2] = math.abs(score)
  431.             end
  432.         end
  433.  
  434.         return oldUpdateScore(unpack(args))
  435.     end
  436.  
  437.     table.insert(shared.callbacks, function()
  438.         roundManager.UpdateScore = oldUpdateScore
  439.     end)
  440. end
  441.  
  442. -- Auto ring collector
  443. do
  444.     local thread = task.spawn(function()
  445.         local map = workspace:waitForChild('Map', 5)
  446.         local buildings = map and map:waitForChild('FunctionalBuildings', 5)
  447.         local spawners = buildings and buildings:waitForChild('RingSpawners', 5)
  448.  
  449.         if spawners == nil then return end
  450.         if type(firetouchinterest) ~= 'function' then return end
  451.  
  452.         while true do
  453.             task.wait()
  454.             if Toggles.AutoClaimRings and Toggles.AutoClaimRings.Value then
  455.                 local character = client.Character
  456.                 local rootPart = character and character:findFirstChild('HumanoidRootPart')
  457.  
  458.                 if rootPart == nil then continue end
  459.  
  460.                 for i, spawner in next, spawners:GetChildren() do
  461.                     for _, ring in next, spawner:GetChildren() do
  462.                         if ring.Name ~= 'GoldenRing' then continue end
  463.  
  464.                         local ring = ring:findFirstChild('ring')
  465.                         if not (ring and ring:IsA('BasePart')) then continue end
  466.                         if ring.Transparency == 1 then continue end
  467.  
  468.                         firetouchinterest(ring, rootPart, 0)
  469.                         firetouchinterest(ring, rootPart, 1)
  470.                     end
  471.                 end
  472.             end
  473.         end
  474.     end)
  475.     table.insert(shared.callbacks, function()
  476.         pcall(task.cancel, thread)
  477.     end)
  478. end
  479.  
  480. local SaveManager = {} do
  481.     SaveManager.Ignore = {}
  482.     SaveManager.Parser = {
  483.         Toggle = {
  484.             Save = function(idx, object)
  485.                 return { type = 'Toggle', idx = idx, value = object.Value }
  486.             end,
  487.             Load = function(idx, data)
  488.                 if Toggles[idx] then
  489.                     Toggles[idx]:SetValue(data.value)
  490.                 end
  491.             end,
  492.         },
  493.         Slider = {
  494.             Save = function(idx, object)
  495.                 return { type = 'Slider', idx = idx, value = tostring(object.Value) }
  496.             end,
  497.             Load = function(idx, data)
  498.                 if Options[idx] then
  499.                     Options[idx]:SetValue(data.value)
  500.                 end
  501.             end,
  502.         },
  503.         Dropdown = {
  504.             Save = function(idx, object)
  505.                 return { type = 'Dropdown', idx = idx, value = object.Value, mutli = object.Multi }
  506.             end,
  507.             Load = function(idx, data)
  508.                 if Options[idx] then
  509.                     Options[idx]:SetValue(data.value)
  510.                 end
  511.             end,
  512.         },
  513.         ColorPicker = {
  514.             Save = function(idx, object)
  515.                 return { type = 'ColorPicker', idx = idx, value = object.Value:ToHex() }
  516.             end,
  517.             Load = function(idx, data)
  518.                 if Options[idx] then
  519.                     Options[idx]:SetValueRGB(Color3.fromHex(data.value))
  520.                 end
  521.             end,
  522.         },
  523.         KeyPicker = {
  524.             Save = function(idx, object)
  525.                 return { type = 'KeyPicker', idx = idx, mode = object.Mode, key = object.Value }
  526.             end,
  527.             Load = function(idx, data)
  528.                 if Options[idx] then
  529.                     Options[idx]:SetValue({ data.key, data.mode })
  530.                 end
  531.             end,
  532.         }
  533.     }
  534.  
  535.     function SaveManager:Save(name)
  536.         local fullPath = 'funky_friday_autoplayer/configs/' .. name .. '.json'
  537.  
  538.         local data = {
  539.             version = 2.2,
  540.             objects = {}
  541.         }
  542.  
  543.         for idx, toggle in next, Toggles do
  544.             if self.Ignore[idx] then continue end
  545.             table.insert(data.objects, self.Parser[toggle.Type].Save(idx, toggle))
  546.         end
  547.  
  548.         for idx, option in next, Options do
  549.             if not self.Parser[option.Type] then continue end
  550.             if self.Ignore[idx] then continue end
  551.  
  552.             table.insert(data.objects, self.Parser[option.Type].Save(idx, option))
  553.         end
  554.  
  555.         local success, encoded = pcall(httpService.JSONEncode, httpService, data)
  556.         if not success then
  557.             return false, 'failed to encode data'
  558.         end
  559.  
  560.         writefile(fullPath, encoded)
  561.         return true
  562.     end
  563.  
  564.     function SaveManager:Load(name)
  565.         local file = 'funky_friday_autoplayer/configs/' .. name .. '.json'
  566.         if not isfile(file) then return false, 'invalid file' end
  567.  
  568.         local success, decoded = pcall(httpService.JSONDecode, httpService, readfile(file))
  569.         if not success then return false, 'decode error' end
  570.         if decoded.version ~= 2.2 then return false, 'invalid version' end
  571.  
  572.         for _, option in next, decoded.objects do
  573.             if self.Parser[option.type] then
  574.                 self.Parser[option.type].Load(option.idx, option)
  575.             end
  576.         end
  577.  
  578.         return true
  579.     end
  580.  
  581.     function SaveManager.Refresh()
  582.         local list = listfiles('funky_friday_autoplayer/configs')
  583.  
  584.         local out = {}
  585.         for i = 1, #list do
  586.             local file = list[i]
  587.             if file:sub(-5) == '.json' then
  588.                 -- i hate this but it has to be done ...
  589.  
  590.                 local pos = file:find('.json', 1, true)
  591.                 local start = pos
  592.  
  593.                 local char = file:sub(pos, pos)
  594.                 while char ~= '/' and char ~= '\\' and char ~= '' do
  595.                     pos = pos - 1
  596.                     char = file:sub(pos, pos)
  597.                 end
  598.  
  599.                 if char == '/' or char == '\\' then
  600.                     table.insert(out, file:sub(pos + 1, start - 1))
  601.                 end
  602.             end
  603.         end
  604.        
  605.         Options.ConfigList.Values = out;
  606.         Options.ConfigList:SetValues()
  607.         Options.ConfigList:Display()
  608.  
  609.         return out
  610.     end
  611.  
  612.     function SaveManager:Delete(name)
  613.         local file = 'funky_friday_autoplayer/configs/' .. name .. '.json'
  614.         if not isfile(file) then return false, string.format('Config %q does not exist', name) end
  615.  
  616.         local succ, err = pcall(delfile, file)
  617.         if not succ then
  618.             return false, string.format('error occured during file deletion: %s', err)
  619.         end
  620.  
  621.         return true
  622.     end
  623.  
  624.     function SaveManager:SetIgnoreIndexes(list)
  625.         for i = 1, #list do
  626.             table.insert(self.Ignore, list[i])
  627.         end
  628.     end
  629.  
  630.     function SaveManager.Check()
  631.         local list = listfiles('funky_friday_autoplayer/configs')
  632.  
  633.         for _, file in next, list do
  634.             if isfolder(file) then continue end
  635.  
  636.             local data = readfile(file)
  637.             local success, decoded = pcall(httpService.JSONDecode, httpService, data)
  638.  
  639.             if success and type(decoded) == 'table' and decoded.version ~= 2.2 then
  640.                 pcall(delfile, file)
  641.             end
  642.         end
  643.     end
  644. end
  645.  
  646. local Window = UI:CreateWindow({
  647.     Title = string.format('Funky Friday Autoplayer - Version %s | Updated: %s', metadata.version, metadata.updated),
  648.     AutoShow = true,
  649.    
  650.     Center = true,
  651.     Size = UDim2.fromOffset(550, 627),
  652. })
  653.  
  654. local Tabs = {}
  655. local Groups = {}
  656.  
  657. Tabs.Main = Window:AddTab('Main')
  658. Tabs.Miscellaneous = Window:AddTab('Miscellaneous')
  659.  
  660. Groups.Autoplayer = Tabs.Main:AddLeftGroupbox('Autoplayer')
  661.     Groups.Autoplayer:AddToggle('Autoplayer', { Text = 'Autoplayer' }):AddKeyPicker('AutoplayerBind', { Default = 'End', NoUI = true, SyncToggleState = true })
  662.     Groups.Autoplayer:AddDropdown('PressMode', {
  663.         Text = 'Input mode',
  664.         Compact = true,
  665.         Default = 'firesignal',
  666.         Values = { 'firesignal', 'virtual input' },
  667.         Tooltip = 'Input method used to press arrows.\n* firesignal: calls input functions directly.\n* virtual input: emulates key presses. use if "firesignal" does not work.',
  668.     })
  669.  
  670. Groups.HitChances = Tabs.Main:AddLeftGroupbox('Hit chances')
  671.     Groups.HitChances:AddDropdown('AutoplayerMode', {
  672.         Text = 'Autoplayer mode',
  673.         Compact = true,
  674.         Default = 1,
  675.         Values = { 'Automatic', 'Manual' },
  676.         Tooltip = 'Mode to use for deciding when to hit notes.\n* Automatic: hits notes based on chance sliders\n* Manual: hits notes based on held keybinds',
  677.     })
  678.  
  679.     Groups.HitChances:AddSlider('SickChance',   { Text = 'Sick chance', Min = 0, Max = 100, Default = 98, Suffix = '%', Rounding = 0, Compact = true })
  680.     Groups.HitChances:AddSlider('GoodChance',   { Text = 'Good chance', Min = 0, Max = 100, Default = 2, Suffix = '%', Rounding = 0, Compact = true })
  681.     Groups.HitChances:AddSlider('OkChance',     { Text = 'Ok chance',   Min = 0, Max = 100, Default = 0, Suffix = '%', Rounding = 0, Compact = true })
  682.     Groups.HitChances:AddSlider('BadChance',    { Text = 'Bad chance',  Min = 0, Max = 100, Default = 0, Suffix = '%', Rounding = 0, Compact = true })
  683.     Groups.HitChances:AddSlider('MissChance',   { Text = 'Miss chance', Min = 0, Max = 100, Default = 0, Suffix = '%', Rounding = 0, Compact = true })
  684.  
  685. Groups.HitTiming = Tabs.Main:AddLeftGroupbox('Hit timing')
  686.     Groups.HitTiming:AddDropdown('DelayMode', {
  687.         Text = 'Delay mode',
  688.         Default = 1,
  689.         Values = { 'Manual', 'Random' },
  690.         Tooltip = 'Adjustable timing for when to release notes.\n* Manual releases the note after a fixed amount of time.\n* Random releases the note after a random amount of time.',
  691.     })
  692.  
  693.     Groups.HitTiming:AddLabel('Manual delay')
  694.     Groups.HitTiming:AddSlider('ReleaseDelay',   { Text = 'Note delay', Min = 0, Max = 500, Default = 20, Rounding = 0, Compact = true, Suffix = 'ms' })
  695.     Groups.HitTiming:AddSlider('HeldDelay',      { Text = 'Held note delay', Min = -20, Max = 100, Default = 0, Rounding = 0, Compact = true, Suffix = 'ms' })
  696.        
  697.     Groups.HitTiming:AddLabel('Random delay')
  698.     Groups.HitTiming:AddSlider('NoteDelayMin',   { Text = 'Min note delay', Min = 0, Max = 100, Default = 0,    Rounding = 0, Compact = true, Suffix = 'ms' })
  699.     Groups.HitTiming:AddSlider('NoteDelayMax',   { Text = 'Max note delay', Min = 0, Max = 500, Default = 20,   Rounding = 0, Compact = true, Suffix = 'ms' })
  700.    
  701.     Groups.HitTiming:AddSlider('HeldDelayMin',   { Text = 'Min held note delay', Min = 0, Max = 100, Default = 0,   Rounding = 0, Compact = true, Suffix = 'ms' })
  702.     Groups.HitTiming:AddSlider('HeldDelayMax',   { Text = 'Max held note delay', Min = 0, Max = 500, Default = 20,  Rounding = 0, Compact = true, Suffix = 'ms' })
  703.  
  704. Groups.Misc = Tabs.Main:AddRightGroupbox('Misc')
  705.     Groups.Misc:AddButton('Unlock developer notes', ActivateUnlockables)
  706.     Groups.Misc:AddToggle('AutoClaimRings', { Text = 'Auto claim rings' })
  707.  
  708. Groups.Keybinds = Tabs.Main:AddRightGroupbox('Keybinds')
  709.     Groups.Keybinds:AddLabel('Sick'):AddKeyPicker('SickBind', { Default = 'One', NoUI = true })
  710.     Groups.Keybinds:AddLabel('Good'):AddKeyPicker('GoodBind', { Default = 'Two', NoUI = true })
  711.     Groups.Keybinds:AddLabel('Ok'):AddKeyPicker('OkayBind', { Default = 'Three', NoUI = true })
  712.     Groups.Keybinds:AddLabel('Bad'):AddKeyPicker('BadBind', { Default = 'Four', NoUI = true })
  713.  
  714. Groups.Configs = Tabs.Miscellaneous:AddRightGroupbox('Configs')
  715. Groups.Credits = Tabs.Miscellaneous:AddRightGroupbox('Credits')
  716.     Groups.Credits:AddLabel('<font color="#3da5ff">wally</font> - script')
  717.     Groups.Credits:AddLabel('<font color="#de6cff">Sezei</font> - contributor')
  718.     Groups.Credits:AddLabel('Inori - ui library')
  719.     Groups.Credits:AddLabel('Jan - old ui library')
  720.  
  721.  
  722. Groups.Misc = Tabs.Miscellaneous:AddRightGroupbox('Miscellaneous')
  723.     Groups.Misc:AddLabel(metadata.message or 'no message found!', true)
  724.  
  725.     Groups.Misc:AddDivider()
  726.     Groups.Misc:AddButton('Unload script', function() pcall(shared._unload) end)
  727.     Groups.Misc:AddButton('Copy discord', function()
  728.         if pcall(setclipboard, "https://wally.cool/discord") then
  729.             UI:Notify('Successfully copied discord link to your clipboard!', 5)
  730.         end
  731.     end)
  732.  
  733.     Groups.Misc:AddLabel('Menu toggle'):AddKeyPicker('MenuToggle', { Default = 'Delete', NoUI = true })
  734.  
  735.     UI.ToggleKeybind = Options.MenuToggle
  736.  
  737. if type(readfile) == 'function' and type(writefile) == 'function' and type(makefolder) == 'function' and type(isfolder) == 'function' then
  738.     makefolder('funky_friday_autoplayer')
  739.     makefolder('funky_friday_autoplayer\\configs')
  740.  
  741.     Groups.Configs:AddDropdown('ConfigList', { Text = 'Config list', Values = {} })
  742.     Groups.Configs:AddInput('ConfigName',    { Text = 'Config name' })
  743.  
  744.     Groups.Configs:AddDivider()
  745.  
  746.     Groups.Configs:AddButton('Save config', function()
  747.         local name = Options.ConfigName.Value;
  748.         if name:gsub(' ', '') == '' then
  749.             return UI:Notify('Invalid config name.', 3)
  750.         end
  751.  
  752.         local success, err = SaveManager:Save(name)
  753.         if not success then
  754.             return UI:Notify(tostring(err), 5)
  755.         end
  756.  
  757.         UI:Notify(string.format('Saved config %q', name), 5)
  758.         task.defer(SaveManager.Refresh)
  759.     end)
  760.  
  761.     Groups.Configs:AddButton('Load', function()
  762.         local name = Options.ConfigList.Value
  763.         local success, err = SaveManager:Load(name)
  764.         if not success then
  765.             return UI:Notify(tostring(err), 5)
  766.         end
  767.  
  768.         UI:Notify(string.format('Loaded config %q', name), 5)
  769.     end):AddButton('Delete', function()
  770.         local name = Options.ConfigList.Value
  771.         if name:gsub(' ', '') == '' then
  772.             return UI:Notify('Invalid config name.', 3)
  773.         end
  774.  
  775.         local success, err = SaveManager:Delete(name)
  776.         if not success then
  777.             return UI:Notify(tostring(err), 5)
  778.         end
  779.  
  780.         UI:Notify(string.format('Deleted config %q', name), 5)
  781.  
  782.         task.spawn(Options.ConfigList.SetValue, Options.ConfigList, nil)
  783.         task.defer(SaveManager.Refresh)
  784.     end)
  785.  
  786.     Groups.Configs:AddButton('Refresh list', SaveManager.Refresh)
  787.  
  788.     task.defer(SaveManager.Refresh)
  789.     task.defer(SaveManager.Check)
  790. else
  791.     Groups.Configs:AddLabel('Your exploit is missing file functions so you are unable to use configs.', true)
  792.     --UI:Notify('Failed to create configs tab due to your exploit missing certain file functions.', 2)
  793. end
  794.  
  795. -- Themes
  796. do
  797.     local latestThemeIndex = 0
  798.     for i, theme in next, themeManager.BuiltInThemes do
  799.         if theme[1] > latestThemeIndex then
  800.             latestThemeIndex = theme[1]
  801.         end
  802.     end
  803.  
  804.     latestThemeIndex = latestThemeIndex + 1
  805.  
  806.     local linoriaTheme = themeManager.BuiltInThemes.Default[2]
  807.     local funkyFridayTheme = table.clone(themeManager.BuiltInThemes.Default[2])
  808.  
  809.     funkyFridayTheme.AccentColor = Color3.fromRGB(255, 65, 65):ToHex()
  810.  
  811.     themeManager.BuiltInThemes['Linoria'] = { latestThemeIndex, linoriaTheme }
  812.     themeManager.BuiltInThemes['Default'] = { 1, funkyFridayTheme }
  813.  
  814.     themeManager:SetLibrary(UI)
  815.     themeManager:SetFolder('funky_friday_autoplayer')
  816.     themeManager:ApplyToGroupbox(Tabs.Miscellaneous:AddLeftGroupbox('Themes'))
  817.  
  818.     SaveManager:SetIgnoreIndexes({
  819.         "BackgroundColor", "MainColor", "AccentColor", "OutlineColor", "FontColor", -- themes
  820.         "ThemeManager_ThemeList", 'ThemeManager_CustomThemeList', 'ThemeManager_CustomThemeName', -- themes
  821.     })
  822. end
  823.  
  824. UI:Notify(string.format('Loaded script in %.4f second(s)!', tick() - start), 3)
Advertisement
Comments
Add Comment
Please, Sign In to add comment
Advertisement