Advertisement
ShadyMoonStudios

Funky Friday AutoPlay Script[with dev arrows]

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