From 9bfaabd33d3b5490aa30815195706048763eb1ef Mon Sep 17 00:00:00 2001 From: GhustOne <71855034+GhustOne@users.noreply.github.com> Date: Thu, 5 Jan 2023 21:33:48 +0300 Subject: [PATCH 01/11] Add files via upload --- aioUpdate.lua | 5327 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 5327 insertions(+) create mode 100644 aioUpdate.lua diff --git a/aioUpdate.lua b/aioUpdate.lua new file mode 100644 index 0000000..df99371 --- /dev/null +++ b/aioUpdate.lua @@ -0,0 +1,5327 @@ +return { + ["GLTW.lua"] = [=[-- Made by GhostOne +-- L00naMods "Even if you say L00na is a bitch just put my name in there somewhere" +-- Ghost's Lua Table Writer +--[[ +nil gltw.write(table table, string name, string path|nil, table index exclusions, skip empty tables) +-- example gltw.write({name = "l00na", iq = -1, braincells = {}}, "something", "folder1\\", {"name"}, true) < this will not write 'name' (excluded) or 'braincells' (empty) + +table[] gltw.read(string name, string path|nil(in same path as lua), table|nil, bool|nil) +-- if a table is the 3rd arg then whatever is read from the file will be added to it without overwriting stuff that isn't in the saved file +-- if the 4th arg is true the function won't throw an error if the file doesn't exist and will return nil +]] + +local gltw = {} +local type = type +local l_next = next +local ipairs = ipairs + +function gltw.write_table(tableTW, indentation, exclusions, exclude_empty, string_lines) + for k, v in l_next, tableTW do + if not exclusions[k] then + local typeofv = type(v) + local index + if type(k) == "number" then + index = "["..k.."] = " + else + index = "[\""..k.."\"] = " + end + + if typeofv == "string" then + string_lines[#string_lines + 1] = indentation..index.."[=["..v.."]=]," + elseif typeofv ~= "function" and typeofv ~= "table" then + string_lines[#string_lines + 1] = indentation..index..tostring(v).."," + elseif typeofv == "table" and (l_next(v) or not exclude_empty) then + string_lines[#string_lines + 1] = indentation..index.."{" + gltw.write_table(v, indentation.." ", exclusions, exclude_empty, string_lines) + string_lines[#string_lines + 1] = indentation.."}," + end + end + end +end + +function gltw.write(tableTW, name, path, exclusions, exclude_empty, compiled) + local convertedExclusions = {} + if exclusions then + for _, v in ipairs(exclusions) do + convertedExclusions[v] = true + end + end + assert(tableTW, "no table was provided"..(name and " to write for file '"..name.."'" or "")) + + if name then + path = path or "" + assert(type(name) == "string" and type(path) == "string", "name or path isn't a string") + end + + local string_lines = {} + + string_lines[#string_lines + 1] = "return {" + gltw.write_table(tableTW, " ", convertedExclusions, exclude_empty, string_lines) + string_lines[#string_lines + 1] = "}" + + if name then + local file = io.open(path..name..".lua", "wb") + assert(file, "'"..name.."' was not created.") + + local stringified = table.concat(string_lines, "\n") + + file:write(compiled and string.dump(load(stringified), true) or stringified) + + file:flush() + file:close() + end + + return string_lines +end + +function gltw.add_to_table(getTable, addToTable, typeMatched) + assert(type(getTable) == "table" and type(addToTable) == "table", "args have to be tables") + for k, v in l_next, getTable do + if type(v) ~= "table" then + if typeMatched and (type(getTable[k]) == type(addToTable[k]) or not addToTable[k]) or not typeMatched then + addToTable[k] = getTable[k] + end + else + if type(addToTable[k]) ~= "table" and not typeMatched then + addToTable[k] = {} + end + if type(addToTable[k]) == "table" then + gltw.add_to_table(getTable[k], addToTable[k]) + end + end + end +end + +function gltw.read(name, path, addToTable, typeMatched, overrideError) + if overrideError and not utils.file_exists(path..name..".lua") then + return + end + + path = path or "" + if type(tableRT) == "string" then + name, path = tableRT, name or path + tableRT = nil + end + + local readTable = loadfile(path..name..".lua", "tb")() + if addToTable then + gltw.add_to_table(readTable, addToTable, typeMatched) + end + return readTable +end + +return gltw +]=], + ["cheesemenu.lua"] = [=[--Made by GhostOne + +--[[ + ,o888888o. 8 8888 8 8 8888888888 8 8888888888 d888888o. 8 8888888888 + 8888 `88. 8 8888 8 8 8888 8 8888 .`8888:' `88. 8 8888 +,8 8888 `8. 8 8888 8 8 8888 8 8888 8.`8888. Y8 8 8888 +88 8888 8 8888 8 8 8888 8 8888 `8.`8888. 8 8888 +88 8888 8 8888 8 8 888888888888 8 888888888888 `8.`8888. 8 888888888888 +88 8888 8 8888 8 8 8888 8 8888 `8.`8888. 8 8888 +88 8888 8 8888888888888 8 8888 8 8888 `8.`8888. 8 8888 +`8 8888 .8' 8 8888 8 8 8888 8 8888 8b `8.`8888. 8 8888 + 8888 ,88' 8 8888 8 8 8888 8 8888 `8b. ;8.`8888 8 8888 + `8888888P' 8 8888 8 8 888888888888 8 888888888888 `Y8888P ,88P' 8 888888888888 + . . + ,8. ,8. 8 8888888888 b. 8 8 8888 88 + ,888. ,888. 8 8888 888o. 8 8 8888 88 + .`8888. .`8888. 8 8888 Y88888o. 8 8 8888 88 + ,8.`8888. ,8.`8888. 8 8888 .`Y888888o. 8 8 8888 88 + ,8'8.`8888,8^8.`8888. 8 888888888888 8o. `Y888888o. 8 8 8888 88 + ,8' `8.`8888' `8.`8888. 8 8888 8`Y8o. `Y88888o8 8 8888 88 + ,8' `8.`88' `8.`8888. 8 8888 8 `Y8o. `Y8888 8 8888 88 + ,8' `8.`' `8.`8888. 8 8888 8 `Y8o. `Y8 ` 8888 ,8P + ,8' `8 `8.`8888. 8 8888 8 `Y8o.` 8888 ,d8P +,8' ` `8.`8888. 8 888888888888 8 `Yo `Y88888P' +]] + +local version = "1.8.2" +local loadCurrentMenu +local httpTrustedOff + +-- Version check +if menu.is_trusted_mode_enabled(1 << 3) and menu.is_trusted_mode_enabled(1 << 2) then + menu.create_thread(function() + local vercheckKeys = {ctrl = MenuKey(), space = MenuKey(), enter = MenuKey(), rshift = MenuKey()} + vercheckKeys.ctrl:push_vk(0x11); vercheckKeys.space:push_vk(0x20); vercheckKeys.enter:push_vk(0x0D); vercheckKeys.rshift:push_vk(0xA1) + + local responseCode, githubVer = web.get("https://raw.githubusercontent.com/GhustOne/CheeseMenu/main/VERSION.txt") + if responseCode == 200 then + githubVer = githubVer:gsub("[\r\n]", "") + if githubVer ~= version then + local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.5+0.5 + local strings = { + version_compare = "\nCurrent Version:"..version.."\nLatest Version:"..githubVer, + version_compare_x_offset = v2(-scriptdraw.get_text_size("\nCurrent Version:"..version.."\nLatest Version:"..githubVer, text_size).x/graphics.get_screen_width(), 0), + new_ver_x_offset = v2(-scriptdraw.get_text_size("New version available. Press CTRL or SPACE to skip or press ENTER or RIGHT SHIFT to update.", text_size).x/graphics.get_screen_width(), 0), + } + strings.changelog_rc, strings.changelog = web.get("https://raw.githubusercontent.com/GhustOne/CheeseMenu/main/CHANGELOG.txt") + if strings.changelog_rc == 200 then + strings.changelog = "\n\n\nChangelog:\n"..strings.changelog + else + strings.changelog = "" + end + strings.changelog_x_offset = v2(-scriptdraw.get_text_size(strings.changelog, text_size).x/graphics.get_screen_width(), 0) + local stringV2size = v2(2, 2) + while true do + scriptdraw.draw_text("New version available. Press CTRL or SPACE to skip or press ENTER or RIGHT SHIFT to update.", strings.new_ver_x_offset, stringV2size, text_size, 0xFF0CB4F4, 2) + scriptdraw.draw_text(strings.version_compare, strings.version_compare_x_offset, stringV2size, text_size, 0xFF0CB4F4, 2) + scriptdraw.draw_text(strings.changelog, strings.changelog_x_offset, stringV2size, text_size, 0xFF0CB4F4, 2) + if vercheckKeys.ctrl:is_down() or vercheckKeys.space:is_down() then + loadCurrentMenu() + break + elseif vercheckKeys.enter:is_down() or vercheckKeys.rshift:is_down() then + local responseCode, autoupdater = web.get([[https://raw.githubusercontent.com/GhustOne/CheeseMenu/main/CMAutoUpdater.lua]]) + if responseCode == 200 then + autoupdater = load(autoupdater) + menu.create_thread(function() + menu.notify("Update started, please wait...", "Cheese Menu") + local status = autoupdater() + if status then + if type(status) == "string" then + menu.notify("Updating local files failed, one or more of the files could not be opened.\nThere is a high chance the files got corrupted, please redownload the menu.", "Cheese Menu", 5, 0x0000FF) + else + menu.notify("Update successful", "Cheese Menu", 4, 0x00FF00) + dofile(utils.get_appdata_path("PopstarDevs", "2Take1Menu").."\\scripts\\cheesemenu.lua") + end + else + menu.notify("Download for updated files failed, current files have not been replaced.", "Cheese Menu", 5, 0x0000FF) + end + end, nil) + break + else + menu.notify("Getting Updater failed. Check your connection and try downloading manually.", "Cheese Menu", 5, 0x0000FF) + end + end + system.wait(0) + end + else + loadCurrentMenu() + end + end + end, nil) +else + if menu.is_trusted_mode_enabled(1 << 2) then + httpTrustedOff = true + else + menu.notify("Trusted mode > Natives has to be on. If you wish for auto updates enable Http too.", "Cheese Menu", 5, 0x0000FF) + end +end + +local features +local currentMenu +local func +local stuff +local menu_configuration_features +function loadCurrentMenu() + features = {OnlinePlayers = {}} + currentMenu = features + func = {} + stuff = { + pid = -1, + player_info = { + {"Player ID", "0"}, + {"God", "false"}, + {"Proofs (God)", "false"}, + {"Vehicle God", "false"}, + {"Flagged as Modder", "false"}, + {"Host", "false"}, + {"Wanted", "0"}, + {"Health", "327/327"}, + {"Armor", "50"}, + {"IP", "0.0.0.0"}, + {"SCID", "133769420"}, + {"Host Token", "0xdeadbeef"}, + {"Host Priority", "0"}, + max_health = "/327", + name = "cheesemenu" + }, + proofs = { + bulletProof = native.ByteBuffer8(), + fireProof = native.ByteBuffer8(), + explosionProof = native.ByteBuffer8(), + collisionProof = native.ByteBuffer8(), + meleeProof = native.ByteBuffer8(), + steamProof = native.ByteBuffer8(), + p7 = native.ByteBuffer8(), + drownProof = native.ByteBuffer8(), + }, + scroll = 1, + scrollHiddenOffset = 0, + drawHiddenOffset = 0, + trusted_mode = 0, + old_selected = 0, + player_submenu_sort = 0, + previousMenus = {}, + threads = {}, + feature_by_id = {}, + player_feature_by_id = {}, + feature_hints = {}, + path = { + scripts = utils.get_appdata_path("PopstarDevs", "2Take1Menu").."\\scripts\\" + }, + hotkeys = {}, + hotkey_cooldowns = {}, + hotkeys_to_vk = {}, + table_sort_functions = { + [0] = function(a, b) return a.pid < b.pid end, + function(a, b) return a.pid > b.pid end, + function(a, b) return a.name:lower() < b.name:lower() end, + function(a, b) return a.name:lower() > b.name:lower() end, + function(a, b) return player.get_player_host_priority(a.pid) < player.get_player_host_priority(b.pid) end, + function(a, b) return player.get_player_host_priority(a.pid) > player.get_player_host_priority(b.pid) end + }, + char_codes = { + ["ENTER"] = 0x0D, + ["0"] = 0x30, + ["1"] = 0x31, + ["2"] = 0x32, + ["3"] = 0x33, + ["4"] = 0x34, + ["5"] = 0x35, + ["6"] = 0x36, + ["7"] = 0x37, + ["8"] = 0x38, + ["9"] = 0x39, + ["A"] = 0x41, + ["B"] = 0x42, + ["C"] = 0x43, + ["D"] = 0x44, + ["E"] = 0x45, + ["F"] = 0x46, + ["G"] = 0x47, + ["H"] = 0x48, + ["I"] = 0x49, + ["J"] = 0x4A, + ["K"] = 0x4B, + ["L"] = 0x4C, + ["M"] = 0x4D, + ["N"] = 0x4E, + ["O"] = 0x4F, + ["P"] = 0x50, + ["Q"] = 0x51, + ["R"] = 0x52, + ["S"] = 0x53, + ["T"] = 0x54, + ["U"] = 0x55, + ["V"] = 0x56, + ["W"] = 0x57, + ["X"] = 0x58, + ["Y"] = 0x59, + ["Z"] = 0x5A, + ["NUM0"] = 0x60, + ["NUM1"] = 0x61, + ["NUM2"] = 0x62, + ["NUM3"] = 0x63, + ["NUM4"] = 0x64, + ["NUM5"] = 0x65, + ["NUM6"] = 0x66, + ["NUM7"] = 0x67, + ["NUM8"] = 0x68, + ["NUM9"] = 0x69, + ["Space"] = 0x20, + [";"] = 0xBA, + ["PLUS"] = 0xBB, + [","] = 0xBC, + ["-"] = 0xBD, + ["DOT"] = 0xBE, + ["/"] = 0xBF, + ["`"] = 0xC0, + ["LSQREBRACKET"] = 0xDB, + ["\\"] = 0xDC, + ["RSQREBRACKET"] = 0xDD, + ["QUOTE"] = 0xDE, + ["NUM*"] = 0x6A, + ["NUMPLUS"] = 0x6B, + ["NUM-"] = 0x6D, + ["NUMDEL"] = 0x6E, + ["NUM/"] = 0x6F, + ["PAGEUP"] = 0x21, + ["PAGEDOWN"] = 0x22, + ["END"] = 0x23, + ["HOME"] = 0x24, + ["SCROLLLOCK"] = 0x91, + ["LEFTARROW"] = 0x25, + ["UPARROW"] = 0x26, + ["RIGHTARROW"] = 0x27, + ["DOWNARROW"] = 0x28, + ["SELECT"] = 0x29, + ["INS"] = 0x2D, + ["DEL"] = 0x2E, + ["PAUSE"] = 0x13, + ["CAPSLOCK"] = 0x14, + ["BACKSPACE"] = 0x08, + ["LSHIFT"] = 0xA0, + ["RSHIFT"] = 0xA1, + ["LCONTROL"] = 0xA2, + ["RCONTROL"] = 0xA3, + ["LALT"] = 0xA4, + ["RALT"] = 0xA5, + ["F1"] = 0x70, + ["F2"] = 0x71, + ["F3"] = 0x72, + ["F4"] = 0x73, + ["F5"] = 0x74, + ["F6"] = 0x75, + ["F7"] = 0x76, + ["F8"] = 0x77, + ["F9"] = 0x78, + ["F10"] = 0x79, + ["F11"] = 0x7A, + ["F12"] = 0x7B, + ["F13"] = 0x7C, + ["F14"] = 0x7D, + ["F15"] = 0x7E, + ["F16"] = 0x7F, + ["F17"] = 0x80, + ["F18"] = 0x81, + ["F19"] = 0x82, + ["F20"] = 0x83, + ["F21"] = 0x84, + ["F22"] = 0x85, + ["F23"] = 0x86, + ["F24"] = 0x87, + }, + hotkey_notifications = {toggle = true, action = false}, + controls = { + left = "LEFTARROW", + up = "UPARROW", + right = "RIGHTARROW", + down = "DOWNARROW", + select = "ENTER", + back = "BACKSPACE", + open = "F4", + setHotkey = "F11", + specialKey = "LCONTROL", + }, + vkcontrols = { + left = 0x25, + up = 0x26, + right = 0x27, + down = 0x28, + select = 0x0D, + back = 0x08, + open = 0x73, + setHotkey = 0x7A, + specialKey = 0xA2, + }, + drawScroll = 0, + maxDrawScroll = 0, + menuData = { + menuToggle = false, + menuNav = true, + chatBoxOpen = false, + pos_x = 0.5, + pos_y = 0.44652777777, + width = 0.2, + height = 0.305, + border = 0.0013888, + selector_speed = 1, + slider = { + width = 0.2, + height = 0.01, + heightActive = 0.025, + }, + footer = { + footer_y_offset = 0, + padding = 0.0078125, + footer_size = 0.019444444, + draw_footer = true, + footer_pos_related_to_background = false, + footer_text = "Made by GhostOne", + }, + fonts = { + text = 0, + footer = 0, + hint = 0 + }, + side_window = { + on = true, + offset = {x = 0, y = 0}, + spacing = 0.0547222, + width = 0.3, + padding = 0.01 + }, + header = "cheese_menu", + feature_offset = 0.025, + feature_scale = {x = 0.2, y = 0.025}, + padding = { + name = 0.003125, + parent = 0.003125, + value = 0.048125, + slider = 0.003125, + }, + text_size = (((graphics.get_screen_width()*graphics.get_screen_height())/3686400)*0.45+0.25), + text_size_modifier = 1, + footer_size_modifier = 1, + hint_size_modifier = 1, + text_y_offset = -0.0055555555, + color = {}, + files = {}, + background_sprite = { + sprite = nil, + size = 1, + loaded_sprites = {}, + offset = {x = 0, y = 0} + }, + max_features = 12, + set_max_features = function(self, int) + int = math.floor(int+0.5) + self.height = int * self.feature_offset + self.max_features = int + end + }, + disable_all_controls = function() + while true do + for i = 0, 360 do + controls.disable_control_action(0, i, true) + end + system.wait(0) + end + end + } + + stuff.menuData.color = { + background = {r = 0, g = 0, b = 0, a = 0}, + sprite = 0xE6FFFFFF, + slider_active = {r = 255, g = 200, b = 0, a = 255}, + slider_background = {r = 0, g = 0, b = 0, a = 160}, + slider_text = {r = 0, g = 0, b = 0, a = 255}, + slider_selectedActive = {r = 255, g = 255, b = 255, a = 160}, + slider_selectedBackground = {r = 255, g = 160, b = 0, a = 180}, + feature_bottomLeft = {r = 255, g = 160, b = 0, a = 170}, + feature_topLeft = {r = 255, g = 160, b = 0, a = 170}, + feature_topRight = {r = 255, g = 160, b = 0, a = 170}, + feature_bottomRight = {r = 255, g = 160, b = 0, a = 170}, + feature_selected_bottomLeft = {r = 0, g = 0, b = 0, a = 200}, + feature_selected_topLeft = {r = 0, g = 0, b = 0, a = 200}, + feature_selected_topRight = {r = 0, g = 0, b = 0, a = 200}, + feature_selected_bottomRight = {r = 0, g = 0, b = 0, a = 200}, + text_selected = {r = 255, g = 200, b = 0, a = 180}, + text = {r = 0, g = 0, b = 0, a = 180}, + border = {r = 0, g = 0, b = 0, a = 180}, + footer = {r = 255, g = 160, b = 0, a = 170}, + footer_text = {r = 0, g = 0, b = 0, a = 180}, + notifications = {r = 255, g = 200, b = 0, a = 255}, + side_window = {r = 0, g = 0, b = 0, a = 150}, + side_window_text = {r = 255, g = 255, b = 255, a = 220} + } + + stuff.path.cheesemenu = stuff.path.scripts.."cheesemenu\\" + for k, v in pairs(utils.get_all_sub_directories_in_directory(stuff.path.cheesemenu)) do + stuff.path[v] = stuff.path.cheesemenu..v.."\\" + end + + stuff.menuData.background_sprite.fit_size_to_width = function(self) + self.size = stuff.menuData.width*graphics.get_screen_width()/scriptdraw.get_sprite_size(func.load_sprite(stuff.path.background..(self.sprite or ""), stuff.menuData.background_sprite.loaded_sprites)).x + end + stuff.menuData.background_sprite.fit_size_to_height = function(self) + self.size = stuff.menuData.height*graphics.get_screen_height()/scriptdraw.get_sprite_size(func.load_sprite(stuff.path.background..(self.sprite or ""), stuff.menuData.background_sprite.loaded_sprites)).y + end + + stuff.image_ext = {"gif", "bmp", "jpg", "jpeg", "png", "2t1", "dds"} + stuff.menuData.files.headers = {} + for _, ext in pairs(stuff.image_ext) do + for _, image in pairs(utils.get_all_files_in_directory(stuff.path.header, ext)) do + stuff.menuData.files.headers[#stuff.menuData.files.headers + 1] = image + end + end + for k, v in pairs(utils.get_all_sub_directories_in_directory(stuff.path.header)) do + stuff.menuData.files.headers[#stuff.menuData.files.headers + 1] = v..".ogif" + end + + stuff.menuData.files.ui = {} + for k, v in pairs(utils.get_all_files_in_directory(stuff.path.ui, "lua")) do + stuff.menuData.files.ui[k] = v:sub(1, #v - 4) + end + + stuff.menuData.files.background = {} + for _, ext in pairs(stuff.image_ext) do + for k, v in pairs(utils.get_all_files_in_directory(stuff.path.background, "png")) do + stuff.menuData.files.background[k] = v + end + end + + stuff.menuData_methods = { + set_color = function(self, colorName, r, g, b, a) + assert(self[colorName], "field "..colorName.." does not exist") + local colors = {r = r or false, g = g or false, b = b or false, a = a or false} + for k, v in pairs(colors) do + if not v then + if type(self[colorName]) == "table" then + colors[k] = self[colorName][k] + else + colors[k] = func.convert_int_to_rgba(self[colorName], k) + end + end + end + for k, v in pairs(colors) do + assert(v <= 255 and v >= 0, "attempted to set invalid "..k.." value to field "..colorName) + end + if type(self[colorName]) == "table" then + self[colorName] = colors + else + self[colorName] = (colors.a << 24) + (colors.b << 16) + (colors.g << 8) + colors.r + end + end + } + function func.convert_rgba_to_int(r, g, b, a) + if type(r) == "table" then + local colorTable = r + r = colorTable.r or colorTable[1] + g = colorTable.g or colorTable[2] + b = colorTable.b or colorTable[3] + a = colorTable.a or colorTable[4] + end + if not a then + a = 255 + end + assert(r and g and b, "one or more of the r, g, b values is invalid") + assert((a <= 255 and a >= 0) and (b <= 255 and b >= 0) and (g <= 255 and g >= 0) and (r <= 255 and r >= 0), "rgba values cannot be more than 255 or less than 0") + return (a << 24) + (b << 16) + (g << 8) + r + end + + stuff.conversionValues = {a = 24, b = 16, g = 8, r = 0} + function func.convert_int_to_rgba(...) + local int, val1, val2, val3, val4 = ... + local values = {val1, val2, val3, val4} + + for k, v in pairs(values) do + values[k] = int >> stuff.conversionValues[v] & 0xff + end + return table.unpack(values) + end + setmetatable(stuff.menuData.color, {__index = stuff.menuData_methods}) + + function func.convert_int_ip(ip) + local ipTable = {} + ipTable[1] = ip >> 24 & 255 + ipTable[2] = ip >> 16 & 255 + ipTable[3] = ip >> 8 & 255 + ipTable[4] = ip & 255 + + return table.concat(ipTable, ".") + end + + stuff.input = require("cheesemenu.libs.Get Input") + local gltw = require("cheesemenu.libs.GLTW") + local cheeseUtils = require("cheesemenu.libs.CheeseUtilities") + assert(gltw, "GLTW library is not found, please install the menu with 'cheesemenu' folder.") + + + gltw.read("controls", stuff.path.cheesemenu, stuff.controls, false, true) + for k, v in pairs(stuff.controls) do + stuff.vkcontrols[k] = stuff.char_codes[v] + end + + gltw.read("hotkey notifications", stuff.path.hotkeys, stuff.hotkey_notifications, false, true) + stuff.hotkeys = gltw.read("hotkeys", stuff.path.hotkeys, nil, false, true) or {} + stuff.hierarchy_key_to_hotkey = {} + for k, v in pairs(stuff.hotkeys) do + stuff.hotkey_cooldowns[k] = 0 + + local string_to_vk = {} + for char in k:gmatch("%|*([^%|]+)%|*") do + string_to_vk[#string_to_vk+1] = stuff.char_codes[char] + end + stuff.hotkeys_to_vk[k] = string_to_vk + + if type(v) == "table" then + for i, e in pairs(v) do + stuff.hierarchy_key_to_hotkey[i] = k + end + end + end + + --local originalGetInput = input.get + if stuff.input then + function input.get(title, default, len, Type) + local originalmenuToggle = stuff.menuData.menuToggle + stuff.menuData.menuToggle = false + stuff.menuData.chatBoxOpen = true + local status, gottenInput = stuff.input.get_input(title, default, len, Type) + + func.toggle_menu(originalmenuToggle) + stuff.menuData.chatBoxOpen = false + return status, gottenInput + end + end + + -- Credit to kektram for these functions + do + local _ENV = { + getmetatable = debug.getmetatable + } + function stuff.rawset(Table, index, value) -- Matches performance of normal rawset. + local metatable = getmetatable(Table) + local __newindex + if metatable then + __newindex = metatable.__newindex + metatable.__newindex = nil + end + Table[index] = value + if __newindex then + metatable.__newindex = __newindex + end + return Table + end + end + do + local _ENV = { + getmetatable = debug.getmetatable + } + function stuff.rawget(Table, index, value) -- Matches performance of normal rawget. + local metatable = getmetatable(Table) + local __index + if metatable then + __index = metatable.__index + metatable.__index = nil + end + local value = Table[index] + if __index then + metatable.__index = __index + end + return value + end + end + -- + + stuff.playerSpecialValues = {value = true, min = true, max = true, mod = true, on = true, real_value = true, real_max = true, real_min = true, real_mod = true, real_on = true} + + stuff.featMetaTable = { + __index = function(t, k) + if k == "is_highlighted" then + return t == currentMenu[stuff.scroll + stuff.scrollHiddenOffset] + elseif k == "parent" then + return t.type >> 15 & 1 == 0 and func.get_feature(t.parent_id) or func.get_player_feature(t.parent_id) + elseif k == "value" or k == "min" or k == "mod" or k == "max" or k == "str_data" or k == "type" or k == "id" or k == "on" or k == "hidden" or k == "data" then + if t.playerFeat and k ~= "str_data" and k ~= "type" and k ~= "id" and k ~= "hidden" and k ~= "data" then + return stuff.rawget(t, "table_"..k) + else + return stuff.rawget(t, "real_"..k) + end + elseif k == "children" and t.type >> 11 & 1 ~= 0 then + return t:get_children() + elseif k == "hint" then + return stuff.feature_hints[t.id].str + --[[ else + return stuff.rawget(t, k) ]] + end + end, + + __newindex = function(t, k, v) + assert(k ~= "id" and k ~= "children" and k ~= "type" and k ~= "str_data" and k ~= "is_highlighted", "'"..k.."' is read only") + if k == "on" and type(v) == "boolean" then + if t.real_on == v then + return + end + --[[ if t.type >> 11 & 1 ~= 0 and t.real_on ~= nil then + func.check_scroll(t.index, (t.parent_id > 0 and t.parent or features), not v) + end ]] + stuff.rawset(t, "real_on", v) + + if t.feats then + for pid, feat in pairs(t.feats) do + if player.is_player_valid(pid) then + feat.on = v + --[[ if feat.type >> 11 & 1 ~= 0 then + func.check_scroll(feat.index, (feat.parent_id > 0 and stuff.feature_by_id[feat.ps_parent_id] or stuff.PlayerParent), not v) + end ]] + end + end + else + if v then + t:activate_feat_func() + end + end + elseif k == "value" or k == "min" or k == "mod" or k == "max" then + if k ~= "value" and t.type >> 5 & 1 ~= 0 then -- value_str + error("max, min and mod are readonly for value_str features") + end + v = tonumber(v) + + assert(t.type >> 1 & 1 ~= 0, "feat type not supported: "..t.type) -- value_[if], value_str + assert(v, "tried to set "..k.." property to a non-number value") + + if t.type >> 5 & 1 ~= 0 then -- value_str + if v < 0 then + v = 0 + elseif t.real_str_data then + if v+1 > #t.real_str_data and #t.real_str_data ~= 0 then + v = #t.real_str_data-1 + end + end + end + + if t.type >> 1 & 1 ~= 0 then + if t.type >> 3 & 1 ~= 0 or t.type >> 5 & 1 ~= 0 then -- value_str + v = math.floor(v) + end + + stuff.rawset(t, "real_"..k, v) + if t.type & 140 ~= 0 then -- i|f|slider + if not t.real_max then + t.real_max = 0 + end + if not t.real_min then + t.real_min = 0 + end + if not t.real_mod then + t.real_mod = 1 + end + if not t.real_value then + t.real_value = 0 + end + + stuff.rawset(t, "real_value", t.real_value >= t.real_max and t.real_max or t.real_value <= t.real_min and t.real_min or t.real_value) + end + + if t["table_"..k] then + local is_num = t.type & 140 ~= 0 + for i = 0, 31 do + t["table_"..k][i] = v + if is_num then + t["table_value"][i] = t["table_value"][i] >= t["table_max"][i] and t["table_max"][i] or t["table_value"][i] <= t["table_min"][i] and t["table_min"][i] or t["table_value"][i] + end + end + end + end + elseif k == "hidden" then + assert(type(v) == "boolean", "hidden only accepts booleans") + if t.real_hidden == v then + return + end + + --[[ if t.real_hidden ~= nil then + func.check_scroll(t.index, (t.parent_id > 0 and t.parent or features), v) + end ]] + + t.real_hidden = v + if t.feats then + for _, feat in ipairs(t.feats) do + feat.hidden = v + end + end + if v then + func.deleted_or_hidden_parent_check(t) + end + elseif k == "data" then + stuff.rawset(t, "real_data", v) + if t.feats then + for i, e in pairs(t.feats) do + t.feats[i].real_data = v + end + end + elseif k == "hint" then + assert(type(v) == "string", "Feat.hint only supports strings") + if not v then + stuff.feature_hints[t.id] = nil + return + end + local str = cheeseUtils.wrap_text(v, stuff.menuData.fonts.hint, stuff.menuData.text_size * stuff.menuData.hint_size_modifier, stuff.menuData.width*2-scriptdraw.size_pixel_to_rel_x(25)) + stuff.feature_hints[t.id] = {str = str, size = scriptdraw.get_text_size(str, 1, stuff.menuData.fonts.hint), original = v} + else + stuff.rawset(t, k, v) + end + end + } + + stuff.playerfeatMetaTable = { + __index = function(t, k) + if k == "is_highlighted" then + return t == currentMenu[stuff.scroll + stuff.scrollHiddenOffset] + elseif k == "parent" then + return func.get_player_feature(t.parent_id) + elseif k == "str_data" or k == "type" or k == "id" or k == "data" or k == "hidden" then + return stuff.rawget(t, "real_"..k) + elseif stuff.playerSpecialValues[k] then + if t["table_"..k:gsub("real_", "")] then + return t["table_"..k:gsub("real_", "")][t.pid] + end + elseif k == "children" and t.type >> 11 & 1 ~= 0 then + return t:get_children() + else + return stuff.rawget(t, k) + end + end, + + __newindex = function(t, k, v) + assert(k ~= "id" and k ~= "children" and k ~= "type" and k ~= "str_data" and k ~= "is_highlighted", "'"..k.."' is read only") + if (k == "on" or k == "real_on") and type(v) == "boolean" then + t["table_on"][t.pid] = v + if v then + t:activate_feat_func() + end + elseif stuff.playerSpecialValues[k] then + k = k:gsub("real_", "") + if k ~= "value" and t.type >> 5 & 1 ~= 0 then + error("max, min and mod are readonly for value_str features") + end + v = tonumber(v) + + assert(t.type >> 1 & 1 ~= 0, "feat type not supported") + assert(v, "tried to set "..k.." property to a non-number value") + + if t.type >> 5 & 1 ~= 0 then + if v < 0 then + v = 0 + elseif t.real_str_data then + if v+1 > #t.real_str_data and #t.real_str_data ~= 0 then + v = #t.real_str_data-1 + end + end + end + + if t.type >> 1 & 1 ~= 0 then + if t.type >> 3 & 1 ~= 0 or t.type >> 5 & 1 ~= 0 then -- value_i|str + v = math.floor(v) + end + + t["table_"..k][t.pid] = v + if t.type & 140 ~= 0 then -- i|f|slider + if not t.real_max then + t.real_max = 0 + end + if not t.real_min then + t.real_min = 0 + end + if not t.real_mod then + t.real_mod = 1 + end + if not t.real_value then + t.real_value = 0 + end + + t["table_value"][t.pid] = t["table_value"][t.pid] >= t["table_max"][t.pid] and t["table_max"][t.pid] or t["table_value"][t.pid] <= t["table_min"][t.pid] and t["table_min"][t.pid] or t["table_value"][t.pid] + end + end + elseif k == "data" then + t.real_data = v + else + stuff.rawset(t, k, v) + end + end + } + + -- featMethods + + -- dogshit dont use + --[[ stuff.set_val = function(self, valueType, val, dont_set_all) + assert(stuff.type_id.id_to_name[self.type]:match("value_[if]") or stuff.type_id.id_to_name[self.type]:match("value_str"), "feat type not supported") + assert(tonumber(val), "tried to set "..valueType.." to a non-number value") + if stuff.type_id.id_to_name[self.type]:match("value_i") then + val = tonumber(math.floor(val)) + else + val = tonumber(val) + end + + if valueType == "value" then + if self.real_min then + if val < self.real_min then + val = self.real_min + end + else + if val < 0 then + val = 0 + end + end + if self.real_max then + if val > self.real_max then + val = self.real_max + end + elseif self.real_str_data then + if val+1 > #self.real_str_data then + val = #self.real_str_data-1 + end + end + end + + self[valueType] = val + if self["table_"..valueType] and not dont_set_all then + for i = 0, 31 do + self["table_"..valueType][i] = val + end + end + end + + stuff.set_value = function(self, val, dont_set_all) + stuff.set_val(self, "value", val, dont_set_all) + end + stuff.set_max = function(self, val, dont_set_all) + stuff.set_val(self, "max", val, dont_set_all) + end + stuff.set_min = function(self, val, dont_set_all) + stuff.set_val(self, "min", val, dont_set_all) + end + stuff.set_mod = function(self, val, dont_set_all) + stuff.set_val(self, "mod", val, dont_set_all) + end ]] + + stuff.get_str_data = function(self) + assert(self.type >> 5 & 1 ~= 0, "used get_str_data on a feature that isn't value_str") + return self.str_data + end + + stuff.set_str_data = function(self, stringTable) + assert(type(stringTable) == "table", "tried to set str_data property to a non-table value") + local numberedTable + for k, v in pairs(stringTable) do + if type(k) ~= "number" then + numberedTable = {} + for k, v in pairs(stringTable) do + numberedTable[#numberedTable + 1] = v + end + break + end + end + self.real_str_data = numberedTable or stringTable + if self.real_value+1 > #self.real_str_data then + self.real_value = #self.real_str_data-1 >= 0 and #self.real_str_data-1 or 0 + end + if self.feats then + for k, v in pairs(self.table_value) do + if v+1 > #self.real_str_data then + self.table_value[k] = #self.real_str_data-1 + end + end + for k, v in pairs(self.feats) do + v.real_str_data = stringTable + end + end + end + + stuff.toggle = function(self, bool) + if self.type & 1 ~= 0 then + if bool ~= nil then + self.real_on = bool + self:activate_feat_func() + else + self.real_on = not self.real_on + self:activate_feat_func() + end + else + self:activate_feat_func() + end + end + + stuff.get_children = function(self) + local children = {} + for k, v in ipairs(self) do + if type(k) == "number" then + children[k] = v + end + end + return children + end + + -- function callback ~Thanks to Proddy for telling me that doing function() every time creates a new one and providing examples on how to use menu.create_thread with the function below + function stuff.feature_callback(self) + local pidordata = self.pid or self.data + if self.on ~= nil and self.type & 2049 == 0 then -- not toggle or parent + self.on = true + end + local continue = self:func(pidordata, self.data) + while continue == HANDLER_CONTINUE do + system.wait(0) + continue = self:func(pidordata, self.data) + end + if self.on ~= nil and self.type & 2049 == 0 then -- not toggle or parent + self.on = false + end + end + + function stuff.highlight_callback(self) + local pidordata = self.pid or self.data + self:hl_func(pidordata, self.data) + end + + stuff.activate_feat_func = function(self) + if not (self.thread) then + self.thread = 0 + end + if self.func and menu.has_thread_finished(self.thread) then + self.thread = menu.create_thread(stuff.feature_callback, self) + end + end + + stuff.activate_hl_func = function(self) + if self.hl_func then + if not self.hl_thread then + self.hl_thread = 0 + end + if menu.has_thread_finished(self.hl_thread) then + self.hl_thread = menu.create_thread(stuff.highlight_callback, self) + end + end + end + + stuff.select = function(self) + local parent_of_feat_wanted = stuff.feature_by_id[self.parent_id] or features + + if not (parent_of_feat_wanted == currentMenu) then + stuff.previousMenus[#stuff.previousMenus + 1] = {menu = currentMenu, scroll = stuff.scroll, drawScroll = stuff.drawScroll, scrollHiddenOffset = stuff.scrollHiddenOffset} + currentMenu = parent_of_feat_wanted + end + + if not self.hidden then + local hiddenOffset = 0 + for k, v in ipairs(parent_of_feat_wanted) do + if type(k) == "number" then + if v.hidden and not (k > self.index) then + hiddenOffset = hiddenOffset + 1 + end + end + end + stuff.scroll = self.index - hiddenOffset + stuff.drawScroll = (stuff.maxDrawScroll >= self.index) and self.index-1 or stuff.maxDrawScroll + end + + stuff.scrollHiddenOffset = 0 + end + -- + + stuff.hotkey_feature_hierarchy_keys = {} + + stuff.type_id = { + name_to_id = { + toggle = 1 << 0, + slider = 1 << 2 | 1 << 1 | 1 << 0, + value_i = 1 << 3 | 1 << 1 | 1 << 0, + value_str = 1 << 5 | 1 << 1 | 1 << 0, + value_f = 1 << 7 | 1 << 1 | 1 << 0, + action = 1 << 9, + action_slider = 1 << 9 | 1 << 2 | 1 << 1, + action_value_i = 1 << 9 | 1 << 3 | 1 << 1, + action_value_str = 1 << 9 | 1 << 5 | 1 << 1, + action_value_f = 1 << 9 | 1 << 7 | 1 << 1, + autoaction_slider = 1 << 10 | 1 << 2 | 1 << 1, + autoaction_value_i = 1 << 10 | 1 << 3 | 1 << 1, + autoaction_value_str = 1 << 10 | 1 << 5 | 1 << 1, + autoaction_value_f = 1 << 10 | 1 << 7 | 1 << 1, + parent = 1 << 11 + }, + } + + --Functions + function func.add_feature(nameOfFeat, TypeOfFeat, parentOfFeat, functionCallback, highlightCallback, playerFeat) + assert((type(nameOfFeat) == "string"), "invalid name in add_feature") + assert((type(TypeOfFeat) == "string") and stuff.type_id.name_to_id[TypeOfFeat], "invalid type in add_feature") + assert((type(parentOfFeat) == "number") or not parentOfFeat, "invalid parent id in add_feature") + assert((type(functionCallback) == "function") or not functionCallback, "invalid function in add_feature") + playerFeat = playerFeat or false + parentOfFeat = parentOfFeat or 0 + --TypeOfFeat = TypeOfFeat:gsub("slider", "value_f") + local currentParent = playerFeat and features["OnlinePlayers"] or features + + local hierarchy_key + if parentOfFeat ~= 0 and parentOfFeat then + currentParent = playerFeat and stuff.player_feature_by_id[parentOfFeat] or stuff.feature_by_id[parentOfFeat] + if currentParent then + assert(currentParent.type >> 11 & 1 ~= 0, "parent is not a parent feature") + assert(currentParent.type >> 15 & 1 ~= 0 == playerFeat, "parent is not valid "..((currentParent.type >> 15 & 1 ~= 0 and not playerFeat) and "using player feature as parent for a local feature" or (currentParent.type >> 15 & 1 == 0 and playerFeat and "using local parent for player feature") or "unknown")) + else + error("parent does not exist") + end + end + if currentParent.hierarchy_key then + hierarchy_key = currentParent.hierarchy_key.."."..nameOfFeat:gsub("[ %.]", "_") + else + hierarchy_key = nameOfFeat:gsub("[ %.]", "_") + end + + currentParent[#currentParent + 1] = {name = nameOfFeat, real_type = stuff.type_id.name_to_id[TypeOfFeat] | (playerFeat and 1 << 15 or 0), real_id = 0, --[[parent = {id = currentParent.id or 0},]] parent_id = currentParent.id or 0, playerFeat = playerFeat, index = #currentParent + 1} + local feat = currentParent[#currentParent] + feat.activate_feat_func = stuff.activate_feat_func + feat.activate_hl_func = stuff.activate_hl_func + feat.set_str_data = stuff.set_str_data + feat.toggle = stuff.toggle + feat.get_children = stuff.get_children + feat.get_str_data = stuff.get_str_data + feat.select = stuff.select + setmetatable(feat, stuff.featMetaTable) + feat.thread = 0 + --if feat.real_type & 1 ~= 0 or feat.real_type >> 9 & 1 ~= 0 then -- toggle + if playerFeat then + feat.table_on = {} + for i = 0, 31 do + feat.table_on[i] = feat.type >> 11 & 1 ~= 0 + end + end + feat.on = feat.type >> 11 & 1 ~= 0 + --end + if feat.real_type >> 5 & 1 ~= 0 then -- value_str + feat.real_str_data = {} + if playerFeat then + feat.table_value = {} + for i = 0, 31 do + feat.table_value[i] = 0 + end + end + feat.value = 0 + elseif feat.real_type >> 1 & 1 ~= 0 then --value any + if playerFeat then + feat.table_max = {} + feat.table_min = {} + feat.table_mod = {} + feat.table_value = {} + for i = 0, 31 do + feat.table_max[i] = 0 + feat.table_min[i] = 0 + feat.table_mod[i] = 1 + feat.table_value[i] = 0 + end + end + feat.max = 0 + feat.min = 0 + feat.mod = 1 + feat.value = 0 + end + feat.hidden = false + feat["func"] = functionCallback + feat["hl_func"] = highlightCallback + if TypeOfFeat == "parent" then + feat.child_count = 0 + end + currentParent.child_count = 0 + for k, v in pairs(currentParent) do + if type(k) == "number" then + currentParent.child_count = currentParent.child_count + 1 + end + end + feat.hotkey = stuff.hierarchy_key_to_hotkey[hierarchy_key] + feat.hierarchy_key = hierarchy_key + if stuff.hotkey_feature_hierarchy_keys[hierarchy_key] then + stuff.hotkey_feature_hierarchy_keys[hierarchy_key][#stuff.hotkey_feature_hierarchy_keys[hierarchy_key] + 1] = feat + else + stuff.hotkey_feature_hierarchy_keys[hierarchy_key] = {feat} + end + if playerFeat then + stuff.player_feature_by_id[#stuff.player_feature_by_id+1] = feat + feat.real_id = #stuff.player_feature_by_id + else + stuff.feature_by_id[#stuff.feature_by_id+1] = feat + feat.real_id = #stuff.feature_by_id + end + return feat + end + + --player feature functions + + -- if you set a toggle player feature to on it'll enable for any valid players/joining players but if a player leaves functions like player.get_player_name will return nil before the feature is turned off + function func.add_player_feature(nameOfFeat, TypeOfFeat, parentOfFeat, functionCallback, highlightCallback) + parentOfFeat = parentOfFeat or 0 + assert(stuff.PlayerParent, "you need to use set_player_feat_parent before adding player features") + local pfeat = func.add_feature(nameOfFeat, TypeOfFeat, parentOfFeat, functionCallback, highlightCallback, true) + pfeat.feats = {} + + if parentOfFeat == 0 then + for k = 0, 31 do + stuff.playerIds[k][#stuff.playerIds[k]+1] = {} + local currentFeat = stuff.playerIds[k][#stuff.playerIds[k]] + func.add_to_table(pfeat, currentFeat, k, nil, true) + stuff.feature_by_id[#stuff.feature_by_id+1] = currentFeat + currentFeat.ps_id = #stuff.feature_by_id + currentFeat.ps_parent_id = stuff.playerIds[k].id + currentFeat.pid = k + pfeat.feats[k] = currentFeat + end + else + local playerParent = stuff.player_feature_by_id[parentOfFeat] + if playerParent then + for k = 0, 31 do + playerParent.feats[k][#playerParent.feats[k]+1] = {} + local currentFeat = playerParent.feats[k][#playerParent.feats[k]] + + func.add_to_table(pfeat, currentFeat, k, nil, true) + stuff.feature_by_id[#stuff.feature_by_id+1] = currentFeat + currentFeat.ps_id = #stuff.feature_by_id + currentFeat.ps_parent_id = playerParent.feats[k].ps_id + currentFeat.pid = k + pfeat.feats[k] = currentFeat + end + end + end + + return pfeat + end + + function func.add_to_table(getTable, addToTable, playerid, override, setmeta) + local isPlayerFeatValues + for k, v in pairs(getTable) do + if tostring(k):match("table_") or stuff.playerSpecialValues[k] then + isPlayerFeatValues = true + elseif type(v) == "table" then + if type(addToTable[k]) ~= "table" then + addToTable[k] = {} + end + if addToTable[k].real_on then + addToTable[k].real_on = false + end + if (v.type or 0) >> 11 & 1 ~= 0 then + func.add_to_table(getTable[k], addToTable[k], playerid, override) + else + for i, e in pairs(getTable[k]) do + if type(e) ~= "table" then + if not addToTable[k][i] or override then + addToTable[k][i] = e + end + end + end + end + setmetatable(addToTable[k], stuff.playerfeatMetaTable) + if v.name then + if not getTable[k].feats then + getTable[k].feats = {} + end + getTable[k].feats[playerid] = addToTable[k] + end + else + if not addToTable[k] or override then + addToTable[k] = v + end + end + end + if setmeta or isPlayerFeatValues then + addToTable.table_value = getTable.table_value + addToTable.table_min = getTable.table_min + addToTable.table_max = getTable.table_max + addToTable.table_mod = getTable.table_mod + addToTable.table_on = getTable.table_on + for i, e in pairs(stuff.playerSpecialValues) do + if addToTable[i] then + stuff.rawset(addToTable, i, nil) + end + end + setmetatable(addToTable, stuff.playerfeatMetaTable) + end + end + + function func.set_player_feat_parent(nameOfFeat, parentOfFeat, functionToDo) + stuff.PlayerParent = func.add_feature(nameOfFeat, "parent", parentOfFeat, functionToDo) + local hierarchy_pattern = stuff.PlayerParent.hierarchy_key..".player_" + + stuff.playerIds = {} + for i = 0, 31 do + stuff.playerIds[i] = func.add_feature(tostring(player.get_player_name(i)), "parent", stuff.PlayerParent.id) + stuff.playerIds[i].pid = i + stuff.playerIds[i].hidden = not player.is_player_valid(i) + stuff.playerIds[i].hierarchy_key = hierarchy_pattern..i + stuff.playerIds[i].real_type = 1 << 15 | stuff.playerIds[i].type + end + + event.add_event_listener("player_join", function(listener) + system.wait(100) + stuff.playerIds[listener.player].hidden = false + stuff.playerIds[listener.player].name = player.get_player_name(listener.player) + func.reset_player_submenu(listener.player) + table.sort(stuff.PlayerParent, stuff.table_sort_functions[stuff.player_submenu_sort]) + end) + event.add_event_listener("player_leave", function(listener) + func.reset_player_submenu(listener.player) + if not player.is_player_valid(listener.player) then + stuff.playerIds[listener.player].hidden = true + stuff.playerIds[listener.player].name = "nil" + end + table.sort(stuff.PlayerParent, stuff.table_sort_functions[stuff.player_submenu_sort]) + end) + + return stuff.PlayerParent + end + + function func.reset_player_submenu(pid, currentParent) + local currentParent = currentParent or features.OnlinePlayers + for k, v in pairs(currentParent) do + if type(v) == "table" then + local feat_type = v.type + if feat_type then + if feat_type >> 1 & 1 ~= 0 then -- toggle + v.table_value[pid] = v.real_value + if feat_type & 136 ~= 0 then -- value if + v.table_min[pid] = v.real_min + v.table_max[pid] = v.real_max + v.table_mod[pid] = v.real_mod + end + end + if feat_type & 1 ~= 0 then -- toggle + if player.is_player_valid(pid) then + v.feats[pid].on = v.real_on + else + v.feats[pid].on = false + v.table_on[pid] = false + end + end + if feat_type >> 11 & 1 ~= 0 then -- parent + func.reset_player_submenu(pid, v) + end + end + end + end + end + --end of player feature functions + + function func.check_scroll(index, parent, bool) + if index <= stuff.scroll + stuff.scrollHiddenOffset and currentMenu == parent then + if bool then + --stuff.scroll = stuff.scroll - 1 + --stuff.scroll = stuff.scroll > 0 and stuff.scroll or 0 + if #currentMenu - stuff.drawHiddenOffset > 1 and stuff.scroll - 1 > 0 then + stuff.scroll = stuff.scroll - 1 + if stuff.scroll - stuff.drawScroll <= 2 and stuff.drawScroll > 0 then + stuff.drawScroll = stuff.drawScroll - 1 + end + end + else + if #currentMenu - stuff.drawHiddenOffset > 1 then + stuff.scroll = stuff.scroll + 1 + if stuff.scroll - stuff.drawScroll >= (stuff.menuData.max_features - 1) and stuff.drawScroll < stuff.maxDrawScroll then + stuff.drawScroll = stuff.drawScroll + 1 + end + end + --stuff.scroll = stuff.scroll + 1 + end + end + end + + function func.deleted_or_hidden_parent_check(parent, check_hidden_only) + if next(stuff.previousMenus) then + local parentBeforeDHparent = false + if parent ~= currentMenu then + for k, v in ipairs(stuff.previousMenus) do + if parentBeforeDHparent then + stuff.previousMenus[k] = nil + else + if (v.menu == parent and not check_hidden_only) or (v.menu.hidden and check_hidden_only) then + parentBeforeDHparent = true + currentMenu = stuff.previousMenus[k-1].menu + stuff.scroll = stuff.previousMenus[k-1].scroll + stuff.drawScroll = stuff.previousMenus[k-1].drawScroll + stuff.scrollHiddenOffset = stuff.previousMenus[k-1].scrollHiddenOffset + stuff.previousMenus[k-1] = nil + stuff.previousMenus[k] = nil + end + end + end + elseif not check_hidden_only then + currentMenu = stuff.previousMenus[#stuff.previousMenus].menu + stuff.scroll = stuff.previousMenus[#stuff.previousMenus].scroll + stuff.drawScroll = stuff.previousMenus[#stuff.previousMenus].drawScroll + stuff.scrollHiddenOffset = stuff.previousMenus[#stuff.previousMenus].scrollHiddenOffset + stuff.previousMenus[#stuff.previousMenus] = nil + end + end + end + + function func.get_feature_by_hierarchy_key(hierarchy_key) + local feat = stuff.hotkey_feature_hierarchy_keys[hierarchy_key] + if feat then + if feat[2] and not feat.name then + return feat, true + else + return feat[1] + end + end + end + + function func.get_feature(id) + assert(type(id) == "number" and id ~= 0, "invalid id in get_feature") + return stuff.feature_by_id[id] + end + + function func.delete_feature(id, bool_ps) + if type(id) == "table" then + id = id.id + end + + local feat = stuff.feature_by_id[id] + if not feat then + return false + end + + if stuff.old_selected == stuff.feature_by_id[id] then + stuff.old_selected = nil + end + stuff.feature_by_id[id] = nil + + if feat.thread then + if not menu.has_thread_finished(feat.thread) then + menu.delete_thread(feat.thread) + end + end + if feat.hl_thread then + if not menu.has_thread_finished(feat.hl_thread) then + menu.delete_thread(feat.hl_thread) + end + end + + local parent + if feat.parent_id ~= 0 or bool_ps then + parent = bool_ps and stuff.feature_by_id[feat.ps_parent_id] or stuff.feature_by_id[feat.parent_id] + else + parent = features + end + + if feat.type >> 11 & 1 ~= 0 then + func.deleted_or_hidden_parent_check(feat) + end + + local index = feat.index + table.remove(parent, tonumber(feat.index)) + + --func.check_scroll(index, parent, true) + + for i = index, #parent do + parent[i].index = i + end + + return true + end + + function func.delete_player_feature(id) + if type(id) == "table" then + id = id.id + end + + + local feat = stuff.player_feature_by_id[id] + if not feat then + return false + end + + stuff.player_feature_by_id[id] = nil + + local parent + if feat.parent_id ~= 0 then + parent = stuff.player_feature_by_id[feat.parent_id] + else + parent = features["OnlinePlayers"] + end + + for k, v in pairs(feat.feats) do + func.delete_feature(v.ps_id, true) + end + + local index = feat.index + table.remove(parent, tonumber(index)) + for i = index, #parent do + parent[i].index = i + for pid = 0, 31 do + parent[i].feats[pid].index = i + end + end + end + + function func.get_player_feature(id) + assert(type(id) == "number" and id ~= 0, "invalid id in get_player_feature") + return stuff.player_feature_by_id[id] + end + + function func.do_key(time, key, doLoopedFunction, functionToDo) + if cheeseUtils.get_key(key):is_down() then + functionToDo() + local timer = utils.time_ms() + time + while timer > utils.time_ms() and cheeseUtils.get_key(key):is_down() do + system.wait(0) + end + while timer < utils.time_ms() and cheeseUtils.get_key(key):is_down() do + if doLoopedFunction then + functionToDo() + end + local timer = utils.time_ms() + 50 + while timer > utils.time_ms() do + system.wait(0) + end + end + end + end + + stuff.header_ids = {} + function func.load_sprite(path_to_file, id_table) + --path = path or stuff.path.header + id_table = id_table or stuff.header_ids + path_to_file = tostring(path_to_file) + assert(path_to_file, "invalid name") + + --name = name:gsub("%.[a-z]+$", "") + + if not id_table[path_to_file] then + if utils.dir_exists(path_to_file:gsub("%.ogif", "")) and path_to_file:find("%.ogif") then + local path = path_to_file:gsub("%.ogif", "").."\\" + local images + + for _, v in pairs(stuff.image_ext) do + images = utils.get_all_files_in_directory(path, v) + if images[1] then break end + end + if not images[1] then + menu.notify("No frames found.", "Cheese Menu", 5, 0x0000FF) + return + end + + id_table[path_to_file] = {} + for i, e in pairs(images) do + id_table[path_to_file][i] = {} + id_table[path_to_file][i].sprite = scriptdraw.register_sprite(path..e) + id_table[path_to_file][i].delay = e:match("%d+_(%d+)") + end + + id_table[path_to_file].constant_delay = utils.get_all_files_in_directory(path, "txt")[1] + if not id_table[path_to_file].constant_delay then + for k, v in pairs(images) do + if not v:match("%d+_(%d+)") then + menu.notify("FPS file not found and frames are not in format, create a txt file with the framerate of the gif.\nExample: '25 fps.txt'", "Cheese Menu", 5, 0x0000FF) + break + end + end + else + id_table[path_to_file].constant_delay = math.floor(1000 / tonumber(id_table[path_to_file].constant_delay:match("(%d*%.*%d+)%s+fps"))) + end + + elseif utils.file_exists(path_to_file) then + id_table[path_to_file] = scriptdraw.register_sprite(path_to_file) + end + end + + return id_table[path_to_file] + end + + function func.toggle_menu(bool) + stuff.menuData.menuToggle = bool + if stuff.menuData.menuToggle then + if currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then + currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() + end + end + end + + function func.selector(feat) + local originalmenuToggle = stuff.menuData.menuToggle + stuff.menuData.menuToggle = false + if feat.str_data then + local index, _ = cheeseUtils.selector(nil, stuff.menuData.selector_speed, feat.real_value + 1, feat.str_data) + if index then + feat.real_value = index - 1 + end + if feat.type >> 10 & 1 ~= 0 then + feat:activate_feat_func() + end + end + func.toggle_menu(originalmenuToggle) + end + + function func.rewrap_hints(font) + local padding = scriptdraw.size_pixel_to_rel_x(25) + for _, hintTable in pairs(stuff.feature_hints) do + hintTable.str = cheeseUtils.wrap_text(hintTable.original, font, stuff.menuData.text_size * stuff.menuData.hint_size_modifier, stuff.menuData.width*2-padding) + hintTable.size = scriptdraw.get_text_size(hintTable.str, 1, font) + end + end + + function func.save_settings() + gltw.write({ + x = stuff.menuData.pos_x, + y = stuff.menuData.pos_y, + side_window = stuff.menuData.side_window, + controls = stuff.controls, + hotkey_notifications = stuff.hotkey_notifications, + player_submenu_sort = stuff.player_submenu_sort, + selector_speed = stuff.menuData.selector_speed + }, "Settings", stuff.path.cheesemenu) + end + + function func.load_settings() + local settings = gltw.read("Settings", stuff.path.cheesemenu, nil, nil, true) + if settings then + stuff.menuData.pos_x = settings.x + stuff.menuData.pos_y = settings.y + stuff.menuData.selector_speed = settings.selector_speed + stuff.player_submenu_sort = settings.player_submenu_sort + + for k, v in pairs(settings.side_window) do + stuff.menuData.side_window[k] = v + end + for k, v in pairs(settings.hotkey_notifications) do + stuff.hotkey_notifications[k] = v + end + for k, v in pairs(settings.controls) do + stuff.controls[k] = v + end + for k, v in pairs(stuff.controls) do + stuff.vkcontrols[k] = stuff.char_codes[v] + end + + menu_configuration_features.menuXfeat.value = math.floor(stuff.menuData.pos_x*graphics.get_screen_width()) + menu_configuration_features.menuYfeat.value = math.floor(stuff.menuData.pos_y*graphics.get_screen_height()) + menu_configuration_features.player_submenu_sort.value = stuff.player_submenu_sort + menu_configuration_features.player_submenu_sort:toggle() + menu_configuration_features.side_window_offsetx.value = math.floor(stuff.menuData.side_window.offset.x*graphics.get_screen_width()) + menu_configuration_features.side_window_offsety.value = math.floor(stuff.menuData.side_window.offset.y*graphics.get_screen_height()) + menu_configuration_features.side_window_spacing.value = math.floor(stuff.menuData.side_window.spacing*graphics.get_screen_height()) + menu_configuration_features.side_window_padding.value = math.floor(stuff.menuData.side_window.padding*graphics.get_screen_width()) + menu_configuration_features.side_window_width.value = math.floor(stuff.menuData.side_window.width*graphics.get_screen_width()) + menu_configuration_features.side_window_on.on = stuff.menuData.side_window.on + menu_configuration_features.selector_speed.value = stuff.menuData.selector_speed + end + end + + function func.save_ui(name) + gltw.write(stuff.menuData, name, stuff.path.ui, {"menuToggle", "menuNav", "loaded_sprites", "files", "pos_x", "pos_y", "side_window", "selector_speed", "chatBoxOpen"}) + end + + function func.load_ui(name) + local uiTable = gltw.read(name, stuff.path.ui, stuff.menuData, true, true) + if not uiTable then + return + end + if menu_configuration_features then + local header, bgSprite = uiTable.header, uiTable.background_sprite and uiTable.background_sprite.sprite or nil + if not header then + menu_configuration_features.headerfeat.value = 0 + menu_configuration_features.headerfeat:toggle() + end + if not bgSprite then + menu_configuration_features.backgroundfeat.value = 0 + menu_configuration_features.backgroundfeat:toggle() + end + + --[[ menu_configuration_features.menuXfeat.value = math.floor(stuff.menuData.pos_x*graphics.get_screen_width()) + menu_configuration_features.menuYfeat.value = math.floor(stuff.menuData.pos_y*graphics.get_screen_height()) ]] + menu_configuration_features.maxfeats.value = math.floor(stuff.menuData.max_features) + menu_configuration_features.menuWidth.value = math.floor(stuff.menuData.width*graphics.get_screen_width()) + menu_configuration_features.featXfeat.value = math.floor(stuff.menuData.feature_scale.x*graphics.get_screen_width()) + menu_configuration_features.featYfeat.value = math.floor(stuff.menuData.feature_scale.y*graphics.get_screen_height()) + menu_configuration_features.feature_offset.value = math.floor(stuff.menuData.feature_offset*graphics.get_screen_height()) + menu_configuration_features.namePadding.value = math.floor(stuff.menuData.padding.name*graphics.get_screen_width()) + menu_configuration_features.parentPadding.value = math.floor(stuff.menuData.padding.parent*graphics.get_screen_width()) + menu_configuration_features.valuePadding.value = math.floor(stuff.menuData.padding.value*graphics.get_screen_width()) + menu_configuration_features.sliderPadding.value = math.floor(stuff.menuData.padding.slider*graphics.get_screen_width()) + menu_configuration_features.sliderWidth.value = math.floor(stuff.menuData.slider.width*graphics.get_screen_width()) + menu_configuration_features.sliderHeight.value = math.floor(stuff.menuData.slider.height*graphics.get_screen_height()) + menu_configuration_features.sliderheightActive.value = math.floor(stuff.menuData.slider.heightActive*graphics.get_screen_height()) + menu_configuration_features.text_size.value = stuff.menuData.text_size_modifier + menu_configuration_features.footer_size.value = stuff.menuData.footer_size_modifier + menu_configuration_features.hint_size.value = stuff.menuData.hint_size_modifier + menu_configuration_features.text_y_offset.value = -math.floor(stuff.menuData.text_y_offset*graphics.get_screen_height()) + stuff.drawFeatParams.textOffset.y = stuff.menuData.text_y_offset + menu_configuration_features.footer_y_offset.value = math.floor(stuff.menuData.footer.footer_y_offset*graphics.get_screen_height()) + menu_configuration_features.border.value = math.floor(stuff.menuData.border*graphics.get_screen_height()) + menu_configuration_features.backgroundsize.value = stuff.menuData.background_sprite.size + menu_configuration_features.backgroundoffsetx.value = math.floor(stuff.menuData.background_sprite.offset.x*graphics.get_screen_width()) + menu_configuration_features.backgroundoffsety.value = math.floor(stuff.menuData.background_sprite.offset.y*graphics.get_screen_height()) + menu_configuration_features.footer_size.value = math.floor(stuff.menuData.footer.footer_size*graphics.get_screen_height()) + menu_configuration_features.footerPadding.value = math.floor(stuff.menuData.footer.padding*graphics.get_screen_width()) + menu_configuration_features.draw_footer.on = stuff.menuData.footer.draw_footer + menu_configuration_features.footer_pos_related_to_background.on = stuff.menuData.footer.footer_pos_related_to_background + --[[ menu_configuration_features.side_window_offsetx.value = math.floor(stuff.menuData.side_window.offset.x*graphics.get_screen_width()) + menu_configuration_features.side_window_offsety.value = math.floor(stuff.menuData.side_window.offset.y*graphics.get_screen_height()) + menu_configuration_features.side_window_spacing.value = math.floor(stuff.menuData.side_window.spacing*graphics.get_screen_height()) + menu_configuration_features.side_window_padding.value = math.floor(stuff.menuData.side_window.padding*graphics.get_screen_width()) + menu_configuration_features.side_window_width.value = math.floor(stuff.menuData.side_window.width*graphics.get_screen_width()) + menu_configuration_features.side_window_on.on = stuff.menuData.side_window.on ]] + menu_configuration_features.text_font.value = stuff.menuData.fonts.text + menu_configuration_features.footer_font.value = stuff.menuData.fonts.footer + menu_configuration_features.hint_font.value = stuff.menuData.fonts.hint + + menu_configuration_features.hint_font:toggle() + + for k, v in pairs(stuff.menuData.color) do + if menu_configuration_features[k] then + if type(v) == "table" then + menu_configuration_features[k].r.value = v.r + menu_configuration_features[k].g.value = v.g + menu_configuration_features[k].b.value = v.b + menu_configuration_features[k].a.value = v.a + else + menu_configuration_features[k].r.value = func.convert_int_to_rgba(v, "r") + menu_configuration_features[k].g.value = func.convert_int_to_rgba(v, "g") + menu_configuration_features[k].b.value = func.convert_int_to_rgba(v, "b") + menu_configuration_features[k].a.value = func.convert_int_to_rgba(v, "a") + end + end + end + + for k, v in pairs(menu_configuration_features.headerfeat.str_data) do + if v == stuff.menuData.header then + menu_configuration_features.headerfeat.value = k - 1 + end + end + + if uiTable.background_sprite then + for k, v in pairs(menu_configuration_features.backgroundfeat.str_data) do + if v == uiTable.background_sprite.sprite then + menu_configuration_features.backgroundfeat.value = k - 1 + end + end + end + end + end + + stuff.drawFeatParams = { + rectPos = v2(stuff.menuData.pos_x, stuff.menuData.pos_y - stuff.menuData.feature_offset/2 + stuff.menuData.border), + textOffset = v2(stuff.menuData.feature_scale.x/2, -0.0055555555), + colorText = stuff.menuData.color.text, + textSize = 0, + } + function func.draw_feat(k, v, offset, hiddenOffset) + --[[ stuff.drawFeatParams.rectPos.x = stuff.menuData.pos_x + stuff.drawFeatParams.rectPos.y = stuff.menuData.pos_y - stuff.menuData.feature_offset/2 + stuff.menuData.border + stuff.drawFeatParams.textOffset.x = stuff.menuData.feature_scale.x/2 + stuff.drawFeatParams.textSize = textSize ]] + stuff.drawFeatParams.colorText = stuff.menuData.color.text + stuff.drawFeatParams.bottomLeft = stuff.menuData.color.feature_bottomLeft + stuff.drawFeatParams.topLeft = stuff.menuData.color.feature_topLeft + stuff.drawFeatParams.topRight = stuff.menuData.color.feature_topRight + stuff.drawFeatParams.bottomRight = stuff.menuData.color.feature_bottomRight + local posY = (stuff.drawFeatParams.rectPos.y + (stuff.menuData.feature_offset * k))*-2+1 + + local is_selected + if stuff.scroll == k + stuff.drawScroll then + stuff.scrollHiddenOffset = hiddenOffset or stuff.scrollHiddenOffset + stuff.drawFeatParams.colorText = stuff.menuData.color.text_selected + stuff.drawFeatParams.bottomLeft = stuff.menuData.color.feature_selected_bottomLeft + stuff.drawFeatParams.topLeft = stuff.menuData.color.feature_selected_topLeft + stuff.drawFeatParams.topRight = stuff.menuData.color.feature_selected_topRight + stuff.drawFeatParams.bottomRight = stuff.menuData.color.feature_selected_bottomRight + is_selected = true + end + if offset == 0 then + local memv2 = cheeseUtils.memoize.v2 + local posX = stuff.drawFeatParams.rectPos.x*2-1 + --[[ scriptdraw.draw_rect( + cheeseUtils.memoize.v2(posX, posY), + cheeseUtils.memoize.v2(stuff.menuData.feature_scale.x*2, stuff.menuData.feature_scale.y*2), + func.convert_rgba_to_int(stuff.drawFeatParams.colorFeature.r, stuff.drawFeatParams.colorFeature.g, stuff.drawFeatParams.colorFeature.b, stuff.drawFeatParams.colorFeature.a) + ) ]] + local Left = posX - stuff.menuData.feature_scale.x + local Right = posX + stuff.menuData.feature_scale.x + local Top = posY + stuff.menuData.feature_scale.y + local Bottom = posY - stuff.menuData.feature_scale.y + scriptdraw.draw_rect_ext( + memv2(Left, Bottom), + memv2(Left, Top), + memv2(Right, Top), + memv2(Right, Bottom), + func.convert_rgba_to_int(stuff.drawFeatParams.bottomLeft.r, stuff.drawFeatParams.bottomLeft.g, stuff.drawFeatParams.bottomLeft.b, stuff.drawFeatParams.bottomLeft.a), + func.convert_rgba_to_int(stuff.drawFeatParams.topLeft.r, stuff.drawFeatParams.topLeft.g, stuff.drawFeatParams.topLeft.b, stuff.drawFeatParams.topLeft.a), + func.convert_rgba_to_int(stuff.drawFeatParams.topRight.r, stuff.drawFeatParams.topRight.g, stuff.drawFeatParams.topRight.b, stuff.drawFeatParams.topRight.a), + func.convert_rgba_to_int(stuff.drawFeatParams.bottomRight.r, stuff.drawFeatParams.bottomRight.g, stuff.drawFeatParams.bottomRight.b, stuff.drawFeatParams.bottomRight.a) + ) + end + + local font = stuff.menuData.fonts.text + if v.type & 1 == 0 then + scriptdraw.draw_text( + v["name"], + cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x - (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.name))*2-1, (stuff.drawFeatParams.rectPos.y + stuff.drawFeatParams.textOffset.y + (stuff.menuData.feature_offset * k))*-2+1), + cheeseUtils.memoize.v2(10, 10), + stuff.drawFeatParams.textSize, + func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a), + 0, font + ) + if v.type >> 11 & 1 ~= 0 then + scriptdraw.draw_text( + ">>", + cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x + (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.parent))*2-1, (stuff.drawFeatParams.rectPos.y + stuff.drawFeatParams.textOffset.y + (stuff.menuData.feature_offset * k))*-2+1), + cheeseUtils.memoize.v2(10, 10), + stuff.drawFeatParams.textSize, + func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a), + 16, font + ) + end + elseif v.type & 1 ~= 0 then -- toggle + cheeseUtils.draw_outline( + cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x - (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.name) + 0.00390625)*2-1, posY), + cheeseUtils.memoize.v2(0.015625, 0.0277777777778), + func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a), + 2 + ) + if v.real_on then + scriptdraw.draw_rect( + cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x - (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.name) + 0.00390625)*2-1, posY), + cheeseUtils.memoize.v2(0.0140625, 0.025), + func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a) + ) + end + + scriptdraw.draw_text( + v.name, + cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x - (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.name) + 0.011328125)*2-1, (stuff.drawFeatParams.rectPos.y + stuff.drawFeatParams.textOffset.y + (stuff.menuData.feature_offset * k))*-2+1), + cheeseUtils.memoize.v2(10, 10), + stuff.drawFeatParams.textSize, + func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a), + 0, font + ) + end + + if v.type >> 1 & 1 ~= 0 then -- value_i_f_str + local rounded_value = v.str_data and v.str_data[v.real_value + 1] or v.real_value + if v.type >> 7 & 1 ~= 0 or v.type >> 2 & 1 ~= 0 then + rounded_value = (rounded_value * 10000) + 0.5 + rounded_value = math.floor(rounded_value) + rounded_value = rounded_value / 10000 + end + if v.type >> 2 & 1 ~= 0 then + cheeseUtils.draw_slider( + cheeseUtils.memoize.v2( + (stuff.drawFeatParams.rectPos.x + stuff.menuData.feature_scale.x/2 - stuff.menuData.slider.width/4 - stuff.menuData.padding.slider)*2-1, + posY + ), + cheeseUtils.memoize.v2(stuff.menuData.slider.width, is_selected and stuff.menuData.slider.heightActive or stuff.menuData.slider.height), + v.min, v.max, v.value, + is_selected and func.convert_rgba_to_int(stuff.menuData.color.slider_selectedBackground) or func.convert_rgba_to_int(stuff.menuData.color.slider_background), + is_selected and func.convert_rgba_to_int(stuff.menuData.color.slider_selectedActive) or func.convert_rgba_to_int(stuff.menuData.color.slider_active), + is_selected and func.convert_rgba_to_int(stuff.menuData.color.slider_text) or 0, + is_selected) + else + local value_str = "< "..tostring(rounded_value).." >" + if v.str_data then + local pixel_size = scriptdraw.get_text_size(value_str, 1, font).x + local screenWidth = graphics.get_screen_width() + if pixel_size/screenWidth > 370/screenWidth then + local original_size = stuff.drawFeatParams.textSize + stuff.drawFeatParams.textSize = stuff.drawFeatParams.textSize * (370 / pixel_size * 0.8) + stuff.drawFeatParams.textSize = math.min(stuff.drawFeatParams.textSize + 0.2, original_size) + end + end + + scriptdraw.draw_text( + value_str, + cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x + (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.value) - scriptdraw.size_pixel_to_rel_x(scriptdraw.get_text_size(value_str, stuff.drawFeatParams.textSize, font).x)/4)*2-1, (stuff.drawFeatParams.rectPos.y + stuff.drawFeatParams.textOffset.y + (stuff.menuData.feature_offset * k))*-2+1), + cheeseUtils.memoize.v2(10, 10), + stuff.drawFeatParams.textSize, + func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a), + 0, font + ) + end + end + end + + stuff.draw_current_menu = {frameCounter = 1, time = utils.time_ms() + 33, currentSprite = stuff.menuData.header} + function func.draw_current_menu() + local sprite = func.load_sprite(stuff.path.header..(stuff.menuData.header or "")) + if stuff.draw_current_menu.currentSprite ~= stuff.menuData.header then + stuff.draw_current_menu.currentSprite = stuff.menuData.header + stuff.draw_current_menu.time = 0 + stuff.draw_current_menu.frameCounter = 1 + if type(sprite) == "table" then + stuff.draw_current_menu.time = utils.time_ms() + (sprite[stuff.draw_current_menu.frameCounter].delay or sprite.constant_delay or 33) + end + end + stuff.drawHiddenOffset = 0 + for k, v in pairs(currentMenu) do + if type(k) == "number" then + if v.hidden or (v.type >> 11 & 1 ~= 0 and not v.on) then + stuff.drawHiddenOffset = stuff.drawHiddenOffset + 1 + end + end + end + local background_sprite_path = stuff.path.background..(stuff.menuData.background_sprite.sprite or "") + if stuff.menuData.background_sprite.sprite and func.load_sprite(background_sprite_path) then + scriptdraw.draw_sprite( + func.load_sprite(background_sprite_path), + cheeseUtils.memoize.v2((stuff.menuData.pos_x + stuff.menuData.background_sprite.offset.x)*2-1, (stuff.menuData.pos_y+stuff.menuData.background_sprite.offset.y+stuff.menuData.height/2+0.01458)*-2+1), + stuff.menuData.background_sprite.size, + 0, + func.convert_rgba_to_int(255, 255, 255, stuff.menuData.color.background.a) + ) + else + scriptdraw.draw_rect( + cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, (stuff.menuData.pos_y+stuff.menuData.border+stuff.menuData.height/2)*-2+1), + cheeseUtils.memoize.v2(stuff.menuData.width*2, stuff.menuData.height*2), + func.convert_rgba_to_int(stuff.menuData.color.background.r, stuff.menuData.color.background.g, stuff.menuData.color.background.b, stuff.menuData.color.background.a) + ) + end + if #currentMenu - stuff.drawHiddenOffset >= stuff.menuData.max_features then + stuff.maxDrawScroll = #currentMenu - stuff.drawHiddenOffset - stuff.menuData.max_features + else + stuff.maxDrawScroll = 0 + end + if stuff.drawScroll > stuff.maxDrawScroll then + stuff.drawScroll = stuff.maxDrawScroll + end + if stuff.scroll > #currentMenu - stuff.drawHiddenOffset then + stuff.scroll = #currentMenu - stuff.drawHiddenOffset + elseif stuff.scroll < 1 and #currentMenu > 0 then + stuff.scroll = 1 + end + + -- header border + scriptdraw.draw_rect(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, (stuff.menuData.pos_y + stuff.menuData.border/2)*-2+1), cheeseUtils.memoize.v2(stuff.menuData.width*2, stuff.menuData.border*2), func.convert_rgba_to_int(stuff.menuData.color.border.r, stuff.menuData.color.border.g, stuff.menuData.color.border.b, stuff.menuData.color.border.a)) + + local hiddenOffset = 0 + local drawnfeats = 0 + stuff.menuData.text_size = (((graphics.get_screen_width()*graphics.get_screen_height())/3686400)*0.45+0.25) -- * stuff.menuData.text_size_modifier + + stuff.drawFeatParams.rectPos.x = stuff.menuData.pos_x + stuff.drawFeatParams.rectPos.y = stuff.menuData.pos_y - stuff.menuData.feature_offset/2 + stuff.menuData.border + stuff.drawFeatParams.textOffset.x = stuff.menuData.feature_scale.x/2 + stuff.drawFeatParams.colorText = stuff.menuData.color.text + stuff.drawFeatParams.colorFeature = stuff.menuData.color.feature + stuff.drawFeatParams.textSize = stuff.menuData.text_size * stuff.menuData.text_size_modifier + + for k, v in ipairs(currentMenu) do + if type(k) == "number" then + if v.hidden or (v.type >> 11 & 1 ~= 0 and not v.on) then + hiddenOffset = hiddenOffset + 1 + elseif k <= stuff.drawScroll + hiddenOffset + stuff.menuData.max_features and k >= stuff.drawScroll + hiddenOffset + 1 then + func.draw_feat(k - stuff.drawScroll - hiddenOffset, v, 0, hiddenOffset) + drawnfeats = drawnfeats + 1 + end + end + end + + if stuff.menuData.footer.draw_footer then + -- footer border + local footer_border_y_pos + if stuff.menuData.footer.footer_pos_related_to_background then + footer_border_y_pos = (stuff.menuData.pos_y + stuff.menuData.height + stuff.menuData.border*1.5)*-2+1 + else + footer_border_y_pos = (stuff.menuData.pos_y + (drawnfeats*stuff.menuData.feature_offset) + stuff.menuData.border*1.5)*-2+1 + end + scriptdraw.draw_rect(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, footer_border_y_pos), cheeseUtils.memoize.v2(stuff.menuData.width*2, stuff.menuData.border*2), func.convert_rgba_to_int(stuff.menuData.color.border.r, stuff.menuData.color.border.g, stuff.menuData.color.border.b, stuff.menuData.color.border.a)) + + -- footer and text/scroll + local footerColor = func.convert_rgba_to_int(stuff.menuData.color.footer.r, stuff.menuData.color.footer.g, stuff.menuData.color.footer.b, stuff.menuData.color.footer.a) + local footer_y_pos + if stuff.menuData.footer.footer_pos_related_to_background then + footer_y_pos = (stuff.menuData.pos_y + stuff.menuData.height + stuff.menuData.border*2 + stuff.menuData.footer.footer_size/2)*-2+1 + else + footer_y_pos = (stuff.menuData.pos_y + (drawnfeats*stuff.menuData.feature_offset) + stuff.menuData.border*2 + stuff.menuData.footer.footer_size/2)*-2+1 + end + scriptdraw.draw_rect(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, footer_y_pos), cheeseUtils.memoize.v2(stuff.menuData.width*2, stuff.menuData.footer.footer_size*2), footerColor) + + local footerTextColor = func.convert_rgba_to_int(stuff.menuData.color.footer_text.r, stuff.menuData.color.footer_text.g, stuff.menuData.color.footer_text.b, stuff.menuData.color.footer_text.a) + local featHint = stuff.feature_hints[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].id] + if featHint then + local padding = scriptdraw.size_pixel_to_rel_y(5) + local hintStrSize = scriptdraw.size_pixel_to_rel_y(featHint.size.y) * (stuff.menuData.text_size * stuff.menuData.hint_size_modifier) + local posY = footer_y_pos - stuff.menuData.border*2 - stuff.menuData.footer.footer_size - padding + local textY = posY - padding + posY = posY - hintStrSize/2 + + local rectHeight = hintStrSize+padding*4 + --scriptdraw.draw_rect(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, posY+rectHalfHeight/2), cheeseUtils.memoize.v2(stuff.menuData.width*2, rectHalfHeight), func.convert_rgba_to_int(stuff.menuData.color.footer.r, stuff.menuData.color.footer.g, stuff.menuData.color.footer.b, stuff.menuData.color.footer.a)) + cheeseUtils.draw_rect_ext_wh(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, posY-padding), cheeseUtils.memoize.v2(stuff.menuData.width*2, rectHeight), (footerColor & 0xffffff) | 50 << 24, footerColor, footerColor, (footerColor & 0xffffff) | 50 << 24) + scriptdraw.draw_text( + featHint.str, + cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1 - stuff.menuData.width + padding, textY), + cheeseUtils.memoize.v2(stuff.menuData.width+padding*2, 2), + stuff.menuData.text_size * stuff.menuData.hint_size_modifier, + footerTextColor, + 0, + stuff.menuData.fonts.hint + ) + end + + local footer_size = stuff.menuData.text_size * stuff.menuData.footer_size_modifier + local text_y_pos = footer_y_pos + 0.011111111 + stuff.menuData.footer.footer_y_offset + scriptdraw.draw_text( + tostring(stuff.menuData.footer.footer_text), + cheeseUtils.memoize.v2((stuff.menuData.pos_x - stuff.menuData.width/2 + stuff.menuData.footer.padding)*2-1, text_y_pos), + cheeseUtils.memoize.v2(2, 2), + footer_size, + footerTextColor, + 0, + stuff.menuData.fonts.footer + ) + + scriptdraw.draw_text( + tostring(stuff.scroll.." / "..(#currentMenu - stuff.drawHiddenOffset)), + cheeseUtils.memoize.v2((stuff.menuData.pos_x + stuff.menuData.width/2 - stuff.menuData.footer.padding)*2-1, text_y_pos), + cheeseUtils.memoize.v2(2, 2), + footer_size, + footerTextColor, + 16, + stuff.menuData.fonts.footer + ) + end + + if type(sprite) == "table" then + if not sprite[stuff.draw_current_menu.frameCounter] then + stuff.draw_current_menu.frameCounter = 1 + end + if utils.time_ms() > stuff.draw_current_menu.time then + if stuff.draw_current_menu.frameCounter < #sprite then + stuff.draw_current_menu.frameCounter = stuff.draw_current_menu.frameCounter + 1 + else + stuff.draw_current_menu.frameCounter = 1 + end + stuff.draw_current_menu.time = utils.time_ms() + (sprite[stuff.draw_current_menu.frameCounter].delay or sprite.constant_delay or 33) + end + sprite = sprite[stuff.draw_current_menu.frameCounter].sprite + end + if sprite then + local size = ((2.56 * stuff.menuData.width) * (1000 / scriptdraw.get_sprite_size(sprite).x)) / (2560 / graphics.get_screen_width()) + scriptdraw.draw_sprite(sprite, cheeseUtils.memoize.v2(stuff.menuData.pos_x * 2 - 1, ((stuff.menuData.pos_y+stuff.menuData.height/2) - (stuff.menuData.height/2 + ((scriptdraw.get_sprite_size(sprite).y*size)/2)/graphics.get_screen_height()))*-2+1), size, 0, stuff.menuData.color.sprite) + end + system.wait(0) + end + + --[[ + example of table_of_lines: + { + {"leftside", "rightside"}, + {"IP", "ddosing u rn"}, + {"Cheesus", "Christ"} + } + has to be in this structure, you can add more than three + ]] + function func.draw_side_window(header_text, table_of_lines, v2pos, rect_color, rect_width, text_spacing, text_padding, text_color) + text_color = text_color or 0xFFFFFFFF + assert( + type(header_text) == "string" + and type(table_of_lines) == "table" + and type(v2pos) == "userdata" + and type(rect_color) == "number" + and type(rect_width) == "number" + and type(text_spacing) == "number" + and type(text_padding) == "number" + and type(text_color) == "number", + "one or more draw_side_window args were invalid" + ) + local rect_height = #table_of_lines*text_spacing+0.07125 + v2pos.y = v2pos.y-(rect_height/2) + + + scriptdraw.draw_rect(v2pos, cheeseUtils.memoize.v2(rect_width, rect_height), rect_color) + + local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 + -- Header text + scriptdraw.draw_text(header_text, cheeseUtils.memoize.v2(v2pos.x - scriptdraw.get_text_size(header_text, text_size, 0).x/graphics.get_screen_width(), v2pos.y+(rect_height/2)-0.015), cheeseUtils.memoize.v2(2, 2), text_size, text_color, 0, 0) + -- table_of_lines + for k, v in ipairs(table_of_lines) do + v[1] = tostring(v[1]) + v[2] = tostring(v[2]) + local pos_y = v2pos.y-k*text_spacing+rect_height/2-0.03 + scriptdraw.draw_text(v[1], cheeseUtils.memoize.v2(v2pos.x-rect_width/2+text_padding, pos_y), cheeseUtils.memoize.v2(2, 2), text_size, text_color, 0, 2) + scriptdraw.draw_text(v[2], cheeseUtils.memoize.v2(v2pos.x+rect_width/2-text_padding, pos_y), cheeseUtils.memoize.v2(2, 2), text_size, text_color, 16, 2) + end + end + + --Hotkey functions + function func.get_hotkey(keyTable, vkTable, singlekey) + local current_key + local excludedkeys = {} + while not keyTable[1] do + if cheeseUtils.get_key(0x1B):is_down() then + return "escaped" + end + for k, v in pairs(stuff.char_codes) do + if cheeseUtils.get_key(v):is_down() then + if v ~= 0x0D or singlekey then + if v ~= 0xA0 and v ~= 0xA1 and v ~= 0xA2 and v ~= 0xA3 and v ~= 0xA4 and v ~= 0xA5 and not singlekey then + keyTable[1] = "NOMOD" + end + if singlekey then + return k, v + else + keyTable[#keyTable + 1] = k + vkTable[#vkTable+1] = v + current_key = v + excludedkeys[v] = true + end + end + end + end + system.wait(0) + end + + if not singlekey then + while cheeseUtils.get_key(current_key):is_down() do + for k, v in pairs(stuff.char_codes) do + if cheeseUtils.get_key(v):is_down() and not excludedkeys[v] and v ~= 0xA0 and v ~= 0xA1 and v ~= 0xA2 and v ~= 0xA3 and v ~= 0xA4 and v ~= 0xA5 then + excludedkeys[v] = true + keyTable[#keyTable + 1] = k + vkTable[#vkTable+1] = v + end + end + system.wait(0) + end + + while not cheeseUtils.get_key(0x1B):is_down() and not cheeseUtils.get_key(0x0D):is_down() do + for k, v in pairs(stuff.char_codes) do + if cheeseUtils.get_key(v):is_down() then + return false + end + end + system.wait(0) + end + + return cheeseUtils.get_key(0x0D):is_down() or "escaped" + end + end + + function func.draw_hotkey(keyTable) + while true do + for i = 0, 360 do + controls.disable_control_action(0, i, true) + end + local concatenated = table.concat(keyTable, "+") + scriptdraw.draw_rect(cheeseUtils.memoize.v2(0, 0), cheeseUtils.memoize.v2(2, 2), 0x7D000000) + scriptdraw.draw_text(concatenated, cheeseUtils.memoize.v2(-(scriptdraw.get_text_size(concatenated, 1, 0).x/graphics.get_screen_width())), cheeseUtils.memoize.v2(2, 2), 1, 0xffffffff, 1 << 1, 0) + system.wait(0) + end + end + + + function func.start_hotkey_process(feat) + stuff.menuData.menuToggle = false + local keyTable = {} + local vkTable = {} + + local drawThread = menu.create_thread(func.draw_hotkey, keyTable) + + while cheeseUtils.get_key(stuff.vkcontrols.setHotkey):is_down() do + system.wait(0) + end + + local response + repeat + response = func.get_hotkey(keyTable, vkTable) + if not response then + for k, v in pairs(keyTable) do + keyTable[k] = nil + end + for k, v in pairs(vkTable) do + vkTable[k] = nil + end + end + until response + + local keyString = table.concat(keyTable, "|") + + if response ~= "escaped" then + stuff.hotkeys_to_vk[keyString] = vkTable + if not stuff.hotkeys[keyString] then + stuff.hotkeys[keyString] = {} + end + stuff.hotkeys[keyString][feat.hierarchy_key] = true + feat.hotkey = keyString + gltw.write(stuff.hotkeys, "hotkeys", stuff.path.hotkeys, nil, true) + end + + menu.delete_thread(drawThread) + while cheeseUtils.get_key(0x0D):is_down() or cheeseUtils.get_key(0x1B):is_down() do -- enter and esc + controls.disable_control_action(0, 200, true) + system.wait(0) + end + controls.disable_control_action(0, 200, true) + func.toggle_menu(true) + return response ~= "escaped" and response + end + + --End of functions + + --threads + menu.create_thread(function() + local side_window_pos = v2((stuff.menuData.pos_x + stuff.menuData.width + stuff.menuData.side_window.offset.x)*2-1, (stuff.menuData.pos_y + stuff.menuData.side_window.offset.y)*-2+1) + while true do + if stuff.menuData.menuToggle then + func.draw_current_menu() + if currentMenu and stuff.menuData.side_window.on then + local pid = currentMenu.pid + if not pid and currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then + pid = currentMenu[stuff.scroll + stuff.scrollHiddenOffset].pid + end + if pid and pid ~= stuff.pid then + if not stuff.playerIds[pid].hidden then + stuff.player_info[1][2] = tostring(pid) + stuff.player_info[10][2] = func.convert_int_ip(player.get_player_ip(pid)) + stuff.player_info[11][2] = tostring(player.get_player_scid(pid)) + stuff.player_info[12][2] = string.format("%X", player.get_player_host_token(pid)) + stuff.player_info.max_health = "/"..math.floor(player.get_player_max_health(pid)) + stuff.player_info.name = tostring(player.get_player_name(pid)) + stuff.pid = pid + end + end + if pid then + side_window_pos.x, side_window_pos.y = (stuff.menuData.pos_x + stuff.menuData.width + stuff.menuData.side_window.offset.x)*2-1, (stuff.menuData.pos_y + stuff.menuData.side_window.offset.y)*-2+1 + native.call(0xBE8CD9BE829BBEBF, player.get_player_ped(stuff.pid), stuff.proofs.bulletProof, stuff.proofs.fireProof, stuff.proofs.explosionProof, stuff.proofs.collisionProof, stuff.proofs.meleeProof, stuff.proofs.steamProof, stuff.proofs.p7, stuff.proofs.drownProof) + stuff.player_info[2][2] = player.is_player_god(stuff.pid) and "Yes" or "No" + stuff.player_info[3][2] = (stuff.proofs.bulletProof:__tointeger()|stuff.proofs.fireProof:__tointeger()|stuff.proofs.explosionProof:__tointeger()|stuff.proofs.collisionProof:__tointeger()|stuff.proofs.meleeProof:__tointeger()|stuff.proofs.steamProof:__tointeger()|stuff.proofs.p7:__tointeger()|stuff.proofs.drownProof:__tointeger()) == 1 and "Yes" or "No" + stuff.player_info[4][2] = player.is_player_vehicle_god(stuff.pid) and "Yes" or "No" + stuff.player_info[5][2] = player.is_player_modder(stuff.pid, -1) and "Yes" or "No" + stuff.player_info[6][2] = player.is_player_host(stuff.pid) and "Yes" or "No" + stuff.player_info[7][2] = player.get_player_wanted_level(stuff.pid) + stuff.player_info[8][2] = math.floor(player.get_player_health(stuff.pid))..stuff.player_info.max_health + stuff.player_info[9][2] = math.floor(player.get_player_armour(stuff.pid)).."/50" + stuff.player_info[13][2] = player.get_player_host_priority(stuff.pid) + func.draw_side_window( + stuff.player_info.name, + stuff.player_info, + side_window_pos, + func.convert_rgba_to_int(stuff.menuData.color.side_window.r, stuff.menuData.color.side_window.g, stuff.menuData.color.side_window.b, stuff.menuData.color.side_window.a), + stuff.menuData.side_window.width, stuff.menuData.side_window.spacing, stuff.menuData.side_window.padding, + func.convert_rgba_to_int(stuff.menuData.color.side_window_text.r, stuff.menuData.color.side_window_text.g, stuff.menuData.color.side_window_text.b, stuff.menuData.color.side_window_text.a) + ) + end + end + if stuff.old_selected ~= currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then + if type(stuff.old_selected) == "table" then + stuff.old_selected:activate_hl_func() + end + if currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then + currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() + end + stuff.old_selected = currentMenu[stuff.scroll + stuff.scrollHiddenOffset] + end + controls.disable_control_action(0, 172, true) + controls.disable_control_action(0, 27, true) + else + system.wait(0) + end + end + end, nil) + + menu.create_thread(function() + while true do + stuff.menuData.menuNav = native.call(0x5FCF4D7069B09026):__tointeger() ~= 1 and not (stuff.menuData.chatBoxOpen or input.is_open() --[[or console.on]]) + if stuff.menuData.menuNav then + func.do_key(500, stuff.vkcontrols.open, false, function() -- F4 + func.toggle_menu(not stuff.menuData.menuToggle) + end) + end + if currentMenu.hidden or not currentMenu then + currentMenu = stuff.previousMenus[#stuff.previousMenus].menu + stuff.scroll = stuff.previousMenus[#stuff.previousMenus].scroll + stuff.drawScroll = stuff.previousMenus[#stuff.previousMenus].drawScroll + stuff.scrollHiddenOffset = stuff.previousMenus[#stuff.previousMenus].scrollHiddenOffset + stuff.previousMenus[#stuff.previousMenus] = nil + end + local pid = player.player_id() + stuff.playerIds[pid].name = player.get_player_name(pid).." [Y]" + if stuff.playerIds[pid].hidden then + stuff.playerIds[pid].hidden = false + func.reset_player_submenu(pid) + end + system.wait(0) + end + end, nil) + menu.create_thread(function() + while true do + system.wait(0) + if stuff.menuData.menuToggle and stuff.menuData.menuNav then + func.do_key(500, stuff.vkcontrols.setHotkey, false, function() -- F11 + if cheeseUtils.get_key(0x10):is_down() and stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey] then + stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey][currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hierarchy_key] = nil + if not next(stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey]) then + stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey] = nil + end + currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey = nil + gltw.write(stuff.hotkeys, "hotkeys", stuff.path.hotkeys, nil, true) + menu.notify("Removed "..currentMenu[stuff.scroll + stuff.scrollHiddenOffset].name.."'s hotkey") + elseif cheeseUtils.get_key(0x11):is_down() then + menu.notify(currentMenu[stuff.scroll + stuff.scrollHiddenOffset].name.."'s hotkey is "..(currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey or "none")) + elseif not cheeseUtils.get_key(0x10):is_down() and not cheeseUtils.get_key(0x11):is_down() then + if stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey] then + stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey][currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hierarchy_key] = nil + end + if func.start_hotkey_process(currentMenu[stuff.scroll + stuff.scrollHiddenOffset]) then + menu.notify("Set "..currentMenu[stuff.scroll + stuff.scrollHiddenOffset].name.."'s hotkey to "..currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey) + end + end + end) + end + end + end,nil) + menu.create_thread(function() + while true do + system.wait(0) + if stuff.menuData.menuToggle and stuff.menuData.menuNav then + func.do_key(500, stuff.vkcontrols.down, true, function() -- downKey + --[[ local old_scroll = stuff.scroll + stuff.scrollHiddenOffset ]] + if stuff.scroll + stuff.drawHiddenOffset >= #currentMenu and #currentMenu - stuff.drawHiddenOffset > 1 then + stuff.scroll = 1 + stuff.drawScroll = 0 + elseif #currentMenu - stuff.drawHiddenOffset > 1 then + stuff.scroll = stuff.scroll + 1 + if stuff.scroll - stuff.drawScroll >= (stuff.menuData.max_features - 1) and stuff.drawScroll < stuff.maxDrawScroll then + stuff.drawScroll = stuff.drawScroll + 1 + end + end + --[[ if old_scroll ~= (stuff.scroll + stuff.scrollHiddenOffset) then + currentMenu[old_scroll]:activate_hl_func() + if currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then + currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() + end + end ]] + end) + end + end + end, nil) + menu.create_thread(function() + while true do + system.wait(0) + if stuff.menuData.menuToggle and stuff.menuData.menuNav then + func.do_key(500, stuff.vkcontrols.up, true, function() -- upKey + --[[ local old_scroll = stuff.scroll + stuff.scrollHiddenOffset ]] + if stuff.scroll <= 1 and #currentMenu - stuff.drawHiddenOffset > 1 then + stuff.scroll = #currentMenu + stuff.drawScroll = stuff.maxDrawScroll + elseif #currentMenu - stuff.drawHiddenOffset > 1 then + stuff.scroll = stuff.scroll - 1 + if stuff.scroll - stuff.drawScroll <= 2 and stuff.drawScroll > 0 then + stuff.drawScroll = stuff.drawScroll - 1 + end + end + --[[ if old_scroll ~= (stuff.scroll + stuff.scrollHiddenOffset) then + currentMenu[old_scroll]:activate_hl_func() + if currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then + currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() + end + end ]] + end) + end + end + end,nil) + menu.create_thread(function() + while true do + system.wait(0) + if stuff.menuData.menuToggle and stuff.menuData.menuNav then + func.do_key(500, stuff.vkcontrols.select, true, function() --enter + local feat = currentMenu[stuff.scroll + stuff.scrollHiddenOffset] + if feat then + if cheeseUtils.get_key(stuff.vkcontrols.specialKey):is_down() and feat.type >> 5 & 1 ~= 0 then + menu.create_thread(func.selector, feat) + elseif feat.type >> 11 & 1 ~= 0 and not feat.hidden then + --feat:activate_hl_func() + stuff.previousMenus[#stuff.previousMenus + 1] = {menu = currentMenu, scroll = stuff.scroll, drawScroll = stuff.drawScroll, scrollHiddenOffset = stuff.scrollHiddenOffset} + currentMenu = feat + currentMenu:activate_feat_func() + stuff.scroll = 1 + system.wait(0) + stuff.drawScroll = 0 + stuff.scrollHiddenOffset = 0 + --[[ if feat then + feat:activate_hl_func() + end ]] + while cheeseUtils.get_key(stuff.vkcontrols.select):is_down() do + system.wait(0) + end + elseif feat.type & 1536 ~= 0 and not feat.hidden then + feat:activate_feat_func() + elseif feat.type & 1 ~= 0 and not feat.hidden then + feat.real_on = not feat.real_on + feat:activate_feat_func() + end + else + system.wait(100) + end + end) + end + end + end, nil) + menu.create_thread(function() + while true do + system.wait(0) + if stuff.menuData.menuToggle and stuff.menuData.menuNav then + func.do_key(500, stuff.vkcontrols.back, false, function() --backspace + if stuff.previousMenus[#stuff.previousMenus] then + --[[ if currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then + currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() + end ]] + currentMenu = stuff.previousMenus[#stuff.previousMenus].menu + stuff.scroll = stuff.previousMenus[#stuff.previousMenus].scroll + stuff.drawScroll = stuff.previousMenus[#stuff.previousMenus].drawScroll + stuff.scrollHiddenOffset = stuff.previousMenus[#stuff.previousMenus].scrollHiddenOffset + stuff.previousMenus[#stuff.previousMenus] = nil + --currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() + end + end) + end + end + end, nil) + menu.create_thread(function() + while true do + system.wait(0) + if stuff.menuData.menuToggle and stuff.menuData.menuNav then + func.do_key(500, stuff.vkcontrols.left, true, function() -- left + local feat = currentMenu[stuff.scroll + stuff.scrollHiddenOffset] + if feat then + if feat.value then + if feat.str_data then + if feat.value <= 0 then + feat.value = #feat.str_data - 1 + else + feat.value = feat.value - 1 + end + else + if tonumber(feat.value) <= feat.min and feat.type >> 2 & 1 == 0 then + feat.value = feat.max + else + feat.value = tonumber(feat.value) - feat.mod + end + end + end + if feat.type then + if feat.type >> 10 & 1 ~= 0 or (feat.type & 3 == 3 and feat.on) then + feat:activate_feat_func() + end + end + end + end) + end + end + end, nil) + menu.create_thread(function() + while true do + if stuff.menuData.menuToggle and stuff.menuData.menuNav then + func.do_key(500, stuff.vkcontrols.right, true, function() -- right + local feat = currentMenu[stuff.scroll + stuff.scrollHiddenOffset] + if feat then + if feat.value then + if feat.str_data then + if tonumber(feat.value) >= tonumber(#feat.str_data) - 1 then + feat.value = 0 + else + feat.value = feat.value + 1 + end + else + if tonumber(feat.value) >= feat.max and feat.type >> 2 & 1 == 0 then + feat.value = feat.min + else + feat.value = tonumber(feat.value) + feat.mod + end + end + end + if feat.type then + if feat.type >> 10 & 1 ~= 0 or (feat.type & 3 == 3 and feat.on) then + feat:activate_feat_func() + end + end + end + end) + end + system.wait(0) + end + end, nil) + + + --Hotkey thread + menu.create_thread(function() + while true do + if stuff.menuData.menuNav then + for k, v in pairs(stuff.hotkeys) do + local hotkey = cheeseUtils.get_key(table.unpack(stuff.hotkeys_to_vk[k])) + if hotkey:is_down() and (not (cheeseUtils.get_key(0x10):is_down() or cheeseUtils.get_key(0x11):is_down() or cheeseUtils.get_key(0x12):is_down()) or not (k:match("NOMOD"))) and utils.time_ms() > stuff.hotkey_cooldowns[k] then + for k, v in pairs(stuff.hotkeys[k]) do + if stuff.hotkey_feature_hierarchy_keys[k] then + for k, v in pairs(stuff.hotkey_feature_hierarchy_keys[k]) do + if v.type & 1 ~= 0 then + v.on = not v.on + if stuff.hotkey_notifications.toggle then + menu.notify("Turned "..v.name.." "..(v.on and "on" or "off"), "Cheese Menu", 3, func.convert_rgba_to_int(stuff.menuData.color.notifications.r, stuff.menuData.color.notifications.g, stuff.menuData.color.notifications.b, stuff.menuData.color.notifications.a)) + end + else + v:activate_feat_func() + if stuff.hotkey_notifications.action then + menu.notify("Activated "..v.name, "Cheese Menu", 3, func.convert_rgba_to_int(stuff.menuData.color.notifications.r, stuff.menuData.color.notifications.g, stuff.menuData.color.notifications.b, stuff.menuData.color.notifications.a)) + end + end + end + end + end + if stuff.hotkey_cooldowns[k] == 0 then + stuff.hotkey_cooldowns[k] = utils.time_ms() + 500 + else + stuff.hotkey_cooldowns[k] = utils.time_ms() + 100 + end + elseif not hotkey:is_down() then + stuff.hotkey_cooldowns[k] = 0 + end + end + end + system.wait(0) + end + end, nil) + --End of threads + menu.notify("Kektram for teaching me lua & sharing neat functions\n\nRimuru for making the first separate ui that helped me in making cheese menu\n\nProddy for showing better ways to do things & sharing Script Manager", "Credits:", 12, 0x00ff00) + menu.notify("Controls can be found in\nScript Features > Cheese Menu > Controls", "CheeseMenu by GhostOne\n"..stuff.controls.open.." to open", 6, 0x00ff00) + + menu_configuration_features = {} + menu_configuration_features.cheesemenuparent = menu.add_feature("Cheese Menu", "parent") + + menu.add_feature("Save Settings", "action", menu_configuration_features.cheesemenuparent.id, function() + func.save_settings() + menu.notify("Settings Saved Successfully", "Cheese Menu", 6, 0x00ff00) + end) + + menu.add_feature("Save UI", "action", menu_configuration_features.cheesemenuparent.id, function() + local status, name = input.get("name of ui", "", 25, 0) + if status == 0 then + func.save_ui(name) + menu.notify("UI Saved Successfully", "Cheese Menu", 6, 0x00ff00) + for _, v in pairs(stuff.menuData.files.ui) do + if v == name then + return + end + end + stuff.menuData.files.ui[#stuff.menuData.files.ui+1] = name + menu_configuration_features.load_ui:set_str_data(stuff.menuData.files.ui) + end + end) + + menu_configuration_features.load_ui = menu.add_feature("Load UI", "action_value_str", menu_configuration_features.cheesemenuparent.id, function(f) + func.load_ui(f.str_data[f.value + 1]) + end) + menu_configuration_features.load_ui:set_str_data(stuff.menuData.files.ui) + + menu_configuration_features.menuXfeat = menu.add_feature("Menu pos X", "autoaction_value_i", menu_configuration_features.cheesemenuparent.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.pos_x = num/graphics.get_screen_height() + f.value = num + end + end + stuff.menuData.pos_x = f.value/graphics.get_screen_width() + end) + menu_configuration_features.menuXfeat.max = graphics.get_screen_width() + menu_configuration_features.menuXfeat.mod = 1 + menu_configuration_features.menuXfeat.min = -graphics.get_screen_width() + menu_configuration_features.menuXfeat.value = math.floor(stuff.menuData.pos_x*graphics.get_screen_width()) + + menu_configuration_features.menuYfeat = menu.add_feature("Menu pos Y", "autoaction_value_i", menu_configuration_features.cheesemenuparent.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.pos_y = num/graphics.get_screen_height() + f.value = num + end + end + stuff.menuData.pos_y = f.value/graphics.get_screen_height() + end) + menu_configuration_features.menuYfeat.max = graphics.get_screen_height() + menu_configuration_features.menuYfeat.mod = 1 + menu_configuration_features.menuYfeat.min = -graphics.get_screen_height() + menu_configuration_features.menuYfeat.value = math.floor(stuff.menuData.pos_y*graphics.get_screen_height()) + + menu_configuration_features.headerfeat = menu.add_feature("Header", "autoaction_value_str", menu_configuration_features.cheesemenuparent.id, function(f) + if f.str_data[f.value + 1] == "NONE" then + stuff.menuData.header = nil + else + stuff.menuData.header = f.str_data[f.value + 1] + end + end) + menu_configuration_features.headerfeat:set_str_data({"NONE", table.unpack(stuff.menuData.files.headers)}) + + menu_configuration_features.layoutParent = menu.add_feature("Layout", "parent", menu_configuration_features.cheesemenuparent.id) + + menu_configuration_features.maxfeats = menu.add_feature("Max features", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData:set_max_features(f.value) + end) + menu_configuration_features.maxfeats.max = 50 + menu_configuration_features.maxfeats.mod = 1 + menu_configuration_features.maxfeats.min = 1 + menu_configuration_features.maxfeats.value = math.floor(stuff.menuData.max_features) + + menu_configuration_features.menuWidth = menu.add_feature("Menu width", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.width = f.value/graphics.get_screen_width() + end) + menu_configuration_features.menuWidth.max = graphics.get_screen_width() + menu_configuration_features.menuWidth.mod = 1 + menu_configuration_features.menuWidth.min = -graphics.get_screen_width() + menu_configuration_features.menuWidth.value = math.floor(stuff.menuData.width*graphics.get_screen_width()) + + menu_configuration_features.featXfeat = menu.add_feature("Feature dimensions X", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.feature_scale.x = f.value/graphics.get_screen_width() + end) + menu_configuration_features.featXfeat.max = graphics.get_screen_width() + menu_configuration_features.featXfeat.mod = 1 + menu_configuration_features.featXfeat.min = -graphics.get_screen_width() + menu_configuration_features.featXfeat.value = math.floor(stuff.menuData.feature_scale.x*graphics.get_screen_width()) + + menu_configuration_features.featYfeat = menu.add_feature("Feature dimensions Y", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.feature_scale.y = f.value/graphics.get_screen_height() + end) + menu_configuration_features.featYfeat.max = graphics.get_screen_height() + menu_configuration_features.featYfeat.mod = 1 + menu_configuration_features.featYfeat.min = -graphics.get_screen_height() + menu_configuration_features.featYfeat.value = math.floor(stuff.menuData.feature_scale.y*graphics.get_screen_height()) + + menu_configuration_features.feature_offset = menu.add_feature("Feature spacing", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.feature_offset = f.value/graphics.get_screen_height() + menu_configuration_features.maxfeats:toggle() + end) + menu_configuration_features.feature_offset.max = graphics.get_screen_height() + menu_configuration_features.feature_offset.mod = 1 + menu_configuration_features.feature_offset.min = -graphics.get_screen_height() + menu_configuration_features.feature_offset.value = math.floor(stuff.menuData.feature_offset*graphics.get_screen_height()) + + menu_configuration_features.text_size = menu.add_feature("Text Size", "autoaction_value_f", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.text_size_modifier = f.value + end) + menu_configuration_features.text_size.max = 5 + menu_configuration_features.text_size.mod = 0.01 + menu_configuration_features.text_size.min = 0.1 + menu_configuration_features.text_size.value = stuff.menuData.text_size_modifier + + menu_configuration_features.footer_size = menu.add_feature("Footer Text Size", "autoaction_value_f", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.footer_size_modifier = f.value + end) + menu_configuration_features.footer_size.max = 5 + menu_configuration_features.footer_size.mod = 0.01 + menu_configuration_features.footer_size.min = 0.1 + menu_configuration_features.footer_size.value = stuff.menuData.footer_size_modifier + + menu_configuration_features.hint_size = menu.add_feature("Hint Text Size", "autoaction_value_f", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.hint_size_modifier = f.value + func.rewrap_hints(stuff.menuData.fonts.hint) + end) + menu_configuration_features.hint_size.max = 5 + menu_configuration_features.hint_size.mod = 0.01 + menu_configuration_features.hint_size.min = 0.1 + menu_configuration_features.hint_size.value = stuff.menuData.hint_size_modifier + + menu_configuration_features.text_y_offset = menu.add_feature("Text Y Offset", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) + stuff.drawFeatParams.textOffset.y = -(f.value/graphics.get_screen_height()) + stuff.menuData.text_y_offset = -(f.value/graphics.get_screen_height()) + end) + menu_configuration_features.text_y_offset.max = 100 + menu_configuration_features.text_y_offset.mod = 1 + menu_configuration_features.text_y_offset.min = -100 + menu_configuration_features.text_y_offset.value = -math.floor(stuff.menuData.text_y_offset*graphics.get_screen_height()) + + menu_configuration_features.border = menu.add_feature("Border", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.border = f.value/graphics.get_screen_height() + end) + menu_configuration_features.border.max = graphics.get_screen_height() + menu_configuration_features.border.mod = 1 + menu_configuration_features.border.min = -graphics.get_screen_height() + menu_configuration_features.border.value = math.floor(stuff.menuData.border*graphics.get_screen_height()) + + menu_configuration_features.selector_speed = menu.add_feature("Selector Speed", "autoaction_value_f", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.selector_speed = f.value + end) + menu_configuration_features.selector_speed.max = 10 + menu_configuration_features.selector_speed.mod = 0.1 + menu_configuration_features.selector_speed.min = 0.2 + menu_configuration_features.selector_speed.value = stuff.menuData.selector_speed + + -- Online Player Submenu Sorting + menu_configuration_features.player_submenu_sort = menu.add_feature("Online Players Sort:", "autoaction_value_str", menu_configuration_features.layoutParent.id, function(f) + table.sort(stuff.PlayerParent, stuff.table_sort_functions[f.value]) + stuff.player_submenu_sort = f.value + end) + menu_configuration_features.player_submenu_sort:set_str_data({'PID', 'PID Reversed', 'Alphabetically', 'Alphabetically Reversed', 'Host Priority', 'Host Priority Reversed'}) + menu_configuration_features.player_submenu_sort.value = stuff.player_submenu_sort + + -- Padding + menu_configuration_features.padding_parent = menu.add_feature("Padding", "parent", menu_configuration_features.layoutParent.id) + + menu_configuration_features.namePadding = menu.add_feature("Name Padding", "autoaction_value_i", menu_configuration_features.padding_parent.id, function(f) + stuff.menuData.padding.name = f.value/graphics.get_screen_width() + end) + menu_configuration_features.namePadding.max = graphics.get_screen_width() + menu_configuration_features.namePadding.mod = 1 + menu_configuration_features.namePadding.min = -graphics.get_screen_width() + menu_configuration_features.namePadding.value = math.floor(stuff.menuData.padding.name*graphics.get_screen_width()) + + menu_configuration_features.parentPadding = menu.add_feature("Parent Padding", "autoaction_value_i", menu_configuration_features.padding_parent.id, function(f) + stuff.menuData.padding.parent = f.value/graphics.get_screen_width() + end) + menu_configuration_features.parentPadding.max = graphics.get_screen_width() + menu_configuration_features.parentPadding.mod = 1 + menu_configuration_features.parentPadding.min = -graphics.get_screen_width() + menu_configuration_features.parentPadding.value = math.floor(stuff.menuData.padding.parent*graphics.get_screen_width()) + + menu_configuration_features.valuePadding = menu.add_feature("Value Padding", "autoaction_value_i", menu_configuration_features.padding_parent.id, function(f) + stuff.menuData.padding.value = f.value/graphics.get_screen_width() + end) + menu_configuration_features.valuePadding.max = graphics.get_screen_width() + menu_configuration_features.valuePadding.mod = 1 + menu_configuration_features.valuePadding.min = -graphics.get_screen_width() + menu_configuration_features.valuePadding.value = math.floor(stuff.menuData.padding.value*graphics.get_screen_width()) + + menu_configuration_features.sliderPadding = menu.add_feature("Slider Padding", "autoaction_value_i", menu_configuration_features.padding_parent.id, function(f) + stuff.menuData.padding.slider = f.value/graphics.get_screen_width() + end) + menu_configuration_features.sliderPadding.max = graphics.get_screen_width() + menu_configuration_features.sliderPadding.mod = 1 + menu_configuration_features.sliderPadding.min = -graphics.get_screen_width() + menu_configuration_features.sliderPadding.value = math.floor(stuff.menuData.padding.slider*graphics.get_screen_width()) + + -- Slider dimensions + menu_configuration_features.slider_parent = menu.add_feature("Slider", "parent", menu_configuration_features.layoutParent.id) + + menu_configuration_features.sliderWidth = menu.add_feature("Slider Width", "autoaction_value_i", menu_configuration_features.slider_parent.id, function(f) + stuff.menuData.slider.width = f.value/graphics.get_screen_width() + end) + menu_configuration_features.sliderWidth.max = graphics.get_screen_width() + menu_configuration_features.sliderWidth.mod = 1 + menu_configuration_features.sliderWidth.min = -graphics.get_screen_width() + menu_configuration_features.sliderWidth.value = math.floor(stuff.menuData.slider.width*graphics.get_screen_width()) + + menu_configuration_features.sliderHeight = menu.add_feature("Slider Height", "autoaction_value_i", menu_configuration_features.slider_parent.id, function(f) + stuff.menuData.slider.height = f.value/graphics.get_screen_height() + end) + menu_configuration_features.sliderHeight.max = graphics.get_screen_height() + menu_configuration_features.sliderHeight.mod = 1 + menu_configuration_features.sliderHeight.min = -graphics.get_screen_height() + menu_configuration_features.sliderHeight.value = math.floor(stuff.menuData.slider.height*graphics.get_screen_height()) + + menu_configuration_features.sliderheightActive = menu.add_feature("Slider Height Active", "autoaction_value_i", menu_configuration_features.slider_parent.id, function(f) + stuff.menuData.slider.heightActive = f.value/graphics.get_screen_height() + end) + menu_configuration_features.sliderheightActive.max = graphics.get_screen_height() + menu_configuration_features.sliderheightActive.mod = 1 + menu_configuration_features.sliderheightActive.min = -graphics.get_screen_height() + menu_configuration_features.sliderheightActive.value = math.floor(stuff.menuData.slider.heightActive*graphics.get_screen_height()) + + -- Controls + menu_configuration_features.controls = menu.add_feature("Controls", "parent", menu_configuration_features.cheesemenuparent.id) + + for k, v in pairs(stuff.controls) do + menu.add_feature(k, "action_value_str", menu_configuration_features.controls.id, function(f) + for k, v in pairs(stuff.char_codes) do + while cheeseUtils.get_key(v):is_down() do + system.wait(0) + end + end + menu.notify("Press any button\nESC to cancel", "Cheese Menu", 3, func.convert_rgba_to_int(stuff.menuData.color.notifications.r, stuff.menuData.color.notifications.g, stuff.menuData.color.notifications.b, stuff.menuData.color.notifications.a)) + local disablethread = menu.create_thread(stuff.disable_all_controls, nil) + local stringkey, vk = func.get_hotkey({}, {}, true) + if stringkey ~= "escaped" then + stuff.controls[k] = stringkey + stuff.vkcontrols[k] = vk + f:set_str_data({stringkey}) + end + menu.delete_thread(disablethread) + end):set_str_data({v}) + end + + -- Player Info + menu_configuration_features.side_window = menu.add_feature("Player Info Window", "parent", menu_configuration_features.cheesemenuparent.id) + + -- On + menu_configuration_features.side_window_on = menu.add_feature("Draw", "toggle", menu_configuration_features.side_window.id, function(f) + stuff.menuData.side_window.on = f.on + end) + menu_configuration_features.side_window_on.on = stuff.menuData.side_window.on + + -- Offset + menu_configuration_features.side_window_offsetx = menu.add_feature("X Offset", "autoaction_value_i", menu_configuration_features.side_window.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.side_window.offset.x = num/graphics.get_screen_height() + f.value = num + end + end + stuff.menuData.side_window.offset.x = f.value/graphics.get_screen_width() + end) + menu_configuration_features.side_window_offsetx.max = graphics.get_screen_width() + menu_configuration_features.side_window_offsetx.mod = 1 + menu_configuration_features.side_window_offsetx.min = -graphics.get_screen_width() + menu_configuration_features.side_window_offsetx.value = math.floor(stuff.menuData.side_window.offset.x*graphics.get_screen_width()) + + menu_configuration_features.side_window_offsety = menu.add_feature("Y Offset", "autoaction_value_i", menu_configuration_features.side_window.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.side_window.offset.y = num/graphics.get_screen_height() + f.value = num + end + end + stuff.menuData.side_window.offset.y = f.value/graphics.get_screen_height() + end) + menu_configuration_features.side_window_offsety.max = graphics.get_screen_height() + menu_configuration_features.side_window_offsety.mod = 1 + menu_configuration_features.side_window_offsety.min = -graphics.get_screen_height() + menu_configuration_features.side_window_offsety.value = math.floor(stuff.menuData.side_window.offset.y*graphics.get_screen_height()) + + -- Spacing + menu_configuration_features.side_window_spacing = menu.add_feature("Spacing", "autoaction_value_i", menu_configuration_features.side_window.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.side_window.spacing = num/graphics.get_screen_height() + f.value = num + end + end + stuff.menuData.side_window.spacing = f.value/graphics.get_screen_height() + end) + menu_configuration_features.side_window_spacing.max = graphics.get_screen_height() + menu_configuration_features.side_window_spacing.mod = 1 + menu_configuration_features.side_window_spacing.min = -graphics.get_screen_height() + menu_configuration_features.side_window_spacing.value = math.floor(stuff.menuData.side_window.spacing*graphics.get_screen_height()) + + -- Padding + menu_configuration_features.side_window_padding = menu.add_feature("Padding", "autoaction_value_i", menu_configuration_features.side_window.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.side_window.padding = num/graphics.get_screen_height() + f.value = num + end + end + stuff.menuData.side_window.padding = f.value/graphics.get_screen_width() + end) + menu_configuration_features.side_window_padding.max = graphics.get_screen_width() + menu_configuration_features.side_window_padding.mod = 1 + menu_configuration_features.side_window_padding.min = -graphics.get_screen_width() + menu_configuration_features.side_window_padding.value = math.floor(stuff.menuData.side_window.padding*graphics.get_screen_width()) + + -- Width + menu_configuration_features.side_window_width = menu.add_feature("Width", "autoaction_value_i", menu_configuration_features.side_window.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.side_window.width = num/graphics.get_screen_height() + f.value = num + end + end + stuff.menuData.side_window.width = f.value/graphics.get_screen_width() + end) + menu_configuration_features.side_window_width.max = graphics.get_screen_width() + menu_configuration_features.side_window_width.mod = 1 + menu_configuration_features.side_window_width.min = -graphics.get_screen_width() + menu_configuration_features.side_window_width.value = math.floor(stuff.menuData.side_window.width*graphics.get_screen_width()) + + -- End of Player Info + + + -- Background + menu_configuration_features.backgroundparent = menu.add_feature("Background", "parent", menu_configuration_features.cheesemenuparent.id) + + menu_configuration_features.backgroundfeat = menu.add_feature("Background", "autoaction_value_str", menu_configuration_features.backgroundparent.id, function(f) + if f.str_data[f.value + 1] == "NONE" then + stuff.menuData.background_sprite.sprite = nil + else + stuff.menuData.background_sprite.sprite = f.str_data[f.value + 1] + end + end) + menu_configuration_features.backgroundfeat:set_str_data({"NONE", table.unpack(stuff.menuData.files.background)}) + + menu.add_feature("Fit background to width", "action", menu_configuration_features.backgroundparent.id, function() + if stuff.menuData.background_sprite.sprite then + stuff.menuData.background_sprite:fit_size_to_width() + end + end) + + menu_configuration_features.backgroundoffsetx = menu.add_feature("Background pos X", "autoaction_value_i", menu_configuration_features.backgroundparent.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.background_sprite.offset.x = num/graphics.get_screen_width() + f.value = num + end + end + stuff.menuData.background_sprite.offset.x = f.value/graphics.get_screen_width() + end) + menu_configuration_features.backgroundoffsetx.max = graphics.get_screen_width() + menu_configuration_features.backgroundoffsetx.mod = 1 + menu_configuration_features.backgroundoffsetx.min = -graphics.get_screen_width() + menu_configuration_features.backgroundoffsetx.value = math.floor(stuff.menuData.background_sprite.offset.x*graphics.get_screen_width()) + + menu_configuration_features.backgroundoffsety = menu.add_feature("Background pos Y", "autoaction_value_i", menu_configuration_features.backgroundparent.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.background_sprite.offset.y = num/graphics.get_screen_height() + f.value = num + end + end + stuff.menuData.background_sprite.offset.y = f.value/graphics.get_screen_height() + end) + menu_configuration_features.backgroundoffsety.max = graphics.get_screen_height() + menu_configuration_features.backgroundoffsety.mod = 1 + menu_configuration_features.backgroundoffsety.min = -graphics.get_screen_height() + menu_configuration_features.backgroundoffsety.value = math.floor(stuff.menuData.background_sprite.offset.y*graphics.get_screen_height()) + + menu_configuration_features.backgroundsize = menu.add_feature("Background Size", "autoaction_value_f", menu_configuration_features.backgroundparent.id, function(f) + stuff.menuData.background_sprite.size = f.value + end) + menu_configuration_features.backgroundsize.max = 1 + menu_configuration_features.backgroundsize.mod = 0.01 + menu_configuration_features.backgroundsize.value = stuff.menuData.background_sprite.size + + -- Footer + menu_configuration_features.footer = menu.add_feature("Footer", "parent", menu_configuration_features.cheesemenuparent.id) + + menu_configuration_features.footer_size = menu.add_feature("Footer Size", "autoaction_value_i", menu_configuration_features.footer.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.footer.footer_size = num/graphics.get_screen_height() + f.value = num + end + end + stuff.menuData.footer.footer_size = f.value/graphics.get_screen_height() + end) + menu_configuration_features.footer_size.max = graphics.get_screen_height() + menu_configuration_features.footer_size.mod = 1 + menu_configuration_features.footer_size.min = 0 + menu_configuration_features.footer_size.value = math.floor(stuff.menuData.footer.footer_size*graphics.get_screen_height()) + + menu_configuration_features.footer_y_offset = menu.add_feature("Footer Y Offset", "autoaction_value_i", menu_configuration_features.footer.id, function(f) + stuff.menuData.footer.footer_y_offset = (f.value/graphics.get_screen_height()) + end) + menu_configuration_features.footer_y_offset.max = 100 + menu_configuration_features.footer_y_offset.mod = 1 + menu_configuration_features.footer_y_offset.min = -100 + menu_configuration_features.footer_y_offset.value = math.floor(stuff.menuData.footer.footer_y_offset*graphics.get_screen_height()) + + menu_configuration_features.footerPadding = menu.add_feature("Padding", "autoaction_value_i", menu_configuration_features.footer.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.footer.padding = num/graphics.get_screen_width() + f.value = num + end + end + stuff.menuData.footer.padding = f.value/graphics.get_screen_width() + end) + menu_configuration_features.footerPadding.max = graphics.get_screen_width() + menu_configuration_features.footerPadding.mod = 1 + menu_configuration_features.footerPadding.min = -graphics.get_screen_width() + menu_configuration_features.footerPadding.value = math.floor(stuff.menuData.footer.padding*graphics.get_screen_width()) + + menu_configuration_features.draw_footer = menu.add_feature("Draw footer", "toggle", menu_configuration_features.footer.id, function(f) + stuff.menuData.footer.draw_footer = f.on + end) + menu_configuration_features.draw_footer.on = stuff.menuData.footer.draw_footer + + menu_configuration_features.footer_pos_related_to_background = menu.add_feature("Footer position based on background", "toggle", menu_configuration_features.footer.id, function(f) + stuff.menuData.footer.footer_pos_related_to_background = f.on + end) + menu_configuration_features.footer_pos_related_to_background.on = stuff.menuData.footer.footer_pos_related_to_background + + menu_configuration_features.footer_text = menu.add_feature("Footer Text", "action", menu_configuration_features.footer.id, function() + local status, text = input.get("Footer Text", "", 50, 0) + if status == 0 then + stuff.menuData.footer.footer_text = tostring(text) + end + end) + + -- Fonts + local fontStrData = { + "Menu Head", + "Menu Tab", + "Menu Entry", + "Menu Foot", + "Script 1", + "Script 2", + "Script 3", + "Script 4", + "Script 5", + } + menu_configuration_features.fonts = menu.add_feature("Fonts", "parent", menu_configuration_features.cheesemenuparent.id) + + menu_configuration_features.text_font = menu.add_feature("Text Font", "autoaction_value_str", menu_configuration_features.fonts.id, function(f) + stuff.menuData.fonts.text = f.value + end) + menu_configuration_features.text_font:set_str_data(fontStrData) + menu_configuration_features.text_font.value = stuff.menuData.fonts.text + + menu_configuration_features.footer_font = menu.add_feature("Footer Font", "autoaction_value_str", menu_configuration_features.fonts.id, function(f) + stuff.menuData.fonts.footer = f.value + end) + menu_configuration_features.footer_font:set_str_data(fontStrData) + menu_configuration_features.footer_font.value = stuff.menuData.fonts.footer + + menu_configuration_features.hint_font = menu.add_feature("Hint Font", "autoaction_value_str", menu_configuration_features.fonts.id, function(f) + stuff.menuData.fonts.hint = f.value + func.rewrap_hints(f.value) + end) + menu_configuration_features.hint_font:set_str_data(fontStrData) + menu_configuration_features.hint_font.value = stuff.menuData.fonts.hint + + -- Hotkeys + menu_configuration_features.hotkeyparent = menu.add_feature("Hotkey notifications", "parent", menu_configuration_features.cheesemenuparent.id) + + menu.add_feature("Toggle notification", "toggle", menu_configuration_features.hotkeyparent.id, function(f) + stuff.hotkey_notifications.toggle = f.on + end).on = stuff.hotkey_notifications.toggle + menu.add_feature("Action notification", "toggle", menu_configuration_features.hotkeyparent.id, function(f) + stuff.hotkey_notifications.action = f.on + end).on = stuff.hotkey_notifications.action + + -- Colors + local colorParent = menu.add_feature("Colors", "parent", menu_configuration_features.cheesemenuparent.id) + do + local tempColor = {} + for k, v in pairs(stuff.menuData.color) do + tempColor[#tempColor+1] = {k, v, sortname = k:gsub("feature_([^s])", "feature_a%1")} + --print(k:gsub("feature_([^s])", "feature_a%1")) + end + table.sort(tempColor, function(a, b) return a["sortname"] < b["sortname"] end) + + for _, v in pairs(tempColor) do + menu_configuration_features[v[1]] = {} + local vParent = menu.add_feature(v[1], "parent", colorParent.id) + + menu_configuration_features[v[1]].r = menu.add_feature("Red", "autoaction_value_i", vParent.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + f.value = num + end + end + stuff.menuData.color:set_color(v[1], f.value) + end) + menu_configuration_features[v[1]].r.max = 255 + if type(v[2]) == "table" then + menu_configuration_features[v[1]].r.value = v[2].r + else + menu_configuration_features[v[1]].r.value = func.convert_int_to_rgba(v[2], "r") + end + + menu_configuration_features[v[1]].g = menu.add_feature("Green", "autoaction_value_i", vParent.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + f.value = num + end + end + stuff.menuData.color:set_color(v[1], nil, f.value) + end) + menu_configuration_features[v[1]].g.max = 255 + if type(v[2]) == "table" then + menu_configuration_features[v[1]].g.value = v[2].g + else + menu_configuration_features[v[1]].g.value = func.convert_int_to_rgba(v[2], "g") + end + + menu_configuration_features[v[1]].b = menu.add_feature("Blue", "autoaction_value_i", vParent.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + f.value = num + end + end + stuff.menuData.color:set_color(v[1], nil, nil, f.value) + end) + menu_configuration_features[v[1]].b.max = 255 + if type(v[2]) == "table" then + menu_configuration_features[v[1]].b.value = v[2].b + else + menu_configuration_features[v[1]].b.value = func.convert_int_to_rgba(v[2], "b") + end + + menu_configuration_features[v[1]].a = menu.add_feature("Alpha", "autoaction_value_i", vParent.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + f.value = num + end + end + stuff.menuData.color:set_color(v[1], nil, nil, nil, f.value) + end) + menu_configuration_features[v[1]].a.max = 255 + if type(v[2]) == "table" then + menu_configuration_features[v[1]].a.value = v[2].a + else + menu_configuration_features[v[1]].a.value = func.convert_int_to_rgba(v[2], "a") + end + end + end + + -- loading default ui & settings + func.load_ui("default") + func.load_settings() + + --changing menu functions to ui functions + local menu_get_feature_by_hierarchy_key = menu.get_feature_by_hierarchy_key + menu_originals = setmetatable({ + --get_feature_by_hierarchy_key = menu.get_feature_by_hierarchy_key, + add_feature = menu.add_feature, + add_player_feature = menu.add_player_feature, + delete_feature = menu.delete_feature, + delete_player_feature = menu.delete_player_feature, + get_player_feature = menu.get_player_feature, + }, {__newindex = function() end}) + menu.add_feature = func.add_feature + menu.add_player_feature = func.add_player_feature + menu.delete_feature = func.delete_feature + menu.delete_player_feature = func.delete_player_feature + menu.get_player_feature = func.get_player_feature + menu.get_feature_by_hierarchy_key = function(hierarchy_key) + if string.find(hierarchy_key:lower(), "trusted") or string.find(hierarchy_key:lower(), "Proddy's Script Manager") then + return + end + local feat, duplicate + feat = menu_get_feature_by_hierarchy_key(hierarchy_key) + if feat then + return feat + else + feat, duplicate = func.get_feature_by_hierarchy_key(hierarchy_key) + if duplicate then + return feat[1] + else + return feat + end + end + end + cheeseUIdata = stuff.menuData + -- + func.set_player_feat_parent("Online Players", 0) + + func.add_feature("cheese", "action", 0).hint = "free cheese\nanother line of free cheese\nDisplays the current street you are on, as well as the intersecting street if you are in an intersection (intersection display can be disabled in the overlay settings).\n\n#FF00A2FF#Requires the [Natives] trusted mode flag to be enabled." + + -- Proddy's Script Manager + gltw.read("Trusted Flags", stuff.path.cheesemenu, stuff, true, true) + menu.is_trusted_mode_enabled = function(flag) + if not flag then + return stuff.trusted_mode & 7 == 7, stuff.trusted_mode_notification + else + return stuff.trusted_mode & flag == flag, stuff.trusted_mode_notification + end + end + + dofile("\\scripts\\cheesemenu\\libs\\Proddy's Script Manager.lua") + + do + local trusted_parent = menu_get_feature_by_hierarchy_key("local.script_features.cheese_menu.proddy_s_script_manager.trusted_mode") + + menu_originals.add_feature("Save Trusted Flags", "action", trusted_parent.id, function() + gltw.write({trusted_mode = stuff.trusted_mode, trusted_mode_notification = stuff.trusted_mode_notification}, "Trusted Flags", stuff.path.cheesemenu, nil, nil, true) + menu.notify("Saved Successfully", "Cheese Menu", 2, 0x00ff00) + end) + + menu_originals.add_feature("Trusted Flags Notification", "toggle", trusted_parent.id, function(f) + stuff.trusted_mode_notification = f.on + end).on = stuff.trusted_mode_notification + + local trusted_names = { + [0] = "Stats", + "Globals / Locals", + "Natives", + "HTTP", + "Memory" + } + + for i = 0, 4 do + menu_originals.add_feature(trusted_names[i], "toggle", trusted_parent.id, function(f) + if f.on then + stuff.trusted_mode = stuff.trusted_mode | 1 << i + else + stuff.trusted_mode = stuff.trusted_mode ~ 1 << i + end + end).on = stuff.trusted_mode & 1 << i ~= 0 + end + end + -- +end +if httpTrustedOff then + loadCurrentMenu() +end]=], + ["CheeseUtilities.lua"] = [=[--Made by GhostOne +local cheeseUtils = {} + +-- Credit to kektram for this whole function ~ a little modified to focus on fractionals +cheeseUtils.memoize = {} +do + local sign_bit_x = 1 << 62 + local sign_bit_y = 1 << 61 + local max_30_bit_num = 1073740823 + local v2 = v2 + local memoized = {} + function cheeseUtils.memoize.v2(x, y) + x = x or 0 + y = y or 0 + local xi = x * 100000000 // 1 -- modified from 1000 to 100,000,000 to support up to 10^-7 fractional digits ~ this limits it to either single or double digits with fractions + local yi = y * 100000000 // 1 -- same here + if xi >= -max_30_bit_num + and xi <= max_30_bit_num + and yi >= -max_30_bit_num + and yi <= max_30_bit_num then + local signs = 0 + if xi < 0 then + xi = xi * -1 + signs = signs | sign_bit_x + end + if yi < 0 then + yi = yi * -1 + signs = signs | sign_bit_y + end + local hash = signs | xi << 30 | yi + memoized[hash] = memoized[hash] or v2(x, y) + return memoized[hash] + else + return v2(x, y) + end + end +end +-- + +function cheeseUtils.draw_outline(v2pos, v2size, color, thickness) + local thickness_y = thickness / graphics.get_screen_height() * 2 + local thickness_x = thickness / graphics.get_screen_width() * 2 + + scriptdraw.draw_rect( + cheeseUtils.memoize.v2(v2pos.x, v2pos.y - (v2size.y/2)), + cheeseUtils.memoize.v2(v2size.x + thickness_x, thickness_y), + color + ) + + scriptdraw.draw_rect( + cheeseUtils.memoize.v2(v2pos.x, v2pos.y + (v2size.y/2)), + cheeseUtils.memoize.v2(v2size.x + thickness_x, thickness_y), + color + ) + + scriptdraw.draw_rect( + cheeseUtils.memoize.v2(v2pos.x - (v2size.x/2), v2pos.y), + cheeseUtils.memoize.v2(thickness_x, v2size.y - thickness_y), + color + ) + + scriptdraw.draw_rect( + cheeseUtils.memoize.v2(v2pos.x + (v2size.x/2), v2pos.y), + cheeseUtils.memoize.v2(thickness_x, v2size.y - thickness_y), + color + ) +end + +-- Credit to Proddy for this function +cheeseUtils.Keys = {} +function cheeseUtils.get_key(...) + local args = {...} + assert(#args > 0, "must give at least one key") + local ID = table.concat(args, "|") + if not cheeseUtils.Keys[ID] then + local key = MenuKey() + for i=1,#args do + key:push_vk(args[i]) + end + cheeseUtils.Keys[ID] = key + end + + return cheeseUtils.Keys[ID] +end + +function cheeseUtils.new_reusable_v2(limit) + limit = limit or 2 + + local counter = 1 + local v2Table = {} + for i = 1, limit do + v2Table[i] = v2() + end + + return function(x, y) + local vector2d = v2Table[counter] + counter = counter + 1 + counter = counter <= limit and counter or 1 + + vector2d.x, vector2d.y = x, y + + return vector2d + end +end + +-- Selector +do + local textv2 = v2(2, 2) + local reuse_v2 = cheeseUtils.new_reusable_v2() + + local key = { + enter = MenuKey(), + backspace = MenuKey(), + up = MenuKey(), + down = MenuKey(), + } + key.enter:push_vk(0x0D) + key.backspace:push_vk(0x08) + key.up:push_vk(0x26) + key.down:push_vk(0x28) + + local key_waits = {} + local function get_key_wait(str_key) + local vk_key = key[str_key] + if vk_key:is_down() and ((utils.time_ms() > key_waits[str_key]) or (key_waits[str_key] == 0)) then + if key_waits[str_key] == 0 then + key_waits[str_key] = utils.time_ms() + 500 + else + key_waits[str_key] = utils.time_ms() + 100 + end + return true + elseif not vk_key:is_down() then + key_waits[str_key] = 0 + end + return false + end + + --local speed_modifier = 0.5 + local function draw_selector(stuff) + while true do + local selected = stuff.selected + scriptdraw.draw_rect(reuse_v2(0, 0), textv2, 0x7D000000) + scriptdraw.draw_text(stuff.selected_str, reuse_v2(-0.02, 0), textv2, 1 / stuff.text_size_rel_to_res, 0xFFFFFFFF, 1 << 4) + + if stuff.move then + local is_going_up = stuff.move == "up" + if (is_going_up and stuff.selected - 1 >= 1) or (not is_going_up and stuff.selected + 1 <= #stuff.items) then + stuff.offset = is_going_up and stuff.offset - stuff.offset_step or stuff.offset + stuff.offset_step + stuff.size_offset = stuff.size_offset + stuff.size_step + if stuff.offset >= 0.08 or stuff.offset <= -0.08 then + stuff.offset = 0 + stuff.size_offset = 0 + stuff.next_selected = 0 + + stuff.selected = is_going_up and stuff.selected - 1 or stuff.selected + 1 + selected = stuff.selected + stuff.move = nil + end + else + stuff.move = nil + end + else + stuff.offset = 0 + stuff.size_offset = 0 + stuff.next_selected = 0 + end + + local min = selected - 5 >= 1 and selected - 5 or 1 + local max = selected + 5 <= #stuff.items and selected + 5 or #stuff.items + for i = min, max do + if stuff.items[i] then + local size = i == selected and 1.3 or 1 + size = i == stuff.next_selected and size + stuff.size_offset or i == selected and size - stuff.size_offset or size + local alpha = stuff.move == "up" and math.max(math.floor(255 - math.abs((i - selected) + math.abs(stuff.offset)/0.08)*51), 0) or math.max(math.floor(255 - math.abs((i - selected) - math.abs(stuff.offset)/0.08)*51), 0) + scriptdraw.draw_text(stuff.items[i], reuse_v2(0, 0.005 - 0.08 * (i - selected) + (stuff.offset or 0)), textv2, size / stuff.text_size_rel_to_res, (alpha << 24 | 0xFFFFFF), 0) + end + end + + controls.disable_control_action(0, 200, true) + controls.disable_control_action(0, 172, true) + controls.disable_control_action(0, 27, true) + + system.wait(0) + end + end + + -- Usage: local index, item = selector("Select Player: ", 2, {"Player 1", "Player 2", "Player 3"}) + -- if cancelled returned `index` will be false + -- `items` has to be in order and starting from 1 + function cheeseUtils.selector(selected_str, speed, index, items) + index = tonumber(index) or 1 + index = index > 1 and index or 1 + assert(type(items) == "table", "items should be a table") + local stuff = { + selected_str = selected_str and tostring(selected_str) or "Select: ", + items = items, + selected = tonumber(index) or 1, + next_selected = 0, + offset = 0, + size_offset = 0, + offset_step = 0.08/(10/(speed or 1)), + size_step = 0.3/(10/(speed or 1)), + text_size_rel_to_res = (3686400/(graphics.get_screen_width()*graphics.get_screen_height()))*0.3+0.7, + } + + local drawThread = menu.create_thread(draw_selector, stuff) + + while key.enter:is_down() do + system.wait(0) + end + + while true do + if key.enter:is_down() then + break + end + if key.backspace:is_down() then + menu.delete_thread(drawThread) + while key.backspace:is_down() do + system.wait(0) + end + return false + end + if get_key_wait("up") then + stuff.move = "up" + stuff.next_selected = stuff.selected - 1 + end + if get_key_wait("down") then + stuff.move = "down" + stuff.next_selected = stuff.selected + 1 + end + system.wait(0) + end + + while key.enter:is_down() do + system.wait(0) + end + + menu.delete_thread(drawThread) + + return stuff.selected, stuff.items[stuff.selected] + end +end +-- + +-- Draw Slider +do + local reuse_v2 = cheeseUtils.new_reusable_v2() + + function cheeseUtils.draw_slider(pos, width, min, max, value, colorBG, colorActive, colorText, draw_value) + scriptdraw.draw_rect(pos, width, colorBG) + local ActiveWidthX = width.x * ((value - min) / (max - min)) + scriptdraw.draw_rect(reuse_v2(pos.x - width.x/2 + ActiveWidthX/2, pos.y), reuse_v2(ActiveWidthX , width.y), colorActive) + + if draw_value then + local text_size = scriptdraw.get_text_size(tostring(value), 1) + local size_correction = width.y*2 / scriptdraw.size_pixel_to_rel_y(text_size.y*2) - 0.12 + text_size = text_size * size_correction + text_size.x = scriptdraw.size_pixel_to_rel_x(text_size.x) + text_size.y = scriptdraw.size_pixel_to_rel_y(text_size.y) + scriptdraw.draw_text(tostring(value), reuse_v2(pos.x - text_size.x/2, pos.y + text_size.y/2), reuse_v2(2, 2), size_correction, colorText, 0) + end + end +end + +-- Use width and height with draw_rect_ext +do + local v2r = cheeseUtils.new_reusable_v2(4) + function cheeseUtils.draw_rect_ext_wh(pos, size, color1, color2, color3, color4) + local halfWdith, halfHeight = size.x/2, size.y/2 + local Bottom = pos.y - halfHeight + local Top = pos.y + halfHeight + local Left = pos.x - halfWdith + local Right = pos.x + halfWdith + scriptdraw.draw_rect_ext(v2r(Left, Bottom), v2r(Left, Top), v2r(Right, Top), v2r(Right, Bottom), color1, color2, color3, color4) + end +end + +-- Side Window +--[[ +Usage example: + local cheeseUtils = require("CheeseUtilities") + + local window_test = cheeseUtils.new_side_window("test_header", v2(0.5, 0.5)) + + local firstField = window_test:add_field("left", "right") + + do + local timer = utils.time_ms() + 100 + window_test:add_field("idk", "1"):set_update_function(function(field) + if timer < utils.time_ms() then + timer = utils.time_ms() + 100 + local fieldValue = tonumber(field.value) + fieldValue = fieldValue + 1 + if fieldValue > 25 then + fieldValue = 1 + end + return fieldValue, fieldValue > 10 and "> 10" or "< 10" + end + end) + end + + window_test:set_position(nil, 0.2) + + window_test:set_rect_color(0xAA000000) + + menu.create_thread(function() + while true do + window_test:update() + window_test:draw() + system.wait(0) + end + end) + + menu.add_feature("hide cheese", "toggle", 0, function(f) + if f.on then + window_test:remove_field(window_test:get_field_by_name("cheese")) + firstField:set_value("right") + else + window_test:add_field("cheese", "menu", 2) + firstField:set_value("cheese enabled") + end + end).on = true +]] +do + local function draw_side_window(self) + assert( + type(self.header_text) == "string" + and type(self.fields) == "table" + and type(self.pos) == "userdata" + and type(self.rect_color) == "number" + and type(self.rect_width) == "number" + and type(self.text_spacing) == "number" + and type(self.text_padding) == "number" + and type(self.text_color) == "number", + "one or more draw_side_window args were invalid" + ) + local rect_height = (#self.fields-self.hidden_fields)*self.text_spacing - self.text_spacing + self.last_name_height + 0.02 --+0.0083--+(self.header_on and 0.07125 or 0.02) + local original_y = self.pos.y--(rect_height/2) + local header_y = original_y+self.header_height/2+rect_height/2 + local hidden_y_offset = 0 + + + scriptdraw.draw_rect(self.pos, cheeseUtils.memoize.v2(self.rect_width, rect_height), self.rect_color) + if self.header_on then + scriptdraw.draw_rect(cheeseUtils.memoize.v2(self.pos.x, header_y), cheeseUtils.memoize.v2(self.rect_width, self.header_height), self.rect_color) + end + + local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 + -- Header text + scriptdraw.draw_text(self.header_text, cheeseUtils.memoize.v2(self.pos.x - self.header_text_width/graphics.get_screen_width(), header_y+0.015), cheeseUtils.memoize.v2(2, 2), text_size, self.text_color, 0, 0) + -- table_of_lines + for id, field in ipairs(self.fields) do + if field.hidden then + hidden_y_offset = hidden_y_offset + 1 + else + local pos_y = original_y-(id-hidden_y_offset-1)*self.text_spacing+rect_height/2 - self.last_name_height/6 - 0.01 --(self.text_spacing/2.5) + scriptdraw.draw_text(field.name, cheeseUtils.memoize.v2(self.pos.x-self.rect_width/2+self.text_padding, pos_y), cheeseUtils.memoize.v2(2, 2), text_size, self.text_color, 0, 2) + scriptdraw.draw_text(field.value, cheeseUtils.memoize.v2(self.pos.x+self.rect_width/2-self.text_padding, pos_y), cheeseUtils.memoize.v2(2, 2), text_size, self.text_color, 16, 2) + end + end + end + + -- field functions + local function set_name(self, new_name) + if new_name then + if self.window.fields[#self.window.fields] == self then + local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 + self.window.last_name_height = scriptdraw.size_pixel_to_rel_y(scriptdraw.get_text_size(new_name, text_size, 0).y) + end + self.fields_by_name[self.name] = nil + self.name = tostring(new_name) or "" + self.fields_by_name[new_name] = self + end + end + + local function set_value(self, value) + if value then + self.value = tostring(value) + end + end + + local function set_update_function(self, callback) + self.update_function = callback + end + + local function update_field(self) + if self.update_function then + local value, name = self:update_function() + + self:set_value(value) + self:set_name(name) + end + end + + local function set_hidden(self, bool) + assert(type(bool) == "boolean", "hidden only accepts boolean value") + if bool ~= self.hidden then + self.hidden = bool + self.window.hidden_fields = self.window.hidden_fields + (bool and 1 or -1) + end + end + -- + + ---@class field + ---@field name string + ---@field value string + ---@field set_name function + ---@field set_value function + ---@field set_update_function function + ---@field update function + + ---@param name string + ---@param value string | number + ---@return field + local function add_field(self, name, value, pos) + local field = { + name = name, + value = value, + id = pos or #self.fields + 1, + fields_by_name = self.fields_by_name, + window = self, + hidden = false, + set_name = set_name, + set_value = set_value, + set_update_function = set_update_function, + update = update_field, + set_hidden = set_hidden + } + if pos then + local prevField = (pos - 1 > 0 and self.fields[pos-1] or true) + assert(prevField, "Fields have to be in increments of 1, for example (1, 2, 5) will not work") + if self.fields[pos] and prevField then + table.insert(self.fields, pos, field) + elseif prevField then + self.fields[pos] = field + end + else + self.fields[#self.fields + 1] = field + local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 + self.last_name_height = scriptdraw.size_pixel_to_rel_y(scriptdraw.get_text_size(name, text_size, 0).y) + end + self.fields_by_name[name] = field + + return field + end + + local function remove_field(self, field) + if field and self.fields[field.id] then + table.remove(self.fields, field.id) + self.fields_by_name[field.name] = nil + + return true + end + + return false + end + + local function get_field_by_name(self, name) + return self.fields_by_name[name] + end + + local function update(self) + for _, field in pairs(self.fields) do + field:update() + end + end + + local function set_position(self, x, y) + self.pos.x = tonumber(x) or self.pos.x + self.pos.y = tonumber(y) or self.pos.y + end + + local function set_header_text(self, text) + text = tostring(text) + self.header_text = text + self.header_on = text ~= "" + local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 + self.header_text_width = scriptdraw.get_text_size(self.header_text, text_size, 0).x + end + + local set_functions = {} + for _, field in ipairs({'text_padding', 'text_spacing', 'rect_width', 'rect_color', 'text_color'}) do + set_functions[field] = function(self, num) + num = tonumber(num) + assert(num, field.." value has to be a number") + self[field] = num + end + end + + ---@class window + ---@field draw function + ---@field update function + ---@field add_field function + ---@field remove_field function + ---@field set_position function + ---@field get_field_by_name function + ---@field set_text_padding function + ---@field set_text_spacing function + ---@field set_rect_width function + ---@field set_rect_color function + ---@field set_text_color function + ---@field set_header_text function + ---@field set_hidden function + ---@field header_text string + ---@field fields table + ---@field fields_by_name table + ---@field pos v2 + ---@field rect_color uint32_t + ---@field rect_width float + ---@field text_spacing float + ---@field text_padding float + ---@field text_color uint32_t + + ---@return window + function cheeseUtils.new_side_window(header_text, pos, rect_color, rect_width, text_spacing, text_padding, text_color) + local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 + + local window = { + header_text = header_text or "", + header_on = header_text ~= "", + fields = {}, + fields_by_name = {}, + pos = pos or v2(), + rect_color = rect_color or 0xFF000000, + rect_width = rect_width or 0.2, + text_spacing = text_spacing or 0.047, + text_padding = text_padding or 0.01, + text_color = text_color or 0xFFFFFFFF, + header_height = 0.06125, + header_text_width = scriptdraw.get_text_size(header_text, text_size, 0).x, + hidden_fields = 0, + } + + window.draw = draw_side_window + window.update = update + window.add_field = add_field + window.remove_field = remove_field + window.set_position = set_position + window.get_field_by_name = get_field_by_name + window.set_header_text = set_header_text + for name, func in pairs(set_functions) do + window['set_'..name] = func + end + + return window + end +end + + +-- Range Converter +do + local function convert_range(self, value) + return self.base_value + (value * self.step) + end + local Metatable = {__call = convert_range} + + function cheeseUtils.create_range_converter(original_range_min, original_range_max, convert_range_min, convert_range_max) + local stuff = {} + + local adjusted_max_original = original_range_max-original_range_min + local adjusted_max_convert = convert_range_max-convert_range_min + + stuff.base_value = (0-original_range_min)/adjusted_max_original*adjusted_max_convert+convert_range_min + stuff.step = (1-original_range_min)/adjusted_max_original*adjusted_max_convert+convert_range_min - stuff.base_value + + setmetatable(stuff, Metatable) + + return stuff + end +end + +-- Text Wrap +do + ---@param text string + ---@param font int + ---@param scale float + ---@param relWidth float + function cheeseUtils.wrap_text(text, font, scale, relWidth) + local spaceSize = scriptdraw.get_text_size(". .", scale, font).x - scriptdraw.get_text_size("..", scale, font).x + local lines = {} + for line, manualNewLines in text:gmatch("([^\r\n]+)([\r\n]*)") do + local newline + local lineSize = scriptdraw.get_text_size(line, scale, font) + + if scriptdraw.size_pixel_to_rel_x(lineSize.x) > relWidth then + local length = 0 + newline = {} + for word in line:gmatch("[^%s-\\,]+[%s-\\,]*") do + local relx = scriptdraw.size_pixel_to_rel_x(scriptdraw.get_text_size(word, scale, font).x) + local spaceRelx = word:gsub("%S", "") + spaceRelx = scriptdraw.size_pixel_to_rel_x(#spaceRelx*spaceSize) + if length + relx > relWidth then + --print(word, length, relx) + newline[#newline+1] = "\n" + length = 0 + end + length = length + relx + spaceRelx + newline[#newline+1] = word + end + + line = table.concat(newline) + end + + --print(line, scriptdraw.size_pixel_to_rel_x(scriptdraw.get_text_size(line, scale, font).x)) + lines[#lines+1] = line..(manualNewLines or "") + end + + return table.concat(lines) + end +end + +return cheeseUtils]=], + ["Get Input.lua"] = [=[--Made by GhostOne + +local cheeseUtils = require("cheesemenu.libs.CheeseUtilities") +local gginput = { + indicator_timer = utils.time_ms() + 750, + indicator = false, + drawStuff = { + cached_table_length = 0, + cached_text_width = 0, + } +} +gginput.char_codes = { + { + [0x30] = {"0", ")"}, + [0x31] = {"1", "!"}, + [0x32] = {"2", "@"}, + [0x33] = {"3", "#"}, + [0x34] = {"4", "$"}, + [0x35] = {"5", "%"}, + [0x36] = {"6", "^"}, + [0x37] = {"7", "&"}, + [0x38] = {"8", "*"}, + [0x39] = {"9", "("}, + [0x41] = {"a"}, + [0x42] = {"b"}, + [0x43] = {"c"}, + [0x44] = {"d"}, + [0x45] = {"e"}, + [0x46] = {"f"}, + [0x47] = {"g"}, + [0x48] = {"h"}, + [0x49] = {"i"}, + [0x4A] = {"j"}, + [0x4B] = {"k"}, + [0x4C] = {"l"}, + [0x4D] = {"m"}, + [0x4E] = {"n"}, + [0x4F] = {"o"}, + [0x50] = {"p"}, + [0x51] = {"q"}, + [0x52] = {"r"}, + [0x53] = {"s"}, + [0x54] = {"t"}, + [0x55] = {"u"}, + [0x56] = {"v"}, + [0x57] = {"w"}, + [0x58] = {"x"}, + [0x59] = {"y"}, + [0x5A] = {"z"}, + [0x60] = {"0", ")"}, + [0x61] = {"1", "!"}, + [0x62] = {"2", "@"}, + [0x63] = {"3", "#"}, + [0x64] = {"4", "$"}, + [0x65] = {"5", "%"}, + [0x66] = {"6", "^"}, + [0x67] = {"7", "&"}, + [0x68] = {"8", "*"}, + [0x69] = {"9", "("}, + [0x20] = {" "}, + [0xBA] = {";", ":"}, + [0xBB] = {"=", "+"}, + [0xBC] = {",", "<"}, + [0xBD] = {"-", "_"}, + [0xBE] = {".", ">"}, + [0xBF] = {"/", "?"}, + [0xC0] = {"`", "~"}, + [0xDB] = {"[", "{"}, + [0xDC] = {"\\", "|"}, + [0xDD] = {"]", "}"}, + [0xDE] = {"\'", "\""}, + [0x6A] = {"*"}, + [0x6B] = {"+"}, + [0x6D] = {"-"}, + [0x6E] = {"."}, + [0x6F] = {"/"} + }, + { + [0x41] = {"a"}, + [0x42] = {"b"}, + [0x43] = {"c"}, + [0x44] = {"d"}, + [0x45] = {"e"}, + [0x46] = {"f"}, + [0x47] = {"g"}, + [0x48] = {"h"}, + [0x49] = {"i"}, + [0x4A] = {"j"}, + [0x4B] = {"k"}, + [0x4C] = {"l"}, + [0x4D] = {"m"}, + [0x4E] = {"n"}, + [0x4F] = {"o"}, + [0x50] = {"p"}, + [0x51] = {"q"}, + [0x52] = {"r"}, + [0x53] = {"s"}, + [0x54] = {"t"}, + [0x55] = {"u"}, + [0x56] = {"v"}, + [0x57] = {"w"}, + [0x58] = {"x"}, + [0x59] = {"y"}, + [0x5A] = {"z"}, + }, + { + [0x41] = {"a"}, + [0x42] = {"b"}, + [0x43] = {"c"}, + [0x44] = {"d"}, + [0x45] = {"e"}, + [0x46] = {"f"}, + [0x47] = {"g"}, + [0x48] = {"h"}, + [0x49] = {"i"}, + [0x4A] = {"j"}, + [0x4B] = {"k"}, + [0x4C] = {"l"}, + [0x4D] = {"m"}, + [0x4E] = {"n"}, + [0x4F] = {"o"}, + [0x50] = {"p"}, + [0x51] = {"q"}, + [0x52] = {"r"}, + [0x53] = {"s"}, + [0x54] = {"t"}, + [0x55] = {"u"}, + [0x56] = {"v"}, + [0x57] = {"w"}, + [0x58] = {"x"}, + [0x59] = {"y"}, + [0x5A] = {"z"}, + [0x60] = {"0"}, + [0x61] = {"1"}, + [0x62] = {"2"}, + [0x63] = {"3"}, + [0x64] = {"4"}, + [0x65] = {"5"}, + [0x66] = {"6"}, + [0x67] = {"7"}, + [0x68] = {"8"}, + [0x69] = {"9"}, + [0x30] = {"0"}, + [0x31] = {"1"}, + [0x32] = {"2"}, + [0x33] = {"3"}, + [0x34] = {"4"}, + [0x35] = {"5"}, + [0x36] = {"6"}, + [0x37] = {"7"}, + [0x38] = {"8"}, + [0x39] = {"9"} + }, + { + [0xBD] = {"-"}, + [0x6D] = {"-"}, + [0x60] = {"0"}, + [0x61] = {"1"}, + [0x62] = {"2"}, + [0x63] = {"3"}, + [0x64] = {"4"}, + [0x65] = {"5"}, + [0x66] = {"6"}, + [0x67] = {"7"}, + [0x68] = {"8"}, + [0x69] = {"9"}, + [0x30] = {"0"}, + [0x31] = {"1"}, + [0x32] = {"2"}, + [0x33] = {"3"}, + [0x34] = {"4"}, + [0x35] = {"5"}, + [0x36] = {"6"}, + [0x37] = {"7"}, + [0x38] = {"8"}, + [0x39] = {"9"} + }, + { + [0xBD] = {"-"}, + [0x6D] = {"-"}, + [0x60] = {"0"}, + [0x61] = {"1"}, + [0x62] = {"2"}, + [0x63] = {"3"}, + [0x64] = {"4"}, + [0x65] = {"5"}, + [0x66] = {"6"}, + [0x67] = {"7"}, + [0x68] = {"8"}, + [0x69] = {"9"}, + [0x30] = {"0"}, + [0x31] = {"1"}, + [0x32] = {"2"}, + [0x33] = {"3"}, + [0x34] = {"4"}, + [0x35] = {"5"}, + [0x36] = {"6"}, + [0x37] = {"7"}, + [0x38] = {"8"}, + [0x39] = {"9"}, + [0x6E] = {"."}, + [0xBE] = {"."}, + }, + { + [0xBD] = {"-"}, + [0x6D] = {"-"}, + [0x60] = {"0"}, + [0x61] = {"1"}, + [0x62] = {"2"}, + [0x63] = {"3"}, + [0x64] = {"4"}, + [0x65] = {"5"}, + [0x66] = {"6"}, + [0x67] = {"7"}, + [0x68] = {"8"}, + [0x69] = {"9"}, + [0x30] = {"0"}, + [0x31] = {"1"}, + [0x32] = {"2"}, + [0x33] = {"3"}, + [0x34] = {"4"}, + [0x35] = {"5"}, + [0x36] = {"6"}, + [0x37] = {"7"}, + [0x38] = {"8"}, + [0x39] = {"9"}, + [0x6E] = {"."}, + [0xBE] = {"."}, + }, +} + +--Functions + + function gginput.do_key(key, pressed, funcPressed, ...) + if cheeseUtils.get_key(key):is_down() and ((utils.time_ms() > pressed[key]) or (pressed[key] == 0)) then + funcPressed(...) + if pressed[key] == 0 then + pressed[key] = utils.time_ms() + 500 + else + pressed[key] = utils.time_ms() + 30 + end + elseif not cheeseUtils.get_key(key):is_down() then + pressed[key] = 0 + end + end + + --[[ function gginput.draw_outline(v2pos, v2size, color, thickness, reusablePos, reusablePos2) + local thickness_y = thickness / graphics.get_screen_height() * 2 + local thickness_x = thickness / graphics.get_screen_width() * 2 + + reusablePos2.x, reusablePos2.y = v2pos.x, v2pos.y + + reusablePos2.y = v2pos.y - (v2size.y/2) + reusablePos.x, reusablePos.y = v2size.x + thickness_x, thickness_y + scriptdraw.draw_rect(reusablePos2, reusablePos, color) + + reusablePos2.y = v2pos.y + (v2size.y/2) + scriptdraw.draw_rect(reusablePos2, reusablePos, color) + + reusablePos2.y = v2pos.y + reusablePos2.x = v2pos.x - (v2size.x/2) + reusablePos.x, reusablePos.y = thickness_x, v2size.y - thickness_y + scriptdraw.draw_rect(reusablePos2, reusablePos, color) + + reusablePos2.x = v2pos.x + (v2size.x/2) + + scriptdraw.draw_rect(reusablePos2, reusablePos, color) + end ]] + + function gginput.draw_input(inputTable, bg_color, inputbox_color, outline_color, text_color, tableOfPos_Size) + if #inputTable.string ~= gginput.drawStuff.cached_table_length then + gginput.drawStuff.string = table.concat(inputTable.string) + gginput.drawStuff.indicator_string = gginput.drawStuff.string:sub(1, inputTable.cursor-1).."_"..gginput.drawStuff.string:sub(inputTable.cursor+1, #gginput.drawStuff.string) + gginput.drawStuff.cached_text_width = scriptdraw.get_text_size(gginput.drawStuff.string:sub(1, inputTable.cursor-1):gsub(" ", "."), gginput.drawStuff.text_size).x/graphics.get_screen_width()*2 + gginput.drawStuff.cached_table_length = #inputTable.string + end + local drawString = gginput.indicator and gginput.drawStuff.indicator_string or gginput.drawStuff.string + --[[ if gginput.indicator then + gginput.drawStuff.string = gginput.drawStuff.string:sub(1, inputTable.cursor-1).."_"..gginput.drawStuff.string:sub(inputTable.cursor+1, #gginput.drawStuff.string) + end ]] + + scriptdraw.draw_rect(tableOfPos_Size.middle_pos, tableOfPos_Size.backround_size, bg_color) -- background + cheeseUtils.draw_outline(tableOfPos_Size.middle_pos, tableOfPos_Size.outline_size, outline_color, 2) + scriptdraw.draw_rect(tableOfPos_Size.middle_pos, tableOfPos_Size.inputBox_size, inputbox_color) -- inputBox + scriptdraw.draw_text(drawString, tableOfPos_Size.text_pos, tableOfPos_Size.backround_size, gginput.drawStuff.text_size, text_color, 0) + scriptdraw.draw_text(inputTable.title, tableOfPos_Size.title_pos, tableOfPos_Size.backround_size, gginput.drawStuff.text_size+0.4, 0xDC000000 | (text_color & 0xFFFFFF), 0) + + tableOfPos_Size.underscore_pos.x = -0.4609375 + gginput.drawStuff.cached_text_width + 0.0015625 + scriptdraw.draw_text("_", tableOfPos_Size.underscore_pos, tableOfPos_Size.backround_size, gginput.drawStuff.text_size, 0x64000000 | (text_color & 0xFFFFFF), 0) + end + + gginput.tableOfPos_Size = { + middle_pos = v2(0, 0), + backround_size = v2(2, 2), + outline_size = v2(0.9390625, 0.06180555555555), + inputBox_size = v2(0.9375, 0.0590277777777778), + text_pos = v2(-0.4609375, 0.01111111111111111), + underscore_pos = v2(0, 0.01111111111111111), + title_pos = v2(0, 0.10555554), + } + function gginput.draw_thread(inputTable) + gginput.tableOfPos_Size.title_pos.x = -scriptdraw.get_text_size(inputTable.title, gginput.drawStuff.text_size+0.4).x/graphics.get_screen_width() + while true do + for i = 0, 357 do + controls.disable_control_action(0, i, true) + end + if utils.time_ms() > gginput.indicator_timer then + gginput.indicator = not gginput.indicator + gginput.indicator_timer = utils.time_ms() + 750 + end + gginput.draw_input(inputTable, 0x64000000, 0xC8000000, 0xC8FFFFFF, 0xC8FFFFFF, gginput.tableOfPos_Size) + system.wait(0) + end + end + + function gginput.disableESC() + while cheeseUtils.get_key(0x1B):is_down() do + controls.disable_control_action(0, 200, true) + system.wait(0) + end + controls.disable_control_action(0, 200, true) + end + + function gginput.moveCursorRight(inputTable, moveAmount) + if cheeseUtils.get_key(0x11):is_down() then + for i = inputTable.cursor+1, #inputTable.string do + if inputTable.string[i] == " " then + if i == inputTable.cursor+1 then + for i = inputTable.cursor+1, #inputTable.string do + if inputTable.string[i] ~= " " then + inputTable.cursor = i-1 + break + elseif i == #inputTable.string then + inputTable.cursor = #inputTable.string + end + end + else + inputTable.cursor = i-1 + end + break + elseif i == #inputTable.string then + inputTable.cursor = #inputTable.string + end + end + elseif not (inputTable.cursor >= #inputTable.string) then + inputTable.cursor = inputTable.cursor + moveAmount + end + gginput.drawStuff.indicator_string = gginput.drawStuff.string:sub(1, inputTable.cursor-1).."_"..gginput.drawStuff.string:sub(inputTable.cursor+1, #gginput.drawStuff.string) + gginput.drawStuff.cached_text_width = scriptdraw.get_text_size(gginput.drawStuff.string:sub(1, inputTable.cursor-1):gsub(" ", "."), gginput.drawStuff.text_size).x/graphics.get_screen_width()*2 + end + function gginput.moveCursorLeft(inputTable, moveAmount) + if cheeseUtils.get_key(0x11):is_down() then + for i = inputTable.cursor, 2, -1 do + if inputTable.string[i] == " " then + if i == inputTable.cursor then + for i = inputTable.cursor, 2, -1 do + if inputTable.string[i] ~= " " then + inputTable.cursor = i + break + elseif i == 2 then + inputTable.cursor = 1 + end + end + else + inputTable.cursor = i + end + break + elseif i == 2 then + inputTable.cursor = 1 + end + end + elseif not (inputTable.cursor <= 1) then + inputTable.cursor = inputTable.cursor - moveAmount + end + gginput.drawStuff.indicator_string = gginput.drawStuff.string:sub(1, inputTable.cursor-1).."_"..gginput.drawStuff.string:sub(inputTable.cursor+1, #gginput.drawStuff.string) + gginput.drawStuff.cached_text_width = scriptdraw.get_text_size(gginput.drawStuff.string:sub(1, inputTable.cursor-1):gsub(" ", "."), gginput.drawStuff.text_size).x/graphics.get_screen_width()*2 + end + + function gginput.write_char(keyTable, inputTable) + if cheeseUtils.get_key(0x10):is_down() then + if inputTable.cursor == #inputTable.string then + inputTable.string[#inputTable.string+1] = keyTable[2] or keyTable[1]:upper() + else + table.insert(inputTable.string, inputTable.cursor+1, keyTable[2] or keyTable[1]:upper()) + end + else + if inputTable.cursor == #inputTable.string then + inputTable.string[#inputTable.string+1] = keyTable[1] + else + table.insert(inputTable.string, inputTable.cursor+1, keyTable[1]) + end + end + + gginput.moveCursorRight(inputTable, 1) + end + + function gginput.paste(stringInput, inputTable) + stringInput = tostring(stringInput) + if inputTable.cursor == #inputTable.string then + for char in stringInput:gmatch(".") do + if #inputTable.string-1 ~= inputTable.limit then + inputTable.string[#inputTable.string+1] = char + end + end + inputTable.cursor = #inputTable.string + else + for char in stringInput:gmatch(".") do + if #inputTable.string-1 ~= inputTable.limit then + table.insert(inputTable.string, inputTable.cursor+1, char) + inputTable.cursor = inputTable.cursor+1 + end + end + end + end + + function gginput.delete_char(inputTable, range_start, range_end) + if not range_start then + gginput.moveCursorLeft(inputTable, 1) + if inputTable.cursor == #inputTable.string-1 then + inputTable.string[#inputTable.string] = nil + else + table.remove(inputTable.string, inputTable.cursor+1) + end + else + if range_end ~= #inputTable.string then + inputTable.cursor = range_start + for i = range_end, range_start+1, -1 do + table.remove(inputTable.string, i) + end + else + inputTable.cursor = range_start + for i = range_start+1, #inputTable.string do + inputTable.string[i] = i == 1 and "" or nil + end + end + end + end + + function gginput.delete(inputTable) + if cheeseUtils.get_key(0x11):is_down() then + local range_start + for i = inputTable.cursor, 1, -1 do + if inputTable.string[i] == " " then + if i == inputTable.cursor then + for i = inputTable.cursor, 1, -1 do + if inputTable.string[i] ~= " " then + range_start = i + break + end + end + else + range_start = i + end + break + elseif i == 1 then + range_start = 1 + end + end + gginput.delete_char(inputTable, range_start, inputTable.cursor) + else + gginput.delete_char(inputTable) + end + end + + local shift_esc = MenuKey() + shift_esc:push_vk(0x10) + shift_esc:push_vk(0x1B) + function gginput.reset_menu_nav() + while true do + if shift_esc:is_down() then + menu.set_menu_can_navigate(true) + menu.notify("Reset menu navigation") + break + end + system.wait(0) + end + end + + + function gginput.get_input(title, default, len, inputtype, inputTable) + local menuNavThread = menu.create_thread(gginput.reset_menu_nav) + menu.set_menu_can_navigate(false) + local pressed = {} + + for k, v in pairs(gginput.char_codes[1]) do + if cheeseUtils.get_key(k):is_down() then + pressed[k] = utils.time_ms() + 2000 + else + pressed[k] = 0 + end + end + + inputtype = tonumber(inputtype) + inputtype = (inputtype <= 5 and inputtype >= 0) and inputtype or 0 + inputtype = inputtype + 1 + local charTable = gginput.char_codes[inputtype] + local pasteCheck = {} + for k, v in pairs(charTable) do + local concatenated = table.concat(v) + pasteCheck[#pasteCheck+1] = concatenated + if concatenated ~= concatenated:upper() then + pasteCheck[#pasteCheck+1] = concatenated:upper() + end + end + pasteCheck = "[^"..table.concat(pasteCheck).."]" + + inputTable = inputTable or {} + inputTable.string = {""} + inputTable.state = 1 + inputTable.cursor = 1 + inputTable.title = tostring(title) + inputTable.limit = tonumber(len) or 25 + + gginput.paste(default, inputTable) + + gginput.drawStuff.text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.6+0.2 + + local drawThread = menu.create_thread(gginput.draw_thread, inputTable) + while cheeseUtils.get_key(0x0D):is_down() do + system.wait() + end + while not (cheeseUtils.get_key(0x0D):is_down() or cheeseUtils.get_key(0x1B):is_down()) do + for k, v in pairs(charTable) do + if not cheeseUtils.get_key(0x11):is_down() and #inputTable.string-1 ~= len then + gginput.do_key(k, pressed, gginput.write_char, v, inputTable) + end + end + + if cheeseUtils.get_key(0x11, 0x56):is_down() then + gginput.paste(utils.from_clipboard():gsub("[\r\n]", " "):gsub(pasteCheck, ""), inputTable) + while cheeseUtils.get_key(0x11, 0x56):is_down() do + system.wait() + end + elseif cheeseUtils.get_key(0x11, 0x43):is_down() then + utils.to_clipboard(table.concat(inputTable.string)) + end + + gginput.do_key(0x08, pressed, gginput.delete, inputTable) -- backspace + gginput.do_key(0x27, pressed, gginput.moveCursorRight, inputTable, 1) -- right + gginput.do_key(0x25, pressed, gginput.moveCursorLeft, inputTable, 1) -- left + system.wait(0) + end + + gginput.disableESC() + + local success = cheeseUtils.get_key(0x0D):is_down() + while cheeseUtils.get_key(0x0D):is_down() do + system.wait(0) + end + menu.delete_thread(drawThread) + menu.delete_thread(menuNavThread) + menu.set_menu_can_navigate(true) + inputTable.string = table.concat(inputTable.string) + inputTable.state = success and 0 or 2 + + gginput.drawStuff.string = "" + gginput.drawStuff.indicator_string = "" + gginput.drawStuff.cached_text_width = 0 + gginput.drawStuff.cached_table_length = 0 + + return inputTable.state, success and inputTable.string or nil + end +-- + +return gginput +]=], + ["Proddy's Script Manager.lua"] = [=[local ScriptName = "Proddy's Script Manager (CheeseMenu)" +local Version = "2.3.2" +local Exiting = false + +local Paths = {} +Paths.Root = utils.get_appdata_path("PopstarDevs", "2Take1Menu") +Paths.Cfg = Paths.Root .. "\\cfg" +Paths.LogFile = Paths.Root .. "\\" .. ScriptName .. ".log" +Paths.Scripts = Paths.Root .. "\\scripts" + +local og_loadfile = loadfile +local og__loadfile = _loadfile +local og_load = load +local og_pcall = _pcall +local io_open = io.open +local os_date = os.date +local string_format = string.format +local system_wait = system.wait + +local basePrint = print +local function print(...) + basePrint(...) + local success, result = og_pcall(function(...) + local args = {...} + if #args == 0 then + return + end + + local currTime = os_date("*t") + local file = io_open(Paths.LogFile, "a") + + for i=1,#args do + file:write(string_format("[%02d-%02d-%02d %02d:%02d:%02d] <%s> %s\n", currTime.year, currTime.month, currTime.day, currTime.hour, currTime.min, currTime.sec, Version, tostring(args[i]))) + end + + file:close() + end, ...) + if not success then + basePrint("Error writing log: " .. result) + end +end + +local notif = menu.notify +local function notify(msg, colour) + notif(msg, ScriptName .. " v" .. Version, nil, colour) + print(msg) +end + +if ProddysScriptManager then + notify(ScriptName .. " already loaded.", 0xFF50C8F0) + return +end + +--notify(ScriptName .. " v" .. Version .. " loading...") + +local function CloneTable(obj, seen) + if type(obj) ~= 'table' then + return obj + end + + if seen and seen[obj] then + return seen[obj] + end + + local s = seen or {} + local res = {} + s[obj] = res + + for k, v in pairs(obj) do + res[CloneTable(k, s)] = CloneTable(v, s) + end + + return setmetatable(res, getmetatable(obj)) --Should definitely clone the metatable +end + +local function Trim(s) + local n = s:find"%S" + return n and s:match(".*%S", n) or "" +end + +local function FileNameWithoutExtension(FileName) + local name = FileName:match("(.+)%.") + return name or FileName +end + +local ExcludedScripts = {} +ExcludedScripts["autoexec.lua"] = true +ExcludedScripts["autoexec.luac"] = true +ExcludedScripts["cheesemenu.lua"] = true +ExcludedScripts[debug.getinfo(1, "S").source:sub(Paths.Scripts:len() + 3):lower()] = true + +local Settings = {} + +function Settings.Save(SettingsFile, SettingsTbl) + assert(SettingsFile, "Nil passed for SettingsFile to Settings.Save") + assert(type(SettingsTbl) == "table", "Not a table passed for SettingsTbl to Settings.Save") + local file = io.open(Paths.Cfg .. "\\" .. SettingsFile .. ".cfg", "w") + local keys = {} + for k in pairs(SettingsTbl) do + keys[#keys + 1] = k + end + table.sort(keys) + for i=1,#keys do + file:write(tostring(keys[i]) .. "=" .. tostring(SettingsTbl[keys[i]]) .. "\n") + end + file:close() +end + +function Settings.Load(SettingsFile, SettingsTbl) + assert(SettingsFile, "Nil passed for SettingsFile to Settings.Load") + assert(type(SettingsTbl) == "table", "Not a table passed for SettingsTbl to Settings.Load") + SettingsFile = Paths.Cfg .. "\\" .. SettingsFile .. ".cfg" + if not utils.file_exists(SettingsFile) then + return false + end + for line in io.lines(SettingsFile) do + local key, value = line:match("^(.-)=(.-)$") + if key and value then + local num = tonumber(value) + if num then + value = num + elseif value == "true" then + value = true + elseif value == "false" then + value = false + end + num = tonumber(key) + if num then + key = num + end + SettingsTbl[key] = value + end + end + return true +end + +local FeatType = { + [2048] = "parent", + [1] = "toggle", + [512] = "action", + [11] = "value_i", + [131] = "value_f", + [7] = "slider", + [35] = "value_str", + [522] = "action_value_i", + [642] = "action_value_f", + [518] = "action_slider", + [546] = "action_value_str", + [1034] = "autoaction_value_i", + [1154] = "autoaction_value_f", + [1030] = "autoaction_slider", + [1058] = "autoaction_value_str", +} + +local AutoloadTbl = {} +Settings.Load(ScriptName, AutoloadTbl) + +local LoadedScripts = {} + +local add_feature = menu.add_feature +local add_player_feature = menu.add_player_feature +local delete_feature = menu.delete_feature +local delete_player_feature = menu.delete_player_feature +local create_thread = menu.create_thread +local delete_thread = menu.delete_thread + +local register_script_event_hook = hook.register_script_event_hook +local remove_script_event_hook = hook.remove_script_event_hook +local register_net_event_hook = hook.register_net_event_hook +local remove_net_event_hook = hook.remove_net_event_hook + +local add_event_listener = event.add_event_listener +local remove_event_listener = event.remove_event_listener + +local register_command = console.register_command +local remove_command = console.remove_command + +local Parent = menu_originals.add_feature("Proddy's Script Manager", "parent", menu.get_feature_by_hierarchy_key("local.script_features.cheese_menu").id) +local ParentId = Parent.id +local FirstChild +local AutoloadFirstChild +local FilterFeat + +menu_originals.add_feature("Trusted Mode", "parent", ParentId) + +local AutoloadParent = menu_originals.add_feature("Manage Autoload Scripts", "parent", ParentId) +local AutoloadParentId = AutoloadParent.id + +local assert = assert +local error = error +local type = type + +local UnloadScript + +local function DeleteFeature(Feat) + if Feat then + if Feat.type == 2048 then + for i=1,Feat.child_count do + DeleteFeature(Feat.children[1]) + end + elseif Feat.type == 1 then + if Feat.data and type(Feat.data) == "table" and Feat.data.ScriptManager then + print("Deleting script: " .. Feat.name) + UnloadScript(Feat) + print("Deleted script: " .. Feat.name) + end + end + if Feat.activate_feat_func then + delete_feature(Feat.id) + else + menu_originals.delete_feature(Feat.id) + end + end +end +local function DeletePlayerFeature(Feat) + delete_player_feature(Feat.id) +end + +UnloadScript = function(f) + if Exiting then return end + if not f.data or type(f.data) ~= "table" or not f.data.ScriptManager then return end + + print("Unloading script: " .. f.name) + + local success, result = og_pcall(function(data) + if data.exits then + for k,v in pairs(data.exits) do + v({["code"]=69}) + end + end + + if data.features then + local ids = {} + for k in pairs(data.features) do + ids[#ids + 1] = k + end + table.sort(ids) + for i = #ids,1,-1 do + DeleteFeature(data.features[ids[i]]) + end + end + + if data.player_features then + local ids = {} + for k in pairs(data.player_features) do + ids[#ids + 1] = k + end + table.sort(ids) + for i = #ids,1,-1 do + DeletePlayerFeature(data.player_features[ids[i]]) + end + end + + if data.threads then + local ids = {} + for k in pairs(data.threads) do + ids[#ids + 1] = k + end + table.sort(ids) + for i = #ids,1,-1 do + delete_thread(ids[i]) + end + end + + if data.script_hooks then + local ids = {} + for k in pairs(data.script_hooks) do + ids[#ids + 1] = k + end + table.sort(ids) + for i = #ids,1,-1 do + remove_script_event_hook(ids[i]) + end + end + + if data.net_hooks then + local ids = {} + for k in pairs(data.net_hooks) do + ids[#ids + 1] = k + end + table.sort(ids) + for i = #ids,1,-1 do + remove_net_event_hook(ids[i]) + end + end + + if data.events then + for eventName,v in pairs(data.events) do + local ids = {} + for k in pairs(v) do + ids[#ids + 1] = k + end + table.sort(ids) + for i = #ids,1,-1 do + remove_event_listener(eventName, ids[i]) + end + end + end + + if data.commands then + for name in pairs(data.commands) do + remove_command(name) + end + end + end, f.data) + + LoadedScripts[f.name] = nil + f.data = nil + f.on = false + + if success then + notify("Unloaded script: " .. f.name, 0xFF00FF00) + else + notify("Failed to unload script: " .. f.name .. "\n" .. result, 0xFF00FF00) + end + + collectgarbage("collect") +end + +-- modified +local limited_functions = { + { + namespace = "stats", + table = stats, + ["stat_set_int"] = true, + ["stat_set_float"] = true, + ["stat_set_bool"] = true, + ["stat_set_i64"] = true, + ["stat_set_u64"] = true, + ["stat_set_masked_int"] = true, + ["stat_set_masked_bool"] = true, + }, + { + namespace = "script", + table = script, + ["set_global_f"] = true, + ["set_global_i"] = true, + ["set_global_s"] = true, + ["set_local_f"] = true, + ["set_local_i"] = true, + ["set_local_s"] = true, + }, + { + namespace = "native", + table = native, + ["call"] = true, + }, + { + namespace = "web", + table = web, + ["post"] = true, + ["get"] = true, + ["request"] = true, + ["urlencode"] = true, + ["urldecode"] = true, + }, + { + namespace = "memory", + table = memory, + ["get_any"] = true, + ["get_entity"] = true, + ["get_ped"] = true, + ["get_vehicle"] = true, + ["get_object"] = true, + ["get_pickup"] = true, + ["read_u64"] = true, + ["read_u32"] = true, + ["read_u16"] = true, + ["read_u8"] = true, + ["read_i64"] = true, + ["read_i32"] = true, + ["read_i16"] = true, + ["read_i8"] = true, + ["read_f32"] = true, + }, +} + +local trusted_names = { + [0] = "Stats", + "Globals / Locals", + "Natives", + "HTTP", + "Memory" +} + +local modified_functions = { + stats = {}, + script = {}, + native = {}, + web = {}, + memory = {}, +} + +for k, v in ipairs(limited_functions) do + local namespace = v.namespace + for name, data in pairs(v) do + if data == true then + modified_functions[namespace][name] = function(...) + local is_flag_on, notify = menu.is_trusted_mode_enabled(1 << (k-1)) + if is_flag_on then + return v.table[name](...) + elseif notify then + menu.notify("Trusted Flag '"..trusted_names[k-1].."' is not enabled.\nFunction used: "..namespace..'.'..name, "Cheese Menu", 5, 0x00ffff) + end + end + end + end +end +-- + +local function LoadScript(f) + if f.on then + if not f.data then + local Filename = f.name + local Filepath = Paths.Scripts .. "\\" .. Filename + + if not utils.file_exists(Filepath) then + notify("Could not find script: " .. Filename,0xFF0000FF) + LoadedScripts[f.name] = nil + f.data = nil + f.on = false + return + end + + print("Enabling script: " .. f.name) + f.data = {} + f.data.ScriptManager = true + f.data.features = {} + f.data.player_features = {} + f.data.threads = {} + f.data.script_hooks = {} + f.data.net_hooks = {} + f.data.events = {} + f.data.exits = {} + f.data.commands = {} + + local env = CloneTable(_G) + function env.SetGlobal(Name, Value) + assert(type(Name) == "string", "Arg #1 (Name) must be a string") + + _G[Name] = Value + for i=FirstChild,Parent.child_count do + local feat = Parent.children[i] + if feat.data and feat.data.env then + feat.data.env[Name] = Value + end + end + end + + for namespace, func_table in pairs(modified_functions) do + local env_namespace = env[namespace] + for name, func in pairs(func_table) do + env_namespace[name] = func + end + end + + env.cheeseUIdata = cheeseUIdata + + env.menu.add_feature = function(...) + local feat = add_feature(...) + if feat then + f.data.features[feat.id] = feat + end + return feat + end + env.menu.add_player_feature = function(...) + local feat = add_player_feature(...) + if feat then + f.data.player_features[feat.id] = feat + end + return feat + end + env.menu.delete_feature = function(id) + local success = delete_feature(id) + if success then + f.data.features[id] = nil + end + return success + end + env.menu.delete_player_feature = function(id) + local success = delete_player_feature(id) + if success then + f.data.player_features[id] = nil + end + return success + end + env.menu.create_thread = function(...) + local id = create_thread(...) + if id then + f.data.threads[id] = true + end + return id + end + env.menu.delete_thread = function(id) + local success = delete_thread(id) + if success then + f.data.threads[id] = nil + end + return success + end + env.hook.register_script_event_hook = function(...) + local id = register_script_event_hook(...) + if id then + f.data.script_hooks[id] = true + end + return id + end + env.hook.remove_script_event_hook = function(id) + local success = remove_script_event_hook(id) + if success then + f.data.script_hooks[id] = nil + end + return success + end + env.hook.register_net_event_hook = function(...) + local id = register_net_event_hook(...) + if id then + f.data.net_hooks[id] = true + end + return id + end + env.hook.remove_net_event_hook = function(id) + local success = remove_net_event_hook(id) + if success then + f.data.net_hooks[id] = nil + end + return success + end + env.event.add_event_listener = function(eventName, callback) + local id = add_event_listener(eventName, callback) + if id then + f.data.events[eventName] = f.data.events[eventName] or {} + f.data.events[eventName][id] = true + if eventName == "exit" then + f.data.exits[id] = callback + end + end + return id + end + env.event.remove_event_listener = function(eventName, id) + local success = remove_event_listener(eventName, id) + if success and f.data.events[eventName] then + f.data.events[eventName][id] = nil + if eventName == "exit" then + f.data.exits[id] = nil + end + end + return success + end + env.console.register_command = function(name, ...) + if register_command(name, ...) then + f.data.commands[name] = true + return true + end + return false + end + env.console.remove_command = function(name) + if remove_command(name) then + for i=FirstChild,Parent.child_count do + local feat = Parent.children[i] + if feat.data and feat.data.commands then + feat.data.commands[name] = nil + end + end + return true + end + return false + end + env.load = function(chunk, chunkname, mode, env2) + return og_load(chunk, chunkname or "=(load)", mode or "bt", env2 or env) + end + env.dofile = function(filename) + return og__loadfile(filename, "bt", env)() + end + env.loadfile = function(filename, mode, env2) + return og__loadfile(filename, mode or "bt", env2 or env) + end + env._loadfile = function(filename, mode, env) + return og__loadfile(filename, mode or "bt", env or env) + end + local loaders = {} + local loaded = {} + env.require = function(Library) + assert(Library ~= nil, "You must pass a Library name") + assert(type(Library) == "string", "Library name must be a string") + if loaders[Library] then + local status, result = og_pcall(loaders[Library]) + if status then + if result == nil then + return true + else + loaded[Library] = result + return loaded[Library] + end + end + end + local libParts = {} + for part in Library:gmatch("[^.]+") do + libParts[#libParts + 1] = part + end + local subDirTbl = {} + if #libParts > 1 then + for i=1,#libParts-1 do + subDirTbl[#subDirTbl + 1] = libParts[i] + end + end + local subDir = table.concat(subDirTbl, "/") .. "/" + local lib = libParts[#libParts] + for rootDir in env.package.path:gmatch("[^;]+") do + local path = rootDir:gsub("%?", subDir .. lib) + if utils.file_exists(path) then + local chunk, err = og__loadfile(path, "bt", env) + assert(chunk, "Failed to load \"" .. Library .. "\": " .. tostring(err)) + local status, result = og_pcall(chunk) + assert(status, "Failed to exec \"" .. Library .. "\": " .. tostring(result)) + loaders[Library] = chunk + if result == nil then + return true + else + loaded[Library] = result + return loaded[Library] + end + end + end + error("Failed to find library with name \"" .. Library .. "\"") + end + env.clear_lib_cache = function(Library) + if Library then + local retVal = loaders[Library] ~= nil and loaded[Library] ~= nil + loaders[Library] = nil + loaded[Library] = nil + return retVal + else + loaders = {} + loaded = {} + return true + end + end + env.get_lib_cache = function() + local cache = {} + for k,v in pairs(loaded) do + cache[k] = v + end + return cache + end + f.data.env = env + + local chunk, err = og__loadfile(Filepath, "bt", f.data.env) + if chunk then + local status, result = og_pcall(chunk) + if not status then + menu.create_thread(UnloadScript, f) + notify("Error executing script: " .. Filename .. "\n" .. tostring(result), 0xFF0000FF) + else + notify("Loaded script: " .. Filename, 0xFF00FF00) + LoadedScripts[Filename] = true + end + else + menu.create_thread(UnloadScript, f) + notify("Error loading script: " .. Filename .. "\n" .. err, 0xFF0000FF) + end + end + else + if f.data then + menu.create_thread(UnloadScript, f) + end + end +end + +local function CaseInsensitiveSort(a, b) + return tostring(a):lower() < tostring(b):lower() +end + +local function LoadScripts(feat) + if FilterFeat then + FilterFeat.data = "" + FilterFeat.name = "Filter: " + end + + local files = utils.get_all_files_in_directory(Paths.Scripts, "lua") + local files2 = {} + for i=1,#files do + files2[files[i]] = true + end + local files3 = utils.get_all_files_in_directory(Paths.Scripts, "luac") + for i=1,#files3 do + if not files2[files3[i]] then + files[#files + 1] = files3[i] + files2[files3[i]] = true + end + end + table.sort(files, CaseInsensitiveSort) + local threads = {} + for i=Parent.child_count,FirstChild,-1 do + if not files2[Parent.children[i].name] then + threads[#threads + 1] = create_thread(DeleteFeature, Parent.children[i]) + else + files2[Parent.children[i].name] = false + Parent.children[i].hidden = false + end + end + for i=AutoloadParent.child_count,AutoloadFirstChild,-1 do + threads[#threads + 1] = create_thread(DeleteFeature, AutoloadParent.children[i]) + end + local waiting = true + while waiting do + local running = false + for i=1,#threads do + running = running or (not menu.has_thread_finished(threads[i])) + end + waiting = running + system_wait(0) + end + for i=1,#files do + if not ExcludedScripts[files[i]:lower()] then + if files2[files[i]] then + menu_originals.add_feature(files[i], "toggle", ParentId, LoadScript, f) + end + local autoloadFeat = menu_originals.add_feature(files[i], "value_i", AutoloadParentId) + autoloadFeat.min = 1 + autoloadFeat.max = 999 + autoloadFeat.mod = 1 + local val = AutoloadTbl[files[i]] + if val then + autoloadFeat.value = type(val) == "number" and val or 1 + autoloadFeat.on = true + else + autoloadFeat.value = 1 + end + end + end +end + +local ExitFeat = menu_originals.add_feature("Exit Listener", "toggle", ParentId, function(f) + if not f.on then + print("Exit Listener Feat Off") + Exiting = true + end +end) +ExitFeat.hidden = true +ExitFeat.on = true + +local delayFeat + +menu_originals.add_feature("Save Autoload Scripts", "action", AutoloadParentId, function(f) + AutoloadTbl = { + ["autoload_delay_between_scripts"] = delayFeat.value + } + for i=AutoloadFirstChild,AutoloadParent.child_count do + local child = AutoloadParent.children[i] + if child.on then + AutoloadTbl[child.name] = child.value + end + end + Settings.Save(ScriptName, AutoloadTbl) + notify("Saved autoload scripts.", 0xFF00FF00) +end) + +delayFeat = menu_originals.add_feature("Delay between scripts (ms)", "action_value_i", AutoloadParentId, function(f) + local r, s + repeat + r, s = input.get("Enter delay", f.value, 4, eInputType.IT_NUM) + if r == 2 then return HANDLER_POP end + system_wait(0) + until r == 0 + + local num = tonumber(s) + if num and num >= f.min and num <= f.max then + f.value = num + end +end) +delayFeat.min = 0 +delayFeat.max = 1000 +delayFeat.mod = 1 +local delayVal = AutoloadTbl["autoload_delay_between_scripts"] +if type(delayVal) ~= "number" or delayVal < delayFeat.min then + delayVal = delayFeat.min +elseif delayVal > delayFeat.max then + delayVal = delayFeat.max +end +delayFeat.value = delayVal + +local RefreshFeat = menu_originals.add_feature("Refresh Scripts", "action", ParentId, function(f) + LoadScripts(f) + notify("Refreshed scripts list.", 0xFF00FF00) +end) + +local function FocusFeat(f) + if f.data.parent then + f.data.parent:toggle() + end + f.data:select() +end + +local function ToggleFeat(f) + f.data:toggle() +end + +local SearchParentId = menu_originals.add_feature("Search Script Features", "parent", ParentId).id +menu_originals.add_feature("Filter: ", "action", SearchParentId, function(f) + local r, s + repeat + r, s = input.get("Enter search query", f.data, 64, 0) + if r == 2 then return HANDLER_POP end + system_wait(0) + until r == 0 + + local threads = {} + for i=f.parent.child_count,2,-1 do + threads[#threads + 1] = create_thread(DeleteFeature, f.parent.children[i]) + end + + local waiting = true + while waiting do + local running = false + for i=1,#threads do + running = running or (not menu.has_thread_finished(threads[i])) + end + waiting = running + system_wait(0) + end + + s = Trim(s) + if s:len() == 0 then + f.data = "" + f.name = "Filter: " + return HANDLER_POP + end + + local count = 0 + for i=4,RefreshFeat.parent.child_count do + local child = RefreshFeat.parent.children[i] + if child.data and child.data.features and type(child.data.features) == "table" then + for j=1,#child.data.features do + local feat = child.data.features[j] + if feat then + if feat.name:lower():find(s:lower(), 1, true) then + if feat.type == 2048 then + menu_originals.add_feature(FileNameWithoutExtension(child.name) .. " | " .. feat.name, "parent", SearchParentId, ToggleFeat).data = feat + else + menu_originals.add_feature(FileNameWithoutExtension(child.name) .. " | " .. feat.name, "action", SearchParentId, FocusFeat).data = feat + end + count = count + 1 + end + end + end + end + end + + f.data = s + f.name = "Filter: <" .. s .. "> (" .. count .. ")" +end).data = "" + +FilterFeat = menu_originals.add_feature("Filter: ", "action", ParentId, function(f) + local r, s + repeat + r, s = input.get("Enter search query", f.data, 64, 0) + if r == 2 then return HANDLER_POP end + system_wait(0) + until r == 0 + + s = Trim(s) + if s:len() == 0 then + f.data = "" + f.name = "Filter: " + for i=f.parent.child_count,FirstChild,-1 do + f.parent.children[i].hidden = false + end + return HANDLER_POP + end + + local count = 0 + for i=f.parent.child_count,FirstChild,-1 do + if f.parent.children[i].name:lower():find(s, 1, true) then + f.parent.children[i].hidden = false + count = count + 1 + else + f.parent.children[i].hidden = true + end + end + + f.data = s + f.name = "Filter: <" .. s .. "> (" .. count .. ")" +end) +FilterFeat.data = "" + +ProddysScriptManager = true + +create_thread(function(f) + FirstChild = Parent.child_count + 1 + AutoloadFirstChild = AutoloadParent.child_count + 1 + LoadScripts(f) + + local delay = 0 + local autoload = {} + for k,v in pairs(AutoloadTbl) do + if k == "autoload_delay_between_scripts" then + if type(v) == "number" and v >= 0 then + delay = v + end + else + if type(v) ~= "number" then v = 1 end + autoload[v] = autoload[v] or {} + autoload[v][#autoload[v] + 1] = k + end + end + + print("Autoloading with delay: " .. delay) + + if #autoload > 0 then + local scripts = {} + for i=FirstChild,Parent.child_count do + local feat = Parent.children[i] + scripts[feat.name] = feat + end + + local ids = {} + for k in pairs(autoload) do + ids[#ids + 1] = k + end + table.sort(ids) + + for i=1,#ids do + local tbl = autoload[ids[i]] + for j=1,#tbl do + local script = scripts[tbl[j]] + if script then + system_wait(delay) + print("Enabled autoload script: " .. script.name) + script.on = true + end + end + end + end +end, RefreshFeat) + +--notify(ScriptName .. " v" .. Version .. " loaded.", 0xFF0FF00)]=], +} \ No newline at end of file From b1dfd30b87514a6a97fc6cb3d84de28dbab17a3c Mon Sep 17 00:00:00 2001 From: GhustOne <71855034+GhustOne@users.noreply.github.com> Date: Thu, 5 Jan 2023 21:34:38 +0300 Subject: [PATCH 02/11] Update aioUpdate.lua --- aioUpdate.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aioUpdate.lua b/aioUpdate.lua index df99371..a1ee4dc 100644 --- a/aioUpdate.lua +++ b/aioUpdate.lua @@ -1,5 +1,5 @@ return { - ["GLTW.lua"] = [=[-- Made by GhostOne + ["GLTW.lua"] = [==[-- Made by GhostOne -- L00naMods "Even if you say L00na is a bitch just put my name in there somewhere" -- Ghost's Lua Table Writer --[[ @@ -112,7 +112,7 @@ function gltw.read(name, path, addToTable, typeMatched, overrideError) end return gltw -]=], +]==], ["cheesemenu.lua"] = [=[--Made by GhostOne --[[ @@ -5324,4 +5324,4 @@ create_thread(function(f) end, RefreshFeat) --notify(ScriptName .. " v" .. Version .. " loaded.", 0xFF0FF00)]=], -} \ No newline at end of file +} From f6cad506bbf28be7be753b347ece787fbb13ba6b Mon Sep 17 00:00:00 2001 From: GhustOne <71855034+GhustOne@users.noreply.github.com> Date: Thu, 5 Jan 2023 21:38:15 +0300 Subject: [PATCH 03/11] Update CMAutoUpdater.lua --- CMAutoUpdater.lua | 53 ++++++++++++++++++----------------------------- 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/CMAutoUpdater.lua b/CMAutoUpdater.lua index 0a2f401..6c2e2fd 100644 --- a/CMAutoUpdater.lua +++ b/CMAutoUpdater.lua @@ -2,42 +2,28 @@ local status = true local appdata_path = utils.get_appdata_path("PopstarDevs", "2Take1Menu") local filePaths = { - cheesemenu = appdata_path.."\\scripts\\cheesemenu.lua", - gltw = appdata_path.."\\scripts\\cheesemenu\\libs\\GLTW.lua", - getinput = appdata_path.."\\scripts\\cheesemenu\\libs\\Get Input.lua", - cheeseUtils = appdata_path.."\\scripts\\cheesemenu\\libs\\CheeseUtilities.lua", - proddysManager = appdata_path.."\\scripts\\cheesemenu\\libs\\Proddy's Script Manager.lua", -} -local files = { - cheesemenu = [[https://raw.githubusercontent.com/GhustOne/CheeseMenu/main/cheesemenu.lua]], - gltw = [[https://raw.githubusercontent.com/GhustOne/CheeseMenu/main/cheesemenu/libs/GLTW.lua]], - getinput = [[https://raw.githubusercontent.com/GhustOne/CheeseMenu/main/cheesemenu/libs/Get%20Input.lua]], - cheeseUtils = [[https://raw.githubusercontent.com/GhustOne/CheeseMenu/main/cheesemenu/libs/CheeseUtilities.lua]], - proddysManager = [[https://raw.githubusercontent.com/GhustOne/CheeseMenu/main/cheesemenu/libs/Proddy's%20Script%20Manager.lua]], + ["cheesemenu.lua"] = appdata_path.."\\scripts\\cheesemenu.lua", + ["GLTW.lua"] = appdata_path.."\\scripts\\cheesemenu\\libs\\GLTW.lua", + ["Get Input.lua"] = appdata_path.."\\scripts\\cheesemenu\\libs\\Get Input.lua", + ["CheeseUtilities.lua"] = appdata_path.."\\scripts\\cheesemenu\\libs\\CheeseUtilities.lua", + ["Proddy's Script Manager.lua"] = appdata_path.."\\scripts\\cheesemenu\\libs\\Proddy's Script Manager.lua", } -local all_files = 0 -local downloaded_files = 0 -for k, v in pairs(files) do - all_files = all_files + 1 - menu.create_thread(function() - local responseCode, file = web.get(v) - if responseCode == 200 then - files[k] = file - downloaded_files = downloaded_files + 1 - else - print("Failed to download: "..v) - status = false - end - end) +local responseCode, responseBody = web.get([[https://raw.githubusercontent.com/GhustOne/CheeseMenu/dev/aioUpdate.lua]]) +if responseCode ~= 200 then + print("Failed to download update.") + status = false end -while downloaded_files < all_files and status do - system.wait(0) +local chunk = load(responseBody) +if not chunk then + status = false + return status end +local updatedFiles = chunk() if status then - for k, v in pairs(files) do - local currentFile = io.open(filePaths[k], "a+") + for _, v in pairs(filePaths) do + local currentFile = io.open(v, "a+") if not currentFile then status = "ERROR REPLACING" break @@ -45,14 +31,15 @@ if status then currentFile:close() end if status ~= "ERROR REPLACING" then - for k, v in pairs(files) do - local currentFile = io.open(filePaths[k], "w+b") + for k, v in pairs(filePaths) do + local currentFile = io.open(v, "w+b") if currentFile then - currentFile:write(v) + currentFile:write(updatedFiles[k]) currentFile:flush() currentFile:close() else status = "ERROR REPLACING" + break end end end From 649a7e5aa7e4db9363329f2d70569d5770f2c3cc Mon Sep 17 00:00:00 2001 From: GhustOne <71855034+GhustOne@users.noreply.github.com> Date: Thu, 5 Jan 2023 22:42:57 +0300 Subject: [PATCH 04/11] v1.9 - Added feature hints - Added support for gif, 2t1 and dds headers (old gif folders still work) - Added gradient support for features (UIs will have to be edited and resaved) - Added customizable sizes for footer text and hint text - Improved hotkey activation (shouldn't activate when input box is open, will add console later) --- CHANGELOG.txt | 15 +- VERSION.txt | 2 +- cheesemenu.lua | 381 +++++++++++++++++++--------- cheesemenu/libs/CheeseUtilities.lua | 40 ++- cheesemenu/libs/GLTW.lua | 7 +- cheesemenu/ui/2take1.lua | 347 +++++++++++++------------ cheesemenu/ui/Rimurus.lua | 278 +++++++++++++------- cheesemenu/ui/cheese.lua | 347 +++++++++++++------------ 8 files changed, 890 insertions(+), 527 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 4c446da..c046884 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,9 +1,6 @@ -Moved controls, hotkey notifications, menu pos, player info to one settings file -Improved highlight function activation -Sorted Color submenu -Added Online Player Sort -Added Custom Trusted Mode for scripts loaded with Proddy's Manager -Added Proddy's Script Manager (REQUIRED TO LOAD OTHER SCRIPTS) -in Script Features > Cheese Menu > Proddy's Script Manager -v1.8.2: -Included Proddy's Script Manager in Auto updater +- Added feature hints +- Added support for gif, 2t1 and dds headers (old gif folders still work) +- Added gradient support for features (UIs will have to be edited and resaved) +- Added customizable sizes for footer text and hint text + +- Improved hotkey activation (shouldn't activate when input box is open, will add console later) diff --git a/VERSION.txt b/VERSION.txt index 53adb84..2e0e38c 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -1.8.2 +1.9 diff --git a/cheesemenu.lua b/cheesemenu.lua index 1dbe404..bf3aaea 100644 --- a/cheesemenu.lua +++ b/cheesemenu.lua @@ -24,7 +24,7 @@ ,8' ` `8.`8888. 8 888888888888 8 `Yo `Y88888P' ]] -local version = "1.8.2" +local version = "1.9" local loadCurrentMenu local httpTrustedOff @@ -145,6 +145,8 @@ function loadCurrentMenu() threads = {}, feature_by_id = {}, player_feature_by_id = {}, + feature_hints = {}, + player_feature_hints = {}, path = { scripts = utils.get_appdata_path("PopstarDevs", "2Take1Menu").."\\scripts\\" }, @@ -297,9 +299,10 @@ function loadCurrentMenu() maxDrawScroll = 0, menuData = { menuToggle = false, + menuNav = true, chatBoxOpen = false, - x = 0.5, - y = 0.44652777777, + pos_x = 0.5, + pos_y = 0.44652777777, width = 0.2, height = 0.305, border = 0.0013888, @@ -319,7 +322,8 @@ function loadCurrentMenu() }, fonts = { text = 0, - footer = 0 + footer = 0, + hint = 0 }, side_window = { on = true, @@ -328,7 +332,7 @@ function loadCurrentMenu() width = 0.3, padding = 0.01 }, - header = "cheese_menu", + header = "cheese_menu.png", feature_offset = 0.025, feature_scale = {x = 0.2, y = 0.025}, padding = { @@ -337,7 +341,10 @@ function loadCurrentMenu() value = 0.048125, slider = 0.003125, }, + text_size = (((graphics.get_screen_width()*graphics.get_screen_height())/3686400)*0.45+0.25), text_size_modifier = 1, + footer_size_modifier = 1, + hint_size_modifier = 1, text_y_offset = -0.0055555555, color = {}, files = {}, @@ -372,8 +379,14 @@ function loadCurrentMenu() slider_text = {r = 0, g = 0, b = 0, a = 255}, slider_selectedActive = {r = 255, g = 255, b = 255, a = 160}, slider_selectedBackground = {r = 255, g = 160, b = 0, a = 180}, - feature = {r = 255, g = 160, b = 0, a = 170}, - feature_selected = {r = 0, g = 0, b = 0, a = 200}, + feature_bottomLeft = {r = 255, g = 160, b = 0, a = 170}, + feature_topLeft = {r = 255, g = 160, b = 0, a = 170}, + feature_topRight = {r = 255, g = 160, b = 0, a = 170}, + feature_bottomRight = {r = 255, g = 160, b = 0, a = 170}, + feature_selected_bottomLeft = {r = 0, g = 0, b = 0, a = 200}, + feature_selected_topLeft = {r = 0, g = 0, b = 0, a = 200}, + feature_selected_topRight = {r = 0, g = 0, b = 0, a = 200}, + feature_selected_bottomRight = {r = 0, g = 0, b = 0, a = 200}, text_selected = {r = 255, g = 200, b = 0, a = 180}, text = {r = 0, g = 0, b = 0, a = 180}, border = {r = 0, g = 0, b = 0, a = 180}, @@ -390,18 +403,21 @@ function loadCurrentMenu() end stuff.menuData.background_sprite.fit_size_to_width = function(self) - self.size = stuff.menuData.width*graphics.get_screen_width()/scriptdraw.get_sprite_size(func.load_sprite(self.sprite, stuff.path.background, stuff.menuData.background_sprite.loaded_sprites)).x + self.size = stuff.menuData.width*graphics.get_screen_width()/scriptdraw.get_sprite_size(func.load_sprite(stuff.path.background..(self.sprite or ""), stuff.menuData.background_sprite.loaded_sprites)).x end stuff.menuData.background_sprite.fit_size_to_height = function(self) - self.size = stuff.menuData.height*graphics.get_screen_height()/scriptdraw.get_sprite_size(func.load_sprite(self.sprite, stuff.path.background, stuff.menuData.background_sprite.loaded_sprites)).y + self.size = stuff.menuData.height*graphics.get_screen_height()/scriptdraw.get_sprite_size(func.load_sprite(stuff.path.background..(self.sprite or ""), stuff.menuData.background_sprite.loaded_sprites)).y end + stuff.image_ext = {"gif", "bmp", "jpg", "jpeg", "png", "2t1", "dds"} stuff.menuData.files.headers = {} - for k, v in pairs(utils.get_all_files_in_directory(stuff.path.header, "png")) do - stuff.menuData.files.headers[#stuff.menuData.files.headers + 1] = v:sub(1, #v - 4) + for _, ext in pairs(stuff.image_ext) do + for _, image in pairs(utils.get_all_files_in_directory(stuff.path.header, ext)) do + stuff.menuData.files.headers[#stuff.menuData.files.headers + 1] = image + end end for k, v in pairs(utils.get_all_sub_directories_in_directory(stuff.path.header)) do - stuff.menuData.files.headers[#stuff.menuData.files.headers + 1] = v + stuff.menuData.files.headers[#stuff.menuData.files.headers + 1] = v..".ogif" end stuff.menuData.files.ui = {} @@ -410,8 +426,10 @@ function loadCurrentMenu() end stuff.menuData.files.background = {} - for k, v in pairs(utils.get_all_files_in_directory(stuff.path.background, "png")) do - stuff.menuData.files.background[k] = v:sub(1, #v - 4) + for _, ext in pairs(stuff.image_ext) do + for k, v in pairs(utils.get_all_files_in_directory(stuff.path.background, "png")) do + stuff.menuData.files.background[k] = v + end end stuff.menuData_methods = { @@ -574,8 +592,11 @@ function loadCurrentMenu() end elseif k == "children" and t.type >> 11 & 1 ~= 0 then return t:get_children() - else - return stuff.rawget(t, k) + elseif k == "hint" then + local hintTable = t.type >> 15 & 1 ~= 0 and stuff.player_feature_hints or stuff.feature_hints + return hintTable[t.id].str + --[[ else + return stuff.rawget(t, k) ]] end end, @@ -682,6 +703,15 @@ function loadCurrentMenu() t.feats[i].real_data = v end end + elseif k == "hint" then + local hintTable = t.type >> 15 & 1 ~= 0 and stuff.player_feature_hints or stuff.feature_hints + if not v then + hintTable[t.id] = nil + return + end + assert(type(v) == "string", "Feat.hint only supports strings") + local str = cheeseUtils.wrap_text(v, stuff.menuData.fonts.hint, stuff.menuData.text_size * stuff.menuData.hint_size_modifier, stuff.menuData.width*2-scriptdraw.size_pixel_to_rel_x(25)) + hintTable[t.id] = {str = str, size = scriptdraw.get_text_size(str, 1, stuff.menuData.fonts.hint), original = v} else stuff.rawset(t, k, v) end @@ -1327,6 +1357,9 @@ function loadCurrentMenu() end local index = feat.index + if not bool_ps then + stuff.feature_hints[index] = nil + end table.remove(parent, tonumber(feat.index)) --func.check_scroll(index, parent, true) @@ -1343,6 +1376,7 @@ function loadCurrentMenu() id = id.id end + stuff.player_feature_hints[id] = nil local feat = stuff.player_feature_by_id[id] if not feat then @@ -1396,19 +1430,18 @@ function loadCurrentMenu() end end - stuff.image_ext = {"gif", "bmp", "jpg", "jpeg", "png"} stuff.header_ids = {} - function func.load_sprite(name, path, id_table) - path = path or stuff.path.header + function func.load_sprite(path_to_file, id_table) + --path = path or stuff.path.header id_table = id_table or stuff.header_ids - name = tostring(name) - assert(name, "invalid name") + path_to_file = tostring(path_to_file) + assert(path_to_file, "invalid name") - name = name:gsub("%.[a-z]+$", "") + --name = name:gsub("%.[a-z]+$", "") - if not id_table[name] then - if utils.dir_exists(path..name) then - local path = path..name.."\\" + if not id_table[path_to_file] then + if utils.dir_exists(path_to_file:gsub("%.ogif", "")) and path_to_file:find("%.ogif") then + local path = path_to_file:gsub("%.ogif", "").."\\" local images for _, v in pairs(stuff.image_ext) do @@ -1420,15 +1453,15 @@ function loadCurrentMenu() return end - id_table[name] = {} + id_table[path_to_file] = {} for i, e in pairs(images) do - id_table[name][i] = {} - id_table[name][i].sprite = scriptdraw.register_sprite(path..e) - id_table[name][i].delay = e:match("%d+_(%d+)") + id_table[path_to_file][i] = {} + id_table[path_to_file][i].sprite = scriptdraw.register_sprite(path..e) + id_table[path_to_file][i].delay = e:match("%d+_(%d+)") end - id_table[name].constant_delay = utils.get_all_files_in_directory(path, "txt")[1] - if not id_table[name].constant_delay then + id_table[path_to_file].constant_delay = utils.get_all_files_in_directory(path, "txt")[1] + if not id_table[path_to_file].constant_delay then for k, v in pairs(images) do if not v:match("%d+_(%d+)") then menu.notify("FPS file not found and frames are not in format, create a txt file with the framerate of the gif.\nExample: '25 fps.txt'", "Cheese Menu", 5, 0x0000FF) @@ -1436,21 +1469,23 @@ function loadCurrentMenu() end end else - id_table[name].constant_delay = math.floor(1000 / tonumber(id_table[name].constant_delay:match("(%d*%.*%d+)%s+fps"))) + id_table[path_to_file].constant_delay = math.floor(1000 / tonumber(id_table[path_to_file].constant_delay:match("(%d*%.*%d+)%s+fps"))) end - elseif utils.file_exists(path..name..".png") then - id_table[name] = scriptdraw.register_sprite(path..name..".png") + elseif utils.file_exists(path_to_file) then + id_table[path_to_file] = scriptdraw.register_sprite(path_to_file) end end - return id_table[name] + return id_table[path_to_file] end function func.toggle_menu(bool) stuff.menuData.menuToggle = bool if stuff.menuData.menuToggle then - currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() + if currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then + currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() + end end end @@ -1469,11 +1504,25 @@ function loadCurrentMenu() func.toggle_menu(originalmenuToggle) end + function func.rewrap_hint(hintTable, font, padding) + hintTable.str = cheeseUtils.wrap_text(hintTable.original, font, stuff.menuData.text_size * stuff.menuData.hint_size_modifier, stuff.menuData.width*2-padding) + hintTable.size = scriptdraw.get_text_size(hintTable.str, 1, font) + end + + function func.rewrap_hints(font) + local padding = scriptdraw.size_pixel_to_rel_x(25) + for _, hintTable in pairs(stuff.feature_hints) do + func.rewrap_hint(hintTable, font, padding) + end + for _, hintTable in pairs(stuff.player_feature_hints) do + func.rewrap_hint(hintTable, font, padding) + end + end function func.save_settings() gltw.write({ - x = stuff.menuData.x, - y = stuff.menuData.y, + x = stuff.menuData.pos_x, + y = stuff.menuData.pos_y, side_window = stuff.menuData.side_window, controls = stuff.controls, hotkey_notifications = stuff.hotkey_notifications, @@ -1485,8 +1534,8 @@ function loadCurrentMenu() function func.load_settings() local settings = gltw.read("Settings", stuff.path.cheesemenu, nil, nil, true) if settings then - stuff.menuData.x = settings.x - stuff.menuData.y = settings.y + stuff.menuData.pos_x = settings.x + stuff.menuData.pos_y = settings.y stuff.menuData.selector_speed = settings.selector_speed stuff.player_submenu_sort = settings.player_submenu_sort @@ -1503,8 +1552,8 @@ function loadCurrentMenu() stuff.vkcontrols[k] = stuff.char_codes[v] end - menu_configuration_features.menuXfeat.value = math.floor(stuff.menuData.x*graphics.get_screen_width()) - menu_configuration_features.menuYfeat.value = math.floor(stuff.menuData.y*graphics.get_screen_height()) + menu_configuration_features.menuXfeat.value = math.floor(stuff.menuData.pos_x*graphics.get_screen_width()) + menu_configuration_features.menuYfeat.value = math.floor(stuff.menuData.pos_y*graphics.get_screen_height()) menu_configuration_features.player_submenu_sort.value = stuff.player_submenu_sort menu_configuration_features.player_submenu_sort:toggle() menu_configuration_features.side_window_offsetx.value = math.floor(stuff.menuData.side_window.offset.x*graphics.get_screen_width()) @@ -1518,7 +1567,7 @@ function loadCurrentMenu() end function func.save_ui(name) - gltw.write(stuff.menuData, name, stuff.path.ui, {"menuToggle", "loaded_sprites", "files", "x", "y", "side_window", "selector_speed"}) + gltw.write(stuff.menuData, name, stuff.path.ui, {"menuToggle", "menuNav", "loaded_sprites", "files", "pos_x", "pos_y", "side_window", "selector_speed", "chatBoxOpen"}) end function func.load_ui(name) @@ -1537,8 +1586,8 @@ function loadCurrentMenu() menu_configuration_features.backgroundfeat:toggle() end - --[[ menu_configuration_features.menuXfeat.value = math.floor(stuff.menuData.x*graphics.get_screen_width()) - menu_configuration_features.menuYfeat.value = math.floor(stuff.menuData.y*graphics.get_screen_height()) ]] + --[[ menu_configuration_features.menuXfeat.value = math.floor(stuff.menuData.pos_x*graphics.get_screen_width()) + menu_configuration_features.menuYfeat.value = math.floor(stuff.menuData.pos_y*graphics.get_screen_height()) ]] menu_configuration_features.maxfeats.value = math.floor(stuff.menuData.max_features) menu_configuration_features.menuWidth.value = math.floor(stuff.menuData.width*graphics.get_screen_width()) menu_configuration_features.featXfeat.value = math.floor(stuff.menuData.feature_scale.x*graphics.get_screen_width()) @@ -1552,6 +1601,8 @@ function loadCurrentMenu() menu_configuration_features.sliderHeight.value = math.floor(stuff.menuData.slider.height*graphics.get_screen_height()) menu_configuration_features.sliderheightActive.value = math.floor(stuff.menuData.slider.heightActive*graphics.get_screen_height()) menu_configuration_features.text_size.value = stuff.menuData.text_size_modifier + menu_configuration_features.footer_size.value = stuff.menuData.footer_size_modifier + menu_configuration_features.hint_size.value = stuff.menuData.hint_size_modifier menu_configuration_features.text_y_offset.value = -math.floor(stuff.menuData.text_y_offset*graphics.get_screen_height()) stuff.drawFeatParams.textOffset.y = stuff.menuData.text_y_offset menu_configuration_features.footer_y_offset.value = math.floor(stuff.menuData.footer.footer_y_offset*graphics.get_screen_height()) @@ -1571,18 +1622,23 @@ function loadCurrentMenu() menu_configuration_features.side_window_on.on = stuff.menuData.side_window.on ]] menu_configuration_features.text_font.value = stuff.menuData.fonts.text menu_configuration_features.footer_font.value = stuff.menuData.fonts.footer + menu_configuration_features.hint_font.value = stuff.menuData.fonts.hint + + menu_configuration_features.hint_font:toggle() for k, v in pairs(stuff.menuData.color) do - if type(v) == "table" then - menu_configuration_features[k].r.value = v.r - menu_configuration_features[k].g.value = v.g - menu_configuration_features[k].b.value = v.b - menu_configuration_features[k].a.value = v.a - else - menu_configuration_features[k].r.value = func.convert_int_to_rgba(v, "r") - menu_configuration_features[k].g.value = func.convert_int_to_rgba(v, "g") - menu_configuration_features[k].b.value = func.convert_int_to_rgba(v, "b") - menu_configuration_features[k].a.value = func.convert_int_to_rgba(v, "a") + if menu_configuration_features[k] then + if type(v) == "table" then + menu_configuration_features[k].r.value = v.r + menu_configuration_features[k].g.value = v.g + menu_configuration_features[k].b.value = v.b + menu_configuration_features[k].a.value = v.a + else + menu_configuration_features[k].r.value = func.convert_int_to_rgba(v, "r") + menu_configuration_features[k].g.value = func.convert_int_to_rgba(v, "g") + menu_configuration_features[k].b.value = func.convert_int_to_rgba(v, "b") + menu_configuration_features[k].a.value = func.convert_int_to_rgba(v, "a") + end end end @@ -1603,34 +1659,54 @@ function loadCurrentMenu() end stuff.drawFeatParams = { - rectPos = v2(stuff.menuData.x, stuff.menuData.y - stuff.menuData.feature_offset/2 + stuff.menuData.border), + rectPos = v2(stuff.menuData.pos_x, stuff.menuData.pos_y - stuff.menuData.feature_offset/2 + stuff.menuData.border), textOffset = v2(stuff.menuData.feature_scale.x/2, -0.0055555555), colorText = stuff.menuData.color.text, - colorFeature = stuff.menuData.color.feature, textSize = 0, - featV2_pos = v2(), - featV2_size = v2(), } - function func.draw_feat(k, v, offset, hiddenOffset, textSize) - stuff.drawFeatParams.rectPos.x = stuff.menuData.x - stuff.drawFeatParams.rectPos.y = stuff.menuData.y - stuff.menuData.feature_offset/2 + stuff.menuData.border + function func.draw_feat(k, v, offset, hiddenOffset) + --[[ stuff.drawFeatParams.rectPos.x = stuff.menuData.pos_x + stuff.drawFeatParams.rectPos.y = stuff.menuData.pos_y - stuff.menuData.feature_offset/2 + stuff.menuData.border stuff.drawFeatParams.textOffset.x = stuff.menuData.feature_scale.x/2 + stuff.drawFeatParams.textSize = textSize ]] stuff.drawFeatParams.colorText = stuff.menuData.color.text - stuff.drawFeatParams.colorFeature = stuff.menuData.color.feature - stuff.drawFeatParams.textSize = textSize + stuff.drawFeatParams.bottomLeft = stuff.menuData.color.feature_bottomLeft + stuff.drawFeatParams.topLeft = stuff.menuData.color.feature_topLeft + stuff.drawFeatParams.topRight = stuff.menuData.color.feature_topRight + stuff.drawFeatParams.bottomRight = stuff.menuData.color.feature_bottomRight + local posY = (stuff.drawFeatParams.rectPos.y + (stuff.menuData.feature_offset * k))*-2+1 local is_selected if stuff.scroll == k + stuff.drawScroll then stuff.scrollHiddenOffset = hiddenOffset or stuff.scrollHiddenOffset stuff.drawFeatParams.colorText = stuff.menuData.color.text_selected - stuff.drawFeatParams.colorFeature = stuff.menuData.color.feature_selected + stuff.drawFeatParams.bottomLeft = stuff.menuData.color.feature_selected_bottomLeft + stuff.drawFeatParams.topLeft = stuff.menuData.color.feature_selected_topLeft + stuff.drawFeatParams.topRight = stuff.menuData.color.feature_selected_topRight + stuff.drawFeatParams.bottomRight = stuff.menuData.color.feature_selected_bottomRight is_selected = true end if offset == 0 then - scriptdraw.draw_rect( - cheeseUtils.memoize.v2(stuff.drawFeatParams.rectPos.x*2-1, (stuff.drawFeatParams.rectPos.y + (stuff.menuData.feature_offset * k))*-2+1), + local memv2 = cheeseUtils.memoize.v2 + local posX = stuff.drawFeatParams.rectPos.x*2-1 + --[[ scriptdraw.draw_rect( + cheeseUtils.memoize.v2(posX, posY), cheeseUtils.memoize.v2(stuff.menuData.feature_scale.x*2, stuff.menuData.feature_scale.y*2), func.convert_rgba_to_int(stuff.drawFeatParams.colorFeature.r, stuff.drawFeatParams.colorFeature.g, stuff.drawFeatParams.colorFeature.b, stuff.drawFeatParams.colorFeature.a) + ) ]] + local Left = posX - stuff.menuData.feature_scale.x + local Right = posX + stuff.menuData.feature_scale.x + local Top = posY + stuff.menuData.feature_scale.y + local Bottom = posY - stuff.menuData.feature_scale.y + scriptdraw.draw_rect_ext( + memv2(Left, Bottom), + memv2(Left, Top), + memv2(Right, Top), + memv2(Right, Bottom), + func.convert_rgba_to_int(stuff.drawFeatParams.bottomLeft.r, stuff.drawFeatParams.bottomLeft.g, stuff.drawFeatParams.bottomLeft.b, stuff.drawFeatParams.bottomLeft.a), + func.convert_rgba_to_int(stuff.drawFeatParams.topLeft.r, stuff.drawFeatParams.topLeft.g, stuff.drawFeatParams.topLeft.b, stuff.drawFeatParams.topLeft.a), + func.convert_rgba_to_int(stuff.drawFeatParams.topRight.r, stuff.drawFeatParams.topRight.g, stuff.drawFeatParams.topRight.b, stuff.drawFeatParams.topRight.a), + func.convert_rgba_to_int(stuff.drawFeatParams.bottomRight.r, stuff.drawFeatParams.bottomRight.g, stuff.drawFeatParams.bottomRight.b, stuff.drawFeatParams.bottomRight.a) ) end @@ -1656,14 +1732,14 @@ function loadCurrentMenu() end elseif v.type & 1 ~= 0 then -- toggle cheeseUtils.draw_outline( - cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x - (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.name) + 0.00390625)*2-1, (stuff.drawFeatParams.rectPos.y + (stuff.menuData.feature_offset * k))*-2+1), + cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x - (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.name) + 0.00390625)*2-1, posY), cheeseUtils.memoize.v2(0.015625, 0.0277777777778), func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a), 2 ) if v.real_on then scriptdraw.draw_rect( - cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x - (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.name) + 0.00390625)*2-1, (stuff.drawFeatParams.rectPos.y + (stuff.menuData.feature_offset * k))*-2+1), + cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x - (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.name) + 0.00390625)*2-1, posY), cheeseUtils.memoize.v2(0.0140625, 0.025), func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a) ) @@ -1690,7 +1766,7 @@ function loadCurrentMenu() cheeseUtils.draw_slider( cheeseUtils.memoize.v2( (stuff.drawFeatParams.rectPos.x + stuff.menuData.feature_scale.x/2 - stuff.menuData.slider.width/4 - stuff.menuData.padding.slider)*2-1, - (stuff.drawFeatParams.rectPos.y + (stuff.menuData.feature_offset * k))*-2+1 + posY ), cheeseUtils.memoize.v2(stuff.menuData.slider.width, is_selected and stuff.menuData.slider.heightActive or stuff.menuData.slider.height), v.min, v.max, v.value, @@ -1724,7 +1800,7 @@ function loadCurrentMenu() stuff.draw_current_menu = {frameCounter = 1, time = utils.time_ms() + 33, currentSprite = stuff.menuData.header} function func.draw_current_menu() - local sprite = func.load_sprite(stuff.menuData.header) + local sprite = func.load_sprite(stuff.path.header..(stuff.menuData.header or "")) if stuff.draw_current_menu.currentSprite ~= stuff.menuData.header then stuff.draw_current_menu.currentSprite = stuff.menuData.header stuff.draw_current_menu.time = 0 @@ -1741,17 +1817,18 @@ function loadCurrentMenu() end end end - if stuff.menuData.background_sprite.sprite and func.load_sprite(stuff.menuData.background_sprite.sprite, stuff.path.background) then + local background_sprite_path = stuff.path.background..(stuff.menuData.background_sprite.sprite or "") + if stuff.menuData.background_sprite.sprite and func.load_sprite(background_sprite_path) then scriptdraw.draw_sprite( - func.load_sprite(stuff.menuData.background_sprite.sprite, stuff.path.background), - cheeseUtils.memoize.v2((stuff.menuData.x + stuff.menuData.background_sprite.offset.x)*2-1, (stuff.menuData.y+stuff.menuData.background_sprite.offset.y+stuff.menuData.height/2+0.01458)*-2+1), + func.load_sprite(background_sprite_path), + cheeseUtils.memoize.v2((stuff.menuData.pos_x + stuff.menuData.background_sprite.offset.x)*2-1, (stuff.menuData.pos_y+stuff.menuData.background_sprite.offset.y+stuff.menuData.height/2+0.01458)*-2+1), stuff.menuData.background_sprite.size, 0, func.convert_rgba_to_int(255, 255, 255, stuff.menuData.color.background.a) ) else scriptdraw.draw_rect( - cheeseUtils.memoize.v2(stuff.menuData.x*2-1, (stuff.menuData.y+stuff.menuData.border+stuff.menuData.height/2)*-2+1), + cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, (stuff.menuData.pos_y+stuff.menuData.border+stuff.menuData.height/2)*-2+1), cheeseUtils.memoize.v2(stuff.menuData.width*2, stuff.menuData.height*2), func.convert_rgba_to_int(stuff.menuData.color.background.r, stuff.menuData.color.background.g, stuff.menuData.color.background.b, stuff.menuData.color.background.a) ) @@ -1771,17 +1848,25 @@ function loadCurrentMenu() end -- header border - scriptdraw.draw_rect(cheeseUtils.memoize.v2(stuff.menuData.x*2-1, (stuff.menuData.y + stuff.menuData.border/2)*-2+1), cheeseUtils.memoize.v2(stuff.menuData.width*2, stuff.menuData.border*2), func.convert_rgba_to_int(stuff.menuData.color.border.r, stuff.menuData.color.border.g, stuff.menuData.color.border.b, stuff.menuData.color.border.a)) + scriptdraw.draw_rect(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, (stuff.menuData.pos_y + stuff.menuData.border/2)*-2+1), cheeseUtils.memoize.v2(stuff.menuData.width*2, stuff.menuData.border*2), func.convert_rgba_to_int(stuff.menuData.color.border.r, stuff.menuData.color.border.g, stuff.menuData.color.border.b, stuff.menuData.color.border.a)) local hiddenOffset = 0 local drawnfeats = 0 - local text_size = (((graphics.get_screen_width()*graphics.get_screen_height())/3686400)*0.45+0.25) * stuff.menuData.text_size_modifier + stuff.menuData.text_size = (((graphics.get_screen_width()*graphics.get_screen_height())/3686400)*0.45+0.25) -- * stuff.menuData.text_size_modifier + + stuff.drawFeatParams.rectPos.x = stuff.menuData.pos_x + stuff.drawFeatParams.rectPos.y = stuff.menuData.pos_y - stuff.menuData.feature_offset/2 + stuff.menuData.border + stuff.drawFeatParams.textOffset.x = stuff.menuData.feature_scale.x/2 + stuff.drawFeatParams.colorText = stuff.menuData.color.text + stuff.drawFeatParams.colorFeature = stuff.menuData.color.feature + stuff.drawFeatParams.textSize = stuff.menuData.text_size * stuff.menuData.text_size_modifier + for k, v in ipairs(currentMenu) do if type(k) == "number" then if v.hidden or (v.type >> 11 & 1 ~= 0 and not v.on) then hiddenOffset = hiddenOffset + 1 elseif k <= stuff.drawScroll + hiddenOffset + stuff.menuData.max_features and k >= stuff.drawScroll + hiddenOffset + 1 then - func.draw_feat(k - stuff.drawScroll - hiddenOffset, v, 0, hiddenOffset, text_size) + func.draw_feat(k - stuff.drawScroll - hiddenOffset, v, 0, hiddenOffset) drawnfeats = drawnfeats + 1 end end @@ -1791,25 +1876,67 @@ function loadCurrentMenu() -- footer border local footer_border_y_pos if stuff.menuData.footer.footer_pos_related_to_background then - footer_border_y_pos = (stuff.menuData.y + stuff.menuData.height + stuff.menuData.border*1.5)*-2+1 + footer_border_y_pos = (stuff.menuData.pos_y + stuff.menuData.height + stuff.menuData.border*1.5)*-2+1 else - footer_border_y_pos = (stuff.menuData.y + (drawnfeats*stuff.menuData.feature_offset) + stuff.menuData.border*1.5)*-2+1 + footer_border_y_pos = (stuff.menuData.pos_y + (drawnfeats*stuff.menuData.feature_offset) + stuff.menuData.border*1.5)*-2+1 end - scriptdraw.draw_rect(cheeseUtils.memoize.v2(stuff.menuData.x*2-1, footer_border_y_pos), cheeseUtils.memoize.v2(stuff.menuData.width*2, stuff.menuData.border*2), func.convert_rgba_to_int(stuff.menuData.color.border.r, stuff.menuData.color.border.g, stuff.menuData.color.border.b, stuff.menuData.color.border.a)) + scriptdraw.draw_rect(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, footer_border_y_pos), cheeseUtils.memoize.v2(stuff.menuData.width*2, stuff.menuData.border*2), func.convert_rgba_to_int(stuff.menuData.color.border.r, stuff.menuData.color.border.g, stuff.menuData.color.border.b, stuff.menuData.color.border.a)) -- footer and text/scroll + local footerColor = func.convert_rgba_to_int(stuff.menuData.color.footer.r, stuff.menuData.color.footer.g, stuff.menuData.color.footer.b, stuff.menuData.color.footer.a) local footer_y_pos if stuff.menuData.footer.footer_pos_related_to_background then - footer_y_pos = (stuff.menuData.y + stuff.menuData.height + stuff.menuData.border*2 + stuff.menuData.footer.footer_size/2)*-2+1 + footer_y_pos = (stuff.menuData.pos_y + stuff.menuData.height + stuff.menuData.border*2 + stuff.menuData.footer.footer_size/2)*-2+1 else - footer_y_pos = (stuff.menuData.y + (drawnfeats*stuff.menuData.feature_offset) + stuff.menuData.border*2 + stuff.menuData.footer.footer_size/2)*-2+1 + footer_y_pos = (stuff.menuData.pos_y + (drawnfeats*stuff.menuData.feature_offset) + stuff.menuData.border*2 + stuff.menuData.footer.footer_size/2)*-2+1 + end + scriptdraw.draw_rect(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, footer_y_pos), cheeseUtils.memoize.v2(stuff.menuData.width*2, stuff.menuData.footer.footer_size*2), footerColor) + + local footerTextColor = func.convert_rgba_to_int(stuff.menuData.color.footer_text.r, stuff.menuData.color.footer_text.g, stuff.menuData.color.footer_text.b, stuff.menuData.color.footer_text.a) + local feat = currentMenu[stuff.scroll + stuff.scrollHiddenOffset] + local featHint = feat.type >> 15 & 1 ~= 0 and stuff.player_feature_hints[feat.id] or stuff.feature_hints[feat.id] + if featHint then + local padding = scriptdraw.size_pixel_to_rel_y(5) + local hintStrSize = scriptdraw.size_pixel_to_rel_y(featHint.size.y) * (stuff.menuData.text_size * stuff.menuData.hint_size_modifier) + local posY = footer_y_pos - stuff.menuData.border*2 - stuff.menuData.footer.footer_size - padding + local textY = posY - padding + posY = posY - hintStrSize/2 + + local rectHeight = hintStrSize+padding*4 + --scriptdraw.draw_rect(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, posY+rectHalfHeight/2), cheeseUtils.memoize.v2(stuff.menuData.width*2, rectHalfHeight), func.convert_rgba_to_int(stuff.menuData.color.footer.r, stuff.menuData.color.footer.g, stuff.menuData.color.footer.b, stuff.menuData.color.footer.a)) + cheeseUtils.draw_rect_ext_wh(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, posY-padding), cheeseUtils.memoize.v2(stuff.menuData.width*2, rectHeight), (footerColor & 0xffffff) | 50 << 24, footerColor, footerColor, (footerColor & 0xffffff) | 50 << 24) + scriptdraw.draw_text( + featHint.str, + cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1 - stuff.menuData.width + padding, textY), + cheeseUtils.memoize.v2(stuff.menuData.width+padding*2, 2), + stuff.menuData.text_size * stuff.menuData.hint_size_modifier, + footerTextColor, + 0, + stuff.menuData.fonts.hint + ) end - scriptdraw.draw_rect(cheeseUtils.memoize.v2(stuff.menuData.x*2-1, footer_y_pos), cheeseUtils.memoize.v2(stuff.menuData.width*2, stuff.menuData.footer.footer_size*2), func.convert_rgba_to_int(stuff.menuData.color.footer.r, stuff.menuData.color.footer.g, stuff.menuData.color.footer.b, stuff.menuData.color.footer.a)) + local footer_size = stuff.menuData.text_size * stuff.menuData.footer_size_modifier local text_y_pos = footer_y_pos + 0.011111111 + stuff.menuData.footer.footer_y_offset - scriptdraw.draw_text(tostring(stuff.menuData.footer.footer_text), cheeseUtils.memoize.v2((stuff.menuData.x - stuff.menuData.width/2 + stuff.menuData.footer.padding)*2-1, text_y_pos), cheeseUtils.memoize.v2(2, 2), text_size, func.convert_rgba_to_int(stuff.menuData.color.footer_text.r, stuff.menuData.color.footer_text.g, stuff.menuData.color.footer_text.b, stuff.menuData.color.footer_text.a), 0, stuff.menuData.fonts.footer) + scriptdraw.draw_text( + tostring(stuff.menuData.footer.footer_text), + cheeseUtils.memoize.v2((stuff.menuData.pos_x - stuff.menuData.width/2 + stuff.menuData.footer.padding)*2-1, text_y_pos), + cheeseUtils.memoize.v2(2, 2), + footer_size, + footerTextColor, + 0, + stuff.menuData.fonts.footer + ) - scriptdraw.draw_text(tostring(stuff.scroll.." / "..(#currentMenu - stuff.drawHiddenOffset)), cheeseUtils.memoize.v2((stuff.menuData.x + stuff.menuData.width/2 - stuff.menuData.footer.padding)*2-1, text_y_pos), cheeseUtils.memoize.v2(2, 2), text_size, func.convert_rgba_to_int(stuff.menuData.color.footer_text.r, stuff.menuData.color.footer_text.g, stuff.menuData.color.footer_text.b, stuff.menuData.color.footer_text.a), 16, stuff.menuData.fonts.footer) + scriptdraw.draw_text( + tostring(stuff.scroll.." / "..(#currentMenu - stuff.drawHiddenOffset)), + cheeseUtils.memoize.v2((stuff.menuData.pos_x + stuff.menuData.width/2 - stuff.menuData.footer.padding)*2-1, text_y_pos), + cheeseUtils.memoize.v2(2, 2), + footer_size, + footerTextColor, + 16, + stuff.menuData.fonts.footer + ) end if type(sprite) == "table" then @@ -1827,7 +1954,8 @@ function loadCurrentMenu() sprite = sprite[stuff.draw_current_menu.frameCounter].sprite end if sprite then - scriptdraw.draw_sprite(sprite, cheeseUtils.memoize.v2(stuff.menuData.x * 2 - 1, ((stuff.menuData.y+stuff.menuData.height/2) - (stuff.menuData.height/2 + ((scriptdraw.get_sprite_size(sprite).y*((2.56 * stuff.menuData.width) * (1000 / scriptdraw.get_sprite_size(sprite).x)) / (2560 / graphics.get_screen_width()))/2)/graphics.get_screen_height()))*-2+1), ((2.56 * stuff.menuData.width) * (1000 / scriptdraw.get_sprite_size(sprite).x)) / (2560 / graphics.get_screen_width()), 0, stuff.menuData.color.sprite) + local size = ((2.56 * stuff.menuData.width) * (1000 / scriptdraw.get_sprite_size(sprite).x)) / (2560 / graphics.get_screen_width()) + scriptdraw.draw_sprite(sprite, cheeseUtils.memoize.v2(stuff.menuData.pos_x * 2 - 1, ((stuff.menuData.pos_y+stuff.menuData.height/2) - (stuff.menuData.height/2 + ((scriptdraw.get_sprite_size(sprite).y*size)/2)/graphics.get_screen_height()))*-2+1), size, 0, stuff.menuData.color.sprite) end system.wait(0) end @@ -1989,7 +2117,7 @@ function loadCurrentMenu() --threads menu.create_thread(function() - local side_window_pos = v2((stuff.menuData.x + stuff.menuData.width + stuff.menuData.side_window.offset.x)*2-1, (stuff.menuData.y + stuff.menuData.side_window.offset.y)*-2+1) + local side_window_pos = v2((stuff.menuData.pos_x + stuff.menuData.width + stuff.menuData.side_window.offset.x)*2-1, (stuff.menuData.pos_y + stuff.menuData.side_window.offset.y)*-2+1) while true do if stuff.menuData.menuToggle then func.draw_current_menu() @@ -2010,7 +2138,7 @@ function loadCurrentMenu() end end if pid then - side_window_pos.x, side_window_pos.y = (stuff.menuData.x + stuff.menuData.width + stuff.menuData.side_window.offset.x)*2-1, (stuff.menuData.y + stuff.menuData.side_window.offset.y)*-2+1 + side_window_pos.x, side_window_pos.y = (stuff.menuData.pos_x + stuff.menuData.width + stuff.menuData.side_window.offset.x)*2-1, (stuff.menuData.pos_y + stuff.menuData.side_window.offset.y)*-2+1 native.call(0xBE8CD9BE829BBEBF, player.get_player_ped(stuff.pid), stuff.proofs.bulletProof, stuff.proofs.fireProof, stuff.proofs.explosionProof, stuff.proofs.collisionProof, stuff.proofs.meleeProof, stuff.proofs.steamProof, stuff.proofs.p7, stuff.proofs.drownProof) stuff.player_info[2][2] = player.is_player_god(stuff.pid) and "Yes" or "No" stuff.player_info[3][2] = (stuff.proofs.bulletProof:__tointeger()|stuff.proofs.fireProof:__tointeger()|stuff.proofs.explosionProof:__tointeger()|stuff.proofs.collisionProof:__tointeger()|stuff.proofs.meleeProof:__tointeger()|stuff.proofs.steamProof:__tointeger()|stuff.proofs.p7:__tointeger()|stuff.proofs.drownProof:__tointeger()) == 1 and "Yes" or "No" @@ -2050,9 +2178,12 @@ function loadCurrentMenu() menu.create_thread(function() while true do - func.do_key(500, stuff.vkcontrols.open, false, function() -- F4 - func.toggle_menu(not stuff.menuData.menuToggle) - end) + stuff.menuData.menuNav = native.call(0x5FCF4D7069B09026):__tointeger() ~= 1 and not (stuff.menuData.chatBoxOpen or input.is_open() --[[or console.on]]) + if stuff.menuData.menuNav then + func.do_key(500, stuff.vkcontrols.open, false, function() -- F4 + func.toggle_menu(not stuff.menuData.menuToggle) + end) + end if currentMenu.hidden or not currentMenu then currentMenu = stuff.previousMenus[#stuff.previousMenus].menu stuff.scroll = stuff.previousMenus[#stuff.previousMenus].scroll @@ -2072,7 +2203,7 @@ function loadCurrentMenu() menu.create_thread(function() while true do system.wait(0) - if stuff.menuData.menuToggle then + if stuff.menuData.menuToggle and stuff.menuData.menuNav then func.do_key(500, stuff.vkcontrols.setHotkey, false, function() -- F11 if cheeseUtils.get_key(0x10):is_down() and stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey] then stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey][currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hierarchy_key] = nil @@ -2099,7 +2230,7 @@ function loadCurrentMenu() menu.create_thread(function() while true do system.wait(0) - if stuff.menuData.menuToggle then + if stuff.menuData.menuToggle and stuff.menuData.menuNav then func.do_key(500, stuff.vkcontrols.down, true, function() -- downKey --[[ local old_scroll = stuff.scroll + stuff.scrollHiddenOffset ]] if stuff.scroll + stuff.drawHiddenOffset >= #currentMenu and #currentMenu - stuff.drawHiddenOffset > 1 then @@ -2124,7 +2255,7 @@ function loadCurrentMenu() menu.create_thread(function() while true do system.wait(0) - if stuff.menuData.menuToggle then + if stuff.menuData.menuToggle and stuff.menuData.menuNav then func.do_key(500, stuff.vkcontrols.up, true, function() -- upKey --[[ local old_scroll = stuff.scroll + stuff.scrollHiddenOffset ]] if stuff.scroll <= 1 and #currentMenu - stuff.drawHiddenOffset > 1 then @@ -2149,7 +2280,7 @@ function loadCurrentMenu() menu.create_thread(function() while true do system.wait(0) - if stuff.menuData.menuToggle then + if stuff.menuData.menuToggle and stuff.menuData.menuNav then func.do_key(500, stuff.vkcontrols.select, true, function() --enter local feat = currentMenu[stuff.scroll + stuff.scrollHiddenOffset] if feat then @@ -2186,7 +2317,7 @@ function loadCurrentMenu() menu.create_thread(function() while true do system.wait(0) - if stuff.menuData.menuToggle then + if stuff.menuData.menuToggle and stuff.menuData.menuNav then func.do_key(500, stuff.vkcontrols.back, false, function() --backspace if stuff.previousMenus[#stuff.previousMenus] then --[[ if currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then @@ -2206,7 +2337,7 @@ function loadCurrentMenu() menu.create_thread(function() while true do system.wait(0) - if stuff.menuData.menuToggle then + if stuff.menuData.menuToggle and stuff.menuData.menuNav then func.do_key(500, stuff.vkcontrols.left, true, function() -- left local feat = currentMenu[stuff.scroll + stuff.scrollHiddenOffset] if feat then @@ -2237,7 +2368,7 @@ function loadCurrentMenu() end, nil) menu.create_thread(function() while true do - if stuff.menuData.menuToggle then + if stuff.menuData.menuToggle and stuff.menuData.menuNav then func.do_key(500, stuff.vkcontrols.right, true, function() -- right local feat = currentMenu[stuff.scroll + stuff.scrollHiddenOffset] if feat then @@ -2272,7 +2403,7 @@ function loadCurrentMenu() --Hotkey thread menu.create_thread(function() while true do - if native.call(0x5FCF4D7069B09026):__tointeger() ~= 1 and not stuff.menuData.chatBoxOpen then + if stuff.menuData.menuNav then for k, v in pairs(stuff.hotkeys) do local hotkey = cheeseUtils.get_key(table.unpack(stuff.hotkeys_to_vk[k])) if hotkey:is_down() and (not (cheeseUtils.get_key(0x10):is_down() or cheeseUtils.get_key(0x11):is_down() or cheeseUtils.get_key(0x12):is_down()) or not (k:match("NOMOD"))) and utils.time_ms() > stuff.hotkey_cooldowns[k] then @@ -2342,31 +2473,31 @@ function loadCurrentMenu() if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then local stat, num = input.get("num", "", 10, 3) if stat == 0 and tonumber(num) then - stuff.menuData.x = num/graphics.get_screen_height() + stuff.menuData.pos_x = num/graphics.get_screen_height() f.value = num end end - stuff.menuData.x = f.value/graphics.get_screen_width() + stuff.menuData.pos_x = f.value/graphics.get_screen_width() end) menu_configuration_features.menuXfeat.max = graphics.get_screen_width() menu_configuration_features.menuXfeat.mod = 1 menu_configuration_features.menuXfeat.min = -graphics.get_screen_width() - menu_configuration_features.menuXfeat.value = math.floor(stuff.menuData.x*graphics.get_screen_width()) + menu_configuration_features.menuXfeat.value = math.floor(stuff.menuData.pos_x*graphics.get_screen_width()) menu_configuration_features.menuYfeat = menu.add_feature("Menu pos Y", "autoaction_value_i", menu_configuration_features.cheesemenuparent.id, function(f) if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then local stat, num = input.get("num", "", 10, 3) if stat == 0 and tonumber(num) then - stuff.menuData.y = num/graphics.get_screen_height() + stuff.menuData.pos_y = num/graphics.get_screen_height() f.value = num end end - stuff.menuData.y = f.value/graphics.get_screen_height() + stuff.menuData.pos_y = f.value/graphics.get_screen_height() end) menu_configuration_features.menuYfeat.max = graphics.get_screen_height() menu_configuration_features.menuYfeat.mod = 1 menu_configuration_features.menuYfeat.min = -graphics.get_screen_height() - menu_configuration_features.menuYfeat.value = math.floor(stuff.menuData.y*graphics.get_screen_height()) + menu_configuration_features.menuYfeat.value = math.floor(stuff.menuData.pos_y*graphics.get_screen_height()) menu_configuration_features.headerfeat = menu.add_feature("Header", "autoaction_value_str", menu_configuration_features.cheesemenuparent.id, function(f) if f.str_data[f.value + 1] == "NONE" then @@ -2428,6 +2559,23 @@ function loadCurrentMenu() menu_configuration_features.text_size.min = 0.1 menu_configuration_features.text_size.value = stuff.menuData.text_size_modifier + menu_configuration_features.footer_size = menu.add_feature("Footer Text Size", "autoaction_value_f", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.footer_size_modifier = f.value + end) + menu_configuration_features.footer_size.max = 5 + menu_configuration_features.footer_size.mod = 0.01 + menu_configuration_features.footer_size.min = 0.1 + menu_configuration_features.footer_size.value = stuff.menuData.footer_size_modifier + + menu_configuration_features.hint_size = menu.add_feature("Hint Text Size", "autoaction_value_f", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.hint_size_modifier = f.value + func.rewrap_hints(stuff.menuData.fonts.hint) + end) + menu_configuration_features.hint_size.max = 5 + menu_configuration_features.hint_size.mod = 0.01 + menu_configuration_features.hint_size.min = 0.1 + menu_configuration_features.hint_size.value = stuff.menuData.hint_size_modifier + menu_configuration_features.text_y_offset = menu.add_feature("Text Y Offset", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) stuff.drawFeatParams.textOffset.y = -(f.value/graphics.get_screen_height()) stuff.menuData.text_y_offset = -(f.value/graphics.get_screen_height()) @@ -2775,6 +2923,13 @@ function loadCurrentMenu() menu_configuration_features.footer_font:set_str_data(fontStrData) menu_configuration_features.footer_font.value = stuff.menuData.fonts.footer + menu_configuration_features.hint_font = menu.add_feature("Hint Font", "autoaction_value_str", menu_configuration_features.fonts.id, function(f) + stuff.menuData.fonts.hint = f.value + func.rewrap_hints(f.value) + end) + menu_configuration_features.hint_font:set_str_data(fontStrData) + menu_configuration_features.hint_font.value = stuff.menuData.fonts.hint + -- Hotkeys menu_configuration_features.hotkeyparent = menu.add_feature("Hotkey notifications", "parent", menu_configuration_features.cheesemenuparent.id) @@ -2790,9 +2945,9 @@ function loadCurrentMenu() do local tempColor = {} for k, v in pairs(stuff.menuData.color) do - tempColor[#tempColor+1] = {k, v} + tempColor[#tempColor+1] = {k, v, sortname = k:gsub("feature_([^s])", "feature_a%1")} end - table.sort(tempColor, function(a, b) return a[1] < b[1] end) + table.sort(tempColor, function(a, b) return a["sortname"] < b["sortname"] end) for _, v in pairs(tempColor) do menu_configuration_features[v[1]] = {} @@ -2884,7 +3039,7 @@ function loadCurrentMenu() menu.delete_player_feature = func.delete_player_feature menu.get_player_feature = func.get_player_feature menu.get_feature_by_hierarchy_key = function(hierarchy_key) - if string.find(hierarchy_key:lower(), "trusted") then + if string.find(hierarchy_key:lower(), "trusted") or string.find(hierarchy_key:lower(), "Proddy's Script Manager") then return end local feat, duplicate @@ -2930,10 +3085,10 @@ function loadCurrentMenu() local trusted_names = { [0] = "Stats", - "Globals / Locals", - "Natives", - "HTTP", - "Memory" + [1] = "Globals / Locals", + [2] = "Natives", + [3] = "HTTP", + [4] = "Memory" } for i = 0, 4 do diff --git a/cheesemenu/libs/CheeseUtilities.lua b/cheesemenu/libs/CheeseUtilities.lua index c783616..03dd2ca 100644 --- a/cheesemenu/libs/CheeseUtilities.lua +++ b/cheesemenu/libs/CheeseUtilities.lua @@ -569,4 +569,42 @@ do end end -return cheeseUtils +-- Text Wrap +do + ---@param text string + ---@param font int + ---@param scale float + ---@param relWidth float + function cheeseUtils.wrap_text(text, font, scale, relWidth) + local spaceSize = scriptdraw.get_text_size(". .", scale, font).x - scriptdraw.get_text_size("..", scale, font).x + local lines = {} + for line, manualNewLines in text:gmatch("([^\r\n]+)([\r\n]*)") do + local newline + local lineSize = scriptdraw.get_text_size(line, scale, font) + + if scriptdraw.size_pixel_to_rel_x(lineSize.x) > relWidth then + local length = 0 + newline = {} + for word in line:gmatch("[^%s-\\,]+[%s-\\,]*") do + local relx = scriptdraw.size_pixel_to_rel_x(scriptdraw.get_text_size(word, scale, font).x) + local spaceRelx = word:gsub("%S", "") + spaceRelx = scriptdraw.size_pixel_to_rel_x(#spaceRelx*spaceSize) + if length + relx > relWidth then + newline[#newline+1] = "\n" + length = 0 + end + length = length + relx + spaceRelx + newline[#newline+1] = word + end + + line = table.concat(newline) + end + + lines[#lines+1] = line..(manualNewLines or "") + end + + return table.concat(lines) + end +end + +return cheeseUtils \ No newline at end of file diff --git a/cheesemenu/libs/GLTW.lua b/cheesemenu/libs/GLTW.lua index dd2e34a..becec76 100644 --- a/cheesemenu/libs/GLTW.lua +++ b/cheesemenu/libs/GLTW.lua @@ -13,13 +13,10 @@ table[] gltw.read(string name, string path|nil(in same path as lua), table|nil, local gltw = {} local type = type local l_next = next -local l_pairs = function(t) - return l_next, t, nil -end local ipairs = ipairs function gltw.write_table(tableTW, indentation, exclusions, exclude_empty, string_lines) - for k, v in l_pairs(tableTW) do + for k, v in l_next, tableTW do if not exclusions[k] then local typeofv = type(v) local index @@ -79,7 +76,7 @@ end function gltw.add_to_table(getTable, addToTable, typeMatched) assert(type(getTable) == "table" and type(addToTable) == "table", "args have to be tables") - for k, v in l_pairs(getTable) do + for k, v in l_next, getTable do if type(v) ~= "table" then if typeMatched and (type(getTable[k]) == type(addToTable[k]) or not addToTable[k]) or not typeMatched then addToTable[k] = getTable[k] diff --git a/cheesemenu/ui/2take1.lua b/cheesemenu/ui/2take1.lua index 0d64744..3652c4f 100644 --- a/cheesemenu/ui/2take1.lua +++ b/cheesemenu/ui/2take1.lua @@ -1,157 +1,192 @@ -return { - ["border"] = 0.0013888888888889, - ["fonts"] = { - ["footer"] = 0, - ["text"] = 0, - }, - ["header"] = [=[2t1]=], - ["height"] = 0.42777777777778, - ["y"] = 0.19791666666667, - ["x"] = 0.34375, - ["footer"] = { - ["footer_text"] = [=[CheeseMenu VIP]=], - ["footer_y_offset"] = 0, - ["padding"] = 0.00390625, - ["draw_footer"] = true, - ["footer_size"] = 0.021527777777778, - ["footer_pos_related_to_background"] = false, - }, - ["text_y_offset"] = -0.0055555555, - ["slider"] = { - ["width"] = 0.171875, - ["heightActive"] = 0.020833333333333, - ["height"] = 0.010416666666667, - }, - ["chatBoxOpen"] = false, - ["width"] = 0.1875, - ["outline"] = false, - ["feature_offset"] = 0.030555555555556, - ["max_features"] = 14, - ["text_size_modifier"] = 1, - ["side_window"] = { - ["offset"] = { - ["y"] = 0, - ["x"] = -0.013671875, - }, - ["spacing"] = 0.0547222, - ["width"] = 0.3, - ["padding"] = 0.01015625, - ["on"] = true, - }, - ["background_sprite"] = { - ["offset"] = { - ["y"] = 0, - ["x"] = 0, - }, - ["size"] = 0.6448362720403, - }, - ["padding"] = { - ["slider"] = 0.003125, - ["value"] = 0.046875, - ["parent"] = 0.003125, - ["name"] = 0.003125, - }, - ["color"] = { - ["border"] = { - ["g"] = 255, - ["r"] = 255, - ["a"] = 208, - ["b"] = 255, - }, - ["text"] = { - ["g"] = 255, - ["r"] = 255, - ["a"] = 200, - ["b"] = 255, - }, - ["notifications"] = { - ["g"] = 53, - ["r"] = 108, - ["a"] = 255, - ["b"] = 112, - }, - ["background"] = { - ["g"] = 0, - ["r"] = 0, - ["a"] = 0, - ["b"] = 0, - }, - ["sprite"] = 2701131775, - ["feature_selected"] = { - ["g"] = 255, - ["r"] = 255, - ["a"] = 208, - ["b"] = 255, - }, - ["slider_background"] = { - ["g"] = 100, - ["r"] = 100, - ["a"] = 200, - ["b"] = 100, - }, - ["side_window_text"] = { - ["g"] = 255, - ["r"] = 255, - ["a"] = 200, - ["b"] = 255, - }, - ["slider_selectedBackground"] = { - ["g"] = 100, - ["r"] = 100, - ["a"] = 200, - ["b"] = 100, - }, - ["side_window"] = { - ["g"] = 0, - ["r"] = 0, - ["a"] = 150, - ["b"] = 0, - }, - ["footer_text"] = { - ["g"] = 255, - ["r"] = 255, - ["a"] = 200, - ["b"] = 255, - }, - ["slider_active"] = { - ["g"] = 255, - ["r"] = 255, - ["a"] = 150, - ["b"] = 255, - }, - ["footer"] = { - ["g"] = 0, - ["r"] = 0, - ["a"] = 160, - ["b"] = 0, - }, - ["slider_selectedActive"] = { - ["g"] = 0, - ["r"] = 0, - ["a"] = 180, - ["b"] = 0, - }, - ["text_selected"] = { - ["g"] = 0, - ["r"] = 0, - ["a"] = 224, - ["b"] = 0, - }, - ["feature"] = { - ["g"] = 0, - ["r"] = 0, - ["a"] = 160, - ["b"] = 0, - }, - ["slider_text"] = { - ["g"] = 255, - ["r"] = 255, - ["a"] = 255, - ["b"] = 255, - }, - }, - ["feature_scale"] = { - ["y"] = 0.030555555555556, - ["x"] = 0.1875, - }, +return { + ["footer"] = { + ["footer_y_offset"] = 0, + ["draw_footer"] = true, + ["footer_pos_related_to_background"] = false, + ["padding"] = 0.00390625, + ["footer_text"] = [=[CheeseMenu VIP]=], + ["footer_size"] = 0.021527777777778, + }, + ["header"] = [=[2t1.png]=], + ["feature_scale"] = { + ["x"] = 0.1875, + ["y"] = 0.030555555555556, + }, + ["padding"] = { + ["slider"] = 0.003125, + ["name"] = 0.003125, + ["value"] = 0.046875, + ["parent"] = 0.003125, + }, + ["outline"] = false, + ["color"] = { + ["slider_active"] = { + ["b"] = 255, + ["g"] = 255, + ["r"] = 255, + ["a"] = 150, + }, + ["feature_bottomRight"] = { + ["b"] = 0, + ["g"] = 0, + ["r"] = 0, + ["a"] = 170, + }, + ["text"] = { + ["b"] = 255, + ["g"] = 255, + ["r"] = 255, + ["a"] = 200, + }, + ["feature_selected_topLeft"] = { + ["b"] = 255, + ["g"] = 255, + ["r"] = 255, + ["a"] = 200, + }, + ["feature"] = { + ["b"] = 0, + ["g"] = 0, + ["r"] = 0, + ["a"] = 160, + }, + ["border"] = { + ["b"] = 255, + ["g"] = 255, + ["r"] = 255, + ["a"] = 208, + }, + ["footer_text"] = { + ["b"] = 255, + ["g"] = 255, + ["r"] = 255, + ["a"] = 200, + }, + ["feature_topLeft"] = { + ["b"] = 0, + ["g"] = 0, + ["r"] = 0, + ["a"] = 170, + }, + ["feature_topRight"] = { + ["b"] = 0, + ["g"] = 0, + ["r"] = 0, + ["a"] = 170, + }, + ["feature_selected"] = { + ["b"] = 255, + ["g"] = 255, + ["r"] = 255, + ["a"] = 208, + }, + ["slider_selectedBackground"] = { + ["b"] = 100, + ["g"] = 100, + ["r"] = 100, + ["a"] = 200, + }, + ["feature_selected_bottomRight"] = { + ["b"] = 255, + ["g"] = 255, + ["r"] = 255, + ["a"] = 200, + }, + ["side_window_text"] = { + ["b"] = 255, + ["g"] = 255, + ["r"] = 255, + ["a"] = 200, + }, + ["slider_selectedActive"] = { + ["b"] = 0, + ["g"] = 0, + ["r"] = 0, + ["a"] = 180, + }, + ["slider_text"] = { + ["b"] = 255, + ["g"] = 255, + ["r"] = 255, + ["a"] = 255, + }, + ["sprite"] = 2701131775, + ["notifications"] = { + ["b"] = 112, + ["g"] = 53, + ["r"] = 108, + ["a"] = 255, + }, + ["footer"] = { + ["b"] = 0, + ["g"] = 0, + ["r"] = 0, + ["a"] = 160, + }, + ["background"] = { + ["b"] = 0, + ["g"] = 0, + ["r"] = 0, + ["a"] = 0, + }, + ["feature_selected_topRight"] = { + ["b"] = 255, + ["g"] = 255, + ["r"] = 255, + ["a"] = 200, + }, + ["text_selected"] = { + ["b"] = 0, + ["g"] = 0, + ["r"] = 0, + ["a"] = 224, + }, + ["slider_background"] = { + ["b"] = 100, + ["g"] = 100, + ["r"] = 100, + ["a"] = 200, + }, + ["feature_selected_bottomLeft"] = { + ["b"] = 255, + ["g"] = 255, + ["r"] = 255, + ["a"] = 200, + }, + ["feature_bottomLeft"] = { + ["b"] = 0, + ["g"] = 0, + ["r"] = 0, + ["a"] = 170, + }, + }, + ["background_sprite"] = { + ["size"] = 0.6448362720403, + ["offset"] = { + ["x"] = 0, + ["y"] = 0, + }, + }, + ["text_size_modifier"] = 1, + ["slider"] = { + ["heightActive"] = 0.020833333333333, + ["height"] = 0.010416666666667, + ["width"] = 0.171875, + }, + ["footer_size_modifier"] = 1, + ["height"] = 0.42777777777778, + ["y"] = 0.19791666666667, + ["x"] = 0.34375, + ["text_size"] = 0.7, + ["hint_size_modifier"] = 1.1499998569489, + ["feature_offset"] = 0.030555555555556, + ["max_features"] = 14, + ["text_y_offset"] = -0.0055555555, + ["border"] = 0.0013888888888889, + ["fonts"] = { + ["text"] = 0, + ["footer"] = 0, + ["hint"] = 1, + }, + ["width"] = 0.1875, } \ No newline at end of file diff --git a/cheesemenu/ui/Rimurus.lua b/cheesemenu/ui/Rimurus.lua index a19dc5a..b104fa1 100644 --- a/cheesemenu/ui/Rimurus.lua +++ b/cheesemenu/ui/Rimurus.lua @@ -1,86 +1,192 @@ -return { - ["feature_offset"] = 0.025, - ["outline"] = false, - ["y"] = 0.23055555555556, - ["x"] = 0.362109375, - ["width"] = 0.2, - ["max_features"] = 13, - ["border"] = 0.0041666666666667, - ["height"] = 0.325, - ["header"] = [[eclipse banner]], - ["footer"] = { - ["footer_size"] = 0.025694444444444, - ["padding"] = 0.00390625, - ["footer_text"] = [[Made by GhostOne]], - ["footer_pos_related_to_background"] = true, - ["draw_footer"] = true, - }, - ["background_sprite"] = { - ["size"] = 0.6448362720403, - ["offset"] = { - ["y"] = 0, - ["x"] = 0.0, - }, - }, - ["color"] = { - ["sprite"] = 4294967295, - ["feature"] = { - ["g"] = 0, - ["r"] = 0, - ["a"] = 150, - ["b"] = 0, - }, - ["footer"] = { - ["g"] = 0, - ["r"] = 0, - ["a"] = 220, - ["b"] = 0, - }, - ["background"] = { - ["g"] = 0, - ["r"] = 0, - ["a"] = 255, - ["b"] = 0, - }, - ["border"] = { - ["g"] = 0, - ["r"] = 79, - ["a"] = 255, - ["b"] = 141, - }, - ["text"] = { - ["g"] = 255, - ["r"] = 255, - ["a"] = 180, - ["b"] = 255, - }, - ["notifications"] = { - ["g"] = 0, - ["r"] = 91, - ["a"] = 255, - ["b"] = 164, - }, - ["feature_selected"] = { - ["g"] = 0, - ["r"] = 91, - ["a"] = 255, - ["b"] = 164, - }, - ["footer_text"] = { - ["g"] = 255, - ["r"] = 255, - ["a"] = 225, - ["b"] = 255, - }, - ["text_selected"] = { - ["g"] = 255, - ["r"] = 255, - ["a"] = 200, - ["b"] = 255, - }, - }, - ["feature_scale"] = { - ["y"] = 0.025, - ["x"] = 0.2, - }, -} +return { + ["height"] = 0.325, + ["outline"] = false, + ["fonts"] = { + ["text"] = 0, + ["hint"] = 1, + ["footer"] = 0, + }, + ["text_size_modifier"] = 1, + ["hint_size_modifier"] = 1.0999999046326, + ["text_y_offset"] = -0.0055555555, + ["slider"] = { + ["width"] = 0.2, + ["heightActive"] = 0.020833333333333, + ["height"] = 0.010416666666667, + }, + ["max_features"] = 13, + ["background_sprite"] = { + ["size"] = 0.6448362720403, + ["offset"] = { + ["y"] = 0, + ["x"] = 0.0, + }, + }, + ["padding"] = { + ["name"] = 0.003125, + ["parent"] = 0.003125, + ["value"] = 0.046875, + ["slider"] = 0.013671875, + }, + ["footer"] = { + ["footer_size"] = 0.025694444444444, + ["footer_y_offset"] = 0, + ["padding"] = 0.00390625, + ["footer_pos_related_to_background"] = true, + ["footer_text"] = [=[Made by GhostOne]=], + ["draw_footer"] = true, + }, + ["header"] = [=[eclipse banner.png]=], + ["footer_size_modifier"] = 1, + ["y"] = 0.23055555555556, + ["x"] = 0.362109375, + ["text_size"] = 0.7, + ["feature_scale"] = { + ["y"] = 0.025, + ["x"] = 0.2, + }, + ["width"] = 0.2, + ["feature_offset"] = 0.025, + ["color"] = { + ["feature_selected_bottomRight"] = { + ["a"] = 0, + ["b"] = 141, + ["g"] = 0, + ["r"] = 79, + }, + ["notifications"] = { + ["a"] = 255, + ["b"] = 164, + ["g"] = 0, + ["r"] = 91, + }, + ["feature_selected_topRight"] = { + ["a"] = 0, + ["b"] = 141, + ["g"] = 0, + ["r"] = 79, + }, + ["feature_selected"] = { + ["a"] = 255, + ["b"] = 164, + ["g"] = 0, + ["r"] = 91, + }, + ["side_window_text"] = { + ["a"] = 200, + ["b"] = 255, + ["g"] = 0, + ["r"] = 142, + }, + ["text_selected"] = { + ["a"] = 200, + ["b"] = 255, + ["g"] = 255, + ["r"] = 255, + }, + ["feature"] = { + ["a"] = 150, + ["b"] = 0, + ["g"] = 0, + ["r"] = 0, + }, + ["background"] = { + ["a"] = 255, + ["b"] = 0, + ["g"] = 0, + ["r"] = 0, + }, + ["slider_selectedActive"] = { + ["a"] = 255, + ["b"] = 200, + ["g"] = 0, + ["r"] = 112, + }, + ["feature_selected_bottomLeft"] = { + ["a"] = 255, + ["b"] = 141, + ["g"] = 0, + ["r"] = 79, + }, + ["footer"] = { + ["a"] = 220, + ["b"] = 0, + ["g"] = 0, + ["r"] = 0, + }, + ["border"] = { + ["a"] = 255, + ["b"] = 141, + ["g"] = 0, + ["r"] = 79, + }, + ["slider_active"] = { + ["a"] = 255, + ["b"] = 200, + ["g"] = 0, + ["r"] = 112, + }, + ["text"] = { + ["a"] = 180, + ["b"] = 255, + ["g"] = 255, + ["r"] = 255, + }, + ["slider_text"] = { + ["a"] = 200, + ["b"] = 255, + ["g"] = 255, + ["r"] = 255, + }, + ["feature_selected_topLeft"] = { + ["a"] = 255, + ["b"] = 141, + ["g"] = 0, + ["r"] = 79, + }, + ["slider_background"] = { + ["a"] = 160, + ["b"] = 141, + ["g"] = 0, + ["r"] = 79, + }, + ["feature_topRight"] = { + ["a"] = 0, + ["b"] = 0, + ["g"] = 160, + ["r"] = 255, + }, + ["feature_bottomRight"] = { + ["a"] = 0, + ["b"] = 0, + ["g"] = 160, + ["r"] = 255, + }, + ["feature_topLeft"] = { + ["a"] = 0, + ["b"] = 0, + ["g"] = 160, + ["r"] = 255, + }, + ["sprite"] = 4294967295, + ["feature_bottomLeft"] = { + ["a"] = 0, + ["b"] = 0, + ["g"] = 0, + ["r"] = 0, + }, + ["footer_text"] = { + ["a"] = 225, + ["b"] = 255, + ["g"] = 255, + ["r"] = 255, + }, + ["slider_selectedBackground"] = { + ["a"] = 180, + ["b"] = 141, + ["g"] = 0, + ["r"] = 79, + }, + }, + ["border"] = 0.0041666666666667, +} \ No newline at end of file diff --git a/cheesemenu/ui/cheese.lua b/cheesemenu/ui/cheese.lua index 67e3dcf..4b8bcc9 100644 --- a/cheesemenu/ui/cheese.lua +++ b/cheesemenu/ui/cheese.lua @@ -1,157 +1,192 @@ -return { - ["slider"] = { - ["width"] = 0.2, - ["height"] = 0.010416666666667, - ["heightActive"] = 0.020833333333333, - }, - ["feature_offset"] = 0.025, - ["x"] = 0.73046875, - ["y"] = 0.24305555555556, - ["header"] = [=[cheese_menu]=], - ["color"] = { - ["feature_selected"] = { - ["g"] = 0, - ["b"] = 0, - ["a"] = 200, - ["r"] = 0, - }, - ["side_window"] = { - ["g"] = 0, - ["b"] = 0, - ["a"] = 150, - ["r"] = 0, - }, - ["side_window_text"] = { - ["g"] = 255, - ["b"] = 60, - ["a"] = 200, - ["r"] = 150, - }, - ["feature"] = { - ["g"] = 160, - ["b"] = 0, - ["a"] = 170, - ["r"] = 255, - }, - ["footer"] = { - ["g"] = 160, - ["b"] = 0, - ["a"] = 170, - ["r"] = 255, - }, - ["sprite"] = 3875536895, - ["slider_text"] = { - ["g"] = 0, - ["b"] = 0, - ["a"] = 255, - ["r"] = 0, - }, - ["background"] = { - ["g"] = 0, - ["b"] = 0, - ["a"] = 0, - ["r"] = 0, - }, - ["slider_active"] = { - ["g"] = 200, - ["b"] = 0, - ["a"] = 255, - ["r"] = 255, - }, - ["slider_background"] = { - ["g"] = 0, - ["b"] = 0, - ["a"] = 160, - ["r"] = 0, - }, - ["notifications"] = { - ["g"] = 200, - ["b"] = 0, - ["a"] = 255, - ["r"] = 255, - }, - ["slider_selectedBackground"] = { - ["g"] = 160, - ["b"] = 0, - ["a"] = 180, - ["r"] = 255, - }, - ["footer_text"] = { - ["g"] = 0, - ["b"] = 0, - ["a"] = 180, - ["r"] = 0, - }, - ["border"] = { - ["g"] = 0, - ["b"] = 0, - ["a"] = 180, - ["r"] = 0, - }, - ["text"] = { - ["g"] = 0, - ["b"] = 0, - ["a"] = 180, - ["r"] = 0, - }, - ["text_selected"] = { - ["g"] = 200, - ["b"] = 0, - ["a"] = 180, - ["r"] = 255, - }, - ["slider_selectedActive"] = { - ["g"] = 255, - ["b"] = 255, - ["a"] = 160, - ["r"] = 255, - }, - }, - ["footer"] = { - ["footer_y_offset"] = 0, - ["draw_footer"] = true, - ["footer_text"] = [=[Made by GhostOne]=], - ["padding"] = 0.0078125, - ["footer_pos_related_to_background"] = false, - ["footer_size"] = 0.019444444, - }, - ["outline"] = false, - ["max_features"] = 14, - ["height"] = 0.35, - ["background_sprite"] = { - ["offset"] = { - ["y"] = 0, - ["x"] = 0, - }, - ["size"] = 1, - }, - ["fonts"] = { - ["text"] = 0, - ["footer"] = 0, - }, - ["text_y_offset"] = -0.0055555555, - ["width"] = 0.2, - ["side_window"] = { - ["offset"] = { - ["y"] = 0, - ["x"] = -0.013671875, - }, - ["on"] = true, - ["spacing"] = 0.0547222, - ["width"] = 0.3, - ["padding"] = 0.01015625, - }, - ["chatBoxOpen"] = false, - ["feature_scale"] = { - ["y"] = 0.025, - ["x"] = 0.2, - }, - ["padding"] = { - ["slider"] = 0.013671875, - ["parent"] = 0.003125, - ["value"] = 0.046875, - ["name"] = 0.003125, - }, - ["border"] = 0.0013888, - ["text_size_modifier"] = 1, +return { + ["footer"] = { + ["footer_y_offset"] = 0, + ["draw_footer"] = true, + ["footer_pos_related_to_background"] = false, + ["padding"] = 0.0078125, + ["footer_text"] = [=[Made by GhostOne]=], + ["footer_size"] = 0.019444444, + }, + ["header"] = [=[cheese_menu.png]=], + ["feature_scale"] = { + ["x"] = 0.2, + ["y"] = 0.025, + }, + ["padding"] = { + ["slider"] = 0.013671875, + ["name"] = 0.003125, + ["value"] = 0.046875, + ["parent"] = 0.003125, + }, + ["outline"] = false, + ["color"] = { + ["slider_active"] = { + ["b"] = 0, + ["g"] = 200, + ["r"] = 255, + ["a"] = 255, + }, + ["feature_bottomRight"] = { + ["b"] = 0, + ["g"] = 160, + ["r"] = 255, + ["a"] = 170, + }, + ["text"] = { + ["b"] = 0, + ["g"] = 0, + ["r"] = 0, + ["a"] = 180, + }, + ["feature_selected_topLeft"] = { + ["b"] = 0, + ["g"] = 0, + ["r"] = 0, + ["a"] = 200, + }, + ["feature"] = { + ["b"] = 0, + ["g"] = 160, + ["r"] = 255, + ["a"] = 170, + }, + ["border"] = { + ["b"] = 0, + ["g"] = 0, + ["r"] = 0, + ["a"] = 180, + }, + ["footer_text"] = { + ["b"] = 0, + ["g"] = 0, + ["r"] = 0, + ["a"] = 180, + }, + ["feature_topLeft"] = { + ["b"] = 0, + ["g"] = 160, + ["r"] = 255, + ["a"] = 170, + }, + ["feature_topRight"] = { + ["b"] = 0, + ["g"] = 160, + ["r"] = 255, + ["a"] = 170, + }, + ["feature_selected"] = { + ["b"] = 0, + ["g"] = 0, + ["r"] = 0, + ["a"] = 200, + }, + ["slider_selectedBackground"] = { + ["b"] = 0, + ["g"] = 160, + ["r"] = 255, + ["a"] = 180, + }, + ["feature_selected_bottomRight"] = { + ["b"] = 0, + ["g"] = 0, + ["r"] = 0, + ["a"] = 200, + }, + ["side_window_text"] = { + ["b"] = 0, + ["g"] = 200, + ["r"] = 255, + ["a"] = 200, + }, + ["slider_selectedActive"] = { + ["b"] = 255, + ["g"] = 255, + ["r"] = 255, + ["a"] = 160, + }, + ["slider_text"] = { + ["b"] = 0, + ["g"] = 0, + ["r"] = 0, + ["a"] = 255, + }, + ["sprite"] = 3875536895, + ["notifications"] = { + ["b"] = 0, + ["g"] = 200, + ["r"] = 255, + ["a"] = 255, + }, + ["footer"] = { + ["b"] = 0, + ["g"] = 160, + ["r"] = 255, + ["a"] = 170, + }, + ["background"] = { + ["b"] = 0, + ["g"] = 0, + ["r"] = 0, + ["a"] = 0, + }, + ["feature_selected_topRight"] = { + ["b"] = 0, + ["g"] = 0, + ["r"] = 0, + ["a"] = 200, + }, + ["text_selected"] = { + ["b"] = 0, + ["g"] = 200, + ["r"] = 255, + ["a"] = 180, + }, + ["slider_background"] = { + ["b"] = 0, + ["g"] = 0, + ["r"] = 0, + ["a"] = 160, + }, + ["feature_selected_bottomLeft"] = { + ["b"] = 0, + ["g"] = 0, + ["r"] = 0, + ["a"] = 200, + }, + ["feature_bottomLeft"] = { + ["b"] = 0, + ["g"] = 160, + ["r"] = 255, + ["a"] = 170, + }, + }, + ["background_sprite"] = { + ["size"] = 1, + ["offset"] = { + ["x"] = 0, + ["y"] = 0, + }, + }, + ["text_size_modifier"] = 1, + ["slider"] = { + ["heightActive"] = 0.020833333333333, + ["height"] = 0.010416666666667, + ["width"] = 0.2, + }, + ["footer_size_modifier"] = 1, + ["height"] = 0.35, + ["y"] = 0.24305555555556, + ["x"] = 0.73046875, + ["text_size"] = 0.7, + ["hint_size_modifier"] = 1, + ["feature_offset"] = 0.025, + ["max_features"] = 14, + ["text_y_offset"] = -0.0055555555, + ["border"] = 0.0013888, + ["fonts"] = { + ["text"] = 0, + ["footer"] = 0, + ["hint"] = 0, + }, + ["width"] = 0.2, } \ No newline at end of file From e99e2ac99ffbaffc5ed88de63da78fe39e4b09a5 Mon Sep 17 00:00:00 2001 From: GhustOne <71855034+GhustOne@users.noreply.github.com> Date: Thu, 5 Jan 2023 22:46:30 +0300 Subject: [PATCH 05/11] Update aioUpdate.lua --- aioUpdate.lua | 9386 +++++++++++++++++++++++++------------------------ 1 file changed, 4698 insertions(+), 4688 deletions(-) diff --git a/aioUpdate.lua b/aioUpdate.lua index a1ee4dc..458e8b0 100644 --- a/aioUpdate.lua +++ b/aioUpdate.lua @@ -1,5327 +1,5337 @@ return { - ["GLTW.lua"] = [==[-- Made by GhostOne --- L00naMods "Even if you say L00na is a bitch just put my name in there somewhere" --- Ghost's Lua Table Writer ---[[ -nil gltw.write(table table, string name, string path|nil, table index exclusions, skip empty tables) --- example gltw.write({name = "l00na", iq = -1, braincells = {}}, "something", "folder1\\", {"name"}, true) < this will not write 'name' (excluded) or 'braincells' (empty) + ["Proddy's Script Manager.lua"] = [=[local ScriptName = "Proddy's Script Manager (CheeseMenu)" +local Version = "2.3.2" +local Exiting = false -table[] gltw.read(string name, string path|nil(in same path as lua), table|nil, bool|nil) --- if a table is the 3rd arg then whatever is read from the file will be added to it without overwriting stuff that isn't in the saved file --- if the 4th arg is true the function won't throw an error if the file doesn't exist and will return nil -]] +local Paths = {} +Paths.Root = utils.get_appdata_path("PopstarDevs", "2Take1Menu") +Paths.Cfg = Paths.Root .. "\\cfg" +Paths.LogFile = Paths.Root .. "\\" .. ScriptName .. ".log" +Paths.Scripts = Paths.Root .. "\\scripts" -local gltw = {} -local type = type -local l_next = next -local ipairs = ipairs +local og_loadfile = loadfile +local og__loadfile = _loadfile +local og_load = load +local og_pcall = _pcall +local io_open = io.open +local os_date = os.date +local string_format = string.format +local system_wait = system.wait -function gltw.write_table(tableTW, indentation, exclusions, exclude_empty, string_lines) - for k, v in l_next, tableTW do - if not exclusions[k] then - local typeofv = type(v) - local index - if type(k) == "number" then - index = "["..k.."] = " - else - index = "[\""..k.."\"] = " - end +local basePrint = print +local function print(...) + basePrint(...) + local success, result = og_pcall(function(...) + local args = {...} + if #args == 0 then + return + end - if typeofv == "string" then - string_lines[#string_lines + 1] = indentation..index.."[=["..v.."]=]," - elseif typeofv ~= "function" and typeofv ~= "table" then - string_lines[#string_lines + 1] = indentation..index..tostring(v).."," - elseif typeofv == "table" and (l_next(v) or not exclude_empty) then - string_lines[#string_lines + 1] = indentation..index.."{" - gltw.write_table(v, indentation.." ", exclusions, exclude_empty, string_lines) - string_lines[#string_lines + 1] = indentation.."}," - end + local currTime = os_date("*t") + local file = io_open(Paths.LogFile, "a") + + for i=1,#args do + file:write(string_format("[%02d-%02d-%02d %02d:%02d:%02d] <%s> %s\n", currTime.year, currTime.month, currTime.day, currTime.hour, currTime.min, currTime.sec, Version, tostring(args[i]))) end + + file:close() + end, ...) + if not success then + basePrint("Error writing log: " .. result) end end -function gltw.write(tableTW, name, path, exclusions, exclude_empty, compiled) - local convertedExclusions = {} - if exclusions then - for _, v in ipairs(exclusions) do - convertedExclusions[v] = true - end +local notif = menu.notify +local function notify(msg, colour) + notif(msg, ScriptName .. " v" .. Version, nil, colour) + print(msg) +end + +if ProddysScriptManager then + notify(ScriptName .. " already loaded.", 0xFF50C8F0) + return +end + +--notify(ScriptName .. " v" .. Version .. " loading...") + +local function CloneTable(obj, seen) + if type(obj) ~= 'table' then + return obj end - assert(tableTW, "no table was provided"..(name and " to write for file '"..name.."'" or "")) - if name then - path = path or "" - assert(type(name) == "string" and type(path) == "string", "name or path isn't a string") + if seen and seen[obj] then + return seen[obj] end - local string_lines = {} + local s = seen or {} + local res = {} + s[obj] = res - string_lines[#string_lines + 1] = "return {" - gltw.write_table(tableTW, " ", convertedExclusions, exclude_empty, string_lines) - string_lines[#string_lines + 1] = "}" + for k, v in pairs(obj) do + res[CloneTable(k, s)] = CloneTable(v, s) + end - if name then - local file = io.open(path..name..".lua", "wb") - assert(file, "'"..name.."' was not created.") + return setmetatable(res, getmetatable(obj)) --Should definitely clone the metatable +end - local stringified = table.concat(string_lines, "\n") +local function Trim(s) + local n = s:find"%S" + return n and s:match(".*%S", n) or "" +end - file:write(compiled and string.dump(load(stringified), true) or stringified) +local function FileNameWithoutExtension(FileName) + local name = FileName:match("(.+)%.") + return name or FileName +end - file:flush() - file:close() - end +local ExcludedScripts = {} +ExcludedScripts["autoexec.lua"] = true +ExcludedScripts["autoexec.luac"] = true +ExcludedScripts["cheesemenu.lua"] = true +ExcludedScripts[debug.getinfo(1, "S").source:sub(Paths.Scripts:len() + 3):lower()] = true - return string_lines +local Settings = {} + +function Settings.Save(SettingsFile, SettingsTbl) + assert(SettingsFile, "Nil passed for SettingsFile to Settings.Save") + assert(type(SettingsTbl) == "table", "Not a table passed for SettingsTbl to Settings.Save") + local file = io.open(Paths.Cfg .. "\\" .. SettingsFile .. ".cfg", "w") + local keys = {} + for k in pairs(SettingsTbl) do + keys[#keys + 1] = k + end + table.sort(keys) + for i=1,#keys do + file:write(tostring(keys[i]) .. "=" .. tostring(SettingsTbl[keys[i]]) .. "\n") + end + file:close() end -function gltw.add_to_table(getTable, addToTable, typeMatched) - assert(type(getTable) == "table" and type(addToTable) == "table", "args have to be tables") - for k, v in l_next, getTable do - if type(v) ~= "table" then - if typeMatched and (type(getTable[k]) == type(addToTable[k]) or not addToTable[k]) or not typeMatched then - addToTable[k] = getTable[k] - end - else - if type(addToTable[k]) ~= "table" and not typeMatched then - addToTable[k] = {} +function Settings.Load(SettingsFile, SettingsTbl) + assert(SettingsFile, "Nil passed for SettingsFile to Settings.Load") + assert(type(SettingsTbl) == "table", "Not a table passed for SettingsTbl to Settings.Load") + SettingsFile = Paths.Cfg .. "\\" .. SettingsFile .. ".cfg" + if not utils.file_exists(SettingsFile) then + return false + end + for line in io.lines(SettingsFile) do + local key, value = line:match("^(.-)=(.-)$") + if key and value then + local num = tonumber(value) + if num then + value = num + elseif value == "true" then + value = true + elseif value == "false" then + value = false end - if type(addToTable[k]) == "table" then - gltw.add_to_table(getTable[k], addToTable[k]) + num = tonumber(key) + if num then + key = num end + SettingsTbl[key] = value end end + return true end -function gltw.read(name, path, addToTable, typeMatched, overrideError) - if overrideError and not utils.file_exists(path..name..".lua") then - return - end +local FeatType = { + [2048] = "parent", + [1] = "toggle", + [512] = "action", + [11] = "value_i", + [131] = "value_f", + [7] = "slider", + [35] = "value_str", + [522] = "action_value_i", + [642] = "action_value_f", + [518] = "action_slider", + [546] = "action_value_str", + [1034] = "autoaction_value_i", + [1154] = "autoaction_value_f", + [1030] = "autoaction_slider", + [1058] = "autoaction_value_str", +} - path = path or "" - if type(tableRT) == "string" then - name, path = tableRT, name or path - tableRT = nil - end +local AutoloadTbl = {} +Settings.Load(ScriptName, AutoloadTbl) - local readTable = loadfile(path..name..".lua", "tb")() - if addToTable then - gltw.add_to_table(readTable, addToTable, typeMatched) - end - return readTable -end +local LoadedScripts = {} -return gltw -]==], - ["cheesemenu.lua"] = [=[--Made by GhostOne +local add_feature = menu.add_feature +local add_player_feature = menu.add_player_feature +local delete_feature = menu.delete_feature +local delete_player_feature = menu.delete_player_feature +local create_thread = menu.create_thread +local delete_thread = menu.delete_thread ---[[ - ,o888888o. 8 8888 8 8 8888888888 8 8888888888 d888888o. 8 8888888888 - 8888 `88. 8 8888 8 8 8888 8 8888 .`8888:' `88. 8 8888 -,8 8888 `8. 8 8888 8 8 8888 8 8888 8.`8888. Y8 8 8888 -88 8888 8 8888 8 8 8888 8 8888 `8.`8888. 8 8888 -88 8888 8 8888 8 8 888888888888 8 888888888888 `8.`8888. 8 888888888888 -88 8888 8 8888 8 8 8888 8 8888 `8.`8888. 8 8888 -88 8888 8 8888888888888 8 8888 8 8888 `8.`8888. 8 8888 -`8 8888 .8' 8 8888 8 8 8888 8 8888 8b `8.`8888. 8 8888 - 8888 ,88' 8 8888 8 8 8888 8 8888 `8b. ;8.`8888 8 8888 - `8888888P' 8 8888 8 8 888888888888 8 888888888888 `Y8888P ,88P' 8 888888888888 - . . - ,8. ,8. 8 8888888888 b. 8 8 8888 88 - ,888. ,888. 8 8888 888o. 8 8 8888 88 - .`8888. .`8888. 8 8888 Y88888o. 8 8 8888 88 - ,8.`8888. ,8.`8888. 8 8888 .`Y888888o. 8 8 8888 88 - ,8'8.`8888,8^8.`8888. 8 888888888888 8o. `Y888888o. 8 8 8888 88 - ,8' `8.`8888' `8.`8888. 8 8888 8`Y8o. `Y88888o8 8 8888 88 - ,8' `8.`88' `8.`8888. 8 8888 8 `Y8o. `Y8888 8 8888 88 - ,8' `8.`' `8.`8888. 8 8888 8 `Y8o. `Y8 ` 8888 ,8P - ,8' `8 `8.`8888. 8 8888 8 `Y8o.` 8888 ,d8P -,8' ` `8.`8888. 8 888888888888 8 `Yo `Y88888P' -]] +local register_script_event_hook = hook.register_script_event_hook +local remove_script_event_hook = hook.remove_script_event_hook +local register_net_event_hook = hook.register_net_event_hook +local remove_net_event_hook = hook.remove_net_event_hook -local version = "1.8.2" -local loadCurrentMenu -local httpTrustedOff +local add_event_listener = event.add_event_listener +local remove_event_listener = event.remove_event_listener --- Version check -if menu.is_trusted_mode_enabled(1 << 3) and menu.is_trusted_mode_enabled(1 << 2) then - menu.create_thread(function() - local vercheckKeys = {ctrl = MenuKey(), space = MenuKey(), enter = MenuKey(), rshift = MenuKey()} - vercheckKeys.ctrl:push_vk(0x11); vercheckKeys.space:push_vk(0x20); vercheckKeys.enter:push_vk(0x0D); vercheckKeys.rshift:push_vk(0xA1) +local register_command = console.register_command +local remove_command = console.remove_command - local responseCode, githubVer = web.get("https://raw.githubusercontent.com/GhustOne/CheeseMenu/main/VERSION.txt") - if responseCode == 200 then - githubVer = githubVer:gsub("[\r\n]", "") - if githubVer ~= version then - local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.5+0.5 - local strings = { - version_compare = "\nCurrent Version:"..version.."\nLatest Version:"..githubVer, - version_compare_x_offset = v2(-scriptdraw.get_text_size("\nCurrent Version:"..version.."\nLatest Version:"..githubVer, text_size).x/graphics.get_screen_width(), 0), - new_ver_x_offset = v2(-scriptdraw.get_text_size("New version available. Press CTRL or SPACE to skip or press ENTER or RIGHT SHIFT to update.", text_size).x/graphics.get_screen_width(), 0), - } - strings.changelog_rc, strings.changelog = web.get("https://raw.githubusercontent.com/GhustOne/CheeseMenu/main/CHANGELOG.txt") - if strings.changelog_rc == 200 then - strings.changelog = "\n\n\nChangelog:\n"..strings.changelog - else - strings.changelog = "" +local Parent = menu_originals.add_feature("Proddy's Script Manager", "parent", menu.get_feature_by_hierarchy_key("local.script_features.cheese_menu").id) +local ParentId = Parent.id +local FirstChild +local AutoloadFirstChild +local FilterFeat + +menu_originals.add_feature("Trusted Mode", "parent", ParentId) + +local AutoloadParent = menu_originals.add_feature("Manage Autoload Scripts", "parent", ParentId) +local AutoloadParentId = AutoloadParent.id + +local assert = assert +local error = error +local type = type + +local UnloadScript + +local function DeleteFeature(Feat) + if Feat then + if Feat.type == 2048 then + for i=1,Feat.child_count do + DeleteFeature(Feat.children[1]) + end + elseif Feat.type == 1 then + if Feat.data and type(Feat.data) == "table" and Feat.data.ScriptManager then + print("Deleting script: " .. Feat.name) + UnloadScript(Feat) + print("Deleted script: " .. Feat.name) + end + end + if Feat.activate_feat_func then + delete_feature(Feat.id) + else + menu_originals.delete_feature(Feat.id) + end + end +end +local function DeletePlayerFeature(Feat) + delete_player_feature(Feat.id) +end + +UnloadScript = function(f) + if Exiting then return end + if not f.data or type(f.data) ~= "table" or not f.data.ScriptManager then return end + + print("Unloading script: " .. f.name) + + local success, result = og_pcall(function(data) + if data.exits then + for k,v in pairs(data.exits) do + v({["code"]=69}) + end + end + + if data.features then + local ids = {} + for k in pairs(data.features) do + ids[#ids + 1] = k + end + table.sort(ids) + for i = #ids,1,-1 do + DeleteFeature(data.features[ids[i]]) + end + end + + if data.player_features then + local ids = {} + for k in pairs(data.player_features) do + ids[#ids + 1] = k + end + table.sort(ids) + for i = #ids,1,-1 do + DeletePlayerFeature(data.player_features[ids[i]]) + end + end + + if data.threads then + local ids = {} + for k in pairs(data.threads) do + ids[#ids + 1] = k + end + table.sort(ids) + for i = #ids,1,-1 do + delete_thread(ids[i]) + end + end + + if data.script_hooks then + local ids = {} + for k in pairs(data.script_hooks) do + ids[#ids + 1] = k + end + table.sort(ids) + for i = #ids,1,-1 do + remove_script_event_hook(ids[i]) + end + end + + if data.net_hooks then + local ids = {} + for k in pairs(data.net_hooks) do + ids[#ids + 1] = k + end + table.sort(ids) + for i = #ids,1,-1 do + remove_net_event_hook(ids[i]) + end + end + + if data.events then + for eventName,v in pairs(data.events) do + local ids = {} + for k in pairs(v) do + ids[#ids + 1] = k end - strings.changelog_x_offset = v2(-scriptdraw.get_text_size(strings.changelog, text_size).x/graphics.get_screen_width(), 0) - local stringV2size = v2(2, 2) - while true do - scriptdraw.draw_text("New version available. Press CTRL or SPACE to skip or press ENTER or RIGHT SHIFT to update.", strings.new_ver_x_offset, stringV2size, text_size, 0xFF0CB4F4, 2) - scriptdraw.draw_text(strings.version_compare, strings.version_compare_x_offset, stringV2size, text_size, 0xFF0CB4F4, 2) - scriptdraw.draw_text(strings.changelog, strings.changelog_x_offset, stringV2size, text_size, 0xFF0CB4F4, 2) - if vercheckKeys.ctrl:is_down() or vercheckKeys.space:is_down() then - loadCurrentMenu() - break - elseif vercheckKeys.enter:is_down() or vercheckKeys.rshift:is_down() then - local responseCode, autoupdater = web.get([[https://raw.githubusercontent.com/GhustOne/CheeseMenu/main/CMAutoUpdater.lua]]) - if responseCode == 200 then - autoupdater = load(autoupdater) - menu.create_thread(function() - menu.notify("Update started, please wait...", "Cheese Menu") - local status = autoupdater() - if status then - if type(status) == "string" then - menu.notify("Updating local files failed, one or more of the files could not be opened.\nThere is a high chance the files got corrupted, please redownload the menu.", "Cheese Menu", 5, 0x0000FF) - else - menu.notify("Update successful", "Cheese Menu", 4, 0x00FF00) - dofile(utils.get_appdata_path("PopstarDevs", "2Take1Menu").."\\scripts\\cheesemenu.lua") - end - else - menu.notify("Download for updated files failed, current files have not been replaced.", "Cheese Menu", 5, 0x0000FF) - end - end, nil) - break - else - menu.notify("Getting Updater failed. Check your connection and try downloading manually.", "Cheese Menu", 5, 0x0000FF) - end - end - system.wait(0) + table.sort(ids) + for i = #ids,1,-1 do + remove_event_listener(eventName, ids[i]) end - else - loadCurrentMenu() end end - end, nil) -else - if menu.is_trusted_mode_enabled(1 << 2) then - httpTrustedOff = true + + if data.commands then + for name in pairs(data.commands) do + remove_command(name) + end + end + end, f.data) + + LoadedScripts[f.name] = nil + f.data = nil + f.on = false + + if success then + notify("Unloaded script: " .. f.name, 0xFF00FF00) else - menu.notify("Trusted mode > Natives has to be on. If you wish for auto updates enable Http too.", "Cheese Menu", 5, 0x0000FF) + notify("Failed to unload script: " .. f.name .. "\n" .. result, 0xFF00FF00) end + + collectgarbage("collect") end -local features -local currentMenu -local func -local stuff -local menu_configuration_features -function loadCurrentMenu() - features = {OnlinePlayers = {}} - currentMenu = features - func = {} - stuff = { - pid = -1, - player_info = { - {"Player ID", "0"}, - {"God", "false"}, - {"Proofs (God)", "false"}, - {"Vehicle God", "false"}, - {"Flagged as Modder", "false"}, - {"Host", "false"}, - {"Wanted", "0"}, - {"Health", "327/327"}, - {"Armor", "50"}, - {"IP", "0.0.0.0"}, - {"SCID", "133769420"}, - {"Host Token", "0xdeadbeef"}, - {"Host Priority", "0"}, - max_health = "/327", - name = "cheesemenu" - }, - proofs = { - bulletProof = native.ByteBuffer8(), - fireProof = native.ByteBuffer8(), - explosionProof = native.ByteBuffer8(), - collisionProof = native.ByteBuffer8(), - meleeProof = native.ByteBuffer8(), - steamProof = native.ByteBuffer8(), - p7 = native.ByteBuffer8(), - drownProof = native.ByteBuffer8(), - }, - scroll = 1, - scrollHiddenOffset = 0, - drawHiddenOffset = 0, - trusted_mode = 0, - old_selected = 0, - player_submenu_sort = 0, - previousMenus = {}, - threads = {}, - feature_by_id = {}, - player_feature_by_id = {}, - feature_hints = {}, - path = { - scripts = utils.get_appdata_path("PopstarDevs", "2Take1Menu").."\\scripts\\" - }, - hotkeys = {}, - hotkey_cooldowns = {}, - hotkeys_to_vk = {}, - table_sort_functions = { - [0] = function(a, b) return a.pid < b.pid end, - function(a, b) return a.pid > b.pid end, - function(a, b) return a.name:lower() < b.name:lower() end, - function(a, b) return a.name:lower() > b.name:lower() end, - function(a, b) return player.get_player_host_priority(a.pid) < player.get_player_host_priority(b.pid) end, - function(a, b) return player.get_player_host_priority(a.pid) > player.get_player_host_priority(b.pid) end - }, - char_codes = { - ["ENTER"] = 0x0D, - ["0"] = 0x30, - ["1"] = 0x31, - ["2"] = 0x32, - ["3"] = 0x33, - ["4"] = 0x34, - ["5"] = 0x35, - ["6"] = 0x36, - ["7"] = 0x37, - ["8"] = 0x38, - ["9"] = 0x39, - ["A"] = 0x41, - ["B"] = 0x42, - ["C"] = 0x43, - ["D"] = 0x44, - ["E"] = 0x45, - ["F"] = 0x46, - ["G"] = 0x47, - ["H"] = 0x48, - ["I"] = 0x49, - ["J"] = 0x4A, - ["K"] = 0x4B, - ["L"] = 0x4C, - ["M"] = 0x4D, - ["N"] = 0x4E, - ["O"] = 0x4F, - ["P"] = 0x50, - ["Q"] = 0x51, - ["R"] = 0x52, - ["S"] = 0x53, - ["T"] = 0x54, - ["U"] = 0x55, - ["V"] = 0x56, - ["W"] = 0x57, - ["X"] = 0x58, - ["Y"] = 0x59, - ["Z"] = 0x5A, - ["NUM0"] = 0x60, - ["NUM1"] = 0x61, - ["NUM2"] = 0x62, - ["NUM3"] = 0x63, - ["NUM4"] = 0x64, - ["NUM5"] = 0x65, - ["NUM6"] = 0x66, - ["NUM7"] = 0x67, - ["NUM8"] = 0x68, - ["NUM9"] = 0x69, - ["Space"] = 0x20, - [";"] = 0xBA, - ["PLUS"] = 0xBB, - [","] = 0xBC, - ["-"] = 0xBD, - ["DOT"] = 0xBE, - ["/"] = 0xBF, - ["`"] = 0xC0, - ["LSQREBRACKET"] = 0xDB, - ["\\"] = 0xDC, - ["RSQREBRACKET"] = 0xDD, - ["QUOTE"] = 0xDE, - ["NUM*"] = 0x6A, - ["NUMPLUS"] = 0x6B, - ["NUM-"] = 0x6D, - ["NUMDEL"] = 0x6E, - ["NUM/"] = 0x6F, - ["PAGEUP"] = 0x21, - ["PAGEDOWN"] = 0x22, - ["END"] = 0x23, - ["HOME"] = 0x24, - ["SCROLLLOCK"] = 0x91, - ["LEFTARROW"] = 0x25, - ["UPARROW"] = 0x26, - ["RIGHTARROW"] = 0x27, - ["DOWNARROW"] = 0x28, - ["SELECT"] = 0x29, - ["INS"] = 0x2D, - ["DEL"] = 0x2E, - ["PAUSE"] = 0x13, - ["CAPSLOCK"] = 0x14, - ["BACKSPACE"] = 0x08, - ["LSHIFT"] = 0xA0, - ["RSHIFT"] = 0xA1, - ["LCONTROL"] = 0xA2, - ["RCONTROL"] = 0xA3, - ["LALT"] = 0xA4, - ["RALT"] = 0xA5, - ["F1"] = 0x70, - ["F2"] = 0x71, - ["F3"] = 0x72, - ["F4"] = 0x73, - ["F5"] = 0x74, - ["F6"] = 0x75, - ["F7"] = 0x76, - ["F8"] = 0x77, - ["F9"] = 0x78, - ["F10"] = 0x79, - ["F11"] = 0x7A, - ["F12"] = 0x7B, - ["F13"] = 0x7C, - ["F14"] = 0x7D, - ["F15"] = 0x7E, - ["F16"] = 0x7F, - ["F17"] = 0x80, - ["F18"] = 0x81, - ["F19"] = 0x82, - ["F20"] = 0x83, - ["F21"] = 0x84, - ["F22"] = 0x85, - ["F23"] = 0x86, - ["F24"] = 0x87, - }, - hotkey_notifications = {toggle = true, action = false}, - controls = { - left = "LEFTARROW", - up = "UPARROW", - right = "RIGHTARROW", - down = "DOWNARROW", - select = "ENTER", - back = "BACKSPACE", - open = "F4", - setHotkey = "F11", - specialKey = "LCONTROL", - }, - vkcontrols = { - left = 0x25, - up = 0x26, - right = 0x27, - down = 0x28, - select = 0x0D, - back = 0x08, - open = 0x73, - setHotkey = 0x7A, - specialKey = 0xA2, - }, - drawScroll = 0, - maxDrawScroll = 0, - menuData = { - menuToggle = false, - menuNav = true, - chatBoxOpen = false, - pos_x = 0.5, - pos_y = 0.44652777777, - width = 0.2, - height = 0.305, - border = 0.0013888, - selector_speed = 1, - slider = { - width = 0.2, - height = 0.01, - heightActive = 0.025, - }, - footer = { - footer_y_offset = 0, - padding = 0.0078125, - footer_size = 0.019444444, - draw_footer = true, - footer_pos_related_to_background = false, - footer_text = "Made by GhostOne", - }, - fonts = { - text = 0, - footer = 0, - hint = 0 - }, - side_window = { - on = true, - offset = {x = 0, y = 0}, - spacing = 0.0547222, - width = 0.3, - padding = 0.01 - }, - header = "cheese_menu", - feature_offset = 0.025, - feature_scale = {x = 0.2, y = 0.025}, - padding = { - name = 0.003125, - parent = 0.003125, - value = 0.048125, - slider = 0.003125, - }, - text_size = (((graphics.get_screen_width()*graphics.get_screen_height())/3686400)*0.45+0.25), - text_size_modifier = 1, - footer_size_modifier = 1, - hint_size_modifier = 1, - text_y_offset = -0.0055555555, - color = {}, - files = {}, - background_sprite = { - sprite = nil, - size = 1, - loaded_sprites = {}, - offset = {x = 0, y = 0} - }, - max_features = 12, - set_max_features = function(self, int) - int = math.floor(int+0.5) - self.height = int * self.feature_offset - self.max_features = int - end - }, - disable_all_controls = function() - while true do - for i = 0, 360 do - controls.disable_control_action(0, i, true) - end - system.wait(0) - end - end - } - - stuff.menuData.color = { - background = {r = 0, g = 0, b = 0, a = 0}, - sprite = 0xE6FFFFFF, - slider_active = {r = 255, g = 200, b = 0, a = 255}, - slider_background = {r = 0, g = 0, b = 0, a = 160}, - slider_text = {r = 0, g = 0, b = 0, a = 255}, - slider_selectedActive = {r = 255, g = 255, b = 255, a = 160}, - slider_selectedBackground = {r = 255, g = 160, b = 0, a = 180}, - feature_bottomLeft = {r = 255, g = 160, b = 0, a = 170}, - feature_topLeft = {r = 255, g = 160, b = 0, a = 170}, - feature_topRight = {r = 255, g = 160, b = 0, a = 170}, - feature_bottomRight = {r = 255, g = 160, b = 0, a = 170}, - feature_selected_bottomLeft = {r = 0, g = 0, b = 0, a = 200}, - feature_selected_topLeft = {r = 0, g = 0, b = 0, a = 200}, - feature_selected_topRight = {r = 0, g = 0, b = 0, a = 200}, - feature_selected_bottomRight = {r = 0, g = 0, b = 0, a = 200}, - text_selected = {r = 255, g = 200, b = 0, a = 180}, - text = {r = 0, g = 0, b = 0, a = 180}, - border = {r = 0, g = 0, b = 0, a = 180}, - footer = {r = 255, g = 160, b = 0, a = 170}, - footer_text = {r = 0, g = 0, b = 0, a = 180}, - notifications = {r = 255, g = 200, b = 0, a = 255}, - side_window = {r = 0, g = 0, b = 0, a = 150}, - side_window_text = {r = 255, g = 255, b = 255, a = 220} - } - - stuff.path.cheesemenu = stuff.path.scripts.."cheesemenu\\" - for k, v in pairs(utils.get_all_sub_directories_in_directory(stuff.path.cheesemenu)) do - stuff.path[v] = stuff.path.cheesemenu..v.."\\" - end - - stuff.menuData.background_sprite.fit_size_to_width = function(self) - self.size = stuff.menuData.width*graphics.get_screen_width()/scriptdraw.get_sprite_size(func.load_sprite(stuff.path.background..(self.sprite or ""), stuff.menuData.background_sprite.loaded_sprites)).x - end - stuff.menuData.background_sprite.fit_size_to_height = function(self) - self.size = stuff.menuData.height*graphics.get_screen_height()/scriptdraw.get_sprite_size(func.load_sprite(stuff.path.background..(self.sprite or ""), stuff.menuData.background_sprite.loaded_sprites)).y - end - - stuff.image_ext = {"gif", "bmp", "jpg", "jpeg", "png", "2t1", "dds"} - stuff.menuData.files.headers = {} - for _, ext in pairs(stuff.image_ext) do - for _, image in pairs(utils.get_all_files_in_directory(stuff.path.header, ext)) do - stuff.menuData.files.headers[#stuff.menuData.files.headers + 1] = image - end - end - for k, v in pairs(utils.get_all_sub_directories_in_directory(stuff.path.header)) do - stuff.menuData.files.headers[#stuff.menuData.files.headers + 1] = v..".ogif" - end - - stuff.menuData.files.ui = {} - for k, v in pairs(utils.get_all_files_in_directory(stuff.path.ui, "lua")) do - stuff.menuData.files.ui[k] = v:sub(1, #v - 4) - end - - stuff.menuData.files.background = {} - for _, ext in pairs(stuff.image_ext) do - for k, v in pairs(utils.get_all_files_in_directory(stuff.path.background, "png")) do - stuff.menuData.files.background[k] = v - end - end - - stuff.menuData_methods = { - set_color = function(self, colorName, r, g, b, a) - assert(self[colorName], "field "..colorName.." does not exist") - local colors = {r = r or false, g = g or false, b = b or false, a = a or false} - for k, v in pairs(colors) do - if not v then - if type(self[colorName]) == "table" then - colors[k] = self[colorName][k] - else - colors[k] = func.convert_int_to_rgba(self[colorName], k) - end - end - end - for k, v in pairs(colors) do - assert(v <= 255 and v >= 0, "attempted to set invalid "..k.." value to field "..colorName) - end - if type(self[colorName]) == "table" then - self[colorName] = colors - else - self[colorName] = (colors.a << 24) + (colors.b << 16) + (colors.g << 8) + colors.r - end - end - } - function func.convert_rgba_to_int(r, g, b, a) - if type(r) == "table" then - local colorTable = r - r = colorTable.r or colorTable[1] - g = colorTable.g or colorTable[2] - b = colorTable.b or colorTable[3] - a = colorTable.a or colorTable[4] - end - if not a then - a = 255 - end - assert(r and g and b, "one or more of the r, g, b values is invalid") - assert((a <= 255 and a >= 0) and (b <= 255 and b >= 0) and (g <= 255 and g >= 0) and (r <= 255 and r >= 0), "rgba values cannot be more than 255 or less than 0") - return (a << 24) + (b << 16) + (g << 8) + r - end - - stuff.conversionValues = {a = 24, b = 16, g = 8, r = 0} - function func.convert_int_to_rgba(...) - local int, val1, val2, val3, val4 = ... - local values = {val1, val2, val3, val4} - - for k, v in pairs(values) do - values[k] = int >> stuff.conversionValues[v] & 0xff - end - return table.unpack(values) - end - setmetatable(stuff.menuData.color, {__index = stuff.menuData_methods}) - - function func.convert_int_ip(ip) - local ipTable = {} - ipTable[1] = ip >> 24 & 255 - ipTable[2] = ip >> 16 & 255 - ipTable[3] = ip >> 8 & 255 - ipTable[4] = ip & 255 - - return table.concat(ipTable, ".") - end - - stuff.input = require("cheesemenu.libs.Get Input") - local gltw = require("cheesemenu.libs.GLTW") - local cheeseUtils = require("cheesemenu.libs.CheeseUtilities") - assert(gltw, "GLTW library is not found, please install the menu with 'cheesemenu' folder.") - - - gltw.read("controls", stuff.path.cheesemenu, stuff.controls, false, true) - for k, v in pairs(stuff.controls) do - stuff.vkcontrols[k] = stuff.char_codes[v] - end - - gltw.read("hotkey notifications", stuff.path.hotkeys, stuff.hotkey_notifications, false, true) - stuff.hotkeys = gltw.read("hotkeys", stuff.path.hotkeys, nil, false, true) or {} - stuff.hierarchy_key_to_hotkey = {} - for k, v in pairs(stuff.hotkeys) do - stuff.hotkey_cooldowns[k] = 0 - - local string_to_vk = {} - for char in k:gmatch("%|*([^%|]+)%|*") do - string_to_vk[#string_to_vk+1] = stuff.char_codes[char] - end - stuff.hotkeys_to_vk[k] = string_to_vk - - if type(v) == "table" then - for i, e in pairs(v) do - stuff.hierarchy_key_to_hotkey[i] = k - end - end - end - - --local originalGetInput = input.get - if stuff.input then - function input.get(title, default, len, Type) - local originalmenuToggle = stuff.menuData.menuToggle - stuff.menuData.menuToggle = false - stuff.menuData.chatBoxOpen = true - local status, gottenInput = stuff.input.get_input(title, default, len, Type) - - func.toggle_menu(originalmenuToggle) - stuff.menuData.chatBoxOpen = false - return status, gottenInput - end - end - - -- Credit to kektram for these functions - do - local _ENV = { - getmetatable = debug.getmetatable - } - function stuff.rawset(Table, index, value) -- Matches performance of normal rawset. - local metatable = getmetatable(Table) - local __newindex - if metatable then - __newindex = metatable.__newindex - metatable.__newindex = nil - end - Table[index] = value - if __newindex then - metatable.__newindex = __newindex - end - return Table - end - end - do - local _ENV = { - getmetatable = debug.getmetatable - } - function stuff.rawget(Table, index, value) -- Matches performance of normal rawget. - local metatable = getmetatable(Table) - local __index - if metatable then - __index = metatable.__index - metatable.__index = nil - end - local value = Table[index] - if __index then - metatable.__index = __index - end - return value - end - end - -- - - stuff.playerSpecialValues = {value = true, min = true, max = true, mod = true, on = true, real_value = true, real_max = true, real_min = true, real_mod = true, real_on = true} - - stuff.featMetaTable = { - __index = function(t, k) - if k == "is_highlighted" then - return t == currentMenu[stuff.scroll + stuff.scrollHiddenOffset] - elseif k == "parent" then - return t.type >> 15 & 1 == 0 and func.get_feature(t.parent_id) or func.get_player_feature(t.parent_id) - elseif k == "value" or k == "min" or k == "mod" or k == "max" or k == "str_data" or k == "type" or k == "id" or k == "on" or k == "hidden" or k == "data" then - if t.playerFeat and k ~= "str_data" and k ~= "type" and k ~= "id" and k ~= "hidden" and k ~= "data" then - return stuff.rawget(t, "table_"..k) - else - return stuff.rawget(t, "real_"..k) - end - elseif k == "children" and t.type >> 11 & 1 ~= 0 then - return t:get_children() - elseif k == "hint" then - return stuff.feature_hints[t.id].str - --[[ else - return stuff.rawget(t, k) ]] - end - end, - - __newindex = function(t, k, v) - assert(k ~= "id" and k ~= "children" and k ~= "type" and k ~= "str_data" and k ~= "is_highlighted", "'"..k.."' is read only") - if k == "on" and type(v) == "boolean" then - if t.real_on == v then - return - end - --[[ if t.type >> 11 & 1 ~= 0 and t.real_on ~= nil then - func.check_scroll(t.index, (t.parent_id > 0 and t.parent or features), not v) - end ]] - stuff.rawset(t, "real_on", v) - - if t.feats then - for pid, feat in pairs(t.feats) do - if player.is_player_valid(pid) then - feat.on = v - --[[ if feat.type >> 11 & 1 ~= 0 then - func.check_scroll(feat.index, (feat.parent_id > 0 and stuff.feature_by_id[feat.ps_parent_id] or stuff.PlayerParent), not v) - end ]] - end - end - else - if v then - t:activate_feat_func() - end - end - elseif k == "value" or k == "min" or k == "mod" or k == "max" then - if k ~= "value" and t.type >> 5 & 1 ~= 0 then -- value_str - error("max, min and mod are readonly for value_str features") - end - v = tonumber(v) - - assert(t.type >> 1 & 1 ~= 0, "feat type not supported: "..t.type) -- value_[if], value_str - assert(v, "tried to set "..k.." property to a non-number value") - - if t.type >> 5 & 1 ~= 0 then -- value_str - if v < 0 then - v = 0 - elseif t.real_str_data then - if v+1 > #t.real_str_data and #t.real_str_data ~= 0 then - v = #t.real_str_data-1 - end - end - end - - if t.type >> 1 & 1 ~= 0 then - if t.type >> 3 & 1 ~= 0 or t.type >> 5 & 1 ~= 0 then -- value_str - v = math.floor(v) - end - - stuff.rawset(t, "real_"..k, v) - if t.type & 140 ~= 0 then -- i|f|slider - if not t.real_max then - t.real_max = 0 - end - if not t.real_min then - t.real_min = 0 - end - if not t.real_mod then - t.real_mod = 1 - end - if not t.real_value then - t.real_value = 0 - end - - stuff.rawset(t, "real_value", t.real_value >= t.real_max and t.real_max or t.real_value <= t.real_min and t.real_min or t.real_value) - end - - if t["table_"..k] then - local is_num = t.type & 140 ~= 0 - for i = 0, 31 do - t["table_"..k][i] = v - if is_num then - t["table_value"][i] = t["table_value"][i] >= t["table_max"][i] and t["table_max"][i] or t["table_value"][i] <= t["table_min"][i] and t["table_min"][i] or t["table_value"][i] - end - end - end - end - elseif k == "hidden" then - assert(type(v) == "boolean", "hidden only accepts booleans") - if t.real_hidden == v then - return - end - - --[[ if t.real_hidden ~= nil then - func.check_scroll(t.index, (t.parent_id > 0 and t.parent or features), v) - end ]] - - t.real_hidden = v - if t.feats then - for _, feat in ipairs(t.feats) do - feat.hidden = v - end - end - if v then - func.deleted_or_hidden_parent_check(t) - end - elseif k == "data" then - stuff.rawset(t, "real_data", v) - if t.feats then - for i, e in pairs(t.feats) do - t.feats[i].real_data = v - end - end - elseif k == "hint" then - assert(type(v) == "string", "Feat.hint only supports strings") - if not v then - stuff.feature_hints[t.id] = nil - return - end - local str = cheeseUtils.wrap_text(v, stuff.menuData.fonts.hint, stuff.menuData.text_size * stuff.menuData.hint_size_modifier, stuff.menuData.width*2-scriptdraw.size_pixel_to_rel_x(25)) - stuff.feature_hints[t.id] = {str = str, size = scriptdraw.get_text_size(str, 1, stuff.menuData.fonts.hint), original = v} - else - stuff.rawset(t, k, v) - end - end - } - - stuff.playerfeatMetaTable = { - __index = function(t, k) - if k == "is_highlighted" then - return t == currentMenu[stuff.scroll + stuff.scrollHiddenOffset] - elseif k == "parent" then - return func.get_player_feature(t.parent_id) - elseif k == "str_data" or k == "type" or k == "id" or k == "data" or k == "hidden" then - return stuff.rawget(t, "real_"..k) - elseif stuff.playerSpecialValues[k] then - if t["table_"..k:gsub("real_", "")] then - return t["table_"..k:gsub("real_", "")][t.pid] - end - elseif k == "children" and t.type >> 11 & 1 ~= 0 then - return t:get_children() - else - return stuff.rawget(t, k) - end - end, - - __newindex = function(t, k, v) - assert(k ~= "id" and k ~= "children" and k ~= "type" and k ~= "str_data" and k ~= "is_highlighted", "'"..k.."' is read only") - if (k == "on" or k == "real_on") and type(v) == "boolean" then - t["table_on"][t.pid] = v - if v then - t:activate_feat_func() - end - elseif stuff.playerSpecialValues[k] then - k = k:gsub("real_", "") - if k ~= "value" and t.type >> 5 & 1 ~= 0 then - error("max, min and mod are readonly for value_str features") - end - v = tonumber(v) - - assert(t.type >> 1 & 1 ~= 0, "feat type not supported") - assert(v, "tried to set "..k.." property to a non-number value") - - if t.type >> 5 & 1 ~= 0 then - if v < 0 then - v = 0 - elseif t.real_str_data then - if v+1 > #t.real_str_data and #t.real_str_data ~= 0 then - v = #t.real_str_data-1 - end - end - end +-- modified +local limited_functions = { + { + namespace = "stats", + table = stats, + ["stat_set_int"] = true, + ["stat_set_float"] = true, + ["stat_set_bool"] = true, + ["stat_set_i64"] = true, + ["stat_set_u64"] = true, + ["stat_set_masked_int"] = true, + ["stat_set_masked_bool"] = true, + }, + { + namespace = "script", + table = script, + ["set_global_f"] = true, + ["set_global_i"] = true, + ["set_global_s"] = true, + ["set_local_f"] = true, + ["set_local_i"] = true, + ["set_local_s"] = true, + }, + { + namespace = "native", + table = native, + ["call"] = true, + }, + { + namespace = "web", + table = web, + ["post"] = true, + ["get"] = true, + ["request"] = true, + ["urlencode"] = true, + ["urldecode"] = true, + }, + { + namespace = "memory", + table = memory, + ["get_any"] = true, + ["get_entity"] = true, + ["get_ped"] = true, + ["get_vehicle"] = true, + ["get_object"] = true, + ["get_pickup"] = true, + ["read_u64"] = true, + ["read_u32"] = true, + ["read_u16"] = true, + ["read_u8"] = true, + ["read_i64"] = true, + ["read_i32"] = true, + ["read_i16"] = true, + ["read_i8"] = true, + ["read_f32"] = true, + }, +} - if t.type >> 1 & 1 ~= 0 then - if t.type >> 3 & 1 ~= 0 or t.type >> 5 & 1 ~= 0 then -- value_i|str - v = math.floor(v) - end +local trusted_names = { + [0] = "Stats", + "Globals / Locals", + "Natives", + "HTTP", + "Memory" +} - t["table_"..k][t.pid] = v - if t.type & 140 ~= 0 then -- i|f|slider - if not t.real_max then - t.real_max = 0 - end - if not t.real_min then - t.real_min = 0 - end - if not t.real_mod then - t.real_mod = 1 - end - if not t.real_value then - t.real_value = 0 - end +local modified_functions = { + stats = {}, + script = {}, + native = {}, + web = {}, + memory = {}, +} - t["table_value"][t.pid] = t["table_value"][t.pid] >= t["table_max"][t.pid] and t["table_max"][t.pid] or t["table_value"][t.pid] <= t["table_min"][t.pid] and t["table_min"][t.pid] or t["table_value"][t.pid] - end +for k, v in ipairs(limited_functions) do + local namespace = v.namespace + for name, data in pairs(v) do + if data == true then + modified_functions[namespace][name] = function(...) + local is_flag_on, notify = menu.is_trusted_mode_enabled(1 << (k-1)) + if is_flag_on then + return v.table[name](...) + elseif notify then + menu.notify("Trusted Flag '"..trusted_names[k-1].."' is not enabled.\nFunction used: "..namespace..'.'..name, "Cheese Menu", 5, 0x00ffff) end - elseif k == "data" then - t.real_data = v - else - stuff.rawset(t, k, v) end end - } - - -- featMethods + end +end +-- - -- dogshit dont use - --[[ stuff.set_val = function(self, valueType, val, dont_set_all) - assert(stuff.type_id.id_to_name[self.type]:match("value_[if]") or stuff.type_id.id_to_name[self.type]:match("value_str"), "feat type not supported") - assert(tonumber(val), "tried to set "..valueType.." to a non-number value") - if stuff.type_id.id_to_name[self.type]:match("value_i") then - val = tonumber(math.floor(val)) - else - val = tonumber(val) - end +local function LoadScript(f) + if f.on then + if not f.data then + local Filename = f.name + local Filepath = Paths.Scripts .. "\\" .. Filename - if valueType == "value" then - if self.real_min then - if val < self.real_min then - val = self.real_min - end - else - if val < 0 then - val = 0 - end + if not utils.file_exists(Filepath) then + notify("Could not find script: " .. Filename,0xFF0000FF) + LoadedScripts[f.name] = nil + f.data = nil + f.on = false + return end - if self.real_max then - if val > self.real_max then - val = self.real_max - end - elseif self.real_str_data then - if val+1 > #self.real_str_data then - val = #self.real_str_data-1 + + print("Enabling script: " .. f.name) + f.data = {} + f.data.ScriptManager = true + f.data.features = {} + f.data.player_features = {} + f.data.threads = {} + f.data.script_hooks = {} + f.data.net_hooks = {} + f.data.events = {} + f.data.exits = {} + f.data.commands = {} + + local env = CloneTable(_G) + function env.SetGlobal(Name, Value) + assert(type(Name) == "string", "Arg #1 (Name) must be a string") + + _G[Name] = Value + for i=FirstChild,Parent.child_count do + local feat = Parent.children[i] + if feat.data and feat.data.env then + feat.data.env[Name] = Value + end end end - end - self[valueType] = val - if self["table_"..valueType] and not dont_set_all then - for i = 0, 31 do - self["table_"..valueType][i] = val + for namespace, func_table in pairs(modified_functions) do + local env_namespace = env[namespace] + for name, func in pairs(func_table) do + env_namespace[name] = func + end end - end - end - - stuff.set_value = function(self, val, dont_set_all) - stuff.set_val(self, "value", val, dont_set_all) - end - stuff.set_max = function(self, val, dont_set_all) - stuff.set_val(self, "max", val, dont_set_all) - end - stuff.set_min = function(self, val, dont_set_all) - stuff.set_val(self, "min", val, dont_set_all) - end - stuff.set_mod = function(self, val, dont_set_all) - stuff.set_val(self, "mod", val, dont_set_all) - end ]] - stuff.get_str_data = function(self) - assert(self.type >> 5 & 1 ~= 0, "used get_str_data on a feature that isn't value_str") - return self.str_data - end + env.cheeseUIdata = cheeseUIdata - stuff.set_str_data = function(self, stringTable) - assert(type(stringTable) == "table", "tried to set str_data property to a non-table value") - local numberedTable - for k, v in pairs(stringTable) do - if type(k) ~= "number" then - numberedTable = {} - for k, v in pairs(stringTable) do - numberedTable[#numberedTable + 1] = v + env.menu.add_feature = function(...) + local feat = add_feature(...) + if feat then + f.data.features[feat.id] = feat end - break + return feat end - end - self.real_str_data = numberedTable or stringTable - if self.real_value+1 > #self.real_str_data then - self.real_value = #self.real_str_data-1 >= 0 and #self.real_str_data-1 or 0 - end - if self.feats then - for k, v in pairs(self.table_value) do - if v+1 > #self.real_str_data then - self.table_value[k] = #self.real_str_data-1 + env.menu.add_player_feature = function(...) + local feat = add_player_feature(...) + if feat then + f.data.player_features[feat.id] = feat end + return feat end - for k, v in pairs(self.feats) do - v.real_str_data = stringTable - end - end - end - - stuff.toggle = function(self, bool) - if self.type & 1 ~= 0 then - if bool ~= nil then - self.real_on = bool - self:activate_feat_func() - else - self.real_on = not self.real_on - self:activate_feat_func() + env.menu.delete_feature = function(id) + local success = delete_feature(id) + if success then + f.data.features[id] = nil + end + return success end - else - self:activate_feat_func() - end - end - - stuff.get_children = function(self) - local children = {} - for k, v in ipairs(self) do - if type(k) == "number" then - children[k] = v + env.menu.delete_player_feature = function(id) + local success = delete_player_feature(id) + if success then + f.data.player_features[id] = nil + end + return success end - end - return children - end - - -- function callback ~Thanks to Proddy for telling me that doing function() every time creates a new one and providing examples on how to use menu.create_thread with the function below - function stuff.feature_callback(self) - local pidordata = self.pid or self.data - if self.on ~= nil and self.type & 2049 == 0 then -- not toggle or parent - self.on = true - end - local continue = self:func(pidordata, self.data) - while continue == HANDLER_CONTINUE do - system.wait(0) - continue = self:func(pidordata, self.data) - end - if self.on ~= nil and self.type & 2049 == 0 then -- not toggle or parent - self.on = false - end - end - - function stuff.highlight_callback(self) - local pidordata = self.pid or self.data - self:hl_func(pidordata, self.data) - end - - stuff.activate_feat_func = function(self) - if not (self.thread) then - self.thread = 0 - end - if self.func and menu.has_thread_finished(self.thread) then - self.thread = menu.create_thread(stuff.feature_callback, self) - end - end - - stuff.activate_hl_func = function(self) - if self.hl_func then - if not self.hl_thread then - self.hl_thread = 0 + env.menu.create_thread = function(...) + local id = create_thread(...) + if id then + f.data.threads[id] = true + end + return id end - if menu.has_thread_finished(self.hl_thread) then - self.hl_thread = menu.create_thread(stuff.highlight_callback, self) + env.menu.delete_thread = function(id) + local success = delete_thread(id) + if success then + f.data.threads[id] = nil + end + return success end - end - end - - stuff.select = function(self) - local parent_of_feat_wanted = stuff.feature_by_id[self.parent_id] or features - - if not (parent_of_feat_wanted == currentMenu) then - stuff.previousMenus[#stuff.previousMenus + 1] = {menu = currentMenu, scroll = stuff.scroll, drawScroll = stuff.drawScroll, scrollHiddenOffset = stuff.scrollHiddenOffset} - currentMenu = parent_of_feat_wanted - end - - if not self.hidden then - local hiddenOffset = 0 - for k, v in ipairs(parent_of_feat_wanted) do - if type(k) == "number" then - if v.hidden and not (k > self.index) then - hiddenOffset = hiddenOffset + 1 - end + env.hook.register_script_event_hook = function(...) + local id = register_script_event_hook(...) + if id then + f.data.script_hooks[id] = true end + return id end - stuff.scroll = self.index - hiddenOffset - stuff.drawScroll = (stuff.maxDrawScroll >= self.index) and self.index-1 or stuff.maxDrawScroll - end - - stuff.scrollHiddenOffset = 0 - end - -- - - stuff.hotkey_feature_hierarchy_keys = {} - - stuff.type_id = { - name_to_id = { - toggle = 1 << 0, - slider = 1 << 2 | 1 << 1 | 1 << 0, - value_i = 1 << 3 | 1 << 1 | 1 << 0, - value_str = 1 << 5 | 1 << 1 | 1 << 0, - value_f = 1 << 7 | 1 << 1 | 1 << 0, - action = 1 << 9, - action_slider = 1 << 9 | 1 << 2 | 1 << 1, - action_value_i = 1 << 9 | 1 << 3 | 1 << 1, - action_value_str = 1 << 9 | 1 << 5 | 1 << 1, - action_value_f = 1 << 9 | 1 << 7 | 1 << 1, - autoaction_slider = 1 << 10 | 1 << 2 | 1 << 1, - autoaction_value_i = 1 << 10 | 1 << 3 | 1 << 1, - autoaction_value_str = 1 << 10 | 1 << 5 | 1 << 1, - autoaction_value_f = 1 << 10 | 1 << 7 | 1 << 1, - parent = 1 << 11 - }, - } - - --Functions - function func.add_feature(nameOfFeat, TypeOfFeat, parentOfFeat, functionCallback, highlightCallback, playerFeat) - assert((type(nameOfFeat) == "string"), "invalid name in add_feature") - assert((type(TypeOfFeat) == "string") and stuff.type_id.name_to_id[TypeOfFeat], "invalid type in add_feature") - assert((type(parentOfFeat) == "number") or not parentOfFeat, "invalid parent id in add_feature") - assert((type(functionCallback) == "function") or not functionCallback, "invalid function in add_feature") - playerFeat = playerFeat or false - parentOfFeat = parentOfFeat or 0 - --TypeOfFeat = TypeOfFeat:gsub("slider", "value_f") - local currentParent = playerFeat and features["OnlinePlayers"] or features - - local hierarchy_key - if parentOfFeat ~= 0 and parentOfFeat then - currentParent = playerFeat and stuff.player_feature_by_id[parentOfFeat] or stuff.feature_by_id[parentOfFeat] - if currentParent then - assert(currentParent.type >> 11 & 1 ~= 0, "parent is not a parent feature") - assert(currentParent.type >> 15 & 1 ~= 0 == playerFeat, "parent is not valid "..((currentParent.type >> 15 & 1 ~= 0 and not playerFeat) and "using player feature as parent for a local feature" or (currentParent.type >> 15 & 1 == 0 and playerFeat and "using local parent for player feature") or "unknown")) - else - error("parent does not exist") + env.hook.remove_script_event_hook = function(id) + local success = remove_script_event_hook(id) + if success then + f.data.script_hooks[id] = nil + end + return success end - end - if currentParent.hierarchy_key then - hierarchy_key = currentParent.hierarchy_key.."."..nameOfFeat:gsub("[ %.]", "_") - else - hierarchy_key = nameOfFeat:gsub("[ %.]", "_") - end - - currentParent[#currentParent + 1] = {name = nameOfFeat, real_type = stuff.type_id.name_to_id[TypeOfFeat] | (playerFeat and 1 << 15 or 0), real_id = 0, --[[parent = {id = currentParent.id or 0},]] parent_id = currentParent.id or 0, playerFeat = playerFeat, index = #currentParent + 1} - local feat = currentParent[#currentParent] - feat.activate_feat_func = stuff.activate_feat_func - feat.activate_hl_func = stuff.activate_hl_func - feat.set_str_data = stuff.set_str_data - feat.toggle = stuff.toggle - feat.get_children = stuff.get_children - feat.get_str_data = stuff.get_str_data - feat.select = stuff.select - setmetatable(feat, stuff.featMetaTable) - feat.thread = 0 - --if feat.real_type & 1 ~= 0 or feat.real_type >> 9 & 1 ~= 0 then -- toggle - if playerFeat then - feat.table_on = {} - for i = 0, 31 do - feat.table_on[i] = feat.type >> 11 & 1 ~= 0 + env.hook.register_net_event_hook = function(...) + local id = register_net_event_hook(...) + if id then + f.data.net_hooks[id] = true end + return id end - feat.on = feat.type >> 11 & 1 ~= 0 - --end - if feat.real_type >> 5 & 1 ~= 0 then -- value_str - feat.real_str_data = {} - if playerFeat then - feat.table_value = {} - for i = 0, 31 do - feat.table_value[i] = 0 + env.hook.remove_net_event_hook = function(id) + local success = remove_net_event_hook(id) + if success then + f.data.net_hooks[id] = nil end + return success end - feat.value = 0 - elseif feat.real_type >> 1 & 1 ~= 0 then --value any - if playerFeat then - feat.table_max = {} - feat.table_min = {} - feat.table_mod = {} - feat.table_value = {} - for i = 0, 31 do - feat.table_max[i] = 0 - feat.table_min[i] = 0 - feat.table_mod[i] = 1 - feat.table_value[i] = 0 + env.event.add_event_listener = function(eventName, callback) + local id = add_event_listener(eventName, callback) + if id then + f.data.events[eventName] = f.data.events[eventName] or {} + f.data.events[eventName][id] = true + if eventName == "exit" then + f.data.exits[id] = callback + end end + return id end - feat.max = 0 - feat.min = 0 - feat.mod = 1 - feat.value = 0 - end - feat.hidden = false - feat["func"] = functionCallback - feat["hl_func"] = highlightCallback - if TypeOfFeat == "parent" then - feat.child_count = 0 - end - currentParent.child_count = 0 - for k, v in pairs(currentParent) do - if type(k) == "number" then - currentParent.child_count = currentParent.child_count + 1 + env.event.remove_event_listener = function(eventName, id) + local success = remove_event_listener(eventName, id) + if success and f.data.events[eventName] then + f.data.events[eventName][id] = nil + if eventName == "exit" then + f.data.exits[id] = nil + end + end + return success end - end - feat.hotkey = stuff.hierarchy_key_to_hotkey[hierarchy_key] - feat.hierarchy_key = hierarchy_key - if stuff.hotkey_feature_hierarchy_keys[hierarchy_key] then - stuff.hotkey_feature_hierarchy_keys[hierarchy_key][#stuff.hotkey_feature_hierarchy_keys[hierarchy_key] + 1] = feat - else - stuff.hotkey_feature_hierarchy_keys[hierarchy_key] = {feat} - end - if playerFeat then - stuff.player_feature_by_id[#stuff.player_feature_by_id+1] = feat - feat.real_id = #stuff.player_feature_by_id - else - stuff.feature_by_id[#stuff.feature_by_id+1] = feat - feat.real_id = #stuff.feature_by_id - end - return feat - end - - --player feature functions - - -- if you set a toggle player feature to on it'll enable for any valid players/joining players but if a player leaves functions like player.get_player_name will return nil before the feature is turned off - function func.add_player_feature(nameOfFeat, TypeOfFeat, parentOfFeat, functionCallback, highlightCallback) - parentOfFeat = parentOfFeat or 0 - assert(stuff.PlayerParent, "you need to use set_player_feat_parent before adding player features") - local pfeat = func.add_feature(nameOfFeat, TypeOfFeat, parentOfFeat, functionCallback, highlightCallback, true) - pfeat.feats = {} - - if parentOfFeat == 0 then - for k = 0, 31 do - stuff.playerIds[k][#stuff.playerIds[k]+1] = {} - local currentFeat = stuff.playerIds[k][#stuff.playerIds[k]] - func.add_to_table(pfeat, currentFeat, k, nil, true) - stuff.feature_by_id[#stuff.feature_by_id+1] = currentFeat - currentFeat.ps_id = #stuff.feature_by_id - currentFeat.ps_parent_id = stuff.playerIds[k].id - currentFeat.pid = k - pfeat.feats[k] = currentFeat + env.console.register_command = function(name, ...) + if register_command(name, ...) then + f.data.commands[name] = true + return true + end + return false end - else - local playerParent = stuff.player_feature_by_id[parentOfFeat] - if playerParent then - for k = 0, 31 do - playerParent.feats[k][#playerParent.feats[k]+1] = {} - local currentFeat = playerParent.feats[k][#playerParent.feats[k]] - - func.add_to_table(pfeat, currentFeat, k, nil, true) - stuff.feature_by_id[#stuff.feature_by_id+1] = currentFeat - currentFeat.ps_id = #stuff.feature_by_id - currentFeat.ps_parent_id = playerParent.feats[k].ps_id - currentFeat.pid = k - pfeat.feats[k] = currentFeat + env.console.remove_command = function(name) + if remove_command(name) then + for i=FirstChild,Parent.child_count do + local feat = Parent.children[i] + if feat.data and feat.data.commands then + feat.data.commands[name] = nil + end + end + return true end + return false + end + env.load = function(chunk, chunkname, mode, env2) + return og_load(chunk, chunkname or "=(load)", mode or "bt", env2 or env) + end + env.dofile = function(filename) + return og__loadfile(filename, "bt", env)() + end + env.loadfile = function(filename, mode, env2) + return og__loadfile(filename, mode or "bt", env2 or env) + end + env._loadfile = function(filename, mode, env) + return og__loadfile(filename, mode or "bt", env or env) end - end - - return pfeat - end - - function func.add_to_table(getTable, addToTable, playerid, override, setmeta) - local isPlayerFeatValues - for k, v in pairs(getTable) do - if tostring(k):match("table_") or stuff.playerSpecialValues[k] then - isPlayerFeatValues = true - elseif type(v) == "table" then - if type(addToTable[k]) ~= "table" then - addToTable[k] = {} + local loaders = {} + local loaded = {} + env.require = function(Library) + assert(Library ~= nil, "You must pass a Library name") + assert(type(Library) == "string", "Library name must be a string") + if loaders[Library] then + local status, result = og_pcall(loaders[Library]) + if status then + if result == nil then + return true + else + loaded[Library] = result + return loaded[Library] + end + end end - if addToTable[k].real_on then - addToTable[k].real_on = false + local libParts = {} + for part in Library:gmatch("[^.]+") do + libParts[#libParts + 1] = part end - if (v.type or 0) >> 11 & 1 ~= 0 then - func.add_to_table(getTable[k], addToTable[k], playerid, override) - else - for i, e in pairs(getTable[k]) do - if type(e) ~= "table" then - if not addToTable[k][i] or override then - addToTable[k][i] = e - end - end + local subDirTbl = {} + if #libParts > 1 then + for i=1,#libParts-1 do + subDirTbl[#subDirTbl + 1] = libParts[i] end end - setmetatable(addToTable[k], stuff.playerfeatMetaTable) - if v.name then - if not getTable[k].feats then - getTable[k].feats = {} + local subDir = table.concat(subDirTbl, "/") .. "/" + local lib = libParts[#libParts] + for rootDir in env.package.path:gmatch("[^;]+") do + local path = rootDir:gsub("%?", subDir .. lib) + if utils.file_exists(path) then + local chunk, err = og__loadfile(path, "bt", env) + assert(chunk, "Failed to load \"" .. Library .. "\": " .. tostring(err)) + local status, result = og_pcall(chunk) + assert(status, "Failed to exec \"" .. Library .. "\": " .. tostring(result)) + loaders[Library] = chunk + if result == nil then + return true + else + loaded[Library] = result + return loaded[Library] + end end - getTable[k].feats[playerid] = addToTable[k] end - else - if not addToTable[k] or override then - addToTable[k] = v + error("Failed to find library with name \"" .. Library .. "\"") + end + env.clear_lib_cache = function(Library) + if Library then + local retVal = loaders[Library] ~= nil and loaded[Library] ~= nil + loaders[Library] = nil + loaded[Library] = nil + return retVal + else + loaders = {} + loaded = {} + return true end end - end - if setmeta or isPlayerFeatValues then - addToTable.table_value = getTable.table_value - addToTable.table_min = getTable.table_min - addToTable.table_max = getTable.table_max - addToTable.table_mod = getTable.table_mod - addToTable.table_on = getTable.table_on - for i, e in pairs(stuff.playerSpecialValues) do - if addToTable[i] then - stuff.rawset(addToTable, i, nil) + env.get_lib_cache = function() + local cache = {} + for k,v in pairs(loaded) do + cache[k] = v end + return cache end - setmetatable(addToTable, stuff.playerfeatMetaTable) - end - end - - function func.set_player_feat_parent(nameOfFeat, parentOfFeat, functionToDo) - stuff.PlayerParent = func.add_feature(nameOfFeat, "parent", parentOfFeat, functionToDo) - local hierarchy_pattern = stuff.PlayerParent.hierarchy_key..".player_" + f.data.env = env - stuff.playerIds = {} - for i = 0, 31 do - stuff.playerIds[i] = func.add_feature(tostring(player.get_player_name(i)), "parent", stuff.PlayerParent.id) - stuff.playerIds[i].pid = i - stuff.playerIds[i].hidden = not player.is_player_valid(i) - stuff.playerIds[i].hierarchy_key = hierarchy_pattern..i - stuff.playerIds[i].real_type = 1 << 15 | stuff.playerIds[i].type + local chunk, err = og__loadfile(Filepath, "bt", f.data.env) + if chunk then + local status, result = og_pcall(chunk) + if not status then + menu.create_thread(UnloadScript, f) + notify("Error executing script: " .. Filename .. "\n" .. tostring(result), 0xFF0000FF) + else + notify("Loaded script: " .. Filename, 0xFF00FF00) + LoadedScripts[Filename] = true + end + else + menu.create_thread(UnloadScript, f) + notify("Error loading script: " .. Filename .. "\n" .. err, 0xFF0000FF) + end + end + else + if f.data then + menu.create_thread(UnloadScript, f) end + end +end - event.add_event_listener("player_join", function(listener) - system.wait(100) - stuff.playerIds[listener.player].hidden = false - stuff.playerIds[listener.player].name = player.get_player_name(listener.player) - func.reset_player_submenu(listener.player) - table.sort(stuff.PlayerParent, stuff.table_sort_functions[stuff.player_submenu_sort]) - end) - event.add_event_listener("player_leave", function(listener) - func.reset_player_submenu(listener.player) - if not player.is_player_valid(listener.player) then - stuff.playerIds[listener.player].hidden = true - stuff.playerIds[listener.player].name = "nil" - end - table.sort(stuff.PlayerParent, stuff.table_sort_functions[stuff.player_submenu_sort]) - end) +local function CaseInsensitiveSort(a, b) + return tostring(a):lower() < tostring(b):lower() +end - return stuff.PlayerParent +local function LoadScripts(feat) + if FilterFeat then + FilterFeat.data = "" + FilterFeat.name = "Filter: " end - function func.reset_player_submenu(pid, currentParent) - local currentParent = currentParent or features.OnlinePlayers - for k, v in pairs(currentParent) do - if type(v) == "table" then - local feat_type = v.type - if feat_type then - if feat_type >> 1 & 1 ~= 0 then -- toggle - v.table_value[pid] = v.real_value - if feat_type & 136 ~= 0 then -- value if - v.table_min[pid] = v.real_min - v.table_max[pid] = v.real_max - v.table_mod[pid] = v.real_mod - end - end - if feat_type & 1 ~= 0 then -- toggle - if player.is_player_valid(pid) then - v.feats[pid].on = v.real_on - else - v.feats[pid].on = false - v.table_on[pid] = false - end - end - if feat_type >> 11 & 1 ~= 0 then -- parent - func.reset_player_submenu(pid, v) - end - end - end + local files = utils.get_all_files_in_directory(Paths.Scripts, "lua") + local files2 = {} + for i=1,#files do + files2[files[i]] = true + end + local files3 = utils.get_all_files_in_directory(Paths.Scripts, "luac") + for i=1,#files3 do + if not files2[files3[i]] then + files[#files + 1] = files3[i] + files2[files3[i]] = true end end - --end of player feature functions - - function func.check_scroll(index, parent, bool) - if index <= stuff.scroll + stuff.scrollHiddenOffset and currentMenu == parent then - if bool then - --stuff.scroll = stuff.scroll - 1 - --stuff.scroll = stuff.scroll > 0 and stuff.scroll or 0 - if #currentMenu - stuff.drawHiddenOffset > 1 and stuff.scroll - 1 > 0 then - stuff.scroll = stuff.scroll - 1 - if stuff.scroll - stuff.drawScroll <= 2 and stuff.drawScroll > 0 then - stuff.drawScroll = stuff.drawScroll - 1 - end - end - else - if #currentMenu - stuff.drawHiddenOffset > 1 then - stuff.scroll = stuff.scroll + 1 - if stuff.scroll - stuff.drawScroll >= (stuff.menuData.max_features - 1) and stuff.drawScroll < stuff.maxDrawScroll then - stuff.drawScroll = stuff.drawScroll + 1 - end - end - --stuff.scroll = stuff.scroll + 1 - end + table.sort(files, CaseInsensitiveSort) + local threads = {} + for i=Parent.child_count,FirstChild,-1 do + if not files2[Parent.children[i].name] then + threads[#threads + 1] = create_thread(DeleteFeature, Parent.children[i]) + else + files2[Parent.children[i].name] = false + Parent.children[i].hidden = false end end - - function func.deleted_or_hidden_parent_check(parent, check_hidden_only) - if next(stuff.previousMenus) then - local parentBeforeDHparent = false - if parent ~= currentMenu then - for k, v in ipairs(stuff.previousMenus) do - if parentBeforeDHparent then - stuff.previousMenus[k] = nil - else - if (v.menu == parent and not check_hidden_only) or (v.menu.hidden and check_hidden_only) then - parentBeforeDHparent = true - currentMenu = stuff.previousMenus[k-1].menu - stuff.scroll = stuff.previousMenus[k-1].scroll - stuff.drawScroll = stuff.previousMenus[k-1].drawScroll - stuff.scrollHiddenOffset = stuff.previousMenus[k-1].scrollHiddenOffset - stuff.previousMenus[k-1] = nil - stuff.previousMenus[k] = nil - end - end - end - elseif not check_hidden_only then - currentMenu = stuff.previousMenus[#stuff.previousMenus].menu - stuff.scroll = stuff.previousMenus[#stuff.previousMenus].scroll - stuff.drawScroll = stuff.previousMenus[#stuff.previousMenus].drawScroll - stuff.scrollHiddenOffset = stuff.previousMenus[#stuff.previousMenus].scrollHiddenOffset - stuff.previousMenus[#stuff.previousMenus] = nil - end + for i=AutoloadParent.child_count,AutoloadFirstChild,-1 do + threads[#threads + 1] = create_thread(DeleteFeature, AutoloadParent.children[i]) + end + local waiting = true + while waiting do + local running = false + for i=1,#threads do + running = running or (not menu.has_thread_finished(threads[i])) end + waiting = running + system_wait(0) end - - function func.get_feature_by_hierarchy_key(hierarchy_key) - local feat = stuff.hotkey_feature_hierarchy_keys[hierarchy_key] - if feat then - if feat[2] and not feat.name then - return feat, true + for i=1,#files do + if not ExcludedScripts[files[i]:lower()] then + if files2[files[i]] then + menu_originals.add_feature(files[i], "toggle", ParentId, LoadScript, f) + end + local autoloadFeat = menu_originals.add_feature(files[i], "value_i", AutoloadParentId) + autoloadFeat.min = 1 + autoloadFeat.max = 999 + autoloadFeat.mod = 1 + local val = AutoloadTbl[files[i]] + if val then + autoloadFeat.value = type(val) == "number" and val or 1 + autoloadFeat.on = true else - return feat[1] + autoloadFeat.value = 1 end end end +end - function func.get_feature(id) - assert(type(id) == "number" and id ~= 0, "invalid id in get_feature") - return stuff.feature_by_id[id] +local ExitFeat = menu_originals.add_feature("Exit Listener", "toggle", ParentId, function(f) + if not f.on then + print("Exit Listener Feat Off") + Exiting = true end +end) +ExitFeat.hidden = true +ExitFeat.on = true - function func.delete_feature(id, bool_ps) - if type(id) == "table" then - id = id.id - end - - local feat = stuff.feature_by_id[id] - if not feat then - return false - end - - if stuff.old_selected == stuff.feature_by_id[id] then - stuff.old_selected = nil - end - stuff.feature_by_id[id] = nil - - if feat.thread then - if not menu.has_thread_finished(feat.thread) then - menu.delete_thread(feat.thread) - end - end - if feat.hl_thread then - if not menu.has_thread_finished(feat.hl_thread) then - menu.delete_thread(feat.hl_thread) - end - end - - local parent - if feat.parent_id ~= 0 or bool_ps then - parent = bool_ps and stuff.feature_by_id[feat.ps_parent_id] or stuff.feature_by_id[feat.parent_id] - else - parent = features - end +local delayFeat - if feat.type >> 11 & 1 ~= 0 then - func.deleted_or_hidden_parent_check(feat) +menu_originals.add_feature("Save Autoload Scripts", "action", AutoloadParentId, function(f) + AutoloadTbl = { + ["autoload_delay_between_scripts"] = delayFeat.value + } + for i=AutoloadFirstChild,AutoloadParent.child_count do + local child = AutoloadParent.children[i] + if child.on then + AutoloadTbl[child.name] = child.value end + end + Settings.Save(ScriptName, AutoloadTbl) + notify("Saved autoload scripts.", 0xFF00FF00) +end) - local index = feat.index - table.remove(parent, tonumber(feat.index)) - - --func.check_scroll(index, parent, true) - - for i = index, #parent do - parent[i].index = i - end +delayFeat = menu_originals.add_feature("Delay between scripts (ms)", "action_value_i", AutoloadParentId, function(f) + local r, s + repeat + r, s = input.get("Enter delay", f.value, 4, eInputType.IT_NUM) + if r == 2 then return HANDLER_POP end + system_wait(0) + until r == 0 - return true + local num = tonumber(s) + if num and num >= f.min and num <= f.max then + f.value = num end +end) +delayFeat.min = 0 +delayFeat.max = 1000 +delayFeat.mod = 1 +local delayVal = AutoloadTbl["autoload_delay_between_scripts"] +if type(delayVal) ~= "number" or delayVal < delayFeat.min then + delayVal = delayFeat.min +elseif delayVal > delayFeat.max then + delayVal = delayFeat.max +end +delayFeat.value = delayVal - function func.delete_player_feature(id) - if type(id) == "table" then - id = id.id - end - +local RefreshFeat = menu_originals.add_feature("Refresh Scripts", "action", ParentId, function(f) + LoadScripts(f) + notify("Refreshed scripts list.", 0xFF00FF00) +end) - local feat = stuff.player_feature_by_id[id] - if not feat then - return false - end +local function FocusFeat(f) + if f.data.parent then + f.data.parent:toggle() + end + f.data:select() +end - stuff.player_feature_by_id[id] = nil +local function ToggleFeat(f) + f.data:toggle() +end - local parent - if feat.parent_id ~= 0 then - parent = stuff.player_feature_by_id[feat.parent_id] - else - parent = features["OnlinePlayers"] - end +local SearchParentId = menu_originals.add_feature("Search Script Features", "parent", ParentId).id +menu_originals.add_feature("Filter: ", "action", SearchParentId, function(f) + local r, s + repeat + r, s = input.get("Enter search query", f.data, 64, 0) + if r == 2 then return HANDLER_POP end + system_wait(0) + until r == 0 - for k, v in pairs(feat.feats) do - func.delete_feature(v.ps_id, true) - end + local threads = {} + for i=f.parent.child_count,2,-1 do + threads[#threads + 1] = create_thread(DeleteFeature, f.parent.children[i]) + end - local index = feat.index - table.remove(parent, tonumber(index)) - for i = index, #parent do - parent[i].index = i - for pid = 0, 31 do - parent[i].feats[pid].index = i - end + local waiting = true + while waiting do + local running = false + for i=1,#threads do + running = running or (not menu.has_thread_finished(threads[i])) end + waiting = running + system_wait(0) end - function func.get_player_feature(id) - assert(type(id) == "number" and id ~= 0, "invalid id in get_player_feature") - return stuff.player_feature_by_id[id] + s = Trim(s) + if s:len() == 0 then + f.data = "" + f.name = "Filter: " + return HANDLER_POP end - function func.do_key(time, key, doLoopedFunction, functionToDo) - if cheeseUtils.get_key(key):is_down() then - functionToDo() - local timer = utils.time_ms() + time - while timer > utils.time_ms() and cheeseUtils.get_key(key):is_down() do - system.wait(0) - end - while timer < utils.time_ms() and cheeseUtils.get_key(key):is_down() do - if doLoopedFunction then - functionToDo() - end - local timer = utils.time_ms() + 50 - while timer > utils.time_ms() do - system.wait(0) + local count = 0 + for i=4,RefreshFeat.parent.child_count do + local child = RefreshFeat.parent.children[i] + if child.data and child.data.features and type(child.data.features) == "table" then + for j=1,#child.data.features do + local feat = child.data.features[j] + if feat then + if feat.name:lower():find(s:lower(), 1, true) then + if feat.type == 2048 then + menu_originals.add_feature(FileNameWithoutExtension(child.name) .. " | " .. feat.name, "parent", SearchParentId, ToggleFeat).data = feat + else + menu_originals.add_feature(FileNameWithoutExtension(child.name) .. " | " .. feat.name, "action", SearchParentId, FocusFeat).data = feat + end + count = count + 1 + end end end end end - stuff.header_ids = {} - function func.load_sprite(path_to_file, id_table) - --path = path or stuff.path.header - id_table = id_table or stuff.header_ids - path_to_file = tostring(path_to_file) - assert(path_to_file, "invalid name") + f.data = s + f.name = "Filter: <" .. s .. "> (" .. count .. ")" +end).data = "" - --name = name:gsub("%.[a-z]+$", "") +FilterFeat = menu_originals.add_feature("Filter: ", "action", ParentId, function(f) + local r, s + repeat + r, s = input.get("Enter search query", f.data, 64, 0) + if r == 2 then return HANDLER_POP end + system_wait(0) + until r == 0 - if not id_table[path_to_file] then - if utils.dir_exists(path_to_file:gsub("%.ogif", "")) and path_to_file:find("%.ogif") then - local path = path_to_file:gsub("%.ogif", "").."\\" - local images + s = Trim(s) + if s:len() == 0 then + f.data = "" + f.name = "Filter: " + for i=f.parent.child_count,FirstChild,-1 do + f.parent.children[i].hidden = false + end + return HANDLER_POP + end - for _, v in pairs(stuff.image_ext) do - images = utils.get_all_files_in_directory(path, v) - if images[1] then break end - end - if not images[1] then - menu.notify("No frames found.", "Cheese Menu", 5, 0x0000FF) - return - end + local count = 0 + for i=f.parent.child_count,FirstChild,-1 do + if f.parent.children[i].name:lower():find(s, 1, true) then + f.parent.children[i].hidden = false + count = count + 1 + else + f.parent.children[i].hidden = true + end + end + + f.data = s + f.name = "Filter: <" .. s .. "> (" .. count .. ")" +end) +FilterFeat.data = "" - id_table[path_to_file] = {} - for i, e in pairs(images) do - id_table[path_to_file][i] = {} - id_table[path_to_file][i].sprite = scriptdraw.register_sprite(path..e) - id_table[path_to_file][i].delay = e:match("%d+_(%d+)") - end +ProddysScriptManager = true - id_table[path_to_file].constant_delay = utils.get_all_files_in_directory(path, "txt")[1] - if not id_table[path_to_file].constant_delay then - for k, v in pairs(images) do - if not v:match("%d+_(%d+)") then - menu.notify("FPS file not found and frames are not in format, create a txt file with the framerate of the gif.\nExample: '25 fps.txt'", "Cheese Menu", 5, 0x0000FF) - break - end - end - else - id_table[path_to_file].constant_delay = math.floor(1000 / tonumber(id_table[path_to_file].constant_delay:match("(%d*%.*%d+)%s+fps"))) - end +create_thread(function(f) + FirstChild = Parent.child_count + 1 + AutoloadFirstChild = AutoloadParent.child_count + 1 + LoadScripts(f) - elseif utils.file_exists(path_to_file) then - id_table[path_to_file] = scriptdraw.register_sprite(path_to_file) + local delay = 0 + local autoload = {} + for k,v in pairs(AutoloadTbl) do + if k == "autoload_delay_between_scripts" then + if type(v) == "number" and v >= 0 then + delay = v end + else + if type(v) ~= "number" then v = 1 end + autoload[v] = autoload[v] or {} + autoload[v][#autoload[v] + 1] = k end - - return id_table[path_to_file] end - function func.toggle_menu(bool) - stuff.menuData.menuToggle = bool - if stuff.menuData.menuToggle then - if currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then - currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() + print("Autoloading with delay: " .. delay) + + if #autoload > 0 then + local scripts = {} + for i=FirstChild,Parent.child_count do + local feat = Parent.children[i] + scripts[feat.name] = feat + end + + local ids = {} + for k in pairs(autoload) do + ids[#ids + 1] = k + end + table.sort(ids) + + for i=1,#ids do + local tbl = autoload[ids[i]] + for j=1,#tbl do + local script = scripts[tbl[j]] + if script then + system_wait(delay) + print("Enabled autoload script: " .. script.name) + script.on = true + end end end end +end, RefreshFeat) - function func.selector(feat) - local originalmenuToggle = stuff.menuData.menuToggle - stuff.menuData.menuToggle = false - if feat.str_data then - local index, _ = cheeseUtils.selector(nil, stuff.menuData.selector_speed, feat.real_value + 1, feat.str_data) - if index then - feat.real_value = index - 1 +--notify(ScriptName .. " v" .. Version .. " loaded.", 0xFF0FF00)]=], + ["CheeseUtilities.lua"] = [=[--Made by GhostOne +local cheeseUtils = {} + +-- Credit to kektram for this whole function ~ a little modified to focus on fractionals +cheeseUtils.memoize = {} +do + local sign_bit_x = 1 << 62 + local sign_bit_y = 1 << 61 + local max_30_bit_num = 1073740823 + local v2 = v2 + local memoized = {} + function cheeseUtils.memoize.v2(x, y) + x = x or 0 + y = y or 0 + local xi = x * 100000000 // 1 -- modified from 1000 to 100,000,000 to support up to 10^-7 fractional digits ~ this limits it to either single or double digits with fractions + local yi = y * 100000000 // 1 -- same here + if xi >= -max_30_bit_num + and xi <= max_30_bit_num + and yi >= -max_30_bit_num + and yi <= max_30_bit_num then + local signs = 0 + if xi < 0 then + xi = xi * -1 + signs = signs | sign_bit_x end - if feat.type >> 10 & 1 ~= 0 then - feat:activate_feat_func() + if yi < 0 then + yi = yi * -1 + signs = signs | sign_bit_y end + local hash = signs | xi << 30 | yi + memoized[hash] = memoized[hash] or v2(x, y) + return memoized[hash] + else + return v2(x, y) end - func.toggle_menu(originalmenuToggle) end +end +-- - function func.rewrap_hints(font) - local padding = scriptdraw.size_pixel_to_rel_x(25) - for _, hintTable in pairs(stuff.feature_hints) do - hintTable.str = cheeseUtils.wrap_text(hintTable.original, font, stuff.menuData.text_size * stuff.menuData.hint_size_modifier, stuff.menuData.width*2-padding) - hintTable.size = scriptdraw.get_text_size(hintTable.str, 1, font) - end - end +function cheeseUtils.draw_outline(v2pos, v2size, color, thickness) + local thickness_y = thickness / graphics.get_screen_height() * 2 + local thickness_x = thickness / graphics.get_screen_width() * 2 - function func.save_settings() - gltw.write({ - x = stuff.menuData.pos_x, - y = stuff.menuData.pos_y, - side_window = stuff.menuData.side_window, - controls = stuff.controls, - hotkey_notifications = stuff.hotkey_notifications, - player_submenu_sort = stuff.player_submenu_sort, - selector_speed = stuff.menuData.selector_speed - }, "Settings", stuff.path.cheesemenu) - end + scriptdraw.draw_rect( + cheeseUtils.memoize.v2(v2pos.x, v2pos.y - (v2size.y/2)), + cheeseUtils.memoize.v2(v2size.x + thickness_x, thickness_y), + color + ) - function func.load_settings() - local settings = gltw.read("Settings", stuff.path.cheesemenu, nil, nil, true) - if settings then - stuff.menuData.pos_x = settings.x - stuff.menuData.pos_y = settings.y - stuff.menuData.selector_speed = settings.selector_speed - stuff.player_submenu_sort = settings.player_submenu_sort + scriptdraw.draw_rect( + cheeseUtils.memoize.v2(v2pos.x, v2pos.y + (v2size.y/2)), + cheeseUtils.memoize.v2(v2size.x + thickness_x, thickness_y), + color + ) - for k, v in pairs(settings.side_window) do - stuff.menuData.side_window[k] = v - end - for k, v in pairs(settings.hotkey_notifications) do - stuff.hotkey_notifications[k] = v - end - for k, v in pairs(settings.controls) do - stuff.controls[k] = v - end - for k, v in pairs(stuff.controls) do - stuff.vkcontrols[k] = stuff.char_codes[v] - end + scriptdraw.draw_rect( + cheeseUtils.memoize.v2(v2pos.x - (v2size.x/2), v2pos.y), + cheeseUtils.memoize.v2(thickness_x, v2size.y - thickness_y), + color + ) - menu_configuration_features.menuXfeat.value = math.floor(stuff.menuData.pos_x*graphics.get_screen_width()) - menu_configuration_features.menuYfeat.value = math.floor(stuff.menuData.pos_y*graphics.get_screen_height()) - menu_configuration_features.player_submenu_sort.value = stuff.player_submenu_sort - menu_configuration_features.player_submenu_sort:toggle() - menu_configuration_features.side_window_offsetx.value = math.floor(stuff.menuData.side_window.offset.x*graphics.get_screen_width()) - menu_configuration_features.side_window_offsety.value = math.floor(stuff.menuData.side_window.offset.y*graphics.get_screen_height()) - menu_configuration_features.side_window_spacing.value = math.floor(stuff.menuData.side_window.spacing*graphics.get_screen_height()) - menu_configuration_features.side_window_padding.value = math.floor(stuff.menuData.side_window.padding*graphics.get_screen_width()) - menu_configuration_features.side_window_width.value = math.floor(stuff.menuData.side_window.width*graphics.get_screen_width()) - menu_configuration_features.side_window_on.on = stuff.menuData.side_window.on - menu_configuration_features.selector_speed.value = stuff.menuData.selector_speed + scriptdraw.draw_rect( + cheeseUtils.memoize.v2(v2pos.x + (v2size.x/2), v2pos.y), + cheeseUtils.memoize.v2(thickness_x, v2size.y - thickness_y), + color + ) +end + +-- Credit to Proddy for this function +cheeseUtils.Keys = {} +function cheeseUtils.get_key(...) + local args = {...} + assert(#args > 0, "must give at least one key") + local ID = table.concat(args, "|") + if not cheeseUtils.Keys[ID] then + local key = MenuKey() + for i=1,#args do + key:push_vk(args[i]) end + cheeseUtils.Keys[ID] = key end - function func.save_ui(name) - gltw.write(stuff.menuData, name, stuff.path.ui, {"menuToggle", "menuNav", "loaded_sprites", "files", "pos_x", "pos_y", "side_window", "selector_speed", "chatBoxOpen"}) - end + return cheeseUtils.Keys[ID] +end - function func.load_ui(name) - local uiTable = gltw.read(name, stuff.path.ui, stuff.menuData, true, true) - if not uiTable then - return - end - if menu_configuration_features then - local header, bgSprite = uiTable.header, uiTable.background_sprite and uiTable.background_sprite.sprite or nil - if not header then - menu_configuration_features.headerfeat.value = 0 - menu_configuration_features.headerfeat:toggle() - end - if not bgSprite then - menu_configuration_features.backgroundfeat.value = 0 - menu_configuration_features.backgroundfeat:toggle() - end +function cheeseUtils.new_reusable_v2(limit) + limit = limit or 2 - --[[ menu_configuration_features.menuXfeat.value = math.floor(stuff.menuData.pos_x*graphics.get_screen_width()) - menu_configuration_features.menuYfeat.value = math.floor(stuff.menuData.pos_y*graphics.get_screen_height()) ]] - menu_configuration_features.maxfeats.value = math.floor(stuff.menuData.max_features) - menu_configuration_features.menuWidth.value = math.floor(stuff.menuData.width*graphics.get_screen_width()) - menu_configuration_features.featXfeat.value = math.floor(stuff.menuData.feature_scale.x*graphics.get_screen_width()) - menu_configuration_features.featYfeat.value = math.floor(stuff.menuData.feature_scale.y*graphics.get_screen_height()) - menu_configuration_features.feature_offset.value = math.floor(stuff.menuData.feature_offset*graphics.get_screen_height()) - menu_configuration_features.namePadding.value = math.floor(stuff.menuData.padding.name*graphics.get_screen_width()) - menu_configuration_features.parentPadding.value = math.floor(stuff.menuData.padding.parent*graphics.get_screen_width()) - menu_configuration_features.valuePadding.value = math.floor(stuff.menuData.padding.value*graphics.get_screen_width()) - menu_configuration_features.sliderPadding.value = math.floor(stuff.menuData.padding.slider*graphics.get_screen_width()) - menu_configuration_features.sliderWidth.value = math.floor(stuff.menuData.slider.width*graphics.get_screen_width()) - menu_configuration_features.sliderHeight.value = math.floor(stuff.menuData.slider.height*graphics.get_screen_height()) - menu_configuration_features.sliderheightActive.value = math.floor(stuff.menuData.slider.heightActive*graphics.get_screen_height()) - menu_configuration_features.text_size.value = stuff.menuData.text_size_modifier - menu_configuration_features.footer_size.value = stuff.menuData.footer_size_modifier - menu_configuration_features.hint_size.value = stuff.menuData.hint_size_modifier - menu_configuration_features.text_y_offset.value = -math.floor(stuff.menuData.text_y_offset*graphics.get_screen_height()) - stuff.drawFeatParams.textOffset.y = stuff.menuData.text_y_offset - menu_configuration_features.footer_y_offset.value = math.floor(stuff.menuData.footer.footer_y_offset*graphics.get_screen_height()) - menu_configuration_features.border.value = math.floor(stuff.menuData.border*graphics.get_screen_height()) - menu_configuration_features.backgroundsize.value = stuff.menuData.background_sprite.size - menu_configuration_features.backgroundoffsetx.value = math.floor(stuff.menuData.background_sprite.offset.x*graphics.get_screen_width()) - menu_configuration_features.backgroundoffsety.value = math.floor(stuff.menuData.background_sprite.offset.y*graphics.get_screen_height()) - menu_configuration_features.footer_size.value = math.floor(stuff.menuData.footer.footer_size*graphics.get_screen_height()) - menu_configuration_features.footerPadding.value = math.floor(stuff.menuData.footer.padding*graphics.get_screen_width()) - menu_configuration_features.draw_footer.on = stuff.menuData.footer.draw_footer - menu_configuration_features.footer_pos_related_to_background.on = stuff.menuData.footer.footer_pos_related_to_background - --[[ menu_configuration_features.side_window_offsetx.value = math.floor(stuff.menuData.side_window.offset.x*graphics.get_screen_width()) - menu_configuration_features.side_window_offsety.value = math.floor(stuff.menuData.side_window.offset.y*graphics.get_screen_height()) - menu_configuration_features.side_window_spacing.value = math.floor(stuff.menuData.side_window.spacing*graphics.get_screen_height()) - menu_configuration_features.side_window_padding.value = math.floor(stuff.menuData.side_window.padding*graphics.get_screen_width()) - menu_configuration_features.side_window_width.value = math.floor(stuff.menuData.side_window.width*graphics.get_screen_width()) - menu_configuration_features.side_window_on.on = stuff.menuData.side_window.on ]] - menu_configuration_features.text_font.value = stuff.menuData.fonts.text - menu_configuration_features.footer_font.value = stuff.menuData.fonts.footer - menu_configuration_features.hint_font.value = stuff.menuData.fonts.hint + local counter = 1 + local v2Table = {} + for i = 1, limit do + v2Table[i] = v2() + end - menu_configuration_features.hint_font:toggle() + return function(x, y) + local vector2d = v2Table[counter] + counter = counter + 1 + counter = counter <= limit and counter or 1 - for k, v in pairs(stuff.menuData.color) do - if menu_configuration_features[k] then - if type(v) == "table" then - menu_configuration_features[k].r.value = v.r - menu_configuration_features[k].g.value = v.g - menu_configuration_features[k].b.value = v.b - menu_configuration_features[k].a.value = v.a - else - menu_configuration_features[k].r.value = func.convert_int_to_rgba(v, "r") - menu_configuration_features[k].g.value = func.convert_int_to_rgba(v, "g") - menu_configuration_features[k].b.value = func.convert_int_to_rgba(v, "b") - menu_configuration_features[k].a.value = func.convert_int_to_rgba(v, "a") - end - end - end + vector2d.x, vector2d.y = x, y - for k, v in pairs(menu_configuration_features.headerfeat.str_data) do - if v == stuff.menuData.header then - menu_configuration_features.headerfeat.value = k - 1 - end - end + return vector2d + end +end - if uiTable.background_sprite then - for k, v in pairs(menu_configuration_features.backgroundfeat.str_data) do - if v == uiTable.background_sprite.sprite then - menu_configuration_features.backgroundfeat.value = k - 1 - end - end +-- Selector +do + local textv2 = v2(2, 2) + local reuse_v2 = cheeseUtils.new_reusable_v2() + + local key = { + enter = MenuKey(), + backspace = MenuKey(), + up = MenuKey(), + down = MenuKey(), + } + key.enter:push_vk(0x0D) + key.backspace:push_vk(0x08) + key.up:push_vk(0x26) + key.down:push_vk(0x28) + + local key_waits = {} + local function get_key_wait(str_key) + local vk_key = key[str_key] + if vk_key:is_down() and ((utils.time_ms() > key_waits[str_key]) or (key_waits[str_key] == 0)) then + if key_waits[str_key] == 0 then + key_waits[str_key] = utils.time_ms() + 500 + else + key_waits[str_key] = utils.time_ms() + 100 end + return true + elseif not vk_key:is_down() then + key_waits[str_key] = 0 end + return false end - stuff.drawFeatParams = { - rectPos = v2(stuff.menuData.pos_x, stuff.menuData.pos_y - stuff.menuData.feature_offset/2 + stuff.menuData.border), - textOffset = v2(stuff.menuData.feature_scale.x/2, -0.0055555555), - colorText = stuff.menuData.color.text, - textSize = 0, - } - function func.draw_feat(k, v, offset, hiddenOffset) - --[[ stuff.drawFeatParams.rectPos.x = stuff.menuData.pos_x - stuff.drawFeatParams.rectPos.y = stuff.menuData.pos_y - stuff.menuData.feature_offset/2 + stuff.menuData.border - stuff.drawFeatParams.textOffset.x = stuff.menuData.feature_scale.x/2 - stuff.drawFeatParams.textSize = textSize ]] - stuff.drawFeatParams.colorText = stuff.menuData.color.text - stuff.drawFeatParams.bottomLeft = stuff.menuData.color.feature_bottomLeft - stuff.drawFeatParams.topLeft = stuff.menuData.color.feature_topLeft - stuff.drawFeatParams.topRight = stuff.menuData.color.feature_topRight - stuff.drawFeatParams.bottomRight = stuff.menuData.color.feature_bottomRight - local posY = (stuff.drawFeatParams.rectPos.y + (stuff.menuData.feature_offset * k))*-2+1 + --local speed_modifier = 0.5 + local function draw_selector(stuff) + while true do + local selected = stuff.selected + scriptdraw.draw_rect(reuse_v2(0, 0), textv2, 0x7D000000) + scriptdraw.draw_text(stuff.selected_str, reuse_v2(-0.02, 0), textv2, 1 / stuff.text_size_rel_to_res, 0xFFFFFFFF, 1 << 4) - local is_selected - if stuff.scroll == k + stuff.drawScroll then - stuff.scrollHiddenOffset = hiddenOffset or stuff.scrollHiddenOffset - stuff.drawFeatParams.colorText = stuff.menuData.color.text_selected - stuff.drawFeatParams.bottomLeft = stuff.menuData.color.feature_selected_bottomLeft - stuff.drawFeatParams.topLeft = stuff.menuData.color.feature_selected_topLeft - stuff.drawFeatParams.topRight = stuff.menuData.color.feature_selected_topRight - stuff.drawFeatParams.bottomRight = stuff.menuData.color.feature_selected_bottomRight - is_selected = true - end - if offset == 0 then - local memv2 = cheeseUtils.memoize.v2 - local posX = stuff.drawFeatParams.rectPos.x*2-1 - --[[ scriptdraw.draw_rect( - cheeseUtils.memoize.v2(posX, posY), - cheeseUtils.memoize.v2(stuff.menuData.feature_scale.x*2, stuff.menuData.feature_scale.y*2), - func.convert_rgba_to_int(stuff.drawFeatParams.colorFeature.r, stuff.drawFeatParams.colorFeature.g, stuff.drawFeatParams.colorFeature.b, stuff.drawFeatParams.colorFeature.a) - ) ]] - local Left = posX - stuff.menuData.feature_scale.x - local Right = posX + stuff.menuData.feature_scale.x - local Top = posY + stuff.menuData.feature_scale.y - local Bottom = posY - stuff.menuData.feature_scale.y - scriptdraw.draw_rect_ext( - memv2(Left, Bottom), - memv2(Left, Top), - memv2(Right, Top), - memv2(Right, Bottom), - func.convert_rgba_to_int(stuff.drawFeatParams.bottomLeft.r, stuff.drawFeatParams.bottomLeft.g, stuff.drawFeatParams.bottomLeft.b, stuff.drawFeatParams.bottomLeft.a), - func.convert_rgba_to_int(stuff.drawFeatParams.topLeft.r, stuff.drawFeatParams.topLeft.g, stuff.drawFeatParams.topLeft.b, stuff.drawFeatParams.topLeft.a), - func.convert_rgba_to_int(stuff.drawFeatParams.topRight.r, stuff.drawFeatParams.topRight.g, stuff.drawFeatParams.topRight.b, stuff.drawFeatParams.topRight.a), - func.convert_rgba_to_int(stuff.drawFeatParams.bottomRight.r, stuff.drawFeatParams.bottomRight.g, stuff.drawFeatParams.bottomRight.b, stuff.drawFeatParams.bottomRight.a) - ) - end + if stuff.move then + local is_going_up = stuff.move == "up" + if (is_going_up and stuff.selected - 1 >= 1) or (not is_going_up and stuff.selected + 1 <= #stuff.items) then + stuff.offset = is_going_up and stuff.offset - stuff.offset_step or stuff.offset + stuff.offset_step + stuff.size_offset = stuff.size_offset + stuff.size_step + if stuff.offset >= 0.08 or stuff.offset <= -0.08 then + stuff.offset = 0 + stuff.size_offset = 0 + stuff.next_selected = 0 - local font = stuff.menuData.fonts.text - if v.type & 1 == 0 then - scriptdraw.draw_text( - v["name"], - cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x - (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.name))*2-1, (stuff.drawFeatParams.rectPos.y + stuff.drawFeatParams.textOffset.y + (stuff.menuData.feature_offset * k))*-2+1), - cheeseUtils.memoize.v2(10, 10), - stuff.drawFeatParams.textSize, - func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a), - 0, font - ) - if v.type >> 11 & 1 ~= 0 then - scriptdraw.draw_text( - ">>", - cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x + (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.parent))*2-1, (stuff.drawFeatParams.rectPos.y + stuff.drawFeatParams.textOffset.y + (stuff.menuData.feature_offset * k))*-2+1), - cheeseUtils.memoize.v2(10, 10), - stuff.drawFeatParams.textSize, - func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a), - 16, font - ) + stuff.selected = is_going_up and stuff.selected - 1 or stuff.selected + 1 + selected = stuff.selected + stuff.move = nil + end + else + stuff.move = nil + end + else + stuff.offset = 0 + stuff.size_offset = 0 + stuff.next_selected = 0 end - elseif v.type & 1 ~= 0 then -- toggle - cheeseUtils.draw_outline( - cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x - (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.name) + 0.00390625)*2-1, posY), - cheeseUtils.memoize.v2(0.015625, 0.0277777777778), - func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a), - 2 - ) - if v.real_on then - scriptdraw.draw_rect( - cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x - (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.name) + 0.00390625)*2-1, posY), - cheeseUtils.memoize.v2(0.0140625, 0.025), - func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a) - ) + + local min = selected - 5 >= 1 and selected - 5 or 1 + local max = selected + 5 <= #stuff.items and selected + 5 or #stuff.items + for i = min, max do + if stuff.items[i] then + local size = i == selected and 1.3 or 1 + size = i == stuff.next_selected and size + stuff.size_offset or i == selected and size - stuff.size_offset or size + local alpha = stuff.move == "up" and math.max(math.floor(255 - math.abs((i - selected) + math.abs(stuff.offset)/0.08)*51), 0) or math.max(math.floor(255 - math.abs((i - selected) - math.abs(stuff.offset)/0.08)*51), 0) + scriptdraw.draw_text(stuff.items[i], reuse_v2(0, 0.005 - 0.08 * (i - selected) + (stuff.offset or 0)), textv2, size / stuff.text_size_rel_to_res, (alpha << 24 | 0xFFFFFF), 0) + end end - scriptdraw.draw_text( - v.name, - cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x - (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.name) + 0.011328125)*2-1, (stuff.drawFeatParams.rectPos.y + stuff.drawFeatParams.textOffset.y + (stuff.menuData.feature_offset * k))*-2+1), - cheeseUtils.memoize.v2(10, 10), - stuff.drawFeatParams.textSize, - func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a), - 0, font - ) + controls.disable_control_action(0, 200, true) + controls.disable_control_action(0, 172, true) + controls.disable_control_action(0, 27, true) + + system.wait(0) end + end - if v.type >> 1 & 1 ~= 0 then -- value_i_f_str - local rounded_value = v.str_data and v.str_data[v.real_value + 1] or v.real_value - if v.type >> 7 & 1 ~= 0 or v.type >> 2 & 1 ~= 0 then - rounded_value = (rounded_value * 10000) + 0.5 - rounded_value = math.floor(rounded_value) - rounded_value = rounded_value / 10000 - end - if v.type >> 2 & 1 ~= 0 then - cheeseUtils.draw_slider( - cheeseUtils.memoize.v2( - (stuff.drawFeatParams.rectPos.x + stuff.menuData.feature_scale.x/2 - stuff.menuData.slider.width/4 - stuff.menuData.padding.slider)*2-1, - posY - ), - cheeseUtils.memoize.v2(stuff.menuData.slider.width, is_selected and stuff.menuData.slider.heightActive or stuff.menuData.slider.height), - v.min, v.max, v.value, - is_selected and func.convert_rgba_to_int(stuff.menuData.color.slider_selectedBackground) or func.convert_rgba_to_int(stuff.menuData.color.slider_background), - is_selected and func.convert_rgba_to_int(stuff.menuData.color.slider_selectedActive) or func.convert_rgba_to_int(stuff.menuData.color.slider_active), - is_selected and func.convert_rgba_to_int(stuff.menuData.color.slider_text) or 0, - is_selected) - else - local value_str = "< "..tostring(rounded_value).." >" - if v.str_data then - local pixel_size = scriptdraw.get_text_size(value_str, 1, font).x - local screenWidth = graphics.get_screen_width() - if pixel_size/screenWidth > 370/screenWidth then - local original_size = stuff.drawFeatParams.textSize - stuff.drawFeatParams.textSize = stuff.drawFeatParams.textSize * (370 / pixel_size * 0.8) - stuff.drawFeatParams.textSize = math.min(stuff.drawFeatParams.textSize + 0.2, original_size) - end - end + -- Usage: local index, item = selector("Select Player: ", 2, {"Player 1", "Player 2", "Player 3"}) + -- if cancelled returned `index` will be false + -- `items` has to be in order and starting from 1 + function cheeseUtils.selector(selected_str, speed, index, items) + index = tonumber(index) or 1 + index = index > 1 and index or 1 + assert(type(items) == "table", "items should be a table") + local stuff = { + selected_str = selected_str and tostring(selected_str) or "Select: ", + items = items, + selected = tonumber(index) or 1, + next_selected = 0, + offset = 0, + size_offset = 0, + offset_step = 0.08/(10/(speed or 1)), + size_step = 0.3/(10/(speed or 1)), + text_size_rel_to_res = (3686400/(graphics.get_screen_width()*graphics.get_screen_height()))*0.3+0.7, + } - scriptdraw.draw_text( - value_str, - cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x + (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.value) - scriptdraw.size_pixel_to_rel_x(scriptdraw.get_text_size(value_str, stuff.drawFeatParams.textSize, font).x)/4)*2-1, (stuff.drawFeatParams.rectPos.y + stuff.drawFeatParams.textOffset.y + (stuff.menuData.feature_offset * k))*-2+1), - cheeseUtils.memoize.v2(10, 10), - stuff.drawFeatParams.textSize, - func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a), - 0, font - ) - end + local drawThread = menu.create_thread(draw_selector, stuff) + + while key.enter:is_down() do + system.wait(0) end - end - stuff.draw_current_menu = {frameCounter = 1, time = utils.time_ms() + 33, currentSprite = stuff.menuData.header} - function func.draw_current_menu() - local sprite = func.load_sprite(stuff.path.header..(stuff.menuData.header or "")) - if stuff.draw_current_menu.currentSprite ~= stuff.menuData.header then - stuff.draw_current_menu.currentSprite = stuff.menuData.header - stuff.draw_current_menu.time = 0 - stuff.draw_current_menu.frameCounter = 1 - if type(sprite) == "table" then - stuff.draw_current_menu.time = utils.time_ms() + (sprite[stuff.draw_current_menu.frameCounter].delay or sprite.constant_delay or 33) + while true do + if key.enter:is_down() then + break end - end - stuff.drawHiddenOffset = 0 - for k, v in pairs(currentMenu) do - if type(k) == "number" then - if v.hidden or (v.type >> 11 & 1 ~= 0 and not v.on) then - stuff.drawHiddenOffset = stuff.drawHiddenOffset + 1 + if key.backspace:is_down() then + menu.delete_thread(drawThread) + while key.backspace:is_down() do + system.wait(0) end + return false end + if get_key_wait("up") then + stuff.move = "up" + stuff.next_selected = stuff.selected - 1 + end + if get_key_wait("down") then + stuff.move = "down" + stuff.next_selected = stuff.selected + 1 + end + system.wait(0) end - local background_sprite_path = stuff.path.background..(stuff.menuData.background_sprite.sprite or "") - if stuff.menuData.background_sprite.sprite and func.load_sprite(background_sprite_path) then - scriptdraw.draw_sprite( - func.load_sprite(background_sprite_path), - cheeseUtils.memoize.v2((stuff.menuData.pos_x + stuff.menuData.background_sprite.offset.x)*2-1, (stuff.menuData.pos_y+stuff.menuData.background_sprite.offset.y+stuff.menuData.height/2+0.01458)*-2+1), - stuff.menuData.background_sprite.size, - 0, - func.convert_rgba_to_int(255, 255, 255, stuff.menuData.color.background.a) - ) - else - scriptdraw.draw_rect( - cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, (stuff.menuData.pos_y+stuff.menuData.border+stuff.menuData.height/2)*-2+1), - cheeseUtils.memoize.v2(stuff.menuData.width*2, stuff.menuData.height*2), - func.convert_rgba_to_int(stuff.menuData.color.background.r, stuff.menuData.color.background.g, stuff.menuData.color.background.b, stuff.menuData.color.background.a) - ) - end - if #currentMenu - stuff.drawHiddenOffset >= stuff.menuData.max_features then - stuff.maxDrawScroll = #currentMenu - stuff.drawHiddenOffset - stuff.menuData.max_features - else - stuff.maxDrawScroll = 0 - end - if stuff.drawScroll > stuff.maxDrawScroll then - stuff.drawScroll = stuff.maxDrawScroll - end - if stuff.scroll > #currentMenu - stuff.drawHiddenOffset then - stuff.scroll = #currentMenu - stuff.drawHiddenOffset - elseif stuff.scroll < 1 and #currentMenu > 0 then - stuff.scroll = 1 + + while key.enter:is_down() do + system.wait(0) end - -- header border - scriptdraw.draw_rect(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, (stuff.menuData.pos_y + stuff.menuData.border/2)*-2+1), cheeseUtils.memoize.v2(stuff.menuData.width*2, stuff.menuData.border*2), func.convert_rgba_to_int(stuff.menuData.color.border.r, stuff.menuData.color.border.g, stuff.menuData.color.border.b, stuff.menuData.color.border.a)) + menu.delete_thread(drawThread) - local hiddenOffset = 0 - local drawnfeats = 0 - stuff.menuData.text_size = (((graphics.get_screen_width()*graphics.get_screen_height())/3686400)*0.45+0.25) -- * stuff.menuData.text_size_modifier + return stuff.selected, stuff.items[stuff.selected] + end +end +-- - stuff.drawFeatParams.rectPos.x = stuff.menuData.pos_x - stuff.drawFeatParams.rectPos.y = stuff.menuData.pos_y - stuff.menuData.feature_offset/2 + stuff.menuData.border - stuff.drawFeatParams.textOffset.x = stuff.menuData.feature_scale.x/2 - stuff.drawFeatParams.colorText = stuff.menuData.color.text - stuff.drawFeatParams.colorFeature = stuff.menuData.color.feature - stuff.drawFeatParams.textSize = stuff.menuData.text_size * stuff.menuData.text_size_modifier +-- Draw Slider +do + local reuse_v2 = cheeseUtils.new_reusable_v2() - for k, v in ipairs(currentMenu) do - if type(k) == "number" then - if v.hidden or (v.type >> 11 & 1 ~= 0 and not v.on) then - hiddenOffset = hiddenOffset + 1 - elseif k <= stuff.drawScroll + hiddenOffset + stuff.menuData.max_features and k >= stuff.drawScroll + hiddenOffset + 1 then - func.draw_feat(k - stuff.drawScroll - hiddenOffset, v, 0, hiddenOffset) - drawnfeats = drawnfeats + 1 - end - end + function cheeseUtils.draw_slider(pos, width, min, max, value, colorBG, colorActive, colorText, draw_value) + scriptdraw.draw_rect(pos, width, colorBG) + local ActiveWidthX = width.x * ((value - min) / (max - min)) + scriptdraw.draw_rect(reuse_v2(pos.x - width.x/2 + ActiveWidthX/2, pos.y), reuse_v2(ActiveWidthX , width.y), colorActive) + + if draw_value then + local text_size = scriptdraw.get_text_size(tostring(value), 1) + local size_correction = width.y*2 / scriptdraw.size_pixel_to_rel_y(text_size.y*2) - 0.12 + text_size = text_size * size_correction + text_size.x = scriptdraw.size_pixel_to_rel_x(text_size.x) + text_size.y = scriptdraw.size_pixel_to_rel_y(text_size.y) + scriptdraw.draw_text(tostring(value), reuse_v2(pos.x - text_size.x/2, pos.y + text_size.y/2), reuse_v2(2, 2), size_correction, colorText, 0) end + end +end - if stuff.menuData.footer.draw_footer then - -- footer border - local footer_border_y_pos - if stuff.menuData.footer.footer_pos_related_to_background then - footer_border_y_pos = (stuff.menuData.pos_y + stuff.menuData.height + stuff.menuData.border*1.5)*-2+1 - else - footer_border_y_pos = (stuff.menuData.pos_y + (drawnfeats*stuff.menuData.feature_offset) + stuff.menuData.border*1.5)*-2+1 - end - scriptdraw.draw_rect(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, footer_border_y_pos), cheeseUtils.memoize.v2(stuff.menuData.width*2, stuff.menuData.border*2), func.convert_rgba_to_int(stuff.menuData.color.border.r, stuff.menuData.color.border.g, stuff.menuData.color.border.b, stuff.menuData.color.border.a)) +-- Use width and height with draw_rect_ext +do + local v2r = cheeseUtils.new_reusable_v2(4) + function cheeseUtils.draw_rect_ext_wh(pos, size, color1, color2, color3, color4) + local halfWdith, halfHeight = size.x/2, size.y/2 + local Bottom = pos.y - halfHeight + local Top = pos.y + halfHeight + local Left = pos.x - halfWdith + local Right = pos.x + halfWdith + scriptdraw.draw_rect_ext(v2r(Left, Bottom), v2r(Left, Top), v2r(Right, Top), v2r(Right, Bottom), color1, color2, color3, color4) + end +end - -- footer and text/scroll - local footerColor = func.convert_rgba_to_int(stuff.menuData.color.footer.r, stuff.menuData.color.footer.g, stuff.menuData.color.footer.b, stuff.menuData.color.footer.a) - local footer_y_pos - if stuff.menuData.footer.footer_pos_related_to_background then - footer_y_pos = (stuff.menuData.pos_y + stuff.menuData.height + stuff.menuData.border*2 + stuff.menuData.footer.footer_size/2)*-2+1 - else - footer_y_pos = (stuff.menuData.pos_y + (drawnfeats*stuff.menuData.feature_offset) + stuff.menuData.border*2 + stuff.menuData.footer.footer_size/2)*-2+1 - end - scriptdraw.draw_rect(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, footer_y_pos), cheeseUtils.memoize.v2(stuff.menuData.width*2, stuff.menuData.footer.footer_size*2), footerColor) +-- Side Window +--[[ +Usage example: + local cheeseUtils = require("CheeseUtilities") - local footerTextColor = func.convert_rgba_to_int(stuff.menuData.color.footer_text.r, stuff.menuData.color.footer_text.g, stuff.menuData.color.footer_text.b, stuff.menuData.color.footer_text.a) - local featHint = stuff.feature_hints[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].id] - if featHint then - local padding = scriptdraw.size_pixel_to_rel_y(5) - local hintStrSize = scriptdraw.size_pixel_to_rel_y(featHint.size.y) * (stuff.menuData.text_size * stuff.menuData.hint_size_modifier) - local posY = footer_y_pos - stuff.menuData.border*2 - stuff.menuData.footer.footer_size - padding - local textY = posY - padding - posY = posY - hintStrSize/2 + local window_test = cheeseUtils.new_side_window("test_header", v2(0.5, 0.5)) - local rectHeight = hintStrSize+padding*4 - --scriptdraw.draw_rect(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, posY+rectHalfHeight/2), cheeseUtils.memoize.v2(stuff.menuData.width*2, rectHalfHeight), func.convert_rgba_to_int(stuff.menuData.color.footer.r, stuff.menuData.color.footer.g, stuff.menuData.color.footer.b, stuff.menuData.color.footer.a)) - cheeseUtils.draw_rect_ext_wh(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, posY-padding), cheeseUtils.memoize.v2(stuff.menuData.width*2, rectHeight), (footerColor & 0xffffff) | 50 << 24, footerColor, footerColor, (footerColor & 0xffffff) | 50 << 24) - scriptdraw.draw_text( - featHint.str, - cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1 - stuff.menuData.width + padding, textY), - cheeseUtils.memoize.v2(stuff.menuData.width+padding*2, 2), - stuff.menuData.text_size * stuff.menuData.hint_size_modifier, - footerTextColor, - 0, - stuff.menuData.fonts.hint - ) + local firstField = window_test:add_field("left", "right") + + do + local timer = utils.time_ms() + 100 + window_test:add_field("idk", "1"):set_update_function(function(field) + if timer < utils.time_ms() then + timer = utils.time_ms() + 100 + local fieldValue = tonumber(field.value) + fieldValue = fieldValue + 1 + if fieldValue > 25 then + fieldValue = 1 + end + return fieldValue, fieldValue > 10 and "> 10" or "< 10" end + end) + end - local footer_size = stuff.menuData.text_size * stuff.menuData.footer_size_modifier - local text_y_pos = footer_y_pos + 0.011111111 + stuff.menuData.footer.footer_y_offset - scriptdraw.draw_text( - tostring(stuff.menuData.footer.footer_text), - cheeseUtils.memoize.v2((stuff.menuData.pos_x - stuff.menuData.width/2 + stuff.menuData.footer.padding)*2-1, text_y_pos), - cheeseUtils.memoize.v2(2, 2), - footer_size, - footerTextColor, - 0, - stuff.menuData.fonts.footer - ) + window_test:set_position(nil, 0.2) - scriptdraw.draw_text( - tostring(stuff.scroll.." / "..(#currentMenu - stuff.drawHiddenOffset)), - cheeseUtils.memoize.v2((stuff.menuData.pos_x + stuff.menuData.width/2 - stuff.menuData.footer.padding)*2-1, text_y_pos), - cheeseUtils.memoize.v2(2, 2), - footer_size, - footerTextColor, - 16, - stuff.menuData.fonts.footer - ) - end + window_test:set_rect_color(0xAA000000) - if type(sprite) == "table" then - if not sprite[stuff.draw_current_menu.frameCounter] then - stuff.draw_current_menu.frameCounter = 1 - end - if utils.time_ms() > stuff.draw_current_menu.time then - if stuff.draw_current_menu.frameCounter < #sprite then - stuff.draw_current_menu.frameCounter = stuff.draw_current_menu.frameCounter + 1 - else - stuff.draw_current_menu.frameCounter = 1 - end - stuff.draw_current_menu.time = utils.time_ms() + (sprite[stuff.draw_current_menu.frameCounter].delay or sprite.constant_delay or 33) - end - sprite = sprite[stuff.draw_current_menu.frameCounter].sprite - end - if sprite then - local size = ((2.56 * stuff.menuData.width) * (1000 / scriptdraw.get_sprite_size(sprite).x)) / (2560 / graphics.get_screen_width()) - scriptdraw.draw_sprite(sprite, cheeseUtils.memoize.v2(stuff.menuData.pos_x * 2 - 1, ((stuff.menuData.pos_y+stuff.menuData.height/2) - (stuff.menuData.height/2 + ((scriptdraw.get_sprite_size(sprite).y*size)/2)/graphics.get_screen_height()))*-2+1), size, 0, stuff.menuData.color.sprite) + menu.create_thread(function() + while true do + window_test:update() + window_test:draw() + system.wait(0) end - system.wait(0) - end + end) - --[[ - example of table_of_lines: - { - {"leftside", "rightside"}, - {"IP", "ddosing u rn"}, - {"Cheesus", "Christ"} - } - has to be in this structure, you can add more than three - ]] - function func.draw_side_window(header_text, table_of_lines, v2pos, rect_color, rect_width, text_spacing, text_padding, text_color) - text_color = text_color or 0xFFFFFFFF - assert( - type(header_text) == "string" - and type(table_of_lines) == "table" - and type(v2pos) == "userdata" - and type(rect_color) == "number" - and type(rect_width) == "number" - and type(text_spacing) == "number" - and type(text_padding) == "number" - and type(text_color) == "number", + menu.add_feature("hide cheese", "toggle", 0, function(f) + if f.on then + window_test:remove_field(window_test:get_field_by_name("cheese")) + firstField:set_value("right") + else + window_test:add_field("cheese", "menu", 2) + firstField:set_value("cheese enabled") + end + end).on = true +]] +do + local function draw_side_window(self) + assert( + type(self.header_text) == "string" + and type(self.fields) == "table" + and type(self.pos) == "userdata" + and type(self.rect_color) == "number" + and type(self.rect_width) == "number" + and type(self.text_spacing) == "number" + and type(self.text_padding) == "number" + and type(self.text_color) == "number", "one or more draw_side_window args were invalid" ) - local rect_height = #table_of_lines*text_spacing+0.07125 - v2pos.y = v2pos.y-(rect_height/2) + local rect_height = (#self.fields-self.hidden_fields)*self.text_spacing - self.text_spacing + self.last_name_height + 0.02 --+0.0083--+(self.header_on and 0.07125 or 0.02) + local original_y = self.pos.y--(rect_height/2) + local header_y = original_y+self.header_height/2+rect_height/2 + local hidden_y_offset = 0 - scriptdraw.draw_rect(v2pos, cheeseUtils.memoize.v2(rect_width, rect_height), rect_color) + scriptdraw.draw_rect(self.pos, cheeseUtils.memoize.v2(self.rect_width, rect_height), self.rect_color) + if self.header_on then + scriptdraw.draw_rect(cheeseUtils.memoize.v2(self.pos.x, header_y), cheeseUtils.memoize.v2(self.rect_width, self.header_height), self.rect_color) + end local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 -- Header text - scriptdraw.draw_text(header_text, cheeseUtils.memoize.v2(v2pos.x - scriptdraw.get_text_size(header_text, text_size, 0).x/graphics.get_screen_width(), v2pos.y+(rect_height/2)-0.015), cheeseUtils.memoize.v2(2, 2), text_size, text_color, 0, 0) + scriptdraw.draw_text(self.header_text, cheeseUtils.memoize.v2(self.pos.x - self.header_text_width/graphics.get_screen_width(), header_y+0.015), cheeseUtils.memoize.v2(2, 2), text_size, self.text_color, 0, 0) -- table_of_lines - for k, v in ipairs(table_of_lines) do - v[1] = tostring(v[1]) - v[2] = tostring(v[2]) - local pos_y = v2pos.y-k*text_spacing+rect_height/2-0.03 - scriptdraw.draw_text(v[1], cheeseUtils.memoize.v2(v2pos.x-rect_width/2+text_padding, pos_y), cheeseUtils.memoize.v2(2, 2), text_size, text_color, 0, 2) - scriptdraw.draw_text(v[2], cheeseUtils.memoize.v2(v2pos.x+rect_width/2-text_padding, pos_y), cheeseUtils.memoize.v2(2, 2), text_size, text_color, 16, 2) + for id, field in ipairs(self.fields) do + if field.hidden then + hidden_y_offset = hidden_y_offset + 1 + else + local pos_y = original_y-(id-hidden_y_offset-1)*self.text_spacing+rect_height/2 - self.last_name_height/6 - 0.01 --(self.text_spacing/2.5) + scriptdraw.draw_text(field.name, cheeseUtils.memoize.v2(self.pos.x-self.rect_width/2+self.text_padding, pos_y), cheeseUtils.memoize.v2(2, 2), text_size, self.text_color, 0, 2) + scriptdraw.draw_text(field.value, cheeseUtils.memoize.v2(self.pos.x+self.rect_width/2-self.text_padding, pos_y), cheeseUtils.memoize.v2(2, 2), text_size, self.text_color, 16, 2) + end end end - --Hotkey functions - function func.get_hotkey(keyTable, vkTable, singlekey) - local current_key - local excludedkeys = {} - while not keyTable[1] do - if cheeseUtils.get_key(0x1B):is_down() then - return "escaped" - end - for k, v in pairs(stuff.char_codes) do - if cheeseUtils.get_key(v):is_down() then - if v ~= 0x0D or singlekey then - if v ~= 0xA0 and v ~= 0xA1 and v ~= 0xA2 and v ~= 0xA3 and v ~= 0xA4 and v ~= 0xA5 and not singlekey then - keyTable[1] = "NOMOD" - end - if singlekey then - return k, v - else - keyTable[#keyTable + 1] = k - vkTable[#vkTable+1] = v - current_key = v - excludedkeys[v] = true - end - end + -- field functions + local function set_name(self, new_name) + if new_name then + if self.window.fields[#self.window.fields] == self then + local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 + self.window.last_name_height = scriptdraw.size_pixel_to_rel_y(scriptdraw.get_text_size(new_name, text_size, 0).y) end + self.fields_by_name[self.name] = nil + self.name = tostring(new_name) or "" + self.fields_by_name[new_name] = self end - system.wait(0) end - if not singlekey then - while cheeseUtils.get_key(current_key):is_down() do - for k, v in pairs(stuff.char_codes) do - if cheeseUtils.get_key(v):is_down() and not excludedkeys[v] and v ~= 0xA0 and v ~= 0xA1 and v ~= 0xA2 and v ~= 0xA3 and v ~= 0xA4 and v ~= 0xA5 then - excludedkeys[v] = true - keyTable[#keyTable + 1] = k - vkTable[#vkTable+1] = v - end - end - system.wait(0) + local function set_value(self, value) + if value then + self.value = tostring(value) end + end - while not cheeseUtils.get_key(0x1B):is_down() and not cheeseUtils.get_key(0x0D):is_down() do - for k, v in pairs(stuff.char_codes) do - if cheeseUtils.get_key(v):is_down() then - return false - end - end - system.wait(0) + local function set_update_function(self, callback) + self.update_function = callback + end + + local function update_field(self) + if self.update_function then + local value, name = self:update_function() + + self:set_value(value) + self:set_name(name) end + end - return cheeseUtils.get_key(0x0D):is_down() or "escaped" + local function set_hidden(self, bool) + assert(type(bool) == "boolean", "hidden only accepts boolean value") + if bool ~= self.hidden then + self.hidden = bool + self.window.hidden_fields = self.window.hidden_fields + (bool and 1 or -1) + end end - end + -- - function func.draw_hotkey(keyTable) - while true do - for i = 0, 360 do - controls.disable_control_action(0, i, true) + ---@class field + ---@field name string + ---@field value string + ---@field set_name function + ---@field set_value function + ---@field set_update_function function + ---@field update function + + ---@param name string + ---@param value string | number + ---@return field + local function add_field(self, name, value, pos) + local field = { + name = name, + value = value, + id = pos or #self.fields + 1, + fields_by_name = self.fields_by_name, + window = self, + hidden = false, + set_name = set_name, + set_value = set_value, + set_update_function = set_update_function, + update = update_field, + set_hidden = set_hidden + } + if pos then + local prevField = (pos - 1 > 0 and self.fields[pos-1] or true) + assert(prevField, "Fields have to be in increments of 1, for example (1, 2, 5) will not work") + if self.fields[pos] and prevField then + table.insert(self.fields, pos, field) + elseif prevField then + self.fields[pos] = field end - local concatenated = table.concat(keyTable, "+") - scriptdraw.draw_rect(cheeseUtils.memoize.v2(0, 0), cheeseUtils.memoize.v2(2, 2), 0x7D000000) - scriptdraw.draw_text(concatenated, cheeseUtils.memoize.v2(-(scriptdraw.get_text_size(concatenated, 1, 0).x/graphics.get_screen_width())), cheeseUtils.memoize.v2(2, 2), 1, 0xffffffff, 1 << 1, 0) - system.wait(0) + else + self.fields[#self.fields + 1] = field + local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 + self.last_name_height = scriptdraw.size_pixel_to_rel_y(scriptdraw.get_text_size(name, text_size, 0).y) end + self.fields_by_name[name] = field + + return field end + local function remove_field(self, field) + if field and self.fields[field.id] then + table.remove(self.fields, field.id) + self.fields_by_name[field.name] = nil - function func.start_hotkey_process(feat) - stuff.menuData.menuToggle = false - local keyTable = {} - local vkTable = {} + return true + end - local drawThread = menu.create_thread(func.draw_hotkey, keyTable) + return false + end - while cheeseUtils.get_key(stuff.vkcontrols.setHotkey):is_down() do - system.wait(0) + local function get_field_by_name(self, name) + return self.fields_by_name[name] + end + + local function update(self) + for _, field in pairs(self.fields) do + field:update() end + end - local response - repeat - response = func.get_hotkey(keyTable, vkTable) - if not response then - for k, v in pairs(keyTable) do - keyTable[k] = nil - end - for k, v in pairs(vkTable) do - vkTable[k] = nil - end - end - until response + local function set_position(self, x, y) + self.pos.x = tonumber(x) or self.pos.x + self.pos.y = tonumber(y) or self.pos.y + end - local keyString = table.concat(keyTable, "|") + local function set_header_text(self, text) + text = tostring(text) + self.header_text = text + self.header_on = text ~= "" + local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 + self.header_text_width = scriptdraw.get_text_size(self.header_text, text_size, 0).x + end + + local set_functions = {} + for _, field in ipairs({'text_padding', 'text_spacing', 'rect_width', 'rect_color', 'text_color'}) do + set_functions[field] = function(self, num) + num = tonumber(num) + assert(num, field.." value has to be a number") + self[field] = num + end + end + + ---@class window + ---@field draw function + ---@field update function + ---@field add_field function + ---@field remove_field function + ---@field set_position function + ---@field get_field_by_name function + ---@field set_text_padding function + ---@field set_text_spacing function + ---@field set_rect_width function + ---@field set_rect_color function + ---@field set_text_color function + ---@field set_header_text function + ---@field set_hidden function + ---@field header_text string + ---@field fields table + ---@field fields_by_name table + ---@field pos v2 + ---@field rect_color uint32_t + ---@field rect_width float + ---@field text_spacing float + ---@field text_padding float + ---@field text_color uint32_t + + ---@return window + function cheeseUtils.new_side_window(header_text, pos, rect_color, rect_width, text_spacing, text_padding, text_color) + local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 + + local window = { + header_text = header_text or "", + header_on = header_text ~= "", + fields = {}, + fields_by_name = {}, + pos = pos or v2(), + rect_color = rect_color or 0xFF000000, + rect_width = rect_width or 0.2, + text_spacing = text_spacing or 0.047, + text_padding = text_padding or 0.01, + text_color = text_color or 0xFFFFFFFF, + header_height = 0.06125, + header_text_width = scriptdraw.get_text_size(header_text, text_size, 0).x, + hidden_fields = 0, + } - if response ~= "escaped" then - stuff.hotkeys_to_vk[keyString] = vkTable - if not stuff.hotkeys[keyString] then - stuff.hotkeys[keyString] = {} - end - stuff.hotkeys[keyString][feat.hierarchy_key] = true - feat.hotkey = keyString - gltw.write(stuff.hotkeys, "hotkeys", stuff.path.hotkeys, nil, true) + window.draw = draw_side_window + window.update = update + window.add_field = add_field + window.remove_field = remove_field + window.set_position = set_position + window.get_field_by_name = get_field_by_name + window.set_header_text = set_header_text + for name, func in pairs(set_functions) do + window['set_'..name] = func end - menu.delete_thread(drawThread) - while cheeseUtils.get_key(0x0D):is_down() or cheeseUtils.get_key(0x1B):is_down() do -- enter and esc - controls.disable_control_action(0, 200, true) - system.wait(0) - end - controls.disable_control_action(0, 200, true) - func.toggle_menu(true) - return response ~= "escaped" and response + return window end +end - --End of functions - --threads - menu.create_thread(function() - local side_window_pos = v2((stuff.menuData.pos_x + stuff.menuData.width + stuff.menuData.side_window.offset.x)*2-1, (stuff.menuData.pos_y + stuff.menuData.side_window.offset.y)*-2+1) - while true do - if stuff.menuData.menuToggle then - func.draw_current_menu() - if currentMenu and stuff.menuData.side_window.on then - local pid = currentMenu.pid - if not pid and currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then - pid = currentMenu[stuff.scroll + stuff.scrollHiddenOffset].pid - end - if pid and pid ~= stuff.pid then - if not stuff.playerIds[pid].hidden then - stuff.player_info[1][2] = tostring(pid) - stuff.player_info[10][2] = func.convert_int_ip(player.get_player_ip(pid)) - stuff.player_info[11][2] = tostring(player.get_player_scid(pid)) - stuff.player_info[12][2] = string.format("%X", player.get_player_host_token(pid)) - stuff.player_info.max_health = "/"..math.floor(player.get_player_max_health(pid)) - stuff.player_info.name = tostring(player.get_player_name(pid)) - stuff.pid = pid - end - end - if pid then - side_window_pos.x, side_window_pos.y = (stuff.menuData.pos_x + stuff.menuData.width + stuff.menuData.side_window.offset.x)*2-1, (stuff.menuData.pos_y + stuff.menuData.side_window.offset.y)*-2+1 - native.call(0xBE8CD9BE829BBEBF, player.get_player_ped(stuff.pid), stuff.proofs.bulletProof, stuff.proofs.fireProof, stuff.proofs.explosionProof, stuff.proofs.collisionProof, stuff.proofs.meleeProof, stuff.proofs.steamProof, stuff.proofs.p7, stuff.proofs.drownProof) - stuff.player_info[2][2] = player.is_player_god(stuff.pid) and "Yes" or "No" - stuff.player_info[3][2] = (stuff.proofs.bulletProof:__tointeger()|stuff.proofs.fireProof:__tointeger()|stuff.proofs.explosionProof:__tointeger()|stuff.proofs.collisionProof:__tointeger()|stuff.proofs.meleeProof:__tointeger()|stuff.proofs.steamProof:__tointeger()|stuff.proofs.p7:__tointeger()|stuff.proofs.drownProof:__tointeger()) == 1 and "Yes" or "No" - stuff.player_info[4][2] = player.is_player_vehicle_god(stuff.pid) and "Yes" or "No" - stuff.player_info[5][2] = player.is_player_modder(stuff.pid, -1) and "Yes" or "No" - stuff.player_info[6][2] = player.is_player_host(stuff.pid) and "Yes" or "No" - stuff.player_info[7][2] = player.get_player_wanted_level(stuff.pid) - stuff.player_info[8][2] = math.floor(player.get_player_health(stuff.pid))..stuff.player_info.max_health - stuff.player_info[9][2] = math.floor(player.get_player_armour(stuff.pid)).."/50" - stuff.player_info[13][2] = player.get_player_host_priority(stuff.pid) - func.draw_side_window( - stuff.player_info.name, - stuff.player_info, - side_window_pos, - func.convert_rgba_to_int(stuff.menuData.color.side_window.r, stuff.menuData.color.side_window.g, stuff.menuData.color.side_window.b, stuff.menuData.color.side_window.a), - stuff.menuData.side_window.width, stuff.menuData.side_window.spacing, stuff.menuData.side_window.padding, - func.convert_rgba_to_int(stuff.menuData.color.side_window_text.r, stuff.menuData.color.side_window_text.g, stuff.menuData.color.side_window_text.b, stuff.menuData.color.side_window_text.a) - ) - end - end - if stuff.old_selected ~= currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then - if type(stuff.old_selected) == "table" then - stuff.old_selected:activate_hl_func() - end - if currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then - currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() - end - stuff.old_selected = currentMenu[stuff.scroll + stuff.scrollHiddenOffset] - end - controls.disable_control_action(0, 172, true) - controls.disable_control_action(0, 27, true) - else - system.wait(0) - end - end - end, nil) +-- Range Converter +do + local function convert_range(self, value) + return self.base_value + (value * self.step) + end + local Metatable = {__call = convert_range} - menu.create_thread(function() - while true do - stuff.menuData.menuNav = native.call(0x5FCF4D7069B09026):__tointeger() ~= 1 and not (stuff.menuData.chatBoxOpen or input.is_open() --[[or console.on]]) - if stuff.menuData.menuNav then - func.do_key(500, stuff.vkcontrols.open, false, function() -- F4 - func.toggle_menu(not stuff.menuData.menuToggle) - end) - end - if currentMenu.hidden or not currentMenu then - currentMenu = stuff.previousMenus[#stuff.previousMenus].menu - stuff.scroll = stuff.previousMenus[#stuff.previousMenus].scroll - stuff.drawScroll = stuff.previousMenus[#stuff.previousMenus].drawScroll - stuff.scrollHiddenOffset = stuff.previousMenus[#stuff.previousMenus].scrollHiddenOffset - stuff.previousMenus[#stuff.previousMenus] = nil - end - local pid = player.player_id() - stuff.playerIds[pid].name = player.get_player_name(pid).." [Y]" - if stuff.playerIds[pid].hidden then - stuff.playerIds[pid].hidden = false - func.reset_player_submenu(pid) - end - system.wait(0) - end - end, nil) - menu.create_thread(function() - while true do - system.wait(0) - if stuff.menuData.menuToggle and stuff.menuData.menuNav then - func.do_key(500, stuff.vkcontrols.setHotkey, false, function() -- F11 - if cheeseUtils.get_key(0x10):is_down() and stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey] then - stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey][currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hierarchy_key] = nil - if not next(stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey]) then - stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey] = nil - end - currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey = nil - gltw.write(stuff.hotkeys, "hotkeys", stuff.path.hotkeys, nil, true) - menu.notify("Removed "..currentMenu[stuff.scroll + stuff.scrollHiddenOffset].name.."'s hotkey") - elseif cheeseUtils.get_key(0x11):is_down() then - menu.notify(currentMenu[stuff.scroll + stuff.scrollHiddenOffset].name.."'s hotkey is "..(currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey or "none")) - elseif not cheeseUtils.get_key(0x10):is_down() and not cheeseUtils.get_key(0x11):is_down() then - if stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey] then - stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey][currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hierarchy_key] = nil - end - if func.start_hotkey_process(currentMenu[stuff.scroll + stuff.scrollHiddenOffset]) then - menu.notify("Set "..currentMenu[stuff.scroll + stuff.scrollHiddenOffset].name.."'s hotkey to "..currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey) - end - end - end) - end - end - end,nil) - menu.create_thread(function() - while true do - system.wait(0) - if stuff.menuData.menuToggle and stuff.menuData.menuNav then - func.do_key(500, stuff.vkcontrols.down, true, function() -- downKey - --[[ local old_scroll = stuff.scroll + stuff.scrollHiddenOffset ]] - if stuff.scroll + stuff.drawHiddenOffset >= #currentMenu and #currentMenu - stuff.drawHiddenOffset > 1 then - stuff.scroll = 1 - stuff.drawScroll = 0 - elseif #currentMenu - stuff.drawHiddenOffset > 1 then - stuff.scroll = stuff.scroll + 1 - if stuff.scroll - stuff.drawScroll >= (stuff.menuData.max_features - 1) and stuff.drawScroll < stuff.maxDrawScroll then - stuff.drawScroll = stuff.drawScroll + 1 - end - end - --[[ if old_scroll ~= (stuff.scroll + stuff.scrollHiddenOffset) then - currentMenu[old_scroll]:activate_hl_func() - if currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then - currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() - end - end ]] - end) - end - end - end, nil) - menu.create_thread(function() - while true do - system.wait(0) - if stuff.menuData.menuToggle and stuff.menuData.menuNav then - func.do_key(500, stuff.vkcontrols.up, true, function() -- upKey - --[[ local old_scroll = stuff.scroll + stuff.scrollHiddenOffset ]] - if stuff.scroll <= 1 and #currentMenu - stuff.drawHiddenOffset > 1 then - stuff.scroll = #currentMenu - stuff.drawScroll = stuff.maxDrawScroll - elseif #currentMenu - stuff.drawHiddenOffset > 1 then - stuff.scroll = stuff.scroll - 1 - if stuff.scroll - stuff.drawScroll <= 2 and stuff.drawScroll > 0 then - stuff.drawScroll = stuff.drawScroll - 1 - end - end - --[[ if old_scroll ~= (stuff.scroll + stuff.scrollHiddenOffset) then - currentMenu[old_scroll]:activate_hl_func() - if currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then - currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() - end - end ]] - end) - end - end - end,nil) - menu.create_thread(function() - while true do - system.wait(0) - if stuff.menuData.menuToggle and stuff.menuData.menuNav then - func.do_key(500, stuff.vkcontrols.select, true, function() --enter - local feat = currentMenu[stuff.scroll + stuff.scrollHiddenOffset] - if feat then - if cheeseUtils.get_key(stuff.vkcontrols.specialKey):is_down() and feat.type >> 5 & 1 ~= 0 then - menu.create_thread(func.selector, feat) - elseif feat.type >> 11 & 1 ~= 0 and not feat.hidden then - --feat:activate_hl_func() - stuff.previousMenus[#stuff.previousMenus + 1] = {menu = currentMenu, scroll = stuff.scroll, drawScroll = stuff.drawScroll, scrollHiddenOffset = stuff.scrollHiddenOffset} - currentMenu = feat - currentMenu:activate_feat_func() - stuff.scroll = 1 - system.wait(0) - stuff.drawScroll = 0 - stuff.scrollHiddenOffset = 0 - --[[ if feat then - feat:activate_hl_func() - end ]] - while cheeseUtils.get_key(stuff.vkcontrols.select):is_down() do - system.wait(0) - end - elseif feat.type & 1536 ~= 0 and not feat.hidden then - feat:activate_feat_func() - elseif feat.type & 1 ~= 0 and not feat.hidden then - feat.real_on = not feat.real_on - feat:activate_feat_func() - end - else - system.wait(100) - end - end) - end - end - end, nil) - menu.create_thread(function() - while true do - system.wait(0) - if stuff.menuData.menuToggle and stuff.menuData.menuNav then - func.do_key(500, stuff.vkcontrols.back, false, function() --backspace - if stuff.previousMenus[#stuff.previousMenus] then - --[[ if currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then - currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() - end ]] - currentMenu = stuff.previousMenus[#stuff.previousMenus].menu - stuff.scroll = stuff.previousMenus[#stuff.previousMenus].scroll - stuff.drawScroll = stuff.previousMenus[#stuff.previousMenus].drawScroll - stuff.scrollHiddenOffset = stuff.previousMenus[#stuff.previousMenus].scrollHiddenOffset - stuff.previousMenus[#stuff.previousMenus] = nil - --currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() + function cheeseUtils.create_range_converter(original_range_min, original_range_max, convert_range_min, convert_range_max) + local stuff = {} + + local adjusted_max_original = original_range_max-original_range_min + local adjusted_max_convert = convert_range_max-convert_range_min + + stuff.base_value = (0-original_range_min)/adjusted_max_original*adjusted_max_convert+convert_range_min + stuff.step = (1-original_range_min)/adjusted_max_original*adjusted_max_convert+convert_range_min - stuff.base_value + + setmetatable(stuff, Metatable) + + return stuff + end +end + +-- Text Wrap +do + ---@param text string + ---@param font int + ---@param scale float + ---@param relWidth float + function cheeseUtils.wrap_text(text, font, scale, relWidth) + local spaceSize = scriptdraw.get_text_size(". .", scale, font).x - scriptdraw.get_text_size("..", scale, font).x + local lines = {} + for line, manualNewLines in text:gmatch("([^\r\n]+)([\r\n]*)") do + local newline + local lineSize = scriptdraw.get_text_size(line, scale, font) + + if scriptdraw.size_pixel_to_rel_x(lineSize.x) > relWidth then + local length = 0 + newline = {} + for word in line:gmatch("[^%s-\\,]+[%s-\\,]*") do + local relx = scriptdraw.size_pixel_to_rel_x(scriptdraw.get_text_size(word, scale, font).x) + local spaceRelx = word:gsub("%S", "") + spaceRelx = scriptdraw.size_pixel_to_rel_x(#spaceRelx*spaceSize) + if length + relx > relWidth then + newline[#newline+1] = "\n" + length = 0 end - end) + length = length + relx + spaceRelx + newline[#newline+1] = word + end + + line = table.concat(newline) end + + lines[#lines+1] = line..(manualNewLines or "") end - end, nil) + + return table.concat(lines) + end +end + +return cheeseUtils]=], + ["cheesemenu.lua"] = [=[--Made by GhostOne + +--[[ + ,o888888o. 8 8888 8 8 8888888888 8 8888888888 d888888o. 8 8888888888 + 8888 `88. 8 8888 8 8 8888 8 8888 .`8888:' `88. 8 8888 +,8 8888 `8. 8 8888 8 8 8888 8 8888 8.`8888. Y8 8 8888 +88 8888 8 8888 8 8 8888 8 8888 `8.`8888. 8 8888 +88 8888 8 8888 8 8 888888888888 8 888888888888 `8.`8888. 8 888888888888 +88 8888 8 8888 8 8 8888 8 8888 `8.`8888. 8 8888 +88 8888 8 8888888888888 8 8888 8 8888 `8.`8888. 8 8888 +`8 8888 .8' 8 8888 8 8 8888 8 8888 8b `8.`8888. 8 8888 + 8888 ,88' 8 8888 8 8 8888 8 8888 `8b. ;8.`8888 8 8888 + `8888888P' 8 8888 8 8 888888888888 8 888888888888 `Y8888P ,88P' 8 888888888888 + . . + ,8. ,8. 8 8888888888 b. 8 8 8888 88 + ,888. ,888. 8 8888 888o. 8 8 8888 88 + .`8888. .`8888. 8 8888 Y88888o. 8 8 8888 88 + ,8.`8888. ,8.`8888. 8 8888 .`Y888888o. 8 8 8888 88 + ,8'8.`8888,8^8.`8888. 8 888888888888 8o. `Y888888o. 8 8 8888 88 + ,8' `8.`8888' `8.`8888. 8 8888 8`Y8o. `Y88888o8 8 8888 88 + ,8' `8.`88' `8.`8888. 8 8888 8 `Y8o. `Y8888 8 8888 88 + ,8' `8.`' `8.`8888. 8 8888 8 `Y8o. `Y8 ` 8888 ,8P + ,8' `8 `8.`8888. 8 8888 8 `Y8o.` 8888 ,d8P +,8' ` `8.`8888. 8 888888888888 8 `Yo `Y88888P' +]] + +local version = "1.9" +local loadCurrentMenu +local httpTrustedOff + +-- Version check +if menu.is_trusted_mode_enabled(1 << 3) and menu.is_trusted_mode_enabled(1 << 2) then menu.create_thread(function() - while true do - system.wait(0) - if stuff.menuData.menuToggle and stuff.menuData.menuNav then - func.do_key(500, stuff.vkcontrols.left, true, function() -- left - local feat = currentMenu[stuff.scroll + stuff.scrollHiddenOffset] - if feat then - if feat.value then - if feat.str_data then - if feat.value <= 0 then - feat.value = #feat.str_data - 1 - else - feat.value = feat.value - 1 - end - else - if tonumber(feat.value) <= feat.min and feat.type >> 2 & 1 == 0 then - feat.value = feat.max + local vercheckKeys = {ctrl = MenuKey(), space = MenuKey(), enter = MenuKey(), rshift = MenuKey()} + vercheckKeys.ctrl:push_vk(0x11); vercheckKeys.space:push_vk(0x20); vercheckKeys.enter:push_vk(0x0D); vercheckKeys.rshift:push_vk(0xA1) + + local responseCode, githubVer = web.get("https://raw.githubusercontent.com/GhustOne/CheeseMenu/main/VERSION.txt") + if responseCode == 200 then + githubVer = githubVer:gsub("[\r\n]", "") + if githubVer ~= version then + local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.5+0.5 + local strings = { + version_compare = "\nCurrent Version:"..version.."\nLatest Version:"..githubVer, + version_compare_x_offset = v2(-scriptdraw.get_text_size("\nCurrent Version:"..version.."\nLatest Version:"..githubVer, text_size).x/graphics.get_screen_width(), 0), + new_ver_x_offset = v2(-scriptdraw.get_text_size("New version available. Press CTRL or SPACE to skip or press ENTER or RIGHT SHIFT to update.", text_size).x/graphics.get_screen_width(), 0), + } + strings.changelog_rc, strings.changelog = web.get("https://raw.githubusercontent.com/GhustOne/CheeseMenu/main/CHANGELOG.txt") + if strings.changelog_rc == 200 then + strings.changelog = "\n\n\nChangelog:\n"..strings.changelog + else + strings.changelog = "" + end + strings.changelog_x_offset = v2(-scriptdraw.get_text_size(strings.changelog, text_size).x/graphics.get_screen_width(), 0) + local stringV2size = v2(2, 2) + while true do + scriptdraw.draw_text("New version available. Press CTRL or SPACE to skip or press ENTER or RIGHT SHIFT to update.", strings.new_ver_x_offset, stringV2size, text_size, 0xFF0CB4F4, 2) + scriptdraw.draw_text(strings.version_compare, strings.version_compare_x_offset, stringV2size, text_size, 0xFF0CB4F4, 2) + scriptdraw.draw_text(strings.changelog, strings.changelog_x_offset, stringV2size, text_size, 0xFF0CB4F4, 2) + if vercheckKeys.ctrl:is_down() or vercheckKeys.space:is_down() then + loadCurrentMenu() + break + elseif vercheckKeys.enter:is_down() or vercheckKeys.rshift:is_down() then + local responseCode, autoupdater = web.get([[https://raw.githubusercontent.com/GhustOne/CheeseMenu/main/CMAutoUpdater.lua]]) + if responseCode == 200 then + autoupdater = load(autoupdater) + menu.create_thread(function() + menu.notify("Update started, please wait...", "Cheese Menu") + local status = autoupdater() + if status then + if type(status) == "string" then + menu.notify("Updating local files failed, one or more of the files could not be opened.\nThere is a high chance the files got corrupted, please redownload the menu.", "Cheese Menu", 5, 0x0000FF) + else + menu.notify("Update successful", "Cheese Menu", 4, 0x00FF00) + dofile(utils.get_appdata_path("PopstarDevs", "2Take1Menu").."\\scripts\\cheesemenu.lua") + end else - feat.value = tonumber(feat.value) - feat.mod + menu.notify("Download for updated files failed, current files have not been replaced.", "Cheese Menu", 5, 0x0000FF) end - end - end - if feat.type then - if feat.type >> 10 & 1 ~= 0 or (feat.type & 3 == 3 and feat.on) then - feat:activate_feat_func() - end + end, nil) + break + else + menu.notify("Getting Updater failed. Check your connection and try downloading manually.", "Cheese Menu", 5, 0x0000FF) end end - end) + system.wait(0) + end + else + loadCurrentMenu() end end end, nil) - menu.create_thread(function() - while true do - if stuff.menuData.menuToggle and stuff.menuData.menuNav then - func.do_key(500, stuff.vkcontrols.right, true, function() -- right - local feat = currentMenu[stuff.scroll + stuff.scrollHiddenOffset] - if feat then - if feat.value then - if feat.str_data then - if tonumber(feat.value) >= tonumber(#feat.str_data) - 1 then - feat.value = 0 - else - feat.value = feat.value + 1 - end - else - if tonumber(feat.value) >= feat.max and feat.type >> 2 & 1 == 0 then - feat.value = feat.min - else - feat.value = tonumber(feat.value) + feat.mod - end - end - end - if feat.type then - if feat.type >> 10 & 1 ~= 0 or (feat.type & 3 == 3 and feat.on) then - feat:activate_feat_func() - end - end - end - end) +else + if menu.is_trusted_mode_enabled(1 << 2) then + httpTrustedOff = true + else + menu.notify("Trusted mode > Natives has to be on. If you wish for auto updates enable Http too.", "Cheese Menu", 5, 0x0000FF) + end +end + +local features +local currentMenu +local func +local stuff +local menu_configuration_features +function loadCurrentMenu() + features = {OnlinePlayers = {}} + currentMenu = features + func = {} + stuff = { + pid = -1, + player_info = { + {"Player ID", "0"}, + {"God", "false"}, + {"Proofs (God)", "false"}, + {"Vehicle God", "false"}, + {"Flagged as Modder", "false"}, + {"Host", "false"}, + {"Wanted", "0"}, + {"Health", "327/327"}, + {"Armor", "50"}, + {"IP", "0.0.0.0"}, + {"SCID", "133769420"}, + {"Host Token", "0xdeadbeef"}, + {"Host Priority", "0"}, + max_health = "/327", + name = "cheesemenu" + }, + proofs = { + bulletProof = native.ByteBuffer8(), + fireProof = native.ByteBuffer8(), + explosionProof = native.ByteBuffer8(), + collisionProof = native.ByteBuffer8(), + meleeProof = native.ByteBuffer8(), + steamProof = native.ByteBuffer8(), + p7 = native.ByteBuffer8(), + drownProof = native.ByteBuffer8(), + }, + scroll = 1, + scrollHiddenOffset = 0, + drawHiddenOffset = 0, + trusted_mode = 0, + old_selected = 0, + player_submenu_sort = 0, + previousMenus = {}, + threads = {}, + feature_by_id = {}, + player_feature_by_id = {}, + feature_hints = {}, + player_feature_hints = {}, + path = { + scripts = utils.get_appdata_path("PopstarDevs", "2Take1Menu").."\\scripts\\" + }, + hotkeys = {}, + hotkey_cooldowns = {}, + hotkeys_to_vk = {}, + table_sort_functions = { + [0] = function(a, b) return a.pid < b.pid end, + function(a, b) return a.pid > b.pid end, + function(a, b) return a.name:lower() < b.name:lower() end, + function(a, b) return a.name:lower() > b.name:lower() end, + function(a, b) return player.get_player_host_priority(a.pid) < player.get_player_host_priority(b.pid) end, + function(a, b) return player.get_player_host_priority(a.pid) > player.get_player_host_priority(b.pid) end + }, + char_codes = { + ["ENTER"] = 0x0D, + ["0"] = 0x30, + ["1"] = 0x31, + ["2"] = 0x32, + ["3"] = 0x33, + ["4"] = 0x34, + ["5"] = 0x35, + ["6"] = 0x36, + ["7"] = 0x37, + ["8"] = 0x38, + ["9"] = 0x39, + ["A"] = 0x41, + ["B"] = 0x42, + ["C"] = 0x43, + ["D"] = 0x44, + ["E"] = 0x45, + ["F"] = 0x46, + ["G"] = 0x47, + ["H"] = 0x48, + ["I"] = 0x49, + ["J"] = 0x4A, + ["K"] = 0x4B, + ["L"] = 0x4C, + ["M"] = 0x4D, + ["N"] = 0x4E, + ["O"] = 0x4F, + ["P"] = 0x50, + ["Q"] = 0x51, + ["R"] = 0x52, + ["S"] = 0x53, + ["T"] = 0x54, + ["U"] = 0x55, + ["V"] = 0x56, + ["W"] = 0x57, + ["X"] = 0x58, + ["Y"] = 0x59, + ["Z"] = 0x5A, + ["NUM0"] = 0x60, + ["NUM1"] = 0x61, + ["NUM2"] = 0x62, + ["NUM3"] = 0x63, + ["NUM4"] = 0x64, + ["NUM5"] = 0x65, + ["NUM6"] = 0x66, + ["NUM7"] = 0x67, + ["NUM8"] = 0x68, + ["NUM9"] = 0x69, + ["Space"] = 0x20, + [";"] = 0xBA, + ["PLUS"] = 0xBB, + [","] = 0xBC, + ["-"] = 0xBD, + ["DOT"] = 0xBE, + ["/"] = 0xBF, + ["`"] = 0xC0, + ["LSQREBRACKET"] = 0xDB, + ["\\"] = 0xDC, + ["RSQREBRACKET"] = 0xDD, + ["QUOTE"] = 0xDE, + ["NUM*"] = 0x6A, + ["NUMPLUS"] = 0x6B, + ["NUM-"] = 0x6D, + ["NUMDEL"] = 0x6E, + ["NUM/"] = 0x6F, + ["PAGEUP"] = 0x21, + ["PAGEDOWN"] = 0x22, + ["END"] = 0x23, + ["HOME"] = 0x24, + ["SCROLLLOCK"] = 0x91, + ["LEFTARROW"] = 0x25, + ["UPARROW"] = 0x26, + ["RIGHTARROW"] = 0x27, + ["DOWNARROW"] = 0x28, + ["SELECT"] = 0x29, + ["INS"] = 0x2D, + ["DEL"] = 0x2E, + ["PAUSE"] = 0x13, + ["CAPSLOCK"] = 0x14, + ["BACKSPACE"] = 0x08, + ["LSHIFT"] = 0xA0, + ["RSHIFT"] = 0xA1, + ["LCONTROL"] = 0xA2, + ["RCONTROL"] = 0xA3, + ["LALT"] = 0xA4, + ["RALT"] = 0xA5, + ["F1"] = 0x70, + ["F2"] = 0x71, + ["F3"] = 0x72, + ["F4"] = 0x73, + ["F5"] = 0x74, + ["F6"] = 0x75, + ["F7"] = 0x76, + ["F8"] = 0x77, + ["F9"] = 0x78, + ["F10"] = 0x79, + ["F11"] = 0x7A, + ["F12"] = 0x7B, + ["F13"] = 0x7C, + ["F14"] = 0x7D, + ["F15"] = 0x7E, + ["F16"] = 0x7F, + ["F17"] = 0x80, + ["F18"] = 0x81, + ["F19"] = 0x82, + ["F20"] = 0x83, + ["F21"] = 0x84, + ["F22"] = 0x85, + ["F23"] = 0x86, + ["F24"] = 0x87, + }, + hotkey_notifications = {toggle = true, action = false}, + controls = { + left = "LEFTARROW", + up = "UPARROW", + right = "RIGHTARROW", + down = "DOWNARROW", + select = "ENTER", + back = "BACKSPACE", + open = "F4", + setHotkey = "F11", + specialKey = "LCONTROL", + }, + vkcontrols = { + left = 0x25, + up = 0x26, + right = 0x27, + down = 0x28, + select = 0x0D, + back = 0x08, + open = 0x73, + setHotkey = 0x7A, + specialKey = 0xA2, + }, + drawScroll = 0, + maxDrawScroll = 0, + menuData = { + menuToggle = false, + menuNav = true, + chatBoxOpen = false, + pos_x = 0.5, + pos_y = 0.44652777777, + width = 0.2, + height = 0.305, + border = 0.0013888, + selector_speed = 1, + slider = { + width = 0.2, + height = 0.01, + heightActive = 0.025, + }, + footer = { + footer_y_offset = 0, + padding = 0.0078125, + footer_size = 0.019444444, + draw_footer = true, + footer_pos_related_to_background = false, + footer_text = "Made by GhostOne", + }, + fonts = { + text = 0, + footer = 0, + hint = 0 + }, + side_window = { + on = true, + offset = {x = 0, y = 0}, + spacing = 0.0547222, + width = 0.3, + padding = 0.01 + }, + header = "cheese_menu.png", + feature_offset = 0.025, + feature_scale = {x = 0.2, y = 0.025}, + padding = { + name = 0.003125, + parent = 0.003125, + value = 0.048125, + slider = 0.003125, + }, + text_size = (((graphics.get_screen_width()*graphics.get_screen_height())/3686400)*0.45+0.25), + text_size_modifier = 1, + footer_size_modifier = 1, + hint_size_modifier = 1, + text_y_offset = -0.0055555555, + color = {}, + files = {}, + background_sprite = { + sprite = nil, + size = 1, + loaded_sprites = {}, + offset = {x = 0, y = 0} + }, + max_features = 12, + set_max_features = function(self, int) + int = math.floor(int+0.5) + self.height = int * self.feature_offset + self.max_features = int end - system.wait(0) - end - end, nil) - - - --Hotkey thread - menu.create_thread(function() - while true do - if stuff.menuData.menuNav then - for k, v in pairs(stuff.hotkeys) do - local hotkey = cheeseUtils.get_key(table.unpack(stuff.hotkeys_to_vk[k])) - if hotkey:is_down() and (not (cheeseUtils.get_key(0x10):is_down() or cheeseUtils.get_key(0x11):is_down() or cheeseUtils.get_key(0x12):is_down()) or not (k:match("NOMOD"))) and utils.time_ms() > stuff.hotkey_cooldowns[k] then - for k, v in pairs(stuff.hotkeys[k]) do - if stuff.hotkey_feature_hierarchy_keys[k] then - for k, v in pairs(stuff.hotkey_feature_hierarchy_keys[k]) do - if v.type & 1 ~= 0 then - v.on = not v.on - if stuff.hotkey_notifications.toggle then - menu.notify("Turned "..v.name.." "..(v.on and "on" or "off"), "Cheese Menu", 3, func.convert_rgba_to_int(stuff.menuData.color.notifications.r, stuff.menuData.color.notifications.g, stuff.menuData.color.notifications.b, stuff.menuData.color.notifications.a)) - end - else - v:activate_feat_func() - if stuff.hotkey_notifications.action then - menu.notify("Activated "..v.name, "Cheese Menu", 3, func.convert_rgba_to_int(stuff.menuData.color.notifications.r, stuff.menuData.color.notifications.g, stuff.menuData.color.notifications.b, stuff.menuData.color.notifications.a)) - end - end - end - end - end - if stuff.hotkey_cooldowns[k] == 0 then - stuff.hotkey_cooldowns[k] = utils.time_ms() + 500 - else - stuff.hotkey_cooldowns[k] = utils.time_ms() + 100 - end - elseif not hotkey:is_down() then - stuff.hotkey_cooldowns[k] = 0 - end + }, + disable_all_controls = function() + while true do + for i = 0, 360 do + controls.disable_control_action(0, i, true) end + system.wait(0) end - system.wait(0) end - end, nil) - --End of threads - menu.notify("Kektram for teaching me lua & sharing neat functions\n\nRimuru for making the first separate ui that helped me in making cheese menu\n\nProddy for showing better ways to do things & sharing Script Manager", "Credits:", 12, 0x00ff00) - menu.notify("Controls can be found in\nScript Features > Cheese Menu > Controls", "CheeseMenu by GhostOne\n"..stuff.controls.open.." to open", 6, 0x00ff00) + } + + stuff.menuData.color = { + background = {r = 0, g = 0, b = 0, a = 0}, + sprite = 0xE6FFFFFF, + slider_active = {r = 255, g = 200, b = 0, a = 255}, + slider_background = {r = 0, g = 0, b = 0, a = 160}, + slider_text = {r = 0, g = 0, b = 0, a = 255}, + slider_selectedActive = {r = 255, g = 255, b = 255, a = 160}, + slider_selectedBackground = {r = 255, g = 160, b = 0, a = 180}, + feature_bottomLeft = {r = 255, g = 160, b = 0, a = 170}, + feature_topLeft = {r = 255, g = 160, b = 0, a = 170}, + feature_topRight = {r = 255, g = 160, b = 0, a = 170}, + feature_bottomRight = {r = 255, g = 160, b = 0, a = 170}, + feature_selected_bottomLeft = {r = 0, g = 0, b = 0, a = 200}, + feature_selected_topLeft = {r = 0, g = 0, b = 0, a = 200}, + feature_selected_topRight = {r = 0, g = 0, b = 0, a = 200}, + feature_selected_bottomRight = {r = 0, g = 0, b = 0, a = 200}, + text_selected = {r = 255, g = 200, b = 0, a = 180}, + text = {r = 0, g = 0, b = 0, a = 180}, + border = {r = 0, g = 0, b = 0, a = 180}, + footer = {r = 255, g = 160, b = 0, a = 170}, + footer_text = {r = 0, g = 0, b = 0, a = 180}, + notifications = {r = 255, g = 200, b = 0, a = 255}, + side_window = {r = 0, g = 0, b = 0, a = 150}, + side_window_text = {r = 255, g = 255, b = 255, a = 220} + } - menu_configuration_features = {} - menu_configuration_features.cheesemenuparent = menu.add_feature("Cheese Menu", "parent") + stuff.path.cheesemenu = stuff.path.scripts.."cheesemenu\\" + for k, v in pairs(utils.get_all_sub_directories_in_directory(stuff.path.cheesemenu)) do + stuff.path[v] = stuff.path.cheesemenu..v.."\\" + end - menu.add_feature("Save Settings", "action", menu_configuration_features.cheesemenuparent.id, function() - func.save_settings() - menu.notify("Settings Saved Successfully", "Cheese Menu", 6, 0x00ff00) - end) + stuff.menuData.background_sprite.fit_size_to_width = function(self) + self.size = stuff.menuData.width*graphics.get_screen_width()/scriptdraw.get_sprite_size(func.load_sprite(stuff.path.background..(self.sprite or ""), stuff.menuData.background_sprite.loaded_sprites)).x + end + stuff.menuData.background_sprite.fit_size_to_height = function(self) + self.size = stuff.menuData.height*graphics.get_screen_height()/scriptdraw.get_sprite_size(func.load_sprite(stuff.path.background..(self.sprite or ""), stuff.menuData.background_sprite.loaded_sprites)).y + end - menu.add_feature("Save UI", "action", menu_configuration_features.cheesemenuparent.id, function() - local status, name = input.get("name of ui", "", 25, 0) - if status == 0 then - func.save_ui(name) - menu.notify("UI Saved Successfully", "Cheese Menu", 6, 0x00ff00) - for _, v in pairs(stuff.menuData.files.ui) do - if v == name then - return - end - end - stuff.menuData.files.ui[#stuff.menuData.files.ui+1] = name - menu_configuration_features.load_ui:set_str_data(stuff.menuData.files.ui) + stuff.image_ext = {"gif", "bmp", "jpg", "jpeg", "png", "2t1", "dds"} + stuff.menuData.files.headers = {} + for _, ext in pairs(stuff.image_ext) do + for _, image in pairs(utils.get_all_files_in_directory(stuff.path.header, ext)) do + stuff.menuData.files.headers[#stuff.menuData.files.headers + 1] = image end - end) + end + for k, v in pairs(utils.get_all_sub_directories_in_directory(stuff.path.header)) do + stuff.menuData.files.headers[#stuff.menuData.files.headers + 1] = v..".ogif" + end - menu_configuration_features.load_ui = menu.add_feature("Load UI", "action_value_str", menu_configuration_features.cheesemenuparent.id, function(f) - func.load_ui(f.str_data[f.value + 1]) - end) - menu_configuration_features.load_ui:set_str_data(stuff.menuData.files.ui) + stuff.menuData.files.ui = {} + for k, v in pairs(utils.get_all_files_in_directory(stuff.path.ui, "lua")) do + stuff.menuData.files.ui[k] = v:sub(1, #v - 4) + end - menu_configuration_features.menuXfeat = menu.add_feature("Menu pos X", "autoaction_value_i", menu_configuration_features.cheesemenuparent.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - stuff.menuData.pos_x = num/graphics.get_screen_height() - f.value = num - end + stuff.menuData.files.background = {} + for _, ext in pairs(stuff.image_ext) do + for k, v in pairs(utils.get_all_files_in_directory(stuff.path.background, "png")) do + stuff.menuData.files.background[k] = v end - stuff.menuData.pos_x = f.value/graphics.get_screen_width() - end) - menu_configuration_features.menuXfeat.max = graphics.get_screen_width() - menu_configuration_features.menuXfeat.mod = 1 - menu_configuration_features.menuXfeat.min = -graphics.get_screen_width() - menu_configuration_features.menuXfeat.value = math.floor(stuff.menuData.pos_x*graphics.get_screen_width()) + end - menu_configuration_features.menuYfeat = menu.add_feature("Menu pos Y", "autoaction_value_i", menu_configuration_features.cheesemenuparent.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - stuff.menuData.pos_y = num/graphics.get_screen_height() - f.value = num + stuff.menuData_methods = { + set_color = function(self, colorName, r, g, b, a) + assert(self[colorName], "field "..colorName.." does not exist") + local colors = {r = r or false, g = g or false, b = b or false, a = a or false} + for k, v in pairs(colors) do + if not v then + if type(self[colorName]) == "table" then + colors[k] = self[colorName][k] + else + colors[k] = func.convert_int_to_rgba(self[colorName], k) + end + end + end + for k, v in pairs(colors) do + assert(v <= 255 and v >= 0, "attempted to set invalid "..k.." value to field "..colorName) + end + if type(self[colorName]) == "table" then + self[colorName] = colors + else + self[colorName] = (colors.a << 24) + (colors.b << 16) + (colors.g << 8) + colors.r end end - stuff.menuData.pos_y = f.value/graphics.get_screen_height() - end) - menu_configuration_features.menuYfeat.max = graphics.get_screen_height() - menu_configuration_features.menuYfeat.mod = 1 - menu_configuration_features.menuYfeat.min = -graphics.get_screen_height() - menu_configuration_features.menuYfeat.value = math.floor(stuff.menuData.pos_y*graphics.get_screen_height()) - - menu_configuration_features.headerfeat = menu.add_feature("Header", "autoaction_value_str", menu_configuration_features.cheesemenuparent.id, function(f) - if f.str_data[f.value + 1] == "NONE" then - stuff.menuData.header = nil - else - stuff.menuData.header = f.str_data[f.value + 1] + } + function func.convert_rgba_to_int(r, g, b, a) + if type(r) == "table" then + local colorTable = r + r = colorTable.r or colorTable[1] + g = colorTable.g or colorTable[2] + b = colorTable.b or colorTable[3] + a = colorTable.a or colorTable[4] end - end) - menu_configuration_features.headerfeat:set_str_data({"NONE", table.unpack(stuff.menuData.files.headers)}) - - menu_configuration_features.layoutParent = menu.add_feature("Layout", "parent", menu_configuration_features.cheesemenuparent.id) - - menu_configuration_features.maxfeats = menu.add_feature("Max features", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) - stuff.menuData:set_max_features(f.value) - end) - menu_configuration_features.maxfeats.max = 50 - menu_configuration_features.maxfeats.mod = 1 - menu_configuration_features.maxfeats.min = 1 - menu_configuration_features.maxfeats.value = math.floor(stuff.menuData.max_features) - - menu_configuration_features.menuWidth = menu.add_feature("Menu width", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) - stuff.menuData.width = f.value/graphics.get_screen_width() - end) - menu_configuration_features.menuWidth.max = graphics.get_screen_width() - menu_configuration_features.menuWidth.mod = 1 - menu_configuration_features.menuWidth.min = -graphics.get_screen_width() - menu_configuration_features.menuWidth.value = math.floor(stuff.menuData.width*graphics.get_screen_width()) - - menu_configuration_features.featXfeat = menu.add_feature("Feature dimensions X", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) - stuff.menuData.feature_scale.x = f.value/graphics.get_screen_width() - end) - menu_configuration_features.featXfeat.max = graphics.get_screen_width() - menu_configuration_features.featXfeat.mod = 1 - menu_configuration_features.featXfeat.min = -graphics.get_screen_width() - menu_configuration_features.featXfeat.value = math.floor(stuff.menuData.feature_scale.x*graphics.get_screen_width()) - - menu_configuration_features.featYfeat = menu.add_feature("Feature dimensions Y", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) - stuff.menuData.feature_scale.y = f.value/graphics.get_screen_height() - end) - menu_configuration_features.featYfeat.max = graphics.get_screen_height() - menu_configuration_features.featYfeat.mod = 1 - menu_configuration_features.featYfeat.min = -graphics.get_screen_height() - menu_configuration_features.featYfeat.value = math.floor(stuff.menuData.feature_scale.y*graphics.get_screen_height()) - - menu_configuration_features.feature_offset = menu.add_feature("Feature spacing", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) - stuff.menuData.feature_offset = f.value/graphics.get_screen_height() - menu_configuration_features.maxfeats:toggle() - end) - menu_configuration_features.feature_offset.max = graphics.get_screen_height() - menu_configuration_features.feature_offset.mod = 1 - menu_configuration_features.feature_offset.min = -graphics.get_screen_height() - menu_configuration_features.feature_offset.value = math.floor(stuff.menuData.feature_offset*graphics.get_screen_height()) - - menu_configuration_features.text_size = menu.add_feature("Text Size", "autoaction_value_f", menu_configuration_features.layoutParent.id, function(f) - stuff.menuData.text_size_modifier = f.value - end) - menu_configuration_features.text_size.max = 5 - menu_configuration_features.text_size.mod = 0.01 - menu_configuration_features.text_size.min = 0.1 - menu_configuration_features.text_size.value = stuff.menuData.text_size_modifier - - menu_configuration_features.footer_size = menu.add_feature("Footer Text Size", "autoaction_value_f", menu_configuration_features.layoutParent.id, function(f) - stuff.menuData.footer_size_modifier = f.value - end) - menu_configuration_features.footer_size.max = 5 - menu_configuration_features.footer_size.mod = 0.01 - menu_configuration_features.footer_size.min = 0.1 - menu_configuration_features.footer_size.value = stuff.menuData.footer_size_modifier - - menu_configuration_features.hint_size = menu.add_feature("Hint Text Size", "autoaction_value_f", menu_configuration_features.layoutParent.id, function(f) - stuff.menuData.hint_size_modifier = f.value - func.rewrap_hints(stuff.menuData.fonts.hint) - end) - menu_configuration_features.hint_size.max = 5 - menu_configuration_features.hint_size.mod = 0.01 - menu_configuration_features.hint_size.min = 0.1 - menu_configuration_features.hint_size.value = stuff.menuData.hint_size_modifier - - menu_configuration_features.text_y_offset = menu.add_feature("Text Y Offset", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) - stuff.drawFeatParams.textOffset.y = -(f.value/graphics.get_screen_height()) - stuff.menuData.text_y_offset = -(f.value/graphics.get_screen_height()) - end) - menu_configuration_features.text_y_offset.max = 100 - menu_configuration_features.text_y_offset.mod = 1 - menu_configuration_features.text_y_offset.min = -100 - menu_configuration_features.text_y_offset.value = -math.floor(stuff.menuData.text_y_offset*graphics.get_screen_height()) - - menu_configuration_features.border = menu.add_feature("Border", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) - stuff.menuData.border = f.value/graphics.get_screen_height() - end) - menu_configuration_features.border.max = graphics.get_screen_height() - menu_configuration_features.border.mod = 1 - menu_configuration_features.border.min = -graphics.get_screen_height() - menu_configuration_features.border.value = math.floor(stuff.menuData.border*graphics.get_screen_height()) - - menu_configuration_features.selector_speed = menu.add_feature("Selector Speed", "autoaction_value_f", menu_configuration_features.layoutParent.id, function(f) - stuff.menuData.selector_speed = f.value - end) - menu_configuration_features.selector_speed.max = 10 - menu_configuration_features.selector_speed.mod = 0.1 - menu_configuration_features.selector_speed.min = 0.2 - menu_configuration_features.selector_speed.value = stuff.menuData.selector_speed - - -- Online Player Submenu Sorting - menu_configuration_features.player_submenu_sort = menu.add_feature("Online Players Sort:", "autoaction_value_str", menu_configuration_features.layoutParent.id, function(f) - table.sort(stuff.PlayerParent, stuff.table_sort_functions[f.value]) - stuff.player_submenu_sort = f.value - end) - menu_configuration_features.player_submenu_sort:set_str_data({'PID', 'PID Reversed', 'Alphabetically', 'Alphabetically Reversed', 'Host Priority', 'Host Priority Reversed'}) - menu_configuration_features.player_submenu_sort.value = stuff.player_submenu_sort - - -- Padding - menu_configuration_features.padding_parent = menu.add_feature("Padding", "parent", menu_configuration_features.layoutParent.id) + if not a then + a = 255 + end + assert(r and g and b, "one or more of the r, g, b values is invalid") + assert((a <= 255 and a >= 0) and (b <= 255 and b >= 0) and (g <= 255 and g >= 0) and (r <= 255 and r >= 0), "rgba values cannot be more than 255 or less than 0") + return (a << 24) + (b << 16) + (g << 8) + r + end - menu_configuration_features.namePadding = menu.add_feature("Name Padding", "autoaction_value_i", menu_configuration_features.padding_parent.id, function(f) - stuff.menuData.padding.name = f.value/graphics.get_screen_width() - end) - menu_configuration_features.namePadding.max = graphics.get_screen_width() - menu_configuration_features.namePadding.mod = 1 - menu_configuration_features.namePadding.min = -graphics.get_screen_width() - menu_configuration_features.namePadding.value = math.floor(stuff.menuData.padding.name*graphics.get_screen_width()) + stuff.conversionValues = {a = 24, b = 16, g = 8, r = 0} + function func.convert_int_to_rgba(...) + local int, val1, val2, val3, val4 = ... + local values = {val1, val2, val3, val4} - menu_configuration_features.parentPadding = menu.add_feature("Parent Padding", "autoaction_value_i", menu_configuration_features.padding_parent.id, function(f) - stuff.menuData.padding.parent = f.value/graphics.get_screen_width() - end) - menu_configuration_features.parentPadding.max = graphics.get_screen_width() - menu_configuration_features.parentPadding.mod = 1 - menu_configuration_features.parentPadding.min = -graphics.get_screen_width() - menu_configuration_features.parentPadding.value = math.floor(stuff.menuData.padding.parent*graphics.get_screen_width()) + for k, v in pairs(values) do + values[k] = int >> stuff.conversionValues[v] & 0xff + end + return table.unpack(values) + end + setmetatable(stuff.menuData.color, {__index = stuff.menuData_methods}) - menu_configuration_features.valuePadding = menu.add_feature("Value Padding", "autoaction_value_i", menu_configuration_features.padding_parent.id, function(f) - stuff.menuData.padding.value = f.value/graphics.get_screen_width() - end) - menu_configuration_features.valuePadding.max = graphics.get_screen_width() - menu_configuration_features.valuePadding.mod = 1 - menu_configuration_features.valuePadding.min = -graphics.get_screen_width() - menu_configuration_features.valuePadding.value = math.floor(stuff.menuData.padding.value*graphics.get_screen_width()) + function func.convert_int_ip(ip) + local ipTable = {} + ipTable[1] = ip >> 24 & 255 + ipTable[2] = ip >> 16 & 255 + ipTable[3] = ip >> 8 & 255 + ipTable[4] = ip & 255 - menu_configuration_features.sliderPadding = menu.add_feature("Slider Padding", "autoaction_value_i", menu_configuration_features.padding_parent.id, function(f) - stuff.menuData.padding.slider = f.value/graphics.get_screen_width() - end) - menu_configuration_features.sliderPadding.max = graphics.get_screen_width() - menu_configuration_features.sliderPadding.mod = 1 - menu_configuration_features.sliderPadding.min = -graphics.get_screen_width() - menu_configuration_features.sliderPadding.value = math.floor(stuff.menuData.padding.slider*graphics.get_screen_width()) + return table.concat(ipTable, ".") + end - -- Slider dimensions - menu_configuration_features.slider_parent = menu.add_feature("Slider", "parent", menu_configuration_features.layoutParent.id) + stuff.input = require("cheesemenu.libs.Get Input") + local gltw = require("cheesemenu.libs.GLTW") + local cheeseUtils = require("cheesemenu.libs.CheeseUtilities") + assert(gltw, "GLTW library is not found, please install the menu with 'cheesemenu' folder.") - menu_configuration_features.sliderWidth = menu.add_feature("Slider Width", "autoaction_value_i", menu_configuration_features.slider_parent.id, function(f) - stuff.menuData.slider.width = f.value/graphics.get_screen_width() - end) - menu_configuration_features.sliderWidth.max = graphics.get_screen_width() - menu_configuration_features.sliderWidth.mod = 1 - menu_configuration_features.sliderWidth.min = -graphics.get_screen_width() - menu_configuration_features.sliderWidth.value = math.floor(stuff.menuData.slider.width*graphics.get_screen_width()) - menu_configuration_features.sliderHeight = menu.add_feature("Slider Height", "autoaction_value_i", menu_configuration_features.slider_parent.id, function(f) - stuff.menuData.slider.height = f.value/graphics.get_screen_height() - end) - menu_configuration_features.sliderHeight.max = graphics.get_screen_height() - menu_configuration_features.sliderHeight.mod = 1 - menu_configuration_features.sliderHeight.min = -graphics.get_screen_height() - menu_configuration_features.sliderHeight.value = math.floor(stuff.menuData.slider.height*graphics.get_screen_height()) + gltw.read("controls", stuff.path.cheesemenu, stuff.controls, false, true) + for k, v in pairs(stuff.controls) do + stuff.vkcontrols[k] = stuff.char_codes[v] + end - menu_configuration_features.sliderheightActive = menu.add_feature("Slider Height Active", "autoaction_value_i", menu_configuration_features.slider_parent.id, function(f) - stuff.menuData.slider.heightActive = f.value/graphics.get_screen_height() - end) - menu_configuration_features.sliderheightActive.max = graphics.get_screen_height() - menu_configuration_features.sliderheightActive.mod = 1 - menu_configuration_features.sliderheightActive.min = -graphics.get_screen_height() - menu_configuration_features.sliderheightActive.value = math.floor(stuff.menuData.slider.heightActive*graphics.get_screen_height()) + gltw.read("hotkey notifications", stuff.path.hotkeys, stuff.hotkey_notifications, false, true) + stuff.hotkeys = gltw.read("hotkeys", stuff.path.hotkeys, nil, false, true) or {} + stuff.hierarchy_key_to_hotkey = {} + for k, v in pairs(stuff.hotkeys) do + stuff.hotkey_cooldowns[k] = 0 - -- Controls - menu_configuration_features.controls = menu.add_feature("Controls", "parent", menu_configuration_features.cheesemenuparent.id) + local string_to_vk = {} + for char in k:gmatch("%|*([^%|]+)%|*") do + string_to_vk[#string_to_vk+1] = stuff.char_codes[char] + end + stuff.hotkeys_to_vk[k] = string_to_vk - for k, v in pairs(stuff.controls) do - menu.add_feature(k, "action_value_str", menu_configuration_features.controls.id, function(f) - for k, v in pairs(stuff.char_codes) do - while cheeseUtils.get_key(v):is_down() do - system.wait(0) - end - end - menu.notify("Press any button\nESC to cancel", "Cheese Menu", 3, func.convert_rgba_to_int(stuff.menuData.color.notifications.r, stuff.menuData.color.notifications.g, stuff.menuData.color.notifications.b, stuff.menuData.color.notifications.a)) - local disablethread = menu.create_thread(stuff.disable_all_controls, nil) - local stringkey, vk = func.get_hotkey({}, {}, true) - if stringkey ~= "escaped" then - stuff.controls[k] = stringkey - stuff.vkcontrols[k] = vk - f:set_str_data({stringkey}) - end - menu.delete_thread(disablethread) - end):set_str_data({v}) + if type(v) == "table" then + for i, e in pairs(v) do + stuff.hierarchy_key_to_hotkey[i] = k end + end + end - -- Player Info - menu_configuration_features.side_window = menu.add_feature("Player Info Window", "parent", menu_configuration_features.cheesemenuparent.id) + --local originalGetInput = input.get + if stuff.input then + function input.get(title, default, len, Type) + local originalmenuToggle = stuff.menuData.menuToggle + stuff.menuData.menuToggle = false + stuff.menuData.chatBoxOpen = true + local status, gottenInput = stuff.input.get_input(title, default, len, Type) - -- On - menu_configuration_features.side_window_on = menu.add_feature("Draw", "toggle", menu_configuration_features.side_window.id, function(f) - stuff.menuData.side_window.on = f.on - end) - menu_configuration_features.side_window_on.on = stuff.menuData.side_window.on + func.toggle_menu(originalmenuToggle) + stuff.menuData.chatBoxOpen = false + return status, gottenInput + end + end - -- Offset - menu_configuration_features.side_window_offsetx = menu.add_feature("X Offset", "autoaction_value_i", menu_configuration_features.side_window.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - stuff.menuData.side_window.offset.x = num/graphics.get_screen_height() - f.value = num - end + -- Credit to kektram for these functions + do + local _ENV = { + getmetatable = debug.getmetatable + } + function stuff.rawset(Table, index, value) -- Matches performance of normal rawset. + local metatable = getmetatable(Table) + local __newindex + if metatable then + __newindex = metatable.__newindex + metatable.__newindex = nil end - stuff.menuData.side_window.offset.x = f.value/graphics.get_screen_width() - end) - menu_configuration_features.side_window_offsetx.max = graphics.get_screen_width() - menu_configuration_features.side_window_offsetx.mod = 1 - menu_configuration_features.side_window_offsetx.min = -graphics.get_screen_width() - menu_configuration_features.side_window_offsetx.value = math.floor(stuff.menuData.side_window.offset.x*graphics.get_screen_width()) - - menu_configuration_features.side_window_offsety = menu.add_feature("Y Offset", "autoaction_value_i", menu_configuration_features.side_window.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - stuff.menuData.side_window.offset.y = num/graphics.get_screen_height() - f.value = num - end + Table[index] = value + if __newindex then + metatable.__newindex = __newindex end - stuff.menuData.side_window.offset.y = f.value/graphics.get_screen_height() - end) - menu_configuration_features.side_window_offsety.max = graphics.get_screen_height() - menu_configuration_features.side_window_offsety.mod = 1 - menu_configuration_features.side_window_offsety.min = -graphics.get_screen_height() - menu_configuration_features.side_window_offsety.value = math.floor(stuff.menuData.side_window.offset.y*graphics.get_screen_height()) - - -- Spacing - menu_configuration_features.side_window_spacing = menu.add_feature("Spacing", "autoaction_value_i", menu_configuration_features.side_window.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - stuff.menuData.side_window.spacing = num/graphics.get_screen_height() - f.value = num - end + return Table + end + end + do + local _ENV = { + getmetatable = debug.getmetatable + } + function stuff.rawget(Table, index, value) -- Matches performance of normal rawget. + local metatable = getmetatable(Table) + local __index + if metatable then + __index = metatable.__index + metatable.__index = nil end - stuff.menuData.side_window.spacing = f.value/graphics.get_screen_height() - end) - menu_configuration_features.side_window_spacing.max = graphics.get_screen_height() - menu_configuration_features.side_window_spacing.mod = 1 - menu_configuration_features.side_window_spacing.min = -graphics.get_screen_height() - menu_configuration_features.side_window_spacing.value = math.floor(stuff.menuData.side_window.spacing*graphics.get_screen_height()) - - -- Padding - menu_configuration_features.side_window_padding = menu.add_feature("Padding", "autoaction_value_i", menu_configuration_features.side_window.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - stuff.menuData.side_window.padding = num/graphics.get_screen_height() - f.value = num - end + local value = Table[index] + if __index then + metatable.__index = __index end - stuff.menuData.side_window.padding = f.value/graphics.get_screen_width() - end) - menu_configuration_features.side_window_padding.max = graphics.get_screen_width() - menu_configuration_features.side_window_padding.mod = 1 - menu_configuration_features.side_window_padding.min = -graphics.get_screen_width() - menu_configuration_features.side_window_padding.value = math.floor(stuff.menuData.side_window.padding*graphics.get_screen_width()) + return value + end + end + -- - -- Width - menu_configuration_features.side_window_width = menu.add_feature("Width", "autoaction_value_i", menu_configuration_features.side_window.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - stuff.menuData.side_window.width = num/graphics.get_screen_height() - f.value = num + stuff.playerSpecialValues = {value = true, min = true, max = true, mod = true, on = true, real_value = true, real_max = true, real_min = true, real_mod = true, real_on = true} + + stuff.featMetaTable = { + __index = function(t, k) + if k == "is_highlighted" then + return t == currentMenu[stuff.scroll + stuff.scrollHiddenOffset] + elseif k == "parent" then + return t.type >> 15 & 1 == 0 and func.get_feature(t.parent_id) or func.get_player_feature(t.parent_id) + elseif k == "value" or k == "min" or k == "mod" or k == "max" or k == "str_data" or k == "type" or k == "id" or k == "on" or k == "hidden" or k == "data" then + if t.playerFeat and k ~= "str_data" and k ~= "type" and k ~= "id" and k ~= "hidden" and k ~= "data" then + return stuff.rawget(t, "table_"..k) + else + return stuff.rawget(t, "real_"..k) end + elseif k == "children" and t.type >> 11 & 1 ~= 0 then + return t:get_children() + elseif k == "hint" then + local hintTable = t.type >> 15 & 1 ~= 0 and stuff.player_feature_hints or stuff.feature_hints + return hintTable[t.id].str + --[[ else + return stuff.rawget(t, k) ]] end - stuff.menuData.side_window.width = f.value/graphics.get_screen_width() - end) - menu_configuration_features.side_window_width.max = graphics.get_screen_width() - menu_configuration_features.side_window_width.mod = 1 - menu_configuration_features.side_window_width.min = -graphics.get_screen_width() - menu_configuration_features.side_window_width.value = math.floor(stuff.menuData.side_window.width*graphics.get_screen_width()) - - -- End of Player Info - + end, - -- Background - menu_configuration_features.backgroundparent = menu.add_feature("Background", "parent", menu_configuration_features.cheesemenuparent.id) + __newindex = function(t, k, v) + assert(k ~= "id" and k ~= "children" and k ~= "type" and k ~= "str_data" and k ~= "is_highlighted", "'"..k.."' is read only") + if k == "on" and type(v) == "boolean" then + if t.real_on == v then + return + end + --[[ if t.type >> 11 & 1 ~= 0 and t.real_on ~= nil then + func.check_scroll(t.index, (t.parent_id > 0 and t.parent or features), not v) + end ]] + stuff.rawset(t, "real_on", v) - menu_configuration_features.backgroundfeat = menu.add_feature("Background", "autoaction_value_str", menu_configuration_features.backgroundparent.id, function(f) - if f.str_data[f.value + 1] == "NONE" then - stuff.menuData.background_sprite.sprite = nil + if t.feats then + for pid, feat in pairs(t.feats) do + if player.is_player_valid(pid) then + feat.on = v + --[[ if feat.type >> 11 & 1 ~= 0 then + func.check_scroll(feat.index, (feat.parent_id > 0 and stuff.feature_by_id[feat.ps_parent_id] or stuff.PlayerParent), not v) + end ]] + end + end else - stuff.menuData.background_sprite.sprite = f.str_data[f.value + 1] + if v then + t:activate_feat_func() + end end - end) - menu_configuration_features.backgroundfeat:set_str_data({"NONE", table.unpack(stuff.menuData.files.background)}) - - menu.add_feature("Fit background to width", "action", menu_configuration_features.backgroundparent.id, function() - if stuff.menuData.background_sprite.sprite then - stuff.menuData.background_sprite:fit_size_to_width() + elseif k == "value" or k == "min" or k == "mod" or k == "max" then + if k ~= "value" and t.type >> 5 & 1 ~= 0 then -- value_str + error("max, min and mod are readonly for value_str features") end - end) + v = tonumber(v) - menu_configuration_features.backgroundoffsetx = menu.add_feature("Background pos X", "autoaction_value_i", menu_configuration_features.backgroundparent.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - stuff.menuData.background_sprite.offset.x = num/graphics.get_screen_width() - f.value = num + assert(t.type >> 1 & 1 ~= 0, "feat type not supported: "..t.type) -- value_[if], value_str + assert(v, "tried to set "..k.." property to a non-number value") + + if t.type >> 5 & 1 ~= 0 then -- value_str + if v < 0 then + v = 0 + elseif t.real_str_data then + if v+1 > #t.real_str_data and #t.real_str_data ~= 0 then + v = #t.real_str_data-1 + end end end - stuff.menuData.background_sprite.offset.x = f.value/graphics.get_screen_width() - end) - menu_configuration_features.backgroundoffsetx.max = graphics.get_screen_width() - menu_configuration_features.backgroundoffsetx.mod = 1 - menu_configuration_features.backgroundoffsetx.min = -graphics.get_screen_width() - menu_configuration_features.backgroundoffsetx.value = math.floor(stuff.menuData.background_sprite.offset.x*graphics.get_screen_width()) - menu_configuration_features.backgroundoffsety = menu.add_feature("Background pos Y", "autoaction_value_i", menu_configuration_features.backgroundparent.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - stuff.menuData.background_sprite.offset.y = num/graphics.get_screen_height() - f.value = num + if t.type >> 1 & 1 ~= 0 then + if t.type >> 3 & 1 ~= 0 or t.type >> 5 & 1 ~= 0 then -- value_str + v = math.floor(v) end - end - stuff.menuData.background_sprite.offset.y = f.value/graphics.get_screen_height() - end) - menu_configuration_features.backgroundoffsety.max = graphics.get_screen_height() - menu_configuration_features.backgroundoffsety.mod = 1 - menu_configuration_features.backgroundoffsety.min = -graphics.get_screen_height() - menu_configuration_features.backgroundoffsety.value = math.floor(stuff.menuData.background_sprite.offset.y*graphics.get_screen_height()) - menu_configuration_features.backgroundsize = menu.add_feature("Background Size", "autoaction_value_f", menu_configuration_features.backgroundparent.id, function(f) - stuff.menuData.background_sprite.size = f.value - end) - menu_configuration_features.backgroundsize.max = 1 - menu_configuration_features.backgroundsize.mod = 0.01 - menu_configuration_features.backgroundsize.value = stuff.menuData.background_sprite.size + stuff.rawset(t, "real_"..k, v) + if t.type & 140 ~= 0 then -- i|f|slider + if not t.real_max then + t.real_max = 0 + end + if not t.real_min then + t.real_min = 0 + end + if not t.real_mod then + t.real_mod = 1 + end + if not t.real_value then + t.real_value = 0 + end - -- Footer - menu_configuration_features.footer = menu.add_feature("Footer", "parent", menu_configuration_features.cheesemenuparent.id) + stuff.rawset(t, "real_value", t.real_value >= t.real_max and t.real_max or t.real_value <= t.real_min and t.real_min or t.real_value) + end - menu_configuration_features.footer_size = menu.add_feature("Footer Size", "autoaction_value_i", menu_configuration_features.footer.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - stuff.menuData.footer.footer_size = num/graphics.get_screen_height() - f.value = num + if t["table_"..k] then + local is_num = t.type & 140 ~= 0 + for i = 0, 31 do + t["table_"..k][i] = v + if is_num then + t["table_value"][i] = t["table_value"][i] >= t["table_max"][i] and t["table_max"][i] or t["table_value"][i] <= t["table_min"][i] and t["table_min"][i] or t["table_value"][i] + end + end end end - stuff.menuData.footer.footer_size = f.value/graphics.get_screen_height() - end) - menu_configuration_features.footer_size.max = graphics.get_screen_height() - menu_configuration_features.footer_size.mod = 1 - menu_configuration_features.footer_size.min = 0 - menu_configuration_features.footer_size.value = math.floor(stuff.menuData.footer.footer_size*graphics.get_screen_height()) + elseif k == "hidden" then + assert(type(v) == "boolean", "hidden only accepts booleans") + if t.real_hidden == v then + return + end - menu_configuration_features.footer_y_offset = menu.add_feature("Footer Y Offset", "autoaction_value_i", menu_configuration_features.footer.id, function(f) - stuff.menuData.footer.footer_y_offset = (f.value/graphics.get_screen_height()) - end) - menu_configuration_features.footer_y_offset.max = 100 - menu_configuration_features.footer_y_offset.mod = 1 - menu_configuration_features.footer_y_offset.min = -100 - menu_configuration_features.footer_y_offset.value = math.floor(stuff.menuData.footer.footer_y_offset*graphics.get_screen_height()) + --[[ if t.real_hidden ~= nil then + func.check_scroll(t.index, (t.parent_id > 0 and t.parent or features), v) + end ]] - menu_configuration_features.footerPadding = menu.add_feature("Padding", "autoaction_value_i", menu_configuration_features.footer.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - stuff.menuData.footer.padding = num/graphics.get_screen_width() - f.value = num + t.real_hidden = v + if t.feats then + for _, feat in ipairs(t.feats) do + feat.hidden = v end end - stuff.menuData.footer.padding = f.value/graphics.get_screen_width() - end) - menu_configuration_features.footerPadding.max = graphics.get_screen_width() - menu_configuration_features.footerPadding.mod = 1 - menu_configuration_features.footerPadding.min = -graphics.get_screen_width() - menu_configuration_features.footerPadding.value = math.floor(stuff.menuData.footer.padding*graphics.get_screen_width()) + if v then + func.deleted_or_hidden_parent_check(t) + end + elseif k == "data" then + stuff.rawset(t, "real_data", v) + if t.feats then + for i, e in pairs(t.feats) do + t.feats[i].real_data = v + end + end + elseif k == "hint" then + local hintTable = t.type >> 15 & 1 ~= 0 and stuff.player_feature_hints or stuff.feature_hints + if not v then + hintTable[t.id] = nil + return + end + assert(type(v) == "string", "Feat.hint only supports strings") + local str = cheeseUtils.wrap_text(v, stuff.menuData.fonts.hint, stuff.menuData.text_size * stuff.menuData.hint_size_modifier, stuff.menuData.width*2-scriptdraw.size_pixel_to_rel_x(25)) + hintTable[t.id] = {str = str, size = scriptdraw.get_text_size(str, 1, stuff.menuData.fonts.hint), original = v} + else + stuff.rawset(t, k, v) + end + end + } - menu_configuration_features.draw_footer = menu.add_feature("Draw footer", "toggle", menu_configuration_features.footer.id, function(f) - stuff.menuData.footer.draw_footer = f.on - end) - menu_configuration_features.draw_footer.on = stuff.menuData.footer.draw_footer + stuff.playerfeatMetaTable = { + __index = function(t, k) + if k == "is_highlighted" then + return t == currentMenu[stuff.scroll + stuff.scrollHiddenOffset] + elseif k == "parent" then + return func.get_player_feature(t.parent_id) + elseif k == "str_data" or k == "type" or k == "id" or k == "data" or k == "hidden" then + return stuff.rawget(t, "real_"..k) + elseif stuff.playerSpecialValues[k] then + if t["table_"..k:gsub("real_", "")] then + return t["table_"..k:gsub("real_", "")][t.pid] + end + elseif k == "children" and t.type >> 11 & 1 ~= 0 then + return t:get_children() + else + return stuff.rawget(t, k) + end + end, - menu_configuration_features.footer_pos_related_to_background = menu.add_feature("Footer position based on background", "toggle", menu_configuration_features.footer.id, function(f) - stuff.menuData.footer.footer_pos_related_to_background = f.on - end) - menu_configuration_features.footer_pos_related_to_background.on = stuff.menuData.footer.footer_pos_related_to_background + __newindex = function(t, k, v) + assert(k ~= "id" and k ~= "children" and k ~= "type" and k ~= "str_data" and k ~= "is_highlighted", "'"..k.."' is read only") + if (k == "on" or k == "real_on") and type(v) == "boolean" then + t["table_on"][t.pid] = v + if v then + t:activate_feat_func() + end + elseif stuff.playerSpecialValues[k] then + k = k:gsub("real_", "") + if k ~= "value" and t.type >> 5 & 1 ~= 0 then + error("max, min and mod are readonly for value_str features") + end + v = tonumber(v) - menu_configuration_features.footer_text = menu.add_feature("Footer Text", "action", menu_configuration_features.footer.id, function() - local status, text = input.get("Footer Text", "", 50, 0) - if status == 0 then - stuff.menuData.footer.footer_text = tostring(text) + assert(t.type >> 1 & 1 ~= 0, "feat type not supported") + assert(v, "tried to set "..k.." property to a non-number value") + + if t.type >> 5 & 1 ~= 0 then + if v < 0 then + v = 0 + elseif t.real_str_data then + if v+1 > #t.real_str_data and #t.real_str_data ~= 0 then + v = #t.real_str_data-1 + end + end end - end) - -- Fonts - local fontStrData = { - "Menu Head", - "Menu Tab", - "Menu Entry", - "Menu Foot", - "Script 1", - "Script 2", - "Script 3", - "Script 4", - "Script 5", - } - menu_configuration_features.fonts = menu.add_feature("Fonts", "parent", menu_configuration_features.cheesemenuparent.id) + if t.type >> 1 & 1 ~= 0 then + if t.type >> 3 & 1 ~= 0 or t.type >> 5 & 1 ~= 0 then -- value_i|str + v = math.floor(v) + end - menu_configuration_features.text_font = menu.add_feature("Text Font", "autoaction_value_str", menu_configuration_features.fonts.id, function(f) - stuff.menuData.fonts.text = f.value - end) - menu_configuration_features.text_font:set_str_data(fontStrData) - menu_configuration_features.text_font.value = stuff.menuData.fonts.text + t["table_"..k][t.pid] = v + if t.type & 140 ~= 0 then -- i|f|slider + if not t.real_max then + t.real_max = 0 + end + if not t.real_min then + t.real_min = 0 + end + if not t.real_mod then + t.real_mod = 1 + end + if not t.real_value then + t.real_value = 0 + end + + t["table_value"][t.pid] = t["table_value"][t.pid] >= t["table_max"][t.pid] and t["table_max"][t.pid] or t["table_value"][t.pid] <= t["table_min"][t.pid] and t["table_min"][t.pid] or t["table_value"][t.pid] + end + end + elseif k == "data" then + t.real_data = v + else + stuff.rawset(t, k, v) + end + end + } - menu_configuration_features.footer_font = menu.add_feature("Footer Font", "autoaction_value_str", menu_configuration_features.fonts.id, function(f) - stuff.menuData.fonts.footer = f.value - end) - menu_configuration_features.footer_font:set_str_data(fontStrData) - menu_configuration_features.footer_font.value = stuff.menuData.fonts.footer + -- featMethods - menu_configuration_features.hint_font = menu.add_feature("Hint Font", "autoaction_value_str", menu_configuration_features.fonts.id, function(f) - stuff.menuData.fonts.hint = f.value - func.rewrap_hints(f.value) - end) - menu_configuration_features.hint_font:set_str_data(fontStrData) - menu_configuration_features.hint_font.value = stuff.menuData.fonts.hint + -- dogshit dont use + --[[ stuff.set_val = function(self, valueType, val, dont_set_all) + assert(stuff.type_id.id_to_name[self.type]:match("value_[if]") or stuff.type_id.id_to_name[self.type]:match("value_str"), "feat type not supported") + assert(tonumber(val), "tried to set "..valueType.." to a non-number value") + if stuff.type_id.id_to_name[self.type]:match("value_i") then + val = tonumber(math.floor(val)) + else + val = tonumber(val) + end - -- Hotkeys - menu_configuration_features.hotkeyparent = menu.add_feature("Hotkey notifications", "parent", menu_configuration_features.cheesemenuparent.id) + if valueType == "value" then + if self.real_min then + if val < self.real_min then + val = self.real_min + end + else + if val < 0 then + val = 0 + end + end + if self.real_max then + if val > self.real_max then + val = self.real_max + end + elseif self.real_str_data then + if val+1 > #self.real_str_data then + val = #self.real_str_data-1 + end + end + end - menu.add_feature("Toggle notification", "toggle", menu_configuration_features.hotkeyparent.id, function(f) - stuff.hotkey_notifications.toggle = f.on - end).on = stuff.hotkey_notifications.toggle - menu.add_feature("Action notification", "toggle", menu_configuration_features.hotkeyparent.id, function(f) - stuff.hotkey_notifications.action = f.on - end).on = stuff.hotkey_notifications.action + self[valueType] = val + if self["table_"..valueType] and not dont_set_all then + for i = 0, 31 do + self["table_"..valueType][i] = val + end + end + end - -- Colors - local colorParent = menu.add_feature("Colors", "parent", menu_configuration_features.cheesemenuparent.id) - do - local tempColor = {} - for k, v in pairs(stuff.menuData.color) do - tempColor[#tempColor+1] = {k, v, sortname = k:gsub("feature_([^s])", "feature_a%1")} - --print(k:gsub("feature_([^s])", "feature_a%1")) + stuff.set_value = function(self, val, dont_set_all) + stuff.set_val(self, "value", val, dont_set_all) + end + stuff.set_max = function(self, val, dont_set_all) + stuff.set_val(self, "max", val, dont_set_all) + end + stuff.set_min = function(self, val, dont_set_all) + stuff.set_val(self, "min", val, dont_set_all) + end + stuff.set_mod = function(self, val, dont_set_all) + stuff.set_val(self, "mod", val, dont_set_all) + end ]] + + stuff.get_str_data = function(self) + assert(self.type >> 5 & 1 ~= 0, "used get_str_data on a feature that isn't value_str") + return self.str_data + end + + stuff.set_str_data = function(self, stringTable) + assert(type(stringTable) == "table", "tried to set str_data property to a non-table value") + local numberedTable + for k, v in pairs(stringTable) do + if type(k) ~= "number" then + numberedTable = {} + for k, v in pairs(stringTable) do + numberedTable[#numberedTable + 1] = v end - table.sort(tempColor, function(a, b) return a["sortname"] < b["sortname"] end) + break + end + end + self.real_str_data = numberedTable or stringTable + if self.real_value+1 > #self.real_str_data then + self.real_value = #self.real_str_data-1 >= 0 and #self.real_str_data-1 or 0 + end + if self.feats then + for k, v in pairs(self.table_value) do + if v+1 > #self.real_str_data then + self.table_value[k] = #self.real_str_data-1 + end + end + for k, v in pairs(self.feats) do + v.real_str_data = stringTable + end + end + end - for _, v in pairs(tempColor) do - menu_configuration_features[v[1]] = {} - local vParent = menu.add_feature(v[1], "parent", colorParent.id) + stuff.toggle = function(self, bool) + if self.type & 1 ~= 0 then + if bool ~= nil then + self.real_on = bool + self:activate_feat_func() + else + self.real_on = not self.real_on + self:activate_feat_func() + end + else + self:activate_feat_func() + end + end - menu_configuration_features[v[1]].r = menu.add_feature("Red", "autoaction_value_i", vParent.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - f.value = num - end - end - stuff.menuData.color:set_color(v[1], f.value) - end) - menu_configuration_features[v[1]].r.max = 255 - if type(v[2]) == "table" then - menu_configuration_features[v[1]].r.value = v[2].r - else - menu_configuration_features[v[1]].r.value = func.convert_int_to_rgba(v[2], "r") - end + stuff.get_children = function(self) + local children = {} + for k, v in ipairs(self) do + if type(k) == "number" then + children[k] = v + end + end + return children + end - menu_configuration_features[v[1]].g = menu.add_feature("Green", "autoaction_value_i", vParent.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - f.value = num - end - end - stuff.menuData.color:set_color(v[1], nil, f.value) - end) - menu_configuration_features[v[1]].g.max = 255 - if type(v[2]) == "table" then - menu_configuration_features[v[1]].g.value = v[2].g - else - menu_configuration_features[v[1]].g.value = func.convert_int_to_rgba(v[2], "g") - end + -- function callback ~Thanks to Proddy for telling me that doing function() every time creates a new one and providing examples on how to use menu.create_thread with the function below + function stuff.feature_callback(self) + local pidordata = self.pid or self.data + if self.on ~= nil and self.type & 2049 == 0 then -- not toggle or parent + self.on = true + end + local continue = self:func(pidordata, self.data) + while continue == HANDLER_CONTINUE do + system.wait(0) + continue = self:func(pidordata, self.data) + end + if self.on ~= nil and self.type & 2049 == 0 then -- not toggle or parent + self.on = false + end + end - menu_configuration_features[v[1]].b = menu.add_feature("Blue", "autoaction_value_i", vParent.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - f.value = num - end - end - stuff.menuData.color:set_color(v[1], nil, nil, f.value) - end) - menu_configuration_features[v[1]].b.max = 255 - if type(v[2]) == "table" then - menu_configuration_features[v[1]].b.value = v[2].b - else - menu_configuration_features[v[1]].b.value = func.convert_int_to_rgba(v[2], "b") - end + function stuff.highlight_callback(self) + local pidordata = self.pid or self.data + self:hl_func(pidordata, self.data) + end - menu_configuration_features[v[1]].a = menu.add_feature("Alpha", "autoaction_value_i", vParent.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - f.value = num - end - end - stuff.menuData.color:set_color(v[1], nil, nil, nil, f.value) - end) - menu_configuration_features[v[1]].a.max = 255 - if type(v[2]) == "table" then - menu_configuration_features[v[1]].a.value = v[2].a - else - menu_configuration_features[v[1]].a.value = func.convert_int_to_rgba(v[2], "a") - end - end + stuff.activate_feat_func = function(self) + if not (self.thread) then + self.thread = 0 + end + if self.func and menu.has_thread_finished(self.thread) then + self.thread = menu.create_thread(stuff.feature_callback, self) + end + end + + stuff.activate_hl_func = function(self) + if self.hl_func then + if not self.hl_thread then + self.hl_thread = 0 + end + if menu.has_thread_finished(self.hl_thread) then + self.hl_thread = menu.create_thread(stuff.highlight_callback, self) end + end + end - -- loading default ui & settings - func.load_ui("default") - func.load_settings() + stuff.select = function(self) + local parent_of_feat_wanted = stuff.feature_by_id[self.parent_id] or features - --changing menu functions to ui functions - local menu_get_feature_by_hierarchy_key = menu.get_feature_by_hierarchy_key - menu_originals = setmetatable({ - --get_feature_by_hierarchy_key = menu.get_feature_by_hierarchy_key, - add_feature = menu.add_feature, - add_player_feature = menu.add_player_feature, - delete_feature = menu.delete_feature, - delete_player_feature = menu.delete_player_feature, - get_player_feature = menu.get_player_feature, - }, {__newindex = function() end}) - menu.add_feature = func.add_feature - menu.add_player_feature = func.add_player_feature - menu.delete_feature = func.delete_feature - menu.delete_player_feature = func.delete_player_feature - menu.get_player_feature = func.get_player_feature - menu.get_feature_by_hierarchy_key = function(hierarchy_key) - if string.find(hierarchy_key:lower(), "trusted") or string.find(hierarchy_key:lower(), "Proddy's Script Manager") then - return + if not (parent_of_feat_wanted == currentMenu) then + stuff.previousMenus[#stuff.previousMenus + 1] = {menu = currentMenu, scroll = stuff.scroll, drawScroll = stuff.drawScroll, scrollHiddenOffset = stuff.scrollHiddenOffset} + currentMenu = parent_of_feat_wanted end - local feat, duplicate - feat = menu_get_feature_by_hierarchy_key(hierarchy_key) - if feat then - return feat - else - feat, duplicate = func.get_feature_by_hierarchy_key(hierarchy_key) - if duplicate then - return feat[1] - else - return feat + + if not self.hidden then + local hiddenOffset = 0 + for k, v in ipairs(parent_of_feat_wanted) do + if type(k) == "number" then + if v.hidden and not (k > self.index) then + hiddenOffset = hiddenOffset + 1 + end + end end + stuff.scroll = self.index - hiddenOffset + stuff.drawScroll = (stuff.maxDrawScroll >= self.index) and self.index-1 or stuff.maxDrawScroll end + + stuff.scrollHiddenOffset = 0 end - cheeseUIdata = stuff.menuData -- - func.set_player_feat_parent("Online Players", 0) - func.add_feature("cheese", "action", 0).hint = "free cheese\nanother line of free cheese\nDisplays the current street you are on, as well as the intersecting street if you are in an intersection (intersection display can be disabled in the overlay settings).\n\n#FF00A2FF#Requires the [Natives] trusted mode flag to be enabled." + stuff.hotkey_feature_hierarchy_keys = {} - -- Proddy's Script Manager - gltw.read("Trusted Flags", stuff.path.cheesemenu, stuff, true, true) - menu.is_trusted_mode_enabled = function(flag) - if not flag then - return stuff.trusted_mode & 7 == 7, stuff.trusted_mode_notification + stuff.type_id = { + name_to_id = { + toggle = 1 << 0, + slider = 1 << 2 | 1 << 1 | 1 << 0, + value_i = 1 << 3 | 1 << 1 | 1 << 0, + value_str = 1 << 5 | 1 << 1 | 1 << 0, + value_f = 1 << 7 | 1 << 1 | 1 << 0, + action = 1 << 9, + action_slider = 1 << 9 | 1 << 2 | 1 << 1, + action_value_i = 1 << 9 | 1 << 3 | 1 << 1, + action_value_str = 1 << 9 | 1 << 5 | 1 << 1, + action_value_f = 1 << 9 | 1 << 7 | 1 << 1, + autoaction_slider = 1 << 10 | 1 << 2 | 1 << 1, + autoaction_value_i = 1 << 10 | 1 << 3 | 1 << 1, + autoaction_value_str = 1 << 10 | 1 << 5 | 1 << 1, + autoaction_value_f = 1 << 10 | 1 << 7 | 1 << 1, + parent = 1 << 11 + }, + } + + --Functions + function func.add_feature(nameOfFeat, TypeOfFeat, parentOfFeat, functionCallback, highlightCallback, playerFeat) + assert((type(nameOfFeat) == "string"), "invalid name in add_feature") + assert((type(TypeOfFeat) == "string") and stuff.type_id.name_to_id[TypeOfFeat], "invalid type in add_feature") + assert((type(parentOfFeat) == "number") or not parentOfFeat, "invalid parent id in add_feature") + assert((type(functionCallback) == "function") or not functionCallback, "invalid function in add_feature") + playerFeat = playerFeat or false + parentOfFeat = parentOfFeat or 0 + --TypeOfFeat = TypeOfFeat:gsub("slider", "value_f") + local currentParent = playerFeat and features["OnlinePlayers"] or features + + local hierarchy_key + if parentOfFeat ~= 0 and parentOfFeat then + currentParent = playerFeat and stuff.player_feature_by_id[parentOfFeat] or stuff.feature_by_id[parentOfFeat] + if currentParent then + assert(currentParent.type >> 11 & 1 ~= 0, "parent is not a parent feature") + assert(currentParent.type >> 15 & 1 ~= 0 == playerFeat, "parent is not valid "..((currentParent.type >> 15 & 1 ~= 0 and not playerFeat) and "using player feature as parent for a local feature" or (currentParent.type >> 15 & 1 == 0 and playerFeat and "using local parent for player feature") or "unknown")) else - return stuff.trusted_mode & flag == flag, stuff.trusted_mode_notification + error("parent does not exist") end end + if currentParent.hierarchy_key then + hierarchy_key = currentParent.hierarchy_key.."."..nameOfFeat:gsub("[ %.]", "_") + else + hierarchy_key = nameOfFeat:gsub("[ %.]", "_") + end - dofile("\\scripts\\cheesemenu\\libs\\Proddy's Script Manager.lua") - - do - local trusted_parent = menu_get_feature_by_hierarchy_key("local.script_features.cheese_menu.proddy_s_script_manager.trusted_mode") + currentParent[#currentParent + 1] = {name = nameOfFeat, real_type = stuff.type_id.name_to_id[TypeOfFeat] | (playerFeat and 1 << 15 or 0), real_id = 0, --[[parent = {id = currentParent.id or 0},]] parent_id = currentParent.id or 0, playerFeat = playerFeat, index = #currentParent + 1} + local feat = currentParent[#currentParent] + feat.activate_feat_func = stuff.activate_feat_func + feat.activate_hl_func = stuff.activate_hl_func + feat.set_str_data = stuff.set_str_data + feat.toggle = stuff.toggle + feat.get_children = stuff.get_children + feat.get_str_data = stuff.get_str_data + feat.select = stuff.select + setmetatable(feat, stuff.featMetaTable) + feat.thread = 0 + --if feat.real_type & 1 ~= 0 or feat.real_type >> 9 & 1 ~= 0 then -- toggle + if playerFeat then + feat.table_on = {} + for i = 0, 31 do + feat.table_on[i] = feat.type >> 11 & 1 ~= 0 + end + end + feat.on = feat.type >> 11 & 1 ~= 0 + --end + if feat.real_type >> 5 & 1 ~= 0 then -- value_str + feat.real_str_data = {} + if playerFeat then + feat.table_value = {} + for i = 0, 31 do + feat.table_value[i] = 0 + end + end + feat.value = 0 + elseif feat.real_type >> 1 & 1 ~= 0 then --value any + if playerFeat then + feat.table_max = {} + feat.table_min = {} + feat.table_mod = {} + feat.table_value = {} + for i = 0, 31 do + feat.table_max[i] = 0 + feat.table_min[i] = 0 + feat.table_mod[i] = 1 + feat.table_value[i] = 0 + end + end + feat.max = 0 + feat.min = 0 + feat.mod = 1 + feat.value = 0 + end + feat.hidden = false + feat["func"] = functionCallback + feat["hl_func"] = highlightCallback + if TypeOfFeat == "parent" then + feat.child_count = 0 + end + currentParent.child_count = 0 + for k, v in pairs(currentParent) do + if type(k) == "number" then + currentParent.child_count = currentParent.child_count + 1 + end + end + feat.hotkey = stuff.hierarchy_key_to_hotkey[hierarchy_key] + feat.hierarchy_key = hierarchy_key + if stuff.hotkey_feature_hierarchy_keys[hierarchy_key] then + stuff.hotkey_feature_hierarchy_keys[hierarchy_key][#stuff.hotkey_feature_hierarchy_keys[hierarchy_key] + 1] = feat + else + stuff.hotkey_feature_hierarchy_keys[hierarchy_key] = {feat} + end + if playerFeat then + stuff.player_feature_by_id[#stuff.player_feature_by_id+1] = feat + feat.real_id = #stuff.player_feature_by_id + else + stuff.feature_by_id[#stuff.feature_by_id+1] = feat + feat.real_id = #stuff.feature_by_id + end + return feat + end - menu_originals.add_feature("Save Trusted Flags", "action", trusted_parent.id, function() - gltw.write({trusted_mode = stuff.trusted_mode, trusted_mode_notification = stuff.trusted_mode_notification}, "Trusted Flags", stuff.path.cheesemenu, nil, nil, true) - menu.notify("Saved Successfully", "Cheese Menu", 2, 0x00ff00) - end) + --player feature functions - menu_originals.add_feature("Trusted Flags Notification", "toggle", trusted_parent.id, function(f) - stuff.trusted_mode_notification = f.on - end).on = stuff.trusted_mode_notification + -- if you set a toggle player feature to on it'll enable for any valid players/joining players but if a player leaves functions like player.get_player_name will return nil before the feature is turned off + function func.add_player_feature(nameOfFeat, TypeOfFeat, parentOfFeat, functionCallback, highlightCallback) + parentOfFeat = parentOfFeat or 0 + assert(stuff.PlayerParent, "you need to use set_player_feat_parent before adding player features") + local pfeat = func.add_feature(nameOfFeat, TypeOfFeat, parentOfFeat, functionCallback, highlightCallback, true) + pfeat.feats = {} - local trusted_names = { - [0] = "Stats", - "Globals / Locals", - "Natives", - "HTTP", - "Memory" - } + if parentOfFeat == 0 then + for k = 0, 31 do + stuff.playerIds[k][#stuff.playerIds[k]+1] = {} + local currentFeat = stuff.playerIds[k][#stuff.playerIds[k]] + func.add_to_table(pfeat, currentFeat, k, nil, true) + stuff.feature_by_id[#stuff.feature_by_id+1] = currentFeat + currentFeat.ps_id = #stuff.feature_by_id + currentFeat.ps_parent_id = stuff.playerIds[k].id + currentFeat.pid = k + pfeat.feats[k] = currentFeat + end + else + local playerParent = stuff.player_feature_by_id[parentOfFeat] + if playerParent then + for k = 0, 31 do + playerParent.feats[k][#playerParent.feats[k]+1] = {} + local currentFeat = playerParent.feats[k][#playerParent.feats[k]] - for i = 0, 4 do - menu_originals.add_feature(trusted_names[i], "toggle", trusted_parent.id, function(f) - if f.on then - stuff.trusted_mode = stuff.trusted_mode | 1 << i - else - stuff.trusted_mode = stuff.trusted_mode ~ 1 << i - end - end).on = stuff.trusted_mode & 1 << i ~= 0 + func.add_to_table(pfeat, currentFeat, k, nil, true) + stuff.feature_by_id[#stuff.feature_by_id+1] = currentFeat + currentFeat.ps_id = #stuff.feature_by_id + currentFeat.ps_parent_id = playerParent.feats[k].ps_id + currentFeat.pid = k + pfeat.feats[k] = currentFeat + end end end - -- -end -if httpTrustedOff then - loadCurrentMenu() -end]=], - ["CheeseUtilities.lua"] = [=[--Made by GhostOne -local cheeseUtils = {} --- Credit to kektram for this whole function ~ a little modified to focus on fractionals -cheeseUtils.memoize = {} -do - local sign_bit_x = 1 << 62 - local sign_bit_y = 1 << 61 - local max_30_bit_num = 1073740823 - local v2 = v2 - local memoized = {} - function cheeseUtils.memoize.v2(x, y) - x = x or 0 - y = y or 0 - local xi = x * 100000000 // 1 -- modified from 1000 to 100,000,000 to support up to 10^-7 fractional digits ~ this limits it to either single or double digits with fractions - local yi = y * 100000000 // 1 -- same here - if xi >= -max_30_bit_num - and xi <= max_30_bit_num - and yi >= -max_30_bit_num - and yi <= max_30_bit_num then - local signs = 0 - if xi < 0 then - xi = xi * -1 - signs = signs | sign_bit_x + return pfeat + end + + function func.add_to_table(getTable, addToTable, playerid, override, setmeta) + local isPlayerFeatValues + for k, v in pairs(getTable) do + if tostring(k):match("table_") or stuff.playerSpecialValues[k] then + isPlayerFeatValues = true + elseif type(v) == "table" then + if type(addToTable[k]) ~= "table" then + addToTable[k] = {} + end + if addToTable[k].real_on then + addToTable[k].real_on = false + end + if (v.type or 0) >> 11 & 1 ~= 0 then + func.add_to_table(getTable[k], addToTable[k], playerid, override) + else + for i, e in pairs(getTable[k]) do + if type(e) ~= "table" then + if not addToTable[k][i] or override then + addToTable[k][i] = e + end + end + end + end + setmetatable(addToTable[k], stuff.playerfeatMetaTable) + if v.name then + if not getTable[k].feats then + getTable[k].feats = {} + end + getTable[k].feats[playerid] = addToTable[k] + end + else + if not addToTable[k] or override then + addToTable[k] = v + end end - if yi < 0 then - yi = yi * -1 - signs = signs | sign_bit_y + end + if setmeta or isPlayerFeatValues then + addToTable.table_value = getTable.table_value + addToTable.table_min = getTable.table_min + addToTable.table_max = getTable.table_max + addToTable.table_mod = getTable.table_mod + addToTable.table_on = getTable.table_on + for i, e in pairs(stuff.playerSpecialValues) do + if addToTable[i] then + stuff.rawset(addToTable, i, nil) + end end - local hash = signs | xi << 30 | yi - memoized[hash] = memoized[hash] or v2(x, y) - return memoized[hash] - else - return v2(x, y) + setmetatable(addToTable, stuff.playerfeatMetaTable) end end -end --- - -function cheeseUtils.draw_outline(v2pos, v2size, color, thickness) - local thickness_y = thickness / graphics.get_screen_height() * 2 - local thickness_x = thickness / graphics.get_screen_width() * 2 - - scriptdraw.draw_rect( - cheeseUtils.memoize.v2(v2pos.x, v2pos.y - (v2size.y/2)), - cheeseUtils.memoize.v2(v2size.x + thickness_x, thickness_y), - color - ) - - scriptdraw.draw_rect( - cheeseUtils.memoize.v2(v2pos.x, v2pos.y + (v2size.y/2)), - cheeseUtils.memoize.v2(v2size.x + thickness_x, thickness_y), - color - ) - - scriptdraw.draw_rect( - cheeseUtils.memoize.v2(v2pos.x - (v2size.x/2), v2pos.y), - cheeseUtils.memoize.v2(thickness_x, v2size.y - thickness_y), - color - ) - scriptdraw.draw_rect( - cheeseUtils.memoize.v2(v2pos.x + (v2size.x/2), v2pos.y), - cheeseUtils.memoize.v2(thickness_x, v2size.y - thickness_y), - color - ) -end + function func.set_player_feat_parent(nameOfFeat, parentOfFeat, functionToDo) + stuff.PlayerParent = func.add_feature(nameOfFeat, "parent", parentOfFeat, functionToDo) + local hierarchy_pattern = stuff.PlayerParent.hierarchy_key..".player_" --- Credit to Proddy for this function -cheeseUtils.Keys = {} -function cheeseUtils.get_key(...) - local args = {...} - assert(#args > 0, "must give at least one key") - local ID = table.concat(args, "|") - if not cheeseUtils.Keys[ID] then - local key = MenuKey() - for i=1,#args do - key:push_vk(args[i]) + stuff.playerIds = {} + for i = 0, 31 do + stuff.playerIds[i] = func.add_feature(tostring(player.get_player_name(i)), "parent", stuff.PlayerParent.id) + stuff.playerIds[i].pid = i + stuff.playerIds[i].hidden = not player.is_player_valid(i) + stuff.playerIds[i].hierarchy_key = hierarchy_pattern..i + stuff.playerIds[i].real_type = 1 << 15 | stuff.playerIds[i].type end - cheeseUtils.Keys[ID] = key - end - - return cheeseUtils.Keys[ID] -end - -function cheeseUtils.new_reusable_v2(limit) - limit = limit or 2 - - local counter = 1 - local v2Table = {} - for i = 1, limit do - v2Table[i] = v2() - end - return function(x, y) - local vector2d = v2Table[counter] - counter = counter + 1 - counter = counter <= limit and counter or 1 - - vector2d.x, vector2d.y = x, y + event.add_event_listener("player_join", function(listener) + system.wait(100) + stuff.playerIds[listener.player].hidden = false + stuff.playerIds[listener.player].name = player.get_player_name(listener.player) + func.reset_player_submenu(listener.player) + table.sort(stuff.PlayerParent, stuff.table_sort_functions[stuff.player_submenu_sort]) + end) + event.add_event_listener("player_leave", function(listener) + func.reset_player_submenu(listener.player) + if not player.is_player_valid(listener.player) then + stuff.playerIds[listener.player].hidden = true + stuff.playerIds[listener.player].name = "nil" + end + table.sort(stuff.PlayerParent, stuff.table_sort_functions[stuff.player_submenu_sort]) + end) - return vector2d + return stuff.PlayerParent end -end - --- Selector -do - local textv2 = v2(2, 2) - local reuse_v2 = cheeseUtils.new_reusable_v2() - - local key = { - enter = MenuKey(), - backspace = MenuKey(), - up = MenuKey(), - down = MenuKey(), - } - key.enter:push_vk(0x0D) - key.backspace:push_vk(0x08) - key.up:push_vk(0x26) - key.down:push_vk(0x28) - local key_waits = {} - local function get_key_wait(str_key) - local vk_key = key[str_key] - if vk_key:is_down() and ((utils.time_ms() > key_waits[str_key]) or (key_waits[str_key] == 0)) then - if key_waits[str_key] == 0 then - key_waits[str_key] = utils.time_ms() + 500 - else - key_waits[str_key] = utils.time_ms() + 100 + function func.reset_player_submenu(pid, currentParent) + local currentParent = currentParent or features.OnlinePlayers + for k, v in pairs(currentParent) do + if type(v) == "table" then + local feat_type = v.type + if feat_type then + if feat_type >> 1 & 1 ~= 0 then -- toggle + v.table_value[pid] = v.real_value + if feat_type & 136 ~= 0 then -- value if + v.table_min[pid] = v.real_min + v.table_max[pid] = v.real_max + v.table_mod[pid] = v.real_mod + end + end + if feat_type & 1 ~= 0 then -- toggle + if player.is_player_valid(pid) then + v.feats[pid].on = v.real_on + else + v.feats[pid].on = false + v.table_on[pid] = false + end + end + if feat_type >> 11 & 1 ~= 0 then -- parent + func.reset_player_submenu(pid, v) + end + end end - return true - elseif not vk_key:is_down() then - key_waits[str_key] = 0 end - return false end + --end of player feature functions - --local speed_modifier = 0.5 - local function draw_selector(stuff) - while true do - local selected = stuff.selected - scriptdraw.draw_rect(reuse_v2(0, 0), textv2, 0x7D000000) - scriptdraw.draw_text(stuff.selected_str, reuse_v2(-0.02, 0), textv2, 1 / stuff.text_size_rel_to_res, 0xFFFFFFFF, 1 << 4) - - if stuff.move then - local is_going_up = stuff.move == "up" - if (is_going_up and stuff.selected - 1 >= 1) or (not is_going_up and stuff.selected + 1 <= #stuff.items) then - stuff.offset = is_going_up and stuff.offset - stuff.offset_step or stuff.offset + stuff.offset_step - stuff.size_offset = stuff.size_offset + stuff.size_step - if stuff.offset >= 0.08 or stuff.offset <= -0.08 then - stuff.offset = 0 - stuff.size_offset = 0 - stuff.next_selected = 0 - - stuff.selected = is_going_up and stuff.selected - 1 or stuff.selected + 1 - selected = stuff.selected - stuff.move = nil + function func.check_scroll(index, parent, bool) + if index <= stuff.scroll + stuff.scrollHiddenOffset and currentMenu == parent then + if bool then + --stuff.scroll = stuff.scroll - 1 + --stuff.scroll = stuff.scroll > 0 and stuff.scroll or 0 + if #currentMenu - stuff.drawHiddenOffset > 1 and stuff.scroll - 1 > 0 then + stuff.scroll = stuff.scroll - 1 + if stuff.scroll - stuff.drawScroll <= 2 and stuff.drawScroll > 0 then + stuff.drawScroll = stuff.drawScroll - 1 end - else - stuff.move = nil end else - stuff.offset = 0 - stuff.size_offset = 0 - stuff.next_selected = 0 + if #currentMenu - stuff.drawHiddenOffset > 1 then + stuff.scroll = stuff.scroll + 1 + if stuff.scroll - stuff.drawScroll >= (stuff.menuData.max_features - 1) and stuff.drawScroll < stuff.maxDrawScroll then + stuff.drawScroll = stuff.drawScroll + 1 + end + end + --stuff.scroll = stuff.scroll + 1 end + end + end - local min = selected - 5 >= 1 and selected - 5 or 1 - local max = selected + 5 <= #stuff.items and selected + 5 or #stuff.items - for i = min, max do - if stuff.items[i] then - local size = i == selected and 1.3 or 1 - size = i == stuff.next_selected and size + stuff.size_offset or i == selected and size - stuff.size_offset or size - local alpha = stuff.move == "up" and math.max(math.floor(255 - math.abs((i - selected) + math.abs(stuff.offset)/0.08)*51), 0) or math.max(math.floor(255 - math.abs((i - selected) - math.abs(stuff.offset)/0.08)*51), 0) - scriptdraw.draw_text(stuff.items[i], reuse_v2(0, 0.005 - 0.08 * (i - selected) + (stuff.offset or 0)), textv2, size / stuff.text_size_rel_to_res, (alpha << 24 | 0xFFFFFF), 0) + function func.deleted_or_hidden_parent_check(parent, check_hidden_only) + if next(stuff.previousMenus) then + local parentBeforeDHparent = false + if parent ~= currentMenu then + for k, v in ipairs(stuff.previousMenus) do + if parentBeforeDHparent then + stuff.previousMenus[k] = nil + else + if (v.menu == parent and not check_hidden_only) or (v.menu.hidden and check_hidden_only) then + parentBeforeDHparent = true + currentMenu = stuff.previousMenus[k-1].menu + stuff.scroll = stuff.previousMenus[k-1].scroll + stuff.drawScroll = stuff.previousMenus[k-1].drawScroll + stuff.scrollHiddenOffset = stuff.previousMenus[k-1].scrollHiddenOffset + stuff.previousMenus[k-1] = nil + stuff.previousMenus[k] = nil + end + end end + elseif not check_hidden_only then + currentMenu = stuff.previousMenus[#stuff.previousMenus].menu + stuff.scroll = stuff.previousMenus[#stuff.previousMenus].scroll + stuff.drawScroll = stuff.previousMenus[#stuff.previousMenus].drawScroll + stuff.scrollHiddenOffset = stuff.previousMenus[#stuff.previousMenus].scrollHiddenOffset + stuff.previousMenus[#stuff.previousMenus] = nil end + end + end - controls.disable_control_action(0, 200, true) - controls.disable_control_action(0, 172, true) - controls.disable_control_action(0, 27, true) - - system.wait(0) + function func.get_feature_by_hierarchy_key(hierarchy_key) + local feat = stuff.hotkey_feature_hierarchy_keys[hierarchy_key] + if feat then + if feat[2] and not feat.name then + return feat, true + else + return feat[1] + end end end - -- Usage: local index, item = selector("Select Player: ", 2, {"Player 1", "Player 2", "Player 3"}) - -- if cancelled returned `index` will be false - -- `items` has to be in order and starting from 1 - function cheeseUtils.selector(selected_str, speed, index, items) - index = tonumber(index) or 1 - index = index > 1 and index or 1 - assert(type(items) == "table", "items should be a table") - local stuff = { - selected_str = selected_str and tostring(selected_str) or "Select: ", - items = items, - selected = tonumber(index) or 1, - next_selected = 0, - offset = 0, - size_offset = 0, - offset_step = 0.08/(10/(speed or 1)), - size_step = 0.3/(10/(speed or 1)), - text_size_rel_to_res = (3686400/(graphics.get_screen_width()*graphics.get_screen_height()))*0.3+0.7, - } + function func.get_feature(id) + assert(type(id) == "number" and id ~= 0, "invalid id in get_feature") + return stuff.feature_by_id[id] + end - local drawThread = menu.create_thread(draw_selector, stuff) + function func.delete_feature(id, bool_ps) + if type(id) == "table" then + id = id.id + end - while key.enter:is_down() do - system.wait(0) + local feat = stuff.feature_by_id[id] + if not feat then + return false end - while true do - if key.enter:is_down() then - break - end - if key.backspace:is_down() then - menu.delete_thread(drawThread) - while key.backspace:is_down() do - system.wait(0) - end - return false - end - if get_key_wait("up") then - stuff.move = "up" - stuff.next_selected = stuff.selected - 1 + if stuff.old_selected == stuff.feature_by_id[id] then + stuff.old_selected = nil + end + stuff.feature_by_id[id] = nil + + if feat.thread then + if not menu.has_thread_finished(feat.thread) then + menu.delete_thread(feat.thread) end - if get_key_wait("down") then - stuff.move = "down" - stuff.next_selected = stuff.selected + 1 + end + if feat.hl_thread then + if not menu.has_thread_finished(feat.hl_thread) then + menu.delete_thread(feat.hl_thread) end - system.wait(0) end - while key.enter:is_down() do - system.wait(0) + local parent + if feat.parent_id ~= 0 or bool_ps then + parent = bool_ps and stuff.feature_by_id[feat.ps_parent_id] or stuff.feature_by_id[feat.parent_id] + else + parent = features end - menu.delete_thread(drawThread) - - return stuff.selected, stuff.items[stuff.selected] - end -end --- - --- Draw Slider -do - local reuse_v2 = cheeseUtils.new_reusable_v2() - - function cheeseUtils.draw_slider(pos, width, min, max, value, colorBG, colorActive, colorText, draw_value) - scriptdraw.draw_rect(pos, width, colorBG) - local ActiveWidthX = width.x * ((value - min) / (max - min)) - scriptdraw.draw_rect(reuse_v2(pos.x - width.x/2 + ActiveWidthX/2, pos.y), reuse_v2(ActiveWidthX , width.y), colorActive) - - if draw_value then - local text_size = scriptdraw.get_text_size(tostring(value), 1) - local size_correction = width.y*2 / scriptdraw.size_pixel_to_rel_y(text_size.y*2) - 0.12 - text_size = text_size * size_correction - text_size.x = scriptdraw.size_pixel_to_rel_x(text_size.x) - text_size.y = scriptdraw.size_pixel_to_rel_y(text_size.y) - scriptdraw.draw_text(tostring(value), reuse_v2(pos.x - text_size.x/2, pos.y + text_size.y/2), reuse_v2(2, 2), size_correction, colorText, 0) + if feat.type >> 11 & 1 ~= 0 then + func.deleted_or_hidden_parent_check(feat) end - end -end - --- Use width and height with draw_rect_ext -do - local v2r = cheeseUtils.new_reusable_v2(4) - function cheeseUtils.draw_rect_ext_wh(pos, size, color1, color2, color3, color4) - local halfWdith, halfHeight = size.x/2, size.y/2 - local Bottom = pos.y - halfHeight - local Top = pos.y + halfHeight - local Left = pos.x - halfWdith - local Right = pos.x + halfWdith - scriptdraw.draw_rect_ext(v2r(Left, Bottom), v2r(Left, Top), v2r(Right, Top), v2r(Right, Bottom), color1, color2, color3, color4) - end -end --- Side Window ---[[ -Usage example: - local cheeseUtils = require("CheeseUtilities") + local index = feat.index + if not bool_ps then + stuff.feature_hints[index] = nil + end + table.remove(parent, tonumber(feat.index)) - local window_test = cheeseUtils.new_side_window("test_header", v2(0.5, 0.5)) + --func.check_scroll(index, parent, true) - local firstField = window_test:add_field("left", "right") + for i = index, #parent do + parent[i].index = i + end - do - local timer = utils.time_ms() + 100 - window_test:add_field("idk", "1"):set_update_function(function(field) - if timer < utils.time_ms() then - timer = utils.time_ms() + 100 - local fieldValue = tonumber(field.value) - fieldValue = fieldValue + 1 - if fieldValue > 25 then - fieldValue = 1 - end - return fieldValue, fieldValue > 10 and "> 10" or "< 10" - end - end) + return true end - window_test:set_position(nil, 0.2) + function func.delete_player_feature(id) + if type(id) == "table" then + id = id.id + end - window_test:set_rect_color(0xAA000000) + stuff.player_feature_hints[id] = nil - menu.create_thread(function() - while true do - window_test:update() - window_test:draw() - system.wait(0) + local feat = stuff.player_feature_by_id[id] + if not feat then + return false end - end) - menu.add_feature("hide cheese", "toggle", 0, function(f) - if f.on then - window_test:remove_field(window_test:get_field_by_name("cheese")) - firstField:set_value("right") + stuff.player_feature_by_id[id] = nil + + local parent + if feat.parent_id ~= 0 then + parent = stuff.player_feature_by_id[feat.parent_id] else - window_test:add_field("cheese", "menu", 2) - firstField:set_value("cheese enabled") + parent = features["OnlinePlayers"] end - end).on = true -]] -do - local function draw_side_window(self) - assert( - type(self.header_text) == "string" - and type(self.fields) == "table" - and type(self.pos) == "userdata" - and type(self.rect_color) == "number" - and type(self.rect_width) == "number" - and type(self.text_spacing) == "number" - and type(self.text_padding) == "number" - and type(self.text_color) == "number", - "one or more draw_side_window args were invalid" - ) - local rect_height = (#self.fields-self.hidden_fields)*self.text_spacing - self.text_spacing + self.last_name_height + 0.02 --+0.0083--+(self.header_on and 0.07125 or 0.02) - local original_y = self.pos.y--(rect_height/2) - local header_y = original_y+self.header_height/2+rect_height/2 - local hidden_y_offset = 0 + for k, v in pairs(feat.feats) do + func.delete_feature(v.ps_id, true) + end - scriptdraw.draw_rect(self.pos, cheeseUtils.memoize.v2(self.rect_width, rect_height), self.rect_color) - if self.header_on then - scriptdraw.draw_rect(cheeseUtils.memoize.v2(self.pos.x, header_y), cheeseUtils.memoize.v2(self.rect_width, self.header_height), self.rect_color) + local index = feat.index + table.remove(parent, tonumber(index)) + for i = index, #parent do + parent[i].index = i + for pid = 0, 31 do + parent[i].feats[pid].index = i + end end + end - local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 - -- Header text - scriptdraw.draw_text(self.header_text, cheeseUtils.memoize.v2(self.pos.x - self.header_text_width/graphics.get_screen_width(), header_y+0.015), cheeseUtils.memoize.v2(2, 2), text_size, self.text_color, 0, 0) - -- table_of_lines - for id, field in ipairs(self.fields) do - if field.hidden then - hidden_y_offset = hidden_y_offset + 1 - else - local pos_y = original_y-(id-hidden_y_offset-1)*self.text_spacing+rect_height/2 - self.last_name_height/6 - 0.01 --(self.text_spacing/2.5) - scriptdraw.draw_text(field.name, cheeseUtils.memoize.v2(self.pos.x-self.rect_width/2+self.text_padding, pos_y), cheeseUtils.memoize.v2(2, 2), text_size, self.text_color, 0, 2) - scriptdraw.draw_text(field.value, cheeseUtils.memoize.v2(self.pos.x+self.rect_width/2-self.text_padding, pos_y), cheeseUtils.memoize.v2(2, 2), text_size, self.text_color, 16, 2) + function func.get_player_feature(id) + assert(type(id) == "number" and id ~= 0, "invalid id in get_player_feature") + return stuff.player_feature_by_id[id] + end + + function func.do_key(time, key, doLoopedFunction, functionToDo) + if cheeseUtils.get_key(key):is_down() then + functionToDo() + local timer = utils.time_ms() + time + while timer > utils.time_ms() and cheeseUtils.get_key(key):is_down() do + system.wait(0) + end + while timer < utils.time_ms() and cheeseUtils.get_key(key):is_down() do + if doLoopedFunction then + functionToDo() + end + local timer = utils.time_ms() + 50 + while timer > utils.time_ms() do + system.wait(0) + end end end end - -- field functions - local function set_name(self, new_name) - if new_name then - if self.window.fields[#self.window.fields] == self then - local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 - self.window.last_name_height = scriptdraw.size_pixel_to_rel_y(scriptdraw.get_text_size(new_name, text_size, 0).y) + stuff.header_ids = {} + function func.load_sprite(path_to_file, id_table) + --path = path or stuff.path.header + id_table = id_table or stuff.header_ids + path_to_file = tostring(path_to_file) + assert(path_to_file, "invalid name") + + --name = name:gsub("%.[a-z]+$", "") + + if not id_table[path_to_file] then + if utils.dir_exists(path_to_file:gsub("%.ogif", "")) and path_to_file:find("%.ogif") then + local path = path_to_file:gsub("%.ogif", "").."\\" + local images + + for _, v in pairs(stuff.image_ext) do + images = utils.get_all_files_in_directory(path, v) + if images[1] then break end + end + if not images[1] then + menu.notify("No frames found.", "Cheese Menu", 5, 0x0000FF) + return + end + + id_table[path_to_file] = {} + for i, e in pairs(images) do + id_table[path_to_file][i] = {} + id_table[path_to_file][i].sprite = scriptdraw.register_sprite(path..e) + id_table[path_to_file][i].delay = e:match("%d+_(%d+)") end - self.fields_by_name[self.name] = nil - self.name = tostring(new_name) or "" - self.fields_by_name[new_name] = self - end - end - local function set_value(self, value) - if value then - self.value = tostring(value) - end - end + id_table[path_to_file].constant_delay = utils.get_all_files_in_directory(path, "txt")[1] + if not id_table[path_to_file].constant_delay then + for k, v in pairs(images) do + if not v:match("%d+_(%d+)") then + menu.notify("FPS file not found and frames are not in format, create a txt file with the framerate of the gif.\nExample: '25 fps.txt'", "Cheese Menu", 5, 0x0000FF) + break + end + end + else + id_table[path_to_file].constant_delay = math.floor(1000 / tonumber(id_table[path_to_file].constant_delay:match("(%d*%.*%d+)%s+fps"))) + end - local function set_update_function(self, callback) - self.update_function = callback + elseif utils.file_exists(path_to_file) then + id_table[path_to_file] = scriptdraw.register_sprite(path_to_file) + end end - local function update_field(self) - if self.update_function then - local value, name = self:update_function() + return id_table[path_to_file] + end - self:set_value(value) - self:set_name(name) + function func.toggle_menu(bool) + stuff.menuData.menuToggle = bool + if stuff.menuData.menuToggle then + if currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then + currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() end end + end - local function set_hidden(self, bool) - assert(type(bool) == "boolean", "hidden only accepts boolean value") - if bool ~= self.hidden then - self.hidden = bool - self.window.hidden_fields = self.window.hidden_fields + (bool and 1 or -1) + function func.selector(feat) + local originalmenuToggle = stuff.menuData.menuToggle + stuff.menuData.menuToggle = false + if feat.str_data then + local index, _ = cheeseUtils.selector(nil, stuff.menuData.selector_speed, feat.real_value + 1, feat.str_data) + if index then + feat.real_value = index - 1 end - end - -- - - ---@class field - ---@field name string - ---@field value string - ---@field set_name function - ---@field set_value function - ---@field set_update_function function - ---@field update function - - ---@param name string - ---@param value string | number - ---@return field - local function add_field(self, name, value, pos) - local field = { - name = name, - value = value, - id = pos or #self.fields + 1, - fields_by_name = self.fields_by_name, - window = self, - hidden = false, - set_name = set_name, - set_value = set_value, - set_update_function = set_update_function, - update = update_field, - set_hidden = set_hidden - } - if pos then - local prevField = (pos - 1 > 0 and self.fields[pos-1] or true) - assert(prevField, "Fields have to be in increments of 1, for example (1, 2, 5) will not work") - if self.fields[pos] and prevField then - table.insert(self.fields, pos, field) - elseif prevField then - self.fields[pos] = field + if feat.type >> 10 & 1 ~= 0 then + feat:activate_feat_func() end - else - self.fields[#self.fields + 1] = field - local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 - self.last_name_height = scriptdraw.size_pixel_to_rel_y(scriptdraw.get_text_size(name, text_size, 0).y) end - self.fields_by_name[name] = field - - return field + func.toggle_menu(originalmenuToggle) end - local function remove_field(self, field) - if field and self.fields[field.id] then - table.remove(self.fields, field.id) - self.fields_by_name[field.name] = nil + function func.rewrap_hint(hintTable, font, padding) + hintTable.str = cheeseUtils.wrap_text(hintTable.original, font, stuff.menuData.text_size * stuff.menuData.hint_size_modifier, stuff.menuData.width*2-padding) + hintTable.size = scriptdraw.get_text_size(hintTable.str, 1, font) + end - return true + function func.rewrap_hints(font) + local padding = scriptdraw.size_pixel_to_rel_x(25) + for _, hintTable in pairs(stuff.feature_hints) do + func.rewrap_hint(hintTable, font, padding) + end + for _, hintTable in pairs(stuff.player_feature_hints) do + func.rewrap_hint(hintTable, font, padding) end - - return false end - local function get_field_by_name(self, name) - return self.fields_by_name[name] + function func.save_settings() + gltw.write({ + x = stuff.menuData.pos_x, + y = stuff.menuData.pos_y, + side_window = stuff.menuData.side_window, + controls = stuff.controls, + hotkey_notifications = stuff.hotkey_notifications, + player_submenu_sort = stuff.player_submenu_sort, + selector_speed = stuff.menuData.selector_speed + }, "Settings", stuff.path.cheesemenu) end - local function update(self) - for _, field in pairs(self.fields) do - field:update() - end - end + function func.load_settings() + local settings = gltw.read("Settings", stuff.path.cheesemenu, nil, nil, true) + if settings then + stuff.menuData.pos_x = settings.x + stuff.menuData.pos_y = settings.y + stuff.menuData.selector_speed = settings.selector_speed + stuff.player_submenu_sort = settings.player_submenu_sort - local function set_position(self, x, y) - self.pos.x = tonumber(x) or self.pos.x - self.pos.y = tonumber(y) or self.pos.y + for k, v in pairs(settings.side_window) do + stuff.menuData.side_window[k] = v + end + for k, v in pairs(settings.hotkey_notifications) do + stuff.hotkey_notifications[k] = v + end + for k, v in pairs(settings.controls) do + stuff.controls[k] = v + end + for k, v in pairs(stuff.controls) do + stuff.vkcontrols[k] = stuff.char_codes[v] + end + + menu_configuration_features.menuXfeat.value = math.floor(stuff.menuData.pos_x*graphics.get_screen_width()) + menu_configuration_features.menuYfeat.value = math.floor(stuff.menuData.pos_y*graphics.get_screen_height()) + menu_configuration_features.player_submenu_sort.value = stuff.player_submenu_sort + menu_configuration_features.player_submenu_sort:toggle() + menu_configuration_features.side_window_offsetx.value = math.floor(stuff.menuData.side_window.offset.x*graphics.get_screen_width()) + menu_configuration_features.side_window_offsety.value = math.floor(stuff.menuData.side_window.offset.y*graphics.get_screen_height()) + menu_configuration_features.side_window_spacing.value = math.floor(stuff.menuData.side_window.spacing*graphics.get_screen_height()) + menu_configuration_features.side_window_padding.value = math.floor(stuff.menuData.side_window.padding*graphics.get_screen_width()) + menu_configuration_features.side_window_width.value = math.floor(stuff.menuData.side_window.width*graphics.get_screen_width()) + menu_configuration_features.side_window_on.on = stuff.menuData.side_window.on + menu_configuration_features.selector_speed.value = stuff.menuData.selector_speed + end end - local function set_header_text(self, text) - text = tostring(text) - self.header_text = text - self.header_on = text ~= "" - local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 - self.header_text_width = scriptdraw.get_text_size(self.header_text, text_size, 0).x + function func.save_ui(name) + gltw.write(stuff.menuData, name, stuff.path.ui, {"menuToggle", "menuNav", "loaded_sprites", "files", "pos_x", "pos_y", "side_window", "selector_speed", "chatBoxOpen"}) end - local set_functions = {} - for _, field in ipairs({'text_padding', 'text_spacing', 'rect_width', 'rect_color', 'text_color'}) do - set_functions[field] = function(self, num) - num = tonumber(num) - assert(num, field.." value has to be a number") - self[field] = num + function func.load_ui(name) + local uiTable = gltw.read(name, stuff.path.ui, stuff.menuData, true, true) + if not uiTable then + return end - end + if menu_configuration_features then + local header, bgSprite = uiTable.header, uiTable.background_sprite and uiTable.background_sprite.sprite or nil + if not header then + menu_configuration_features.headerfeat.value = 0 + menu_configuration_features.headerfeat:toggle() + end + if not bgSprite then + menu_configuration_features.backgroundfeat.value = 0 + menu_configuration_features.backgroundfeat:toggle() + end - ---@class window - ---@field draw function - ---@field update function - ---@field add_field function - ---@field remove_field function - ---@field set_position function - ---@field get_field_by_name function - ---@field set_text_padding function - ---@field set_text_spacing function - ---@field set_rect_width function - ---@field set_rect_color function - ---@field set_text_color function - ---@field set_header_text function - ---@field set_hidden function - ---@field header_text string - ---@field fields table - ---@field fields_by_name table - ---@field pos v2 - ---@field rect_color uint32_t - ---@field rect_width float - ---@field text_spacing float - ---@field text_padding float - ---@field text_color uint32_t + --[[ menu_configuration_features.menuXfeat.value = math.floor(stuff.menuData.pos_x*graphics.get_screen_width()) + menu_configuration_features.menuYfeat.value = math.floor(stuff.menuData.pos_y*graphics.get_screen_height()) ]] + menu_configuration_features.maxfeats.value = math.floor(stuff.menuData.max_features) + menu_configuration_features.menuWidth.value = math.floor(stuff.menuData.width*graphics.get_screen_width()) + menu_configuration_features.featXfeat.value = math.floor(stuff.menuData.feature_scale.x*graphics.get_screen_width()) + menu_configuration_features.featYfeat.value = math.floor(stuff.menuData.feature_scale.y*graphics.get_screen_height()) + menu_configuration_features.feature_offset.value = math.floor(stuff.menuData.feature_offset*graphics.get_screen_height()) + menu_configuration_features.namePadding.value = math.floor(stuff.menuData.padding.name*graphics.get_screen_width()) + menu_configuration_features.parentPadding.value = math.floor(stuff.menuData.padding.parent*graphics.get_screen_width()) + menu_configuration_features.valuePadding.value = math.floor(stuff.menuData.padding.value*graphics.get_screen_width()) + menu_configuration_features.sliderPadding.value = math.floor(stuff.menuData.padding.slider*graphics.get_screen_width()) + menu_configuration_features.sliderWidth.value = math.floor(stuff.menuData.slider.width*graphics.get_screen_width()) + menu_configuration_features.sliderHeight.value = math.floor(stuff.menuData.slider.height*graphics.get_screen_height()) + menu_configuration_features.sliderheightActive.value = math.floor(stuff.menuData.slider.heightActive*graphics.get_screen_height()) + menu_configuration_features.text_size.value = stuff.menuData.text_size_modifier + menu_configuration_features.footer_size.value = stuff.menuData.footer_size_modifier + menu_configuration_features.hint_size.value = stuff.menuData.hint_size_modifier + menu_configuration_features.text_y_offset.value = -math.floor(stuff.menuData.text_y_offset*graphics.get_screen_height()) + stuff.drawFeatParams.textOffset.y = stuff.menuData.text_y_offset + menu_configuration_features.footer_y_offset.value = math.floor(stuff.menuData.footer.footer_y_offset*graphics.get_screen_height()) + menu_configuration_features.border.value = math.floor(stuff.menuData.border*graphics.get_screen_height()) + menu_configuration_features.backgroundsize.value = stuff.menuData.background_sprite.size + menu_configuration_features.backgroundoffsetx.value = math.floor(stuff.menuData.background_sprite.offset.x*graphics.get_screen_width()) + menu_configuration_features.backgroundoffsety.value = math.floor(stuff.menuData.background_sprite.offset.y*graphics.get_screen_height()) + menu_configuration_features.footer_size.value = math.floor(stuff.menuData.footer.footer_size*graphics.get_screen_height()) + menu_configuration_features.footerPadding.value = math.floor(stuff.menuData.footer.padding*graphics.get_screen_width()) + menu_configuration_features.draw_footer.on = stuff.menuData.footer.draw_footer + menu_configuration_features.footer_pos_related_to_background.on = stuff.menuData.footer.footer_pos_related_to_background + --[[ menu_configuration_features.side_window_offsetx.value = math.floor(stuff.menuData.side_window.offset.x*graphics.get_screen_width()) + menu_configuration_features.side_window_offsety.value = math.floor(stuff.menuData.side_window.offset.y*graphics.get_screen_height()) + menu_configuration_features.side_window_spacing.value = math.floor(stuff.menuData.side_window.spacing*graphics.get_screen_height()) + menu_configuration_features.side_window_padding.value = math.floor(stuff.menuData.side_window.padding*graphics.get_screen_width()) + menu_configuration_features.side_window_width.value = math.floor(stuff.menuData.side_window.width*graphics.get_screen_width()) + menu_configuration_features.side_window_on.on = stuff.menuData.side_window.on ]] + menu_configuration_features.text_font.value = stuff.menuData.fonts.text + menu_configuration_features.footer_font.value = stuff.menuData.fonts.footer + menu_configuration_features.hint_font.value = stuff.menuData.fonts.hint - ---@return window - function cheeseUtils.new_side_window(header_text, pos, rect_color, rect_width, text_spacing, text_padding, text_color) - local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 + menu_configuration_features.hint_font:toggle() - local window = { - header_text = header_text or "", - header_on = header_text ~= "", - fields = {}, - fields_by_name = {}, - pos = pos or v2(), - rect_color = rect_color or 0xFF000000, - rect_width = rect_width or 0.2, - text_spacing = text_spacing or 0.047, - text_padding = text_padding or 0.01, - text_color = text_color or 0xFFFFFFFF, - header_height = 0.06125, - header_text_width = scriptdraw.get_text_size(header_text, text_size, 0).x, - hidden_fields = 0, - } + for k, v in pairs(stuff.menuData.color) do + if menu_configuration_features[k] then + if type(v) == "table" then + menu_configuration_features[k].r.value = v.r + menu_configuration_features[k].g.value = v.g + menu_configuration_features[k].b.value = v.b + menu_configuration_features[k].a.value = v.a + else + menu_configuration_features[k].r.value = func.convert_int_to_rgba(v, "r") + menu_configuration_features[k].g.value = func.convert_int_to_rgba(v, "g") + menu_configuration_features[k].b.value = func.convert_int_to_rgba(v, "b") + menu_configuration_features[k].a.value = func.convert_int_to_rgba(v, "a") + end + end + end - window.draw = draw_side_window - window.update = update - window.add_field = add_field - window.remove_field = remove_field - window.set_position = set_position - window.get_field_by_name = get_field_by_name - window.set_header_text = set_header_text - for name, func in pairs(set_functions) do - window['set_'..name] = func - end + for k, v in pairs(menu_configuration_features.headerfeat.str_data) do + if v == stuff.menuData.header then + menu_configuration_features.headerfeat.value = k - 1 + end + end - return window + if uiTable.background_sprite then + for k, v in pairs(menu_configuration_features.backgroundfeat.str_data) do + if v == uiTable.background_sprite.sprite then + menu_configuration_features.backgroundfeat.value = k - 1 + end + end + end + end end -end + stuff.drawFeatParams = { + rectPos = v2(stuff.menuData.pos_x, stuff.menuData.pos_y - stuff.menuData.feature_offset/2 + stuff.menuData.border), + textOffset = v2(stuff.menuData.feature_scale.x/2, -0.0055555555), + colorText = stuff.menuData.color.text, + textSize = 0, + } + function func.draw_feat(k, v, offset, hiddenOffset) + --[[ stuff.drawFeatParams.rectPos.x = stuff.menuData.pos_x + stuff.drawFeatParams.rectPos.y = stuff.menuData.pos_y - stuff.menuData.feature_offset/2 + stuff.menuData.border + stuff.drawFeatParams.textOffset.x = stuff.menuData.feature_scale.x/2 + stuff.drawFeatParams.textSize = textSize ]] + stuff.drawFeatParams.colorText = stuff.menuData.color.text + stuff.drawFeatParams.bottomLeft = stuff.menuData.color.feature_bottomLeft + stuff.drawFeatParams.topLeft = stuff.menuData.color.feature_topLeft + stuff.drawFeatParams.topRight = stuff.menuData.color.feature_topRight + stuff.drawFeatParams.bottomRight = stuff.menuData.color.feature_bottomRight + local posY = (stuff.drawFeatParams.rectPos.y + (stuff.menuData.feature_offset * k))*-2+1 --- Range Converter -do - local function convert_range(self, value) - return self.base_value + (value * self.step) - end - local Metatable = {__call = convert_range} - - function cheeseUtils.create_range_converter(original_range_min, original_range_max, convert_range_min, convert_range_max) - local stuff = {} + local is_selected + if stuff.scroll == k + stuff.drawScroll then + stuff.scrollHiddenOffset = hiddenOffset or stuff.scrollHiddenOffset + stuff.drawFeatParams.colorText = stuff.menuData.color.text_selected + stuff.drawFeatParams.bottomLeft = stuff.menuData.color.feature_selected_bottomLeft + stuff.drawFeatParams.topLeft = stuff.menuData.color.feature_selected_topLeft + stuff.drawFeatParams.topRight = stuff.menuData.color.feature_selected_topRight + stuff.drawFeatParams.bottomRight = stuff.menuData.color.feature_selected_bottomRight + is_selected = true + end + if offset == 0 then + local memv2 = cheeseUtils.memoize.v2 + local posX = stuff.drawFeatParams.rectPos.x*2-1 + --[[ scriptdraw.draw_rect( + cheeseUtils.memoize.v2(posX, posY), + cheeseUtils.memoize.v2(stuff.menuData.feature_scale.x*2, stuff.menuData.feature_scale.y*2), + func.convert_rgba_to_int(stuff.drawFeatParams.colorFeature.r, stuff.drawFeatParams.colorFeature.g, stuff.drawFeatParams.colorFeature.b, stuff.drawFeatParams.colorFeature.a) + ) ]] + local Left = posX - stuff.menuData.feature_scale.x + local Right = posX + stuff.menuData.feature_scale.x + local Top = posY + stuff.menuData.feature_scale.y + local Bottom = posY - stuff.menuData.feature_scale.y + scriptdraw.draw_rect_ext( + memv2(Left, Bottom), + memv2(Left, Top), + memv2(Right, Top), + memv2(Right, Bottom), + func.convert_rgba_to_int(stuff.drawFeatParams.bottomLeft.r, stuff.drawFeatParams.bottomLeft.g, stuff.drawFeatParams.bottomLeft.b, stuff.drawFeatParams.bottomLeft.a), + func.convert_rgba_to_int(stuff.drawFeatParams.topLeft.r, stuff.drawFeatParams.topLeft.g, stuff.drawFeatParams.topLeft.b, stuff.drawFeatParams.topLeft.a), + func.convert_rgba_to_int(stuff.drawFeatParams.topRight.r, stuff.drawFeatParams.topRight.g, stuff.drawFeatParams.topRight.b, stuff.drawFeatParams.topRight.a), + func.convert_rgba_to_int(stuff.drawFeatParams.bottomRight.r, stuff.drawFeatParams.bottomRight.g, stuff.drawFeatParams.bottomRight.b, stuff.drawFeatParams.bottomRight.a) + ) + end - local adjusted_max_original = original_range_max-original_range_min - local adjusted_max_convert = convert_range_max-convert_range_min + local font = stuff.menuData.fonts.text + if v.type & 1 == 0 then + scriptdraw.draw_text( + v["name"], + cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x - (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.name))*2-1, (stuff.drawFeatParams.rectPos.y + stuff.drawFeatParams.textOffset.y + (stuff.menuData.feature_offset * k))*-2+1), + cheeseUtils.memoize.v2(10, 10), + stuff.drawFeatParams.textSize, + func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a), + 0, font + ) + if v.type >> 11 & 1 ~= 0 then + scriptdraw.draw_text( + ">>", + cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x + (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.parent))*2-1, (stuff.drawFeatParams.rectPos.y + stuff.drawFeatParams.textOffset.y + (stuff.menuData.feature_offset * k))*-2+1), + cheeseUtils.memoize.v2(10, 10), + stuff.drawFeatParams.textSize, + func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a), + 16, font + ) + end + elseif v.type & 1 ~= 0 then -- toggle + cheeseUtils.draw_outline( + cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x - (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.name) + 0.00390625)*2-1, posY), + cheeseUtils.memoize.v2(0.015625, 0.0277777777778), + func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a), + 2 + ) + if v.real_on then + scriptdraw.draw_rect( + cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x - (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.name) + 0.00390625)*2-1, posY), + cheeseUtils.memoize.v2(0.0140625, 0.025), + func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a) + ) + end - stuff.base_value = (0-original_range_min)/adjusted_max_original*adjusted_max_convert+convert_range_min - stuff.step = (1-original_range_min)/adjusted_max_original*adjusted_max_convert+convert_range_min - stuff.base_value + scriptdraw.draw_text( + v.name, + cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x - (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.name) + 0.011328125)*2-1, (stuff.drawFeatParams.rectPos.y + stuff.drawFeatParams.textOffset.y + (stuff.menuData.feature_offset * k))*-2+1), + cheeseUtils.memoize.v2(10, 10), + stuff.drawFeatParams.textSize, + func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a), + 0, font + ) + end - setmetatable(stuff, Metatable) + if v.type >> 1 & 1 ~= 0 then -- value_i_f_str + local rounded_value = v.str_data and v.str_data[v.real_value + 1] or v.real_value + if v.type >> 7 & 1 ~= 0 or v.type >> 2 & 1 ~= 0 then + rounded_value = (rounded_value * 10000) + 0.5 + rounded_value = math.floor(rounded_value) + rounded_value = rounded_value / 10000 + end + if v.type >> 2 & 1 ~= 0 then + cheeseUtils.draw_slider( + cheeseUtils.memoize.v2( + (stuff.drawFeatParams.rectPos.x + stuff.menuData.feature_scale.x/2 - stuff.menuData.slider.width/4 - stuff.menuData.padding.slider)*2-1, + posY + ), + cheeseUtils.memoize.v2(stuff.menuData.slider.width, is_selected and stuff.menuData.slider.heightActive or stuff.menuData.slider.height), + v.min, v.max, v.value, + is_selected and func.convert_rgba_to_int(stuff.menuData.color.slider_selectedBackground) or func.convert_rgba_to_int(stuff.menuData.color.slider_background), + is_selected and func.convert_rgba_to_int(stuff.menuData.color.slider_selectedActive) or func.convert_rgba_to_int(stuff.menuData.color.slider_active), + is_selected and func.convert_rgba_to_int(stuff.menuData.color.slider_text) or 0, + is_selected) + else + local value_str = "< "..tostring(rounded_value).." >" + if v.str_data then + local pixel_size = scriptdraw.get_text_size(value_str, 1, font).x + local screenWidth = graphics.get_screen_width() + if pixel_size/screenWidth > 370/screenWidth then + local original_size = stuff.drawFeatParams.textSize + stuff.drawFeatParams.textSize = stuff.drawFeatParams.textSize * (370 / pixel_size * 0.8) + stuff.drawFeatParams.textSize = math.min(stuff.drawFeatParams.textSize + 0.2, original_size) + end + end - return stuff + scriptdraw.draw_text( + value_str, + cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x + (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.value) - scriptdraw.size_pixel_to_rel_x(scriptdraw.get_text_size(value_str, stuff.drawFeatParams.textSize, font).x)/4)*2-1, (stuff.drawFeatParams.rectPos.y + stuff.drawFeatParams.textOffset.y + (stuff.menuData.feature_offset * k))*-2+1), + cheeseUtils.memoize.v2(10, 10), + stuff.drawFeatParams.textSize, + func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a), + 0, font + ) + end + end end -end - --- Text Wrap -do - ---@param text string - ---@param font int - ---@param scale float - ---@param relWidth float - function cheeseUtils.wrap_text(text, font, scale, relWidth) - local spaceSize = scriptdraw.get_text_size(". .", scale, font).x - scriptdraw.get_text_size("..", scale, font).x - local lines = {} - for line, manualNewLines in text:gmatch("([^\r\n]+)([\r\n]*)") do - local newline - local lineSize = scriptdraw.get_text_size(line, scale, font) - if scriptdraw.size_pixel_to_rel_x(lineSize.x) > relWidth then - local length = 0 - newline = {} - for word in line:gmatch("[^%s-\\,]+[%s-\\,]*") do - local relx = scriptdraw.size_pixel_to_rel_x(scriptdraw.get_text_size(word, scale, font).x) - local spaceRelx = word:gsub("%S", "") - spaceRelx = scriptdraw.size_pixel_to_rel_x(#spaceRelx*spaceSize) - if length + relx > relWidth then - --print(word, length, relx) - newline[#newline+1] = "\n" - length = 0 - end - length = length + relx + spaceRelx - newline[#newline+1] = word + stuff.draw_current_menu = {frameCounter = 1, time = utils.time_ms() + 33, currentSprite = stuff.menuData.header} + function func.draw_current_menu() + local sprite = func.load_sprite(stuff.path.header..(stuff.menuData.header or "")) + if stuff.draw_current_menu.currentSprite ~= stuff.menuData.header then + stuff.draw_current_menu.currentSprite = stuff.menuData.header + stuff.draw_current_menu.time = 0 + stuff.draw_current_menu.frameCounter = 1 + if type(sprite) == "table" then + stuff.draw_current_menu.time = utils.time_ms() + (sprite[stuff.draw_current_menu.frameCounter].delay or sprite.constant_delay or 33) + end + end + stuff.drawHiddenOffset = 0 + for k, v in pairs(currentMenu) do + if type(k) == "number" then + if v.hidden or (v.type >> 11 & 1 ~= 0 and not v.on) then + stuff.drawHiddenOffset = stuff.drawHiddenOffset + 1 end - - line = table.concat(newline) end - - --print(line, scriptdraw.size_pixel_to_rel_x(scriptdraw.get_text_size(line, scale, font).x)) - lines[#lines+1] = line..(manualNewLines or "") + end + local background_sprite_path = stuff.path.background..(stuff.menuData.background_sprite.sprite or "") + if stuff.menuData.background_sprite.sprite and func.load_sprite(background_sprite_path) then + scriptdraw.draw_sprite( + func.load_sprite(background_sprite_path), + cheeseUtils.memoize.v2((stuff.menuData.pos_x + stuff.menuData.background_sprite.offset.x)*2-1, (stuff.menuData.pos_y+stuff.menuData.background_sprite.offset.y+stuff.menuData.height/2+0.01458)*-2+1), + stuff.menuData.background_sprite.size, + 0, + func.convert_rgba_to_int(255, 255, 255, stuff.menuData.color.background.a) + ) + else + scriptdraw.draw_rect( + cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, (stuff.menuData.pos_y+stuff.menuData.border+stuff.menuData.height/2)*-2+1), + cheeseUtils.memoize.v2(stuff.menuData.width*2, stuff.menuData.height*2), + func.convert_rgba_to_int(stuff.menuData.color.background.r, stuff.menuData.color.background.g, stuff.menuData.color.background.b, stuff.menuData.color.background.a) + ) + end + if #currentMenu - stuff.drawHiddenOffset >= stuff.menuData.max_features then + stuff.maxDrawScroll = #currentMenu - stuff.drawHiddenOffset - stuff.menuData.max_features + else + stuff.maxDrawScroll = 0 + end + if stuff.drawScroll > stuff.maxDrawScroll then + stuff.drawScroll = stuff.maxDrawScroll + end + if stuff.scroll > #currentMenu - stuff.drawHiddenOffset then + stuff.scroll = #currentMenu - stuff.drawHiddenOffset + elseif stuff.scroll < 1 and #currentMenu > 0 then + stuff.scroll = 1 end - return table.concat(lines) - end -end - -return cheeseUtils]=], - ["Get Input.lua"] = [=[--Made by GhostOne - -local cheeseUtils = require("cheesemenu.libs.CheeseUtilities") -local gginput = { - indicator_timer = utils.time_ms() + 750, - indicator = false, - drawStuff = { - cached_table_length = 0, - cached_text_width = 0, - } -} -gginput.char_codes = { - { - [0x30] = {"0", ")"}, - [0x31] = {"1", "!"}, - [0x32] = {"2", "@"}, - [0x33] = {"3", "#"}, - [0x34] = {"4", "$"}, - [0x35] = {"5", "%"}, - [0x36] = {"6", "^"}, - [0x37] = {"7", "&"}, - [0x38] = {"8", "*"}, - [0x39] = {"9", "("}, - [0x41] = {"a"}, - [0x42] = {"b"}, - [0x43] = {"c"}, - [0x44] = {"d"}, - [0x45] = {"e"}, - [0x46] = {"f"}, - [0x47] = {"g"}, - [0x48] = {"h"}, - [0x49] = {"i"}, - [0x4A] = {"j"}, - [0x4B] = {"k"}, - [0x4C] = {"l"}, - [0x4D] = {"m"}, - [0x4E] = {"n"}, - [0x4F] = {"o"}, - [0x50] = {"p"}, - [0x51] = {"q"}, - [0x52] = {"r"}, - [0x53] = {"s"}, - [0x54] = {"t"}, - [0x55] = {"u"}, - [0x56] = {"v"}, - [0x57] = {"w"}, - [0x58] = {"x"}, - [0x59] = {"y"}, - [0x5A] = {"z"}, - [0x60] = {"0", ")"}, - [0x61] = {"1", "!"}, - [0x62] = {"2", "@"}, - [0x63] = {"3", "#"}, - [0x64] = {"4", "$"}, - [0x65] = {"5", "%"}, - [0x66] = {"6", "^"}, - [0x67] = {"7", "&"}, - [0x68] = {"8", "*"}, - [0x69] = {"9", "("}, - [0x20] = {" "}, - [0xBA] = {";", ":"}, - [0xBB] = {"=", "+"}, - [0xBC] = {",", "<"}, - [0xBD] = {"-", "_"}, - [0xBE] = {".", ">"}, - [0xBF] = {"/", "?"}, - [0xC0] = {"`", "~"}, - [0xDB] = {"[", "{"}, - [0xDC] = {"\\", "|"}, - [0xDD] = {"]", "}"}, - [0xDE] = {"\'", "\""}, - [0x6A] = {"*"}, - [0x6B] = {"+"}, - [0x6D] = {"-"}, - [0x6E] = {"."}, - [0x6F] = {"/"} - }, - { - [0x41] = {"a"}, - [0x42] = {"b"}, - [0x43] = {"c"}, - [0x44] = {"d"}, - [0x45] = {"e"}, - [0x46] = {"f"}, - [0x47] = {"g"}, - [0x48] = {"h"}, - [0x49] = {"i"}, - [0x4A] = {"j"}, - [0x4B] = {"k"}, - [0x4C] = {"l"}, - [0x4D] = {"m"}, - [0x4E] = {"n"}, - [0x4F] = {"o"}, - [0x50] = {"p"}, - [0x51] = {"q"}, - [0x52] = {"r"}, - [0x53] = {"s"}, - [0x54] = {"t"}, - [0x55] = {"u"}, - [0x56] = {"v"}, - [0x57] = {"w"}, - [0x58] = {"x"}, - [0x59] = {"y"}, - [0x5A] = {"z"}, - }, - { - [0x41] = {"a"}, - [0x42] = {"b"}, - [0x43] = {"c"}, - [0x44] = {"d"}, - [0x45] = {"e"}, - [0x46] = {"f"}, - [0x47] = {"g"}, - [0x48] = {"h"}, - [0x49] = {"i"}, - [0x4A] = {"j"}, - [0x4B] = {"k"}, - [0x4C] = {"l"}, - [0x4D] = {"m"}, - [0x4E] = {"n"}, - [0x4F] = {"o"}, - [0x50] = {"p"}, - [0x51] = {"q"}, - [0x52] = {"r"}, - [0x53] = {"s"}, - [0x54] = {"t"}, - [0x55] = {"u"}, - [0x56] = {"v"}, - [0x57] = {"w"}, - [0x58] = {"x"}, - [0x59] = {"y"}, - [0x5A] = {"z"}, - [0x60] = {"0"}, - [0x61] = {"1"}, - [0x62] = {"2"}, - [0x63] = {"3"}, - [0x64] = {"4"}, - [0x65] = {"5"}, - [0x66] = {"6"}, - [0x67] = {"7"}, - [0x68] = {"8"}, - [0x69] = {"9"}, - [0x30] = {"0"}, - [0x31] = {"1"}, - [0x32] = {"2"}, - [0x33] = {"3"}, - [0x34] = {"4"}, - [0x35] = {"5"}, - [0x36] = {"6"}, - [0x37] = {"7"}, - [0x38] = {"8"}, - [0x39] = {"9"} - }, - { - [0xBD] = {"-"}, - [0x6D] = {"-"}, - [0x60] = {"0"}, - [0x61] = {"1"}, - [0x62] = {"2"}, - [0x63] = {"3"}, - [0x64] = {"4"}, - [0x65] = {"5"}, - [0x66] = {"6"}, - [0x67] = {"7"}, - [0x68] = {"8"}, - [0x69] = {"9"}, - [0x30] = {"0"}, - [0x31] = {"1"}, - [0x32] = {"2"}, - [0x33] = {"3"}, - [0x34] = {"4"}, - [0x35] = {"5"}, - [0x36] = {"6"}, - [0x37] = {"7"}, - [0x38] = {"8"}, - [0x39] = {"9"} - }, - { - [0xBD] = {"-"}, - [0x6D] = {"-"}, - [0x60] = {"0"}, - [0x61] = {"1"}, - [0x62] = {"2"}, - [0x63] = {"3"}, - [0x64] = {"4"}, - [0x65] = {"5"}, - [0x66] = {"6"}, - [0x67] = {"7"}, - [0x68] = {"8"}, - [0x69] = {"9"}, - [0x30] = {"0"}, - [0x31] = {"1"}, - [0x32] = {"2"}, - [0x33] = {"3"}, - [0x34] = {"4"}, - [0x35] = {"5"}, - [0x36] = {"6"}, - [0x37] = {"7"}, - [0x38] = {"8"}, - [0x39] = {"9"}, - [0x6E] = {"."}, - [0xBE] = {"."}, - }, - { - [0xBD] = {"-"}, - [0x6D] = {"-"}, - [0x60] = {"0"}, - [0x61] = {"1"}, - [0x62] = {"2"}, - [0x63] = {"3"}, - [0x64] = {"4"}, - [0x65] = {"5"}, - [0x66] = {"6"}, - [0x67] = {"7"}, - [0x68] = {"8"}, - [0x69] = {"9"}, - [0x30] = {"0"}, - [0x31] = {"1"}, - [0x32] = {"2"}, - [0x33] = {"3"}, - [0x34] = {"4"}, - [0x35] = {"5"}, - [0x36] = {"6"}, - [0x37] = {"7"}, - [0x38] = {"8"}, - [0x39] = {"9"}, - [0x6E] = {"."}, - [0xBE] = {"."}, - }, -} - ---Functions + -- header border + scriptdraw.draw_rect(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, (stuff.menuData.pos_y + stuff.menuData.border/2)*-2+1), cheeseUtils.memoize.v2(stuff.menuData.width*2, stuff.menuData.border*2), func.convert_rgba_to_int(stuff.menuData.color.border.r, stuff.menuData.color.border.g, stuff.menuData.color.border.b, stuff.menuData.color.border.a)) - function gginput.do_key(key, pressed, funcPressed, ...) - if cheeseUtils.get_key(key):is_down() and ((utils.time_ms() > pressed[key]) or (pressed[key] == 0)) then - funcPressed(...) - if pressed[key] == 0 then - pressed[key] = utils.time_ms() + 500 + local hiddenOffset = 0 + local drawnfeats = 0 + stuff.menuData.text_size = (((graphics.get_screen_width()*graphics.get_screen_height())/3686400)*0.45+0.25) -- * stuff.menuData.text_size_modifier + + stuff.drawFeatParams.rectPos.x = stuff.menuData.pos_x + stuff.drawFeatParams.rectPos.y = stuff.menuData.pos_y - stuff.menuData.feature_offset/2 + stuff.menuData.border + stuff.drawFeatParams.textOffset.x = stuff.menuData.feature_scale.x/2 + stuff.drawFeatParams.colorText = stuff.menuData.color.text + stuff.drawFeatParams.colorFeature = stuff.menuData.color.feature + stuff.drawFeatParams.textSize = stuff.menuData.text_size * stuff.menuData.text_size_modifier + + for k, v in ipairs(currentMenu) do + if type(k) == "number" then + if v.hidden or (v.type >> 11 & 1 ~= 0 and not v.on) then + hiddenOffset = hiddenOffset + 1 + elseif k <= stuff.drawScroll + hiddenOffset + stuff.menuData.max_features and k >= stuff.drawScroll + hiddenOffset + 1 then + func.draw_feat(k - stuff.drawScroll - hiddenOffset, v, 0, hiddenOffset) + drawnfeats = drawnfeats + 1 + end + end + end + + if stuff.menuData.footer.draw_footer then + -- footer border + local footer_border_y_pos + if stuff.menuData.footer.footer_pos_related_to_background then + footer_border_y_pos = (stuff.menuData.pos_y + stuff.menuData.height + stuff.menuData.border*1.5)*-2+1 else - pressed[key] = utils.time_ms() + 30 + footer_border_y_pos = (stuff.menuData.pos_y + (drawnfeats*stuff.menuData.feature_offset) + stuff.menuData.border*1.5)*-2+1 end - elseif not cheeseUtils.get_key(key):is_down() then - pressed[key] = 0 + scriptdraw.draw_rect(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, footer_border_y_pos), cheeseUtils.memoize.v2(stuff.menuData.width*2, stuff.menuData.border*2), func.convert_rgba_to_int(stuff.menuData.color.border.r, stuff.menuData.color.border.g, stuff.menuData.color.border.b, stuff.menuData.color.border.a)) + + -- footer and text/scroll + local footerColor = func.convert_rgba_to_int(stuff.menuData.color.footer.r, stuff.menuData.color.footer.g, stuff.menuData.color.footer.b, stuff.menuData.color.footer.a) + local footer_y_pos + if stuff.menuData.footer.footer_pos_related_to_background then + footer_y_pos = (stuff.menuData.pos_y + stuff.menuData.height + stuff.menuData.border*2 + stuff.menuData.footer.footer_size/2)*-2+1 + else + footer_y_pos = (stuff.menuData.pos_y + (drawnfeats*stuff.menuData.feature_offset) + stuff.menuData.border*2 + stuff.menuData.footer.footer_size/2)*-2+1 + end + scriptdraw.draw_rect(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, footer_y_pos), cheeseUtils.memoize.v2(stuff.menuData.width*2, stuff.menuData.footer.footer_size*2), footerColor) + + local footerTextColor = func.convert_rgba_to_int(stuff.menuData.color.footer_text.r, stuff.menuData.color.footer_text.g, stuff.menuData.color.footer_text.b, stuff.menuData.color.footer_text.a) + local feat = currentMenu[stuff.scroll + stuff.scrollHiddenOffset] + local featHint = feat.type >> 15 & 1 ~= 0 and stuff.player_feature_hints[feat.id] or stuff.feature_hints[feat.id] + if featHint then + local padding = scriptdraw.size_pixel_to_rel_y(5) + local hintStrSize = scriptdraw.size_pixel_to_rel_y(featHint.size.y) * (stuff.menuData.text_size * stuff.menuData.hint_size_modifier) + local posY = footer_y_pos - stuff.menuData.border*2 - stuff.menuData.footer.footer_size - padding + local textY = posY - padding + posY = posY - hintStrSize/2 + + local rectHeight = hintStrSize+padding*4 + --scriptdraw.draw_rect(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, posY+rectHalfHeight/2), cheeseUtils.memoize.v2(stuff.menuData.width*2, rectHalfHeight), func.convert_rgba_to_int(stuff.menuData.color.footer.r, stuff.menuData.color.footer.g, stuff.menuData.color.footer.b, stuff.menuData.color.footer.a)) + cheeseUtils.draw_rect_ext_wh(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, posY-padding), cheeseUtils.memoize.v2(stuff.menuData.width*2, rectHeight), (footerColor & 0xffffff) | 50 << 24, footerColor, footerColor, (footerColor & 0xffffff) | 50 << 24) + scriptdraw.draw_text( + featHint.str, + cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1 - stuff.menuData.width + padding, textY), + cheeseUtils.memoize.v2(stuff.menuData.width+padding*2, 2), + stuff.menuData.text_size * stuff.menuData.hint_size_modifier, + footerTextColor, + 0, + stuff.menuData.fonts.hint + ) + end + + local footer_size = stuff.menuData.text_size * stuff.menuData.footer_size_modifier + local text_y_pos = footer_y_pos + 0.011111111 + stuff.menuData.footer.footer_y_offset + scriptdraw.draw_text( + tostring(stuff.menuData.footer.footer_text), + cheeseUtils.memoize.v2((stuff.menuData.pos_x - stuff.menuData.width/2 + stuff.menuData.footer.padding)*2-1, text_y_pos), + cheeseUtils.memoize.v2(2, 2), + footer_size, + footerTextColor, + 0, + stuff.menuData.fonts.footer + ) + + scriptdraw.draw_text( + tostring(stuff.scroll.." / "..(#currentMenu - stuff.drawHiddenOffset)), + cheeseUtils.memoize.v2((stuff.menuData.pos_x + stuff.menuData.width/2 - stuff.menuData.footer.padding)*2-1, text_y_pos), + cheeseUtils.memoize.v2(2, 2), + footer_size, + footerTextColor, + 16, + stuff.menuData.fonts.footer + ) + end + + if type(sprite) == "table" then + if not sprite[stuff.draw_current_menu.frameCounter] then + stuff.draw_current_menu.frameCounter = 1 + end + if utils.time_ms() > stuff.draw_current_menu.time then + if stuff.draw_current_menu.frameCounter < #sprite then + stuff.draw_current_menu.frameCounter = stuff.draw_current_menu.frameCounter + 1 + else + stuff.draw_current_menu.frameCounter = 1 + end + stuff.draw_current_menu.time = utils.time_ms() + (sprite[stuff.draw_current_menu.frameCounter].delay or sprite.constant_delay or 33) + end + sprite = sprite[stuff.draw_current_menu.frameCounter].sprite + end + if sprite then + local size = ((2.56 * stuff.menuData.width) * (1000 / scriptdraw.get_sprite_size(sprite).x)) / (2560 / graphics.get_screen_width()) + scriptdraw.draw_sprite(sprite, cheeseUtils.memoize.v2(stuff.menuData.pos_x * 2 - 1, ((stuff.menuData.pos_y+stuff.menuData.height/2) - (stuff.menuData.height/2 + ((scriptdraw.get_sprite_size(sprite).y*size)/2)/graphics.get_screen_height()))*-2+1), size, 0, stuff.menuData.color.sprite) + end + system.wait(0) + end + + --[[ + example of table_of_lines: + { + {"leftside", "rightside"}, + {"IP", "ddosing u rn"}, + {"Cheesus", "Christ"} + } + has to be in this structure, you can add more than three + ]] + function func.draw_side_window(header_text, table_of_lines, v2pos, rect_color, rect_width, text_spacing, text_padding, text_color) + text_color = text_color or 0xFFFFFFFF + assert( + type(header_text) == "string" + and type(table_of_lines) == "table" + and type(v2pos) == "userdata" + and type(rect_color) == "number" + and type(rect_width) == "number" + and type(text_spacing) == "number" + and type(text_padding) == "number" + and type(text_color) == "number", + "one or more draw_side_window args were invalid" + ) + local rect_height = #table_of_lines*text_spacing+0.07125 + v2pos.y = v2pos.y-(rect_height/2) + + + scriptdraw.draw_rect(v2pos, cheeseUtils.memoize.v2(rect_width, rect_height), rect_color) + + local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 + -- Header text + scriptdraw.draw_text(header_text, cheeseUtils.memoize.v2(v2pos.x - scriptdraw.get_text_size(header_text, text_size, 0).x/graphics.get_screen_width(), v2pos.y+(rect_height/2)-0.015), cheeseUtils.memoize.v2(2, 2), text_size, text_color, 0, 0) + -- table_of_lines + for k, v in ipairs(table_of_lines) do + v[1] = tostring(v[1]) + v[2] = tostring(v[2]) + local pos_y = v2pos.y-k*text_spacing+rect_height/2-0.03 + scriptdraw.draw_text(v[1], cheeseUtils.memoize.v2(v2pos.x-rect_width/2+text_padding, pos_y), cheeseUtils.memoize.v2(2, 2), text_size, text_color, 0, 2) + scriptdraw.draw_text(v[2], cheeseUtils.memoize.v2(v2pos.x+rect_width/2-text_padding, pos_y), cheeseUtils.memoize.v2(2, 2), text_size, text_color, 16, 2) end end - --[[ function gginput.draw_outline(v2pos, v2size, color, thickness, reusablePos, reusablePos2) - local thickness_y = thickness / graphics.get_screen_height() * 2 - local thickness_x = thickness / graphics.get_screen_width() * 2 + --Hotkey functions + function func.get_hotkey(keyTable, vkTable, singlekey) + local current_key + local excludedkeys = {} + while not keyTable[1] do + if cheeseUtils.get_key(0x1B):is_down() then + return "escaped" + end + for k, v in pairs(stuff.char_codes) do + if cheeseUtils.get_key(v):is_down() then + if v ~= 0x0D or singlekey then + if v ~= 0xA0 and v ~= 0xA1 and v ~= 0xA2 and v ~= 0xA3 and v ~= 0xA4 and v ~= 0xA5 and not singlekey then + keyTable[1] = "NOMOD" + end + if singlekey then + return k, v + else + keyTable[#keyTable + 1] = k + vkTable[#vkTable+1] = v + current_key = v + excludedkeys[v] = true + end + end + end + end + system.wait(0) + end - reusablePos2.x, reusablePos2.y = v2pos.x, v2pos.y + if not singlekey then + while cheeseUtils.get_key(current_key):is_down() do + for k, v in pairs(stuff.char_codes) do + if cheeseUtils.get_key(v):is_down() and not excludedkeys[v] and v ~= 0xA0 and v ~= 0xA1 and v ~= 0xA2 and v ~= 0xA3 and v ~= 0xA4 and v ~= 0xA5 then + excludedkeys[v] = true + keyTable[#keyTable + 1] = k + vkTable[#vkTable+1] = v + end + end + system.wait(0) + end - reusablePos2.y = v2pos.y - (v2size.y/2) - reusablePos.x, reusablePos.y = v2size.x + thickness_x, thickness_y - scriptdraw.draw_rect(reusablePos2, reusablePos, color) + while not cheeseUtils.get_key(0x1B):is_down() and not cheeseUtils.get_key(0x0D):is_down() do + for k, v in pairs(stuff.char_codes) do + if cheeseUtils.get_key(v):is_down() then + return false + end + end + system.wait(0) + end - reusablePos2.y = v2pos.y + (v2size.y/2) - scriptdraw.draw_rect(reusablePos2, reusablePos, color) + return cheeseUtils.get_key(0x0D):is_down() or "escaped" + end + end + + function func.draw_hotkey(keyTable) + while true do + for i = 0, 360 do + controls.disable_control_action(0, i, true) + end + local concatenated = table.concat(keyTable, "+") + scriptdraw.draw_rect(cheeseUtils.memoize.v2(0, 0), cheeseUtils.memoize.v2(2, 2), 0x7D000000) + scriptdraw.draw_text(concatenated, cheeseUtils.memoize.v2(-(scriptdraw.get_text_size(concatenated, 1, 0).x/graphics.get_screen_width())), cheeseUtils.memoize.v2(2, 2), 1, 0xffffffff, 1 << 1, 0) + system.wait(0) + end + end + + + function func.start_hotkey_process(feat) + stuff.menuData.menuToggle = false + local keyTable = {} + local vkTable = {} + + local drawThread = menu.create_thread(func.draw_hotkey, keyTable) + + while cheeseUtils.get_key(stuff.vkcontrols.setHotkey):is_down() do + system.wait(0) + end + + local response + repeat + response = func.get_hotkey(keyTable, vkTable) + if not response then + for k, v in pairs(keyTable) do + keyTable[k] = nil + end + for k, v in pairs(vkTable) do + vkTable[k] = nil + end + end + until response - reusablePos2.y = v2pos.y - reusablePos2.x = v2pos.x - (v2size.x/2) - reusablePos.x, reusablePos.y = thickness_x, v2size.y - thickness_y - scriptdraw.draw_rect(reusablePos2, reusablePos, color) + local keyString = table.concat(keyTable, "|") - reusablePos2.x = v2pos.x + (v2size.x/2) - - scriptdraw.draw_rect(reusablePos2, reusablePos, color) - end ]] + if response ~= "escaped" then + stuff.hotkeys_to_vk[keyString] = vkTable + if not stuff.hotkeys[keyString] then + stuff.hotkeys[keyString] = {} + end + stuff.hotkeys[keyString][feat.hierarchy_key] = true + feat.hotkey = keyString + gltw.write(stuff.hotkeys, "hotkeys", stuff.path.hotkeys, nil, true) + end - function gginput.draw_input(inputTable, bg_color, inputbox_color, outline_color, text_color, tableOfPos_Size) - if #inputTable.string ~= gginput.drawStuff.cached_table_length then - gginput.drawStuff.string = table.concat(inputTable.string) - gginput.drawStuff.indicator_string = gginput.drawStuff.string:sub(1, inputTable.cursor-1).."_"..gginput.drawStuff.string:sub(inputTable.cursor+1, #gginput.drawStuff.string) - gginput.drawStuff.cached_text_width = scriptdraw.get_text_size(gginput.drawStuff.string:sub(1, inputTable.cursor-1):gsub(" ", "."), gginput.drawStuff.text_size).x/graphics.get_screen_width()*2 - gginput.drawStuff.cached_table_length = #inputTable.string + menu.delete_thread(drawThread) + while cheeseUtils.get_key(0x0D):is_down() or cheeseUtils.get_key(0x1B):is_down() do -- enter and esc + controls.disable_control_action(0, 200, true) + system.wait(0) end - local drawString = gginput.indicator and gginput.drawStuff.indicator_string or gginput.drawStuff.string - --[[ if gginput.indicator then - gginput.drawStuff.string = gginput.drawStuff.string:sub(1, inputTable.cursor-1).."_"..gginput.drawStuff.string:sub(inputTable.cursor+1, #gginput.drawStuff.string) - end ]] + controls.disable_control_action(0, 200, true) + func.toggle_menu(true) + return response ~= "escaped" and response + end - scriptdraw.draw_rect(tableOfPos_Size.middle_pos, tableOfPos_Size.backround_size, bg_color) -- background - cheeseUtils.draw_outline(tableOfPos_Size.middle_pos, tableOfPos_Size.outline_size, outline_color, 2) - scriptdraw.draw_rect(tableOfPos_Size.middle_pos, tableOfPos_Size.inputBox_size, inputbox_color) -- inputBox - scriptdraw.draw_text(drawString, tableOfPos_Size.text_pos, tableOfPos_Size.backround_size, gginput.drawStuff.text_size, text_color, 0) - scriptdraw.draw_text(inputTable.title, tableOfPos_Size.title_pos, tableOfPos_Size.backround_size, gginput.drawStuff.text_size+0.4, 0xDC000000 | (text_color & 0xFFFFFF), 0) + --End of functions - tableOfPos_Size.underscore_pos.x = -0.4609375 + gginput.drawStuff.cached_text_width + 0.0015625 - scriptdraw.draw_text("_", tableOfPos_Size.underscore_pos, tableOfPos_Size.backround_size, gginput.drawStuff.text_size, 0x64000000 | (text_color & 0xFFFFFF), 0) - end + --threads + menu.create_thread(function() + local side_window_pos = v2((stuff.menuData.pos_x + stuff.menuData.width + stuff.menuData.side_window.offset.x)*2-1, (stuff.menuData.pos_y + stuff.menuData.side_window.offset.y)*-2+1) + while true do + if stuff.menuData.menuToggle then + func.draw_current_menu() + if currentMenu and stuff.menuData.side_window.on then + local pid = currentMenu.pid + if not pid and currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then + pid = currentMenu[stuff.scroll + stuff.scrollHiddenOffset].pid + end + if pid and pid ~= stuff.pid then + if not stuff.playerIds[pid].hidden then + stuff.player_info[1][2] = tostring(pid) + stuff.player_info[10][2] = func.convert_int_ip(player.get_player_ip(pid)) + stuff.player_info[11][2] = tostring(player.get_player_scid(pid)) + stuff.player_info[12][2] = string.format("%X", player.get_player_host_token(pid)) + stuff.player_info.max_health = "/"..math.floor(player.get_player_max_health(pid)) + stuff.player_info.name = tostring(player.get_player_name(pid)) + stuff.pid = pid + end + end + if pid then + side_window_pos.x, side_window_pos.y = (stuff.menuData.pos_x + stuff.menuData.width + stuff.menuData.side_window.offset.x)*2-1, (stuff.menuData.pos_y + stuff.menuData.side_window.offset.y)*-2+1 + native.call(0xBE8CD9BE829BBEBF, player.get_player_ped(stuff.pid), stuff.proofs.bulletProof, stuff.proofs.fireProof, stuff.proofs.explosionProof, stuff.proofs.collisionProof, stuff.proofs.meleeProof, stuff.proofs.steamProof, stuff.proofs.p7, stuff.proofs.drownProof) + stuff.player_info[2][2] = player.is_player_god(stuff.pid) and "Yes" or "No" + stuff.player_info[3][2] = (stuff.proofs.bulletProof:__tointeger()|stuff.proofs.fireProof:__tointeger()|stuff.proofs.explosionProof:__tointeger()|stuff.proofs.collisionProof:__tointeger()|stuff.proofs.meleeProof:__tointeger()|stuff.proofs.steamProof:__tointeger()|stuff.proofs.p7:__tointeger()|stuff.proofs.drownProof:__tointeger()) == 1 and "Yes" or "No" + stuff.player_info[4][2] = player.is_player_vehicle_god(stuff.pid) and "Yes" or "No" + stuff.player_info[5][2] = player.is_player_modder(stuff.pid, -1) and "Yes" or "No" + stuff.player_info[6][2] = player.is_player_host(stuff.pid) and "Yes" or "No" + stuff.player_info[7][2] = player.get_player_wanted_level(stuff.pid) + stuff.player_info[8][2] = math.floor(player.get_player_health(stuff.pid))..stuff.player_info.max_health + stuff.player_info[9][2] = math.floor(player.get_player_armour(stuff.pid)).."/50" + stuff.player_info[13][2] = player.get_player_host_priority(stuff.pid) + func.draw_side_window( + stuff.player_info.name, + stuff.player_info, + side_window_pos, + func.convert_rgba_to_int(stuff.menuData.color.side_window.r, stuff.menuData.color.side_window.g, stuff.menuData.color.side_window.b, stuff.menuData.color.side_window.a), + stuff.menuData.side_window.width, stuff.menuData.side_window.spacing, stuff.menuData.side_window.padding, + func.convert_rgba_to_int(stuff.menuData.color.side_window_text.r, stuff.menuData.color.side_window_text.g, stuff.menuData.color.side_window_text.b, stuff.menuData.color.side_window_text.a) + ) + end + end + if stuff.old_selected ~= currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then + if type(stuff.old_selected) == "table" then + stuff.old_selected:activate_hl_func() + end + if currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then + currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() + end + stuff.old_selected = currentMenu[stuff.scroll + stuff.scrollHiddenOffset] + end + controls.disable_control_action(0, 172, true) + controls.disable_control_action(0, 27, true) + else + system.wait(0) + end + end + end, nil) - gginput.tableOfPos_Size = { - middle_pos = v2(0, 0), - backround_size = v2(2, 2), - outline_size = v2(0.9390625, 0.06180555555555), - inputBox_size = v2(0.9375, 0.0590277777777778), - text_pos = v2(-0.4609375, 0.01111111111111111), - underscore_pos = v2(0, 0.01111111111111111), - title_pos = v2(0, 0.10555554), - } - function gginput.draw_thread(inputTable) - gginput.tableOfPos_Size.title_pos.x = -scriptdraw.get_text_size(inputTable.title, gginput.drawStuff.text_size+0.4).x/graphics.get_screen_width() + menu.create_thread(function() while true do - for i = 0, 357 do - controls.disable_control_action(0, i, true) + stuff.menuData.menuNav = native.call(0x5FCF4D7069B09026):__tointeger() ~= 1 and not (stuff.menuData.chatBoxOpen or input.is_open() --[[or console.on]]) + if stuff.menuData.menuNav then + func.do_key(500, stuff.vkcontrols.open, false, function() -- F4 + func.toggle_menu(not stuff.menuData.menuToggle) + end) end - if utils.time_ms() > gginput.indicator_timer then - gginput.indicator = not gginput.indicator - gginput.indicator_timer = utils.time_ms() + 750 + if currentMenu.hidden or not currentMenu then + currentMenu = stuff.previousMenus[#stuff.previousMenus].menu + stuff.scroll = stuff.previousMenus[#stuff.previousMenus].scroll + stuff.drawScroll = stuff.previousMenus[#stuff.previousMenus].drawScroll + stuff.scrollHiddenOffset = stuff.previousMenus[#stuff.previousMenus].scrollHiddenOffset + stuff.previousMenus[#stuff.previousMenus] = nil + end + local pid = player.player_id() + stuff.playerIds[pid].name = player.get_player_name(pid).." [Y]" + if stuff.playerIds[pid].hidden then + stuff.playerIds[pid].hidden = false + func.reset_player_submenu(pid) + end + system.wait(0) + end + end, nil) + menu.create_thread(function() + while true do + system.wait(0) + if stuff.menuData.menuToggle and stuff.menuData.menuNav then + func.do_key(500, stuff.vkcontrols.setHotkey, false, function() -- F11 + if cheeseUtils.get_key(0x10):is_down() and stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey] then + stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey][currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hierarchy_key] = nil + if not next(stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey]) then + stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey] = nil + end + currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey = nil + gltw.write(stuff.hotkeys, "hotkeys", stuff.path.hotkeys, nil, true) + menu.notify("Removed "..currentMenu[stuff.scroll + stuff.scrollHiddenOffset].name.."'s hotkey") + elseif cheeseUtils.get_key(0x11):is_down() then + menu.notify(currentMenu[stuff.scroll + stuff.scrollHiddenOffset].name.."'s hotkey is "..(currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey or "none")) + elseif not cheeseUtils.get_key(0x10):is_down() and not cheeseUtils.get_key(0x11):is_down() then + if stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey] then + stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey][currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hierarchy_key] = nil + end + if func.start_hotkey_process(currentMenu[stuff.scroll + stuff.scrollHiddenOffset]) then + menu.notify("Set "..currentMenu[stuff.scroll + stuff.scrollHiddenOffset].name.."'s hotkey to "..currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey) + end + end + end) + end + end + end,nil) + menu.create_thread(function() + while true do + system.wait(0) + if stuff.menuData.menuToggle and stuff.menuData.menuNav then + func.do_key(500, stuff.vkcontrols.down, true, function() -- downKey + --[[ local old_scroll = stuff.scroll + stuff.scrollHiddenOffset ]] + if stuff.scroll + stuff.drawHiddenOffset >= #currentMenu and #currentMenu - stuff.drawHiddenOffset > 1 then + stuff.scroll = 1 + stuff.drawScroll = 0 + elseif #currentMenu - stuff.drawHiddenOffset > 1 then + stuff.scroll = stuff.scroll + 1 + if stuff.scroll - stuff.drawScroll >= (stuff.menuData.max_features - 1) and stuff.drawScroll < stuff.maxDrawScroll then + stuff.drawScroll = stuff.drawScroll + 1 + end + end + --[[ if old_scroll ~= (stuff.scroll + stuff.scrollHiddenOffset) then + currentMenu[old_scroll]:activate_hl_func() + if currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then + currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() + end + end ]] + end) + end + end + end, nil) + menu.create_thread(function() + while true do + system.wait(0) + if stuff.menuData.menuToggle and stuff.menuData.menuNav then + func.do_key(500, stuff.vkcontrols.up, true, function() -- upKey + --[[ local old_scroll = stuff.scroll + stuff.scrollHiddenOffset ]] + if stuff.scroll <= 1 and #currentMenu - stuff.drawHiddenOffset > 1 then + stuff.scroll = #currentMenu + stuff.drawScroll = stuff.maxDrawScroll + elseif #currentMenu - stuff.drawHiddenOffset > 1 then + stuff.scroll = stuff.scroll - 1 + if stuff.scroll - stuff.drawScroll <= 2 and stuff.drawScroll > 0 then + stuff.drawScroll = stuff.drawScroll - 1 + end + end + --[[ if old_scroll ~= (stuff.scroll + stuff.scrollHiddenOffset) then + currentMenu[old_scroll]:activate_hl_func() + if currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then + currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() + end + end ]] + end) + end + end + end,nil) + menu.create_thread(function() + while true do + system.wait(0) + if stuff.menuData.menuToggle and stuff.menuData.menuNav then + func.do_key(500, stuff.vkcontrols.select, true, function() --enter + local feat = currentMenu[stuff.scroll + stuff.scrollHiddenOffset] + if feat then + if cheeseUtils.get_key(stuff.vkcontrols.specialKey):is_down() and feat.type >> 5 & 1 ~= 0 then + menu.create_thread(func.selector, feat) + elseif feat.type >> 11 & 1 ~= 0 and not feat.hidden then + --feat:activate_hl_func() + stuff.previousMenus[#stuff.previousMenus + 1] = {menu = currentMenu, scroll = stuff.scroll, drawScroll = stuff.drawScroll, scrollHiddenOffset = stuff.scrollHiddenOffset} + currentMenu = feat + currentMenu:activate_feat_func() + stuff.scroll = 1 + system.wait(0) + stuff.drawScroll = 0 + stuff.scrollHiddenOffset = 0 + --[[ if feat then + feat:activate_hl_func() + end ]] + while cheeseUtils.get_key(stuff.vkcontrols.select):is_down() do + system.wait(0) + end + elseif feat.type & 1536 ~= 0 and not feat.hidden then + feat:activate_feat_func() + elseif feat.type & 1 ~= 0 and not feat.hidden then + feat.real_on = not feat.real_on + feat:activate_feat_func() + end + else + system.wait(100) + end + end) end - gginput.draw_input(inputTable, 0x64000000, 0xC8000000, 0xC8FFFFFF, 0xC8FFFFFF, gginput.tableOfPos_Size) - system.wait(0) end - end - - function gginput.disableESC() - while cheeseUtils.get_key(0x1B):is_down() do - controls.disable_control_action(0, 200, true) + end, nil) + menu.create_thread(function() + while true do system.wait(0) + if stuff.menuData.menuToggle and stuff.menuData.menuNav then + func.do_key(500, stuff.vkcontrols.back, false, function() --backspace + if stuff.previousMenus[#stuff.previousMenus] then + --[[ if currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then + currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() + end ]] + currentMenu = stuff.previousMenus[#stuff.previousMenus].menu + stuff.scroll = stuff.previousMenus[#stuff.previousMenus].scroll + stuff.drawScroll = stuff.previousMenus[#stuff.previousMenus].drawScroll + stuff.scrollHiddenOffset = stuff.previousMenus[#stuff.previousMenus].scrollHiddenOffset + stuff.previousMenus[#stuff.previousMenus] = nil + --currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() + end + end) + end end - controls.disable_control_action(0, 200, true) - end - - function gginput.moveCursorRight(inputTable, moveAmount) - if cheeseUtils.get_key(0x11):is_down() then - for i = inputTable.cursor+1, #inputTable.string do - if inputTable.string[i] == " " then - if i == inputTable.cursor+1 then - for i = inputTable.cursor+1, #inputTable.string do - if inputTable.string[i] ~= " " then - inputTable.cursor = i-1 - break - elseif i == #inputTable.string then - inputTable.cursor = #inputTable.string + end, nil) + menu.create_thread(function() + while true do + system.wait(0) + if stuff.menuData.menuToggle and stuff.menuData.menuNav then + func.do_key(500, stuff.vkcontrols.left, true, function() -- left + local feat = currentMenu[stuff.scroll + stuff.scrollHiddenOffset] + if feat then + if feat.value then + if feat.str_data then + if feat.value <= 0 then + feat.value = #feat.str_data - 1 + else + feat.value = feat.value - 1 + end + else + if tonumber(feat.value) <= feat.min and feat.type >> 2 & 1 == 0 then + feat.value = feat.max + else + feat.value = tonumber(feat.value) - feat.mod + end + end + end + if feat.type then + if feat.type >> 10 & 1 ~= 0 or (feat.type & 3 == 3 and feat.on) then + feat:activate_feat_func() end end - else - inputTable.cursor = i-1 end - break - elseif i == #inputTable.string then - inputTable.cursor = #inputTable.string - end + end) end - elseif not (inputTable.cursor >= #inputTable.string) then - inputTable.cursor = inputTable.cursor + moveAmount end - gginput.drawStuff.indicator_string = gginput.drawStuff.string:sub(1, inputTable.cursor-1).."_"..gginput.drawStuff.string:sub(inputTable.cursor+1, #gginput.drawStuff.string) - gginput.drawStuff.cached_text_width = scriptdraw.get_text_size(gginput.drawStuff.string:sub(1, inputTable.cursor-1):gsub(" ", "."), gginput.drawStuff.text_size).x/graphics.get_screen_width()*2 - end - function gginput.moveCursorLeft(inputTable, moveAmount) - if cheeseUtils.get_key(0x11):is_down() then - for i = inputTable.cursor, 2, -1 do - if inputTable.string[i] == " " then - if i == inputTable.cursor then - for i = inputTable.cursor, 2, -1 do - if inputTable.string[i] ~= " " then - inputTable.cursor = i - break - elseif i == 2 then - inputTable.cursor = 1 + end, nil) + menu.create_thread(function() + while true do + if stuff.menuData.menuToggle and stuff.menuData.menuNav then + func.do_key(500, stuff.vkcontrols.right, true, function() -- right + local feat = currentMenu[stuff.scroll + stuff.scrollHiddenOffset] + if feat then + if feat.value then + if feat.str_data then + if tonumber(feat.value) >= tonumber(#feat.str_data) - 1 then + feat.value = 0 + else + feat.value = feat.value + 1 + end + else + if tonumber(feat.value) >= feat.max and feat.type >> 2 & 1 == 0 then + feat.value = feat.min + else + feat.value = tonumber(feat.value) + feat.mod + end + end + end + if feat.type then + if feat.type >> 10 & 1 ~= 0 or (feat.type & 3 == 3 and feat.on) then + feat:activate_feat_func() end end - else - inputTable.cursor = i end - break - elseif i == 2 then - inputTable.cursor = 1 - end - end - elseif not (inputTable.cursor <= 1) then - inputTable.cursor = inputTable.cursor - moveAmount - end - gginput.drawStuff.indicator_string = gginput.drawStuff.string:sub(1, inputTable.cursor-1).."_"..gginput.drawStuff.string:sub(inputTable.cursor+1, #gginput.drawStuff.string) - gginput.drawStuff.cached_text_width = scriptdraw.get_text_size(gginput.drawStuff.string:sub(1, inputTable.cursor-1):gsub(" ", "."), gginput.drawStuff.text_size).x/graphics.get_screen_width()*2 - end - - function gginput.write_char(keyTable, inputTable) - if cheeseUtils.get_key(0x10):is_down() then - if inputTable.cursor == #inputTable.string then - inputTable.string[#inputTable.string+1] = keyTable[2] or keyTable[1]:upper() - else - table.insert(inputTable.string, inputTable.cursor+1, keyTable[2] or keyTable[1]:upper()) - end - else - if inputTable.cursor == #inputTable.string then - inputTable.string[#inputTable.string+1] = keyTable[1] - else - table.insert(inputTable.string, inputTable.cursor+1, keyTable[1]) + end) end + system.wait(0) end + end, nil) - gginput.moveCursorRight(inputTable, 1) - end - function gginput.paste(stringInput, inputTable) - stringInput = tostring(stringInput) - if inputTable.cursor == #inputTable.string then - for char in stringInput:gmatch(".") do - if #inputTable.string-1 ~= inputTable.limit then - inputTable.string[#inputTable.string+1] = char - end - end - inputTable.cursor = #inputTable.string - else - for char in stringInput:gmatch(".") do - if #inputTable.string-1 ~= inputTable.limit then - table.insert(inputTable.string, inputTable.cursor+1, char) - inputTable.cursor = inputTable.cursor+1 + --Hotkey thread + menu.create_thread(function() + while true do + if stuff.menuData.menuNav then + for k, v in pairs(stuff.hotkeys) do + local hotkey = cheeseUtils.get_key(table.unpack(stuff.hotkeys_to_vk[k])) + if hotkey:is_down() and (not (cheeseUtils.get_key(0x10):is_down() or cheeseUtils.get_key(0x11):is_down() or cheeseUtils.get_key(0x12):is_down()) or not (k:match("NOMOD"))) and utils.time_ms() > stuff.hotkey_cooldowns[k] then + for k, v in pairs(stuff.hotkeys[k]) do + if stuff.hotkey_feature_hierarchy_keys[k] then + for k, v in pairs(stuff.hotkey_feature_hierarchy_keys[k]) do + if v.type & 1 ~= 0 then + v.on = not v.on + if stuff.hotkey_notifications.toggle then + menu.notify("Turned "..v.name.." "..(v.on and "on" or "off"), "Cheese Menu", 3, func.convert_rgba_to_int(stuff.menuData.color.notifications.r, stuff.menuData.color.notifications.g, stuff.menuData.color.notifications.b, stuff.menuData.color.notifications.a)) + end + else + v:activate_feat_func() + if stuff.hotkey_notifications.action then + menu.notify("Activated "..v.name, "Cheese Menu", 3, func.convert_rgba_to_int(stuff.menuData.color.notifications.r, stuff.menuData.color.notifications.g, stuff.menuData.color.notifications.b, stuff.menuData.color.notifications.a)) + end + end + end + end + end + if stuff.hotkey_cooldowns[k] == 0 then + stuff.hotkey_cooldowns[k] = utils.time_ms() + 500 + else + stuff.hotkey_cooldowns[k] = utils.time_ms() + 100 + end + elseif not hotkey:is_down() then + stuff.hotkey_cooldowns[k] = 0 + end end end + system.wait(0) end - end + end, nil) + --End of threads + menu.notify("Kektram for teaching me lua & sharing neat functions\n\nRimuru for making the first separate ui that helped me in making cheese menu\n\nProddy for showing better ways to do things & sharing Script Manager", "Credits:", 12, 0x00ff00) + menu.notify("Controls can be found in\nScript Features > Cheese Menu > Controls", "CheeseMenu by GhostOne\n"..stuff.controls.open.." to open", 6, 0x00ff00) - function gginput.delete_char(inputTable, range_start, range_end) - if not range_start then - gginput.moveCursorLeft(inputTable, 1) - if inputTable.cursor == #inputTable.string-1 then - inputTable.string[#inputTable.string] = nil - else - table.remove(inputTable.string, inputTable.cursor+1) - end - else - if range_end ~= #inputTable.string then - inputTable.cursor = range_start - for i = range_end, range_start+1, -1 do - table.remove(inputTable.string, i) - end - else - inputTable.cursor = range_start - for i = range_start+1, #inputTable.string do - inputTable.string[i] = i == 1 and "" or nil - end - end - end - end + menu_configuration_features = {} + menu_configuration_features.cheesemenuparent = menu.add_feature("Cheese Menu", "parent") - function gginput.delete(inputTable) - if cheeseUtils.get_key(0x11):is_down() then - local range_start - for i = inputTable.cursor, 1, -1 do - if inputTable.string[i] == " " then - if i == inputTable.cursor then - for i = inputTable.cursor, 1, -1 do - if inputTable.string[i] ~= " " then - range_start = i - break - end - end - else - range_start = i - end - break - elseif i == 1 then - range_start = 1 + menu.add_feature("Save Settings", "action", menu_configuration_features.cheesemenuparent.id, function() + func.save_settings() + menu.notify("Settings Saved Successfully", "Cheese Menu", 6, 0x00ff00) + end) + + menu.add_feature("Save UI", "action", menu_configuration_features.cheesemenuparent.id, function() + local status, name = input.get("name of ui", "", 25, 0) + if status == 0 then + func.save_ui(name) + menu.notify("UI Saved Successfully", "Cheese Menu", 6, 0x00ff00) + for _, v in pairs(stuff.menuData.files.ui) do + if v == name then + return end end - gginput.delete_char(inputTable, range_start, inputTable.cursor) - else - gginput.delete_char(inputTable) + stuff.menuData.files.ui[#stuff.menuData.files.ui+1] = name + menu_configuration_features.load_ui:set_str_data(stuff.menuData.files.ui) end - end + end) - local shift_esc = MenuKey() - shift_esc:push_vk(0x10) - shift_esc:push_vk(0x1B) - function gginput.reset_menu_nav() - while true do - if shift_esc:is_down() then - menu.set_menu_can_navigate(true) - menu.notify("Reset menu navigation") - break + menu_configuration_features.load_ui = menu.add_feature("Load UI", "action_value_str", menu_configuration_features.cheesemenuparent.id, function(f) + func.load_ui(f.str_data[f.value + 1]) + end) + menu_configuration_features.load_ui:set_str_data(stuff.menuData.files.ui) + + menu_configuration_features.menuXfeat = menu.add_feature("Menu pos X", "autoaction_value_i", menu_configuration_features.cheesemenuparent.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.pos_x = num/graphics.get_screen_height() + f.value = num end - system.wait(0) end - end - - - function gginput.get_input(title, default, len, inputtype, inputTable) - local menuNavThread = menu.create_thread(gginput.reset_menu_nav) - menu.set_menu_can_navigate(false) - local pressed = {} + stuff.menuData.pos_x = f.value/graphics.get_screen_width() + end) + menu_configuration_features.menuXfeat.max = graphics.get_screen_width() + menu_configuration_features.menuXfeat.mod = 1 + menu_configuration_features.menuXfeat.min = -graphics.get_screen_width() + menu_configuration_features.menuXfeat.value = math.floor(stuff.menuData.pos_x*graphics.get_screen_width()) - for k, v in pairs(gginput.char_codes[1]) do - if cheeseUtils.get_key(k):is_down() then - pressed[k] = utils.time_ms() + 2000 - else - pressed[k] = 0 + menu_configuration_features.menuYfeat = menu.add_feature("Menu pos Y", "autoaction_value_i", menu_configuration_features.cheesemenuparent.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.pos_y = num/graphics.get_screen_height() + f.value = num end end + stuff.menuData.pos_y = f.value/graphics.get_screen_height() + end) + menu_configuration_features.menuYfeat.max = graphics.get_screen_height() + menu_configuration_features.menuYfeat.mod = 1 + menu_configuration_features.menuYfeat.min = -graphics.get_screen_height() + menu_configuration_features.menuYfeat.value = math.floor(stuff.menuData.pos_y*graphics.get_screen_height()) - inputtype = tonumber(inputtype) - inputtype = (inputtype <= 5 and inputtype >= 0) and inputtype or 0 - inputtype = inputtype + 1 - local charTable = gginput.char_codes[inputtype] - local pasteCheck = {} - for k, v in pairs(charTable) do - local concatenated = table.concat(v) - pasteCheck[#pasteCheck+1] = concatenated - if concatenated ~= concatenated:upper() then - pasteCheck[#pasteCheck+1] = concatenated:upper() - end + menu_configuration_features.headerfeat = menu.add_feature("Header", "autoaction_value_str", menu_configuration_features.cheesemenuparent.id, function(f) + if f.str_data[f.value + 1] == "NONE" then + stuff.menuData.header = nil + else + stuff.menuData.header = f.str_data[f.value + 1] end - pasteCheck = "[^"..table.concat(pasteCheck).."]" + end) + menu_configuration_features.headerfeat:set_str_data({"NONE", table.unpack(stuff.menuData.files.headers)}) - inputTable = inputTable or {} - inputTable.string = {""} - inputTable.state = 1 - inputTable.cursor = 1 - inputTable.title = tostring(title) - inputTable.limit = tonumber(len) or 25 + menu_configuration_features.layoutParent = menu.add_feature("Layout", "parent", menu_configuration_features.cheesemenuparent.id) - gginput.paste(default, inputTable) + menu_configuration_features.maxfeats = menu.add_feature("Max features", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData:set_max_features(f.value) + end) + menu_configuration_features.maxfeats.max = 50 + menu_configuration_features.maxfeats.mod = 1 + menu_configuration_features.maxfeats.min = 1 + menu_configuration_features.maxfeats.value = math.floor(stuff.menuData.max_features) - gginput.drawStuff.text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.6+0.2 + menu_configuration_features.menuWidth = menu.add_feature("Menu width", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.width = f.value/graphics.get_screen_width() + end) + menu_configuration_features.menuWidth.max = graphics.get_screen_width() + menu_configuration_features.menuWidth.mod = 1 + menu_configuration_features.menuWidth.min = -graphics.get_screen_width() + menu_configuration_features.menuWidth.value = math.floor(stuff.menuData.width*graphics.get_screen_width()) - local drawThread = menu.create_thread(gginput.draw_thread, inputTable) - while cheeseUtils.get_key(0x0D):is_down() do - system.wait() - end - while not (cheeseUtils.get_key(0x0D):is_down() or cheeseUtils.get_key(0x1B):is_down()) do - for k, v in pairs(charTable) do - if not cheeseUtils.get_key(0x11):is_down() and #inputTable.string-1 ~= len then - gginput.do_key(k, pressed, gginput.write_char, v, inputTable) - end - end + menu_configuration_features.featXfeat = menu.add_feature("Feature dimensions X", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.feature_scale.x = f.value/graphics.get_screen_width() + end) + menu_configuration_features.featXfeat.max = graphics.get_screen_width() + menu_configuration_features.featXfeat.mod = 1 + menu_configuration_features.featXfeat.min = -graphics.get_screen_width() + menu_configuration_features.featXfeat.value = math.floor(stuff.menuData.feature_scale.x*graphics.get_screen_width()) - if cheeseUtils.get_key(0x11, 0x56):is_down() then - gginput.paste(utils.from_clipboard():gsub("[\r\n]", " "):gsub(pasteCheck, ""), inputTable) - while cheeseUtils.get_key(0x11, 0x56):is_down() do - system.wait() - end - elseif cheeseUtils.get_key(0x11, 0x43):is_down() then - utils.to_clipboard(table.concat(inputTable.string)) - end + menu_configuration_features.featYfeat = menu.add_feature("Feature dimensions Y", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.feature_scale.y = f.value/graphics.get_screen_height() + end) + menu_configuration_features.featYfeat.max = graphics.get_screen_height() + menu_configuration_features.featYfeat.mod = 1 + menu_configuration_features.featYfeat.min = -graphics.get_screen_height() + menu_configuration_features.featYfeat.value = math.floor(stuff.menuData.feature_scale.y*graphics.get_screen_height()) - gginput.do_key(0x08, pressed, gginput.delete, inputTable) -- backspace - gginput.do_key(0x27, pressed, gginput.moveCursorRight, inputTable, 1) -- right - gginput.do_key(0x25, pressed, gginput.moveCursorLeft, inputTable, 1) -- left - system.wait(0) - end + menu_configuration_features.feature_offset = menu.add_feature("Feature spacing", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.feature_offset = f.value/graphics.get_screen_height() + menu_configuration_features.maxfeats:toggle() + end) + menu_configuration_features.feature_offset.max = graphics.get_screen_height() + menu_configuration_features.feature_offset.mod = 1 + menu_configuration_features.feature_offset.min = -graphics.get_screen_height() + menu_configuration_features.feature_offset.value = math.floor(stuff.menuData.feature_offset*graphics.get_screen_height()) - gginput.disableESC() + menu_configuration_features.text_size = menu.add_feature("Text Size", "autoaction_value_f", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.text_size_modifier = f.value + end) + menu_configuration_features.text_size.max = 5 + menu_configuration_features.text_size.mod = 0.01 + menu_configuration_features.text_size.min = 0.1 + menu_configuration_features.text_size.value = stuff.menuData.text_size_modifier - local success = cheeseUtils.get_key(0x0D):is_down() - while cheeseUtils.get_key(0x0D):is_down() do - system.wait(0) - end - menu.delete_thread(drawThread) - menu.delete_thread(menuNavThread) - menu.set_menu_can_navigate(true) - inputTable.string = table.concat(inputTable.string) - inputTable.state = success and 0 or 2 + menu_configuration_features.footer_size = menu.add_feature("Footer Text Size", "autoaction_value_f", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.footer_size_modifier = f.value + end) + menu_configuration_features.footer_size.max = 5 + menu_configuration_features.footer_size.mod = 0.01 + menu_configuration_features.footer_size.min = 0.1 + menu_configuration_features.footer_size.value = stuff.menuData.footer_size_modifier - gginput.drawStuff.string = "" - gginput.drawStuff.indicator_string = "" - gginput.drawStuff.cached_text_width = 0 - gginput.drawStuff.cached_table_length = 0 + menu_configuration_features.hint_size = menu.add_feature("Hint Text Size", "autoaction_value_f", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.hint_size_modifier = f.value + func.rewrap_hints(stuff.menuData.fonts.hint) + end) + menu_configuration_features.hint_size.max = 5 + menu_configuration_features.hint_size.mod = 0.01 + menu_configuration_features.hint_size.min = 0.1 + menu_configuration_features.hint_size.value = stuff.menuData.hint_size_modifier - return inputTable.state, success and inputTable.string or nil - end --- + menu_configuration_features.text_y_offset = menu.add_feature("Text Y Offset", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) + stuff.drawFeatParams.textOffset.y = -(f.value/graphics.get_screen_height()) + stuff.menuData.text_y_offset = -(f.value/graphics.get_screen_height()) + end) + menu_configuration_features.text_y_offset.max = 100 + menu_configuration_features.text_y_offset.mod = 1 + menu_configuration_features.text_y_offset.min = -100 + menu_configuration_features.text_y_offset.value = -math.floor(stuff.menuData.text_y_offset*graphics.get_screen_height()) -return gginput -]=], - ["Proddy's Script Manager.lua"] = [=[local ScriptName = "Proddy's Script Manager (CheeseMenu)" -local Version = "2.3.2" -local Exiting = false + menu_configuration_features.border = menu.add_feature("Border", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.border = f.value/graphics.get_screen_height() + end) + menu_configuration_features.border.max = graphics.get_screen_height() + menu_configuration_features.border.mod = 1 + menu_configuration_features.border.min = -graphics.get_screen_height() + menu_configuration_features.border.value = math.floor(stuff.menuData.border*graphics.get_screen_height()) + + menu_configuration_features.selector_speed = menu.add_feature("Selector Speed", "autoaction_value_f", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.selector_speed = f.value + end) + menu_configuration_features.selector_speed.max = 10 + menu_configuration_features.selector_speed.mod = 0.1 + menu_configuration_features.selector_speed.min = 0.2 + menu_configuration_features.selector_speed.value = stuff.menuData.selector_speed + + -- Online Player Submenu Sorting + menu_configuration_features.player_submenu_sort = menu.add_feature("Online Players Sort:", "autoaction_value_str", menu_configuration_features.layoutParent.id, function(f) + table.sort(stuff.PlayerParent, stuff.table_sort_functions[f.value]) + stuff.player_submenu_sort = f.value + end) + menu_configuration_features.player_submenu_sort:set_str_data({'PID', 'PID Reversed', 'Alphabetically', 'Alphabetically Reversed', 'Host Priority', 'Host Priority Reversed'}) + menu_configuration_features.player_submenu_sort.value = stuff.player_submenu_sort + + -- Padding + menu_configuration_features.padding_parent = menu.add_feature("Padding", "parent", menu_configuration_features.layoutParent.id) + + menu_configuration_features.namePadding = menu.add_feature("Name Padding", "autoaction_value_i", menu_configuration_features.padding_parent.id, function(f) + stuff.menuData.padding.name = f.value/graphics.get_screen_width() + end) + menu_configuration_features.namePadding.max = graphics.get_screen_width() + menu_configuration_features.namePadding.mod = 1 + menu_configuration_features.namePadding.min = -graphics.get_screen_width() + menu_configuration_features.namePadding.value = math.floor(stuff.menuData.padding.name*graphics.get_screen_width()) + + menu_configuration_features.parentPadding = menu.add_feature("Parent Padding", "autoaction_value_i", menu_configuration_features.padding_parent.id, function(f) + stuff.menuData.padding.parent = f.value/graphics.get_screen_width() + end) + menu_configuration_features.parentPadding.max = graphics.get_screen_width() + menu_configuration_features.parentPadding.mod = 1 + menu_configuration_features.parentPadding.min = -graphics.get_screen_width() + menu_configuration_features.parentPadding.value = math.floor(stuff.menuData.padding.parent*graphics.get_screen_width()) + + menu_configuration_features.valuePadding = menu.add_feature("Value Padding", "autoaction_value_i", menu_configuration_features.padding_parent.id, function(f) + stuff.menuData.padding.value = f.value/graphics.get_screen_width() + end) + menu_configuration_features.valuePadding.max = graphics.get_screen_width() + menu_configuration_features.valuePadding.mod = 1 + menu_configuration_features.valuePadding.min = -graphics.get_screen_width() + menu_configuration_features.valuePadding.value = math.floor(stuff.menuData.padding.value*graphics.get_screen_width()) + + menu_configuration_features.sliderPadding = menu.add_feature("Slider Padding", "autoaction_value_i", menu_configuration_features.padding_parent.id, function(f) + stuff.menuData.padding.slider = f.value/graphics.get_screen_width() + end) + menu_configuration_features.sliderPadding.max = graphics.get_screen_width() + menu_configuration_features.sliderPadding.mod = 1 + menu_configuration_features.sliderPadding.min = -graphics.get_screen_width() + menu_configuration_features.sliderPadding.value = math.floor(stuff.menuData.padding.slider*graphics.get_screen_width()) -local Paths = {} -Paths.Root = utils.get_appdata_path("PopstarDevs", "2Take1Menu") -Paths.Cfg = Paths.Root .. "\\cfg" -Paths.LogFile = Paths.Root .. "\\" .. ScriptName .. ".log" -Paths.Scripts = Paths.Root .. "\\scripts" + -- Slider dimensions + menu_configuration_features.slider_parent = menu.add_feature("Slider", "parent", menu_configuration_features.layoutParent.id) -local og_loadfile = loadfile -local og__loadfile = _loadfile -local og_load = load -local og_pcall = _pcall -local io_open = io.open -local os_date = os.date -local string_format = string.format -local system_wait = system.wait + menu_configuration_features.sliderWidth = menu.add_feature("Slider Width", "autoaction_value_i", menu_configuration_features.slider_parent.id, function(f) + stuff.menuData.slider.width = f.value/graphics.get_screen_width() + end) + menu_configuration_features.sliderWidth.max = graphics.get_screen_width() + menu_configuration_features.sliderWidth.mod = 1 + menu_configuration_features.sliderWidth.min = -graphics.get_screen_width() + menu_configuration_features.sliderWidth.value = math.floor(stuff.menuData.slider.width*graphics.get_screen_width()) -local basePrint = print -local function print(...) - basePrint(...) - local success, result = og_pcall(function(...) - local args = {...} - if #args == 0 then - return - end + menu_configuration_features.sliderHeight = menu.add_feature("Slider Height", "autoaction_value_i", menu_configuration_features.slider_parent.id, function(f) + stuff.menuData.slider.height = f.value/graphics.get_screen_height() + end) + menu_configuration_features.sliderHeight.max = graphics.get_screen_height() + menu_configuration_features.sliderHeight.mod = 1 + menu_configuration_features.sliderHeight.min = -graphics.get_screen_height() + menu_configuration_features.sliderHeight.value = math.floor(stuff.menuData.slider.height*graphics.get_screen_height()) - local currTime = os_date("*t") - local file = io_open(Paths.LogFile, "a") + menu_configuration_features.sliderheightActive = menu.add_feature("Slider Height Active", "autoaction_value_i", menu_configuration_features.slider_parent.id, function(f) + stuff.menuData.slider.heightActive = f.value/graphics.get_screen_height() + end) + menu_configuration_features.sliderheightActive.max = graphics.get_screen_height() + menu_configuration_features.sliderheightActive.mod = 1 + menu_configuration_features.sliderheightActive.min = -graphics.get_screen_height() + menu_configuration_features.sliderheightActive.value = math.floor(stuff.menuData.slider.heightActive*graphics.get_screen_height()) - for i=1,#args do - file:write(string_format("[%02d-%02d-%02d %02d:%02d:%02d] <%s> %s\n", currTime.year, currTime.month, currTime.day, currTime.hour, currTime.min, currTime.sec, Version, tostring(args[i]))) - end + -- Controls + menu_configuration_features.controls = menu.add_feature("Controls", "parent", menu_configuration_features.cheesemenuparent.id) - file:close() - end, ...) - if not success then - basePrint("Error writing log: " .. result) - end -end + for k, v in pairs(stuff.controls) do + menu.add_feature(k, "action_value_str", menu_configuration_features.controls.id, function(f) + for k, v in pairs(stuff.char_codes) do + while cheeseUtils.get_key(v):is_down() do + system.wait(0) + end + end + menu.notify("Press any button\nESC to cancel", "Cheese Menu", 3, func.convert_rgba_to_int(stuff.menuData.color.notifications.r, stuff.menuData.color.notifications.g, stuff.menuData.color.notifications.b, stuff.menuData.color.notifications.a)) + local disablethread = menu.create_thread(stuff.disable_all_controls, nil) + local stringkey, vk = func.get_hotkey({}, {}, true) + if stringkey ~= "escaped" then + stuff.controls[k] = stringkey + stuff.vkcontrols[k] = vk + f:set_str_data({stringkey}) + end + menu.delete_thread(disablethread) + end):set_str_data({v}) + end -local notif = menu.notify -local function notify(msg, colour) - notif(msg, ScriptName .. " v" .. Version, nil, colour) - print(msg) -end + -- Player Info + menu_configuration_features.side_window = menu.add_feature("Player Info Window", "parent", menu_configuration_features.cheesemenuparent.id) -if ProddysScriptManager then - notify(ScriptName .. " already loaded.", 0xFF50C8F0) - return -end + -- On + menu_configuration_features.side_window_on = menu.add_feature("Draw", "toggle", menu_configuration_features.side_window.id, function(f) + stuff.menuData.side_window.on = f.on + end) + menu_configuration_features.side_window_on.on = stuff.menuData.side_window.on ---notify(ScriptName .. " v" .. Version .. " loading...") + -- Offset + menu_configuration_features.side_window_offsetx = menu.add_feature("X Offset", "autoaction_value_i", menu_configuration_features.side_window.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.side_window.offset.x = num/graphics.get_screen_height() + f.value = num + end + end + stuff.menuData.side_window.offset.x = f.value/graphics.get_screen_width() + end) + menu_configuration_features.side_window_offsetx.max = graphics.get_screen_width() + menu_configuration_features.side_window_offsetx.mod = 1 + menu_configuration_features.side_window_offsetx.min = -graphics.get_screen_width() + menu_configuration_features.side_window_offsetx.value = math.floor(stuff.menuData.side_window.offset.x*graphics.get_screen_width()) -local function CloneTable(obj, seen) - if type(obj) ~= 'table' then - return obj - end + menu_configuration_features.side_window_offsety = menu.add_feature("Y Offset", "autoaction_value_i", menu_configuration_features.side_window.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.side_window.offset.y = num/graphics.get_screen_height() + f.value = num + end + end + stuff.menuData.side_window.offset.y = f.value/graphics.get_screen_height() + end) + menu_configuration_features.side_window_offsety.max = graphics.get_screen_height() + menu_configuration_features.side_window_offsety.mod = 1 + menu_configuration_features.side_window_offsety.min = -graphics.get_screen_height() + menu_configuration_features.side_window_offsety.value = math.floor(stuff.menuData.side_window.offset.y*graphics.get_screen_height()) - if seen and seen[obj] then - return seen[obj] - end + -- Spacing + menu_configuration_features.side_window_spacing = menu.add_feature("Spacing", "autoaction_value_i", menu_configuration_features.side_window.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.side_window.spacing = num/graphics.get_screen_height() + f.value = num + end + end + stuff.menuData.side_window.spacing = f.value/graphics.get_screen_height() + end) + menu_configuration_features.side_window_spacing.max = graphics.get_screen_height() + menu_configuration_features.side_window_spacing.mod = 1 + menu_configuration_features.side_window_spacing.min = -graphics.get_screen_height() + menu_configuration_features.side_window_spacing.value = math.floor(stuff.menuData.side_window.spacing*graphics.get_screen_height()) - local s = seen or {} - local res = {} - s[obj] = res + -- Padding + menu_configuration_features.side_window_padding = menu.add_feature("Padding", "autoaction_value_i", menu_configuration_features.side_window.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.side_window.padding = num/graphics.get_screen_height() + f.value = num + end + end + stuff.menuData.side_window.padding = f.value/graphics.get_screen_width() + end) + menu_configuration_features.side_window_padding.max = graphics.get_screen_width() + menu_configuration_features.side_window_padding.mod = 1 + menu_configuration_features.side_window_padding.min = -graphics.get_screen_width() + menu_configuration_features.side_window_padding.value = math.floor(stuff.menuData.side_window.padding*graphics.get_screen_width()) - for k, v in pairs(obj) do - res[CloneTable(k, s)] = CloneTable(v, s) - end + -- Width + menu_configuration_features.side_window_width = menu.add_feature("Width", "autoaction_value_i", menu_configuration_features.side_window.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.side_window.width = num/graphics.get_screen_height() + f.value = num + end + end + stuff.menuData.side_window.width = f.value/graphics.get_screen_width() + end) + menu_configuration_features.side_window_width.max = graphics.get_screen_width() + menu_configuration_features.side_window_width.mod = 1 + menu_configuration_features.side_window_width.min = -graphics.get_screen_width() + menu_configuration_features.side_window_width.value = math.floor(stuff.menuData.side_window.width*graphics.get_screen_width()) - return setmetatable(res, getmetatable(obj)) --Should definitely clone the metatable -end + -- End of Player Info -local function Trim(s) - local n = s:find"%S" - return n and s:match(".*%S", n) or "" -end -local function FileNameWithoutExtension(FileName) - local name = FileName:match("(.+)%.") - return name or FileName -end + -- Background + menu_configuration_features.backgroundparent = menu.add_feature("Background", "parent", menu_configuration_features.cheesemenuparent.id) -local ExcludedScripts = {} -ExcludedScripts["autoexec.lua"] = true -ExcludedScripts["autoexec.luac"] = true -ExcludedScripts["cheesemenu.lua"] = true -ExcludedScripts[debug.getinfo(1, "S").source:sub(Paths.Scripts:len() + 3):lower()] = true + menu_configuration_features.backgroundfeat = menu.add_feature("Background", "autoaction_value_str", menu_configuration_features.backgroundparent.id, function(f) + if f.str_data[f.value + 1] == "NONE" then + stuff.menuData.background_sprite.sprite = nil + else + stuff.menuData.background_sprite.sprite = f.str_data[f.value + 1] + end + end) + menu_configuration_features.backgroundfeat:set_str_data({"NONE", table.unpack(stuff.menuData.files.background)}) -local Settings = {} + menu.add_feature("Fit background to width", "action", menu_configuration_features.backgroundparent.id, function() + if stuff.menuData.background_sprite.sprite then + stuff.menuData.background_sprite:fit_size_to_width() + end + end) -function Settings.Save(SettingsFile, SettingsTbl) - assert(SettingsFile, "Nil passed for SettingsFile to Settings.Save") - assert(type(SettingsTbl) == "table", "Not a table passed for SettingsTbl to Settings.Save") - local file = io.open(Paths.Cfg .. "\\" .. SettingsFile .. ".cfg", "w") - local keys = {} - for k in pairs(SettingsTbl) do - keys[#keys + 1] = k - end - table.sort(keys) - for i=1,#keys do - file:write(tostring(keys[i]) .. "=" .. tostring(SettingsTbl[keys[i]]) .. "\n") - end - file:close() -end + menu_configuration_features.backgroundoffsetx = menu.add_feature("Background pos X", "autoaction_value_i", menu_configuration_features.backgroundparent.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.background_sprite.offset.x = num/graphics.get_screen_width() + f.value = num + end + end + stuff.menuData.background_sprite.offset.x = f.value/graphics.get_screen_width() + end) + menu_configuration_features.backgroundoffsetx.max = graphics.get_screen_width() + menu_configuration_features.backgroundoffsetx.mod = 1 + menu_configuration_features.backgroundoffsetx.min = -graphics.get_screen_width() + menu_configuration_features.backgroundoffsetx.value = math.floor(stuff.menuData.background_sprite.offset.x*graphics.get_screen_width()) + + menu_configuration_features.backgroundoffsety = menu.add_feature("Background pos Y", "autoaction_value_i", menu_configuration_features.backgroundparent.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.background_sprite.offset.y = num/graphics.get_screen_height() + f.value = num + end + end + stuff.menuData.background_sprite.offset.y = f.value/graphics.get_screen_height() + end) + menu_configuration_features.backgroundoffsety.max = graphics.get_screen_height() + menu_configuration_features.backgroundoffsety.mod = 1 + menu_configuration_features.backgroundoffsety.min = -graphics.get_screen_height() + menu_configuration_features.backgroundoffsety.value = math.floor(stuff.menuData.background_sprite.offset.y*graphics.get_screen_height()) + + menu_configuration_features.backgroundsize = menu.add_feature("Background Size", "autoaction_value_f", menu_configuration_features.backgroundparent.id, function(f) + stuff.menuData.background_sprite.size = f.value + end) + menu_configuration_features.backgroundsize.max = 1 + menu_configuration_features.backgroundsize.mod = 0.01 + menu_configuration_features.backgroundsize.value = stuff.menuData.background_sprite.size -function Settings.Load(SettingsFile, SettingsTbl) - assert(SettingsFile, "Nil passed for SettingsFile to Settings.Load") - assert(type(SettingsTbl) == "table", "Not a table passed for SettingsTbl to Settings.Load") - SettingsFile = Paths.Cfg .. "\\" .. SettingsFile .. ".cfg" - if not utils.file_exists(SettingsFile) then - return false - end - for line in io.lines(SettingsFile) do - local key, value = line:match("^(.-)=(.-)$") - if key and value then - local num = tonumber(value) - if num then - value = num - elseif value == "true" then - value = true - elseif value == "false" then - value = false - end - num = tonumber(key) - if num then - key = num - end - SettingsTbl[key] = value - end - end - return true -end + -- Footer + menu_configuration_features.footer = menu.add_feature("Footer", "parent", menu_configuration_features.cheesemenuparent.id) -local FeatType = { - [2048] = "parent", - [1] = "toggle", - [512] = "action", - [11] = "value_i", - [131] = "value_f", - [7] = "slider", - [35] = "value_str", - [522] = "action_value_i", - [642] = "action_value_f", - [518] = "action_slider", - [546] = "action_value_str", - [1034] = "autoaction_value_i", - [1154] = "autoaction_value_f", - [1030] = "autoaction_slider", - [1058] = "autoaction_value_str", -} + menu_configuration_features.footer_size = menu.add_feature("Footer Size", "autoaction_value_i", menu_configuration_features.footer.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.footer.footer_size = num/graphics.get_screen_height() + f.value = num + end + end + stuff.menuData.footer.footer_size = f.value/graphics.get_screen_height() + end) + menu_configuration_features.footer_size.max = graphics.get_screen_height() + menu_configuration_features.footer_size.mod = 1 + menu_configuration_features.footer_size.min = 0 + menu_configuration_features.footer_size.value = math.floor(stuff.menuData.footer.footer_size*graphics.get_screen_height()) -local AutoloadTbl = {} -Settings.Load(ScriptName, AutoloadTbl) + menu_configuration_features.footer_y_offset = menu.add_feature("Footer Y Offset", "autoaction_value_i", menu_configuration_features.footer.id, function(f) + stuff.menuData.footer.footer_y_offset = (f.value/graphics.get_screen_height()) + end) + menu_configuration_features.footer_y_offset.max = 100 + menu_configuration_features.footer_y_offset.mod = 1 + menu_configuration_features.footer_y_offset.min = -100 + menu_configuration_features.footer_y_offset.value = math.floor(stuff.menuData.footer.footer_y_offset*graphics.get_screen_height()) -local LoadedScripts = {} + menu_configuration_features.footerPadding = menu.add_feature("Padding", "autoaction_value_i", menu_configuration_features.footer.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.footer.padding = num/graphics.get_screen_width() + f.value = num + end + end + stuff.menuData.footer.padding = f.value/graphics.get_screen_width() + end) + menu_configuration_features.footerPadding.max = graphics.get_screen_width() + menu_configuration_features.footerPadding.mod = 1 + menu_configuration_features.footerPadding.min = -graphics.get_screen_width() + menu_configuration_features.footerPadding.value = math.floor(stuff.menuData.footer.padding*graphics.get_screen_width()) -local add_feature = menu.add_feature -local add_player_feature = menu.add_player_feature -local delete_feature = menu.delete_feature -local delete_player_feature = menu.delete_player_feature -local create_thread = menu.create_thread -local delete_thread = menu.delete_thread + menu_configuration_features.draw_footer = menu.add_feature("Draw footer", "toggle", menu_configuration_features.footer.id, function(f) + stuff.menuData.footer.draw_footer = f.on + end) + menu_configuration_features.draw_footer.on = stuff.menuData.footer.draw_footer -local register_script_event_hook = hook.register_script_event_hook -local remove_script_event_hook = hook.remove_script_event_hook -local register_net_event_hook = hook.register_net_event_hook -local remove_net_event_hook = hook.remove_net_event_hook + menu_configuration_features.footer_pos_related_to_background = menu.add_feature("Footer position based on background", "toggle", menu_configuration_features.footer.id, function(f) + stuff.menuData.footer.footer_pos_related_to_background = f.on + end) + menu_configuration_features.footer_pos_related_to_background.on = stuff.menuData.footer.footer_pos_related_to_background -local add_event_listener = event.add_event_listener -local remove_event_listener = event.remove_event_listener + menu_configuration_features.footer_text = menu.add_feature("Footer Text", "action", menu_configuration_features.footer.id, function() + local status, text = input.get("Footer Text", "", 50, 0) + if status == 0 then + stuff.menuData.footer.footer_text = tostring(text) + end + end) -local register_command = console.register_command -local remove_command = console.remove_command + -- Fonts + local fontStrData = { + "Menu Head", + "Menu Tab", + "Menu Entry", + "Menu Foot", + "Script 1", + "Script 2", + "Script 3", + "Script 4", + "Script 5", + } + menu_configuration_features.fonts = menu.add_feature("Fonts", "parent", menu_configuration_features.cheesemenuparent.id) -local Parent = menu_originals.add_feature("Proddy's Script Manager", "parent", menu.get_feature_by_hierarchy_key("local.script_features.cheese_menu").id) -local ParentId = Parent.id -local FirstChild -local AutoloadFirstChild -local FilterFeat + menu_configuration_features.text_font = menu.add_feature("Text Font", "autoaction_value_str", menu_configuration_features.fonts.id, function(f) + stuff.menuData.fonts.text = f.value + end) + menu_configuration_features.text_font:set_str_data(fontStrData) + menu_configuration_features.text_font.value = stuff.menuData.fonts.text -menu_originals.add_feature("Trusted Mode", "parent", ParentId) + menu_configuration_features.footer_font = menu.add_feature("Footer Font", "autoaction_value_str", menu_configuration_features.fonts.id, function(f) + stuff.menuData.fonts.footer = f.value + end) + menu_configuration_features.footer_font:set_str_data(fontStrData) + menu_configuration_features.footer_font.value = stuff.menuData.fonts.footer -local AutoloadParent = menu_originals.add_feature("Manage Autoload Scripts", "parent", ParentId) -local AutoloadParentId = AutoloadParent.id + menu_configuration_features.hint_font = menu.add_feature("Hint Font", "autoaction_value_str", menu_configuration_features.fonts.id, function(f) + stuff.menuData.fonts.hint = f.value + func.rewrap_hints(f.value) + end) + menu_configuration_features.hint_font:set_str_data(fontStrData) + menu_configuration_features.hint_font.value = stuff.menuData.fonts.hint -local assert = assert -local error = error -local type = type + -- Hotkeys + menu_configuration_features.hotkeyparent = menu.add_feature("Hotkey notifications", "parent", menu_configuration_features.cheesemenuparent.id) -local UnloadScript + menu.add_feature("Toggle notification", "toggle", menu_configuration_features.hotkeyparent.id, function(f) + stuff.hotkey_notifications.toggle = f.on + end).on = stuff.hotkey_notifications.toggle + menu.add_feature("Action notification", "toggle", menu_configuration_features.hotkeyparent.id, function(f) + stuff.hotkey_notifications.action = f.on + end).on = stuff.hotkey_notifications.action -local function DeleteFeature(Feat) - if Feat then - if Feat.type == 2048 then - for i=1,Feat.child_count do - DeleteFeature(Feat.children[1]) - end - elseif Feat.type == 1 then - if Feat.data and type(Feat.data) == "table" and Feat.data.ScriptManager then - print("Deleting script: " .. Feat.name) - UnloadScript(Feat) - print("Deleted script: " .. Feat.name) - end - end - if Feat.activate_feat_func then - delete_feature(Feat.id) - else - menu_originals.delete_feature(Feat.id) - end - end -end -local function DeletePlayerFeature(Feat) - delete_player_feature(Feat.id) -end + -- Colors + local colorParent = menu.add_feature("Colors", "parent", menu_configuration_features.cheesemenuparent.id) + do + local tempColor = {} + for k, v in pairs(stuff.menuData.color) do + tempColor[#tempColor+1] = {k, v, sortname = k:gsub("feature_([^s])", "feature_a%1")} + end + table.sort(tempColor, function(a, b) return a["sortname"] < b["sortname"] end) -UnloadScript = function(f) - if Exiting then return end - if not f.data or type(f.data) ~= "table" or not f.data.ScriptManager then return end + for _, v in pairs(tempColor) do + menu_configuration_features[v[1]] = {} + local vParent = menu.add_feature(v[1], "parent", colorParent.id) - print("Unloading script: " .. f.name) + menu_configuration_features[v[1]].r = menu.add_feature("Red", "autoaction_value_i", vParent.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + f.value = num + end + end + stuff.menuData.color:set_color(v[1], f.value) + end) + menu_configuration_features[v[1]].r.max = 255 + if type(v[2]) == "table" then + menu_configuration_features[v[1]].r.value = v[2].r + else + menu_configuration_features[v[1]].r.value = func.convert_int_to_rgba(v[2], "r") + end - local success, result = og_pcall(function(data) - if data.exits then - for k,v in pairs(data.exits) do - v({["code"]=69}) - end - end + menu_configuration_features[v[1]].g = menu.add_feature("Green", "autoaction_value_i", vParent.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + f.value = num + end + end + stuff.menuData.color:set_color(v[1], nil, f.value) + end) + menu_configuration_features[v[1]].g.max = 255 + if type(v[2]) == "table" then + menu_configuration_features[v[1]].g.value = v[2].g + else + menu_configuration_features[v[1]].g.value = func.convert_int_to_rgba(v[2], "g") + end + + menu_configuration_features[v[1]].b = menu.add_feature("Blue", "autoaction_value_i", vParent.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + f.value = num + end + end + stuff.menuData.color:set_color(v[1], nil, nil, f.value) + end) + menu_configuration_features[v[1]].b.max = 255 + if type(v[2]) == "table" then + menu_configuration_features[v[1]].b.value = v[2].b + else + menu_configuration_features[v[1]].b.value = func.convert_int_to_rgba(v[2], "b") + end - if data.features then - local ids = {} - for k in pairs(data.features) do - ids[#ids + 1] = k - end - table.sort(ids) - for i = #ids,1,-1 do - DeleteFeature(data.features[ids[i]]) + menu_configuration_features[v[1]].a = menu.add_feature("Alpha", "autoaction_value_i", vParent.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + f.value = num + end + end + stuff.menuData.color:set_color(v[1], nil, nil, nil, f.value) + end) + menu_configuration_features[v[1]].a.max = 255 + if type(v[2]) == "table" then + menu_configuration_features[v[1]].a.value = v[2].a + else + menu_configuration_features[v[1]].a.value = func.convert_int_to_rgba(v[2], "a") + end + end end - end - if data.player_features then - local ids = {} - for k in pairs(data.player_features) do - ids[#ids + 1] = k - end - table.sort(ids) - for i = #ids,1,-1 do - DeletePlayerFeature(data.player_features[ids[i]]) - end - end + -- loading default ui & settings + func.load_ui("default") + func.load_settings() - if data.threads then - local ids = {} - for k in pairs(data.threads) do - ids[#ids + 1] = k - end - table.sort(ids) - for i = #ids,1,-1 do - delete_thread(ids[i]) - end + --changing menu functions to ui functions + local menu_get_feature_by_hierarchy_key = menu.get_feature_by_hierarchy_key + menu_originals = setmetatable({ + --get_feature_by_hierarchy_key = menu.get_feature_by_hierarchy_key, + add_feature = menu.add_feature, + add_player_feature = menu.add_player_feature, + delete_feature = menu.delete_feature, + delete_player_feature = menu.delete_player_feature, + get_player_feature = menu.get_player_feature, + }, {__newindex = function() end}) + menu.add_feature = func.add_feature + menu.add_player_feature = func.add_player_feature + menu.delete_feature = func.delete_feature + menu.delete_player_feature = func.delete_player_feature + menu.get_player_feature = func.get_player_feature + menu.get_feature_by_hierarchy_key = function(hierarchy_key) + if string.find(hierarchy_key:lower(), "trusted") or string.find(hierarchy_key:lower(), "Proddy's Script Manager") then + return end - - if data.script_hooks then - local ids = {} - for k in pairs(data.script_hooks) do - ids[#ids + 1] = k - end - table.sort(ids) - for i = #ids,1,-1 do - remove_script_event_hook(ids[i]) + local feat, duplicate + feat = menu_get_feature_by_hierarchy_key(hierarchy_key) + if feat then + return feat + else + feat, duplicate = func.get_feature_by_hierarchy_key(hierarchy_key) + if duplicate then + return feat[1] + else + return feat end end + end + cheeseUIdata = stuff.menuData + -- + func.set_player_feat_parent("Online Players", 0) - if data.net_hooks then - local ids = {} - for k in pairs(data.net_hooks) do - ids[#ids + 1] = k - end - table.sort(ids) - for i = #ids,1,-1 do - remove_net_event_hook(ids[i]) + -- Proddy's Script Manager + gltw.read("Trusted Flags", stuff.path.cheesemenu, stuff, true, true) + menu.is_trusted_mode_enabled = function(flag) + if not flag then + return stuff.trusted_mode & 7 == 7, stuff.trusted_mode_notification + else + return stuff.trusted_mode & flag == flag, stuff.trusted_mode_notification end end - if data.events then - for eventName,v in pairs(data.events) do - local ids = {} - for k in pairs(v) do - ids[#ids + 1] = k - end - table.sort(ids) - for i = #ids,1,-1 do - remove_event_listener(eventName, ids[i]) - end - end - end + dofile("\\scripts\\cheesemenu\\libs\\Proddy's Script Manager.lua") - if data.commands then - for name in pairs(data.commands) do - remove_command(name) - end - end - end, f.data) + do + local trusted_parent = menu_get_feature_by_hierarchy_key("local.script_features.cheese_menu.proddy_s_script_manager.trusted_mode") - LoadedScripts[f.name] = nil - f.data = nil - f.on = false + menu_originals.add_feature("Save Trusted Flags", "action", trusted_parent.id, function() + gltw.write({trusted_mode = stuff.trusted_mode, trusted_mode_notification = stuff.trusted_mode_notification}, "Trusted Flags", stuff.path.cheesemenu, nil, nil, true) + menu.notify("Saved Successfully", "Cheese Menu", 2, 0x00ff00) + end) - if success then - notify("Unloaded script: " .. f.name, 0xFF00FF00) - else - notify("Failed to unload script: " .. f.name .. "\n" .. result, 0xFF00FF00) - end + menu_originals.add_feature("Trusted Flags Notification", "toggle", trusted_parent.id, function(f) + stuff.trusted_mode_notification = f.on + end).on = stuff.trusted_mode_notification - collectgarbage("collect") + local trusted_names = { + [0] = "Stats", + [1] = "Globals / Locals", + [2] = "Natives", + [3] = "HTTP", + [4] = "Memory" + } + + for i = 0, 4 do + menu_originals.add_feature(trusted_names[i], "toggle", trusted_parent.id, function(f) + if f.on then + stuff.trusted_mode = stuff.trusted_mode | 1 << i + else + stuff.trusted_mode = stuff.trusted_mode ~ 1 << i + end + end).on = stuff.trusted_mode & 1 << i ~= 0 + end + end + -- end +if httpTrustedOff then + loadCurrentMenu() +end]=], + ["Get Input.lua"] = [=[--Made by GhostOne --- modified -local limited_functions = { +local cheeseUtils = require("cheesemenu.libs.CheeseUtilities") +local gginput = { + indicator_timer = utils.time_ms() + 750, + indicator = false, + drawStuff = { + cached_table_length = 0, + cached_text_width = 0, + } +} +gginput.char_codes = { + { + [0x30] = {"0", ")"}, + [0x31] = {"1", "!"}, + [0x32] = {"2", "@"}, + [0x33] = {"3", "#"}, + [0x34] = {"4", "$"}, + [0x35] = {"5", "%"}, + [0x36] = {"6", "^"}, + [0x37] = {"7", "&"}, + [0x38] = {"8", "*"}, + [0x39] = {"9", "("}, + [0x41] = {"a"}, + [0x42] = {"b"}, + [0x43] = {"c"}, + [0x44] = {"d"}, + [0x45] = {"e"}, + [0x46] = {"f"}, + [0x47] = {"g"}, + [0x48] = {"h"}, + [0x49] = {"i"}, + [0x4A] = {"j"}, + [0x4B] = {"k"}, + [0x4C] = {"l"}, + [0x4D] = {"m"}, + [0x4E] = {"n"}, + [0x4F] = {"o"}, + [0x50] = {"p"}, + [0x51] = {"q"}, + [0x52] = {"r"}, + [0x53] = {"s"}, + [0x54] = {"t"}, + [0x55] = {"u"}, + [0x56] = {"v"}, + [0x57] = {"w"}, + [0x58] = {"x"}, + [0x59] = {"y"}, + [0x5A] = {"z"}, + [0x60] = {"0", ")"}, + [0x61] = {"1", "!"}, + [0x62] = {"2", "@"}, + [0x63] = {"3", "#"}, + [0x64] = {"4", "$"}, + [0x65] = {"5", "%"}, + [0x66] = {"6", "^"}, + [0x67] = {"7", "&"}, + [0x68] = {"8", "*"}, + [0x69] = {"9", "("}, + [0x20] = {" "}, + [0xBA] = {";", ":"}, + [0xBB] = {"=", "+"}, + [0xBC] = {",", "<"}, + [0xBD] = {"-", "_"}, + [0xBE] = {".", ">"}, + [0xBF] = {"/", "?"}, + [0xC0] = {"`", "~"}, + [0xDB] = {"[", "{"}, + [0xDC] = {"\\", "|"}, + [0xDD] = {"]", "}"}, + [0xDE] = {"\'", "\""}, + [0x6A] = {"*"}, + [0x6B] = {"+"}, + [0x6D] = {"-"}, + [0x6E] = {"."}, + [0x6F] = {"/"} + }, { - namespace = "stats", - table = stats, - ["stat_set_int"] = true, - ["stat_set_float"] = true, - ["stat_set_bool"] = true, - ["stat_set_i64"] = true, - ["stat_set_u64"] = true, - ["stat_set_masked_int"] = true, - ["stat_set_masked_bool"] = true, + [0x41] = {"a"}, + [0x42] = {"b"}, + [0x43] = {"c"}, + [0x44] = {"d"}, + [0x45] = {"e"}, + [0x46] = {"f"}, + [0x47] = {"g"}, + [0x48] = {"h"}, + [0x49] = {"i"}, + [0x4A] = {"j"}, + [0x4B] = {"k"}, + [0x4C] = {"l"}, + [0x4D] = {"m"}, + [0x4E] = {"n"}, + [0x4F] = {"o"}, + [0x50] = {"p"}, + [0x51] = {"q"}, + [0x52] = {"r"}, + [0x53] = {"s"}, + [0x54] = {"t"}, + [0x55] = {"u"}, + [0x56] = {"v"}, + [0x57] = {"w"}, + [0x58] = {"x"}, + [0x59] = {"y"}, + [0x5A] = {"z"}, }, { - namespace = "script", - table = script, - ["set_global_f"] = true, - ["set_global_i"] = true, - ["set_global_s"] = true, - ["set_local_f"] = true, - ["set_local_i"] = true, - ["set_local_s"] = true, + [0x41] = {"a"}, + [0x42] = {"b"}, + [0x43] = {"c"}, + [0x44] = {"d"}, + [0x45] = {"e"}, + [0x46] = {"f"}, + [0x47] = {"g"}, + [0x48] = {"h"}, + [0x49] = {"i"}, + [0x4A] = {"j"}, + [0x4B] = {"k"}, + [0x4C] = {"l"}, + [0x4D] = {"m"}, + [0x4E] = {"n"}, + [0x4F] = {"o"}, + [0x50] = {"p"}, + [0x51] = {"q"}, + [0x52] = {"r"}, + [0x53] = {"s"}, + [0x54] = {"t"}, + [0x55] = {"u"}, + [0x56] = {"v"}, + [0x57] = {"w"}, + [0x58] = {"x"}, + [0x59] = {"y"}, + [0x5A] = {"z"}, + [0x60] = {"0"}, + [0x61] = {"1"}, + [0x62] = {"2"}, + [0x63] = {"3"}, + [0x64] = {"4"}, + [0x65] = {"5"}, + [0x66] = {"6"}, + [0x67] = {"7"}, + [0x68] = {"8"}, + [0x69] = {"9"}, + [0x30] = {"0"}, + [0x31] = {"1"}, + [0x32] = {"2"}, + [0x33] = {"3"}, + [0x34] = {"4"}, + [0x35] = {"5"}, + [0x36] = {"6"}, + [0x37] = {"7"}, + [0x38] = {"8"}, + [0x39] = {"9"} }, { - namespace = "native", - table = native, - ["call"] = true, + [0xBD] = {"-"}, + [0x6D] = {"-"}, + [0x60] = {"0"}, + [0x61] = {"1"}, + [0x62] = {"2"}, + [0x63] = {"3"}, + [0x64] = {"4"}, + [0x65] = {"5"}, + [0x66] = {"6"}, + [0x67] = {"7"}, + [0x68] = {"8"}, + [0x69] = {"9"}, + [0x30] = {"0"}, + [0x31] = {"1"}, + [0x32] = {"2"}, + [0x33] = {"3"}, + [0x34] = {"4"}, + [0x35] = {"5"}, + [0x36] = {"6"}, + [0x37] = {"7"}, + [0x38] = {"8"}, + [0x39] = {"9"} }, { - namespace = "web", - table = web, - ["post"] = true, - ["get"] = true, - ["request"] = true, - ["urlencode"] = true, - ["urldecode"] = true, + [0xBD] = {"-"}, + [0x6D] = {"-"}, + [0x60] = {"0"}, + [0x61] = {"1"}, + [0x62] = {"2"}, + [0x63] = {"3"}, + [0x64] = {"4"}, + [0x65] = {"5"}, + [0x66] = {"6"}, + [0x67] = {"7"}, + [0x68] = {"8"}, + [0x69] = {"9"}, + [0x30] = {"0"}, + [0x31] = {"1"}, + [0x32] = {"2"}, + [0x33] = {"3"}, + [0x34] = {"4"}, + [0x35] = {"5"}, + [0x36] = {"6"}, + [0x37] = {"7"}, + [0x38] = {"8"}, + [0x39] = {"9"}, + [0x6E] = {"."}, + [0xBE] = {"."}, }, { - namespace = "memory", - table = memory, - ["get_any"] = true, - ["get_entity"] = true, - ["get_ped"] = true, - ["get_vehicle"] = true, - ["get_object"] = true, - ["get_pickup"] = true, - ["read_u64"] = true, - ["read_u32"] = true, - ["read_u16"] = true, - ["read_u8"] = true, - ["read_i64"] = true, - ["read_i32"] = true, - ["read_i16"] = true, - ["read_i8"] = true, - ["read_f32"] = true, + [0xBD] = {"-"}, + [0x6D] = {"-"}, + [0x60] = {"0"}, + [0x61] = {"1"}, + [0x62] = {"2"}, + [0x63] = {"3"}, + [0x64] = {"4"}, + [0x65] = {"5"}, + [0x66] = {"6"}, + [0x67] = {"7"}, + [0x68] = {"8"}, + [0x69] = {"9"}, + [0x30] = {"0"}, + [0x31] = {"1"}, + [0x32] = {"2"}, + [0x33] = {"3"}, + [0x34] = {"4"}, + [0x35] = {"5"}, + [0x36] = {"6"}, + [0x37] = {"7"}, + [0x38] = {"8"}, + [0x39] = {"9"}, + [0x6E] = {"."}, + [0xBE] = {"."}, }, } -local trusted_names = { - [0] = "Stats", - "Globals / Locals", - "Natives", - "HTTP", - "Memory" -} - -local modified_functions = { - stats = {}, - script = {}, - native = {}, - web = {}, - memory = {}, -} +--Functions -for k, v in ipairs(limited_functions) do - local namespace = v.namespace - for name, data in pairs(v) do - if data == true then - modified_functions[namespace][name] = function(...) - local is_flag_on, notify = menu.is_trusted_mode_enabled(1 << (k-1)) - if is_flag_on then - return v.table[name](...) - elseif notify then - menu.notify("Trusted Flag '"..trusted_names[k-1].."' is not enabled.\nFunction used: "..namespace..'.'..name, "Cheese Menu", 5, 0x00ffff) - end + function gginput.do_key(key, pressed, funcPressed, ...) + if cheeseUtils.get_key(key):is_down() and ((utils.time_ms() > pressed[key]) or (pressed[key] == 0)) then + funcPressed(...) + if pressed[key] == 0 then + pressed[key] = utils.time_ms() + 500 + else + pressed[key] = utils.time_ms() + 30 end + elseif not cheeseUtils.get_key(key):is_down() then + pressed[key] = 0 end end -end --- -local function LoadScript(f) - if f.on then - if not f.data then - local Filename = f.name - local Filepath = Paths.Scripts .. "\\" .. Filename + --[[ function gginput.draw_outline(v2pos, v2size, color, thickness, reusablePos, reusablePos2) + local thickness_y = thickness / graphics.get_screen_height() * 2 + local thickness_x = thickness / graphics.get_screen_width() * 2 - if not utils.file_exists(Filepath) then - notify("Could not find script: " .. Filename,0xFF0000FF) - LoadedScripts[f.name] = nil - f.data = nil - f.on = false - return - end + reusablePos2.x, reusablePos2.y = v2pos.x, v2pos.y - print("Enabling script: " .. f.name) - f.data = {} - f.data.ScriptManager = true - f.data.features = {} - f.data.player_features = {} - f.data.threads = {} - f.data.script_hooks = {} - f.data.net_hooks = {} - f.data.events = {} - f.data.exits = {} - f.data.commands = {} + reusablePos2.y = v2pos.y - (v2size.y/2) + reusablePos.x, reusablePos.y = v2size.x + thickness_x, thickness_y + scriptdraw.draw_rect(reusablePos2, reusablePos, color) + + reusablePos2.y = v2pos.y + (v2size.y/2) + scriptdraw.draw_rect(reusablePos2, reusablePos, color) + + reusablePos2.y = v2pos.y + reusablePos2.x = v2pos.x - (v2size.x/2) + reusablePos.x, reusablePos.y = thickness_x, v2size.y - thickness_y + scriptdraw.draw_rect(reusablePos2, reusablePos, color) + + reusablePos2.x = v2pos.x + (v2size.x/2) + + scriptdraw.draw_rect(reusablePos2, reusablePos, color) + end ]] + + function gginput.draw_input(inputTable, bg_color, inputbox_color, outline_color, text_color, tableOfPos_Size) + if #inputTable.string ~= gginput.drawStuff.cached_table_length then + gginput.drawStuff.string = table.concat(inputTable.string) + gginput.drawStuff.indicator_string = gginput.drawStuff.string:sub(1, inputTable.cursor-1).."_"..gginput.drawStuff.string:sub(inputTable.cursor+1, #gginput.drawStuff.string) + gginput.drawStuff.cached_text_width = scriptdraw.get_text_size(gginput.drawStuff.string:sub(1, inputTable.cursor-1):gsub(" ", "."), gginput.drawStuff.text_size).x/graphics.get_screen_width()*2 + gginput.drawStuff.cached_table_length = #inputTable.string + end + local drawString = gginput.indicator and gginput.drawStuff.indicator_string or gginput.drawStuff.string + --[[ if gginput.indicator then + gginput.drawStuff.string = gginput.drawStuff.string:sub(1, inputTable.cursor-1).."_"..gginput.drawStuff.string:sub(inputTable.cursor+1, #gginput.drawStuff.string) + end ]] - local env = CloneTable(_G) - function env.SetGlobal(Name, Value) - assert(type(Name) == "string", "Arg #1 (Name) must be a string") + scriptdraw.draw_rect(tableOfPos_Size.middle_pos, tableOfPos_Size.backround_size, bg_color) -- background + cheeseUtils.draw_outline(tableOfPos_Size.middle_pos, tableOfPos_Size.outline_size, outline_color, 2) + scriptdraw.draw_rect(tableOfPos_Size.middle_pos, tableOfPos_Size.inputBox_size, inputbox_color) -- inputBox + scriptdraw.draw_text(drawString, tableOfPos_Size.text_pos, tableOfPos_Size.backround_size, gginput.drawStuff.text_size, text_color, 0) + scriptdraw.draw_text(inputTable.title, tableOfPos_Size.title_pos, tableOfPos_Size.backround_size, gginput.drawStuff.text_size+0.4, 0xDC000000 | (text_color & 0xFFFFFF), 0) - _G[Name] = Value - for i=FirstChild,Parent.child_count do - local feat = Parent.children[i] - if feat.data and feat.data.env then - feat.data.env[Name] = Value - end - end - end + tableOfPos_Size.underscore_pos.x = -0.4609375 + gginput.drawStuff.cached_text_width + 0.0015625 + scriptdraw.draw_text("_", tableOfPos_Size.underscore_pos, tableOfPos_Size.backround_size, gginput.drawStuff.text_size, 0x64000000 | (text_color & 0xFFFFFF), 0) + end - for namespace, func_table in pairs(modified_functions) do - local env_namespace = env[namespace] - for name, func in pairs(func_table) do - env_namespace[name] = func - end + gginput.tableOfPos_Size = { + middle_pos = v2(0, 0), + backround_size = v2(2, 2), + outline_size = v2(0.9390625, 0.06180555555555), + inputBox_size = v2(0.9375, 0.0590277777777778), + text_pos = v2(-0.4609375, 0.01111111111111111), + underscore_pos = v2(0, 0.01111111111111111), + title_pos = v2(0, 0.10555554), + } + function gginput.draw_thread(inputTable) + gginput.tableOfPos_Size.title_pos.x = -scriptdraw.get_text_size(inputTable.title, gginput.drawStuff.text_size+0.4).x/graphics.get_screen_width() + while true do + for i = 0, 357 do + controls.disable_control_action(0, i, true) + end + if utils.time_ms() > gginput.indicator_timer then + gginput.indicator = not gginput.indicator + gginput.indicator_timer = utils.time_ms() + 750 end + gginput.draw_input(inputTable, 0x64000000, 0xC8000000, 0xC8FFFFFF, 0xC8FFFFFF, gginput.tableOfPos_Size) + system.wait(0) + end + end - env.cheeseUIdata = cheeseUIdata + function gginput.disableESC() + while cheeseUtils.get_key(0x1B):is_down() do + controls.disable_control_action(0, 200, true) + system.wait(0) + end + controls.disable_control_action(0, 200, true) + end - env.menu.add_feature = function(...) - local feat = add_feature(...) - if feat then - f.data.features[feat.id] = feat - end - return feat - end - env.menu.add_player_feature = function(...) - local feat = add_player_feature(...) - if feat then - f.data.player_features[feat.id] = feat - end - return feat - end - env.menu.delete_feature = function(id) - local success = delete_feature(id) - if success then - f.data.features[id] = nil - end - return success - end - env.menu.delete_player_feature = function(id) - local success = delete_player_feature(id) - if success then - f.data.player_features[id] = nil - end - return success - end - env.menu.create_thread = function(...) - local id = create_thread(...) - if id then - f.data.threads[id] = true - end - return id - end - env.menu.delete_thread = function(id) - local success = delete_thread(id) - if success then - f.data.threads[id] = nil - end - return success - end - env.hook.register_script_event_hook = function(...) - local id = register_script_event_hook(...) - if id then - f.data.script_hooks[id] = true - end - return id - end - env.hook.remove_script_event_hook = function(id) - local success = remove_script_event_hook(id) - if success then - f.data.script_hooks[id] = nil - end - return success - end - env.hook.register_net_event_hook = function(...) - local id = register_net_event_hook(...) - if id then - f.data.net_hooks[id] = true - end - return id - end - env.hook.remove_net_event_hook = function(id) - local success = remove_net_event_hook(id) - if success then - f.data.net_hooks[id] = nil - end - return success - end - env.event.add_event_listener = function(eventName, callback) - local id = add_event_listener(eventName, callback) - if id then - f.data.events[eventName] = f.data.events[eventName] or {} - f.data.events[eventName][id] = true - if eventName == "exit" then - f.data.exits[id] = callback - end - end - return id - end - env.event.remove_event_listener = function(eventName, id) - local success = remove_event_listener(eventName, id) - if success and f.data.events[eventName] then - f.data.events[eventName][id] = nil - if eventName == "exit" then - f.data.exits[id] = nil - end - end - return success - end - env.console.register_command = function(name, ...) - if register_command(name, ...) then - f.data.commands[name] = true - return true - end - return false - end - env.console.remove_command = function(name) - if remove_command(name) then - for i=FirstChild,Parent.child_count do - local feat = Parent.children[i] - if feat.data and feat.data.commands then - feat.data.commands[name] = nil + function gginput.moveCursorRight(inputTable, moveAmount) + if cheeseUtils.get_key(0x11):is_down() then + for i = inputTable.cursor+1, #inputTable.string do + if inputTable.string[i] == " " then + if i == inputTable.cursor+1 then + for i = inputTable.cursor+1, #inputTable.string do + if inputTable.string[i] ~= " " then + inputTable.cursor = i-1 + break + elseif i == #inputTable.string then + inputTable.cursor = #inputTable.string + end end + else + inputTable.cursor = i-1 end - return true + break + elseif i == #inputTable.string then + inputTable.cursor = #inputTable.string end - return false - end - env.load = function(chunk, chunkname, mode, env2) - return og_load(chunk, chunkname or "=(load)", mode or "bt", env2 or env) - end - env.dofile = function(filename) - return og__loadfile(filename, "bt", env)() - end - env.loadfile = function(filename, mode, env2) - return og__loadfile(filename, mode or "bt", env2 or env) - end - env._loadfile = function(filename, mode, env) - return og__loadfile(filename, mode or "bt", env or env) end - local loaders = {} - local loaded = {} - env.require = function(Library) - assert(Library ~= nil, "You must pass a Library name") - assert(type(Library) == "string", "Library name must be a string") - if loaders[Library] then - local status, result = og_pcall(loaders[Library]) - if status then - if result == nil then - return true - else - loaded[Library] = result - return loaded[Library] - end - end - end - local libParts = {} - for part in Library:gmatch("[^.]+") do - libParts[#libParts + 1] = part - end - local subDirTbl = {} - if #libParts > 1 then - for i=1,#libParts-1 do - subDirTbl[#subDirTbl + 1] = libParts[i] - end - end - local subDir = table.concat(subDirTbl, "/") .. "/" - local lib = libParts[#libParts] - for rootDir in env.package.path:gmatch("[^;]+") do - local path = rootDir:gsub("%?", subDir .. lib) - if utils.file_exists(path) then - local chunk, err = og__loadfile(path, "bt", env) - assert(chunk, "Failed to load \"" .. Library .. "\": " .. tostring(err)) - local status, result = og_pcall(chunk) - assert(status, "Failed to exec \"" .. Library .. "\": " .. tostring(result)) - loaders[Library] = chunk - if result == nil then - return true - else - loaded[Library] = result - return loaded[Library] + elseif not (inputTable.cursor >= #inputTable.string) then + inputTable.cursor = inputTable.cursor + moveAmount + end + gginput.drawStuff.indicator_string = gginput.drawStuff.string:sub(1, inputTable.cursor-1).."_"..gginput.drawStuff.string:sub(inputTable.cursor+1, #gginput.drawStuff.string) + gginput.drawStuff.cached_text_width = scriptdraw.get_text_size(gginput.drawStuff.string:sub(1, inputTable.cursor-1):gsub(" ", "."), gginput.drawStuff.text_size).x/graphics.get_screen_width()*2 + end + function gginput.moveCursorLeft(inputTable, moveAmount) + if cheeseUtils.get_key(0x11):is_down() then + for i = inputTable.cursor, 2, -1 do + if inputTable.string[i] == " " then + if i == inputTable.cursor then + for i = inputTable.cursor, 2, -1 do + if inputTable.string[i] ~= " " then + inputTable.cursor = i + break + elseif i == 2 then + inputTable.cursor = 1 + end end + else + inputTable.cursor = i end + break + elseif i == 2 then + inputTable.cursor = 1 end - error("Failed to find library with name \"" .. Library .. "\"") end - env.clear_lib_cache = function(Library) - if Library then - local retVal = loaders[Library] ~= nil and loaded[Library] ~= nil - loaders[Library] = nil - loaded[Library] = nil - return retVal - else - loaders = {} - loaded = {} - return true + elseif not (inputTable.cursor <= 1) then + inputTable.cursor = inputTable.cursor - moveAmount + end + gginput.drawStuff.indicator_string = gginput.drawStuff.string:sub(1, inputTable.cursor-1).."_"..gginput.drawStuff.string:sub(inputTable.cursor+1, #gginput.drawStuff.string) + gginput.drawStuff.cached_text_width = scriptdraw.get_text_size(gginput.drawStuff.string:sub(1, inputTable.cursor-1):gsub(" ", "."), gginput.drawStuff.text_size).x/graphics.get_screen_width()*2 + end + + function gginput.write_char(keyTable, inputTable) + if cheeseUtils.get_key(0x10):is_down() then + if inputTable.cursor == #inputTable.string then + inputTable.string[#inputTable.string+1] = keyTable[2] or keyTable[1]:upper() + else + table.insert(inputTable.string, inputTable.cursor+1, keyTable[2] or keyTable[1]:upper()) + end + else + if inputTable.cursor == #inputTable.string then + inputTable.string[#inputTable.string+1] = keyTable[1] + else + table.insert(inputTable.string, inputTable.cursor+1, keyTable[1]) + end + end + + gginput.moveCursorRight(inputTable, 1) + end + + function gginput.paste(stringInput, inputTable) + stringInput = tostring(stringInput) + if inputTable.cursor == #inputTable.string then + for char in stringInput:gmatch(".") do + if #inputTable.string-1 ~= inputTable.limit then + inputTable.string[#inputTable.string+1] = char end end - env.get_lib_cache = function() - local cache = {} - for k,v in pairs(loaded) do - cache[k] = v + inputTable.cursor = #inputTable.string + else + for char in stringInput:gmatch(".") do + if #inputTable.string-1 ~= inputTable.limit then + table.insert(inputTable.string, inputTable.cursor+1, char) + inputTable.cursor = inputTable.cursor+1 end - return cache end - f.data.env = env + end + end - local chunk, err = og__loadfile(Filepath, "bt", f.data.env) - if chunk then - local status, result = og_pcall(chunk) - if not status then - menu.create_thread(UnloadScript, f) - notify("Error executing script: " .. Filename .. "\n" .. tostring(result), 0xFF0000FF) - else - notify("Loaded script: " .. Filename, 0xFF00FF00) - LoadedScripts[Filename] = true + function gginput.delete_char(inputTable, range_start, range_end) + if not range_start then + gginput.moveCursorLeft(inputTable, 1) + if inputTable.cursor == #inputTable.string-1 then + inputTable.string[#inputTable.string] = nil + else + table.remove(inputTable.string, inputTable.cursor+1) + end + else + if range_end ~= #inputTable.string then + inputTable.cursor = range_start + for i = range_end, range_start+1, -1 do + table.remove(inputTable.string, i) end else - menu.create_thread(UnloadScript, f) - notify("Error loading script: " .. Filename .. "\n" .. err, 0xFF0000FF) + inputTable.cursor = range_start + for i = range_start+1, #inputTable.string do + inputTable.string[i] = i == 1 and "" or nil + end end end - else - if f.data then - menu.create_thread(UnloadScript, f) - end - end -end - -local function CaseInsensitiveSort(a, b) - return tostring(a):lower() < tostring(b):lower() -end - -local function LoadScripts(feat) - if FilterFeat then - FilterFeat.data = "" - FilterFeat.name = "Filter: " end - local files = utils.get_all_files_in_directory(Paths.Scripts, "lua") - local files2 = {} - for i=1,#files do - files2[files[i]] = true - end - local files3 = utils.get_all_files_in_directory(Paths.Scripts, "luac") - for i=1,#files3 do - if not files2[files3[i]] then - files[#files + 1] = files3[i] - files2[files3[i]] = true - end - end - table.sort(files, CaseInsensitiveSort) - local threads = {} - for i=Parent.child_count,FirstChild,-1 do - if not files2[Parent.children[i].name] then - threads[#threads + 1] = create_thread(DeleteFeature, Parent.children[i]) + function gginput.delete(inputTable) + if cheeseUtils.get_key(0x11):is_down() then + local range_start + for i = inputTable.cursor, 1, -1 do + if inputTable.string[i] == " " then + if i == inputTable.cursor then + for i = inputTable.cursor, 1, -1 do + if inputTable.string[i] ~= " " then + range_start = i + break + end + end + else + range_start = i + end + break + elseif i == 1 then + range_start = 1 + end + end + gginput.delete_char(inputTable, range_start, inputTable.cursor) else - files2[Parent.children[i].name] = false - Parent.children[i].hidden = false + gginput.delete_char(inputTable) end end - for i=AutoloadParent.child_count,AutoloadFirstChild,-1 do - threads[#threads + 1] = create_thread(DeleteFeature, AutoloadParent.children[i]) - end - local waiting = true - while waiting do - local running = false - for i=1,#threads do - running = running or (not menu.has_thread_finished(threads[i])) + + local shift_esc = MenuKey() + shift_esc:push_vk(0x10) + shift_esc:push_vk(0x1B) + function gginput.reset_menu_nav() + while true do + if shift_esc:is_down() then + menu.set_menu_can_navigate(true) + menu.notify("Reset menu navigation") + break + end + system.wait(0) end - waiting = running - system_wait(0) end - for i=1,#files do - if not ExcludedScripts[files[i]:lower()] then - if files2[files[i]] then - menu_originals.add_feature(files[i], "toggle", ParentId, LoadScript, f) - end - local autoloadFeat = menu_originals.add_feature(files[i], "value_i", AutoloadParentId) - autoloadFeat.min = 1 - autoloadFeat.max = 999 - autoloadFeat.mod = 1 - local val = AutoloadTbl[files[i]] - if val then - autoloadFeat.value = type(val) == "number" and val or 1 - autoloadFeat.on = true + + + function gginput.get_input(title, default, len, inputtype, inputTable) + local menuNavThread = menu.create_thread(gginput.reset_menu_nav) + menu.set_menu_can_navigate(false) + local pressed = {} + + for k, v in pairs(gginput.char_codes[1]) do + if cheeseUtils.get_key(k):is_down() then + pressed[k] = utils.time_ms() + 2000 else - autoloadFeat.value = 1 + pressed[k] = 0 end end - end -end -local ExitFeat = menu_originals.add_feature("Exit Listener", "toggle", ParentId, function(f) - if not f.on then - print("Exit Listener Feat Off") - Exiting = true - end -end) -ExitFeat.hidden = true -ExitFeat.on = true + inputtype = tonumber(inputtype) + inputtype = (inputtype <= 5 and inputtype >= 0) and inputtype or 0 + inputtype = inputtype + 1 + local charTable = gginput.char_codes[inputtype] + local pasteCheck = {} + for k, v in pairs(charTable) do + local concatenated = table.concat(v) + pasteCheck[#pasteCheck+1] = concatenated + if concatenated ~= concatenated:upper() then + pasteCheck[#pasteCheck+1] = concatenated:upper() + end + end + pasteCheck = "[^"..table.concat(pasteCheck).."]" -local delayFeat + inputTable = inputTable or {} + inputTable.string = {""} + inputTable.state = 1 + inputTable.cursor = 1 + inputTable.title = tostring(title) + inputTable.limit = tonumber(len) or 25 -menu_originals.add_feature("Save Autoload Scripts", "action", AutoloadParentId, function(f) - AutoloadTbl = { - ["autoload_delay_between_scripts"] = delayFeat.value - } - for i=AutoloadFirstChild,AutoloadParent.child_count do - local child = AutoloadParent.children[i] - if child.on then - AutoloadTbl[child.name] = child.value + gginput.paste(default, inputTable) + + gginput.drawStuff.text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.6+0.2 + + local drawThread = menu.create_thread(gginput.draw_thread, inputTable) + while cheeseUtils.get_key(0x0D):is_down() do + system.wait() + end + while not (cheeseUtils.get_key(0x0D):is_down() or cheeseUtils.get_key(0x1B):is_down()) do + for k, v in pairs(charTable) do + if not cheeseUtils.get_key(0x11):is_down() and #inputTable.string-1 ~= len then + gginput.do_key(k, pressed, gginput.write_char, v, inputTable) + end + end + + if cheeseUtils.get_key(0x11, 0x56):is_down() then + gginput.paste(utils.from_clipboard():gsub("[\r\n]", " "):gsub(pasteCheck, ""), inputTable) + while cheeseUtils.get_key(0x11, 0x56):is_down() do + system.wait() + end + elseif cheeseUtils.get_key(0x11, 0x43):is_down() then + utils.to_clipboard(table.concat(inputTable.string)) + end + + gginput.do_key(0x08, pressed, gginput.delete, inputTable) -- backspace + gginput.do_key(0x27, pressed, gginput.moveCursorRight, inputTable, 1) -- right + gginput.do_key(0x25, pressed, gginput.moveCursorLeft, inputTable, 1) -- left + system.wait(0) end - end - Settings.Save(ScriptName, AutoloadTbl) - notify("Saved autoload scripts.", 0xFF00FF00) -end) -delayFeat = menu_originals.add_feature("Delay between scripts (ms)", "action_value_i", AutoloadParentId, function(f) - local r, s - repeat - r, s = input.get("Enter delay", f.value, 4, eInputType.IT_NUM) - if r == 2 then return HANDLER_POP end - system_wait(0) - until r == 0 + gginput.disableESC() - local num = tonumber(s) - if num and num >= f.min and num <= f.max then - f.value = num - end -end) -delayFeat.min = 0 -delayFeat.max = 1000 -delayFeat.mod = 1 -local delayVal = AutoloadTbl["autoload_delay_between_scripts"] -if type(delayVal) ~= "number" or delayVal < delayFeat.min then - delayVal = delayFeat.min -elseif delayVal > delayFeat.max then - delayVal = delayFeat.max -end -delayFeat.value = delayVal + local success = cheeseUtils.get_key(0x0D):is_down() + while cheeseUtils.get_key(0x0D):is_down() do + system.wait(0) + end + menu.delete_thread(drawThread) + menu.delete_thread(menuNavThread) + menu.set_menu_can_navigate(true) + inputTable.string = table.concat(inputTable.string) + inputTable.state = success and 0 or 2 -local RefreshFeat = menu_originals.add_feature("Refresh Scripts", "action", ParentId, function(f) - LoadScripts(f) - notify("Refreshed scripts list.", 0xFF00FF00) -end) + gginput.drawStuff.string = "" + gginput.drawStuff.indicator_string = "" + gginput.drawStuff.cached_text_width = 0 + gginput.drawStuff.cached_table_length = 0 -local function FocusFeat(f) - if f.data.parent then - f.data.parent:toggle() + return inputTable.state, success and inputTable.string or nil end - f.data:select() -end +-- -local function ToggleFeat(f) - f.data:toggle() -end +return gginput +]=], + ["GLTW.lua"] = [==[-- Made by GhostOne +-- L00naMods "Even if you say L00na is a bitch just put my name in there somewhere" +-- Ghost's Lua Table Writer +--[[ +nil gltw.write(table table, string name, string path|nil, table index exclusions, skip empty tables) +-- example gltw.write({name = "l00na", iq = -1, braincells = {}}, "something", "folder1\\", {"name"}, true) < this will not write 'name' (excluded) or 'braincells' (empty) -local SearchParentId = menu_originals.add_feature("Search Script Features", "parent", ParentId).id -menu_originals.add_feature("Filter: ", "action", SearchParentId, function(f) - local r, s - repeat - r, s = input.get("Enter search query", f.data, 64, 0) - if r == 2 then return HANDLER_POP end - system_wait(0) - until r == 0 +table[] gltw.read(string name, string path|nil(in same path as lua), table|nil, bool|nil) +-- if a table is the 3rd arg then whatever is read from the file will be added to it without overwriting stuff that isn't in the saved file +-- if the 4th arg is true the function won't throw an error if the file doesn't exist and will return nil +]] - local threads = {} - for i=f.parent.child_count,2,-1 do - threads[#threads + 1] = create_thread(DeleteFeature, f.parent.children[i]) - end +local gltw = {} +local type = type +local l_next = next +local ipairs = ipairs - local waiting = true - while waiting do - local running = false - for i=1,#threads do - running = running or (not menu.has_thread_finished(threads[i])) +function gltw.write_table(tableTW, indentation, exclusions, exclude_empty, string_lines) + for k, v in l_next, tableTW do + if not exclusions[k] then + local typeofv = type(v) + local index + if type(k) == "number" then + index = "["..k.."] = " + else + index = "[\""..k.."\"] = " + end + + if typeofv == "string" then + string_lines[#string_lines + 1] = indentation..index.."[=["..v.."]=]," + elseif typeofv ~= "function" and typeofv ~= "table" then + string_lines[#string_lines + 1] = indentation..index..tostring(v).."," + elseif typeofv == "table" and (l_next(v) or not exclude_empty) then + string_lines[#string_lines + 1] = indentation..index.."{" + gltw.write_table(v, indentation.." ", exclusions, exclude_empty, string_lines) + string_lines[#string_lines + 1] = indentation.."}," + end end - waiting = running - system_wait(0) end +end - s = Trim(s) - if s:len() == 0 then - f.data = "" - f.name = "Filter: " - return HANDLER_POP +function gltw.write(tableTW, name, path, exclusions, exclude_empty, compiled) + local convertedExclusions = {} + if exclusions then + for _, v in ipairs(exclusions) do + convertedExclusions[v] = true + end end + assert(tableTW, "no table was provided"..(name and " to write for file '"..name.."'" or "")) - local count = 0 - for i=4,RefreshFeat.parent.child_count do - local child = RefreshFeat.parent.children[i] - if child.data and child.data.features and type(child.data.features) == "table" then - for j=1,#child.data.features do - local feat = child.data.features[j] - if feat then - if feat.name:lower():find(s:lower(), 1, true) then - if feat.type == 2048 then - menu_originals.add_feature(FileNameWithoutExtension(child.name) .. " | " .. feat.name, "parent", SearchParentId, ToggleFeat).data = feat - else - menu_originals.add_feature(FileNameWithoutExtension(child.name) .. " | " .. feat.name, "action", SearchParentId, FocusFeat).data = feat - end - count = count + 1 - end - end - end - end + if name then + path = path or "" + assert(type(name) == "string" and type(path) == "string", "name or path isn't a string") end - f.data = s - f.name = "Filter: <" .. s .. "> (" .. count .. ")" -end).data = "" + local string_lines = {} -FilterFeat = menu_originals.add_feature("Filter: ", "action", ParentId, function(f) - local r, s - repeat - r, s = input.get("Enter search query", f.data, 64, 0) - if r == 2 then return HANDLER_POP end - system_wait(0) - until r == 0 + string_lines[#string_lines + 1] = "return {" + gltw.write_table(tableTW, " ", convertedExclusions, exclude_empty, string_lines) + string_lines[#string_lines + 1] = "}" - s = Trim(s) - if s:len() == 0 then - f.data = "" - f.name = "Filter: " - for i=f.parent.child_count,FirstChild,-1 do - f.parent.children[i].hidden = false - end - return HANDLER_POP - end + if name then + local file = io.open(path..name..".lua", "wb") + assert(file, "'"..name.."' was not created.") - local count = 0 - for i=f.parent.child_count,FirstChild,-1 do - if f.parent.children[i].name:lower():find(s, 1, true) then - f.parent.children[i].hidden = false - count = count + 1 - else - f.parent.children[i].hidden = true - end - end + local stringified = table.concat(string_lines, "\n") - f.data = s - f.name = "Filter: <" .. s .. "> (" .. count .. ")" -end) -FilterFeat.data = "" + file:write(compiled and string.dump(load(stringified), true) or stringified) -ProddysScriptManager = true + file:flush() + file:close() + end -create_thread(function(f) - FirstChild = Parent.child_count + 1 - AutoloadFirstChild = AutoloadParent.child_count + 1 - LoadScripts(f) + return string_lines +end - local delay = 0 - local autoload = {} - for k,v in pairs(AutoloadTbl) do - if k == "autoload_delay_between_scripts" then - if type(v) == "number" and v >= 0 then - delay = v +function gltw.add_to_table(getTable, addToTable, typeMatched) + assert(type(getTable) == "table" and type(addToTable) == "table", "args have to be tables") + for k, v in l_next, getTable do + if type(v) ~= "table" then + if typeMatched and (type(getTable[k]) == type(addToTable[k]) or not addToTable[k]) or not typeMatched then + addToTable[k] = getTable[k] end else - if type(v) ~= "number" then v = 1 end - autoload[v] = autoload[v] or {} - autoload[v][#autoload[v] + 1] = k + if type(addToTable[k]) ~= "table" and not typeMatched then + addToTable[k] = {} + end + if type(addToTable[k]) == "table" then + gltw.add_to_table(getTable[k], addToTable[k]) + end end end +end - print("Autoloading with delay: " .. delay) - - if #autoload > 0 then - local scripts = {} - for i=FirstChild,Parent.child_count do - local feat = Parent.children[i] - scripts[feat.name] = feat - end +function gltw.read(name, path, addToTable, typeMatched, overrideError) + if overrideError and not utils.file_exists(path..name..".lua") then + return + end - local ids = {} - for k in pairs(autoload) do - ids[#ids + 1] = k - end - table.sort(ids) + path = path or "" + if type(tableRT) == "string" then + name, path = tableRT, name or path + tableRT = nil + end - for i=1,#ids do - local tbl = autoload[ids[i]] - for j=1,#tbl do - local script = scripts[tbl[j]] - if script then - system_wait(delay) - print("Enabled autoload script: " .. script.name) - script.on = true - end - end - end + local readTable = loadfile(path..name..".lua", "tb")() + if addToTable then + gltw.add_to_table(readTable, addToTable, typeMatched) end -end, RefreshFeat) + return readTable +end ---notify(ScriptName .. " v" .. Version .. " loaded.", 0xFF0FF00)]=], -} +return gltw +]==], +} \ No newline at end of file From d287a2e0b869d2e6c81f78c37d400f022a15ab9c Mon Sep 17 00:00:00 2001 From: GhustOne <71855034+GhustOne@users.noreply.github.com> Date: Thu, 5 Jan 2023 23:09:19 +0300 Subject: [PATCH 06/11] Update CMAutoUpdater.lua --- CMAutoUpdater.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMAutoUpdater.lua b/CMAutoUpdater.lua index 6c2e2fd..45b4521 100644 --- a/CMAutoUpdater.lua +++ b/CMAutoUpdater.lua @@ -9,7 +9,7 @@ local filePaths = { ["Proddy's Script Manager.lua"] = appdata_path.."\\scripts\\cheesemenu\\libs\\Proddy's Script Manager.lua", } -local responseCode, responseBody = web.get([[https://raw.githubusercontent.com/GhustOne/CheeseMenu/dev/aioUpdate.lua]]) +local responseCode, responseBody = web.get([[https://raw.githubusercontent.com/GhustOne/CheeseMenu/main/aioUpdate.lua]]) if responseCode ~= 200 then print("Failed to download update.") status = false From de7f2f1ddb4edace317f09d98184d3e8c3615fb4 Mon Sep 17 00:00:00 2001 From: GhustOne <71855034+GhustOne@users.noreply.github.com> Date: Thu, 5 Jan 2023 23:25:35 +0300 Subject: [PATCH 07/11] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ad84bdc..393aa1a 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,8 @@ How to install 1. Download by going to [Releases](https://github.com/GhustOne/CheeseMenu/releases) and downloading cheesemenu.zip on the latest release 2. Simply put `cheesemenu.lua` and `cheesemenu` folder that are in the downloaded zip in the scripts folder for 2t1 and load it -Any scripts loaded after will be embedded in cheesemenu +Load other scripts through `Local > Script Features > Cheese Menu > Proddy's Script Manager`. +Don't forget to enable trusted mode. Controls are in Script Features > Cheese Menu > Controls From 4e60a17c33816dbe111e6bfd08ccae654569cca1 Mon Sep 17 00:00:00 2001 From: GhustOne <71855034+GhustOne@users.noreply.github.com> Date: Thu, 5 Jan 2023 23:32:25 +0300 Subject: [PATCH 08/11] Update CHANGELOG.txt --- CHANGELOG.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index c046884..eae4340 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,6 +1,7 @@ - Added feature hints -- Added support for gif, 2t1 and dds headers (old gif folders still work) +- Added support for gif, 2t1 and dds headers (old gif folders still work, all saved UIs will have no header) - Added gradient support for features (UIs will have to be edited and resaved) - Added customizable sizes for footer text and hint text - Improved hotkey activation (shouldn't activate when input box is open, will add console later) +- Improved update download (thanks to Proton#5503's idea) From f60078f67948e829a67769856fc35cb5d158262d Mon Sep 17 00:00:00 2001 From: GhustOne <71855034+GhustOne@users.noreply.github.com> Date: Thu, 5 Jan 2023 23:36:11 +0300 Subject: [PATCH 09/11] Update aioUpdate.lua --- aioUpdate.lua | 7760 ++++++++++++++++++++++++------------------------- 1 file changed, 3880 insertions(+), 3880 deletions(-) diff --git a/aioUpdate.lua b/aioUpdate.lua index 458e8b0..a4a0e0c 100644 --- a/aioUpdate.lua +++ b/aioUpdate.lua @@ -1,1647 +1,710 @@ return { - ["Proddy's Script Manager.lua"] = [=[local ScriptName = "Proddy's Script Manager (CheeseMenu)" -local Version = "2.3.2" -local Exiting = false - -local Paths = {} -Paths.Root = utils.get_appdata_path("PopstarDevs", "2Take1Menu") -Paths.Cfg = Paths.Root .. "\\cfg" -Paths.LogFile = Paths.Root .. "\\" .. ScriptName .. ".log" -Paths.Scripts = Paths.Root .. "\\scripts" - -local og_loadfile = loadfile -local og__loadfile = _loadfile -local og_load = load -local og_pcall = _pcall -local io_open = io.open -local os_date = os.date -local string_format = string.format -local system_wait = system.wait - -local basePrint = print -local function print(...) - basePrint(...) - local success, result = og_pcall(function(...) - local args = {...} - if #args == 0 then - return - end - - local currTime = os_date("*t") - local file = io_open(Paths.LogFile, "a") + ["CheeseUtilities.lua"] = [=[--Made by GhostOne +local cheeseUtils = {} - for i=1,#args do - file:write(string_format("[%02d-%02d-%02d %02d:%02d:%02d] <%s> %s\n", currTime.year, currTime.month, currTime.day, currTime.hour, currTime.min, currTime.sec, Version, tostring(args[i]))) +-- Credit to kektram for this whole function ~ a little modified to focus on fractionals +cheeseUtils.memoize = {} +do + local sign_bit_x = 1 << 62 + local sign_bit_y = 1 << 61 + local max_30_bit_num = 1073740823 + local v2 = v2 + local memoized = {} + function cheeseUtils.memoize.v2(x, y) + x = x or 0 + y = y or 0 + local xi = x * 100000000 // 1 -- modified from 1000 to 100,000,000 to support up to 10^-7 fractional digits ~ this limits it to either single or double digits with fractions + local yi = y * 100000000 // 1 -- same here + if xi >= -max_30_bit_num + and xi <= max_30_bit_num + and yi >= -max_30_bit_num + and yi <= max_30_bit_num then + local signs = 0 + if xi < 0 then + xi = xi * -1 + signs = signs | sign_bit_x + end + if yi < 0 then + yi = yi * -1 + signs = signs | sign_bit_y + end + local hash = signs | xi << 30 | yi + memoized[hash] = memoized[hash] or v2(x, y) + return memoized[hash] + else + return v2(x, y) end - - file:close() - end, ...) - if not success then - basePrint("Error writing log: " .. result) end end +-- -local notif = menu.notify -local function notify(msg, colour) - notif(msg, ScriptName .. " v" .. Version, nil, colour) - print(msg) -end - -if ProddysScriptManager then - notify(ScriptName .. " already loaded.", 0xFF50C8F0) - return -end +function cheeseUtils.draw_outline(v2pos, v2size, color, thickness) + local thickness_y = thickness / graphics.get_screen_height() * 2 + local thickness_x = thickness / graphics.get_screen_width() * 2 ---notify(ScriptName .. " v" .. Version .. " loading...") + scriptdraw.draw_rect( + cheeseUtils.memoize.v2(v2pos.x, v2pos.y - (v2size.y/2)), + cheeseUtils.memoize.v2(v2size.x + thickness_x, thickness_y), + color + ) -local function CloneTable(obj, seen) - if type(obj) ~= 'table' then - return obj - end + scriptdraw.draw_rect( + cheeseUtils.memoize.v2(v2pos.x, v2pos.y + (v2size.y/2)), + cheeseUtils.memoize.v2(v2size.x + thickness_x, thickness_y), + color + ) - if seen and seen[obj] then - return seen[obj] - end + scriptdraw.draw_rect( + cheeseUtils.memoize.v2(v2pos.x - (v2size.x/2), v2pos.y), + cheeseUtils.memoize.v2(thickness_x, v2size.y - thickness_y), + color + ) - local s = seen or {} - local res = {} - s[obj] = res + scriptdraw.draw_rect( + cheeseUtils.memoize.v2(v2pos.x + (v2size.x/2), v2pos.y), + cheeseUtils.memoize.v2(thickness_x, v2size.y - thickness_y), + color + ) +end - for k, v in pairs(obj) do - res[CloneTable(k, s)] = CloneTable(v, s) +-- Credit to Proddy for this function +cheeseUtils.Keys = {} +function cheeseUtils.get_key(...) + local args = {...} + assert(#args > 0, "must give at least one key") + local ID = table.concat(args, "|") + if not cheeseUtils.Keys[ID] then + local key = MenuKey() + for i=1,#args do + key:push_vk(args[i]) + end + cheeseUtils.Keys[ID] = key end - return setmetatable(res, getmetatable(obj)) --Should definitely clone the metatable + return cheeseUtils.Keys[ID] end -local function Trim(s) - local n = s:find"%S" - return n and s:match(".*%S", n) or "" -end +function cheeseUtils.new_reusable_v2(limit) + limit = limit or 2 -local function FileNameWithoutExtension(FileName) - local name = FileName:match("(.+)%.") - return name or FileName -end + local counter = 1 + local v2Table = {} + for i = 1, limit do + v2Table[i] = v2() + end -local ExcludedScripts = {} -ExcludedScripts["autoexec.lua"] = true -ExcludedScripts["autoexec.luac"] = true -ExcludedScripts["cheesemenu.lua"] = true -ExcludedScripts[debug.getinfo(1, "S").source:sub(Paths.Scripts:len() + 3):lower()] = true + return function(x, y) + local vector2d = v2Table[counter] + counter = counter + 1 + counter = counter <= limit and counter or 1 -local Settings = {} + vector2d.x, vector2d.y = x, y -function Settings.Save(SettingsFile, SettingsTbl) - assert(SettingsFile, "Nil passed for SettingsFile to Settings.Save") - assert(type(SettingsTbl) == "table", "Not a table passed for SettingsTbl to Settings.Save") - local file = io.open(Paths.Cfg .. "\\" .. SettingsFile .. ".cfg", "w") - local keys = {} - for k in pairs(SettingsTbl) do - keys[#keys + 1] = k - end - table.sort(keys) - for i=1,#keys do - file:write(tostring(keys[i]) .. "=" .. tostring(SettingsTbl[keys[i]]) .. "\n") + return vector2d end - file:close() end -function Settings.Load(SettingsFile, SettingsTbl) - assert(SettingsFile, "Nil passed for SettingsFile to Settings.Load") - assert(type(SettingsTbl) == "table", "Not a table passed for SettingsTbl to Settings.Load") - SettingsFile = Paths.Cfg .. "\\" .. SettingsFile .. ".cfg" - if not utils.file_exists(SettingsFile) then - return false - end - for line in io.lines(SettingsFile) do - local key, value = line:match("^(.-)=(.-)$") - if key and value then - local num = tonumber(value) - if num then - value = num - elseif value == "true" then - value = true - elseif value == "false" then - value = false - end - num = tonumber(key) - if num then - key = num +-- Selector +do + local textv2 = v2(2, 2) + local reuse_v2 = cheeseUtils.new_reusable_v2() + + local key = { + enter = MenuKey(), + backspace = MenuKey(), + up = MenuKey(), + down = MenuKey(), + } + key.enter:push_vk(0x0D) + key.backspace:push_vk(0x08) + key.up:push_vk(0x26) + key.down:push_vk(0x28) + + local key_waits = {} + local function get_key_wait(str_key) + local vk_key = key[str_key] + if vk_key:is_down() and ((utils.time_ms() > key_waits[str_key]) or (key_waits[str_key] == 0)) then + if key_waits[str_key] == 0 then + key_waits[str_key] = utils.time_ms() + 500 + else + key_waits[str_key] = utils.time_ms() + 100 end - SettingsTbl[key] = value + return true + elseif not vk_key:is_down() then + key_waits[str_key] = 0 end + return false end - return true -end - -local FeatType = { - [2048] = "parent", - [1] = "toggle", - [512] = "action", - [11] = "value_i", - [131] = "value_f", - [7] = "slider", - [35] = "value_str", - [522] = "action_value_i", - [642] = "action_value_f", - [518] = "action_slider", - [546] = "action_value_str", - [1034] = "autoaction_value_i", - [1154] = "autoaction_value_f", - [1030] = "autoaction_slider", - [1058] = "autoaction_value_str", -} - -local AutoloadTbl = {} -Settings.Load(ScriptName, AutoloadTbl) -local LoadedScripts = {} + --local speed_modifier = 0.5 + local function draw_selector(stuff) + while true do + local selected = stuff.selected + scriptdraw.draw_rect(reuse_v2(0, 0), textv2, 0x7D000000) + scriptdraw.draw_text(stuff.selected_str, reuse_v2(-0.02, 0), textv2, 1 / stuff.text_size_rel_to_res, 0xFFFFFFFF, 1 << 4) -local add_feature = menu.add_feature -local add_player_feature = menu.add_player_feature -local delete_feature = menu.delete_feature -local delete_player_feature = menu.delete_player_feature -local create_thread = menu.create_thread -local delete_thread = menu.delete_thread - -local register_script_event_hook = hook.register_script_event_hook -local remove_script_event_hook = hook.remove_script_event_hook -local register_net_event_hook = hook.register_net_event_hook -local remove_net_event_hook = hook.remove_net_event_hook + if stuff.move then + local is_going_up = stuff.move == "up" + if (is_going_up and stuff.selected - 1 >= 1) or (not is_going_up and stuff.selected + 1 <= #stuff.items) then + stuff.offset = is_going_up and stuff.offset - stuff.offset_step or stuff.offset + stuff.offset_step + stuff.size_offset = stuff.size_offset + stuff.size_step + if stuff.offset >= 0.08 or stuff.offset <= -0.08 then + stuff.offset = 0 + stuff.size_offset = 0 + stuff.next_selected = 0 -local add_event_listener = event.add_event_listener -local remove_event_listener = event.remove_event_listener + stuff.selected = is_going_up and stuff.selected - 1 or stuff.selected + 1 + selected = stuff.selected + stuff.move = nil + end + else + stuff.move = nil + end + else + stuff.offset = 0 + stuff.size_offset = 0 + stuff.next_selected = 0 + end -local register_command = console.register_command -local remove_command = console.remove_command + local min = selected - 5 >= 1 and selected - 5 or 1 + local max = selected + 5 <= #stuff.items and selected + 5 or #stuff.items + for i = min, max do + if stuff.items[i] then + local size = i == selected and 1.3 or 1 + size = i == stuff.next_selected and size + stuff.size_offset or i == selected and size - stuff.size_offset or size + local alpha = stuff.move == "up" and math.max(math.floor(255 - math.abs((i - selected) + math.abs(stuff.offset)/0.08)*51), 0) or math.max(math.floor(255 - math.abs((i - selected) - math.abs(stuff.offset)/0.08)*51), 0) + scriptdraw.draw_text(stuff.items[i], reuse_v2(0, 0.005 - 0.08 * (i - selected) + (stuff.offset or 0)), textv2, size / stuff.text_size_rel_to_res, (alpha << 24 | 0xFFFFFF), 0) + end + end -local Parent = menu_originals.add_feature("Proddy's Script Manager", "parent", menu.get_feature_by_hierarchy_key("local.script_features.cheese_menu").id) -local ParentId = Parent.id -local FirstChild -local AutoloadFirstChild -local FilterFeat + controls.disable_control_action(0, 200, true) + controls.disable_control_action(0, 172, true) + controls.disable_control_action(0, 27, true) -menu_originals.add_feature("Trusted Mode", "parent", ParentId) + system.wait(0) + end + end -local AutoloadParent = menu_originals.add_feature("Manage Autoload Scripts", "parent", ParentId) -local AutoloadParentId = AutoloadParent.id + -- Usage: local index, item = selector("Select Player: ", 2, {"Player 1", "Player 2", "Player 3"}) + -- if cancelled returned `index` will be false + -- `items` has to be in order and starting from 1 + function cheeseUtils.selector(selected_str, speed, index, items) + index = tonumber(index) or 1 + index = index > 1 and index or 1 + assert(type(items) == "table", "items should be a table") + local stuff = { + selected_str = selected_str and tostring(selected_str) or "Select: ", + items = items, + selected = tonumber(index) or 1, + next_selected = 0, + offset = 0, + size_offset = 0, + offset_step = 0.08/(10/(speed or 1)), + size_step = 0.3/(10/(speed or 1)), + text_size_rel_to_res = (3686400/(graphics.get_screen_width()*graphics.get_screen_height()))*0.3+0.7, + } -local assert = assert -local error = error -local type = type + local drawThread = menu.create_thread(draw_selector, stuff) -local UnloadScript + while key.enter:is_down() do + system.wait(0) + end -local function DeleteFeature(Feat) - if Feat then - if Feat.type == 2048 then - for i=1,Feat.child_count do - DeleteFeature(Feat.children[1]) + while true do + if key.enter:is_down() then + break end - elseif Feat.type == 1 then - if Feat.data and type(Feat.data) == "table" and Feat.data.ScriptManager then - print("Deleting script: " .. Feat.name) - UnloadScript(Feat) - print("Deleted script: " .. Feat.name) + if key.backspace:is_down() then + menu.delete_thread(drawThread) + while key.backspace:is_down() do + system.wait(0) + end + return false + end + if get_key_wait("up") then + stuff.move = "up" + stuff.next_selected = stuff.selected - 1 end + if get_key_wait("down") then + stuff.move = "down" + stuff.next_selected = stuff.selected + 1 + end + system.wait(0) end - if Feat.activate_feat_func then - delete_feature(Feat.id) - else - menu_originals.delete_feature(Feat.id) + + while key.enter:is_down() do + system.wait(0) end + + menu.delete_thread(drawThread) + + return stuff.selected, stuff.items[stuff.selected] end end -local function DeletePlayerFeature(Feat) - delete_player_feature(Feat.id) -end - -UnloadScript = function(f) - if Exiting then return end - if not f.data or type(f.data) ~= "table" or not f.data.ScriptManager then return end +-- - print("Unloading script: " .. f.name) +-- Draw Slider +do + local reuse_v2 = cheeseUtils.new_reusable_v2() - local success, result = og_pcall(function(data) - if data.exits then - for k,v in pairs(data.exits) do - v({["code"]=69}) - end - end + function cheeseUtils.draw_slider(pos, width, min, max, value, colorBG, colorActive, colorText, draw_value) + scriptdraw.draw_rect(pos, width, colorBG) + local ActiveWidthX = width.x * ((value - min) / (max - min)) + scriptdraw.draw_rect(reuse_v2(pos.x - width.x/2 + ActiveWidthX/2, pos.y), reuse_v2(ActiveWidthX , width.y), colorActive) - if data.features then - local ids = {} - for k in pairs(data.features) do - ids[#ids + 1] = k - end - table.sort(ids) - for i = #ids,1,-1 do - DeleteFeature(data.features[ids[i]]) - end + if draw_value then + local text_size = scriptdraw.get_text_size(tostring(value), 1) + local size_correction = width.y*2 / scriptdraw.size_pixel_to_rel_y(text_size.y*2) - 0.12 + text_size = text_size * size_correction + text_size.x = scriptdraw.size_pixel_to_rel_x(text_size.x) + text_size.y = scriptdraw.size_pixel_to_rel_y(text_size.y) + scriptdraw.draw_text(tostring(value), reuse_v2(pos.x - text_size.x/2, pos.y + text_size.y/2), reuse_v2(2, 2), size_correction, colorText, 0) end + end +end - if data.player_features then - local ids = {} - for k in pairs(data.player_features) do - ids[#ids + 1] = k - end - table.sort(ids) - for i = #ids,1,-1 do - DeletePlayerFeature(data.player_features[ids[i]]) - end - end +-- Use width and height with draw_rect_ext +do + local v2r = cheeseUtils.new_reusable_v2(4) + function cheeseUtils.draw_rect_ext_wh(pos, size, color1, color2, color3, color4) + local halfWdith, halfHeight = size.x/2, size.y/2 + local Bottom = pos.y - halfHeight + local Top = pos.y + halfHeight + local Left = pos.x - halfWdith + local Right = pos.x + halfWdith + scriptdraw.draw_rect_ext(v2r(Left, Bottom), v2r(Left, Top), v2r(Right, Top), v2r(Right, Bottom), color1, color2, color3, color4) + end +end - if data.threads then - local ids = {} - for k in pairs(data.threads) do - ids[#ids + 1] = k - end - table.sort(ids) - for i = #ids,1,-1 do - delete_thread(ids[i]) - end - end +-- Side Window +--[[ +Usage example: + local cheeseUtils = require("CheeseUtilities") - if data.script_hooks then - local ids = {} - for k in pairs(data.script_hooks) do - ids[#ids + 1] = k - end - table.sort(ids) - for i = #ids,1,-1 do - remove_script_event_hook(ids[i]) - end - end + local window_test = cheeseUtils.new_side_window("test_header", v2(0.5, 0.5)) - if data.net_hooks then - local ids = {} - for k in pairs(data.net_hooks) do - ids[#ids + 1] = k - end - table.sort(ids) - for i = #ids,1,-1 do - remove_net_event_hook(ids[i]) - end - end + local firstField = window_test:add_field("left", "right") - if data.events then - for eventName,v in pairs(data.events) do - local ids = {} - for k in pairs(v) do - ids[#ids + 1] = k - end - table.sort(ids) - for i = #ids,1,-1 do - remove_event_listener(eventName, ids[i]) + do + local timer = utils.time_ms() + 100 + window_test:add_field("idk", "1"):set_update_function(function(field) + if timer < utils.time_ms() then + timer = utils.time_ms() + 100 + local fieldValue = tonumber(field.value) + fieldValue = fieldValue + 1 + if fieldValue > 25 then + fieldValue = 1 end + return fieldValue, fieldValue > 10 and "> 10" or "< 10" end - end + end) + end - if data.commands then - for name in pairs(data.commands) do - remove_command(name) - end - end - end, f.data) + window_test:set_position(nil, 0.2) - LoadedScripts[f.name] = nil - f.data = nil - f.on = false + window_test:set_rect_color(0xAA000000) - if success then - notify("Unloaded script: " .. f.name, 0xFF00FF00) - else - notify("Failed to unload script: " .. f.name .. "\n" .. result, 0xFF00FF00) - end - - collectgarbage("collect") -end + menu.create_thread(function() + while true do + window_test:update() + window_test:draw() + system.wait(0) + end + end) --- modified -local limited_functions = { - { - namespace = "stats", - table = stats, - ["stat_set_int"] = true, - ["stat_set_float"] = true, - ["stat_set_bool"] = true, - ["stat_set_i64"] = true, - ["stat_set_u64"] = true, - ["stat_set_masked_int"] = true, - ["stat_set_masked_bool"] = true, - }, - { - namespace = "script", - table = script, - ["set_global_f"] = true, - ["set_global_i"] = true, - ["set_global_s"] = true, - ["set_local_f"] = true, - ["set_local_i"] = true, - ["set_local_s"] = true, - }, - { - namespace = "native", - table = native, - ["call"] = true, - }, - { - namespace = "web", - table = web, - ["post"] = true, - ["get"] = true, - ["request"] = true, - ["urlencode"] = true, - ["urldecode"] = true, - }, - { - namespace = "memory", - table = memory, - ["get_any"] = true, - ["get_entity"] = true, - ["get_ped"] = true, - ["get_vehicle"] = true, - ["get_object"] = true, - ["get_pickup"] = true, - ["read_u64"] = true, - ["read_u32"] = true, - ["read_u16"] = true, - ["read_u8"] = true, - ["read_i64"] = true, - ["read_i32"] = true, - ["read_i16"] = true, - ["read_i8"] = true, - ["read_f32"] = true, - }, -} + menu.add_feature("hide cheese", "toggle", 0, function(f) + if f.on then + window_test:remove_field(window_test:get_field_by_name("cheese")) + firstField:set_value("right") + else + window_test:add_field("cheese", "menu", 2) + firstField:set_value("cheese enabled") + end + end).on = true +]] +do + local function draw_side_window(self) + assert( + type(self.header_text) == "string" + and type(self.fields) == "table" + and type(self.pos) == "userdata" + and type(self.rect_color) == "number" + and type(self.rect_width) == "number" + and type(self.text_spacing) == "number" + and type(self.text_padding) == "number" + and type(self.text_color) == "number", + "one or more draw_side_window args were invalid" + ) + local rect_height = (#self.fields-self.hidden_fields)*self.text_spacing - self.text_spacing + self.last_name_height + 0.02 --+0.0083--+(self.header_on and 0.07125 or 0.02) + local original_y = self.pos.y--(rect_height/2) + local header_y = original_y+self.header_height/2+rect_height/2 + local hidden_y_offset = 0 -local trusted_names = { - [0] = "Stats", - "Globals / Locals", - "Natives", - "HTTP", - "Memory" -} -local modified_functions = { - stats = {}, - script = {}, - native = {}, - web = {}, - memory = {}, -} + scriptdraw.draw_rect(self.pos, cheeseUtils.memoize.v2(self.rect_width, rect_height), self.rect_color) + if self.header_on then + scriptdraw.draw_rect(cheeseUtils.memoize.v2(self.pos.x, header_y), cheeseUtils.memoize.v2(self.rect_width, self.header_height), self.rect_color) + end -for k, v in ipairs(limited_functions) do - local namespace = v.namespace - for name, data in pairs(v) do - if data == true then - modified_functions[namespace][name] = function(...) - local is_flag_on, notify = menu.is_trusted_mode_enabled(1 << (k-1)) - if is_flag_on then - return v.table[name](...) - elseif notify then - menu.notify("Trusted Flag '"..trusted_names[k-1].."' is not enabled.\nFunction used: "..namespace..'.'..name, "Cheese Menu", 5, 0x00ffff) - end + local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 + -- Header text + scriptdraw.draw_text(self.header_text, cheeseUtils.memoize.v2(self.pos.x - self.header_text_width/graphics.get_screen_width(), header_y+0.015), cheeseUtils.memoize.v2(2, 2), text_size, self.text_color, 0, 0) + -- table_of_lines + for id, field in ipairs(self.fields) do + if field.hidden then + hidden_y_offset = hidden_y_offset + 1 + else + local pos_y = original_y-(id-hidden_y_offset-1)*self.text_spacing+rect_height/2 - self.last_name_height/6 - 0.01 --(self.text_spacing/2.5) + scriptdraw.draw_text(field.name, cheeseUtils.memoize.v2(self.pos.x-self.rect_width/2+self.text_padding, pos_y), cheeseUtils.memoize.v2(2, 2), text_size, self.text_color, 0, 2) + scriptdraw.draw_text(field.value, cheeseUtils.memoize.v2(self.pos.x+self.rect_width/2-self.text_padding, pos_y), cheeseUtils.memoize.v2(2, 2), text_size, self.text_color, 16, 2) end end end -end --- -local function LoadScript(f) - if f.on then - if not f.data then - local Filename = f.name - local Filepath = Paths.Scripts .. "\\" .. Filename + -- field functions + local function set_name(self, new_name) + if new_name then + if self.window.fields[#self.window.fields] == self then + local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 + self.window.last_name_height = scriptdraw.size_pixel_to_rel_y(scriptdraw.get_text_size(new_name, text_size, 0).y) + end + self.fields_by_name[self.name] = nil + self.name = tostring(new_name) or "" + self.fields_by_name[new_name] = self + end + end - if not utils.file_exists(Filepath) then - notify("Could not find script: " .. Filename,0xFF0000FF) - LoadedScripts[f.name] = nil - f.data = nil - f.on = false - return + local function set_value(self, value) + if value then + self.value = tostring(value) end + end - print("Enabling script: " .. f.name) - f.data = {} - f.data.ScriptManager = true - f.data.features = {} - f.data.player_features = {} - f.data.threads = {} - f.data.script_hooks = {} - f.data.net_hooks = {} - f.data.events = {} - f.data.exits = {} - f.data.commands = {} + local function set_update_function(self, callback) + self.update_function = callback + end - local env = CloneTable(_G) - function env.SetGlobal(Name, Value) - assert(type(Name) == "string", "Arg #1 (Name) must be a string") + local function update_field(self) + if self.update_function then + local value, name = self:update_function() - _G[Name] = Value - for i=FirstChild,Parent.child_count do - local feat = Parent.children[i] - if feat.data and feat.data.env then - feat.data.env[Name] = Value - end - end + self:set_value(value) + self:set_name(name) end + end - for namespace, func_table in pairs(modified_functions) do - local env_namespace = env[namespace] - for name, func in pairs(func_table) do - env_namespace[name] = func - end + local function set_hidden(self, bool) + assert(type(bool) == "boolean", "hidden only accepts boolean value") + if bool ~= self.hidden then + self.hidden = bool + self.window.hidden_fields = self.window.hidden_fields + (bool and 1 or -1) end + end + -- - env.cheeseUIdata = cheeseUIdata + ---@class field + ---@field name string + ---@field value string + ---@field set_name function + ---@field set_value function + ---@field set_update_function function + ---@field update function - env.menu.add_feature = function(...) - local feat = add_feature(...) - if feat then - f.data.features[feat.id] = feat - end - return feat - end - env.menu.add_player_feature = function(...) - local feat = add_player_feature(...) - if feat then - f.data.player_features[feat.id] = feat - end - return feat + ---@param name string + ---@param value string | number + ---@return field + local function add_field(self, name, value, pos) + local field = { + name = name, + value = value, + id = pos or #self.fields + 1, + fields_by_name = self.fields_by_name, + window = self, + hidden = false, + set_name = set_name, + set_value = set_value, + set_update_function = set_update_function, + update = update_field, + set_hidden = set_hidden + } + if pos then + local prevField = (pos - 1 > 0 and self.fields[pos-1] or true) + assert(prevField, "Fields have to be in increments of 1, for example (1, 2, 5) will not work") + if self.fields[pos] and prevField then + table.insert(self.fields, pos, field) + elseif prevField then + self.fields[pos] = field end - env.menu.delete_feature = function(id) - local success = delete_feature(id) - if success then - f.data.features[id] = nil - end - return success - end - env.menu.delete_player_feature = function(id) - local success = delete_player_feature(id) - if success then - f.data.player_features[id] = nil - end - return success - end - env.menu.create_thread = function(...) - local id = create_thread(...) - if id then - f.data.threads[id] = true - end - return id - end - env.menu.delete_thread = function(id) - local success = delete_thread(id) - if success then - f.data.threads[id] = nil - end - return success - end - env.hook.register_script_event_hook = function(...) - local id = register_script_event_hook(...) - if id then - f.data.script_hooks[id] = true - end - return id - end - env.hook.remove_script_event_hook = function(id) - local success = remove_script_event_hook(id) - if success then - f.data.script_hooks[id] = nil - end - return success - end - env.hook.register_net_event_hook = function(...) - local id = register_net_event_hook(...) - if id then - f.data.net_hooks[id] = true - end - return id - end - env.hook.remove_net_event_hook = function(id) - local success = remove_net_event_hook(id) - if success then - f.data.net_hooks[id] = nil - end - return success - end - env.event.add_event_listener = function(eventName, callback) - local id = add_event_listener(eventName, callback) - if id then - f.data.events[eventName] = f.data.events[eventName] or {} - f.data.events[eventName][id] = true - if eventName == "exit" then - f.data.exits[id] = callback - end - end - return id - end - env.event.remove_event_listener = function(eventName, id) - local success = remove_event_listener(eventName, id) - if success and f.data.events[eventName] then - f.data.events[eventName][id] = nil - if eventName == "exit" then - f.data.exits[id] = nil - end - end - return success - end - env.console.register_command = function(name, ...) - if register_command(name, ...) then - f.data.commands[name] = true - return true - end - return false - end - env.console.remove_command = function(name) - if remove_command(name) then - for i=FirstChild,Parent.child_count do - local feat = Parent.children[i] - if feat.data and feat.data.commands then - feat.data.commands[name] = nil - end - end - return true - end - return false - end - env.load = function(chunk, chunkname, mode, env2) - return og_load(chunk, chunkname or "=(load)", mode or "bt", env2 or env) - end - env.dofile = function(filename) - return og__loadfile(filename, "bt", env)() - end - env.loadfile = function(filename, mode, env2) - return og__loadfile(filename, mode or "bt", env2 or env) - end - env._loadfile = function(filename, mode, env) - return og__loadfile(filename, mode or "bt", env or env) - end - local loaders = {} - local loaded = {} - env.require = function(Library) - assert(Library ~= nil, "You must pass a Library name") - assert(type(Library) == "string", "Library name must be a string") - if loaders[Library] then - local status, result = og_pcall(loaders[Library]) - if status then - if result == nil then - return true - else - loaded[Library] = result - return loaded[Library] - end - end - end - local libParts = {} - for part in Library:gmatch("[^.]+") do - libParts[#libParts + 1] = part - end - local subDirTbl = {} - if #libParts > 1 then - for i=1,#libParts-1 do - subDirTbl[#subDirTbl + 1] = libParts[i] - end - end - local subDir = table.concat(subDirTbl, "/") .. "/" - local lib = libParts[#libParts] - for rootDir in env.package.path:gmatch("[^;]+") do - local path = rootDir:gsub("%?", subDir .. lib) - if utils.file_exists(path) then - local chunk, err = og__loadfile(path, "bt", env) - assert(chunk, "Failed to load \"" .. Library .. "\": " .. tostring(err)) - local status, result = og_pcall(chunk) - assert(status, "Failed to exec \"" .. Library .. "\": " .. tostring(result)) - loaders[Library] = chunk - if result == nil then - return true - else - loaded[Library] = result - return loaded[Library] - end - end - end - error("Failed to find library with name \"" .. Library .. "\"") - end - env.clear_lib_cache = function(Library) - if Library then - local retVal = loaders[Library] ~= nil and loaded[Library] ~= nil - loaders[Library] = nil - loaded[Library] = nil - return retVal - else - loaders = {} - loaded = {} - return true - end - end - env.get_lib_cache = function() - local cache = {} - for k,v in pairs(loaded) do - cache[k] = v - end - return cache - end - f.data.env = env - - local chunk, err = og__loadfile(Filepath, "bt", f.data.env) - if chunk then - local status, result = og_pcall(chunk) - if not status then - menu.create_thread(UnloadScript, f) - notify("Error executing script: " .. Filename .. "\n" .. tostring(result), 0xFF0000FF) - else - notify("Loaded script: " .. Filename, 0xFF00FF00) - LoadedScripts[Filename] = true - end - else - menu.create_thread(UnloadScript, f) - notify("Error loading script: " .. Filename .. "\n" .. err, 0xFF0000FF) - end - end - else - if f.data then - menu.create_thread(UnloadScript, f) + else + self.fields[#self.fields + 1] = field + local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 + self.last_name_height = scriptdraw.size_pixel_to_rel_y(scriptdraw.get_text_size(name, text_size, 0).y) end + self.fields_by_name[name] = field + + return field end -end -local function CaseInsensitiveSort(a, b) - return tostring(a):lower() < tostring(b):lower() -end + local function remove_field(self, field) + if field and self.fields[field.id] then + table.remove(self.fields, field.id) + self.fields_by_name[field.name] = nil -local function LoadScripts(feat) - if FilterFeat then - FilterFeat.data = "" - FilterFeat.name = "Filter: " - end + return true + end - local files = utils.get_all_files_in_directory(Paths.Scripts, "lua") - local files2 = {} - for i=1,#files do - files2[files[i]] = true + return false end - local files3 = utils.get_all_files_in_directory(Paths.Scripts, "luac") - for i=1,#files3 do - if not files2[files3[i]] then - files[#files + 1] = files3[i] - files2[files3[i]] = true - end + + local function get_field_by_name(self, name) + return self.fields_by_name[name] end - table.sort(files, CaseInsensitiveSort) - local threads = {} - for i=Parent.child_count,FirstChild,-1 do - if not files2[Parent.children[i].name] then - threads[#threads + 1] = create_thread(DeleteFeature, Parent.children[i]) - else - files2[Parent.children[i].name] = false - Parent.children[i].hidden = false + + local function update(self) + for _, field in pairs(self.fields) do + field:update() end end - for i=AutoloadParent.child_count,AutoloadFirstChild,-1 do - threads[#threads + 1] = create_thread(DeleteFeature, AutoloadParent.children[i]) + + local function set_position(self, x, y) + self.pos.x = tonumber(x) or self.pos.x + self.pos.y = tonumber(y) or self.pos.y end - local waiting = true - while waiting do - local running = false - for i=1,#threads do - running = running or (not menu.has_thread_finished(threads[i])) - end - waiting = running - system_wait(0) + + local function set_header_text(self, text) + text = tostring(text) + self.header_text = text + self.header_on = text ~= "" + local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 + self.header_text_width = scriptdraw.get_text_size(self.header_text, text_size, 0).x end - for i=1,#files do - if not ExcludedScripts[files[i]:lower()] then - if files2[files[i]] then - menu_originals.add_feature(files[i], "toggle", ParentId, LoadScript, f) - end - local autoloadFeat = menu_originals.add_feature(files[i], "value_i", AutoloadParentId) - autoloadFeat.min = 1 - autoloadFeat.max = 999 - autoloadFeat.mod = 1 - local val = AutoloadTbl[files[i]] - if val then - autoloadFeat.value = type(val) == "number" and val or 1 - autoloadFeat.on = true - else - autoloadFeat.value = 1 - end + + local set_functions = {} + for _, field in ipairs({'text_padding', 'text_spacing', 'rect_width', 'rect_color', 'text_color'}) do + set_functions[field] = function(self, num) + num = tonumber(num) + assert(num, field.." value has to be a number") + self[field] = num end end -end -local ExitFeat = menu_originals.add_feature("Exit Listener", "toggle", ParentId, function(f) - if not f.on then - print("Exit Listener Feat Off") - Exiting = true - end -end) -ExitFeat.hidden = true -ExitFeat.on = true + ---@class window + ---@field draw function + ---@field update function + ---@field add_field function + ---@field remove_field function + ---@field set_position function + ---@field get_field_by_name function + ---@field set_text_padding function + ---@field set_text_spacing function + ---@field set_rect_width function + ---@field set_rect_color function + ---@field set_text_color function + ---@field set_header_text function + ---@field set_hidden function + ---@field header_text string + ---@field fields table + ---@field fields_by_name table + ---@field pos v2 + ---@field rect_color uint32_t + ---@field rect_width float + ---@field text_spacing float + ---@field text_padding float + ---@field text_color uint32_t -local delayFeat + ---@return window + function cheeseUtils.new_side_window(header_text, pos, rect_color, rect_width, text_spacing, text_padding, text_color) + local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 -menu_originals.add_feature("Save Autoload Scripts", "action", AutoloadParentId, function(f) - AutoloadTbl = { - ["autoload_delay_between_scripts"] = delayFeat.value - } - for i=AutoloadFirstChild,AutoloadParent.child_count do - local child = AutoloadParent.children[i] - if child.on then - AutoloadTbl[child.name] = child.value - end - end - Settings.Save(ScriptName, AutoloadTbl) - notify("Saved autoload scripts.", 0xFF00FF00) -end) + local window = { + header_text = header_text or "", + header_on = header_text ~= "", + fields = {}, + fields_by_name = {}, + pos = pos or v2(), + rect_color = rect_color or 0xFF000000, + rect_width = rect_width or 0.2, + text_spacing = text_spacing or 0.047, + text_padding = text_padding or 0.01, + text_color = text_color or 0xFFFFFFFF, + header_height = 0.06125, + header_text_width = scriptdraw.get_text_size(header_text, text_size, 0).x, + hidden_fields = 0, + } -delayFeat = menu_originals.add_feature("Delay between scripts (ms)", "action_value_i", AutoloadParentId, function(f) - local r, s - repeat - r, s = input.get("Enter delay", f.value, 4, eInputType.IT_NUM) - if r == 2 then return HANDLER_POP end - system_wait(0) - until r == 0 + window.draw = draw_side_window + window.update = update + window.add_field = add_field + window.remove_field = remove_field + window.set_position = set_position + window.get_field_by_name = get_field_by_name + window.set_header_text = set_header_text + for name, func in pairs(set_functions) do + window['set_'..name] = func + end - local num = tonumber(s) - if num and num >= f.min and num <= f.max then - f.value = num + return window end -end) -delayFeat.min = 0 -delayFeat.max = 1000 -delayFeat.mod = 1 -local delayVal = AutoloadTbl["autoload_delay_between_scripts"] -if type(delayVal) ~= "number" or delayVal < delayFeat.min then - delayVal = delayFeat.min -elseif delayVal > delayFeat.max then - delayVal = delayFeat.max end -delayFeat.value = delayVal -local RefreshFeat = menu_originals.add_feature("Refresh Scripts", "action", ParentId, function(f) - LoadScripts(f) - notify("Refreshed scripts list.", 0xFF00FF00) -end) -local function FocusFeat(f) - if f.data.parent then - f.data.parent:toggle() +-- Range Converter +do + local function convert_range(self, value) + return self.base_value + (value * self.step) end - f.data:select() -end + local Metatable = {__call = convert_range} -local function ToggleFeat(f) - f.data:toggle() -end + function cheeseUtils.create_range_converter(original_range_min, original_range_max, convert_range_min, convert_range_max) + local stuff = {} -local SearchParentId = menu_originals.add_feature("Search Script Features", "parent", ParentId).id -menu_originals.add_feature("Filter: ", "action", SearchParentId, function(f) - local r, s - repeat - r, s = input.get("Enter search query", f.data, 64, 0) - if r == 2 then return HANDLER_POP end - system_wait(0) - until r == 0 + local adjusted_max_original = original_range_max-original_range_min + local adjusted_max_convert = convert_range_max-convert_range_min - local threads = {} - for i=f.parent.child_count,2,-1 do - threads[#threads + 1] = create_thread(DeleteFeature, f.parent.children[i]) - end + stuff.base_value = (0-original_range_min)/adjusted_max_original*adjusted_max_convert+convert_range_min + stuff.step = (1-original_range_min)/adjusted_max_original*adjusted_max_convert+convert_range_min - stuff.base_value - local waiting = true - while waiting do - local running = false - for i=1,#threads do - running = running or (not menu.has_thread_finished(threads[i])) - end - waiting = running - system_wait(0) - end + setmetatable(stuff, Metatable) - s = Trim(s) - if s:len() == 0 then - f.data = "" - f.name = "Filter: " - return HANDLER_POP + return stuff end +end - local count = 0 - for i=4,RefreshFeat.parent.child_count do - local child = RefreshFeat.parent.children[i] - if child.data and child.data.features and type(child.data.features) == "table" then - for j=1,#child.data.features do - local feat = child.data.features[j] - if feat then - if feat.name:lower():find(s:lower(), 1, true) then - if feat.type == 2048 then - menu_originals.add_feature(FileNameWithoutExtension(child.name) .. " | " .. feat.name, "parent", SearchParentId, ToggleFeat).data = feat - else - menu_originals.add_feature(FileNameWithoutExtension(child.name) .. " | " .. feat.name, "action", SearchParentId, FocusFeat).data = feat - end - count = count + 1 +-- Text Wrap +do + ---@param text string + ---@param font int + ---@param scale float + ---@param relWidth float + function cheeseUtils.wrap_text(text, font, scale, relWidth) + local spaceSize = scriptdraw.get_text_size(". .", scale, font).x - scriptdraw.get_text_size("..", scale, font).x + local lines = {} + for line, manualNewLines in text:gmatch("([^\r\n]+)([\r\n]*)") do + local newline + local lineSize = scriptdraw.get_text_size(line, scale, font) + + if scriptdraw.size_pixel_to_rel_x(lineSize.x) > relWidth then + local length = 0 + newline = {} + for word in line:gmatch("[^%s-\\,]+[%s-\\,]*") do + local relx = scriptdraw.size_pixel_to_rel_x(scriptdraw.get_text_size(word, scale, font).x) + local spaceRelx = word:gsub("%S", "") + spaceRelx = scriptdraw.size_pixel_to_rel_x(#spaceRelx*spaceSize) + if length + relx > relWidth then + newline[#newline+1] = "\n" + length = 0 end + length = length + relx + spaceRelx + newline[#newline+1] = word end - end - end - end - - f.data = s - f.name = "Filter: <" .. s .. "> (" .. count .. ")" -end).data = "" -FilterFeat = menu_originals.add_feature("Filter: ", "action", ParentId, function(f) - local r, s - repeat - r, s = input.get("Enter search query", f.data, 64, 0) - if r == 2 then return HANDLER_POP end - system_wait(0) - until r == 0 + line = table.concat(newline) + end - s = Trim(s) - if s:len() == 0 then - f.data = "" - f.name = "Filter: " - for i=f.parent.child_count,FirstChild,-1 do - f.parent.children[i].hidden = false + lines[#lines+1] = line..(manualNewLines or "") end - return HANDLER_POP - end - local count = 0 - for i=f.parent.child_count,FirstChild,-1 do - if f.parent.children[i].name:lower():find(s, 1, true) then - f.parent.children[i].hidden = false - count = count + 1 - else - f.parent.children[i].hidden = true - end + return table.concat(lines) end +end - f.data = s - f.name = "Filter: <" .. s .. "> (" .. count .. ")" -end) -FilterFeat.data = "" - -ProddysScriptManager = true +return cheeseUtils]=], + ["cheesemenu.lua"] = [=[--Made by GhostOne -create_thread(function(f) - FirstChild = Parent.child_count + 1 - AutoloadFirstChild = AutoloadParent.child_count + 1 - LoadScripts(f) - - local delay = 0 - local autoload = {} - for k,v in pairs(AutoloadTbl) do - if k == "autoload_delay_between_scripts" then - if type(v) == "number" and v >= 0 then - delay = v - end - else - if type(v) ~= "number" then v = 1 end - autoload[v] = autoload[v] or {} - autoload[v][#autoload[v] + 1] = k - end - end - - print("Autoloading with delay: " .. delay) +--[[ + ,o888888o. 8 8888 8 8 8888888888 8 8888888888 d888888o. 8 8888888888 + 8888 `88. 8 8888 8 8 8888 8 8888 .`8888:' `88. 8 8888 +,8 8888 `8. 8 8888 8 8 8888 8 8888 8.`8888. Y8 8 8888 +88 8888 8 8888 8 8 8888 8 8888 `8.`8888. 8 8888 +88 8888 8 8888 8 8 888888888888 8 888888888888 `8.`8888. 8 888888888888 +88 8888 8 8888 8 8 8888 8 8888 `8.`8888. 8 8888 +88 8888 8 8888888888888 8 8888 8 8888 `8.`8888. 8 8888 +`8 8888 .8' 8 8888 8 8 8888 8 8888 8b `8.`8888. 8 8888 + 8888 ,88' 8 8888 8 8 8888 8 8888 `8b. ;8.`8888 8 8888 + `8888888P' 8 8888 8 8 888888888888 8 888888888888 `Y8888P ,88P' 8 888888888888 + . . + ,8. ,8. 8 8888888888 b. 8 8 8888 88 + ,888. ,888. 8 8888 888o. 8 8 8888 88 + .`8888. .`8888. 8 8888 Y88888o. 8 8 8888 88 + ,8.`8888. ,8.`8888. 8 8888 .`Y888888o. 8 8 8888 88 + ,8'8.`8888,8^8.`8888. 8 888888888888 8o. `Y888888o. 8 8 8888 88 + ,8' `8.`8888' `8.`8888. 8 8888 8`Y8o. `Y88888o8 8 8888 88 + ,8' `8.`88' `8.`8888. 8 8888 8 `Y8o. `Y8888 8 8888 88 + ,8' `8.`' `8.`8888. 8 8888 8 `Y8o. `Y8 ` 8888 ,8P + ,8' `8 `8.`8888. 8 8888 8 `Y8o.` 8888 ,d8P +,8' ` `8.`8888. 8 888888888888 8 `Yo `Y88888P' +]] - if #autoload > 0 then - local scripts = {} - for i=FirstChild,Parent.child_count do - local feat = Parent.children[i] - scripts[feat.name] = feat - end +local version = "1.9" +local loadCurrentMenu +local httpTrustedOff - local ids = {} - for k in pairs(autoload) do - ids[#ids + 1] = k - end - table.sort(ids) +-- Version check +if menu.is_trusted_mode_enabled(1 << 3) and menu.is_trusted_mode_enabled(1 << 2) then + menu.create_thread(function() + local vercheckKeys = {ctrl = MenuKey(), space = MenuKey(), enter = MenuKey(), rshift = MenuKey()} + vercheckKeys.ctrl:push_vk(0x11); vercheckKeys.space:push_vk(0x20); vercheckKeys.enter:push_vk(0x0D); vercheckKeys.rshift:push_vk(0xA1) - for i=1,#ids do - local tbl = autoload[ids[i]] - for j=1,#tbl do - local script = scripts[tbl[j]] - if script then - system_wait(delay) - print("Enabled autoload script: " .. script.name) - script.on = true + local responseCode, githubVer = web.get("https://raw.githubusercontent.com/GhustOne/CheeseMenu/main/VERSION.txt") + if responseCode == 200 then + githubVer = githubVer:gsub("[\r\n]", "") + if githubVer ~= version then + local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.5+0.5 + local strings = { + version_compare = "\nCurrent Version:"..version.."\nLatest Version:"..githubVer, + version_compare_x_offset = v2(-scriptdraw.get_text_size("\nCurrent Version:"..version.."\nLatest Version:"..githubVer, text_size).x/graphics.get_screen_width(), 0), + new_ver_x_offset = v2(-scriptdraw.get_text_size("New version available. Press CTRL or SPACE to skip or press ENTER or RIGHT SHIFT to update.", text_size).x/graphics.get_screen_width(), 0), + } + strings.changelog_rc, strings.changelog = web.get("https://raw.githubusercontent.com/GhustOne/CheeseMenu/main/CHANGELOG.txt") + if strings.changelog_rc == 200 then + strings.changelog = "\n\n\nChangelog:\n"..strings.changelog + else + strings.changelog = "" end + strings.changelog_x_offset = v2(-scriptdraw.get_text_size(strings.changelog, text_size).x/graphics.get_screen_width(), 0) + local stringV2size = v2(2, 2) + while true do + scriptdraw.draw_text("New version available. Press CTRL or SPACE to skip or press ENTER or RIGHT SHIFT to update.", strings.new_ver_x_offset, stringV2size, text_size, 0xFF0CB4F4, 2) + scriptdraw.draw_text(strings.version_compare, strings.version_compare_x_offset, stringV2size, text_size, 0xFF0CB4F4, 2) + scriptdraw.draw_text(strings.changelog, strings.changelog_x_offset, stringV2size, text_size, 0xFF0CB4F4, 2) + if vercheckKeys.ctrl:is_down() or vercheckKeys.space:is_down() then + loadCurrentMenu() + break + elseif vercheckKeys.enter:is_down() or vercheckKeys.rshift:is_down() then + local responseCode, autoupdater = web.get([[https://raw.githubusercontent.com/GhustOne/CheeseMenu/main/CMAutoUpdater.lua]]) + if responseCode == 200 then + autoupdater = load(autoupdater) + menu.create_thread(function() + menu.notify("Update started, please wait...", "Cheese Menu") + local status = autoupdater() + if status then + if type(status) == "string" then + menu.notify("Updating local files failed, one or more of the files could not be opened.\nThere is a high chance the files got corrupted, please redownload the menu.", "Cheese Menu", 5, 0x0000FF) + else + menu.notify("Update successful", "Cheese Menu", 4, 0x00FF00) + dofile(utils.get_appdata_path("PopstarDevs", "2Take1Menu").."\\scripts\\cheesemenu.lua") + end + else + menu.notify("Download for updated files failed, current files have not been replaced.", "Cheese Menu", 5, 0x0000FF) + end + end, nil) + break + else + menu.notify("Getting Updater failed. Check your connection and try downloading manually.", "Cheese Menu", 5, 0x0000FF) + end + end + system.wait(0) + end + else + loadCurrentMenu() end end - end -end, RefreshFeat) - ---notify(ScriptName .. " v" .. Version .. " loaded.", 0xFF0FF00)]=], - ["CheeseUtilities.lua"] = [=[--Made by GhostOne -local cheeseUtils = {} - --- Credit to kektram for this whole function ~ a little modified to focus on fractionals -cheeseUtils.memoize = {} -do - local sign_bit_x = 1 << 62 - local sign_bit_y = 1 << 61 - local max_30_bit_num = 1073740823 - local v2 = v2 - local memoized = {} - function cheeseUtils.memoize.v2(x, y) - x = x or 0 - y = y or 0 - local xi = x * 100000000 // 1 -- modified from 1000 to 100,000,000 to support up to 10^-7 fractional digits ~ this limits it to either single or double digits with fractions - local yi = y * 100000000 // 1 -- same here - if xi >= -max_30_bit_num - and xi <= max_30_bit_num - and yi >= -max_30_bit_num - and yi <= max_30_bit_num then - local signs = 0 - if xi < 0 then - xi = xi * -1 - signs = signs | sign_bit_x - end - if yi < 0 then - yi = yi * -1 - signs = signs | sign_bit_y - end - local hash = signs | xi << 30 | yi - memoized[hash] = memoized[hash] or v2(x, y) - return memoized[hash] - else - return v2(x, y) - end - end -end --- - -function cheeseUtils.draw_outline(v2pos, v2size, color, thickness) - local thickness_y = thickness / graphics.get_screen_height() * 2 - local thickness_x = thickness / graphics.get_screen_width() * 2 - - scriptdraw.draw_rect( - cheeseUtils.memoize.v2(v2pos.x, v2pos.y - (v2size.y/2)), - cheeseUtils.memoize.v2(v2size.x + thickness_x, thickness_y), - color - ) - - scriptdraw.draw_rect( - cheeseUtils.memoize.v2(v2pos.x, v2pos.y + (v2size.y/2)), - cheeseUtils.memoize.v2(v2size.x + thickness_x, thickness_y), - color - ) - - scriptdraw.draw_rect( - cheeseUtils.memoize.v2(v2pos.x - (v2size.x/2), v2pos.y), - cheeseUtils.memoize.v2(thickness_x, v2size.y - thickness_y), - color - ) - - scriptdraw.draw_rect( - cheeseUtils.memoize.v2(v2pos.x + (v2size.x/2), v2pos.y), - cheeseUtils.memoize.v2(thickness_x, v2size.y - thickness_y), - color - ) -end - --- Credit to Proddy for this function -cheeseUtils.Keys = {} -function cheeseUtils.get_key(...) - local args = {...} - assert(#args > 0, "must give at least one key") - local ID = table.concat(args, "|") - if not cheeseUtils.Keys[ID] then - local key = MenuKey() - for i=1,#args do - key:push_vk(args[i]) - end - cheeseUtils.Keys[ID] = key - end - - return cheeseUtils.Keys[ID] -end - -function cheeseUtils.new_reusable_v2(limit) - limit = limit or 2 - - local counter = 1 - local v2Table = {} - for i = 1, limit do - v2Table[i] = v2() - end - - return function(x, y) - local vector2d = v2Table[counter] - counter = counter + 1 - counter = counter <= limit and counter or 1 - - vector2d.x, vector2d.y = x, y - - return vector2d - end -end - --- Selector -do - local textv2 = v2(2, 2) - local reuse_v2 = cheeseUtils.new_reusable_v2() - - local key = { - enter = MenuKey(), - backspace = MenuKey(), - up = MenuKey(), - down = MenuKey(), - } - key.enter:push_vk(0x0D) - key.backspace:push_vk(0x08) - key.up:push_vk(0x26) - key.down:push_vk(0x28) - - local key_waits = {} - local function get_key_wait(str_key) - local vk_key = key[str_key] - if vk_key:is_down() and ((utils.time_ms() > key_waits[str_key]) or (key_waits[str_key] == 0)) then - if key_waits[str_key] == 0 then - key_waits[str_key] = utils.time_ms() + 500 - else - key_waits[str_key] = utils.time_ms() + 100 - end - return true - elseif not vk_key:is_down() then - key_waits[str_key] = 0 - end - return false - end - - --local speed_modifier = 0.5 - local function draw_selector(stuff) - while true do - local selected = stuff.selected - scriptdraw.draw_rect(reuse_v2(0, 0), textv2, 0x7D000000) - scriptdraw.draw_text(stuff.selected_str, reuse_v2(-0.02, 0), textv2, 1 / stuff.text_size_rel_to_res, 0xFFFFFFFF, 1 << 4) - - if stuff.move then - local is_going_up = stuff.move == "up" - if (is_going_up and stuff.selected - 1 >= 1) or (not is_going_up and stuff.selected + 1 <= #stuff.items) then - stuff.offset = is_going_up and stuff.offset - stuff.offset_step or stuff.offset + stuff.offset_step - stuff.size_offset = stuff.size_offset + stuff.size_step - if stuff.offset >= 0.08 or stuff.offset <= -0.08 then - stuff.offset = 0 - stuff.size_offset = 0 - stuff.next_selected = 0 - - stuff.selected = is_going_up and stuff.selected - 1 or stuff.selected + 1 - selected = stuff.selected - stuff.move = nil - end - else - stuff.move = nil - end - else - stuff.offset = 0 - stuff.size_offset = 0 - stuff.next_selected = 0 - end - - local min = selected - 5 >= 1 and selected - 5 or 1 - local max = selected + 5 <= #stuff.items and selected + 5 or #stuff.items - for i = min, max do - if stuff.items[i] then - local size = i == selected and 1.3 or 1 - size = i == stuff.next_selected and size + stuff.size_offset or i == selected and size - stuff.size_offset or size - local alpha = stuff.move == "up" and math.max(math.floor(255 - math.abs((i - selected) + math.abs(stuff.offset)/0.08)*51), 0) or math.max(math.floor(255 - math.abs((i - selected) - math.abs(stuff.offset)/0.08)*51), 0) - scriptdraw.draw_text(stuff.items[i], reuse_v2(0, 0.005 - 0.08 * (i - selected) + (stuff.offset or 0)), textv2, size / stuff.text_size_rel_to_res, (alpha << 24 | 0xFFFFFF), 0) - end - end - - controls.disable_control_action(0, 200, true) - controls.disable_control_action(0, 172, true) - controls.disable_control_action(0, 27, true) - - system.wait(0) - end - end - - -- Usage: local index, item = selector("Select Player: ", 2, {"Player 1", "Player 2", "Player 3"}) - -- if cancelled returned `index` will be false - -- `items` has to be in order and starting from 1 - function cheeseUtils.selector(selected_str, speed, index, items) - index = tonumber(index) or 1 - index = index > 1 and index or 1 - assert(type(items) == "table", "items should be a table") - local stuff = { - selected_str = selected_str and tostring(selected_str) or "Select: ", - items = items, - selected = tonumber(index) or 1, - next_selected = 0, - offset = 0, - size_offset = 0, - offset_step = 0.08/(10/(speed or 1)), - size_step = 0.3/(10/(speed or 1)), - text_size_rel_to_res = (3686400/(graphics.get_screen_width()*graphics.get_screen_height()))*0.3+0.7, - } - - local drawThread = menu.create_thread(draw_selector, stuff) - - while key.enter:is_down() do - system.wait(0) - end - - while true do - if key.enter:is_down() then - break - end - if key.backspace:is_down() then - menu.delete_thread(drawThread) - while key.backspace:is_down() do - system.wait(0) - end - return false - end - if get_key_wait("up") then - stuff.move = "up" - stuff.next_selected = stuff.selected - 1 - end - if get_key_wait("down") then - stuff.move = "down" - stuff.next_selected = stuff.selected + 1 - end - system.wait(0) - end - - while key.enter:is_down() do - system.wait(0) - end - - menu.delete_thread(drawThread) - - return stuff.selected, stuff.items[stuff.selected] - end -end --- - --- Draw Slider -do - local reuse_v2 = cheeseUtils.new_reusable_v2() - - function cheeseUtils.draw_slider(pos, width, min, max, value, colorBG, colorActive, colorText, draw_value) - scriptdraw.draw_rect(pos, width, colorBG) - local ActiveWidthX = width.x * ((value - min) / (max - min)) - scriptdraw.draw_rect(reuse_v2(pos.x - width.x/2 + ActiveWidthX/2, pos.y), reuse_v2(ActiveWidthX , width.y), colorActive) - - if draw_value then - local text_size = scriptdraw.get_text_size(tostring(value), 1) - local size_correction = width.y*2 / scriptdraw.size_pixel_to_rel_y(text_size.y*2) - 0.12 - text_size = text_size * size_correction - text_size.x = scriptdraw.size_pixel_to_rel_x(text_size.x) - text_size.y = scriptdraw.size_pixel_to_rel_y(text_size.y) - scriptdraw.draw_text(tostring(value), reuse_v2(pos.x - text_size.x/2, pos.y + text_size.y/2), reuse_v2(2, 2), size_correction, colorText, 0) - end - end -end - --- Use width and height with draw_rect_ext -do - local v2r = cheeseUtils.new_reusable_v2(4) - function cheeseUtils.draw_rect_ext_wh(pos, size, color1, color2, color3, color4) - local halfWdith, halfHeight = size.x/2, size.y/2 - local Bottom = pos.y - halfHeight - local Top = pos.y + halfHeight - local Left = pos.x - halfWdith - local Right = pos.x + halfWdith - scriptdraw.draw_rect_ext(v2r(Left, Bottom), v2r(Left, Top), v2r(Right, Top), v2r(Right, Bottom), color1, color2, color3, color4) - end -end - --- Side Window ---[[ -Usage example: - local cheeseUtils = require("CheeseUtilities") - - local window_test = cheeseUtils.new_side_window("test_header", v2(0.5, 0.5)) - - local firstField = window_test:add_field("left", "right") - - do - local timer = utils.time_ms() + 100 - window_test:add_field("idk", "1"):set_update_function(function(field) - if timer < utils.time_ms() then - timer = utils.time_ms() + 100 - local fieldValue = tonumber(field.value) - fieldValue = fieldValue + 1 - if fieldValue > 25 then - fieldValue = 1 - end - return fieldValue, fieldValue > 10 and "> 10" or "< 10" - end - end) - end - - window_test:set_position(nil, 0.2) - - window_test:set_rect_color(0xAA000000) - - menu.create_thread(function() - while true do - window_test:update() - window_test:draw() - system.wait(0) - end - end) - - menu.add_feature("hide cheese", "toggle", 0, function(f) - if f.on then - window_test:remove_field(window_test:get_field_by_name("cheese")) - firstField:set_value("right") - else - window_test:add_field("cheese", "menu", 2) - firstField:set_value("cheese enabled") - end - end).on = true -]] -do - local function draw_side_window(self) - assert( - type(self.header_text) == "string" - and type(self.fields) == "table" - and type(self.pos) == "userdata" - and type(self.rect_color) == "number" - and type(self.rect_width) == "number" - and type(self.text_spacing) == "number" - and type(self.text_padding) == "number" - and type(self.text_color) == "number", - "one or more draw_side_window args were invalid" - ) - local rect_height = (#self.fields-self.hidden_fields)*self.text_spacing - self.text_spacing + self.last_name_height + 0.02 --+0.0083--+(self.header_on and 0.07125 or 0.02) - local original_y = self.pos.y--(rect_height/2) - local header_y = original_y+self.header_height/2+rect_height/2 - local hidden_y_offset = 0 - - - scriptdraw.draw_rect(self.pos, cheeseUtils.memoize.v2(self.rect_width, rect_height), self.rect_color) - if self.header_on then - scriptdraw.draw_rect(cheeseUtils.memoize.v2(self.pos.x, header_y), cheeseUtils.memoize.v2(self.rect_width, self.header_height), self.rect_color) - end - - local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 - -- Header text - scriptdraw.draw_text(self.header_text, cheeseUtils.memoize.v2(self.pos.x - self.header_text_width/graphics.get_screen_width(), header_y+0.015), cheeseUtils.memoize.v2(2, 2), text_size, self.text_color, 0, 0) - -- table_of_lines - for id, field in ipairs(self.fields) do - if field.hidden then - hidden_y_offset = hidden_y_offset + 1 - else - local pos_y = original_y-(id-hidden_y_offset-1)*self.text_spacing+rect_height/2 - self.last_name_height/6 - 0.01 --(self.text_spacing/2.5) - scriptdraw.draw_text(field.name, cheeseUtils.memoize.v2(self.pos.x-self.rect_width/2+self.text_padding, pos_y), cheeseUtils.memoize.v2(2, 2), text_size, self.text_color, 0, 2) - scriptdraw.draw_text(field.value, cheeseUtils.memoize.v2(self.pos.x+self.rect_width/2-self.text_padding, pos_y), cheeseUtils.memoize.v2(2, 2), text_size, self.text_color, 16, 2) - end - end - end - - -- field functions - local function set_name(self, new_name) - if new_name then - if self.window.fields[#self.window.fields] == self then - local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 - self.window.last_name_height = scriptdraw.size_pixel_to_rel_y(scriptdraw.get_text_size(new_name, text_size, 0).y) - end - self.fields_by_name[self.name] = nil - self.name = tostring(new_name) or "" - self.fields_by_name[new_name] = self - end - end - - local function set_value(self, value) - if value then - self.value = tostring(value) - end - end - - local function set_update_function(self, callback) - self.update_function = callback - end - - local function update_field(self) - if self.update_function then - local value, name = self:update_function() - - self:set_value(value) - self:set_name(name) - end - end - - local function set_hidden(self, bool) - assert(type(bool) == "boolean", "hidden only accepts boolean value") - if bool ~= self.hidden then - self.hidden = bool - self.window.hidden_fields = self.window.hidden_fields + (bool and 1 or -1) - end - end - -- - - ---@class field - ---@field name string - ---@field value string - ---@field set_name function - ---@field set_value function - ---@field set_update_function function - ---@field update function - - ---@param name string - ---@param value string | number - ---@return field - local function add_field(self, name, value, pos) - local field = { - name = name, - value = value, - id = pos or #self.fields + 1, - fields_by_name = self.fields_by_name, - window = self, - hidden = false, - set_name = set_name, - set_value = set_value, - set_update_function = set_update_function, - update = update_field, - set_hidden = set_hidden - } - if pos then - local prevField = (pos - 1 > 0 and self.fields[pos-1] or true) - assert(prevField, "Fields have to be in increments of 1, for example (1, 2, 5) will not work") - if self.fields[pos] and prevField then - table.insert(self.fields, pos, field) - elseif prevField then - self.fields[pos] = field - end - else - self.fields[#self.fields + 1] = field - local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 - self.last_name_height = scriptdraw.size_pixel_to_rel_y(scriptdraw.get_text_size(name, text_size, 0).y) - end - self.fields_by_name[name] = field - - return field - end - - local function remove_field(self, field) - if field and self.fields[field.id] then - table.remove(self.fields, field.id) - self.fields_by_name[field.name] = nil - - return true - end - - return false - end - - local function get_field_by_name(self, name) - return self.fields_by_name[name] - end - - local function update(self) - for _, field in pairs(self.fields) do - field:update() - end - end - - local function set_position(self, x, y) - self.pos.x = tonumber(x) or self.pos.x - self.pos.y = tonumber(y) or self.pos.y - end - - local function set_header_text(self, text) - text = tostring(text) - self.header_text = text - self.header_on = text ~= "" - local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 - self.header_text_width = scriptdraw.get_text_size(self.header_text, text_size, 0).x - end - - local set_functions = {} - for _, field in ipairs({'text_padding', 'text_spacing', 'rect_width', 'rect_color', 'text_color'}) do - set_functions[field] = function(self, num) - num = tonumber(num) - assert(num, field.." value has to be a number") - self[field] = num - end - end - - ---@class window - ---@field draw function - ---@field update function - ---@field add_field function - ---@field remove_field function - ---@field set_position function - ---@field get_field_by_name function - ---@field set_text_padding function - ---@field set_text_spacing function - ---@field set_rect_width function - ---@field set_rect_color function - ---@field set_text_color function - ---@field set_header_text function - ---@field set_hidden function - ---@field header_text string - ---@field fields table - ---@field fields_by_name table - ---@field pos v2 - ---@field rect_color uint32_t - ---@field rect_width float - ---@field text_spacing float - ---@field text_padding float - ---@field text_color uint32_t - - ---@return window - function cheeseUtils.new_side_window(header_text, pos, rect_color, rect_width, text_spacing, text_padding, text_color) - local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 - - local window = { - header_text = header_text or "", - header_on = header_text ~= "", - fields = {}, - fields_by_name = {}, - pos = pos or v2(), - rect_color = rect_color or 0xFF000000, - rect_width = rect_width or 0.2, - text_spacing = text_spacing or 0.047, - text_padding = text_padding or 0.01, - text_color = text_color or 0xFFFFFFFF, - header_height = 0.06125, - header_text_width = scriptdraw.get_text_size(header_text, text_size, 0).x, - hidden_fields = 0, - } - - window.draw = draw_side_window - window.update = update - window.add_field = add_field - window.remove_field = remove_field - window.set_position = set_position - window.get_field_by_name = get_field_by_name - window.set_header_text = set_header_text - for name, func in pairs(set_functions) do - window['set_'..name] = func - end - - return window - end -end - - --- Range Converter -do - local function convert_range(self, value) - return self.base_value + (value * self.step) - end - local Metatable = {__call = convert_range} - - function cheeseUtils.create_range_converter(original_range_min, original_range_max, convert_range_min, convert_range_max) - local stuff = {} - - local adjusted_max_original = original_range_max-original_range_min - local adjusted_max_convert = convert_range_max-convert_range_min - - stuff.base_value = (0-original_range_min)/adjusted_max_original*adjusted_max_convert+convert_range_min - stuff.step = (1-original_range_min)/adjusted_max_original*adjusted_max_convert+convert_range_min - stuff.base_value - - setmetatable(stuff, Metatable) - - return stuff - end -end - --- Text Wrap -do - ---@param text string - ---@param font int - ---@param scale float - ---@param relWidth float - function cheeseUtils.wrap_text(text, font, scale, relWidth) - local spaceSize = scriptdraw.get_text_size(". .", scale, font).x - scriptdraw.get_text_size("..", scale, font).x - local lines = {} - for line, manualNewLines in text:gmatch("([^\r\n]+)([\r\n]*)") do - local newline - local lineSize = scriptdraw.get_text_size(line, scale, font) - - if scriptdraw.size_pixel_to_rel_x(lineSize.x) > relWidth then - local length = 0 - newline = {} - for word in line:gmatch("[^%s-\\,]+[%s-\\,]*") do - local relx = scriptdraw.size_pixel_to_rel_x(scriptdraw.get_text_size(word, scale, font).x) - local spaceRelx = word:gsub("%S", "") - spaceRelx = scriptdraw.size_pixel_to_rel_x(#spaceRelx*spaceSize) - if length + relx > relWidth then - newline[#newline+1] = "\n" - length = 0 - end - length = length + relx + spaceRelx - newline[#newline+1] = word - end - - line = table.concat(newline) - end - - lines[#lines+1] = line..(manualNewLines or "") - end - - return table.concat(lines) - end -end - -return cheeseUtils]=], - ["cheesemenu.lua"] = [=[--Made by GhostOne - ---[[ - ,o888888o. 8 8888 8 8 8888888888 8 8888888888 d888888o. 8 8888888888 - 8888 `88. 8 8888 8 8 8888 8 8888 .`8888:' `88. 8 8888 -,8 8888 `8. 8 8888 8 8 8888 8 8888 8.`8888. Y8 8 8888 -88 8888 8 8888 8 8 8888 8 8888 `8.`8888. 8 8888 -88 8888 8 8888 8 8 888888888888 8 888888888888 `8.`8888. 8 888888888888 -88 8888 8 8888 8 8 8888 8 8888 `8.`8888. 8 8888 -88 8888 8 8888888888888 8 8888 8 8888 `8.`8888. 8 8888 -`8 8888 .8' 8 8888 8 8 8888 8 8888 8b `8.`8888. 8 8888 - 8888 ,88' 8 8888 8 8 8888 8 8888 `8b. ;8.`8888 8 8888 - `8888888P' 8 8888 8 8 888888888888 8 888888888888 `Y8888P ,88P' 8 888888888888 - . . - ,8. ,8. 8 8888888888 b. 8 8 8888 88 - ,888. ,888. 8 8888 888o. 8 8 8888 88 - .`8888. .`8888. 8 8888 Y88888o. 8 8 8888 88 - ,8.`8888. ,8.`8888. 8 8888 .`Y888888o. 8 8 8888 88 - ,8'8.`8888,8^8.`8888. 8 888888888888 8o. `Y888888o. 8 8 8888 88 - ,8' `8.`8888' `8.`8888. 8 8888 8`Y8o. `Y88888o8 8 8888 88 - ,8' `8.`88' `8.`8888. 8 8888 8 `Y8o. `Y8888 8 8888 88 - ,8' `8.`' `8.`8888. 8 8888 8 `Y8o. `Y8 ` 8888 ,8P - ,8' `8 `8.`8888. 8 8888 8 `Y8o.` 8888 ,d8P -,8' ` `8.`8888. 8 888888888888 8 `Yo `Y88888P' -]] - -local version = "1.9" -local loadCurrentMenu -local httpTrustedOff - --- Version check -if menu.is_trusted_mode_enabled(1 << 3) and menu.is_trusted_mode_enabled(1 << 2) then - menu.create_thread(function() - local vercheckKeys = {ctrl = MenuKey(), space = MenuKey(), enter = MenuKey(), rshift = MenuKey()} - vercheckKeys.ctrl:push_vk(0x11); vercheckKeys.space:push_vk(0x20); vercheckKeys.enter:push_vk(0x0D); vercheckKeys.rshift:push_vk(0xA1) - - local responseCode, githubVer = web.get("https://raw.githubusercontent.com/GhustOne/CheeseMenu/main/VERSION.txt") - if responseCode == 200 then - githubVer = githubVer:gsub("[\r\n]", "") - if githubVer ~= version then - local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.5+0.5 - local strings = { - version_compare = "\nCurrent Version:"..version.."\nLatest Version:"..githubVer, - version_compare_x_offset = v2(-scriptdraw.get_text_size("\nCurrent Version:"..version.."\nLatest Version:"..githubVer, text_size).x/graphics.get_screen_width(), 0), - new_ver_x_offset = v2(-scriptdraw.get_text_size("New version available. Press CTRL or SPACE to skip or press ENTER or RIGHT SHIFT to update.", text_size).x/graphics.get_screen_width(), 0), - } - strings.changelog_rc, strings.changelog = web.get("https://raw.githubusercontent.com/GhustOne/CheeseMenu/main/CHANGELOG.txt") - if strings.changelog_rc == 200 then - strings.changelog = "\n\n\nChangelog:\n"..strings.changelog - else - strings.changelog = "" - end - strings.changelog_x_offset = v2(-scriptdraw.get_text_size(strings.changelog, text_size).x/graphics.get_screen_width(), 0) - local stringV2size = v2(2, 2) - while true do - scriptdraw.draw_text("New version available. Press CTRL or SPACE to skip or press ENTER or RIGHT SHIFT to update.", strings.new_ver_x_offset, stringV2size, text_size, 0xFF0CB4F4, 2) - scriptdraw.draw_text(strings.version_compare, strings.version_compare_x_offset, stringV2size, text_size, 0xFF0CB4F4, 2) - scriptdraw.draw_text(strings.changelog, strings.changelog_x_offset, stringV2size, text_size, 0xFF0CB4F4, 2) - if vercheckKeys.ctrl:is_down() or vercheckKeys.space:is_down() then - loadCurrentMenu() - break - elseif vercheckKeys.enter:is_down() or vercheckKeys.rshift:is_down() then - local responseCode, autoupdater = web.get([[https://raw.githubusercontent.com/GhustOne/CheeseMenu/main/CMAutoUpdater.lua]]) - if responseCode == 200 then - autoupdater = load(autoupdater) - menu.create_thread(function() - menu.notify("Update started, please wait...", "Cheese Menu") - local status = autoupdater() - if status then - if type(status) == "string" then - menu.notify("Updating local files failed, one or more of the files could not be opened.\nThere is a high chance the files got corrupted, please redownload the menu.", "Cheese Menu", 5, 0x0000FF) - else - menu.notify("Update successful", "Cheese Menu", 4, 0x00FF00) - dofile(utils.get_appdata_path("PopstarDevs", "2Take1Menu").."\\scripts\\cheesemenu.lua") - end - else - menu.notify("Download for updated files failed, current files have not been replaced.", "Cheese Menu", 5, 0x0000FF) - end - end, nil) - break - else - menu.notify("Getting Updater failed. Check your connection and try downloading manually.", "Cheese Menu", 5, 0x0000FF) - end - end - system.wait(0) - end - else - loadCurrentMenu() - end - end - end, nil) -else - if menu.is_trusted_mode_enabled(1 << 2) then - httpTrustedOff = true - else - menu.notify("Trusted mode > Natives has to be on. If you wish for auto updates enable Http too.", "Cheese Menu", 5, 0x0000FF) + end, nil) +else + if menu.is_trusted_mode_enabled(1 << 2) then + httpTrustedOff = true + else + menu.notify("Trusted mode > Natives has to be on. If you wish for auto updates enable Http too.", "Cheese Menu", 5, 0x0000FF) end end @@ -1908,2752 +971,3689 @@ function loadCurrentMenu() self.height = int * self.feature_offset self.max_features = int end - }, - disable_all_controls = function() - while true do - for i = 0, 360 do - controls.disable_control_action(0, i, true) + }, + disable_all_controls = function() + while true do + for i = 0, 360 do + controls.disable_control_action(0, i, true) + end + system.wait(0) + end + end + } + + stuff.menuData.color = { + background = {r = 0, g = 0, b = 0, a = 0}, + sprite = 0xE6FFFFFF, + slider_active = {r = 255, g = 200, b = 0, a = 255}, + slider_background = {r = 0, g = 0, b = 0, a = 160}, + slider_text = {r = 0, g = 0, b = 0, a = 255}, + slider_selectedActive = {r = 255, g = 255, b = 255, a = 160}, + slider_selectedBackground = {r = 255, g = 160, b = 0, a = 180}, + feature_bottomLeft = {r = 255, g = 160, b = 0, a = 170}, + feature_topLeft = {r = 255, g = 160, b = 0, a = 170}, + feature_topRight = {r = 255, g = 160, b = 0, a = 170}, + feature_bottomRight = {r = 255, g = 160, b = 0, a = 170}, + feature_selected_bottomLeft = {r = 0, g = 0, b = 0, a = 200}, + feature_selected_topLeft = {r = 0, g = 0, b = 0, a = 200}, + feature_selected_topRight = {r = 0, g = 0, b = 0, a = 200}, + feature_selected_bottomRight = {r = 0, g = 0, b = 0, a = 200}, + text_selected = {r = 255, g = 200, b = 0, a = 180}, + text = {r = 0, g = 0, b = 0, a = 180}, + border = {r = 0, g = 0, b = 0, a = 180}, + footer = {r = 255, g = 160, b = 0, a = 170}, + footer_text = {r = 0, g = 0, b = 0, a = 180}, + notifications = {r = 255, g = 200, b = 0, a = 255}, + side_window = {r = 0, g = 0, b = 0, a = 150}, + side_window_text = {r = 255, g = 255, b = 255, a = 220} + } + + stuff.path.cheesemenu = stuff.path.scripts.."cheesemenu\\" + for k, v in pairs(utils.get_all_sub_directories_in_directory(stuff.path.cheesemenu)) do + stuff.path[v] = stuff.path.cheesemenu..v.."\\" + end + + stuff.menuData.background_sprite.fit_size_to_width = function(self) + self.size = stuff.menuData.width*graphics.get_screen_width()/scriptdraw.get_sprite_size(func.load_sprite(stuff.path.background..(self.sprite or ""), stuff.menuData.background_sprite.loaded_sprites)).x + end + stuff.menuData.background_sprite.fit_size_to_height = function(self) + self.size = stuff.menuData.height*graphics.get_screen_height()/scriptdraw.get_sprite_size(func.load_sprite(stuff.path.background..(self.sprite or ""), stuff.menuData.background_sprite.loaded_sprites)).y + end + + stuff.image_ext = {"gif", "bmp", "jpg", "jpeg", "png", "2t1", "dds"} + stuff.menuData.files.headers = {} + for _, ext in pairs(stuff.image_ext) do + for _, image in pairs(utils.get_all_files_in_directory(stuff.path.header, ext)) do + stuff.menuData.files.headers[#stuff.menuData.files.headers + 1] = image + end + end + for k, v in pairs(utils.get_all_sub_directories_in_directory(stuff.path.header)) do + stuff.menuData.files.headers[#stuff.menuData.files.headers + 1] = v..".ogif" + end + + stuff.menuData.files.ui = {} + for k, v in pairs(utils.get_all_files_in_directory(stuff.path.ui, "lua")) do + stuff.menuData.files.ui[k] = v:sub(1, #v - 4) + end + + stuff.menuData.files.background = {} + for _, ext in pairs(stuff.image_ext) do + for k, v in pairs(utils.get_all_files_in_directory(stuff.path.background, "png")) do + stuff.menuData.files.background[k] = v + end + end + + stuff.menuData_methods = { + set_color = function(self, colorName, r, g, b, a) + assert(self[colorName], "field "..colorName.." does not exist") + local colors = {r = r or false, g = g or false, b = b or false, a = a or false} + for k, v in pairs(colors) do + if not v then + if type(self[colorName]) == "table" then + colors[k] = self[colorName][k] + else + colors[k] = func.convert_int_to_rgba(self[colorName], k) + end + end + end + for k, v in pairs(colors) do + assert(v <= 255 and v >= 0, "attempted to set invalid "..k.." value to field "..colorName) + end + if type(self[colorName]) == "table" then + self[colorName] = colors + else + self[colorName] = (colors.a << 24) + (colors.b << 16) + (colors.g << 8) + colors.r + end + end + } + function func.convert_rgba_to_int(r, g, b, a) + if type(r) == "table" then + local colorTable = r + r = colorTable.r or colorTable[1] + g = colorTable.g or colorTable[2] + b = colorTable.b or colorTable[3] + a = colorTable.a or colorTable[4] + end + if not a then + a = 255 + end + assert(r and g and b, "one or more of the r, g, b values is invalid") + assert((a <= 255 and a >= 0) and (b <= 255 and b >= 0) and (g <= 255 and g >= 0) and (r <= 255 and r >= 0), "rgba values cannot be more than 255 or less than 0") + return (a << 24) + (b << 16) + (g << 8) + r + end + + stuff.conversionValues = {a = 24, b = 16, g = 8, r = 0} + function func.convert_int_to_rgba(...) + local int, val1, val2, val3, val4 = ... + local values = {val1, val2, val3, val4} + + for k, v in pairs(values) do + values[k] = int >> stuff.conversionValues[v] & 0xff + end + return table.unpack(values) + end + setmetatable(stuff.menuData.color, {__index = stuff.menuData_methods}) + + function func.convert_int_ip(ip) + local ipTable = {} + ipTable[1] = ip >> 24 & 255 + ipTable[2] = ip >> 16 & 255 + ipTable[3] = ip >> 8 & 255 + ipTable[4] = ip & 255 + + return table.concat(ipTable, ".") + end + + stuff.input = require("cheesemenu.libs.Get Input") + local gltw = require("cheesemenu.libs.GLTW") + local cheeseUtils = require("cheesemenu.libs.CheeseUtilities") + assert(gltw, "GLTW library is not found, please install the menu with 'cheesemenu' folder.") + + + gltw.read("controls", stuff.path.cheesemenu, stuff.controls, false, true) + for k, v in pairs(stuff.controls) do + stuff.vkcontrols[k] = stuff.char_codes[v] + end + + gltw.read("hotkey notifications", stuff.path.hotkeys, stuff.hotkey_notifications, false, true) + stuff.hotkeys = gltw.read("hotkeys", stuff.path.hotkeys, nil, false, true) or {} + stuff.hierarchy_key_to_hotkey = {} + for k, v in pairs(stuff.hotkeys) do + stuff.hotkey_cooldowns[k] = 0 + + local string_to_vk = {} + for char in k:gmatch("%|*([^%|]+)%|*") do + string_to_vk[#string_to_vk+1] = stuff.char_codes[char] + end + stuff.hotkeys_to_vk[k] = string_to_vk + + if type(v) == "table" then + for i, e in pairs(v) do + stuff.hierarchy_key_to_hotkey[i] = k + end + end + end + + --local originalGetInput = input.get + if stuff.input then + function input.get(title, default, len, Type) + local originalmenuToggle = stuff.menuData.menuToggle + stuff.menuData.menuToggle = false + stuff.menuData.chatBoxOpen = true + local status, gottenInput = stuff.input.get_input(title, default, len, Type) + + func.toggle_menu(originalmenuToggle) + stuff.menuData.chatBoxOpen = false + return status, gottenInput + end + end + + -- Credit to kektram for these functions + do + local _ENV = { + getmetatable = debug.getmetatable + } + function stuff.rawset(Table, index, value) -- Matches performance of normal rawset. + local metatable = getmetatable(Table) + local __newindex + if metatable then + __newindex = metatable.__newindex + metatable.__newindex = nil + end + Table[index] = value + if __newindex then + metatable.__newindex = __newindex + end + return Table + end + end + do + local _ENV = { + getmetatable = debug.getmetatable + } + function stuff.rawget(Table, index, value) -- Matches performance of normal rawget. + local metatable = getmetatable(Table) + local __index + if metatable then + __index = metatable.__index + metatable.__index = nil + end + local value = Table[index] + if __index then + metatable.__index = __index + end + return value + end + end + -- + + stuff.playerSpecialValues = {value = true, min = true, max = true, mod = true, on = true, real_value = true, real_max = true, real_min = true, real_mod = true, real_on = true} + + stuff.featMetaTable = { + __index = function(t, k) + if k == "is_highlighted" then + return t == currentMenu[stuff.scroll + stuff.scrollHiddenOffset] + elseif k == "parent" then + return t.type >> 15 & 1 == 0 and func.get_feature(t.parent_id) or func.get_player_feature(t.parent_id) + elseif k == "value" or k == "min" or k == "mod" or k == "max" or k == "str_data" or k == "type" or k == "id" or k == "on" or k == "hidden" or k == "data" then + if t.playerFeat and k ~= "str_data" and k ~= "type" and k ~= "id" and k ~= "hidden" and k ~= "data" then + return stuff.rawget(t, "table_"..k) + else + return stuff.rawget(t, "real_"..k) + end + elseif k == "children" and t.type >> 11 & 1 ~= 0 then + return t:get_children() + elseif k == "hint" then + local hintTable = t.type >> 15 & 1 ~= 0 and stuff.player_feature_hints or stuff.feature_hints + return hintTable[t.id].str + --[[ else + return stuff.rawget(t, k) ]] + end + end, + + __newindex = function(t, k, v) + assert(k ~= "id" and k ~= "children" and k ~= "type" and k ~= "str_data" and k ~= "is_highlighted", "'"..k.."' is read only") + if k == "on" and type(v) == "boolean" then + if t.real_on == v then + return + end + --[[ if t.type >> 11 & 1 ~= 0 and t.real_on ~= nil then + func.check_scroll(t.index, (t.parent_id > 0 and t.parent or features), not v) + end ]] + stuff.rawset(t, "real_on", v) + + if t.feats then + for pid, feat in pairs(t.feats) do + if player.is_player_valid(pid) then + feat.on = v + --[[ if feat.type >> 11 & 1 ~= 0 then + func.check_scroll(feat.index, (feat.parent_id > 0 and stuff.feature_by_id[feat.ps_parent_id] or stuff.PlayerParent), not v) + end ]] + end + end + else + if v then + t:activate_feat_func() + end + end + elseif k == "value" or k == "min" or k == "mod" or k == "max" then + if k ~= "value" and t.type >> 5 & 1 ~= 0 then -- value_str + error("max, min and mod are readonly for value_str features") end - system.wait(0) + v = tonumber(v) + + assert(t.type >> 1 & 1 ~= 0, "feat type not supported: "..t.type) -- value_[if], value_str + assert(v, "tried to set "..k.." property to a non-number value") + + if t.type >> 5 & 1 ~= 0 then -- value_str + if v < 0 then + v = 0 + elseif t.real_str_data then + if v+1 > #t.real_str_data and #t.real_str_data ~= 0 then + v = #t.real_str_data-1 + end + end + end + + if t.type >> 1 & 1 ~= 0 then + if t.type >> 3 & 1 ~= 0 or t.type >> 5 & 1 ~= 0 then -- value_str + v = math.floor(v) + end + + stuff.rawset(t, "real_"..k, v) + if t.type & 140 ~= 0 then -- i|f|slider + if not t.real_max then + t.real_max = 0 + end + if not t.real_min then + t.real_min = 0 + end + if not t.real_mod then + t.real_mod = 1 + end + if not t.real_value then + t.real_value = 0 + end + + stuff.rawset(t, "real_value", t.real_value >= t.real_max and t.real_max or t.real_value <= t.real_min and t.real_min or t.real_value) + end + + if t["table_"..k] then + local is_num = t.type & 140 ~= 0 + for i = 0, 31 do + t["table_"..k][i] = v + if is_num then + t["table_value"][i] = t["table_value"][i] >= t["table_max"][i] and t["table_max"][i] or t["table_value"][i] <= t["table_min"][i] and t["table_min"][i] or t["table_value"][i] + end + end + end + end + elseif k == "hidden" then + assert(type(v) == "boolean", "hidden only accepts booleans") + if t.real_hidden == v then + return + end + + --[[ if t.real_hidden ~= nil then + func.check_scroll(t.index, (t.parent_id > 0 and t.parent or features), v) + end ]] + + t.real_hidden = v + if t.feats then + for _, feat in ipairs(t.feats) do + feat.hidden = v + end + end + if v then + func.deleted_or_hidden_parent_check(t) + end + elseif k == "data" then + stuff.rawset(t, "real_data", v) + if t.feats then + for i, e in pairs(t.feats) do + t.feats[i].real_data = v + end + end + elseif k == "hint" then + local hintTable = t.type >> 15 & 1 ~= 0 and stuff.player_feature_hints or stuff.feature_hints + if not v then + hintTable[t.id] = nil + return + end + assert(type(v) == "string", "Feat.hint only supports strings") + local str = cheeseUtils.wrap_text(v, stuff.menuData.fonts.hint, stuff.menuData.text_size * stuff.menuData.hint_size_modifier, stuff.menuData.width*2-scriptdraw.size_pixel_to_rel_x(25)) + hintTable[t.id] = {str = str, size = scriptdraw.get_text_size(str, 1, stuff.menuData.fonts.hint), original = v} + else + stuff.rawset(t, k, v) end end } - stuff.menuData.color = { - background = {r = 0, g = 0, b = 0, a = 0}, - sprite = 0xE6FFFFFF, - slider_active = {r = 255, g = 200, b = 0, a = 255}, - slider_background = {r = 0, g = 0, b = 0, a = 160}, - slider_text = {r = 0, g = 0, b = 0, a = 255}, - slider_selectedActive = {r = 255, g = 255, b = 255, a = 160}, - slider_selectedBackground = {r = 255, g = 160, b = 0, a = 180}, - feature_bottomLeft = {r = 255, g = 160, b = 0, a = 170}, - feature_topLeft = {r = 255, g = 160, b = 0, a = 170}, - feature_topRight = {r = 255, g = 160, b = 0, a = 170}, - feature_bottomRight = {r = 255, g = 160, b = 0, a = 170}, - feature_selected_bottomLeft = {r = 0, g = 0, b = 0, a = 200}, - feature_selected_topLeft = {r = 0, g = 0, b = 0, a = 200}, - feature_selected_topRight = {r = 0, g = 0, b = 0, a = 200}, - feature_selected_bottomRight = {r = 0, g = 0, b = 0, a = 200}, - text_selected = {r = 255, g = 200, b = 0, a = 180}, - text = {r = 0, g = 0, b = 0, a = 180}, - border = {r = 0, g = 0, b = 0, a = 180}, - footer = {r = 255, g = 160, b = 0, a = 170}, - footer_text = {r = 0, g = 0, b = 0, a = 180}, - notifications = {r = 255, g = 200, b = 0, a = 255}, - side_window = {r = 0, g = 0, b = 0, a = 150}, - side_window_text = {r = 255, g = 255, b = 255, a = 220} + stuff.playerfeatMetaTable = { + __index = function(t, k) + if k == "is_highlighted" then + return t == currentMenu[stuff.scroll + stuff.scrollHiddenOffset] + elseif k == "parent" then + return func.get_player_feature(t.parent_id) + elseif k == "str_data" or k == "type" or k == "id" or k == "data" or k == "hidden" then + return stuff.rawget(t, "real_"..k) + elseif stuff.playerSpecialValues[k] then + if t["table_"..k:gsub("real_", "")] then + return t["table_"..k:gsub("real_", "")][t.pid] + end + elseif k == "children" and t.type >> 11 & 1 ~= 0 then + return t:get_children() + else + return stuff.rawget(t, k) + end + end, + + __newindex = function(t, k, v) + assert(k ~= "id" and k ~= "children" and k ~= "type" and k ~= "str_data" and k ~= "is_highlighted", "'"..k.."' is read only") + if (k == "on" or k == "real_on") and type(v) == "boolean" then + t["table_on"][t.pid] = v + if v then + t:activate_feat_func() + end + elseif stuff.playerSpecialValues[k] then + k = k:gsub("real_", "") + if k ~= "value" and t.type >> 5 & 1 ~= 0 then + error("max, min and mod are readonly for value_str features") + end + v = tonumber(v) + + assert(t.type >> 1 & 1 ~= 0, "feat type not supported") + assert(v, "tried to set "..k.." property to a non-number value") + + if t.type >> 5 & 1 ~= 0 then + if v < 0 then + v = 0 + elseif t.real_str_data then + if v+1 > #t.real_str_data and #t.real_str_data ~= 0 then + v = #t.real_str_data-1 + end + end + end + + if t.type >> 1 & 1 ~= 0 then + if t.type >> 3 & 1 ~= 0 or t.type >> 5 & 1 ~= 0 then -- value_i|str + v = math.floor(v) + end + + t["table_"..k][t.pid] = v + if t.type & 140 ~= 0 then -- i|f|slider + if not t.real_max then + t.real_max = 0 + end + if not t.real_min then + t.real_min = 0 + end + if not t.real_mod then + t.real_mod = 1 + end + if not t.real_value then + t.real_value = 0 + end + + t["table_value"][t.pid] = t["table_value"][t.pid] >= t["table_max"][t.pid] and t["table_max"][t.pid] or t["table_value"][t.pid] <= t["table_min"][t.pid] and t["table_min"][t.pid] or t["table_value"][t.pid] + end + end + elseif k == "data" then + t.real_data = v + else + stuff.rawset(t, k, v) + end + end } - stuff.path.cheesemenu = stuff.path.scripts.."cheesemenu\\" - for k, v in pairs(utils.get_all_sub_directories_in_directory(stuff.path.cheesemenu)) do - stuff.path[v] = stuff.path.cheesemenu..v.."\\" + -- featMethods + + -- dogshit dont use + --[[ stuff.set_val = function(self, valueType, val, dont_set_all) + assert(stuff.type_id.id_to_name[self.type]:match("value_[if]") or stuff.type_id.id_to_name[self.type]:match("value_str"), "feat type not supported") + assert(tonumber(val), "tried to set "..valueType.." to a non-number value") + if stuff.type_id.id_to_name[self.type]:match("value_i") then + val = tonumber(math.floor(val)) + else + val = tonumber(val) + end + + if valueType == "value" then + if self.real_min then + if val < self.real_min then + val = self.real_min + end + else + if val < 0 then + val = 0 + end + end + if self.real_max then + if val > self.real_max then + val = self.real_max + end + elseif self.real_str_data then + if val+1 > #self.real_str_data then + val = #self.real_str_data-1 + end + end + end + + self[valueType] = val + if self["table_"..valueType] and not dont_set_all then + for i = 0, 31 do + self["table_"..valueType][i] = val + end + end + end + + stuff.set_value = function(self, val, dont_set_all) + stuff.set_val(self, "value", val, dont_set_all) + end + stuff.set_max = function(self, val, dont_set_all) + stuff.set_val(self, "max", val, dont_set_all) + end + stuff.set_min = function(self, val, dont_set_all) + stuff.set_val(self, "min", val, dont_set_all) + end + stuff.set_mod = function(self, val, dont_set_all) + stuff.set_val(self, "mod", val, dont_set_all) + end ]] + + stuff.get_str_data = function(self) + assert(self.type >> 5 & 1 ~= 0, "used get_str_data on a feature that isn't value_str") + return self.str_data + end + + stuff.set_str_data = function(self, stringTable) + assert(type(stringTable) == "table", "tried to set str_data property to a non-table value") + local numberedTable + for k, v in pairs(stringTable) do + if type(k) ~= "number" then + numberedTable = {} + for k, v in pairs(stringTable) do + numberedTable[#numberedTable + 1] = v + end + break + end + end + self.real_str_data = numberedTable or stringTable + if self.real_value+1 > #self.real_str_data then + self.real_value = #self.real_str_data-1 >= 0 and #self.real_str_data-1 or 0 + end + if self.feats then + for k, v in pairs(self.table_value) do + if v+1 > #self.real_str_data then + self.table_value[k] = #self.real_str_data-1 + end + end + for k, v in pairs(self.feats) do + v.real_str_data = stringTable + end + end end - stuff.menuData.background_sprite.fit_size_to_width = function(self) - self.size = stuff.menuData.width*graphics.get_screen_width()/scriptdraw.get_sprite_size(func.load_sprite(stuff.path.background..(self.sprite or ""), stuff.menuData.background_sprite.loaded_sprites)).x - end - stuff.menuData.background_sprite.fit_size_to_height = function(self) - self.size = stuff.menuData.height*graphics.get_screen_height()/scriptdraw.get_sprite_size(func.load_sprite(stuff.path.background..(self.sprite or ""), stuff.menuData.background_sprite.loaded_sprites)).y + stuff.toggle = function(self, bool) + if self.type & 1 ~= 0 then + if bool ~= nil then + self.real_on = bool + self:activate_feat_func() + else + self.real_on = not self.real_on + self:activate_feat_func() + end + else + self:activate_feat_func() + end end - stuff.image_ext = {"gif", "bmp", "jpg", "jpeg", "png", "2t1", "dds"} - stuff.menuData.files.headers = {} - for _, ext in pairs(stuff.image_ext) do - for _, image in pairs(utils.get_all_files_in_directory(stuff.path.header, ext)) do - stuff.menuData.files.headers[#stuff.menuData.files.headers + 1] = image + stuff.get_children = function(self) + local children = {} + for k, v in ipairs(self) do + if type(k) == "number" then + children[k] = v + end end + return children end - for k, v in pairs(utils.get_all_sub_directories_in_directory(stuff.path.header)) do - stuff.menuData.files.headers[#stuff.menuData.files.headers + 1] = v..".ogif" + + -- function callback ~Thanks to Proddy for telling me that doing function() every time creates a new one and providing examples on how to use menu.create_thread with the function below + function stuff.feature_callback(self) + local pidordata = self.pid or self.data + if self.on ~= nil and self.type & 2049 == 0 then -- not toggle or parent + self.on = true + end + local continue = self:func(pidordata, self.data) + while continue == HANDLER_CONTINUE do + system.wait(0) + continue = self:func(pidordata, self.data) + end + if self.on ~= nil and self.type & 2049 == 0 then -- not toggle or parent + self.on = false + end end - stuff.menuData.files.ui = {} - for k, v in pairs(utils.get_all_files_in_directory(stuff.path.ui, "lua")) do - stuff.menuData.files.ui[k] = v:sub(1, #v - 4) + function stuff.highlight_callback(self) + local pidordata = self.pid or self.data + self:hl_func(pidordata, self.data) end - stuff.menuData.files.background = {} - for _, ext in pairs(stuff.image_ext) do - for k, v in pairs(utils.get_all_files_in_directory(stuff.path.background, "png")) do - stuff.menuData.files.background[k] = v + stuff.activate_feat_func = function(self) + if not (self.thread) then + self.thread = 0 + end + if self.func and menu.has_thread_finished(self.thread) then + self.thread = menu.create_thread(stuff.feature_callback, self) end end - stuff.menuData_methods = { - set_color = function(self, colorName, r, g, b, a) - assert(self[colorName], "field "..colorName.." does not exist") - local colors = {r = r or false, g = g or false, b = b or false, a = a or false} - for k, v in pairs(colors) do - if not v then - if type(self[colorName]) == "table" then - colors[k] = self[colorName][k] - else - colors[k] = func.convert_int_to_rgba(self[colorName], k) - end - end - end - for k, v in pairs(colors) do - assert(v <= 255 and v >= 0, "attempted to set invalid "..k.." value to field "..colorName) + stuff.activate_hl_func = function(self) + if self.hl_func then + if not self.hl_thread then + self.hl_thread = 0 end - if type(self[colorName]) == "table" then - self[colorName] = colors - else - self[colorName] = (colors.a << 24) + (colors.b << 16) + (colors.g << 8) + colors.r + if menu.has_thread_finished(self.hl_thread) then + self.hl_thread = menu.create_thread(stuff.highlight_callback, self) end end - } - function func.convert_rgba_to_int(r, g, b, a) - if type(r) == "table" then - local colorTable = r - r = colorTable.r or colorTable[1] - g = colorTable.g or colorTable[2] - b = colorTable.b or colorTable[3] - a = colorTable.a or colorTable[4] - end - if not a then - a = 255 - end - assert(r and g and b, "one or more of the r, g, b values is invalid") - assert((a <= 255 and a >= 0) and (b <= 255 and b >= 0) and (g <= 255 and g >= 0) and (r <= 255 and r >= 0), "rgba values cannot be more than 255 or less than 0") - return (a << 24) + (b << 16) + (g << 8) + r end - stuff.conversionValues = {a = 24, b = 16, g = 8, r = 0} - function func.convert_int_to_rgba(...) - local int, val1, val2, val3, val4 = ... - local values = {val1, val2, val3, val4} + stuff.select = function(self) + local parent_of_feat_wanted = stuff.feature_by_id[self.parent_id] or features - for k, v in pairs(values) do - values[k] = int >> stuff.conversionValues[v] & 0xff + if not (parent_of_feat_wanted == currentMenu) then + stuff.previousMenus[#stuff.previousMenus + 1] = {menu = currentMenu, scroll = stuff.scroll, drawScroll = stuff.drawScroll, scrollHiddenOffset = stuff.scrollHiddenOffset} + currentMenu = parent_of_feat_wanted end - return table.unpack(values) - end - setmetatable(stuff.menuData.color, {__index = stuff.menuData_methods}) - function func.convert_int_ip(ip) - local ipTable = {} - ipTable[1] = ip >> 24 & 255 - ipTable[2] = ip >> 16 & 255 - ipTable[3] = ip >> 8 & 255 - ipTable[4] = ip & 255 + if not self.hidden then + local hiddenOffset = 0 + for k, v in ipairs(parent_of_feat_wanted) do + if type(k) == "number" then + if v.hidden and not (k > self.index) then + hiddenOffset = hiddenOffset + 1 + end + end + end + stuff.scroll = self.index - hiddenOffset + stuff.drawScroll = (stuff.maxDrawScroll >= self.index) and self.index-1 or stuff.maxDrawScroll + end - return table.concat(ipTable, ".") + stuff.scrollHiddenOffset = 0 end + -- - stuff.input = require("cheesemenu.libs.Get Input") - local gltw = require("cheesemenu.libs.GLTW") - local cheeseUtils = require("cheesemenu.libs.CheeseUtilities") - assert(gltw, "GLTW library is not found, please install the menu with 'cheesemenu' folder.") + stuff.hotkey_feature_hierarchy_keys = {} + stuff.type_id = { + name_to_id = { + toggle = 1 << 0, + slider = 1 << 2 | 1 << 1 | 1 << 0, + value_i = 1 << 3 | 1 << 1 | 1 << 0, + value_str = 1 << 5 | 1 << 1 | 1 << 0, + value_f = 1 << 7 | 1 << 1 | 1 << 0, + action = 1 << 9, + action_slider = 1 << 9 | 1 << 2 | 1 << 1, + action_value_i = 1 << 9 | 1 << 3 | 1 << 1, + action_value_str = 1 << 9 | 1 << 5 | 1 << 1, + action_value_f = 1 << 9 | 1 << 7 | 1 << 1, + autoaction_slider = 1 << 10 | 1 << 2 | 1 << 1, + autoaction_value_i = 1 << 10 | 1 << 3 | 1 << 1, + autoaction_value_str = 1 << 10 | 1 << 5 | 1 << 1, + autoaction_value_f = 1 << 10 | 1 << 7 | 1 << 1, + parent = 1 << 11 + }, + } - gltw.read("controls", stuff.path.cheesemenu, stuff.controls, false, true) - for k, v in pairs(stuff.controls) do - stuff.vkcontrols[k] = stuff.char_codes[v] - end + --Functions + function func.add_feature(nameOfFeat, TypeOfFeat, parentOfFeat, functionCallback, highlightCallback, playerFeat) + assert((type(nameOfFeat) == "string"), "invalid name in add_feature") + assert((type(TypeOfFeat) == "string") and stuff.type_id.name_to_id[TypeOfFeat], "invalid type in add_feature") + assert((type(parentOfFeat) == "number") or not parentOfFeat, "invalid parent id in add_feature") + assert((type(functionCallback) == "function") or not functionCallback, "invalid function in add_feature") + playerFeat = playerFeat or false + parentOfFeat = parentOfFeat or 0 + --TypeOfFeat = TypeOfFeat:gsub("slider", "value_f") + local currentParent = playerFeat and features["OnlinePlayers"] or features - gltw.read("hotkey notifications", stuff.path.hotkeys, stuff.hotkey_notifications, false, true) - stuff.hotkeys = gltw.read("hotkeys", stuff.path.hotkeys, nil, false, true) or {} - stuff.hierarchy_key_to_hotkey = {} - for k, v in pairs(stuff.hotkeys) do - stuff.hotkey_cooldowns[k] = 0 + local hierarchy_key + if parentOfFeat ~= 0 and parentOfFeat then + currentParent = playerFeat and stuff.player_feature_by_id[parentOfFeat] or stuff.feature_by_id[parentOfFeat] + if currentParent then + assert(currentParent.type >> 11 & 1 ~= 0, "parent is not a parent feature") + assert(currentParent.type >> 15 & 1 ~= 0 == playerFeat, "parent is not valid "..((currentParent.type >> 15 & 1 ~= 0 and not playerFeat) and "using player feature as parent for a local feature" or (currentParent.type >> 15 & 1 == 0 and playerFeat and "using local parent for player feature") or "unknown")) + else + error("parent does not exist") + end + end + if currentParent.hierarchy_key then + hierarchy_key = currentParent.hierarchy_key.."."..nameOfFeat:gsub("[ %.]", "_") + else + hierarchy_key = nameOfFeat:gsub("[ %.]", "_") + end - local string_to_vk = {} - for char in k:gmatch("%|*([^%|]+)%|*") do - string_to_vk[#string_to_vk+1] = stuff.char_codes[char] + currentParent[#currentParent + 1] = {name = nameOfFeat, real_type = stuff.type_id.name_to_id[TypeOfFeat] | (playerFeat and 1 << 15 or 0), real_id = 0, --[[parent = {id = currentParent.id or 0},]] parent_id = currentParent.id or 0, playerFeat = playerFeat, index = #currentParent + 1} + local feat = currentParent[#currentParent] + feat.activate_feat_func = stuff.activate_feat_func + feat.activate_hl_func = stuff.activate_hl_func + feat.set_str_data = stuff.set_str_data + feat.toggle = stuff.toggle + feat.get_children = stuff.get_children + feat.get_str_data = stuff.get_str_data + feat.select = stuff.select + setmetatable(feat, stuff.featMetaTable) + feat.thread = 0 + --if feat.real_type & 1 ~= 0 or feat.real_type >> 9 & 1 ~= 0 then -- toggle + if playerFeat then + feat.table_on = {} + for i = 0, 31 do + feat.table_on[i] = feat.type >> 11 & 1 ~= 0 + end + end + feat.on = feat.type >> 11 & 1 ~= 0 + --end + if feat.real_type >> 5 & 1 ~= 0 then -- value_str + feat.real_str_data = {} + if playerFeat then + feat.table_value = {} + for i = 0, 31 do + feat.table_value[i] = 0 + end + end + feat.value = 0 + elseif feat.real_type >> 1 & 1 ~= 0 then --value any + if playerFeat then + feat.table_max = {} + feat.table_min = {} + feat.table_mod = {} + feat.table_value = {} + for i = 0, 31 do + feat.table_max[i] = 0 + feat.table_min[i] = 0 + feat.table_mod[i] = 1 + feat.table_value[i] = 0 + end + end + feat.max = 0 + feat.min = 0 + feat.mod = 1 + feat.value = 0 end - stuff.hotkeys_to_vk[k] = string_to_vk - - if type(v) == "table" then - for i, e in pairs(v) do - stuff.hierarchy_key_to_hotkey[i] = k + feat.hidden = false + feat["func"] = functionCallback + feat["hl_func"] = highlightCallback + if TypeOfFeat == "parent" then + feat.child_count = 0 + end + currentParent.child_count = 0 + for k, v in pairs(currentParent) do + if type(k) == "number" then + currentParent.child_count = currentParent.child_count + 1 end end + feat.hotkey = stuff.hierarchy_key_to_hotkey[hierarchy_key] + feat.hierarchy_key = hierarchy_key + if stuff.hotkey_feature_hierarchy_keys[hierarchy_key] then + stuff.hotkey_feature_hierarchy_keys[hierarchy_key][#stuff.hotkey_feature_hierarchy_keys[hierarchy_key] + 1] = feat + else + stuff.hotkey_feature_hierarchy_keys[hierarchy_key] = {feat} + end + if playerFeat then + stuff.player_feature_by_id[#stuff.player_feature_by_id+1] = feat + feat.real_id = #stuff.player_feature_by_id + else + stuff.feature_by_id[#stuff.feature_by_id+1] = feat + feat.real_id = #stuff.feature_by_id + end + return feat end - --local originalGetInput = input.get - if stuff.input then - function input.get(title, default, len, Type) - local originalmenuToggle = stuff.menuData.menuToggle - stuff.menuData.menuToggle = false - stuff.menuData.chatBoxOpen = true - local status, gottenInput = stuff.input.get_input(title, default, len, Type) + --player feature functions - func.toggle_menu(originalmenuToggle) - stuff.menuData.chatBoxOpen = false - return status, gottenInput - end - end + -- if you set a toggle player feature to on it'll enable for any valid players/joining players but if a player leaves functions like player.get_player_name will return nil before the feature is turned off + function func.add_player_feature(nameOfFeat, TypeOfFeat, parentOfFeat, functionCallback, highlightCallback) + parentOfFeat = parentOfFeat or 0 + assert(stuff.PlayerParent, "you need to use set_player_feat_parent before adding player features") + local pfeat = func.add_feature(nameOfFeat, TypeOfFeat, parentOfFeat, functionCallback, highlightCallback, true) + pfeat.feats = {} - -- Credit to kektram for these functions - do - local _ENV = { - getmetatable = debug.getmetatable - } - function stuff.rawset(Table, index, value) -- Matches performance of normal rawset. - local metatable = getmetatable(Table) - local __newindex - if metatable then - __newindex = metatable.__newindex - metatable.__newindex = nil - end - Table[index] = value - if __newindex then - metatable.__newindex = __newindex - end - return Table - end - end - do - local _ENV = { - getmetatable = debug.getmetatable - } - function stuff.rawget(Table, index, value) -- Matches performance of normal rawget. - local metatable = getmetatable(Table) - local __index - if metatable then - __index = metatable.__index - metatable.__index = nil + if parentOfFeat == 0 then + for k = 0, 31 do + stuff.playerIds[k][#stuff.playerIds[k]+1] = {} + local currentFeat = stuff.playerIds[k][#stuff.playerIds[k]] + func.add_to_table(pfeat, currentFeat, k, nil, true) + stuff.feature_by_id[#stuff.feature_by_id+1] = currentFeat + currentFeat.ps_id = #stuff.feature_by_id + currentFeat.ps_parent_id = stuff.playerIds[k].id + currentFeat.pid = k + pfeat.feats[k] = currentFeat end - local value = Table[index] - if __index then - metatable.__index = __index + else + local playerParent = stuff.player_feature_by_id[parentOfFeat] + if playerParent then + for k = 0, 31 do + playerParent.feats[k][#playerParent.feats[k]+1] = {} + local currentFeat = playerParent.feats[k][#playerParent.feats[k]] + + func.add_to_table(pfeat, currentFeat, k, nil, true) + stuff.feature_by_id[#stuff.feature_by_id+1] = currentFeat + currentFeat.ps_id = #stuff.feature_by_id + currentFeat.ps_parent_id = playerParent.feats[k].ps_id + currentFeat.pid = k + pfeat.feats[k] = currentFeat + end end - return value end - end - -- - stuff.playerSpecialValues = {value = true, min = true, max = true, mod = true, on = true, real_value = true, real_max = true, real_min = true, real_mod = true, real_on = true} + return pfeat + end - stuff.featMetaTable = { - __index = function(t, k) - if k == "is_highlighted" then - return t == currentMenu[stuff.scroll + stuff.scrollHiddenOffset] - elseif k == "parent" then - return t.type >> 15 & 1 == 0 and func.get_feature(t.parent_id) or func.get_player_feature(t.parent_id) - elseif k == "value" or k == "min" or k == "mod" or k == "max" or k == "str_data" or k == "type" or k == "id" or k == "on" or k == "hidden" or k == "data" then - if t.playerFeat and k ~= "str_data" and k ~= "type" and k ~= "id" and k ~= "hidden" and k ~= "data" then - return stuff.rawget(t, "table_"..k) - else - return stuff.rawget(t, "real_"..k) + function func.add_to_table(getTable, addToTable, playerid, override, setmeta) + local isPlayerFeatValues + for k, v in pairs(getTable) do + if tostring(k):match("table_") or stuff.playerSpecialValues[k] then + isPlayerFeatValues = true + elseif type(v) == "table" then + if type(addToTable[k]) ~= "table" then + addToTable[k] = {} end - elseif k == "children" and t.type >> 11 & 1 ~= 0 then - return t:get_children() - elseif k == "hint" then - local hintTable = t.type >> 15 & 1 ~= 0 and stuff.player_feature_hints or stuff.feature_hints - return hintTable[t.id].str - --[[ else - return stuff.rawget(t, k) ]] - end - end, - - __newindex = function(t, k, v) - assert(k ~= "id" and k ~= "children" and k ~= "type" and k ~= "str_data" and k ~= "is_highlighted", "'"..k.."' is read only") - if k == "on" and type(v) == "boolean" then - if t.real_on == v then - return + if addToTable[k].real_on then + addToTable[k].real_on = false end - --[[ if t.type >> 11 & 1 ~= 0 and t.real_on ~= nil then - func.check_scroll(t.index, (t.parent_id > 0 and t.parent or features), not v) - end ]] - stuff.rawset(t, "real_on", v) - - if t.feats then - for pid, feat in pairs(t.feats) do - if player.is_player_valid(pid) then - feat.on = v - --[[ if feat.type >> 11 & 1 ~= 0 then - func.check_scroll(feat.index, (feat.parent_id > 0 and stuff.feature_by_id[feat.ps_parent_id] or stuff.PlayerParent), not v) - end ]] + if (v.type or 0) >> 11 & 1 ~= 0 then + func.add_to_table(getTable[k], addToTable[k], playerid, override) + else + for i, e in pairs(getTable[k]) do + if type(e) ~= "table" then + if not addToTable[k][i] or override then + addToTable[k][i] = e + end end end - else - if v then - t:activate_feat_func() + end + setmetatable(addToTable[k], stuff.playerfeatMetaTable) + if v.name then + if not getTable[k].feats then + getTable[k].feats = {} end + getTable[k].feats[playerid] = addToTable[k] end - elseif k == "value" or k == "min" or k == "mod" or k == "max" then - if k ~= "value" and t.type >> 5 & 1 ~= 0 then -- value_str - error("max, min and mod are readonly for value_str features") + else + if not addToTable[k] or override then + addToTable[k] = v end - v = tonumber(v) + end + end + if setmeta or isPlayerFeatValues then + addToTable.table_value = getTable.table_value + addToTable.table_min = getTable.table_min + addToTable.table_max = getTable.table_max + addToTable.table_mod = getTable.table_mod + addToTable.table_on = getTable.table_on + for i, e in pairs(stuff.playerSpecialValues) do + if addToTable[i] then + stuff.rawset(addToTable, i, nil) + end + end + setmetatable(addToTable, stuff.playerfeatMetaTable) + end + end - assert(t.type >> 1 & 1 ~= 0, "feat type not supported: "..t.type) -- value_[if], value_str - assert(v, "tried to set "..k.." property to a non-number value") + function func.set_player_feat_parent(nameOfFeat, parentOfFeat, functionToDo) + stuff.PlayerParent = func.add_feature(nameOfFeat, "parent", parentOfFeat, functionToDo) + local hierarchy_pattern = stuff.PlayerParent.hierarchy_key..".player_" - if t.type >> 5 & 1 ~= 0 then -- value_str - if v < 0 then - v = 0 - elseif t.real_str_data then - if v+1 > #t.real_str_data and #t.real_str_data ~= 0 then - v = #t.real_str_data-1 + stuff.playerIds = {} + for i = 0, 31 do + stuff.playerIds[i] = func.add_feature(tostring(player.get_player_name(i)), "parent", stuff.PlayerParent.id) + stuff.playerIds[i].pid = i + stuff.playerIds[i].hidden = not player.is_player_valid(i) + stuff.playerIds[i].hierarchy_key = hierarchy_pattern..i + stuff.playerIds[i].real_type = 1 << 15 | stuff.playerIds[i].type + end + + event.add_event_listener("player_join", function(listener) + system.wait(100) + stuff.playerIds[listener.player].hidden = false + stuff.playerIds[listener.player].name = player.get_player_name(listener.player) + func.reset_player_submenu(listener.player) + table.sort(stuff.PlayerParent, stuff.table_sort_functions[stuff.player_submenu_sort]) + end) + event.add_event_listener("player_leave", function(listener) + func.reset_player_submenu(listener.player) + if not player.is_player_valid(listener.player) then + stuff.playerIds[listener.player].hidden = true + stuff.playerIds[listener.player].name = "nil" + end + table.sort(stuff.PlayerParent, stuff.table_sort_functions[stuff.player_submenu_sort]) + end) + + return stuff.PlayerParent + end + + function func.reset_player_submenu(pid, currentParent) + local currentParent = currentParent or features.OnlinePlayers + for k, v in pairs(currentParent) do + if type(v) == "table" then + local feat_type = v.type + if feat_type then + if feat_type >> 1 & 1 ~= 0 then -- toggle + v.table_value[pid] = v.real_value + if feat_type & 136 ~= 0 then -- value if + v.table_min[pid] = v.real_min + v.table_max[pid] = v.real_max + v.table_mod[pid] = v.real_mod end end - end - - if t.type >> 1 & 1 ~= 0 then - if t.type >> 3 & 1 ~= 0 or t.type >> 5 & 1 ~= 0 then -- value_str - v = math.floor(v) - end - - stuff.rawset(t, "real_"..k, v) - if t.type & 140 ~= 0 then -- i|f|slider - if not t.real_max then - t.real_max = 0 - end - if not t.real_min then - t.real_min = 0 - end - if not t.real_mod then - t.real_mod = 1 - end - if not t.real_value then - t.real_value = 0 + if feat_type & 1 ~= 0 then -- toggle + if player.is_player_valid(pid) then + v.feats[pid].on = v.real_on + else + v.feats[pid].on = false + v.table_on[pid] = false end - - stuff.rawset(t, "real_value", t.real_value >= t.real_max and t.real_max or t.real_value <= t.real_min and t.real_min or t.real_value) end - - if t["table_"..k] then - local is_num = t.type & 140 ~= 0 - for i = 0, 31 do - t["table_"..k][i] = v - if is_num then - t["table_value"][i] = t["table_value"][i] >= t["table_max"][i] and t["table_max"][i] or t["table_value"][i] <= t["table_min"][i] and t["table_min"][i] or t["table_value"][i] - end - end + if feat_type >> 11 & 1 ~= 0 then -- parent + func.reset_player_submenu(pid, v) end end - elseif k == "hidden" then - assert(type(v) == "boolean", "hidden only accepts booleans") - if t.real_hidden == v then - return - end - - --[[ if t.real_hidden ~= nil then - func.check_scroll(t.index, (t.parent_id > 0 and t.parent or features), v) - end ]] + end + end + end + --end of player feature functions - t.real_hidden = v - if t.feats then - for _, feat in ipairs(t.feats) do - feat.hidden = v + function func.check_scroll(index, parent, bool) + if index <= stuff.scroll + stuff.scrollHiddenOffset and currentMenu == parent then + if bool then + --stuff.scroll = stuff.scroll - 1 + --stuff.scroll = stuff.scroll > 0 and stuff.scroll or 0 + if #currentMenu - stuff.drawHiddenOffset > 1 and stuff.scroll - 1 > 0 then + stuff.scroll = stuff.scroll - 1 + if stuff.scroll - stuff.drawScroll <= 2 and stuff.drawScroll > 0 then + stuff.drawScroll = stuff.drawScroll - 1 end end - if v then - func.deleted_or_hidden_parent_check(t) - end - elseif k == "data" then - stuff.rawset(t, "real_data", v) - if t.feats then - for i, e in pairs(t.feats) do - t.feats[i].real_data = v + else + if #currentMenu - stuff.drawHiddenOffset > 1 then + stuff.scroll = stuff.scroll + 1 + if stuff.scroll - stuff.drawScroll >= (stuff.menuData.max_features - 1) and stuff.drawScroll < stuff.maxDrawScroll then + stuff.drawScroll = stuff.drawScroll + 1 end end - elseif k == "hint" then - local hintTable = t.type >> 15 & 1 ~= 0 and stuff.player_feature_hints or stuff.feature_hints - if not v then - hintTable[t.id] = nil - return - end - assert(type(v) == "string", "Feat.hint only supports strings") - local str = cheeseUtils.wrap_text(v, stuff.menuData.fonts.hint, stuff.menuData.text_size * stuff.menuData.hint_size_modifier, stuff.menuData.width*2-scriptdraw.size_pixel_to_rel_x(25)) - hintTable[t.id] = {str = str, size = scriptdraw.get_text_size(str, 1, stuff.menuData.fonts.hint), original = v} - else - stuff.rawset(t, k, v) + --stuff.scroll = stuff.scroll + 1 end end - } + end - stuff.playerfeatMetaTable = { - __index = function(t, k) - if k == "is_highlighted" then - return t == currentMenu[stuff.scroll + stuff.scrollHiddenOffset] - elseif k == "parent" then - return func.get_player_feature(t.parent_id) - elseif k == "str_data" or k == "type" or k == "id" or k == "data" or k == "hidden" then - return stuff.rawget(t, "real_"..k) - elseif stuff.playerSpecialValues[k] then - if t["table_"..k:gsub("real_", "")] then - return t["table_"..k:gsub("real_", "")][t.pid] + function func.deleted_or_hidden_parent_check(parent, check_hidden_only) + if next(stuff.previousMenus) then + local parentBeforeDHparent = false + if parent ~= currentMenu then + for k, v in ipairs(stuff.previousMenus) do + if parentBeforeDHparent then + stuff.previousMenus[k] = nil + else + if (v.menu == parent and not check_hidden_only) or (v.menu.hidden and check_hidden_only) then + parentBeforeDHparent = true + currentMenu = stuff.previousMenus[k-1].menu + stuff.scroll = stuff.previousMenus[k-1].scroll + stuff.drawScroll = stuff.previousMenus[k-1].drawScroll + stuff.scrollHiddenOffset = stuff.previousMenus[k-1].scrollHiddenOffset + stuff.previousMenus[k-1] = nil + stuff.previousMenus[k] = nil + end + end end - elseif k == "children" and t.type >> 11 & 1 ~= 0 then - return t:get_children() - else - return stuff.rawget(t, k) + elseif not check_hidden_only then + currentMenu = stuff.previousMenus[#stuff.previousMenus].menu + stuff.scroll = stuff.previousMenus[#stuff.previousMenus].scroll + stuff.drawScroll = stuff.previousMenus[#stuff.previousMenus].drawScroll + stuff.scrollHiddenOffset = stuff.previousMenus[#stuff.previousMenus].scrollHiddenOffset + stuff.previousMenus[#stuff.previousMenus] = nil end - end, + end + end - __newindex = function(t, k, v) - assert(k ~= "id" and k ~= "children" and k ~= "type" and k ~= "str_data" and k ~= "is_highlighted", "'"..k.."' is read only") - if (k == "on" or k == "real_on") and type(v) == "boolean" then - t["table_on"][t.pid] = v - if v then - t:activate_feat_func() - end - elseif stuff.playerSpecialValues[k] then - k = k:gsub("real_", "") - if k ~= "value" and t.type >> 5 & 1 ~= 0 then - error("max, min and mod are readonly for value_str features") - end - v = tonumber(v) + function func.get_feature_by_hierarchy_key(hierarchy_key) + local feat = stuff.hotkey_feature_hierarchy_keys[hierarchy_key] + if feat then + if feat[2] and not feat.name then + return feat, true + else + return feat[1] + end + end + end - assert(t.type >> 1 & 1 ~= 0, "feat type not supported") - assert(v, "tried to set "..k.." property to a non-number value") + function func.get_feature(id) + assert(type(id) == "number" and id ~= 0, "invalid id in get_feature") + return stuff.feature_by_id[id] + end - if t.type >> 5 & 1 ~= 0 then - if v < 0 then - v = 0 - elseif t.real_str_data then - if v+1 > #t.real_str_data and #t.real_str_data ~= 0 then - v = #t.real_str_data-1 - end - end - end + function func.delete_feature(id, bool_ps) + if type(id) == "table" then + id = id.id + end - if t.type >> 1 & 1 ~= 0 then - if t.type >> 3 & 1 ~= 0 or t.type >> 5 & 1 ~= 0 then -- value_i|str - v = math.floor(v) - end + local feat = stuff.feature_by_id[id] + if not feat then + return false + end - t["table_"..k][t.pid] = v - if t.type & 140 ~= 0 then -- i|f|slider - if not t.real_max then - t.real_max = 0 - end - if not t.real_min then - t.real_min = 0 - end - if not t.real_mod then - t.real_mod = 1 - end - if not t.real_value then - t.real_value = 0 - end + if stuff.old_selected == stuff.feature_by_id[id] then + stuff.old_selected = nil + end + stuff.feature_by_id[id] = nil - t["table_value"][t.pid] = t["table_value"][t.pid] >= t["table_max"][t.pid] and t["table_max"][t.pid] or t["table_value"][t.pid] <= t["table_min"][t.pid] and t["table_min"][t.pid] or t["table_value"][t.pid] - end - end - elseif k == "data" then - t.real_data = v - else - stuff.rawset(t, k, v) + if feat.thread then + if not menu.has_thread_finished(feat.thread) then + menu.delete_thread(feat.thread) + end + end + if feat.hl_thread then + if not menu.has_thread_finished(feat.hl_thread) then + menu.delete_thread(feat.hl_thread) end end - } - -- featMethods + local parent + if feat.parent_id ~= 0 or bool_ps then + parent = bool_ps and stuff.feature_by_id[feat.ps_parent_id] or stuff.feature_by_id[feat.parent_id] + else + parent = features + end + + if feat.type >> 11 & 1 ~= 0 then + func.deleted_or_hidden_parent_check(feat) + end + + local index = feat.index + if not bool_ps then + stuff.feature_hints[index] = nil + end + table.remove(parent, tonumber(feat.index)) + + --func.check_scroll(index, parent, true) + + for i = index, #parent do + parent[i].index = i + end + + return true + end + + function func.delete_player_feature(id) + if type(id) == "table" then + id = id.id + end + + stuff.player_feature_hints[id] = nil + + local feat = stuff.player_feature_by_id[id] + if not feat then + return false + end + + stuff.player_feature_by_id[id] = nil - -- dogshit dont use - --[[ stuff.set_val = function(self, valueType, val, dont_set_all) - assert(stuff.type_id.id_to_name[self.type]:match("value_[if]") or stuff.type_id.id_to_name[self.type]:match("value_str"), "feat type not supported") - assert(tonumber(val), "tried to set "..valueType.." to a non-number value") - if stuff.type_id.id_to_name[self.type]:match("value_i") then - val = tonumber(math.floor(val)) + local parent + if feat.parent_id ~= 0 then + parent = stuff.player_feature_by_id[feat.parent_id] else - val = tonumber(val) + parent = features["OnlinePlayers"] end - if valueType == "value" then - if self.real_min then - if val < self.real_min then - val = self.real_min - end - else - if val < 0 then - val = 0 - end - end - if self.real_max then - if val > self.real_max then - val = self.real_max - end - elseif self.real_str_data then - if val+1 > #self.real_str_data then - val = #self.real_str_data-1 - end - end + for k, v in pairs(feat.feats) do + func.delete_feature(v.ps_id, true) end - self[valueType] = val - if self["table_"..valueType] and not dont_set_all then - for i = 0, 31 do - self["table_"..valueType][i] = val + local index = feat.index + table.remove(parent, tonumber(index)) + for i = index, #parent do + parent[i].index = i + for pid = 0, 31 do + parent[i].feats[pid].index = i end end end - stuff.set_value = function(self, val, dont_set_all) - stuff.set_val(self, "value", val, dont_set_all) - end - stuff.set_max = function(self, val, dont_set_all) - stuff.set_val(self, "max", val, dont_set_all) - end - stuff.set_min = function(self, val, dont_set_all) - stuff.set_val(self, "min", val, dont_set_all) - end - stuff.set_mod = function(self, val, dont_set_all) - stuff.set_val(self, "mod", val, dont_set_all) - end ]] - - stuff.get_str_data = function(self) - assert(self.type >> 5 & 1 ~= 0, "used get_str_data on a feature that isn't value_str") - return self.str_data + function func.get_player_feature(id) + assert(type(id) == "number" and id ~= 0, "invalid id in get_player_feature") + return stuff.player_feature_by_id[id] end - stuff.set_str_data = function(self, stringTable) - assert(type(stringTable) == "table", "tried to set str_data property to a non-table value") - local numberedTable - for k, v in pairs(stringTable) do - if type(k) ~= "number" then - numberedTable = {} - for k, v in pairs(stringTable) do - numberedTable[#numberedTable + 1] = v - end - break + function func.do_key(time, key, doLoopedFunction, functionToDo) + if cheeseUtils.get_key(key):is_down() then + functionToDo() + local timer = utils.time_ms() + time + while timer > utils.time_ms() and cheeseUtils.get_key(key):is_down() do + system.wait(0) end - end - self.real_str_data = numberedTable or stringTable - if self.real_value+1 > #self.real_str_data then - self.real_value = #self.real_str_data-1 >= 0 and #self.real_str_data-1 or 0 - end - if self.feats then - for k, v in pairs(self.table_value) do - if v+1 > #self.real_str_data then - self.table_value[k] = #self.real_str_data-1 + while timer < utils.time_ms() and cheeseUtils.get_key(key):is_down() do + if doLoopedFunction then + functionToDo() + end + local timer = utils.time_ms() + 50 + while timer > utils.time_ms() do + system.wait(0) end - end - for k, v in pairs(self.feats) do - v.real_str_data = stringTable end end end - stuff.toggle = function(self, bool) - if self.type & 1 ~= 0 then - if bool ~= nil then - self.real_on = bool - self:activate_feat_func() - else - self.real_on = not self.real_on - self:activate_feat_func() + stuff.header_ids = {} + function func.load_sprite(path_to_file, id_table) + --path = path or stuff.path.header + id_table = id_table or stuff.header_ids + path_to_file = tostring(path_to_file) + assert(path_to_file, "invalid name") + + --name = name:gsub("%.[a-z]+$", "") + + if not id_table[path_to_file] then + if utils.dir_exists(path_to_file:gsub("%.ogif", "")) and path_to_file:find("%.ogif") then + local path = path_to_file:gsub("%.ogif", "").."\\" + local images + + for _, v in pairs(stuff.image_ext) do + images = utils.get_all_files_in_directory(path, v) + if images[1] then break end + end + if not images[1] then + menu.notify("No frames found.", "Cheese Menu", 5, 0x0000FF) + return + end + + id_table[path_to_file] = {} + for i, e in pairs(images) do + id_table[path_to_file][i] = {} + id_table[path_to_file][i].sprite = scriptdraw.register_sprite(path..e) + id_table[path_to_file][i].delay = e:match("%d+_(%d+)") + end + + id_table[path_to_file].constant_delay = utils.get_all_files_in_directory(path, "txt")[1] + if not id_table[path_to_file].constant_delay then + for k, v in pairs(images) do + if not v:match("%d+_(%d+)") then + menu.notify("FPS file not found and frames are not in format, create a txt file with the framerate of the gif.\nExample: '25 fps.txt'", "Cheese Menu", 5, 0x0000FF) + break + end + end + else + id_table[path_to_file].constant_delay = math.floor(1000 / tonumber(id_table[path_to_file].constant_delay:match("(%d*%.*%d+)%s+fps"))) + end + + elseif utils.file_exists(path_to_file) then + id_table[path_to_file] = scriptdraw.register_sprite(path_to_file) end - else - self:activate_feat_func() end + + return id_table[path_to_file] end - stuff.get_children = function(self) - local children = {} - for k, v in ipairs(self) do - if type(k) == "number" then - children[k] = v + function func.toggle_menu(bool) + stuff.menuData.menuToggle = bool + if stuff.menuData.menuToggle then + if currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then + currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() end end - return children end - -- function callback ~Thanks to Proddy for telling me that doing function() every time creates a new one and providing examples on how to use menu.create_thread with the function below - function stuff.feature_callback(self) - local pidordata = self.pid or self.data - if self.on ~= nil and self.type & 2049 == 0 then -- not toggle or parent - self.on = true - end - local continue = self:func(pidordata, self.data) - while continue == HANDLER_CONTINUE do - system.wait(0) - continue = self:func(pidordata, self.data) - end - if self.on ~= nil and self.type & 2049 == 0 then -- not toggle or parent - self.on = false + function func.selector(feat) + local originalmenuToggle = stuff.menuData.menuToggle + stuff.menuData.menuToggle = false + if feat.str_data then + local index, _ = cheeseUtils.selector(nil, stuff.menuData.selector_speed, feat.real_value + 1, feat.str_data) + if index then + feat.real_value = index - 1 + end + if feat.type >> 10 & 1 ~= 0 then + feat:activate_feat_func() + end end + func.toggle_menu(originalmenuToggle) end - function stuff.highlight_callback(self) - local pidordata = self.pid or self.data - self:hl_func(pidordata, self.data) + function func.rewrap_hint(hintTable, font, padding) + hintTable.str = cheeseUtils.wrap_text(hintTable.original, font, stuff.menuData.text_size * stuff.menuData.hint_size_modifier, stuff.menuData.width*2-padding) + hintTable.size = scriptdraw.get_text_size(hintTable.str, 1, font) end - stuff.activate_feat_func = function(self) - if not (self.thread) then - self.thread = 0 + function func.rewrap_hints(font) + local padding = scriptdraw.size_pixel_to_rel_x(25) + for _, hintTable in pairs(stuff.feature_hints) do + func.rewrap_hint(hintTable, font, padding) end - if self.func and menu.has_thread_finished(self.thread) then - self.thread = menu.create_thread(stuff.feature_callback, self) + for _, hintTable in pairs(stuff.player_feature_hints) do + func.rewrap_hint(hintTable, font, padding) end end - stuff.activate_hl_func = function(self) - if self.hl_func then - if not self.hl_thread then - self.hl_thread = 0 + function func.save_settings() + gltw.write({ + x = stuff.menuData.pos_x, + y = stuff.menuData.pos_y, + side_window = stuff.menuData.side_window, + controls = stuff.controls, + hotkey_notifications = stuff.hotkey_notifications, + player_submenu_sort = stuff.player_submenu_sort, + selector_speed = stuff.menuData.selector_speed + }, "Settings", stuff.path.cheesemenu) + end + + function func.load_settings() + local settings = gltw.read("Settings", stuff.path.cheesemenu, nil, nil, true) + if settings then + stuff.menuData.pos_x = settings.x + stuff.menuData.pos_y = settings.y + stuff.menuData.selector_speed = settings.selector_speed + stuff.player_submenu_sort = settings.player_submenu_sort + + for k, v in pairs(settings.side_window) do + stuff.menuData.side_window[k] = v end - if menu.has_thread_finished(self.hl_thread) then - self.hl_thread = menu.create_thread(stuff.highlight_callback, self) + for k, v in pairs(settings.hotkey_notifications) do + stuff.hotkey_notifications[k] = v + end + for k, v in pairs(settings.controls) do + stuff.controls[k] = v + end + for k, v in pairs(stuff.controls) do + stuff.vkcontrols[k] = stuff.char_codes[v] end + + menu_configuration_features.menuXfeat.value = math.floor(stuff.menuData.pos_x*graphics.get_screen_width()) + menu_configuration_features.menuYfeat.value = math.floor(stuff.menuData.pos_y*graphics.get_screen_height()) + menu_configuration_features.player_submenu_sort.value = stuff.player_submenu_sort + menu_configuration_features.player_submenu_sort:toggle() + menu_configuration_features.side_window_offsetx.value = math.floor(stuff.menuData.side_window.offset.x*graphics.get_screen_width()) + menu_configuration_features.side_window_offsety.value = math.floor(stuff.menuData.side_window.offset.y*graphics.get_screen_height()) + menu_configuration_features.side_window_spacing.value = math.floor(stuff.menuData.side_window.spacing*graphics.get_screen_height()) + menu_configuration_features.side_window_padding.value = math.floor(stuff.menuData.side_window.padding*graphics.get_screen_width()) + menu_configuration_features.side_window_width.value = math.floor(stuff.menuData.side_window.width*graphics.get_screen_width()) + menu_configuration_features.side_window_on.on = stuff.menuData.side_window.on + menu_configuration_features.selector_speed.value = stuff.menuData.selector_speed end end - stuff.select = function(self) - local parent_of_feat_wanted = stuff.feature_by_id[self.parent_id] or features + function func.save_ui(name) + gltw.write(stuff.menuData, name, stuff.path.ui, {"menuToggle", "menuNav", "loaded_sprites", "files", "pos_x", "pos_y", "side_window", "selector_speed", "chatBoxOpen"}) + end - if not (parent_of_feat_wanted == currentMenu) then - stuff.previousMenus[#stuff.previousMenus + 1] = {menu = currentMenu, scroll = stuff.scroll, drawScroll = stuff.drawScroll, scrollHiddenOffset = stuff.scrollHiddenOffset} - currentMenu = parent_of_feat_wanted + function func.load_ui(name) + local uiTable = gltw.read(name, stuff.path.ui, stuff.menuData, true, true) + if not uiTable then + return end + if menu_configuration_features then + local header, bgSprite = uiTable.header, uiTable.background_sprite and uiTable.background_sprite.sprite or nil + if not header then + menu_configuration_features.headerfeat.value = 0 + menu_configuration_features.headerfeat:toggle() + end + if not bgSprite then + menu_configuration_features.backgroundfeat.value = 0 + menu_configuration_features.backgroundfeat:toggle() + end - if not self.hidden then - local hiddenOffset = 0 - for k, v in ipairs(parent_of_feat_wanted) do - if type(k) == "number" then - if v.hidden and not (k > self.index) then - hiddenOffset = hiddenOffset + 1 + --[[ menu_configuration_features.menuXfeat.value = math.floor(stuff.menuData.pos_x*graphics.get_screen_width()) + menu_configuration_features.menuYfeat.value = math.floor(stuff.menuData.pos_y*graphics.get_screen_height()) ]] + menu_configuration_features.maxfeats.value = math.floor(stuff.menuData.max_features) + menu_configuration_features.menuWidth.value = math.floor(stuff.menuData.width*graphics.get_screen_width()) + menu_configuration_features.featXfeat.value = math.floor(stuff.menuData.feature_scale.x*graphics.get_screen_width()) + menu_configuration_features.featYfeat.value = math.floor(stuff.menuData.feature_scale.y*graphics.get_screen_height()) + menu_configuration_features.feature_offset.value = math.floor(stuff.menuData.feature_offset*graphics.get_screen_height()) + menu_configuration_features.namePadding.value = math.floor(stuff.menuData.padding.name*graphics.get_screen_width()) + menu_configuration_features.parentPadding.value = math.floor(stuff.menuData.padding.parent*graphics.get_screen_width()) + menu_configuration_features.valuePadding.value = math.floor(stuff.menuData.padding.value*graphics.get_screen_width()) + menu_configuration_features.sliderPadding.value = math.floor(stuff.menuData.padding.slider*graphics.get_screen_width()) + menu_configuration_features.sliderWidth.value = math.floor(stuff.menuData.slider.width*graphics.get_screen_width()) + menu_configuration_features.sliderHeight.value = math.floor(stuff.menuData.slider.height*graphics.get_screen_height()) + menu_configuration_features.sliderheightActive.value = math.floor(stuff.menuData.slider.heightActive*graphics.get_screen_height()) + menu_configuration_features.text_size.value = stuff.menuData.text_size_modifier + menu_configuration_features.footer_size.value = stuff.menuData.footer_size_modifier + menu_configuration_features.hint_size.value = stuff.menuData.hint_size_modifier + menu_configuration_features.text_y_offset.value = -math.floor(stuff.menuData.text_y_offset*graphics.get_screen_height()) + stuff.drawFeatParams.textOffset.y = stuff.menuData.text_y_offset + menu_configuration_features.footer_y_offset.value = math.floor(stuff.menuData.footer.footer_y_offset*graphics.get_screen_height()) + menu_configuration_features.border.value = math.floor(stuff.menuData.border*graphics.get_screen_height()) + menu_configuration_features.backgroundsize.value = stuff.menuData.background_sprite.size + menu_configuration_features.backgroundoffsetx.value = math.floor(stuff.menuData.background_sprite.offset.x*graphics.get_screen_width()) + menu_configuration_features.backgroundoffsety.value = math.floor(stuff.menuData.background_sprite.offset.y*graphics.get_screen_height()) + menu_configuration_features.footer_size.value = math.floor(stuff.menuData.footer.footer_size*graphics.get_screen_height()) + menu_configuration_features.footerPadding.value = math.floor(stuff.menuData.footer.padding*graphics.get_screen_width()) + menu_configuration_features.draw_footer.on = stuff.menuData.footer.draw_footer + menu_configuration_features.footer_pos_related_to_background.on = stuff.menuData.footer.footer_pos_related_to_background + --[[ menu_configuration_features.side_window_offsetx.value = math.floor(stuff.menuData.side_window.offset.x*graphics.get_screen_width()) + menu_configuration_features.side_window_offsety.value = math.floor(stuff.menuData.side_window.offset.y*graphics.get_screen_height()) + menu_configuration_features.side_window_spacing.value = math.floor(stuff.menuData.side_window.spacing*graphics.get_screen_height()) + menu_configuration_features.side_window_padding.value = math.floor(stuff.menuData.side_window.padding*graphics.get_screen_width()) + menu_configuration_features.side_window_width.value = math.floor(stuff.menuData.side_window.width*graphics.get_screen_width()) + menu_configuration_features.side_window_on.on = stuff.menuData.side_window.on ]] + menu_configuration_features.text_font.value = stuff.menuData.fonts.text + menu_configuration_features.footer_font.value = stuff.menuData.fonts.footer + menu_configuration_features.hint_font.value = stuff.menuData.fonts.hint + + menu_configuration_features.hint_font:toggle() + + for k, v in pairs(stuff.menuData.color) do + if menu_configuration_features[k] then + if type(v) == "table" then + menu_configuration_features[k].r.value = v.r + menu_configuration_features[k].g.value = v.g + menu_configuration_features[k].b.value = v.b + menu_configuration_features[k].a.value = v.a + else + menu_configuration_features[k].r.value = func.convert_int_to_rgba(v, "r") + menu_configuration_features[k].g.value = func.convert_int_to_rgba(v, "g") + menu_configuration_features[k].b.value = func.convert_int_to_rgba(v, "b") + menu_configuration_features[k].a.value = func.convert_int_to_rgba(v, "a") end end end - stuff.scroll = self.index - hiddenOffset - stuff.drawScroll = (stuff.maxDrawScroll >= self.index) and self.index-1 or stuff.maxDrawScroll - end - stuff.scrollHiddenOffset = 0 - end - -- + for k, v in pairs(menu_configuration_features.headerfeat.str_data) do + if v == stuff.menuData.header then + menu_configuration_features.headerfeat.value = k - 1 + end + end - stuff.hotkey_feature_hierarchy_keys = {} + if uiTable.background_sprite then + for k, v in pairs(menu_configuration_features.backgroundfeat.str_data) do + if v == uiTable.background_sprite.sprite then + menu_configuration_features.backgroundfeat.value = k - 1 + end + end + end + end + end - stuff.type_id = { - name_to_id = { - toggle = 1 << 0, - slider = 1 << 2 | 1 << 1 | 1 << 0, - value_i = 1 << 3 | 1 << 1 | 1 << 0, - value_str = 1 << 5 | 1 << 1 | 1 << 0, - value_f = 1 << 7 | 1 << 1 | 1 << 0, - action = 1 << 9, - action_slider = 1 << 9 | 1 << 2 | 1 << 1, - action_value_i = 1 << 9 | 1 << 3 | 1 << 1, - action_value_str = 1 << 9 | 1 << 5 | 1 << 1, - action_value_f = 1 << 9 | 1 << 7 | 1 << 1, - autoaction_slider = 1 << 10 | 1 << 2 | 1 << 1, - autoaction_value_i = 1 << 10 | 1 << 3 | 1 << 1, - autoaction_value_str = 1 << 10 | 1 << 5 | 1 << 1, - autoaction_value_f = 1 << 10 | 1 << 7 | 1 << 1, - parent = 1 << 11 - }, + stuff.drawFeatParams = { + rectPos = v2(stuff.menuData.pos_x, stuff.menuData.pos_y - stuff.menuData.feature_offset/2 + stuff.menuData.border), + textOffset = v2(stuff.menuData.feature_scale.x/2, -0.0055555555), + colorText = stuff.menuData.color.text, + textSize = 0, } + function func.draw_feat(k, v, offset, hiddenOffset) + --[[ stuff.drawFeatParams.rectPos.x = stuff.menuData.pos_x + stuff.drawFeatParams.rectPos.y = stuff.menuData.pos_y - stuff.menuData.feature_offset/2 + stuff.menuData.border + stuff.drawFeatParams.textOffset.x = stuff.menuData.feature_scale.x/2 + stuff.drawFeatParams.textSize = textSize ]] + stuff.drawFeatParams.colorText = stuff.menuData.color.text + stuff.drawFeatParams.bottomLeft = stuff.menuData.color.feature_bottomLeft + stuff.drawFeatParams.topLeft = stuff.menuData.color.feature_topLeft + stuff.drawFeatParams.topRight = stuff.menuData.color.feature_topRight + stuff.drawFeatParams.bottomRight = stuff.menuData.color.feature_bottomRight + local posY = (stuff.drawFeatParams.rectPos.y + (stuff.menuData.feature_offset * k))*-2+1 - --Functions - function func.add_feature(nameOfFeat, TypeOfFeat, parentOfFeat, functionCallback, highlightCallback, playerFeat) - assert((type(nameOfFeat) == "string"), "invalid name in add_feature") - assert((type(TypeOfFeat) == "string") and stuff.type_id.name_to_id[TypeOfFeat], "invalid type in add_feature") - assert((type(parentOfFeat) == "number") or not parentOfFeat, "invalid parent id in add_feature") - assert((type(functionCallback) == "function") or not functionCallback, "invalid function in add_feature") - playerFeat = playerFeat or false - parentOfFeat = parentOfFeat or 0 - --TypeOfFeat = TypeOfFeat:gsub("slider", "value_f") - local currentParent = playerFeat and features["OnlinePlayers"] or features - - local hierarchy_key - if parentOfFeat ~= 0 and parentOfFeat then - currentParent = playerFeat and stuff.player_feature_by_id[parentOfFeat] or stuff.feature_by_id[parentOfFeat] - if currentParent then - assert(currentParent.type >> 11 & 1 ~= 0, "parent is not a parent feature") - assert(currentParent.type >> 15 & 1 ~= 0 == playerFeat, "parent is not valid "..((currentParent.type >> 15 & 1 ~= 0 and not playerFeat) and "using player feature as parent for a local feature" or (currentParent.type >> 15 & 1 == 0 and playerFeat and "using local parent for player feature") or "unknown")) - else - error("parent does not exist") - end + local is_selected + if stuff.scroll == k + stuff.drawScroll then + stuff.scrollHiddenOffset = hiddenOffset or stuff.scrollHiddenOffset + stuff.drawFeatParams.colorText = stuff.menuData.color.text_selected + stuff.drawFeatParams.bottomLeft = stuff.menuData.color.feature_selected_bottomLeft + stuff.drawFeatParams.topLeft = stuff.menuData.color.feature_selected_topLeft + stuff.drawFeatParams.topRight = stuff.menuData.color.feature_selected_topRight + stuff.drawFeatParams.bottomRight = stuff.menuData.color.feature_selected_bottomRight + is_selected = true end - if currentParent.hierarchy_key then - hierarchy_key = currentParent.hierarchy_key.."."..nameOfFeat:gsub("[ %.]", "_") - else - hierarchy_key = nameOfFeat:gsub("[ %.]", "_") + if offset == 0 then + local memv2 = cheeseUtils.memoize.v2 + local posX = stuff.drawFeatParams.rectPos.x*2-1 + --[[ scriptdraw.draw_rect( + cheeseUtils.memoize.v2(posX, posY), + cheeseUtils.memoize.v2(stuff.menuData.feature_scale.x*2, stuff.menuData.feature_scale.y*2), + func.convert_rgba_to_int(stuff.drawFeatParams.colorFeature.r, stuff.drawFeatParams.colorFeature.g, stuff.drawFeatParams.colorFeature.b, stuff.drawFeatParams.colorFeature.a) + ) ]] + local Left = posX - stuff.menuData.feature_scale.x + local Right = posX + stuff.menuData.feature_scale.x + local Top = posY + stuff.menuData.feature_scale.y + local Bottom = posY - stuff.menuData.feature_scale.y + scriptdraw.draw_rect_ext( + memv2(Left, Bottom), + memv2(Left, Top), + memv2(Right, Top), + memv2(Right, Bottom), + func.convert_rgba_to_int(stuff.drawFeatParams.bottomLeft.r, stuff.drawFeatParams.bottomLeft.g, stuff.drawFeatParams.bottomLeft.b, stuff.drawFeatParams.bottomLeft.a), + func.convert_rgba_to_int(stuff.drawFeatParams.topLeft.r, stuff.drawFeatParams.topLeft.g, stuff.drawFeatParams.topLeft.b, stuff.drawFeatParams.topLeft.a), + func.convert_rgba_to_int(stuff.drawFeatParams.topRight.r, stuff.drawFeatParams.topRight.g, stuff.drawFeatParams.topRight.b, stuff.drawFeatParams.topRight.a), + func.convert_rgba_to_int(stuff.drawFeatParams.bottomRight.r, stuff.drawFeatParams.bottomRight.g, stuff.drawFeatParams.bottomRight.b, stuff.drawFeatParams.bottomRight.a) + ) end - currentParent[#currentParent + 1] = {name = nameOfFeat, real_type = stuff.type_id.name_to_id[TypeOfFeat] | (playerFeat and 1 << 15 or 0), real_id = 0, --[[parent = {id = currentParent.id or 0},]] parent_id = currentParent.id or 0, playerFeat = playerFeat, index = #currentParent + 1} - local feat = currentParent[#currentParent] - feat.activate_feat_func = stuff.activate_feat_func - feat.activate_hl_func = stuff.activate_hl_func - feat.set_str_data = stuff.set_str_data - feat.toggle = stuff.toggle - feat.get_children = stuff.get_children - feat.get_str_data = stuff.get_str_data - feat.select = stuff.select - setmetatable(feat, stuff.featMetaTable) - feat.thread = 0 - --if feat.real_type & 1 ~= 0 or feat.real_type >> 9 & 1 ~= 0 then -- toggle - if playerFeat then - feat.table_on = {} - for i = 0, 31 do - feat.table_on[i] = feat.type >> 11 & 1 ~= 0 - end + local font = stuff.menuData.fonts.text + if v.type & 1 == 0 then + scriptdraw.draw_text( + v["name"], + cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x - (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.name))*2-1, (stuff.drawFeatParams.rectPos.y + stuff.drawFeatParams.textOffset.y + (stuff.menuData.feature_offset * k))*-2+1), + cheeseUtils.memoize.v2(10, 10), + stuff.drawFeatParams.textSize, + func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a), + 0, font + ) + if v.type >> 11 & 1 ~= 0 then + scriptdraw.draw_text( + ">>", + cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x + (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.parent))*2-1, (stuff.drawFeatParams.rectPos.y + stuff.drawFeatParams.textOffset.y + (stuff.menuData.feature_offset * k))*-2+1), + cheeseUtils.memoize.v2(10, 10), + stuff.drawFeatParams.textSize, + func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a), + 16, font + ) end - feat.on = feat.type >> 11 & 1 ~= 0 - --end - if feat.real_type >> 5 & 1 ~= 0 then -- value_str - feat.real_str_data = {} - if playerFeat then - feat.table_value = {} - for i = 0, 31 do - feat.table_value[i] = 0 - end + elseif v.type & 1 ~= 0 then -- toggle + cheeseUtils.draw_outline( + cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x - (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.name) + 0.00390625)*2-1, posY), + cheeseUtils.memoize.v2(0.015625, 0.0277777777778), + func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a), + 2 + ) + if v.real_on then + scriptdraw.draw_rect( + cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x - (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.name) + 0.00390625)*2-1, posY), + cheeseUtils.memoize.v2(0.0140625, 0.025), + func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a) + ) + end + + scriptdraw.draw_text( + v.name, + cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x - (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.name) + 0.011328125)*2-1, (stuff.drawFeatParams.rectPos.y + stuff.drawFeatParams.textOffset.y + (stuff.menuData.feature_offset * k))*-2+1), + cheeseUtils.memoize.v2(10, 10), + stuff.drawFeatParams.textSize, + func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a), + 0, font + ) + end + + if v.type >> 1 & 1 ~= 0 then -- value_i_f_str + local rounded_value = v.str_data and v.str_data[v.real_value + 1] or v.real_value + if v.type >> 7 & 1 ~= 0 or v.type >> 2 & 1 ~= 0 then + rounded_value = (rounded_value * 10000) + 0.5 + rounded_value = math.floor(rounded_value) + rounded_value = rounded_value / 10000 end - feat.value = 0 - elseif feat.real_type >> 1 & 1 ~= 0 then --value any - if playerFeat then - feat.table_max = {} - feat.table_min = {} - feat.table_mod = {} - feat.table_value = {} - for i = 0, 31 do - feat.table_max[i] = 0 - feat.table_min[i] = 0 - feat.table_mod[i] = 1 - feat.table_value[i] = 0 + if v.type >> 2 & 1 ~= 0 then + cheeseUtils.draw_slider( + cheeseUtils.memoize.v2( + (stuff.drawFeatParams.rectPos.x + stuff.menuData.feature_scale.x/2 - stuff.menuData.slider.width/4 - stuff.menuData.padding.slider)*2-1, + posY + ), + cheeseUtils.memoize.v2(stuff.menuData.slider.width, is_selected and stuff.menuData.slider.heightActive or stuff.menuData.slider.height), + v.min, v.max, v.value, + is_selected and func.convert_rgba_to_int(stuff.menuData.color.slider_selectedBackground) or func.convert_rgba_to_int(stuff.menuData.color.slider_background), + is_selected and func.convert_rgba_to_int(stuff.menuData.color.slider_selectedActive) or func.convert_rgba_to_int(stuff.menuData.color.slider_active), + is_selected and func.convert_rgba_to_int(stuff.menuData.color.slider_text) or 0, + is_selected) + else + local value_str = "< "..tostring(rounded_value).." >" + if v.str_data then + local pixel_size = scriptdraw.get_text_size(value_str, 1, font).x + local screenWidth = graphics.get_screen_width() + if pixel_size/screenWidth > 370/screenWidth then + local original_size = stuff.drawFeatParams.textSize + stuff.drawFeatParams.textSize = stuff.drawFeatParams.textSize * (370 / pixel_size * 0.8) + stuff.drawFeatParams.textSize = math.min(stuff.drawFeatParams.textSize + 0.2, original_size) + end end + + scriptdraw.draw_text( + value_str, + cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x + (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.value) - scriptdraw.size_pixel_to_rel_x(scriptdraw.get_text_size(value_str, stuff.drawFeatParams.textSize, font).x)/4)*2-1, (stuff.drawFeatParams.rectPos.y + stuff.drawFeatParams.textOffset.y + (stuff.menuData.feature_offset * k))*-2+1), + cheeseUtils.memoize.v2(10, 10), + stuff.drawFeatParams.textSize, + func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a), + 0, font + ) end - feat.max = 0 - feat.min = 0 - feat.mod = 1 - feat.value = 0 end - feat.hidden = false - feat["func"] = functionCallback - feat["hl_func"] = highlightCallback - if TypeOfFeat == "parent" then - feat.child_count = 0 + end + + stuff.draw_current_menu = {frameCounter = 1, time = utils.time_ms() + 33, currentSprite = stuff.menuData.header} + function func.draw_current_menu() + local sprite = func.load_sprite(stuff.path.header..(stuff.menuData.header or "")) + if stuff.draw_current_menu.currentSprite ~= stuff.menuData.header then + stuff.draw_current_menu.currentSprite = stuff.menuData.header + stuff.draw_current_menu.time = 0 + stuff.draw_current_menu.frameCounter = 1 + if type(sprite) == "table" then + stuff.draw_current_menu.time = utils.time_ms() + (sprite[stuff.draw_current_menu.frameCounter].delay or sprite.constant_delay or 33) + end end - currentParent.child_count = 0 - for k, v in pairs(currentParent) do + stuff.drawHiddenOffset = 0 + for k, v in pairs(currentMenu) do if type(k) == "number" then - currentParent.child_count = currentParent.child_count + 1 + if v.hidden or (v.type >> 11 & 1 ~= 0 and not v.on) then + stuff.drawHiddenOffset = stuff.drawHiddenOffset + 1 + end end end - feat.hotkey = stuff.hierarchy_key_to_hotkey[hierarchy_key] - feat.hierarchy_key = hierarchy_key - if stuff.hotkey_feature_hierarchy_keys[hierarchy_key] then - stuff.hotkey_feature_hierarchy_keys[hierarchy_key][#stuff.hotkey_feature_hierarchy_keys[hierarchy_key] + 1] = feat - else - stuff.hotkey_feature_hierarchy_keys[hierarchy_key] = {feat} + local background_sprite_path = stuff.path.background..(stuff.menuData.background_sprite.sprite or "") + if stuff.menuData.background_sprite.sprite and func.load_sprite(background_sprite_path) then + scriptdraw.draw_sprite( + func.load_sprite(background_sprite_path), + cheeseUtils.memoize.v2((stuff.menuData.pos_x + stuff.menuData.background_sprite.offset.x)*2-1, (stuff.menuData.pos_y+stuff.menuData.background_sprite.offset.y+stuff.menuData.height/2+0.01458)*-2+1), + stuff.menuData.background_sprite.size, + 0, + func.convert_rgba_to_int(255, 255, 255, stuff.menuData.color.background.a) + ) + else + scriptdraw.draw_rect( + cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, (stuff.menuData.pos_y+stuff.menuData.border+stuff.menuData.height/2)*-2+1), + cheeseUtils.memoize.v2(stuff.menuData.width*2, stuff.menuData.height*2), + func.convert_rgba_to_int(stuff.menuData.color.background.r, stuff.menuData.color.background.g, stuff.menuData.color.background.b, stuff.menuData.color.background.a) + ) end - if playerFeat then - stuff.player_feature_by_id[#stuff.player_feature_by_id+1] = feat - feat.real_id = #stuff.player_feature_by_id + if #currentMenu - stuff.drawHiddenOffset >= stuff.menuData.max_features then + stuff.maxDrawScroll = #currentMenu - stuff.drawHiddenOffset - stuff.menuData.max_features else - stuff.feature_by_id[#stuff.feature_by_id+1] = feat - feat.real_id = #stuff.feature_by_id + stuff.maxDrawScroll = 0 + end + if stuff.drawScroll > stuff.maxDrawScroll then + stuff.drawScroll = stuff.maxDrawScroll + end + if stuff.scroll > #currentMenu - stuff.drawHiddenOffset then + stuff.scroll = #currentMenu - stuff.drawHiddenOffset + elseif stuff.scroll < 1 and #currentMenu > 0 then + stuff.scroll = 1 end - return feat - end - --player feature functions + -- header border + scriptdraw.draw_rect(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, (stuff.menuData.pos_y + stuff.menuData.border/2)*-2+1), cheeseUtils.memoize.v2(stuff.menuData.width*2, stuff.menuData.border*2), func.convert_rgba_to_int(stuff.menuData.color.border.r, stuff.menuData.color.border.g, stuff.menuData.color.border.b, stuff.menuData.color.border.a)) - -- if you set a toggle player feature to on it'll enable for any valid players/joining players but if a player leaves functions like player.get_player_name will return nil before the feature is turned off - function func.add_player_feature(nameOfFeat, TypeOfFeat, parentOfFeat, functionCallback, highlightCallback) - parentOfFeat = parentOfFeat or 0 - assert(stuff.PlayerParent, "you need to use set_player_feat_parent before adding player features") - local pfeat = func.add_feature(nameOfFeat, TypeOfFeat, parentOfFeat, functionCallback, highlightCallback, true) - pfeat.feats = {} + local hiddenOffset = 0 + local drawnfeats = 0 + stuff.menuData.text_size = (((graphics.get_screen_width()*graphics.get_screen_height())/3686400)*0.45+0.25) -- * stuff.menuData.text_size_modifier - if parentOfFeat == 0 then - for k = 0, 31 do - stuff.playerIds[k][#stuff.playerIds[k]+1] = {} - local currentFeat = stuff.playerIds[k][#stuff.playerIds[k]] - func.add_to_table(pfeat, currentFeat, k, nil, true) - stuff.feature_by_id[#stuff.feature_by_id+1] = currentFeat - currentFeat.ps_id = #stuff.feature_by_id - currentFeat.ps_parent_id = stuff.playerIds[k].id - currentFeat.pid = k - pfeat.feats[k] = currentFeat - end - else - local playerParent = stuff.player_feature_by_id[parentOfFeat] - if playerParent then - for k = 0, 31 do - playerParent.feats[k][#playerParent.feats[k]+1] = {} - local currentFeat = playerParent.feats[k][#playerParent.feats[k]] + stuff.drawFeatParams.rectPos.x = stuff.menuData.pos_x + stuff.drawFeatParams.rectPos.y = stuff.menuData.pos_y - stuff.menuData.feature_offset/2 + stuff.menuData.border + stuff.drawFeatParams.textOffset.x = stuff.menuData.feature_scale.x/2 + stuff.drawFeatParams.colorText = stuff.menuData.color.text + stuff.drawFeatParams.colorFeature = stuff.menuData.color.feature + stuff.drawFeatParams.textSize = stuff.menuData.text_size * stuff.menuData.text_size_modifier - func.add_to_table(pfeat, currentFeat, k, nil, true) - stuff.feature_by_id[#stuff.feature_by_id+1] = currentFeat - currentFeat.ps_id = #stuff.feature_by_id - currentFeat.ps_parent_id = playerParent.feats[k].ps_id - currentFeat.pid = k - pfeat.feats[k] = currentFeat + for k, v in ipairs(currentMenu) do + if type(k) == "number" then + if v.hidden or (v.type >> 11 & 1 ~= 0 and not v.on) then + hiddenOffset = hiddenOffset + 1 + elseif k <= stuff.drawScroll + hiddenOffset + stuff.menuData.max_features and k >= stuff.drawScroll + hiddenOffset + 1 then + func.draw_feat(k - stuff.drawScroll - hiddenOffset, v, 0, hiddenOffset) + drawnfeats = drawnfeats + 1 end end end - return pfeat - end + if stuff.menuData.footer.draw_footer then + -- footer border + local footer_border_y_pos + if stuff.menuData.footer.footer_pos_related_to_background then + footer_border_y_pos = (stuff.menuData.pos_y + stuff.menuData.height + stuff.menuData.border*1.5)*-2+1 + else + footer_border_y_pos = (stuff.menuData.pos_y + (drawnfeats*stuff.menuData.feature_offset) + stuff.menuData.border*1.5)*-2+1 + end + scriptdraw.draw_rect(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, footer_border_y_pos), cheeseUtils.memoize.v2(stuff.menuData.width*2, stuff.menuData.border*2), func.convert_rgba_to_int(stuff.menuData.color.border.r, stuff.menuData.color.border.g, stuff.menuData.color.border.b, stuff.menuData.color.border.a)) - function func.add_to_table(getTable, addToTable, playerid, override, setmeta) - local isPlayerFeatValues - for k, v in pairs(getTable) do - if tostring(k):match("table_") or stuff.playerSpecialValues[k] then - isPlayerFeatValues = true - elseif type(v) == "table" then - if type(addToTable[k]) ~= "table" then - addToTable[k] = {} - end - if addToTable[k].real_on then - addToTable[k].real_on = false - end - if (v.type or 0) >> 11 & 1 ~= 0 then - func.add_to_table(getTable[k], addToTable[k], playerid, override) + -- footer and text/scroll + local footerColor = func.convert_rgba_to_int(stuff.menuData.color.footer.r, stuff.menuData.color.footer.g, stuff.menuData.color.footer.b, stuff.menuData.color.footer.a) + local footer_y_pos + if stuff.menuData.footer.footer_pos_related_to_background then + footer_y_pos = (stuff.menuData.pos_y + stuff.menuData.height + stuff.menuData.border*2 + stuff.menuData.footer.footer_size/2)*-2+1 + else + footer_y_pos = (stuff.menuData.pos_y + (drawnfeats*stuff.menuData.feature_offset) + stuff.menuData.border*2 + stuff.menuData.footer.footer_size/2)*-2+1 + end + scriptdraw.draw_rect(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, footer_y_pos), cheeseUtils.memoize.v2(stuff.menuData.width*2, stuff.menuData.footer.footer_size*2), footerColor) + + local footerTextColor = func.convert_rgba_to_int(stuff.menuData.color.footer_text.r, stuff.menuData.color.footer_text.g, stuff.menuData.color.footer_text.b, stuff.menuData.color.footer_text.a) + local feat = currentMenu[stuff.scroll + stuff.scrollHiddenOffset] + local featHint = feat.type >> 15 & 1 ~= 0 and stuff.player_feature_hints[feat.id] or stuff.feature_hints[feat.id] + if featHint then + local padding = scriptdraw.size_pixel_to_rel_y(5) + local hintStrSize = scriptdraw.size_pixel_to_rel_y(featHint.size.y) * (stuff.menuData.text_size * stuff.menuData.hint_size_modifier) + local posY = footer_y_pos - stuff.menuData.border*2 - stuff.menuData.footer.footer_size - padding + local textY = posY - padding + posY = posY - hintStrSize/2 + + local rectHeight = hintStrSize+padding*4 + --scriptdraw.draw_rect(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, posY+rectHalfHeight/2), cheeseUtils.memoize.v2(stuff.menuData.width*2, rectHalfHeight), func.convert_rgba_to_int(stuff.menuData.color.footer.r, stuff.menuData.color.footer.g, stuff.menuData.color.footer.b, stuff.menuData.color.footer.a)) + cheeseUtils.draw_rect_ext_wh(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, posY-padding), cheeseUtils.memoize.v2(stuff.menuData.width*2, rectHeight), (footerColor & 0xffffff) | 50 << 24, footerColor, footerColor, (footerColor & 0xffffff) | 50 << 24) + scriptdraw.draw_text( + featHint.str, + cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1 - stuff.menuData.width + padding, textY), + cheeseUtils.memoize.v2(stuff.menuData.width+padding*2, 2), + stuff.menuData.text_size * stuff.menuData.hint_size_modifier, + footerTextColor, + 0, + stuff.menuData.fonts.hint + ) + end + + local footer_size = stuff.menuData.text_size * stuff.menuData.footer_size_modifier + local text_y_pos = footer_y_pos + 0.011111111 + stuff.menuData.footer.footer_y_offset + scriptdraw.draw_text( + tostring(stuff.menuData.footer.footer_text), + cheeseUtils.memoize.v2((stuff.menuData.pos_x - stuff.menuData.width/2 + stuff.menuData.footer.padding)*2-1, text_y_pos), + cheeseUtils.memoize.v2(2, 2), + footer_size, + footerTextColor, + 0, + stuff.menuData.fonts.footer + ) + + scriptdraw.draw_text( + tostring(stuff.scroll.." / "..(#currentMenu - stuff.drawHiddenOffset)), + cheeseUtils.memoize.v2((stuff.menuData.pos_x + stuff.menuData.width/2 - stuff.menuData.footer.padding)*2-1, text_y_pos), + cheeseUtils.memoize.v2(2, 2), + footer_size, + footerTextColor, + 16, + stuff.menuData.fonts.footer + ) + end + + if type(sprite) == "table" then + if not sprite[stuff.draw_current_menu.frameCounter] then + stuff.draw_current_menu.frameCounter = 1 + end + if utils.time_ms() > stuff.draw_current_menu.time then + if stuff.draw_current_menu.frameCounter < #sprite then + stuff.draw_current_menu.frameCounter = stuff.draw_current_menu.frameCounter + 1 else - for i, e in pairs(getTable[k]) do - if type(e) ~= "table" then - if not addToTable[k][i] or override then - addToTable[k][i] = e - end - end - end - end - setmetatable(addToTable[k], stuff.playerfeatMetaTable) - if v.name then - if not getTable[k].feats then - getTable[k].feats = {} - end - getTable[k].feats[playerid] = addToTable[k] - end - else - if not addToTable[k] or override then - addToTable[k] = v + stuff.draw_current_menu.frameCounter = 1 end + stuff.draw_current_menu.time = utils.time_ms() + (sprite[stuff.draw_current_menu.frameCounter].delay or sprite.constant_delay or 33) end + sprite = sprite[stuff.draw_current_menu.frameCounter].sprite end - if setmeta or isPlayerFeatValues then - addToTable.table_value = getTable.table_value - addToTable.table_min = getTable.table_min - addToTable.table_max = getTable.table_max - addToTable.table_mod = getTable.table_mod - addToTable.table_on = getTable.table_on - for i, e in pairs(stuff.playerSpecialValues) do - if addToTable[i] then - stuff.rawset(addToTable, i, nil) - end - end - setmetatable(addToTable, stuff.playerfeatMetaTable) + if sprite then + local size = ((2.56 * stuff.menuData.width) * (1000 / scriptdraw.get_sprite_size(sprite).x)) / (2560 / graphics.get_screen_width()) + scriptdraw.draw_sprite(sprite, cheeseUtils.memoize.v2(stuff.menuData.pos_x * 2 - 1, ((stuff.menuData.pos_y+stuff.menuData.height/2) - (stuff.menuData.height/2 + ((scriptdraw.get_sprite_size(sprite).y*size)/2)/graphics.get_screen_height()))*-2+1), size, 0, stuff.menuData.color.sprite) end + system.wait(0) end - function func.set_player_feat_parent(nameOfFeat, parentOfFeat, functionToDo) - stuff.PlayerParent = func.add_feature(nameOfFeat, "parent", parentOfFeat, functionToDo) - local hierarchy_pattern = stuff.PlayerParent.hierarchy_key..".player_" + --[[ + example of table_of_lines: + { + {"leftside", "rightside"}, + {"IP", "ddosing u rn"}, + {"Cheesus", "Christ"} + } + has to be in this structure, you can add more than three + ]] + function func.draw_side_window(header_text, table_of_lines, v2pos, rect_color, rect_width, text_spacing, text_padding, text_color) + text_color = text_color or 0xFFFFFFFF + assert( + type(header_text) == "string" + and type(table_of_lines) == "table" + and type(v2pos) == "userdata" + and type(rect_color) == "number" + and type(rect_width) == "number" + and type(text_spacing) == "number" + and type(text_padding) == "number" + and type(text_color) == "number", + "one or more draw_side_window args were invalid" + ) + local rect_height = #table_of_lines*text_spacing+0.07125 + v2pos.y = v2pos.y-(rect_height/2) - stuff.playerIds = {} - for i = 0, 31 do - stuff.playerIds[i] = func.add_feature(tostring(player.get_player_name(i)), "parent", stuff.PlayerParent.id) - stuff.playerIds[i].pid = i - stuff.playerIds[i].hidden = not player.is_player_valid(i) - stuff.playerIds[i].hierarchy_key = hierarchy_pattern..i - stuff.playerIds[i].real_type = 1 << 15 | stuff.playerIds[i].type - end - event.add_event_listener("player_join", function(listener) - system.wait(100) - stuff.playerIds[listener.player].hidden = false - stuff.playerIds[listener.player].name = player.get_player_name(listener.player) - func.reset_player_submenu(listener.player) - table.sort(stuff.PlayerParent, stuff.table_sort_functions[stuff.player_submenu_sort]) - end) - event.add_event_listener("player_leave", function(listener) - func.reset_player_submenu(listener.player) - if not player.is_player_valid(listener.player) then - stuff.playerIds[listener.player].hidden = true - stuff.playerIds[listener.player].name = "nil" - end - table.sort(stuff.PlayerParent, stuff.table_sort_functions[stuff.player_submenu_sort]) - end) + scriptdraw.draw_rect(v2pos, cheeseUtils.memoize.v2(rect_width, rect_height), rect_color) - return stuff.PlayerParent + local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 + -- Header text + scriptdraw.draw_text(header_text, cheeseUtils.memoize.v2(v2pos.x - scriptdraw.get_text_size(header_text, text_size, 0).x/graphics.get_screen_width(), v2pos.y+(rect_height/2)-0.015), cheeseUtils.memoize.v2(2, 2), text_size, text_color, 0, 0) + -- table_of_lines + for k, v in ipairs(table_of_lines) do + v[1] = tostring(v[1]) + v[2] = tostring(v[2]) + local pos_y = v2pos.y-k*text_spacing+rect_height/2-0.03 + scriptdraw.draw_text(v[1], cheeseUtils.memoize.v2(v2pos.x-rect_width/2+text_padding, pos_y), cheeseUtils.memoize.v2(2, 2), text_size, text_color, 0, 2) + scriptdraw.draw_text(v[2], cheeseUtils.memoize.v2(v2pos.x+rect_width/2-text_padding, pos_y), cheeseUtils.memoize.v2(2, 2), text_size, text_color, 16, 2) + end end - function func.reset_player_submenu(pid, currentParent) - local currentParent = currentParent or features.OnlinePlayers - for k, v in pairs(currentParent) do - if type(v) == "table" then - local feat_type = v.type - if feat_type then - if feat_type >> 1 & 1 ~= 0 then -- toggle - v.table_value[pid] = v.real_value - if feat_type & 136 ~= 0 then -- value if - v.table_min[pid] = v.real_min - v.table_max[pid] = v.real_max - v.table_mod[pid] = v.real_mod + --Hotkey functions + function func.get_hotkey(keyTable, vkTable, singlekey) + local current_key + local excludedkeys = {} + while not keyTable[1] do + if cheeseUtils.get_key(0x1B):is_down() then + return "escaped" + end + for k, v in pairs(stuff.char_codes) do + if cheeseUtils.get_key(v):is_down() then + if v ~= 0x0D or singlekey then + if v ~= 0xA0 and v ~= 0xA1 and v ~= 0xA2 and v ~= 0xA3 and v ~= 0xA4 and v ~= 0xA5 and not singlekey then + keyTable[1] = "NOMOD" end - end - if feat_type & 1 ~= 0 then -- toggle - if player.is_player_valid(pid) then - v.feats[pid].on = v.real_on + if singlekey then + return k, v else - v.feats[pid].on = false - v.table_on[pid] = false + keyTable[#keyTable + 1] = k + vkTable[#vkTable+1] = v + current_key = v + excludedkeys[v] = true end end - if feat_type >> 11 & 1 ~= 0 then -- parent - func.reset_player_submenu(pid, v) - end end end + system.wait(0) end - end - --end of player feature functions - function func.check_scroll(index, parent, bool) - if index <= stuff.scroll + stuff.scrollHiddenOffset and currentMenu == parent then - if bool then - --stuff.scroll = stuff.scroll - 1 - --stuff.scroll = stuff.scroll > 0 and stuff.scroll or 0 - if #currentMenu - stuff.drawHiddenOffset > 1 and stuff.scroll - 1 > 0 then - stuff.scroll = stuff.scroll - 1 - if stuff.scroll - stuff.drawScroll <= 2 and stuff.drawScroll > 0 then - stuff.drawScroll = stuff.drawScroll - 1 - end - end - else - if #currentMenu - stuff.drawHiddenOffset > 1 then - stuff.scroll = stuff.scroll + 1 - if stuff.scroll - stuff.drawScroll >= (stuff.menuData.max_features - 1) and stuff.drawScroll < stuff.maxDrawScroll then - stuff.drawScroll = stuff.drawScroll + 1 + if not singlekey then + while cheeseUtils.get_key(current_key):is_down() do + for k, v in pairs(stuff.char_codes) do + if cheeseUtils.get_key(v):is_down() and not excludedkeys[v] and v ~= 0xA0 and v ~= 0xA1 and v ~= 0xA2 and v ~= 0xA3 and v ~= 0xA4 and v ~= 0xA5 then + excludedkeys[v] = true + keyTable[#keyTable + 1] = k + vkTable[#vkTable+1] = v end end - --stuff.scroll = stuff.scroll + 1 + system.wait(0) end - end - end - function func.deleted_or_hidden_parent_check(parent, check_hidden_only) - if next(stuff.previousMenus) then - local parentBeforeDHparent = false - if parent ~= currentMenu then - for k, v in ipairs(stuff.previousMenus) do - if parentBeforeDHparent then - stuff.previousMenus[k] = nil - else - if (v.menu == parent and not check_hidden_only) or (v.menu.hidden and check_hidden_only) then - parentBeforeDHparent = true - currentMenu = stuff.previousMenus[k-1].menu - stuff.scroll = stuff.previousMenus[k-1].scroll - stuff.drawScroll = stuff.previousMenus[k-1].drawScroll - stuff.scrollHiddenOffset = stuff.previousMenus[k-1].scrollHiddenOffset - stuff.previousMenus[k-1] = nil - stuff.previousMenus[k] = nil - end + while not cheeseUtils.get_key(0x1B):is_down() and not cheeseUtils.get_key(0x0D):is_down() do + for k, v in pairs(stuff.char_codes) do + if cheeseUtils.get_key(v):is_down() then + return false end end - elseif not check_hidden_only then - currentMenu = stuff.previousMenus[#stuff.previousMenus].menu - stuff.scroll = stuff.previousMenus[#stuff.previousMenus].scroll - stuff.drawScroll = stuff.previousMenus[#stuff.previousMenus].drawScroll - stuff.scrollHiddenOffset = stuff.previousMenus[#stuff.previousMenus].scrollHiddenOffset - stuff.previousMenus[#stuff.previousMenus] = nil - end - end - end - - function func.get_feature_by_hierarchy_key(hierarchy_key) - local feat = stuff.hotkey_feature_hierarchy_keys[hierarchy_key] - if feat then - if feat[2] and not feat.name then - return feat, true - else - return feat[1] - end - end - end - - function func.get_feature(id) - assert(type(id) == "number" and id ~= 0, "invalid id in get_feature") - return stuff.feature_by_id[id] - end - - function func.delete_feature(id, bool_ps) - if type(id) == "table" then - id = id.id - end - - local feat = stuff.feature_by_id[id] - if not feat then - return false - end - - if stuff.old_selected == stuff.feature_by_id[id] then - stuff.old_selected = nil - end - stuff.feature_by_id[id] = nil - - if feat.thread then - if not menu.has_thread_finished(feat.thread) then - menu.delete_thread(feat.thread) - end - end - if feat.hl_thread then - if not menu.has_thread_finished(feat.hl_thread) then - menu.delete_thread(feat.hl_thread) - end - end - - local parent - if feat.parent_id ~= 0 or bool_ps then - parent = bool_ps and stuff.feature_by_id[feat.ps_parent_id] or stuff.feature_by_id[feat.parent_id] - else - parent = features - end - - if feat.type >> 11 & 1 ~= 0 then - func.deleted_or_hidden_parent_check(feat) - end + system.wait(0) + end - local index = feat.index - if not bool_ps then - stuff.feature_hints[index] = nil + return cheeseUtils.get_key(0x0D):is_down() or "escaped" end - table.remove(parent, tonumber(feat.index)) - - --func.check_scroll(index, parent, true) + end - for i = index, #parent do - parent[i].index = i + function func.draw_hotkey(keyTable) + while true do + for i = 0, 360 do + controls.disable_control_action(0, i, true) + end + local concatenated = table.concat(keyTable, "+") + scriptdraw.draw_rect(cheeseUtils.memoize.v2(0, 0), cheeseUtils.memoize.v2(2, 2), 0x7D000000) + scriptdraw.draw_text(concatenated, cheeseUtils.memoize.v2(-(scriptdraw.get_text_size(concatenated, 1, 0).x/graphics.get_screen_width())), cheeseUtils.memoize.v2(2, 2), 1, 0xffffffff, 1 << 1, 0) + system.wait(0) end - - return true end - function func.delete_player_feature(id) - if type(id) == "table" then - id = id.id - end - stuff.player_feature_hints[id] = nil + function func.start_hotkey_process(feat) + stuff.menuData.menuToggle = false + local keyTable = {} + local vkTable = {} - local feat = stuff.player_feature_by_id[id] - if not feat then - return false + local drawThread = menu.create_thread(func.draw_hotkey, keyTable) + + while cheeseUtils.get_key(stuff.vkcontrols.setHotkey):is_down() do + system.wait(0) end - stuff.player_feature_by_id[id] = nil + local response + repeat + response = func.get_hotkey(keyTable, vkTable) + if not response then + for k, v in pairs(keyTable) do + keyTable[k] = nil + end + for k, v in pairs(vkTable) do + vkTable[k] = nil + end + end + until response - local parent - if feat.parent_id ~= 0 then - parent = stuff.player_feature_by_id[feat.parent_id] - else - parent = features["OnlinePlayers"] - end + local keyString = table.concat(keyTable, "|") - for k, v in pairs(feat.feats) do - func.delete_feature(v.ps_id, true) + if response ~= "escaped" then + stuff.hotkeys_to_vk[keyString] = vkTable + if not stuff.hotkeys[keyString] then + stuff.hotkeys[keyString] = {} + end + stuff.hotkeys[keyString][feat.hierarchy_key] = true + feat.hotkey = keyString + gltw.write(stuff.hotkeys, "hotkeys", stuff.path.hotkeys, nil, true) end - local index = feat.index - table.remove(parent, tonumber(index)) - for i = index, #parent do - parent[i].index = i - for pid = 0, 31 do - parent[i].feats[pid].index = i - end + menu.delete_thread(drawThread) + while cheeseUtils.get_key(0x0D):is_down() or cheeseUtils.get_key(0x1B):is_down() do -- enter and esc + controls.disable_control_action(0, 200, true) + system.wait(0) end + controls.disable_control_action(0, 200, true) + func.toggle_menu(true) + return response ~= "escaped" and response end - function func.get_player_feature(id) - assert(type(id) == "number" and id ~= 0, "invalid id in get_player_feature") - return stuff.player_feature_by_id[id] - end + --End of functions - function func.do_key(time, key, doLoopedFunction, functionToDo) - if cheeseUtils.get_key(key):is_down() then - functionToDo() - local timer = utils.time_ms() + time - while timer > utils.time_ms() and cheeseUtils.get_key(key):is_down() do - system.wait(0) - end - while timer < utils.time_ms() and cheeseUtils.get_key(key):is_down() do - if doLoopedFunction then - functionToDo() + --threads + menu.create_thread(function() + local side_window_pos = v2((stuff.menuData.pos_x + stuff.menuData.width + stuff.menuData.side_window.offset.x)*2-1, (stuff.menuData.pos_y + stuff.menuData.side_window.offset.y)*-2+1) + while true do + if stuff.menuData.menuToggle then + func.draw_current_menu() + if currentMenu and stuff.menuData.side_window.on then + local pid = currentMenu.pid + if not pid and currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then + pid = currentMenu[stuff.scroll + stuff.scrollHiddenOffset].pid + end + if pid and pid ~= stuff.pid then + if not stuff.playerIds[pid].hidden then + stuff.player_info[1][2] = tostring(pid) + stuff.player_info[10][2] = func.convert_int_ip(player.get_player_ip(pid)) + stuff.player_info[11][2] = tostring(player.get_player_scid(pid)) + stuff.player_info[12][2] = string.format("%X", player.get_player_host_token(pid)) + stuff.player_info.max_health = "/"..math.floor(player.get_player_max_health(pid)) + stuff.player_info.name = tostring(player.get_player_name(pid)) + stuff.pid = pid + end + end + if pid then + side_window_pos.x, side_window_pos.y = (stuff.menuData.pos_x + stuff.menuData.width + stuff.menuData.side_window.offset.x)*2-1, (stuff.menuData.pos_y + stuff.menuData.side_window.offset.y)*-2+1 + native.call(0xBE8CD9BE829BBEBF, player.get_player_ped(stuff.pid), stuff.proofs.bulletProof, stuff.proofs.fireProof, stuff.proofs.explosionProof, stuff.proofs.collisionProof, stuff.proofs.meleeProof, stuff.proofs.steamProof, stuff.proofs.p7, stuff.proofs.drownProof) + stuff.player_info[2][2] = player.is_player_god(stuff.pid) and "Yes" or "No" + stuff.player_info[3][2] = (stuff.proofs.bulletProof:__tointeger()|stuff.proofs.fireProof:__tointeger()|stuff.proofs.explosionProof:__tointeger()|stuff.proofs.collisionProof:__tointeger()|stuff.proofs.meleeProof:__tointeger()|stuff.proofs.steamProof:__tointeger()|stuff.proofs.p7:__tointeger()|stuff.proofs.drownProof:__tointeger()) == 1 and "Yes" or "No" + stuff.player_info[4][2] = player.is_player_vehicle_god(stuff.pid) and "Yes" or "No" + stuff.player_info[5][2] = player.is_player_modder(stuff.pid, -1) and "Yes" or "No" + stuff.player_info[6][2] = player.is_player_host(stuff.pid) and "Yes" or "No" + stuff.player_info[7][2] = player.get_player_wanted_level(stuff.pid) + stuff.player_info[8][2] = math.floor(player.get_player_health(stuff.pid))..stuff.player_info.max_health + stuff.player_info[9][2] = math.floor(player.get_player_armour(stuff.pid)).."/50" + stuff.player_info[13][2] = player.get_player_host_priority(stuff.pid) + func.draw_side_window( + stuff.player_info.name, + stuff.player_info, + side_window_pos, + func.convert_rgba_to_int(stuff.menuData.color.side_window.r, stuff.menuData.color.side_window.g, stuff.menuData.color.side_window.b, stuff.menuData.color.side_window.a), + stuff.menuData.side_window.width, stuff.menuData.side_window.spacing, stuff.menuData.side_window.padding, + func.convert_rgba_to_int(stuff.menuData.color.side_window_text.r, stuff.menuData.color.side_window_text.g, stuff.menuData.color.side_window_text.b, stuff.menuData.color.side_window_text.a) + ) + end end - local timer = utils.time_ms() + 50 - while timer > utils.time_ms() do - system.wait(0) + if stuff.old_selected ~= currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then + if type(stuff.old_selected) == "table" then + stuff.old_selected:activate_hl_func() + end + if currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then + currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() + end + stuff.old_selected = currentMenu[stuff.scroll + stuff.scrollHiddenOffset] end + controls.disable_control_action(0, 172, true) + controls.disable_control_action(0, 27, true) + else + system.wait(0) end end - end - - stuff.header_ids = {} - function func.load_sprite(path_to_file, id_table) - --path = path or stuff.path.header - id_table = id_table or stuff.header_ids - path_to_file = tostring(path_to_file) - assert(path_to_file, "invalid name") - - --name = name:gsub("%.[a-z]+$", "") - - if not id_table[path_to_file] then - if utils.dir_exists(path_to_file:gsub("%.ogif", "")) and path_to_file:find("%.ogif") then - local path = path_to_file:gsub("%.ogif", "").."\\" - local images - - for _, v in pairs(stuff.image_ext) do - images = utils.get_all_files_in_directory(path, v) - if images[1] then break end - end - if not images[1] then - menu.notify("No frames found.", "Cheese Menu", 5, 0x0000FF) - return - end - - id_table[path_to_file] = {} - for i, e in pairs(images) do - id_table[path_to_file][i] = {} - id_table[path_to_file][i].sprite = scriptdraw.register_sprite(path..e) - id_table[path_to_file][i].delay = e:match("%d+_(%d+)") - end + end, nil) - id_table[path_to_file].constant_delay = utils.get_all_files_in_directory(path, "txt")[1] - if not id_table[path_to_file].constant_delay then - for k, v in pairs(images) do - if not v:match("%d+_(%d+)") then - menu.notify("FPS file not found and frames are not in format, create a txt file with the framerate of the gif.\nExample: '25 fps.txt'", "Cheese Menu", 5, 0x0000FF) - break + menu.create_thread(function() + while true do + stuff.menuData.menuNav = native.call(0x5FCF4D7069B09026):__tointeger() ~= 1 and not (stuff.menuData.chatBoxOpen or input.is_open() --[[or console.on]]) + if stuff.menuData.menuNav then + func.do_key(500, stuff.vkcontrols.open, false, function() -- F4 + func.toggle_menu(not stuff.menuData.menuToggle) + end) + end + if currentMenu.hidden or not currentMenu then + currentMenu = stuff.previousMenus[#stuff.previousMenus].menu + stuff.scroll = stuff.previousMenus[#stuff.previousMenus].scroll + stuff.drawScroll = stuff.previousMenus[#stuff.previousMenus].drawScroll + stuff.scrollHiddenOffset = stuff.previousMenus[#stuff.previousMenus].scrollHiddenOffset + stuff.previousMenus[#stuff.previousMenus] = nil + end + local pid = player.player_id() + stuff.playerIds[pid].name = player.get_player_name(pid).." [Y]" + if stuff.playerIds[pid].hidden then + stuff.playerIds[pid].hidden = false + func.reset_player_submenu(pid) + end + system.wait(0) + end + end, nil) + menu.create_thread(function() + while true do + system.wait(0) + if stuff.menuData.menuToggle and stuff.menuData.menuNav then + func.do_key(500, stuff.vkcontrols.setHotkey, false, function() -- F11 + if cheeseUtils.get_key(0x10):is_down() and stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey] then + stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey][currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hierarchy_key] = nil + if not next(stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey]) then + stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey] = nil + end + currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey = nil + gltw.write(stuff.hotkeys, "hotkeys", stuff.path.hotkeys, nil, true) + menu.notify("Removed "..currentMenu[stuff.scroll + stuff.scrollHiddenOffset].name.."'s hotkey") + elseif cheeseUtils.get_key(0x11):is_down() then + menu.notify(currentMenu[stuff.scroll + stuff.scrollHiddenOffset].name.."'s hotkey is "..(currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey or "none")) + elseif not cheeseUtils.get_key(0x10):is_down() and not cheeseUtils.get_key(0x11):is_down() then + if stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey] then + stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey][currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hierarchy_key] = nil + end + if func.start_hotkey_process(currentMenu[stuff.scroll + stuff.scrollHiddenOffset]) then + menu.notify("Set "..currentMenu[stuff.scroll + stuff.scrollHiddenOffset].name.."'s hotkey to "..currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey) + end + end + end) + end + end + end,nil) + menu.create_thread(function() + while true do + system.wait(0) + if stuff.menuData.menuToggle and stuff.menuData.menuNav then + func.do_key(500, stuff.vkcontrols.down, true, function() -- downKey + --[[ local old_scroll = stuff.scroll + stuff.scrollHiddenOffset ]] + if stuff.scroll + stuff.drawHiddenOffset >= #currentMenu and #currentMenu - stuff.drawHiddenOffset > 1 then + stuff.scroll = 1 + stuff.drawScroll = 0 + elseif #currentMenu - stuff.drawHiddenOffset > 1 then + stuff.scroll = stuff.scroll + 1 + if stuff.scroll - stuff.drawScroll >= (stuff.menuData.max_features - 1) and stuff.drawScroll < stuff.maxDrawScroll then + stuff.drawScroll = stuff.drawScroll + 1 end end - else - id_table[path_to_file].constant_delay = math.floor(1000 / tonumber(id_table[path_to_file].constant_delay:match("(%d*%.*%d+)%s+fps"))) - end - - elseif utils.file_exists(path_to_file) then - id_table[path_to_file] = scriptdraw.register_sprite(path_to_file) + --[[ if old_scroll ~= (stuff.scroll + stuff.scrollHiddenOffset) then + currentMenu[old_scroll]:activate_hl_func() + if currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then + currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() + end + end ]] + end) end end - - return id_table[path_to_file] - end - - function func.toggle_menu(bool) - stuff.menuData.menuToggle = bool - if stuff.menuData.menuToggle then - if currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then - currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() + end, nil) + menu.create_thread(function() + while true do + system.wait(0) + if stuff.menuData.menuToggle and stuff.menuData.menuNav then + func.do_key(500, stuff.vkcontrols.up, true, function() -- upKey + --[[ local old_scroll = stuff.scroll + stuff.scrollHiddenOffset ]] + if stuff.scroll <= 1 and #currentMenu - stuff.drawHiddenOffset > 1 then + stuff.scroll = #currentMenu + stuff.drawScroll = stuff.maxDrawScroll + elseif #currentMenu - stuff.drawHiddenOffset > 1 then + stuff.scroll = stuff.scroll - 1 + if stuff.scroll - stuff.drawScroll <= 2 and stuff.drawScroll > 0 then + stuff.drawScroll = stuff.drawScroll - 1 + end + end + --[[ if old_scroll ~= (stuff.scroll + stuff.scrollHiddenOffset) then + currentMenu[old_scroll]:activate_hl_func() + if currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then + currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() + end + end ]] + end) end end - end - - function func.selector(feat) - local originalmenuToggle = stuff.menuData.menuToggle - stuff.menuData.menuToggle = false - if feat.str_data then - local index, _ = cheeseUtils.selector(nil, stuff.menuData.selector_speed, feat.real_value + 1, feat.str_data) - if index then - feat.real_value = index - 1 - end - if feat.type >> 10 & 1 ~= 0 then - feat:activate_feat_func() + end,nil) + menu.create_thread(function() + while true do + system.wait(0) + if stuff.menuData.menuToggle and stuff.menuData.menuNav then + func.do_key(500, stuff.vkcontrols.select, true, function() --enter + local feat = currentMenu[stuff.scroll + stuff.scrollHiddenOffset] + if feat then + if cheeseUtils.get_key(stuff.vkcontrols.specialKey):is_down() and feat.type >> 5 & 1 ~= 0 then + menu.create_thread(func.selector, feat) + elseif feat.type >> 11 & 1 ~= 0 and not feat.hidden then + --feat:activate_hl_func() + stuff.previousMenus[#stuff.previousMenus + 1] = {menu = currentMenu, scroll = stuff.scroll, drawScroll = stuff.drawScroll, scrollHiddenOffset = stuff.scrollHiddenOffset} + currentMenu = feat + currentMenu:activate_feat_func() + stuff.scroll = 1 + system.wait(0) + stuff.drawScroll = 0 + stuff.scrollHiddenOffset = 0 + --[[ if feat then + feat:activate_hl_func() + end ]] + while cheeseUtils.get_key(stuff.vkcontrols.select):is_down() do + system.wait(0) + end + elseif feat.type & 1536 ~= 0 and not feat.hidden then + feat:activate_feat_func() + elseif feat.type & 1 ~= 0 and not feat.hidden then + feat.real_on = not feat.real_on + feat:activate_feat_func() + end + else + system.wait(100) + end + end) end end - func.toggle_menu(originalmenuToggle) - end - - function func.rewrap_hint(hintTable, font, padding) - hintTable.str = cheeseUtils.wrap_text(hintTable.original, font, stuff.menuData.text_size * stuff.menuData.hint_size_modifier, stuff.menuData.width*2-padding) - hintTable.size = scriptdraw.get_text_size(hintTable.str, 1, font) - end - - function func.rewrap_hints(font) - local padding = scriptdraw.size_pixel_to_rel_x(25) - for _, hintTable in pairs(stuff.feature_hints) do - func.rewrap_hint(hintTable, font, padding) - end - for _, hintTable in pairs(stuff.player_feature_hints) do - func.rewrap_hint(hintTable, font, padding) - end - end - - function func.save_settings() - gltw.write({ - x = stuff.menuData.pos_x, - y = stuff.menuData.pos_y, - side_window = stuff.menuData.side_window, - controls = stuff.controls, - hotkey_notifications = stuff.hotkey_notifications, - player_submenu_sort = stuff.player_submenu_sort, - selector_speed = stuff.menuData.selector_speed - }, "Settings", stuff.path.cheesemenu) - end - - function func.load_settings() - local settings = gltw.read("Settings", stuff.path.cheesemenu, nil, nil, true) - if settings then - stuff.menuData.pos_x = settings.x - stuff.menuData.pos_y = settings.y - stuff.menuData.selector_speed = settings.selector_speed - stuff.player_submenu_sort = settings.player_submenu_sort - - for k, v in pairs(settings.side_window) do - stuff.menuData.side_window[k] = v - end - for k, v in pairs(settings.hotkey_notifications) do - stuff.hotkey_notifications[k] = v - end - for k, v in pairs(settings.controls) do - stuff.controls[k] = v - end - for k, v in pairs(stuff.controls) do - stuff.vkcontrols[k] = stuff.char_codes[v] + end, nil) + menu.create_thread(function() + while true do + system.wait(0) + if stuff.menuData.menuToggle and stuff.menuData.menuNav then + func.do_key(500, stuff.vkcontrols.back, false, function() --backspace + if stuff.previousMenus[#stuff.previousMenus] then + --[[ if currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then + currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() + end ]] + currentMenu = stuff.previousMenus[#stuff.previousMenus].menu + stuff.scroll = stuff.previousMenus[#stuff.previousMenus].scroll + stuff.drawScroll = stuff.previousMenus[#stuff.previousMenus].drawScroll + stuff.scrollHiddenOffset = stuff.previousMenus[#stuff.previousMenus].scrollHiddenOffset + stuff.previousMenus[#stuff.previousMenus] = nil + --currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() + end + end) end - - menu_configuration_features.menuXfeat.value = math.floor(stuff.menuData.pos_x*graphics.get_screen_width()) - menu_configuration_features.menuYfeat.value = math.floor(stuff.menuData.pos_y*graphics.get_screen_height()) - menu_configuration_features.player_submenu_sort.value = stuff.player_submenu_sort - menu_configuration_features.player_submenu_sort:toggle() - menu_configuration_features.side_window_offsetx.value = math.floor(stuff.menuData.side_window.offset.x*graphics.get_screen_width()) - menu_configuration_features.side_window_offsety.value = math.floor(stuff.menuData.side_window.offset.y*graphics.get_screen_height()) - menu_configuration_features.side_window_spacing.value = math.floor(stuff.menuData.side_window.spacing*graphics.get_screen_height()) - menu_configuration_features.side_window_padding.value = math.floor(stuff.menuData.side_window.padding*graphics.get_screen_width()) - menu_configuration_features.side_window_width.value = math.floor(stuff.menuData.side_window.width*graphics.get_screen_width()) - menu_configuration_features.side_window_on.on = stuff.menuData.side_window.on - menu_configuration_features.selector_speed.value = stuff.menuData.selector_speed - end - end - - function func.save_ui(name) - gltw.write(stuff.menuData, name, stuff.path.ui, {"menuToggle", "menuNav", "loaded_sprites", "files", "pos_x", "pos_y", "side_window", "selector_speed", "chatBoxOpen"}) - end - - function func.load_ui(name) - local uiTable = gltw.read(name, stuff.path.ui, stuff.menuData, true, true) - if not uiTable then - return end - if menu_configuration_features then - local header, bgSprite = uiTable.header, uiTable.background_sprite and uiTable.background_sprite.sprite or nil - if not header then - menu_configuration_features.headerfeat.value = 0 - menu_configuration_features.headerfeat:toggle() - end - if not bgSprite then - menu_configuration_features.backgroundfeat.value = 0 - menu_configuration_features.backgroundfeat:toggle() - end - - --[[ menu_configuration_features.menuXfeat.value = math.floor(stuff.menuData.pos_x*graphics.get_screen_width()) - menu_configuration_features.menuYfeat.value = math.floor(stuff.menuData.pos_y*graphics.get_screen_height()) ]] - menu_configuration_features.maxfeats.value = math.floor(stuff.menuData.max_features) - menu_configuration_features.menuWidth.value = math.floor(stuff.menuData.width*graphics.get_screen_width()) - menu_configuration_features.featXfeat.value = math.floor(stuff.menuData.feature_scale.x*graphics.get_screen_width()) - menu_configuration_features.featYfeat.value = math.floor(stuff.menuData.feature_scale.y*graphics.get_screen_height()) - menu_configuration_features.feature_offset.value = math.floor(stuff.menuData.feature_offset*graphics.get_screen_height()) - menu_configuration_features.namePadding.value = math.floor(stuff.menuData.padding.name*graphics.get_screen_width()) - menu_configuration_features.parentPadding.value = math.floor(stuff.menuData.padding.parent*graphics.get_screen_width()) - menu_configuration_features.valuePadding.value = math.floor(stuff.menuData.padding.value*graphics.get_screen_width()) - menu_configuration_features.sliderPadding.value = math.floor(stuff.menuData.padding.slider*graphics.get_screen_width()) - menu_configuration_features.sliderWidth.value = math.floor(stuff.menuData.slider.width*graphics.get_screen_width()) - menu_configuration_features.sliderHeight.value = math.floor(stuff.menuData.slider.height*graphics.get_screen_height()) - menu_configuration_features.sliderheightActive.value = math.floor(stuff.menuData.slider.heightActive*graphics.get_screen_height()) - menu_configuration_features.text_size.value = stuff.menuData.text_size_modifier - menu_configuration_features.footer_size.value = stuff.menuData.footer_size_modifier - menu_configuration_features.hint_size.value = stuff.menuData.hint_size_modifier - menu_configuration_features.text_y_offset.value = -math.floor(stuff.menuData.text_y_offset*graphics.get_screen_height()) - stuff.drawFeatParams.textOffset.y = stuff.menuData.text_y_offset - menu_configuration_features.footer_y_offset.value = math.floor(stuff.menuData.footer.footer_y_offset*graphics.get_screen_height()) - menu_configuration_features.border.value = math.floor(stuff.menuData.border*graphics.get_screen_height()) - menu_configuration_features.backgroundsize.value = stuff.menuData.background_sprite.size - menu_configuration_features.backgroundoffsetx.value = math.floor(stuff.menuData.background_sprite.offset.x*graphics.get_screen_width()) - menu_configuration_features.backgroundoffsety.value = math.floor(stuff.menuData.background_sprite.offset.y*graphics.get_screen_height()) - menu_configuration_features.footer_size.value = math.floor(stuff.menuData.footer.footer_size*graphics.get_screen_height()) - menu_configuration_features.footerPadding.value = math.floor(stuff.menuData.footer.padding*graphics.get_screen_width()) - menu_configuration_features.draw_footer.on = stuff.menuData.footer.draw_footer - menu_configuration_features.footer_pos_related_to_background.on = stuff.menuData.footer.footer_pos_related_to_background - --[[ menu_configuration_features.side_window_offsetx.value = math.floor(stuff.menuData.side_window.offset.x*graphics.get_screen_width()) - menu_configuration_features.side_window_offsety.value = math.floor(stuff.menuData.side_window.offset.y*graphics.get_screen_height()) - menu_configuration_features.side_window_spacing.value = math.floor(stuff.menuData.side_window.spacing*graphics.get_screen_height()) - menu_configuration_features.side_window_padding.value = math.floor(stuff.menuData.side_window.padding*graphics.get_screen_width()) - menu_configuration_features.side_window_width.value = math.floor(stuff.menuData.side_window.width*graphics.get_screen_width()) - menu_configuration_features.side_window_on.on = stuff.menuData.side_window.on ]] - menu_configuration_features.text_font.value = stuff.menuData.fonts.text - menu_configuration_features.footer_font.value = stuff.menuData.fonts.footer - menu_configuration_features.hint_font.value = stuff.menuData.fonts.hint - - menu_configuration_features.hint_font:toggle() - - for k, v in pairs(stuff.menuData.color) do - if menu_configuration_features[k] then - if type(v) == "table" then - menu_configuration_features[k].r.value = v.r - menu_configuration_features[k].g.value = v.g - menu_configuration_features[k].b.value = v.b - menu_configuration_features[k].a.value = v.a - else - menu_configuration_features[k].r.value = func.convert_int_to_rgba(v, "r") - menu_configuration_features[k].g.value = func.convert_int_to_rgba(v, "g") - menu_configuration_features[k].b.value = func.convert_int_to_rgba(v, "b") - menu_configuration_features[k].a.value = func.convert_int_to_rgba(v, "a") + end, nil) + menu.create_thread(function() + while true do + system.wait(0) + if stuff.menuData.menuToggle and stuff.menuData.menuNav then + func.do_key(500, stuff.vkcontrols.left, true, function() -- left + local feat = currentMenu[stuff.scroll + stuff.scrollHiddenOffset] + if feat then + if feat.value then + if feat.str_data then + if feat.value <= 0 then + feat.value = #feat.str_data - 1 + else + feat.value = feat.value - 1 + end + else + if tonumber(feat.value) <= feat.min and feat.type >> 2 & 1 == 0 then + feat.value = feat.max + else + feat.value = tonumber(feat.value) - feat.mod + end + end + end + if feat.type then + if feat.type >> 10 & 1 ~= 0 or (feat.type & 3 == 3 and feat.on) then + feat:activate_feat_func() + end + end end - end + end) end - - for k, v in pairs(menu_configuration_features.headerfeat.str_data) do - if v == stuff.menuData.header then - menu_configuration_features.headerfeat.value = k - 1 - end + end + end, nil) + menu.create_thread(function() + while true do + if stuff.menuData.menuToggle and stuff.menuData.menuNav then + func.do_key(500, stuff.vkcontrols.right, true, function() -- right + local feat = currentMenu[stuff.scroll + stuff.scrollHiddenOffset] + if feat then + if feat.value then + if feat.str_data then + if tonumber(feat.value) >= tonumber(#feat.str_data) - 1 then + feat.value = 0 + else + feat.value = feat.value + 1 + end + else + if tonumber(feat.value) >= feat.max and feat.type >> 2 & 1 == 0 then + feat.value = feat.min + else + feat.value = tonumber(feat.value) + feat.mod + end + end + end + if feat.type then + if feat.type >> 10 & 1 ~= 0 or (feat.type & 3 == 3 and feat.on) then + feat:activate_feat_func() + end + end + end + end) end + system.wait(0) + end + end, nil) - if uiTable.background_sprite then - for k, v in pairs(menu_configuration_features.backgroundfeat.str_data) do - if v == uiTable.background_sprite.sprite then - menu_configuration_features.backgroundfeat.value = k - 1 + + --Hotkey thread + menu.create_thread(function() + while true do + if stuff.menuData.menuNav then + for k, v in pairs(stuff.hotkeys) do + local hotkey = cheeseUtils.get_key(table.unpack(stuff.hotkeys_to_vk[k])) + if hotkey:is_down() and (not (cheeseUtils.get_key(0x10):is_down() or cheeseUtils.get_key(0x11):is_down() or cheeseUtils.get_key(0x12):is_down()) or not (k:match("NOMOD"))) and utils.time_ms() > stuff.hotkey_cooldowns[k] then + for k, v in pairs(stuff.hotkeys[k]) do + if stuff.hotkey_feature_hierarchy_keys[k] then + for k, v in pairs(stuff.hotkey_feature_hierarchy_keys[k]) do + if v.type & 1 ~= 0 then + v.on = not v.on + if stuff.hotkey_notifications.toggle then + menu.notify("Turned "..v.name.." "..(v.on and "on" or "off"), "Cheese Menu", 3, func.convert_rgba_to_int(stuff.menuData.color.notifications.r, stuff.menuData.color.notifications.g, stuff.menuData.color.notifications.b, stuff.menuData.color.notifications.a)) + end + else + v:activate_feat_func() + if stuff.hotkey_notifications.action then + menu.notify("Activated "..v.name, "Cheese Menu", 3, func.convert_rgba_to_int(stuff.menuData.color.notifications.r, stuff.menuData.color.notifications.g, stuff.menuData.color.notifications.b, stuff.menuData.color.notifications.a)) + end + end + end + end + end + if stuff.hotkey_cooldowns[k] == 0 then + stuff.hotkey_cooldowns[k] = utils.time_ms() + 500 + else + stuff.hotkey_cooldowns[k] = utils.time_ms() + 100 + end + elseif not hotkey:is_down() then + stuff.hotkey_cooldowns[k] = 0 end end end + system.wait(0) end - end + end, nil) + --End of threads + menu.notify("Kektram for teaching me lua & sharing neat functions\n\nRimuru for making the first separate ui that helped me in making cheese menu\n\nProddy for showing better ways to do things & sharing Script Manager", "Credits:", 12, 0x00ff00) + menu.notify("Controls can be found in\nScript Features > Cheese Menu > Controls", "CheeseMenu by GhostOne\n"..stuff.controls.open.." to open", 6, 0x00ff00) - stuff.drawFeatParams = { - rectPos = v2(stuff.menuData.pos_x, stuff.menuData.pos_y - stuff.menuData.feature_offset/2 + stuff.menuData.border), - textOffset = v2(stuff.menuData.feature_scale.x/2, -0.0055555555), - colorText = stuff.menuData.color.text, - textSize = 0, - } - function func.draw_feat(k, v, offset, hiddenOffset) - --[[ stuff.drawFeatParams.rectPos.x = stuff.menuData.pos_x - stuff.drawFeatParams.rectPos.y = stuff.menuData.pos_y - stuff.menuData.feature_offset/2 + stuff.menuData.border - stuff.drawFeatParams.textOffset.x = stuff.menuData.feature_scale.x/2 - stuff.drawFeatParams.textSize = textSize ]] - stuff.drawFeatParams.colorText = stuff.menuData.color.text - stuff.drawFeatParams.bottomLeft = stuff.menuData.color.feature_bottomLeft - stuff.drawFeatParams.topLeft = stuff.menuData.color.feature_topLeft - stuff.drawFeatParams.topRight = stuff.menuData.color.feature_topRight - stuff.drawFeatParams.bottomRight = stuff.menuData.color.feature_bottomRight - local posY = (stuff.drawFeatParams.rectPos.y + (stuff.menuData.feature_offset * k))*-2+1 + menu_configuration_features = {} + menu_configuration_features.cheesemenuparent = menu.add_feature("Cheese Menu", "parent") - local is_selected - if stuff.scroll == k + stuff.drawScroll then - stuff.scrollHiddenOffset = hiddenOffset or stuff.scrollHiddenOffset - stuff.drawFeatParams.colorText = stuff.menuData.color.text_selected - stuff.drawFeatParams.bottomLeft = stuff.menuData.color.feature_selected_bottomLeft - stuff.drawFeatParams.topLeft = stuff.menuData.color.feature_selected_topLeft - stuff.drawFeatParams.topRight = stuff.menuData.color.feature_selected_topRight - stuff.drawFeatParams.bottomRight = stuff.menuData.color.feature_selected_bottomRight - is_selected = true - end - if offset == 0 then - local memv2 = cheeseUtils.memoize.v2 - local posX = stuff.drawFeatParams.rectPos.x*2-1 - --[[ scriptdraw.draw_rect( - cheeseUtils.memoize.v2(posX, posY), - cheeseUtils.memoize.v2(stuff.menuData.feature_scale.x*2, stuff.menuData.feature_scale.y*2), - func.convert_rgba_to_int(stuff.drawFeatParams.colorFeature.r, stuff.drawFeatParams.colorFeature.g, stuff.drawFeatParams.colorFeature.b, stuff.drawFeatParams.colorFeature.a) - ) ]] - local Left = posX - stuff.menuData.feature_scale.x - local Right = posX + stuff.menuData.feature_scale.x - local Top = posY + stuff.menuData.feature_scale.y - local Bottom = posY - stuff.menuData.feature_scale.y - scriptdraw.draw_rect_ext( - memv2(Left, Bottom), - memv2(Left, Top), - memv2(Right, Top), - memv2(Right, Bottom), - func.convert_rgba_to_int(stuff.drawFeatParams.bottomLeft.r, stuff.drawFeatParams.bottomLeft.g, stuff.drawFeatParams.bottomLeft.b, stuff.drawFeatParams.bottomLeft.a), - func.convert_rgba_to_int(stuff.drawFeatParams.topLeft.r, stuff.drawFeatParams.topLeft.g, stuff.drawFeatParams.topLeft.b, stuff.drawFeatParams.topLeft.a), - func.convert_rgba_to_int(stuff.drawFeatParams.topRight.r, stuff.drawFeatParams.topRight.g, stuff.drawFeatParams.topRight.b, stuff.drawFeatParams.topRight.a), - func.convert_rgba_to_int(stuff.drawFeatParams.bottomRight.r, stuff.drawFeatParams.bottomRight.g, stuff.drawFeatParams.bottomRight.b, stuff.drawFeatParams.bottomRight.a) - ) - end + menu.add_feature("Save Settings", "action", menu_configuration_features.cheesemenuparent.id, function() + func.save_settings() + menu.notify("Settings Saved Successfully", "Cheese Menu", 6, 0x00ff00) + end) - local font = stuff.menuData.fonts.text - if v.type & 1 == 0 then - scriptdraw.draw_text( - v["name"], - cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x - (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.name))*2-1, (stuff.drawFeatParams.rectPos.y + stuff.drawFeatParams.textOffset.y + (stuff.menuData.feature_offset * k))*-2+1), - cheeseUtils.memoize.v2(10, 10), - stuff.drawFeatParams.textSize, - func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a), - 0, font - ) - if v.type >> 11 & 1 ~= 0 then - scriptdraw.draw_text( - ">>", - cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x + (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.parent))*2-1, (stuff.drawFeatParams.rectPos.y + stuff.drawFeatParams.textOffset.y + (stuff.menuData.feature_offset * k))*-2+1), - cheeseUtils.memoize.v2(10, 10), - stuff.drawFeatParams.textSize, - func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a), - 16, font - ) - end - elseif v.type & 1 ~= 0 then -- toggle - cheeseUtils.draw_outline( - cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x - (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.name) + 0.00390625)*2-1, posY), - cheeseUtils.memoize.v2(0.015625, 0.0277777777778), - func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a), - 2 - ) - if v.real_on then - scriptdraw.draw_rect( - cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x - (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.name) + 0.00390625)*2-1, posY), - cheeseUtils.memoize.v2(0.0140625, 0.025), - func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a) - ) + menu.add_feature("Save UI", "action", menu_configuration_features.cheesemenuparent.id, function() + local status, name = input.get("name of ui", "", 25, 0) + if status == 0 then + func.save_ui(name) + menu.notify("UI Saved Successfully", "Cheese Menu", 6, 0x00ff00) + for _, v in pairs(stuff.menuData.files.ui) do + if v == name then + return + end end - - scriptdraw.draw_text( - v.name, - cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x - (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.name) + 0.011328125)*2-1, (stuff.drawFeatParams.rectPos.y + stuff.drawFeatParams.textOffset.y + (stuff.menuData.feature_offset * k))*-2+1), - cheeseUtils.memoize.v2(10, 10), - stuff.drawFeatParams.textSize, - func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a), - 0, font - ) + stuff.menuData.files.ui[#stuff.menuData.files.ui+1] = name + menu_configuration_features.load_ui:set_str_data(stuff.menuData.files.ui) end + end) - if v.type >> 1 & 1 ~= 0 then -- value_i_f_str - local rounded_value = v.str_data and v.str_data[v.real_value + 1] or v.real_value - if v.type >> 7 & 1 ~= 0 or v.type >> 2 & 1 ~= 0 then - rounded_value = (rounded_value * 10000) + 0.5 - rounded_value = math.floor(rounded_value) - rounded_value = rounded_value / 10000 - end - if v.type >> 2 & 1 ~= 0 then - cheeseUtils.draw_slider( - cheeseUtils.memoize.v2( - (stuff.drawFeatParams.rectPos.x + stuff.menuData.feature_scale.x/2 - stuff.menuData.slider.width/4 - stuff.menuData.padding.slider)*2-1, - posY - ), - cheeseUtils.memoize.v2(stuff.menuData.slider.width, is_selected and stuff.menuData.slider.heightActive or stuff.menuData.slider.height), - v.min, v.max, v.value, - is_selected and func.convert_rgba_to_int(stuff.menuData.color.slider_selectedBackground) or func.convert_rgba_to_int(stuff.menuData.color.slider_background), - is_selected and func.convert_rgba_to_int(stuff.menuData.color.slider_selectedActive) or func.convert_rgba_to_int(stuff.menuData.color.slider_active), - is_selected and func.convert_rgba_to_int(stuff.menuData.color.slider_text) or 0, - is_selected) - else - local value_str = "< "..tostring(rounded_value).." >" - if v.str_data then - local pixel_size = scriptdraw.get_text_size(value_str, 1, font).x - local screenWidth = graphics.get_screen_width() - if pixel_size/screenWidth > 370/screenWidth then - local original_size = stuff.drawFeatParams.textSize - stuff.drawFeatParams.textSize = stuff.drawFeatParams.textSize * (370 / pixel_size * 0.8) - stuff.drawFeatParams.textSize = math.min(stuff.drawFeatParams.textSize + 0.2, original_size) - end - end + menu_configuration_features.load_ui = menu.add_feature("Load UI", "action_value_str", menu_configuration_features.cheesemenuparent.id, function(f) + func.load_ui(f.str_data[f.value + 1]) + end) + menu_configuration_features.load_ui:set_str_data(stuff.menuData.files.ui) - scriptdraw.draw_text( - value_str, - cheeseUtils.memoize.v2((stuff.drawFeatParams.rectPos.x + (stuff.drawFeatParams.textOffset.x - stuff.menuData.padding.value) - scriptdraw.size_pixel_to_rel_x(scriptdraw.get_text_size(value_str, stuff.drawFeatParams.textSize, font).x)/4)*2-1, (stuff.drawFeatParams.rectPos.y + stuff.drawFeatParams.textOffset.y + (stuff.menuData.feature_offset * k))*-2+1), - cheeseUtils.memoize.v2(10, 10), - stuff.drawFeatParams.textSize, - func.convert_rgba_to_int(stuff.drawFeatParams.colorText.r, stuff.drawFeatParams.colorText.g, stuff.drawFeatParams.colorText.b, stuff.drawFeatParams.colorText.a), - 0, font - ) + menu_configuration_features.menuXfeat = menu.add_feature("Menu pos X", "autoaction_value_i", menu_configuration_features.cheesemenuparent.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.pos_x = num/graphics.get_screen_height() + f.value = num end end - end + stuff.menuData.pos_x = f.value/graphics.get_screen_width() + end) + menu_configuration_features.menuXfeat.max = graphics.get_screen_width() + menu_configuration_features.menuXfeat.mod = 1 + menu_configuration_features.menuXfeat.min = -graphics.get_screen_width() + menu_configuration_features.menuXfeat.value = math.floor(stuff.menuData.pos_x*graphics.get_screen_width()) - stuff.draw_current_menu = {frameCounter = 1, time = utils.time_ms() + 33, currentSprite = stuff.menuData.header} - function func.draw_current_menu() - local sprite = func.load_sprite(stuff.path.header..(stuff.menuData.header or "")) - if stuff.draw_current_menu.currentSprite ~= stuff.menuData.header then - stuff.draw_current_menu.currentSprite = stuff.menuData.header - stuff.draw_current_menu.time = 0 - stuff.draw_current_menu.frameCounter = 1 - if type(sprite) == "table" then - stuff.draw_current_menu.time = utils.time_ms() + (sprite[stuff.draw_current_menu.frameCounter].delay or sprite.constant_delay or 33) - end - end - stuff.drawHiddenOffset = 0 - for k, v in pairs(currentMenu) do - if type(k) == "number" then - if v.hidden or (v.type >> 11 & 1 ~= 0 and not v.on) then - stuff.drawHiddenOffset = stuff.drawHiddenOffset + 1 - end + menu_configuration_features.menuYfeat = menu.add_feature("Menu pos Y", "autoaction_value_i", menu_configuration_features.cheesemenuparent.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.pos_y = num/graphics.get_screen_height() + f.value = num end end - local background_sprite_path = stuff.path.background..(stuff.menuData.background_sprite.sprite or "") - if stuff.menuData.background_sprite.sprite and func.load_sprite(background_sprite_path) then - scriptdraw.draw_sprite( - func.load_sprite(background_sprite_path), - cheeseUtils.memoize.v2((stuff.menuData.pos_x + stuff.menuData.background_sprite.offset.x)*2-1, (stuff.menuData.pos_y+stuff.menuData.background_sprite.offset.y+stuff.menuData.height/2+0.01458)*-2+1), - stuff.menuData.background_sprite.size, - 0, - func.convert_rgba_to_int(255, 255, 255, stuff.menuData.color.background.a) - ) - else - scriptdraw.draw_rect( - cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, (stuff.menuData.pos_y+stuff.menuData.border+stuff.menuData.height/2)*-2+1), - cheeseUtils.memoize.v2(stuff.menuData.width*2, stuff.menuData.height*2), - func.convert_rgba_to_int(stuff.menuData.color.background.r, stuff.menuData.color.background.g, stuff.menuData.color.background.b, stuff.menuData.color.background.a) - ) - end - if #currentMenu - stuff.drawHiddenOffset >= stuff.menuData.max_features then - stuff.maxDrawScroll = #currentMenu - stuff.drawHiddenOffset - stuff.menuData.max_features + stuff.menuData.pos_y = f.value/graphics.get_screen_height() + end) + menu_configuration_features.menuYfeat.max = graphics.get_screen_height() + menu_configuration_features.menuYfeat.mod = 1 + menu_configuration_features.menuYfeat.min = -graphics.get_screen_height() + menu_configuration_features.menuYfeat.value = math.floor(stuff.menuData.pos_y*graphics.get_screen_height()) + + menu_configuration_features.headerfeat = menu.add_feature("Header", "autoaction_value_str", menu_configuration_features.cheesemenuparent.id, function(f) + if f.str_data[f.value + 1] == "NONE" then + stuff.menuData.header = nil else - stuff.maxDrawScroll = 0 - end - if stuff.drawScroll > stuff.maxDrawScroll then - stuff.drawScroll = stuff.maxDrawScroll - end - if stuff.scroll > #currentMenu - stuff.drawHiddenOffset then - stuff.scroll = #currentMenu - stuff.drawHiddenOffset - elseif stuff.scroll < 1 and #currentMenu > 0 then - stuff.scroll = 1 + stuff.menuData.header = f.str_data[f.value + 1] end + end) + menu_configuration_features.headerfeat:set_str_data({"NONE", table.unpack(stuff.menuData.files.headers)}) - -- header border - scriptdraw.draw_rect(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, (stuff.menuData.pos_y + stuff.menuData.border/2)*-2+1), cheeseUtils.memoize.v2(stuff.menuData.width*2, stuff.menuData.border*2), func.convert_rgba_to_int(stuff.menuData.color.border.r, stuff.menuData.color.border.g, stuff.menuData.color.border.b, stuff.menuData.color.border.a)) + menu_configuration_features.layoutParent = menu.add_feature("Layout", "parent", menu_configuration_features.cheesemenuparent.id) - local hiddenOffset = 0 - local drawnfeats = 0 - stuff.menuData.text_size = (((graphics.get_screen_width()*graphics.get_screen_height())/3686400)*0.45+0.25) -- * stuff.menuData.text_size_modifier + menu_configuration_features.maxfeats = menu.add_feature("Max features", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData:set_max_features(f.value) + end) + menu_configuration_features.maxfeats.max = 50 + menu_configuration_features.maxfeats.mod = 1 + menu_configuration_features.maxfeats.min = 1 + menu_configuration_features.maxfeats.value = math.floor(stuff.menuData.max_features) - stuff.drawFeatParams.rectPos.x = stuff.menuData.pos_x - stuff.drawFeatParams.rectPos.y = stuff.menuData.pos_y - stuff.menuData.feature_offset/2 + stuff.menuData.border - stuff.drawFeatParams.textOffset.x = stuff.menuData.feature_scale.x/2 - stuff.drawFeatParams.colorText = stuff.menuData.color.text - stuff.drawFeatParams.colorFeature = stuff.menuData.color.feature - stuff.drawFeatParams.textSize = stuff.menuData.text_size * stuff.menuData.text_size_modifier + menu_configuration_features.menuWidth = menu.add_feature("Menu width", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.width = f.value/graphics.get_screen_width() + end) + menu_configuration_features.menuWidth.max = graphics.get_screen_width() + menu_configuration_features.menuWidth.mod = 1 + menu_configuration_features.menuWidth.min = -graphics.get_screen_width() + menu_configuration_features.menuWidth.value = math.floor(stuff.menuData.width*graphics.get_screen_width()) - for k, v in ipairs(currentMenu) do - if type(k) == "number" then - if v.hidden or (v.type >> 11 & 1 ~= 0 and not v.on) then - hiddenOffset = hiddenOffset + 1 - elseif k <= stuff.drawScroll + hiddenOffset + stuff.menuData.max_features and k >= stuff.drawScroll + hiddenOffset + 1 then - func.draw_feat(k - stuff.drawScroll - hiddenOffset, v, 0, hiddenOffset) - drawnfeats = drawnfeats + 1 - end - end - end + menu_configuration_features.featXfeat = menu.add_feature("Feature dimensions X", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.feature_scale.x = f.value/graphics.get_screen_width() + end) + menu_configuration_features.featXfeat.max = graphics.get_screen_width() + menu_configuration_features.featXfeat.mod = 1 + menu_configuration_features.featXfeat.min = -graphics.get_screen_width() + menu_configuration_features.featXfeat.value = math.floor(stuff.menuData.feature_scale.x*graphics.get_screen_width()) - if stuff.menuData.footer.draw_footer then - -- footer border - local footer_border_y_pos - if stuff.menuData.footer.footer_pos_related_to_background then - footer_border_y_pos = (stuff.menuData.pos_y + stuff.menuData.height + stuff.menuData.border*1.5)*-2+1 - else - footer_border_y_pos = (stuff.menuData.pos_y + (drawnfeats*stuff.menuData.feature_offset) + stuff.menuData.border*1.5)*-2+1 - end - scriptdraw.draw_rect(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, footer_border_y_pos), cheeseUtils.memoize.v2(stuff.menuData.width*2, stuff.menuData.border*2), func.convert_rgba_to_int(stuff.menuData.color.border.r, stuff.menuData.color.border.g, stuff.menuData.color.border.b, stuff.menuData.color.border.a)) + menu_configuration_features.featYfeat = menu.add_feature("Feature dimensions Y", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.feature_scale.y = f.value/graphics.get_screen_height() + end) + menu_configuration_features.featYfeat.max = graphics.get_screen_height() + menu_configuration_features.featYfeat.mod = 1 + menu_configuration_features.featYfeat.min = -graphics.get_screen_height() + menu_configuration_features.featYfeat.value = math.floor(stuff.menuData.feature_scale.y*graphics.get_screen_height()) - -- footer and text/scroll - local footerColor = func.convert_rgba_to_int(stuff.menuData.color.footer.r, stuff.menuData.color.footer.g, stuff.menuData.color.footer.b, stuff.menuData.color.footer.a) - local footer_y_pos - if stuff.menuData.footer.footer_pos_related_to_background then - footer_y_pos = (stuff.menuData.pos_y + stuff.menuData.height + stuff.menuData.border*2 + stuff.menuData.footer.footer_size/2)*-2+1 - else - footer_y_pos = (stuff.menuData.pos_y + (drawnfeats*stuff.menuData.feature_offset) + stuff.menuData.border*2 + stuff.menuData.footer.footer_size/2)*-2+1 - end - scriptdraw.draw_rect(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, footer_y_pos), cheeseUtils.memoize.v2(stuff.menuData.width*2, stuff.menuData.footer.footer_size*2), footerColor) + menu_configuration_features.feature_offset = menu.add_feature("Feature spacing", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.feature_offset = f.value/graphics.get_screen_height() + menu_configuration_features.maxfeats:toggle() + end) + menu_configuration_features.feature_offset.max = graphics.get_screen_height() + menu_configuration_features.feature_offset.mod = 1 + menu_configuration_features.feature_offset.min = -graphics.get_screen_height() + menu_configuration_features.feature_offset.value = math.floor(stuff.menuData.feature_offset*graphics.get_screen_height()) - local footerTextColor = func.convert_rgba_to_int(stuff.menuData.color.footer_text.r, stuff.menuData.color.footer_text.g, stuff.menuData.color.footer_text.b, stuff.menuData.color.footer_text.a) - local feat = currentMenu[stuff.scroll + stuff.scrollHiddenOffset] - local featHint = feat.type >> 15 & 1 ~= 0 and stuff.player_feature_hints[feat.id] or stuff.feature_hints[feat.id] - if featHint then - local padding = scriptdraw.size_pixel_to_rel_y(5) - local hintStrSize = scriptdraw.size_pixel_to_rel_y(featHint.size.y) * (stuff.menuData.text_size * stuff.menuData.hint_size_modifier) - local posY = footer_y_pos - stuff.menuData.border*2 - stuff.menuData.footer.footer_size - padding - local textY = posY - padding - posY = posY - hintStrSize/2 + menu_configuration_features.text_size = menu.add_feature("Text Size", "autoaction_value_f", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.text_size_modifier = f.value + end) + menu_configuration_features.text_size.max = 5 + menu_configuration_features.text_size.mod = 0.01 + menu_configuration_features.text_size.min = 0.1 + menu_configuration_features.text_size.value = stuff.menuData.text_size_modifier - local rectHeight = hintStrSize+padding*4 - --scriptdraw.draw_rect(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, posY+rectHalfHeight/2), cheeseUtils.memoize.v2(stuff.menuData.width*2, rectHalfHeight), func.convert_rgba_to_int(stuff.menuData.color.footer.r, stuff.menuData.color.footer.g, stuff.menuData.color.footer.b, stuff.menuData.color.footer.a)) - cheeseUtils.draw_rect_ext_wh(cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1, posY-padding), cheeseUtils.memoize.v2(stuff.menuData.width*2, rectHeight), (footerColor & 0xffffff) | 50 << 24, footerColor, footerColor, (footerColor & 0xffffff) | 50 << 24) - scriptdraw.draw_text( - featHint.str, - cheeseUtils.memoize.v2(stuff.menuData.pos_x*2-1 - stuff.menuData.width + padding, textY), - cheeseUtils.memoize.v2(stuff.menuData.width+padding*2, 2), - stuff.menuData.text_size * stuff.menuData.hint_size_modifier, - footerTextColor, - 0, - stuff.menuData.fonts.hint - ) - end + menu_configuration_features.footer_size = menu.add_feature("Footer Text Size", "autoaction_value_f", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.footer_size_modifier = f.value + end) + menu_configuration_features.footer_size.max = 5 + menu_configuration_features.footer_size.mod = 0.01 + menu_configuration_features.footer_size.min = 0.1 + menu_configuration_features.footer_size.value = stuff.menuData.footer_size_modifier - local footer_size = stuff.menuData.text_size * stuff.menuData.footer_size_modifier - local text_y_pos = footer_y_pos + 0.011111111 + stuff.menuData.footer.footer_y_offset - scriptdraw.draw_text( - tostring(stuff.menuData.footer.footer_text), - cheeseUtils.memoize.v2((stuff.menuData.pos_x - stuff.menuData.width/2 + stuff.menuData.footer.padding)*2-1, text_y_pos), - cheeseUtils.memoize.v2(2, 2), - footer_size, - footerTextColor, - 0, - stuff.menuData.fonts.footer - ) + menu_configuration_features.hint_size = menu.add_feature("Hint Text Size", "autoaction_value_f", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.hint_size_modifier = f.value + func.rewrap_hints(stuff.menuData.fonts.hint) + end) + menu_configuration_features.hint_size.max = 5 + menu_configuration_features.hint_size.mod = 0.01 + menu_configuration_features.hint_size.min = 0.1 + menu_configuration_features.hint_size.value = stuff.menuData.hint_size_modifier + + menu_configuration_features.text_y_offset = menu.add_feature("Text Y Offset", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) + stuff.drawFeatParams.textOffset.y = -(f.value/graphics.get_screen_height()) + stuff.menuData.text_y_offset = -(f.value/graphics.get_screen_height()) + end) + menu_configuration_features.text_y_offset.max = 100 + menu_configuration_features.text_y_offset.mod = 1 + menu_configuration_features.text_y_offset.min = -100 + menu_configuration_features.text_y_offset.value = -math.floor(stuff.menuData.text_y_offset*graphics.get_screen_height()) + + menu_configuration_features.border = menu.add_feature("Border", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.border = f.value/graphics.get_screen_height() + end) + menu_configuration_features.border.max = graphics.get_screen_height() + menu_configuration_features.border.mod = 1 + menu_configuration_features.border.min = -graphics.get_screen_height() + menu_configuration_features.border.value = math.floor(stuff.menuData.border*graphics.get_screen_height()) + + menu_configuration_features.selector_speed = menu.add_feature("Selector Speed", "autoaction_value_f", menu_configuration_features.layoutParent.id, function(f) + stuff.menuData.selector_speed = f.value + end) + menu_configuration_features.selector_speed.max = 10 + menu_configuration_features.selector_speed.mod = 0.1 + menu_configuration_features.selector_speed.min = 0.2 + menu_configuration_features.selector_speed.value = stuff.menuData.selector_speed + + -- Online Player Submenu Sorting + menu_configuration_features.player_submenu_sort = menu.add_feature("Online Players Sort:", "autoaction_value_str", menu_configuration_features.layoutParent.id, function(f) + table.sort(stuff.PlayerParent, stuff.table_sort_functions[f.value]) + stuff.player_submenu_sort = f.value + end) + menu_configuration_features.player_submenu_sort:set_str_data({'PID', 'PID Reversed', 'Alphabetically', 'Alphabetically Reversed', 'Host Priority', 'Host Priority Reversed'}) + menu_configuration_features.player_submenu_sort.value = stuff.player_submenu_sort + + -- Padding + menu_configuration_features.padding_parent = menu.add_feature("Padding", "parent", menu_configuration_features.layoutParent.id) + + menu_configuration_features.namePadding = menu.add_feature("Name Padding", "autoaction_value_i", menu_configuration_features.padding_parent.id, function(f) + stuff.menuData.padding.name = f.value/graphics.get_screen_width() + end) + menu_configuration_features.namePadding.max = graphics.get_screen_width() + menu_configuration_features.namePadding.mod = 1 + menu_configuration_features.namePadding.min = -graphics.get_screen_width() + menu_configuration_features.namePadding.value = math.floor(stuff.menuData.padding.name*graphics.get_screen_width()) + + menu_configuration_features.parentPadding = menu.add_feature("Parent Padding", "autoaction_value_i", menu_configuration_features.padding_parent.id, function(f) + stuff.menuData.padding.parent = f.value/graphics.get_screen_width() + end) + menu_configuration_features.parentPadding.max = graphics.get_screen_width() + menu_configuration_features.parentPadding.mod = 1 + menu_configuration_features.parentPadding.min = -graphics.get_screen_width() + menu_configuration_features.parentPadding.value = math.floor(stuff.menuData.padding.parent*graphics.get_screen_width()) + + menu_configuration_features.valuePadding = menu.add_feature("Value Padding", "autoaction_value_i", menu_configuration_features.padding_parent.id, function(f) + stuff.menuData.padding.value = f.value/graphics.get_screen_width() + end) + menu_configuration_features.valuePadding.max = graphics.get_screen_width() + menu_configuration_features.valuePadding.mod = 1 + menu_configuration_features.valuePadding.min = -graphics.get_screen_width() + menu_configuration_features.valuePadding.value = math.floor(stuff.menuData.padding.value*graphics.get_screen_width()) - scriptdraw.draw_text( - tostring(stuff.scroll.." / "..(#currentMenu - stuff.drawHiddenOffset)), - cheeseUtils.memoize.v2((stuff.menuData.pos_x + stuff.menuData.width/2 - stuff.menuData.footer.padding)*2-1, text_y_pos), - cheeseUtils.memoize.v2(2, 2), - footer_size, - footerTextColor, - 16, - stuff.menuData.fonts.footer - ) - end + menu_configuration_features.sliderPadding = menu.add_feature("Slider Padding", "autoaction_value_i", menu_configuration_features.padding_parent.id, function(f) + stuff.menuData.padding.slider = f.value/graphics.get_screen_width() + end) + menu_configuration_features.sliderPadding.max = graphics.get_screen_width() + menu_configuration_features.sliderPadding.mod = 1 + menu_configuration_features.sliderPadding.min = -graphics.get_screen_width() + menu_configuration_features.sliderPadding.value = math.floor(stuff.menuData.padding.slider*graphics.get_screen_width()) - if type(sprite) == "table" then - if not sprite[stuff.draw_current_menu.frameCounter] then - stuff.draw_current_menu.frameCounter = 1 - end - if utils.time_ms() > stuff.draw_current_menu.time then - if stuff.draw_current_menu.frameCounter < #sprite then - stuff.draw_current_menu.frameCounter = stuff.draw_current_menu.frameCounter + 1 - else - stuff.draw_current_menu.frameCounter = 1 - end - stuff.draw_current_menu.time = utils.time_ms() + (sprite[stuff.draw_current_menu.frameCounter].delay or sprite.constant_delay or 33) - end - sprite = sprite[stuff.draw_current_menu.frameCounter].sprite - end - if sprite then - local size = ((2.56 * stuff.menuData.width) * (1000 / scriptdraw.get_sprite_size(sprite).x)) / (2560 / graphics.get_screen_width()) - scriptdraw.draw_sprite(sprite, cheeseUtils.memoize.v2(stuff.menuData.pos_x * 2 - 1, ((stuff.menuData.pos_y+stuff.menuData.height/2) - (stuff.menuData.height/2 + ((scriptdraw.get_sprite_size(sprite).y*size)/2)/graphics.get_screen_height()))*-2+1), size, 0, stuff.menuData.color.sprite) - end - system.wait(0) - end + -- Slider dimensions + menu_configuration_features.slider_parent = menu.add_feature("Slider", "parent", menu_configuration_features.layoutParent.id) - --[[ - example of table_of_lines: - { - {"leftside", "rightside"}, - {"IP", "ddosing u rn"}, - {"Cheesus", "Christ"} - } - has to be in this structure, you can add more than three - ]] - function func.draw_side_window(header_text, table_of_lines, v2pos, rect_color, rect_width, text_spacing, text_padding, text_color) - text_color = text_color or 0xFFFFFFFF - assert( - type(header_text) == "string" - and type(table_of_lines) == "table" - and type(v2pos) == "userdata" - and type(rect_color) == "number" - and type(rect_width) == "number" - and type(text_spacing) == "number" - and type(text_padding) == "number" - and type(text_color) == "number", - "one or more draw_side_window args were invalid" - ) - local rect_height = #table_of_lines*text_spacing+0.07125 - v2pos.y = v2pos.y-(rect_height/2) + menu_configuration_features.sliderWidth = menu.add_feature("Slider Width", "autoaction_value_i", menu_configuration_features.slider_parent.id, function(f) + stuff.menuData.slider.width = f.value/graphics.get_screen_width() + end) + menu_configuration_features.sliderWidth.max = graphics.get_screen_width() + menu_configuration_features.sliderWidth.mod = 1 + menu_configuration_features.sliderWidth.min = -graphics.get_screen_width() + menu_configuration_features.sliderWidth.value = math.floor(stuff.menuData.slider.width*graphics.get_screen_width()) + menu_configuration_features.sliderHeight = menu.add_feature("Slider Height", "autoaction_value_i", menu_configuration_features.slider_parent.id, function(f) + stuff.menuData.slider.height = f.value/graphics.get_screen_height() + end) + menu_configuration_features.sliderHeight.max = graphics.get_screen_height() + menu_configuration_features.sliderHeight.mod = 1 + menu_configuration_features.sliderHeight.min = -graphics.get_screen_height() + menu_configuration_features.sliderHeight.value = math.floor(stuff.menuData.slider.height*graphics.get_screen_height()) - scriptdraw.draw_rect(v2pos, cheeseUtils.memoize.v2(rect_width, rect_height), rect_color) + menu_configuration_features.sliderheightActive = menu.add_feature("Slider Height Active", "autoaction_value_i", menu_configuration_features.slider_parent.id, function(f) + stuff.menuData.slider.heightActive = f.value/graphics.get_screen_height() + end) + menu_configuration_features.sliderheightActive.max = graphics.get_screen_height() + menu_configuration_features.sliderheightActive.mod = 1 + menu_configuration_features.sliderheightActive.min = -graphics.get_screen_height() + menu_configuration_features.sliderheightActive.value = math.floor(stuff.menuData.slider.heightActive*graphics.get_screen_height()) - local text_size = graphics.get_screen_width()*graphics.get_screen_height()/3686400*0.75+0.25 - -- Header text - scriptdraw.draw_text(header_text, cheeseUtils.memoize.v2(v2pos.x - scriptdraw.get_text_size(header_text, text_size, 0).x/graphics.get_screen_width(), v2pos.y+(rect_height/2)-0.015), cheeseUtils.memoize.v2(2, 2), text_size, text_color, 0, 0) - -- table_of_lines - for k, v in ipairs(table_of_lines) do - v[1] = tostring(v[1]) - v[2] = tostring(v[2]) - local pos_y = v2pos.y-k*text_spacing+rect_height/2-0.03 - scriptdraw.draw_text(v[1], cheeseUtils.memoize.v2(v2pos.x-rect_width/2+text_padding, pos_y), cheeseUtils.memoize.v2(2, 2), text_size, text_color, 0, 2) - scriptdraw.draw_text(v[2], cheeseUtils.memoize.v2(v2pos.x+rect_width/2-text_padding, pos_y), cheeseUtils.memoize.v2(2, 2), text_size, text_color, 16, 2) - end - end + -- Controls + menu_configuration_features.controls = menu.add_feature("Controls", "parent", menu_configuration_features.cheesemenuparent.id) - --Hotkey functions - function func.get_hotkey(keyTable, vkTable, singlekey) - local current_key - local excludedkeys = {} - while not keyTable[1] do - if cheeseUtils.get_key(0x1B):is_down() then - return "escaped" - end - for k, v in pairs(stuff.char_codes) do - if cheeseUtils.get_key(v):is_down() then - if v ~= 0x0D or singlekey then - if v ~= 0xA0 and v ~= 0xA1 and v ~= 0xA2 and v ~= 0xA3 and v ~= 0xA4 and v ~= 0xA5 and not singlekey then - keyTable[1] = "NOMOD" - end - if singlekey then - return k, v - else - keyTable[#keyTable + 1] = k - vkTable[#vkTable+1] = v - current_key = v - excludedkeys[v] = true + for k, v in pairs(stuff.controls) do + menu.add_feature(k, "action_value_str", menu_configuration_features.controls.id, function(f) + for k, v in pairs(stuff.char_codes) do + while cheeseUtils.get_key(v):is_down() do + system.wait(0) end end - end + menu.notify("Press any button\nESC to cancel", "Cheese Menu", 3, func.convert_rgba_to_int(stuff.menuData.color.notifications.r, stuff.menuData.color.notifications.g, stuff.menuData.color.notifications.b, stuff.menuData.color.notifications.a)) + local disablethread = menu.create_thread(stuff.disable_all_controls, nil) + local stringkey, vk = func.get_hotkey({}, {}, true) + if stringkey ~= "escaped" then + stuff.controls[k] = stringkey + stuff.vkcontrols[k] = vk + f:set_str_data({stringkey}) + end + menu.delete_thread(disablethread) + end):set_str_data({v}) end - system.wait(0) - end - if not singlekey then - while cheeseUtils.get_key(current_key):is_down() do - for k, v in pairs(stuff.char_codes) do - if cheeseUtils.get_key(v):is_down() and not excludedkeys[v] and v ~= 0xA0 and v ~= 0xA1 and v ~= 0xA2 and v ~= 0xA3 and v ~= 0xA4 and v ~= 0xA5 then - excludedkeys[v] = true - keyTable[#keyTable + 1] = k - vkTable[#vkTable+1] = v - end + -- Player Info + menu_configuration_features.side_window = menu.add_feature("Player Info Window", "parent", menu_configuration_features.cheesemenuparent.id) + + -- On + menu_configuration_features.side_window_on = menu.add_feature("Draw", "toggle", menu_configuration_features.side_window.id, function(f) + stuff.menuData.side_window.on = f.on + end) + menu_configuration_features.side_window_on.on = stuff.menuData.side_window.on + + -- Offset + menu_configuration_features.side_window_offsetx = menu.add_feature("X Offset", "autoaction_value_i", menu_configuration_features.side_window.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.side_window.offset.x = num/graphics.get_screen_height() + f.value = num end - system.wait(0) end + stuff.menuData.side_window.offset.x = f.value/graphics.get_screen_width() + end) + menu_configuration_features.side_window_offsetx.max = graphics.get_screen_width() + menu_configuration_features.side_window_offsetx.mod = 1 + menu_configuration_features.side_window_offsetx.min = -graphics.get_screen_width() + menu_configuration_features.side_window_offsetx.value = math.floor(stuff.menuData.side_window.offset.x*graphics.get_screen_width()) - while not cheeseUtils.get_key(0x1B):is_down() and not cheeseUtils.get_key(0x0D):is_down() do - for k, v in pairs(stuff.char_codes) do - if cheeseUtils.get_key(v):is_down() then - return false - end + menu_configuration_features.side_window_offsety = menu.add_feature("Y Offset", "autoaction_value_i", menu_configuration_features.side_window.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.side_window.offset.y = num/graphics.get_screen_height() + f.value = num end - system.wait(0) end + stuff.menuData.side_window.offset.y = f.value/graphics.get_screen_height() + end) + menu_configuration_features.side_window_offsety.max = graphics.get_screen_height() + menu_configuration_features.side_window_offsety.mod = 1 + menu_configuration_features.side_window_offsety.min = -graphics.get_screen_height() + menu_configuration_features.side_window_offsety.value = math.floor(stuff.menuData.side_window.offset.y*graphics.get_screen_height()) - return cheeseUtils.get_key(0x0D):is_down() or "escaped" - end - end + -- Spacing + menu_configuration_features.side_window_spacing = menu.add_feature("Spacing", "autoaction_value_i", menu_configuration_features.side_window.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.side_window.spacing = num/graphics.get_screen_height() + f.value = num + end + end + stuff.menuData.side_window.spacing = f.value/graphics.get_screen_height() + end) + menu_configuration_features.side_window_spacing.max = graphics.get_screen_height() + menu_configuration_features.side_window_spacing.mod = 1 + menu_configuration_features.side_window_spacing.min = -graphics.get_screen_height() + menu_configuration_features.side_window_spacing.value = math.floor(stuff.menuData.side_window.spacing*graphics.get_screen_height()) - function func.draw_hotkey(keyTable) - while true do - for i = 0, 360 do - controls.disable_control_action(0, i, true) + -- Padding + menu_configuration_features.side_window_padding = menu.add_feature("Padding", "autoaction_value_i", menu_configuration_features.side_window.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.side_window.padding = num/graphics.get_screen_height() + f.value = num + end end - local concatenated = table.concat(keyTable, "+") - scriptdraw.draw_rect(cheeseUtils.memoize.v2(0, 0), cheeseUtils.memoize.v2(2, 2), 0x7D000000) - scriptdraw.draw_text(concatenated, cheeseUtils.memoize.v2(-(scriptdraw.get_text_size(concatenated, 1, 0).x/graphics.get_screen_width())), cheeseUtils.memoize.v2(2, 2), 1, 0xffffffff, 1 << 1, 0) - system.wait(0) - end - end + stuff.menuData.side_window.padding = f.value/graphics.get_screen_width() + end) + menu_configuration_features.side_window_padding.max = graphics.get_screen_width() + menu_configuration_features.side_window_padding.mod = 1 + menu_configuration_features.side_window_padding.min = -graphics.get_screen_width() + menu_configuration_features.side_window_padding.value = math.floor(stuff.menuData.side_window.padding*graphics.get_screen_width()) + -- Width + menu_configuration_features.side_window_width = menu.add_feature("Width", "autoaction_value_i", menu_configuration_features.side_window.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.side_window.width = num/graphics.get_screen_height() + f.value = num + end + end + stuff.menuData.side_window.width = f.value/graphics.get_screen_width() + end) + menu_configuration_features.side_window_width.max = graphics.get_screen_width() + menu_configuration_features.side_window_width.mod = 1 + menu_configuration_features.side_window_width.min = -graphics.get_screen_width() + menu_configuration_features.side_window_width.value = math.floor(stuff.menuData.side_window.width*graphics.get_screen_width()) - function func.start_hotkey_process(feat) - stuff.menuData.menuToggle = false - local keyTable = {} - local vkTable = {} + -- End of Player Info - local drawThread = menu.create_thread(func.draw_hotkey, keyTable) - while cheeseUtils.get_key(stuff.vkcontrols.setHotkey):is_down() do - system.wait(0) - end + -- Background + menu_configuration_features.backgroundparent = menu.add_feature("Background", "parent", menu_configuration_features.cheesemenuparent.id) - local response - repeat - response = func.get_hotkey(keyTable, vkTable) - if not response then - for k, v in pairs(keyTable) do - keyTable[k] = nil + menu_configuration_features.backgroundfeat = menu.add_feature("Background", "autoaction_value_str", menu_configuration_features.backgroundparent.id, function(f) + if f.str_data[f.value + 1] == "NONE" then + stuff.menuData.background_sprite.sprite = nil + else + stuff.menuData.background_sprite.sprite = f.str_data[f.value + 1] end - for k, v in pairs(vkTable) do - vkTable[k] = nil + end) + menu_configuration_features.backgroundfeat:set_str_data({"NONE", table.unpack(stuff.menuData.files.background)}) + + menu.add_feature("Fit background to width", "action", menu_configuration_features.backgroundparent.id, function() + if stuff.menuData.background_sprite.sprite then + stuff.menuData.background_sprite:fit_size_to_width() end - end - until response + end) - local keyString = table.concat(keyTable, "|") + menu_configuration_features.backgroundoffsetx = menu.add_feature("Background pos X", "autoaction_value_i", menu_configuration_features.backgroundparent.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.background_sprite.offset.x = num/graphics.get_screen_width() + f.value = num + end + end + stuff.menuData.background_sprite.offset.x = f.value/graphics.get_screen_width() + end) + menu_configuration_features.backgroundoffsetx.max = graphics.get_screen_width() + menu_configuration_features.backgroundoffsetx.mod = 1 + menu_configuration_features.backgroundoffsetx.min = -graphics.get_screen_width() + menu_configuration_features.backgroundoffsetx.value = math.floor(stuff.menuData.background_sprite.offset.x*graphics.get_screen_width()) - if response ~= "escaped" then - stuff.hotkeys_to_vk[keyString] = vkTable - if not stuff.hotkeys[keyString] then - stuff.hotkeys[keyString] = {} - end - stuff.hotkeys[keyString][feat.hierarchy_key] = true - feat.hotkey = keyString - gltw.write(stuff.hotkeys, "hotkeys", stuff.path.hotkeys, nil, true) - end + menu_configuration_features.backgroundoffsety = menu.add_feature("Background pos Y", "autoaction_value_i", menu_configuration_features.backgroundparent.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.background_sprite.offset.y = num/graphics.get_screen_height() + f.value = num + end + end + stuff.menuData.background_sprite.offset.y = f.value/graphics.get_screen_height() + end) + menu_configuration_features.backgroundoffsety.max = graphics.get_screen_height() + menu_configuration_features.backgroundoffsety.mod = 1 + menu_configuration_features.backgroundoffsety.min = -graphics.get_screen_height() + menu_configuration_features.backgroundoffsety.value = math.floor(stuff.menuData.background_sprite.offset.y*graphics.get_screen_height()) - menu.delete_thread(drawThread) - while cheeseUtils.get_key(0x0D):is_down() or cheeseUtils.get_key(0x1B):is_down() do -- enter and esc - controls.disable_control_action(0, 200, true) - system.wait(0) - end - controls.disable_control_action(0, 200, true) - func.toggle_menu(true) - return response ~= "escaped" and response - end + menu_configuration_features.backgroundsize = menu.add_feature("Background Size", "autoaction_value_f", menu_configuration_features.backgroundparent.id, function(f) + stuff.menuData.background_sprite.size = f.value + end) + menu_configuration_features.backgroundsize.max = 1 + menu_configuration_features.backgroundsize.mod = 0.01 + menu_configuration_features.backgroundsize.value = stuff.menuData.background_sprite.size - --End of functions + -- Footer + menu_configuration_features.footer = menu.add_feature("Footer", "parent", menu_configuration_features.cheesemenuparent.id) - --threads - menu.create_thread(function() - local side_window_pos = v2((stuff.menuData.pos_x + stuff.menuData.width + stuff.menuData.side_window.offset.x)*2-1, (stuff.menuData.pos_y + stuff.menuData.side_window.offset.y)*-2+1) - while true do - if stuff.menuData.menuToggle then - func.draw_current_menu() - if currentMenu and stuff.menuData.side_window.on then - local pid = currentMenu.pid - if not pid and currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then - pid = currentMenu[stuff.scroll + stuff.scrollHiddenOffset].pid - end - if pid and pid ~= stuff.pid then - if not stuff.playerIds[pid].hidden then - stuff.player_info[1][2] = tostring(pid) - stuff.player_info[10][2] = func.convert_int_ip(player.get_player_ip(pid)) - stuff.player_info[11][2] = tostring(player.get_player_scid(pid)) - stuff.player_info[12][2] = string.format("%X", player.get_player_host_token(pid)) - stuff.player_info.max_health = "/"..math.floor(player.get_player_max_health(pid)) - stuff.player_info.name = tostring(player.get_player_name(pid)) - stuff.pid = pid - end - end - if pid then - side_window_pos.x, side_window_pos.y = (stuff.menuData.pos_x + stuff.menuData.width + stuff.menuData.side_window.offset.x)*2-1, (stuff.menuData.pos_y + stuff.menuData.side_window.offset.y)*-2+1 - native.call(0xBE8CD9BE829BBEBF, player.get_player_ped(stuff.pid), stuff.proofs.bulletProof, stuff.proofs.fireProof, stuff.proofs.explosionProof, stuff.proofs.collisionProof, stuff.proofs.meleeProof, stuff.proofs.steamProof, stuff.proofs.p7, stuff.proofs.drownProof) - stuff.player_info[2][2] = player.is_player_god(stuff.pid) and "Yes" or "No" - stuff.player_info[3][2] = (stuff.proofs.bulletProof:__tointeger()|stuff.proofs.fireProof:__tointeger()|stuff.proofs.explosionProof:__tointeger()|stuff.proofs.collisionProof:__tointeger()|stuff.proofs.meleeProof:__tointeger()|stuff.proofs.steamProof:__tointeger()|stuff.proofs.p7:__tointeger()|stuff.proofs.drownProof:__tointeger()) == 1 and "Yes" or "No" - stuff.player_info[4][2] = player.is_player_vehicle_god(stuff.pid) and "Yes" or "No" - stuff.player_info[5][2] = player.is_player_modder(stuff.pid, -1) and "Yes" or "No" - stuff.player_info[6][2] = player.is_player_host(stuff.pid) and "Yes" or "No" - stuff.player_info[7][2] = player.get_player_wanted_level(stuff.pid) - stuff.player_info[8][2] = math.floor(player.get_player_health(stuff.pid))..stuff.player_info.max_health - stuff.player_info[9][2] = math.floor(player.get_player_armour(stuff.pid)).."/50" - stuff.player_info[13][2] = player.get_player_host_priority(stuff.pid) - func.draw_side_window( - stuff.player_info.name, - stuff.player_info, - side_window_pos, - func.convert_rgba_to_int(stuff.menuData.color.side_window.r, stuff.menuData.color.side_window.g, stuff.menuData.color.side_window.b, stuff.menuData.color.side_window.a), - stuff.menuData.side_window.width, stuff.menuData.side_window.spacing, stuff.menuData.side_window.padding, - func.convert_rgba_to_int(stuff.menuData.color.side_window_text.r, stuff.menuData.color.side_window_text.g, stuff.menuData.color.side_window_text.b, stuff.menuData.color.side_window_text.a) - ) + menu_configuration_features.footer_size = menu.add_feature("Footer Size", "autoaction_value_i", menu_configuration_features.footer.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.footer.footer_size = num/graphics.get_screen_height() + f.value = num end end - if stuff.old_selected ~= currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then - if type(stuff.old_selected) == "table" then - stuff.old_selected:activate_hl_func() - end - if currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then - currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() + stuff.menuData.footer.footer_size = f.value/graphics.get_screen_height() + end) + menu_configuration_features.footer_size.max = graphics.get_screen_height() + menu_configuration_features.footer_size.mod = 1 + menu_configuration_features.footer_size.min = 0 + menu_configuration_features.footer_size.value = math.floor(stuff.menuData.footer.footer_size*graphics.get_screen_height()) + + menu_configuration_features.footer_y_offset = menu.add_feature("Footer Y Offset", "autoaction_value_i", menu_configuration_features.footer.id, function(f) + stuff.menuData.footer.footer_y_offset = (f.value/graphics.get_screen_height()) + end) + menu_configuration_features.footer_y_offset.max = 100 + menu_configuration_features.footer_y_offset.mod = 1 + menu_configuration_features.footer_y_offset.min = -100 + menu_configuration_features.footer_y_offset.value = math.floor(stuff.menuData.footer.footer_y_offset*graphics.get_screen_height()) + + menu_configuration_features.footerPadding = menu.add_feature("Padding", "autoaction_value_i", menu_configuration_features.footer.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + stuff.menuData.footer.padding = num/graphics.get_screen_width() + f.value = num end - stuff.old_selected = currentMenu[stuff.scroll + stuff.scrollHiddenOffset] end - controls.disable_control_action(0, 172, true) - controls.disable_control_action(0, 27, true) - else - system.wait(0) - end - end - end, nil) + stuff.menuData.footer.padding = f.value/graphics.get_screen_width() + end) + menu_configuration_features.footerPadding.max = graphics.get_screen_width() + menu_configuration_features.footerPadding.mod = 1 + menu_configuration_features.footerPadding.min = -graphics.get_screen_width() + menu_configuration_features.footerPadding.value = math.floor(stuff.menuData.footer.padding*graphics.get_screen_width()) - menu.create_thread(function() - while true do - stuff.menuData.menuNav = native.call(0x5FCF4D7069B09026):__tointeger() ~= 1 and not (stuff.menuData.chatBoxOpen or input.is_open() --[[or console.on]]) - if stuff.menuData.menuNav then - func.do_key(500, stuff.vkcontrols.open, false, function() -- F4 - func.toggle_menu(not stuff.menuData.menuToggle) - end) - end - if currentMenu.hidden or not currentMenu then - currentMenu = stuff.previousMenus[#stuff.previousMenus].menu - stuff.scroll = stuff.previousMenus[#stuff.previousMenus].scroll - stuff.drawScroll = stuff.previousMenus[#stuff.previousMenus].drawScroll - stuff.scrollHiddenOffset = stuff.previousMenus[#stuff.previousMenus].scrollHiddenOffset - stuff.previousMenus[#stuff.previousMenus] = nil - end - local pid = player.player_id() - stuff.playerIds[pid].name = player.get_player_name(pid).." [Y]" - if stuff.playerIds[pid].hidden then - stuff.playerIds[pid].hidden = false - func.reset_player_submenu(pid) - end - system.wait(0) - end - end, nil) - menu.create_thread(function() - while true do - system.wait(0) - if stuff.menuData.menuToggle and stuff.menuData.menuNav then - func.do_key(500, stuff.vkcontrols.setHotkey, false, function() -- F11 - if cheeseUtils.get_key(0x10):is_down() and stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey] then - stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey][currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hierarchy_key] = nil - if not next(stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey]) then - stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey] = nil - end - currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey = nil - gltw.write(stuff.hotkeys, "hotkeys", stuff.path.hotkeys, nil, true) - menu.notify("Removed "..currentMenu[stuff.scroll + stuff.scrollHiddenOffset].name.."'s hotkey") - elseif cheeseUtils.get_key(0x11):is_down() then - menu.notify(currentMenu[stuff.scroll + stuff.scrollHiddenOffset].name.."'s hotkey is "..(currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey or "none")) - elseif not cheeseUtils.get_key(0x10):is_down() and not cheeseUtils.get_key(0x11):is_down() then - if stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey] then - stuff.hotkeys[currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey][currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hierarchy_key] = nil - end - if func.start_hotkey_process(currentMenu[stuff.scroll + stuff.scrollHiddenOffset]) then - menu.notify("Set "..currentMenu[stuff.scroll + stuff.scrollHiddenOffset].name.."'s hotkey to "..currentMenu[stuff.scroll + stuff.scrollHiddenOffset].hotkey) + menu_configuration_features.draw_footer = menu.add_feature("Draw footer", "toggle", menu_configuration_features.footer.id, function(f) + stuff.menuData.footer.draw_footer = f.on + end) + menu_configuration_features.draw_footer.on = stuff.menuData.footer.draw_footer + + menu_configuration_features.footer_pos_related_to_background = menu.add_feature("Footer position based on background", "toggle", menu_configuration_features.footer.id, function(f) + stuff.menuData.footer.footer_pos_related_to_background = f.on + end) + menu_configuration_features.footer_pos_related_to_background.on = stuff.menuData.footer.footer_pos_related_to_background + + menu_configuration_features.footer_text = menu.add_feature("Footer Text", "action", menu_configuration_features.footer.id, function() + local status, text = input.get("Footer Text", "", 50, 0) + if status == 0 then + stuff.menuData.footer.footer_text = tostring(text) + end + end) + + -- Fonts + local fontStrData = { + "Menu Head", + "Menu Tab", + "Menu Entry", + "Menu Foot", + "Script 1", + "Script 2", + "Script 3", + "Script 4", + "Script 5", + } + menu_configuration_features.fonts = menu.add_feature("Fonts", "parent", menu_configuration_features.cheesemenuparent.id) + + menu_configuration_features.text_font = menu.add_feature("Text Font", "autoaction_value_str", menu_configuration_features.fonts.id, function(f) + stuff.menuData.fonts.text = f.value + end) + menu_configuration_features.text_font:set_str_data(fontStrData) + menu_configuration_features.text_font.value = stuff.menuData.fonts.text + + menu_configuration_features.footer_font = menu.add_feature("Footer Font", "autoaction_value_str", menu_configuration_features.fonts.id, function(f) + stuff.menuData.fonts.footer = f.value + end) + menu_configuration_features.footer_font:set_str_data(fontStrData) + menu_configuration_features.footer_font.value = stuff.menuData.fonts.footer + + menu_configuration_features.hint_font = menu.add_feature("Hint Font", "autoaction_value_str", menu_configuration_features.fonts.id, function(f) + stuff.menuData.fonts.hint = f.value + func.rewrap_hints(f.value) + end) + menu_configuration_features.hint_font:set_str_data(fontStrData) + menu_configuration_features.hint_font.value = stuff.menuData.fonts.hint + + -- Hotkeys + menu_configuration_features.hotkeyparent = menu.add_feature("Hotkey notifications", "parent", menu_configuration_features.cheesemenuparent.id) + + menu.add_feature("Toggle notification", "toggle", menu_configuration_features.hotkeyparent.id, function(f) + stuff.hotkey_notifications.toggle = f.on + end).on = stuff.hotkey_notifications.toggle + menu.add_feature("Action notification", "toggle", menu_configuration_features.hotkeyparent.id, function(f) + stuff.hotkey_notifications.action = f.on + end).on = stuff.hotkey_notifications.action + + -- Colors + local colorParent = menu.add_feature("Colors", "parent", menu_configuration_features.cheesemenuparent.id) + do + local tempColor = {} + for k, v in pairs(stuff.menuData.color) do + tempColor[#tempColor+1] = {k, v, sortname = k:gsub("feature_([^s])", "feature_a%1")} + end + table.sort(tempColor, function(a, b) return a["sortname"] < b["sortname"] end) + + for _, v in pairs(tempColor) do + menu_configuration_features[v[1]] = {} + local vParent = menu.add_feature(v[1], "parent", colorParent.id) + + menu_configuration_features[v[1]].r = menu.add_feature("Red", "autoaction_value_i", vParent.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + f.value = num + end end + stuff.menuData.color:set_color(v[1], f.value) + end) + menu_configuration_features[v[1]].r.max = 255 + if type(v[2]) == "table" then + menu_configuration_features[v[1]].r.value = v[2].r + else + menu_configuration_features[v[1]].r.value = func.convert_int_to_rgba(v[2], "r") end - end) - end - end - end,nil) - menu.create_thread(function() - while true do - system.wait(0) - if stuff.menuData.menuToggle and stuff.menuData.menuNav then - func.do_key(500, stuff.vkcontrols.down, true, function() -- downKey - --[[ local old_scroll = stuff.scroll + stuff.scrollHiddenOffset ]] - if stuff.scroll + stuff.drawHiddenOffset >= #currentMenu and #currentMenu - stuff.drawHiddenOffset > 1 then - stuff.scroll = 1 - stuff.drawScroll = 0 - elseif #currentMenu - stuff.drawHiddenOffset > 1 then - stuff.scroll = stuff.scroll + 1 - if stuff.scroll - stuff.drawScroll >= (stuff.menuData.max_features - 1) and stuff.drawScroll < stuff.maxDrawScroll then - stuff.drawScroll = stuff.drawScroll + 1 + + menu_configuration_features[v[1]].g = menu.add_feature("Green", "autoaction_value_i", vParent.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + f.value = num + end end + stuff.menuData.color:set_color(v[1], nil, f.value) + end) + menu_configuration_features[v[1]].g.max = 255 + if type(v[2]) == "table" then + menu_configuration_features[v[1]].g.value = v[2].g + else + menu_configuration_features[v[1]].g.value = func.convert_int_to_rgba(v[2], "g") end - --[[ if old_scroll ~= (stuff.scroll + stuff.scrollHiddenOffset) then - currentMenu[old_scroll]:activate_hl_func() - if currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then - currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() - end - end ]] - end) - end - end - end, nil) - menu.create_thread(function() - while true do - system.wait(0) - if stuff.menuData.menuToggle and stuff.menuData.menuNav then - func.do_key(500, stuff.vkcontrols.up, true, function() -- upKey - --[[ local old_scroll = stuff.scroll + stuff.scrollHiddenOffset ]] - if stuff.scroll <= 1 and #currentMenu - stuff.drawHiddenOffset > 1 then - stuff.scroll = #currentMenu - stuff.drawScroll = stuff.maxDrawScroll - elseif #currentMenu - stuff.drawHiddenOffset > 1 then - stuff.scroll = stuff.scroll - 1 - if stuff.scroll - stuff.drawScroll <= 2 and stuff.drawScroll > 0 then - stuff.drawScroll = stuff.drawScroll - 1 + + menu_configuration_features[v[1]].b = menu.add_feature("Blue", "autoaction_value_i", vParent.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + f.value = num + end end + stuff.menuData.color:set_color(v[1], nil, nil, f.value) + end) + menu_configuration_features[v[1]].b.max = 255 + if type(v[2]) == "table" then + menu_configuration_features[v[1]].b.value = v[2].b + else + menu_configuration_features[v[1]].b.value = func.convert_int_to_rgba(v[2], "b") end - --[[ if old_scroll ~= (stuff.scroll + stuff.scrollHiddenOffset) then - currentMenu[old_scroll]:activate_hl_func() - if currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then - currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() - end - end ]] - end) - end - end - end,nil) - menu.create_thread(function() - while true do - system.wait(0) - if stuff.menuData.menuToggle and stuff.menuData.menuNav then - func.do_key(500, stuff.vkcontrols.select, true, function() --enter - local feat = currentMenu[stuff.scroll + stuff.scrollHiddenOffset] - if feat then - if cheeseUtils.get_key(stuff.vkcontrols.specialKey):is_down() and feat.type >> 5 & 1 ~= 0 then - menu.create_thread(func.selector, feat) - elseif feat.type >> 11 & 1 ~= 0 and not feat.hidden then - --feat:activate_hl_func() - stuff.previousMenus[#stuff.previousMenus + 1] = {menu = currentMenu, scroll = stuff.scroll, drawScroll = stuff.drawScroll, scrollHiddenOffset = stuff.scrollHiddenOffset} - currentMenu = feat - currentMenu:activate_feat_func() - stuff.scroll = 1 - system.wait(0) - stuff.drawScroll = 0 - stuff.scrollHiddenOffset = 0 - --[[ if feat then - feat:activate_hl_func() - end ]] - while cheeseUtils.get_key(stuff.vkcontrols.select):is_down() do - system.wait(0) + + menu_configuration_features[v[1]].a = menu.add_feature("Alpha", "autoaction_value_i", vParent.id, function(f) + if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then + local stat, num = input.get("num", "", 10, 3) + if stat == 0 and tonumber(num) then + f.value = num end - elseif feat.type & 1536 ~= 0 and not feat.hidden then - feat:activate_feat_func() - elseif feat.type & 1 ~= 0 and not feat.hidden then - feat.real_on = not feat.real_on - feat:activate_feat_func() end + stuff.menuData.color:set_color(v[1], nil, nil, nil, f.value) + end) + menu_configuration_features[v[1]].a.max = 255 + if type(v[2]) == "table" then + menu_configuration_features[v[1]].a.value = v[2].a else - system.wait(100) + menu_configuration_features[v[1]].a.value = func.convert_int_to_rgba(v[2], "a") end - end) + end + end + + -- loading default ui & settings + func.load_ui("default") + func.load_settings() + + --changing menu functions to ui functions + local menu_get_feature_by_hierarchy_key = menu.get_feature_by_hierarchy_key + menu_originals = setmetatable({ + --get_feature_by_hierarchy_key = menu.get_feature_by_hierarchy_key, + add_feature = menu.add_feature, + add_player_feature = menu.add_player_feature, + delete_feature = menu.delete_feature, + delete_player_feature = menu.delete_player_feature, + get_player_feature = menu.get_player_feature, + }, {__newindex = function() end}) + menu.add_feature = func.add_feature + menu.add_player_feature = func.add_player_feature + menu.delete_feature = func.delete_feature + menu.delete_player_feature = func.delete_player_feature + menu.get_player_feature = func.get_player_feature + menu.get_feature_by_hierarchy_key = function(hierarchy_key) + if string.find(hierarchy_key:lower(), "trusted") or string.find(hierarchy_key:lower(), "Proddy's Script Manager") then + return + end + local feat, duplicate + feat = menu_get_feature_by_hierarchy_key(hierarchy_key) + if feat then + return feat + else + feat, duplicate = func.get_feature_by_hierarchy_key(hierarchy_key) + if duplicate then + return feat[1] + else + return feat end end - end, nil) - menu.create_thread(function() - while true do - system.wait(0) - if stuff.menuData.menuToggle and stuff.menuData.menuNav then - func.do_key(500, stuff.vkcontrols.back, false, function() --backspace - if stuff.previousMenus[#stuff.previousMenus] then - --[[ if currentMenu[stuff.scroll + stuff.scrollHiddenOffset] then - currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() - end ]] - currentMenu = stuff.previousMenus[#stuff.previousMenus].menu - stuff.scroll = stuff.previousMenus[#stuff.previousMenus].scroll - stuff.drawScroll = stuff.previousMenus[#stuff.previousMenus].drawScroll - stuff.scrollHiddenOffset = stuff.previousMenus[#stuff.previousMenus].scrollHiddenOffset - stuff.previousMenus[#stuff.previousMenus] = nil - --currentMenu[stuff.scroll + stuff.scrollHiddenOffset]:activate_hl_func() + end + cheeseUIdata = stuff.menuData + -- + func.set_player_feat_parent("Online Players", 0) + + -- Proddy's Script Manager + gltw.read("Trusted Flags", stuff.path.cheesemenu, stuff, true, true) + menu.is_trusted_mode_enabled = function(flag) + if not flag then + return stuff.trusted_mode & 7 == 7, stuff.trusted_mode_notification + else + return stuff.trusted_mode & flag == flag, stuff.trusted_mode_notification + end + end + + dofile("\\scripts\\cheesemenu\\libs\\Proddy's Script Manager.lua") + + do + local trusted_parent = menu_get_feature_by_hierarchy_key("local.script_features.cheese_menu.proddy_s_script_manager.trusted_mode") + + menu_originals.add_feature("Save Trusted Flags", "action", trusted_parent.id, function() + gltw.write({trusted_mode = stuff.trusted_mode, trusted_mode_notification = stuff.trusted_mode_notification}, "Trusted Flags", stuff.path.cheesemenu, nil, nil, true) + menu.notify("Saved Successfully", "Cheese Menu", 2, 0x00ff00) + end) + + menu_originals.add_feature("Trusted Flags Notification", "toggle", trusted_parent.id, function(f) + stuff.trusted_mode_notification = f.on + end).on = stuff.trusted_mode_notification + + local trusted_names = { + [0] = "Stats", + [1] = "Globals / Locals", + [2] = "Natives", + [3] = "HTTP", + [4] = "Memory" + } + + for i = 0, 4 do + menu_originals.add_feature(trusted_names[i], "toggle", trusted_parent.id, function(f) + if f.on then + stuff.trusted_mode = stuff.trusted_mode | 1 << i + else + stuff.trusted_mode = stuff.trusted_mode ~ 1 << i end - end) + end).on = stuff.trusted_mode & 1 << i ~= 0 end end - end, nil) - menu.create_thread(function() - while true do - system.wait(0) - if stuff.menuData.menuToggle and stuff.menuData.menuNav then - func.do_key(500, stuff.vkcontrols.left, true, function() -- left - local feat = currentMenu[stuff.scroll + stuff.scrollHiddenOffset] - if feat then - if feat.value then - if feat.str_data then - if feat.value <= 0 then - feat.value = #feat.str_data - 1 - else - feat.value = feat.value - 1 - end - else - if tonumber(feat.value) <= feat.min and feat.type >> 2 & 1 == 0 then - feat.value = feat.max - else - feat.value = tonumber(feat.value) - feat.mod - end - end - end - if feat.type then - if feat.type >> 10 & 1 ~= 0 or (feat.type & 3 == 3 and feat.on) then - feat:activate_feat_func() - end - end - end - end) - end + -- +end +if httpTrustedOff then + loadCurrentMenu() +end]=], + ["Proddy's Script Manager.lua"] = [=[local ScriptName = "Proddy's Script Manager (CheeseMenu)" +local Version = "2.3.2" +local Exiting = false + +local Paths = {} +Paths.Root = utils.get_appdata_path("PopstarDevs", "2Take1Menu") +Paths.Cfg = Paths.Root .. "\\cfg" +Paths.LogFile = Paths.Root .. "\\" .. ScriptName .. ".log" +Paths.Scripts = Paths.Root .. "\\scripts" + +local og_loadfile = loadfile +local og__loadfile = _loadfile +local og_load = load +local og_pcall = _pcall +local io_open = io.open +local os_date = os.date +local string_format = string.format +local system_wait = system.wait + +local basePrint = print +local function print(...) + basePrint(...) + local success, result = og_pcall(function(...) + local args = {...} + if #args == 0 then + return end - end, nil) - menu.create_thread(function() - while true do - if stuff.menuData.menuToggle and stuff.menuData.menuNav then - func.do_key(500, stuff.vkcontrols.right, true, function() -- right - local feat = currentMenu[stuff.scroll + stuff.scrollHiddenOffset] - if feat then - if feat.value then - if feat.str_data then - if tonumber(feat.value) >= tonumber(#feat.str_data) - 1 then - feat.value = 0 - else - feat.value = feat.value + 1 - end - else - if tonumber(feat.value) >= feat.max and feat.type >> 2 & 1 == 0 then - feat.value = feat.min - else - feat.value = tonumber(feat.value) + feat.mod - end - end - end - if feat.type then - if feat.type >> 10 & 1 ~= 0 or (feat.type & 3 == 3 and feat.on) then - feat:activate_feat_func() - end - end - end - end) + + local currTime = os_date("*t") + local file = io_open(Paths.LogFile, "a") + + for i=1,#args do + file:write(string_format("[%02d-%02d-%02d %02d:%02d:%02d] <%s> %s\n", currTime.year, currTime.month, currTime.day, currTime.hour, currTime.min, currTime.sec, Version, tostring(args[i]))) + end + + file:close() + end, ...) + if not success then + basePrint("Error writing log: " .. result) + end +end + +local notif = menu.notify +local function notify(msg, colour) + notif(msg, ScriptName .. " v" .. Version, nil, colour) + print(msg) +end + +if ProddysScriptManager then + notify(ScriptName .. " already loaded.", 0xFF50C8F0) + return +end + +--notify(ScriptName .. " v" .. Version .. " loading...") + +local function CloneTable(obj, seen) + if type(obj) ~= 'table' then + return obj + end + + if seen and seen[obj] then + return seen[obj] + end + + local s = seen or {} + local res = {} + s[obj] = res + + for k, v in pairs(obj) do + res[CloneTable(k, s)] = CloneTable(v, s) + end + + return setmetatable(res, getmetatable(obj)) --Should definitely clone the metatable +end + +local function Trim(s) + local n = s:find"%S" + return n and s:match(".*%S", n) or "" +end + +local function FileNameWithoutExtension(FileName) + local name = FileName:match("(.+)%.") + return name or FileName +end + +local ExcludedScripts = {} +ExcludedScripts["autoexec.lua"] = true +ExcludedScripts["autoexec.luac"] = true +ExcludedScripts["cheesemenu.lua"] = true +ExcludedScripts[debug.getinfo(1, "S").source:sub(Paths.Scripts:len() + 3):lower()] = true + +local Settings = {} + +function Settings.Save(SettingsFile, SettingsTbl) + assert(SettingsFile, "Nil passed for SettingsFile to Settings.Save") + assert(type(SettingsTbl) == "table", "Not a table passed for SettingsTbl to Settings.Save") + local file = io.open(Paths.Cfg .. "\\" .. SettingsFile .. ".cfg", "w") + local keys = {} + for k in pairs(SettingsTbl) do + keys[#keys + 1] = k + end + table.sort(keys) + for i=1,#keys do + file:write(tostring(keys[i]) .. "=" .. tostring(SettingsTbl[keys[i]]) .. "\n") + end + file:close() +end + +function Settings.Load(SettingsFile, SettingsTbl) + assert(SettingsFile, "Nil passed for SettingsFile to Settings.Load") + assert(type(SettingsTbl) == "table", "Not a table passed for SettingsTbl to Settings.Load") + SettingsFile = Paths.Cfg .. "\\" .. SettingsFile .. ".cfg" + if not utils.file_exists(SettingsFile) then + return false + end + for line in io.lines(SettingsFile) do + local key, value = line:match("^(.-)=(.-)$") + if key and value then + local num = tonumber(value) + if num then + value = num + elseif value == "true" then + value = true + elseif value == "false" then + value = false end - system.wait(0) + num = tonumber(key) + if num then + key = num + end + SettingsTbl[key] = value end - end, nil) + end + return true +end + +local FeatType = { + [2048] = "parent", + [1] = "toggle", + [512] = "action", + [11] = "value_i", + [131] = "value_f", + [7] = "slider", + [35] = "value_str", + [522] = "action_value_i", + [642] = "action_value_f", + [518] = "action_slider", + [546] = "action_value_str", + [1034] = "autoaction_value_i", + [1154] = "autoaction_value_f", + [1030] = "autoaction_slider", + [1058] = "autoaction_value_str", +} + +local AutoloadTbl = {} +Settings.Load(ScriptName, AutoloadTbl) + +local LoadedScripts = {} + +local add_feature = menu.add_feature +local add_player_feature = menu.add_player_feature +local delete_feature = menu.delete_feature +local delete_player_feature = menu.delete_player_feature +local create_thread = menu.create_thread +local delete_thread = menu.delete_thread + +local register_script_event_hook = hook.register_script_event_hook +local remove_script_event_hook = hook.remove_script_event_hook +local register_net_event_hook = hook.register_net_event_hook +local remove_net_event_hook = hook.remove_net_event_hook + +local add_event_listener = event.add_event_listener +local remove_event_listener = event.remove_event_listener + +local register_command = console.register_command +local remove_command = console.remove_command + +local Parent = menu_originals.add_feature("Proddy's Script Manager", "parent", menu.get_feature_by_hierarchy_key("local.script_features.cheese_menu").id) +local ParentId = Parent.id +local FirstChild +local AutoloadFirstChild +local FilterFeat + +menu_originals.add_feature("Trusted Mode", "parent", ParentId) +local AutoloadParent = menu_originals.add_feature("Manage Autoload Scripts", "parent", ParentId) +local AutoloadParentId = AutoloadParent.id - --Hotkey thread - menu.create_thread(function() - while true do - if stuff.menuData.menuNav then - for k, v in pairs(stuff.hotkeys) do - local hotkey = cheeseUtils.get_key(table.unpack(stuff.hotkeys_to_vk[k])) - if hotkey:is_down() and (not (cheeseUtils.get_key(0x10):is_down() or cheeseUtils.get_key(0x11):is_down() or cheeseUtils.get_key(0x12):is_down()) or not (k:match("NOMOD"))) and utils.time_ms() > stuff.hotkey_cooldowns[k] then - for k, v in pairs(stuff.hotkeys[k]) do - if stuff.hotkey_feature_hierarchy_keys[k] then - for k, v in pairs(stuff.hotkey_feature_hierarchy_keys[k]) do - if v.type & 1 ~= 0 then - v.on = not v.on - if stuff.hotkey_notifications.toggle then - menu.notify("Turned "..v.name.." "..(v.on and "on" or "off"), "Cheese Menu", 3, func.convert_rgba_to_int(stuff.menuData.color.notifications.r, stuff.menuData.color.notifications.g, stuff.menuData.color.notifications.b, stuff.menuData.color.notifications.a)) - end - else - v:activate_feat_func() - if stuff.hotkey_notifications.action then - menu.notify("Activated "..v.name, "Cheese Menu", 3, func.convert_rgba_to_int(stuff.menuData.color.notifications.r, stuff.menuData.color.notifications.g, stuff.menuData.color.notifications.b, stuff.menuData.color.notifications.a)) - end - end - end - end - end - if stuff.hotkey_cooldowns[k] == 0 then - stuff.hotkey_cooldowns[k] = utils.time_ms() + 500 - else - stuff.hotkey_cooldowns[k] = utils.time_ms() + 100 - end - elseif not hotkey:is_down() then - stuff.hotkey_cooldowns[k] = 0 - end - end +local assert = assert +local error = error +local type = type + +local UnloadScript + +local function DeleteFeature(Feat) + if Feat then + if Feat.type == 2048 then + for i=1,Feat.child_count do + DeleteFeature(Feat.children[1]) + end + elseif Feat.type == 1 then + if Feat.data and type(Feat.data) == "table" and Feat.data.ScriptManager then + print("Deleting script: " .. Feat.name) + UnloadScript(Feat) + print("Deleted script: " .. Feat.name) end - system.wait(0) end - end, nil) - --End of threads - menu.notify("Kektram for teaching me lua & sharing neat functions\n\nRimuru for making the first separate ui that helped me in making cheese menu\n\nProddy for showing better ways to do things & sharing Script Manager", "Credits:", 12, 0x00ff00) - menu.notify("Controls can be found in\nScript Features > Cheese Menu > Controls", "CheeseMenu by GhostOne\n"..stuff.controls.open.." to open", 6, 0x00ff00) + if Feat.activate_feat_func then + delete_feature(Feat.id) + else + menu_originals.delete_feature(Feat.id) + end + end +end +local function DeletePlayerFeature(Feat) + delete_player_feature(Feat.id) +end - menu_configuration_features = {} - menu_configuration_features.cheesemenuparent = menu.add_feature("Cheese Menu", "parent") +UnloadScript = function(f) + if Exiting then return end + if not f.data or type(f.data) ~= "table" or not f.data.ScriptManager then return end - menu.add_feature("Save Settings", "action", menu_configuration_features.cheesemenuparent.id, function() - func.save_settings() - menu.notify("Settings Saved Successfully", "Cheese Menu", 6, 0x00ff00) - end) + print("Unloading script: " .. f.name) - menu.add_feature("Save UI", "action", menu_configuration_features.cheesemenuparent.id, function() - local status, name = input.get("name of ui", "", 25, 0) - if status == 0 then - func.save_ui(name) - menu.notify("UI Saved Successfully", "Cheese Menu", 6, 0x00ff00) - for _, v in pairs(stuff.menuData.files.ui) do - if v == name then - return - end + local success, result = og_pcall(function(data) + if data.exits then + for k,v in pairs(data.exits) do + v({["code"]=69}) end - stuff.menuData.files.ui[#stuff.menuData.files.ui+1] = name - menu_configuration_features.load_ui:set_str_data(stuff.menuData.files.ui) end - end) - - menu_configuration_features.load_ui = menu.add_feature("Load UI", "action_value_str", menu_configuration_features.cheesemenuparent.id, function(f) - func.load_ui(f.str_data[f.value + 1]) - end) - menu_configuration_features.load_ui:set_str_data(stuff.menuData.files.ui) - menu_configuration_features.menuXfeat = menu.add_feature("Menu pos X", "autoaction_value_i", menu_configuration_features.cheesemenuparent.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - stuff.menuData.pos_x = num/graphics.get_screen_height() - f.value = num + if data.features then + local ids = {} + for k in pairs(data.features) do + ids[#ids + 1] = k + end + table.sort(ids) + for i = #ids,1,-1 do + DeleteFeature(data.features[ids[i]]) end end - stuff.menuData.pos_x = f.value/graphics.get_screen_width() - end) - menu_configuration_features.menuXfeat.max = graphics.get_screen_width() - menu_configuration_features.menuXfeat.mod = 1 - menu_configuration_features.menuXfeat.min = -graphics.get_screen_width() - menu_configuration_features.menuXfeat.value = math.floor(stuff.menuData.pos_x*graphics.get_screen_width()) - menu_configuration_features.menuYfeat = menu.add_feature("Menu pos Y", "autoaction_value_i", menu_configuration_features.cheesemenuparent.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - stuff.menuData.pos_y = num/graphics.get_screen_height() - f.value = num + if data.player_features then + local ids = {} + for k in pairs(data.player_features) do + ids[#ids + 1] = k + end + table.sort(ids) + for i = #ids,1,-1 do + DeletePlayerFeature(data.player_features[ids[i]]) end end - stuff.menuData.pos_y = f.value/graphics.get_screen_height() - end) - menu_configuration_features.menuYfeat.max = graphics.get_screen_height() - menu_configuration_features.menuYfeat.mod = 1 - menu_configuration_features.menuYfeat.min = -graphics.get_screen_height() - menu_configuration_features.menuYfeat.value = math.floor(stuff.menuData.pos_y*graphics.get_screen_height()) - menu_configuration_features.headerfeat = menu.add_feature("Header", "autoaction_value_str", menu_configuration_features.cheesemenuparent.id, function(f) - if f.str_data[f.value + 1] == "NONE" then - stuff.menuData.header = nil - else - stuff.menuData.header = f.str_data[f.value + 1] + if data.threads then + local ids = {} + for k in pairs(data.threads) do + ids[#ids + 1] = k + end + table.sort(ids) + for i = #ids,1,-1 do + delete_thread(ids[i]) + end end - end) - menu_configuration_features.headerfeat:set_str_data({"NONE", table.unpack(stuff.menuData.files.headers)}) - - menu_configuration_features.layoutParent = menu.add_feature("Layout", "parent", menu_configuration_features.cheesemenuparent.id) - - menu_configuration_features.maxfeats = menu.add_feature("Max features", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) - stuff.menuData:set_max_features(f.value) - end) - menu_configuration_features.maxfeats.max = 50 - menu_configuration_features.maxfeats.mod = 1 - menu_configuration_features.maxfeats.min = 1 - menu_configuration_features.maxfeats.value = math.floor(stuff.menuData.max_features) - - menu_configuration_features.menuWidth = menu.add_feature("Menu width", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) - stuff.menuData.width = f.value/graphics.get_screen_width() - end) - menu_configuration_features.menuWidth.max = graphics.get_screen_width() - menu_configuration_features.menuWidth.mod = 1 - menu_configuration_features.menuWidth.min = -graphics.get_screen_width() - menu_configuration_features.menuWidth.value = math.floor(stuff.menuData.width*graphics.get_screen_width()) - - menu_configuration_features.featXfeat = menu.add_feature("Feature dimensions X", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) - stuff.menuData.feature_scale.x = f.value/graphics.get_screen_width() - end) - menu_configuration_features.featXfeat.max = graphics.get_screen_width() - menu_configuration_features.featXfeat.mod = 1 - menu_configuration_features.featXfeat.min = -graphics.get_screen_width() - menu_configuration_features.featXfeat.value = math.floor(stuff.menuData.feature_scale.x*graphics.get_screen_width()) - - menu_configuration_features.featYfeat = menu.add_feature("Feature dimensions Y", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) - stuff.menuData.feature_scale.y = f.value/graphics.get_screen_height() - end) - menu_configuration_features.featYfeat.max = graphics.get_screen_height() - menu_configuration_features.featYfeat.mod = 1 - menu_configuration_features.featYfeat.min = -graphics.get_screen_height() - menu_configuration_features.featYfeat.value = math.floor(stuff.menuData.feature_scale.y*graphics.get_screen_height()) - menu_configuration_features.feature_offset = menu.add_feature("Feature spacing", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) - stuff.menuData.feature_offset = f.value/graphics.get_screen_height() - menu_configuration_features.maxfeats:toggle() - end) - menu_configuration_features.feature_offset.max = graphics.get_screen_height() - menu_configuration_features.feature_offset.mod = 1 - menu_configuration_features.feature_offset.min = -graphics.get_screen_height() - menu_configuration_features.feature_offset.value = math.floor(stuff.menuData.feature_offset*graphics.get_screen_height()) + if data.script_hooks then + local ids = {} + for k in pairs(data.script_hooks) do + ids[#ids + 1] = k + end + table.sort(ids) + for i = #ids,1,-1 do + remove_script_event_hook(ids[i]) + end + end - menu_configuration_features.text_size = menu.add_feature("Text Size", "autoaction_value_f", menu_configuration_features.layoutParent.id, function(f) - stuff.menuData.text_size_modifier = f.value - end) - menu_configuration_features.text_size.max = 5 - menu_configuration_features.text_size.mod = 0.01 - menu_configuration_features.text_size.min = 0.1 - menu_configuration_features.text_size.value = stuff.menuData.text_size_modifier + if data.net_hooks then + local ids = {} + for k in pairs(data.net_hooks) do + ids[#ids + 1] = k + end + table.sort(ids) + for i = #ids,1,-1 do + remove_net_event_hook(ids[i]) + end + end - menu_configuration_features.footer_size = menu.add_feature("Footer Text Size", "autoaction_value_f", menu_configuration_features.layoutParent.id, function(f) - stuff.menuData.footer_size_modifier = f.value - end) - menu_configuration_features.footer_size.max = 5 - menu_configuration_features.footer_size.mod = 0.01 - menu_configuration_features.footer_size.min = 0.1 - menu_configuration_features.footer_size.value = stuff.menuData.footer_size_modifier + if data.events then + for eventName,v in pairs(data.events) do + local ids = {} + for k in pairs(v) do + ids[#ids + 1] = k + end + table.sort(ids) + for i = #ids,1,-1 do + remove_event_listener(eventName, ids[i]) + end + end + end - menu_configuration_features.hint_size = menu.add_feature("Hint Text Size", "autoaction_value_f", menu_configuration_features.layoutParent.id, function(f) - stuff.menuData.hint_size_modifier = f.value - func.rewrap_hints(stuff.menuData.fonts.hint) - end) - menu_configuration_features.hint_size.max = 5 - menu_configuration_features.hint_size.mod = 0.01 - menu_configuration_features.hint_size.min = 0.1 - menu_configuration_features.hint_size.value = stuff.menuData.hint_size_modifier + if data.commands then + for name in pairs(data.commands) do + remove_command(name) + end + end + end, f.data) - menu_configuration_features.text_y_offset = menu.add_feature("Text Y Offset", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) - stuff.drawFeatParams.textOffset.y = -(f.value/graphics.get_screen_height()) - stuff.menuData.text_y_offset = -(f.value/graphics.get_screen_height()) - end) - menu_configuration_features.text_y_offset.max = 100 - menu_configuration_features.text_y_offset.mod = 1 - menu_configuration_features.text_y_offset.min = -100 - menu_configuration_features.text_y_offset.value = -math.floor(stuff.menuData.text_y_offset*graphics.get_screen_height()) + LoadedScripts[f.name] = nil + f.data = nil + f.on = false - menu_configuration_features.border = menu.add_feature("Border", "autoaction_value_i", menu_configuration_features.layoutParent.id, function(f) - stuff.menuData.border = f.value/graphics.get_screen_height() - end) - menu_configuration_features.border.max = graphics.get_screen_height() - menu_configuration_features.border.mod = 1 - menu_configuration_features.border.min = -graphics.get_screen_height() - menu_configuration_features.border.value = math.floor(stuff.menuData.border*graphics.get_screen_height()) + if success then + notify("Unloaded script: " .. f.name, 0xFF00FF00) + else + notify("Failed to unload script: " .. f.name .. "\n" .. result, 0xFF00FF00) + end - menu_configuration_features.selector_speed = menu.add_feature("Selector Speed", "autoaction_value_f", menu_configuration_features.layoutParent.id, function(f) - stuff.menuData.selector_speed = f.value - end) - menu_configuration_features.selector_speed.max = 10 - menu_configuration_features.selector_speed.mod = 0.1 - menu_configuration_features.selector_speed.min = 0.2 - menu_configuration_features.selector_speed.value = stuff.menuData.selector_speed + collectgarbage("collect") +end - -- Online Player Submenu Sorting - menu_configuration_features.player_submenu_sort = menu.add_feature("Online Players Sort:", "autoaction_value_str", menu_configuration_features.layoutParent.id, function(f) - table.sort(stuff.PlayerParent, stuff.table_sort_functions[f.value]) - stuff.player_submenu_sort = f.value - end) - menu_configuration_features.player_submenu_sort:set_str_data({'PID', 'PID Reversed', 'Alphabetically', 'Alphabetically Reversed', 'Host Priority', 'Host Priority Reversed'}) - menu_configuration_features.player_submenu_sort.value = stuff.player_submenu_sort +-- modified +local limited_functions = { + { + namespace = "stats", + table = stats, + ["stat_set_int"] = true, + ["stat_set_float"] = true, + ["stat_set_bool"] = true, + ["stat_set_i64"] = true, + ["stat_set_u64"] = true, + ["stat_set_masked_int"] = true, + ["stat_set_masked_bool"] = true, + }, + { + namespace = "script", + table = script, + ["set_global_f"] = true, + ["set_global_i"] = true, + ["set_global_s"] = true, + ["set_local_f"] = true, + ["set_local_i"] = true, + ["set_local_s"] = true, + }, + { + namespace = "native", + table = native, + ["call"] = true, + }, + { + namespace = "web", + table = web, + ["post"] = true, + ["get"] = true, + ["request"] = true, + ["urlencode"] = true, + ["urldecode"] = true, + }, + { + namespace = "memory", + table = memory, + ["get_any"] = true, + ["get_entity"] = true, + ["get_ped"] = true, + ["get_vehicle"] = true, + ["get_object"] = true, + ["get_pickup"] = true, + ["read_u64"] = true, + ["read_u32"] = true, + ["read_u16"] = true, + ["read_u8"] = true, + ["read_i64"] = true, + ["read_i32"] = true, + ["read_i16"] = true, + ["read_i8"] = true, + ["read_f32"] = true, + }, +} - -- Padding - menu_configuration_features.padding_parent = menu.add_feature("Padding", "parent", menu_configuration_features.layoutParent.id) +local trusted_names = { + [0] = "Stats", + "Globals / Locals", + "Natives", + "HTTP", + "Memory" +} - menu_configuration_features.namePadding = menu.add_feature("Name Padding", "autoaction_value_i", menu_configuration_features.padding_parent.id, function(f) - stuff.menuData.padding.name = f.value/graphics.get_screen_width() - end) - menu_configuration_features.namePadding.max = graphics.get_screen_width() - menu_configuration_features.namePadding.mod = 1 - menu_configuration_features.namePadding.min = -graphics.get_screen_width() - menu_configuration_features.namePadding.value = math.floor(stuff.menuData.padding.name*graphics.get_screen_width()) +local modified_functions = { + stats = {}, + script = {}, + native = {}, + web = {}, + memory = {}, +} - menu_configuration_features.parentPadding = menu.add_feature("Parent Padding", "autoaction_value_i", menu_configuration_features.padding_parent.id, function(f) - stuff.menuData.padding.parent = f.value/graphics.get_screen_width() - end) - menu_configuration_features.parentPadding.max = graphics.get_screen_width() - menu_configuration_features.parentPadding.mod = 1 - menu_configuration_features.parentPadding.min = -graphics.get_screen_width() - menu_configuration_features.parentPadding.value = math.floor(stuff.menuData.padding.parent*graphics.get_screen_width()) +for k, v in ipairs(limited_functions) do + local namespace = v.namespace + for name, data in pairs(v) do + if data == true then + modified_functions[namespace][name] = function(...) + local is_flag_on, notify = menu.is_trusted_mode_enabled(1 << (k-1)) + if is_flag_on then + return v.table[name](...) + elseif notify then + menu.notify("Trusted Flag '"..trusted_names[k-1].."' is not enabled.\nFunction used: "..namespace..'.'..name, "Cheese Menu", 5, 0x00ffff) + end + end + end + end +end +-- - menu_configuration_features.valuePadding = menu.add_feature("Value Padding", "autoaction_value_i", menu_configuration_features.padding_parent.id, function(f) - stuff.menuData.padding.value = f.value/graphics.get_screen_width() - end) - menu_configuration_features.valuePadding.max = graphics.get_screen_width() - menu_configuration_features.valuePadding.mod = 1 - menu_configuration_features.valuePadding.min = -graphics.get_screen_width() - menu_configuration_features.valuePadding.value = math.floor(stuff.menuData.padding.value*graphics.get_screen_width()) +local function LoadScript(f) + if f.on then + if not f.data then + local Filename = f.name + local Filepath = Paths.Scripts .. "\\" .. Filename - menu_configuration_features.sliderPadding = menu.add_feature("Slider Padding", "autoaction_value_i", menu_configuration_features.padding_parent.id, function(f) - stuff.menuData.padding.slider = f.value/graphics.get_screen_width() - end) - menu_configuration_features.sliderPadding.max = graphics.get_screen_width() - menu_configuration_features.sliderPadding.mod = 1 - menu_configuration_features.sliderPadding.min = -graphics.get_screen_width() - menu_configuration_features.sliderPadding.value = math.floor(stuff.menuData.padding.slider*graphics.get_screen_width()) + if not utils.file_exists(Filepath) then + notify("Could not find script: " .. Filename,0xFF0000FF) + LoadedScripts[f.name] = nil + f.data = nil + f.on = false + return + end - -- Slider dimensions - menu_configuration_features.slider_parent = menu.add_feature("Slider", "parent", menu_configuration_features.layoutParent.id) + print("Enabling script: " .. f.name) + f.data = {} + f.data.ScriptManager = true + f.data.features = {} + f.data.player_features = {} + f.data.threads = {} + f.data.script_hooks = {} + f.data.net_hooks = {} + f.data.events = {} + f.data.exits = {} + f.data.commands = {} - menu_configuration_features.sliderWidth = menu.add_feature("Slider Width", "autoaction_value_i", menu_configuration_features.slider_parent.id, function(f) - stuff.menuData.slider.width = f.value/graphics.get_screen_width() - end) - menu_configuration_features.sliderWidth.max = graphics.get_screen_width() - menu_configuration_features.sliderWidth.mod = 1 - menu_configuration_features.sliderWidth.min = -graphics.get_screen_width() - menu_configuration_features.sliderWidth.value = math.floor(stuff.menuData.slider.width*graphics.get_screen_width()) + local env = CloneTable(_G) + function env.SetGlobal(Name, Value) + assert(type(Name) == "string", "Arg #1 (Name) must be a string") - menu_configuration_features.sliderHeight = menu.add_feature("Slider Height", "autoaction_value_i", menu_configuration_features.slider_parent.id, function(f) - stuff.menuData.slider.height = f.value/graphics.get_screen_height() - end) - menu_configuration_features.sliderHeight.max = graphics.get_screen_height() - menu_configuration_features.sliderHeight.mod = 1 - menu_configuration_features.sliderHeight.min = -graphics.get_screen_height() - menu_configuration_features.sliderHeight.value = math.floor(stuff.menuData.slider.height*graphics.get_screen_height()) + _G[Name] = Value + for i=FirstChild,Parent.child_count do + local feat = Parent.children[i] + if feat.data and feat.data.env then + feat.data.env[Name] = Value + end + end + end - menu_configuration_features.sliderheightActive = menu.add_feature("Slider Height Active", "autoaction_value_i", menu_configuration_features.slider_parent.id, function(f) - stuff.menuData.slider.heightActive = f.value/graphics.get_screen_height() - end) - menu_configuration_features.sliderheightActive.max = graphics.get_screen_height() - menu_configuration_features.sliderheightActive.mod = 1 - menu_configuration_features.sliderheightActive.min = -graphics.get_screen_height() - menu_configuration_features.sliderheightActive.value = math.floor(stuff.menuData.slider.heightActive*graphics.get_screen_height()) + for namespace, func_table in pairs(modified_functions) do + local env_namespace = env[namespace] + for name, func in pairs(func_table) do + env_namespace[name] = func + end + end - -- Controls - menu_configuration_features.controls = menu.add_feature("Controls", "parent", menu_configuration_features.cheesemenuparent.id) + env.cheeseUIdata = cheeseUIdata - for k, v in pairs(stuff.controls) do - menu.add_feature(k, "action_value_str", menu_configuration_features.controls.id, function(f) - for k, v in pairs(stuff.char_codes) do - while cheeseUtils.get_key(v):is_down() do - system.wait(0) - end - end - menu.notify("Press any button\nESC to cancel", "Cheese Menu", 3, func.convert_rgba_to_int(stuff.menuData.color.notifications.r, stuff.menuData.color.notifications.g, stuff.menuData.color.notifications.b, stuff.menuData.color.notifications.a)) - local disablethread = menu.create_thread(stuff.disable_all_controls, nil) - local stringkey, vk = func.get_hotkey({}, {}, true) - if stringkey ~= "escaped" then - stuff.controls[k] = stringkey - stuff.vkcontrols[k] = vk - f:set_str_data({stringkey}) - end - menu.delete_thread(disablethread) - end):set_str_data({v}) + env.menu.add_feature = function(...) + local feat = add_feature(...) + if feat then + f.data.features[feat.id] = feat + end + return feat + end + env.menu.add_player_feature = function(...) + local feat = add_player_feature(...) + if feat then + f.data.player_features[feat.id] = feat + end + return feat + end + env.menu.delete_feature = function(id) + local success = delete_feature(id) + if success then + f.data.features[id] = nil + end + return success end - - -- Player Info - menu_configuration_features.side_window = menu.add_feature("Player Info Window", "parent", menu_configuration_features.cheesemenuparent.id) - - -- On - menu_configuration_features.side_window_on = menu.add_feature("Draw", "toggle", menu_configuration_features.side_window.id, function(f) - stuff.menuData.side_window.on = f.on - end) - menu_configuration_features.side_window_on.on = stuff.menuData.side_window.on - - -- Offset - menu_configuration_features.side_window_offsetx = menu.add_feature("X Offset", "autoaction_value_i", menu_configuration_features.side_window.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - stuff.menuData.side_window.offset.x = num/graphics.get_screen_height() - f.value = num + env.menu.delete_player_feature = function(id) + local success = delete_player_feature(id) + if success then + f.data.player_features[id] = nil end + return success end - stuff.menuData.side_window.offset.x = f.value/graphics.get_screen_width() - end) - menu_configuration_features.side_window_offsetx.max = graphics.get_screen_width() - menu_configuration_features.side_window_offsetx.mod = 1 - menu_configuration_features.side_window_offsetx.min = -graphics.get_screen_width() - menu_configuration_features.side_window_offsetx.value = math.floor(stuff.menuData.side_window.offset.x*graphics.get_screen_width()) - - menu_configuration_features.side_window_offsety = menu.add_feature("Y Offset", "autoaction_value_i", menu_configuration_features.side_window.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - stuff.menuData.side_window.offset.y = num/graphics.get_screen_height() - f.value = num + env.menu.create_thread = function(...) + local id = create_thread(...) + if id then + f.data.threads[id] = true end + return id end - stuff.menuData.side_window.offset.y = f.value/graphics.get_screen_height() - end) - menu_configuration_features.side_window_offsety.max = graphics.get_screen_height() - menu_configuration_features.side_window_offsety.mod = 1 - menu_configuration_features.side_window_offsety.min = -graphics.get_screen_height() - menu_configuration_features.side_window_offsety.value = math.floor(stuff.menuData.side_window.offset.y*graphics.get_screen_height()) - - -- Spacing - menu_configuration_features.side_window_spacing = menu.add_feature("Spacing", "autoaction_value_i", menu_configuration_features.side_window.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - stuff.menuData.side_window.spacing = num/graphics.get_screen_height() - f.value = num + env.menu.delete_thread = function(id) + local success = delete_thread(id) + if success then + f.data.threads[id] = nil end + return success end - stuff.menuData.side_window.spacing = f.value/graphics.get_screen_height() - end) - menu_configuration_features.side_window_spacing.max = graphics.get_screen_height() - menu_configuration_features.side_window_spacing.mod = 1 - menu_configuration_features.side_window_spacing.min = -graphics.get_screen_height() - menu_configuration_features.side_window_spacing.value = math.floor(stuff.menuData.side_window.spacing*graphics.get_screen_height()) - - -- Padding - menu_configuration_features.side_window_padding = menu.add_feature("Padding", "autoaction_value_i", menu_configuration_features.side_window.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - stuff.menuData.side_window.padding = num/graphics.get_screen_height() - f.value = num + env.hook.register_script_event_hook = function(...) + local id = register_script_event_hook(...) + if id then + f.data.script_hooks[id] = true end + return id end - stuff.menuData.side_window.padding = f.value/graphics.get_screen_width() - end) - menu_configuration_features.side_window_padding.max = graphics.get_screen_width() - menu_configuration_features.side_window_padding.mod = 1 - menu_configuration_features.side_window_padding.min = -graphics.get_screen_width() - menu_configuration_features.side_window_padding.value = math.floor(stuff.menuData.side_window.padding*graphics.get_screen_width()) - - -- Width - menu_configuration_features.side_window_width = menu.add_feature("Width", "autoaction_value_i", menu_configuration_features.side_window.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - stuff.menuData.side_window.width = num/graphics.get_screen_height() - f.value = num + env.hook.remove_script_event_hook = function(id) + local success = remove_script_event_hook(id) + if success then + f.data.script_hooks[id] = nil end + return success end - stuff.menuData.side_window.width = f.value/graphics.get_screen_width() - end) - menu_configuration_features.side_window_width.max = graphics.get_screen_width() - menu_configuration_features.side_window_width.mod = 1 - menu_configuration_features.side_window_width.min = -graphics.get_screen_width() - menu_configuration_features.side_window_width.value = math.floor(stuff.menuData.side_window.width*graphics.get_screen_width()) - - -- End of Player Info - - - -- Background - menu_configuration_features.backgroundparent = menu.add_feature("Background", "parent", menu_configuration_features.cheesemenuparent.id) - - menu_configuration_features.backgroundfeat = menu.add_feature("Background", "autoaction_value_str", menu_configuration_features.backgroundparent.id, function(f) - if f.str_data[f.value + 1] == "NONE" then - stuff.menuData.background_sprite.sprite = nil - else - stuff.menuData.background_sprite.sprite = f.str_data[f.value + 1] + env.hook.register_net_event_hook = function(...) + local id = register_net_event_hook(...) + if id then + f.data.net_hooks[id] = true end - end) - menu_configuration_features.backgroundfeat:set_str_data({"NONE", table.unpack(stuff.menuData.files.background)}) - - menu.add_feature("Fit background to width", "action", menu_configuration_features.backgroundparent.id, function() - if stuff.menuData.background_sprite.sprite then - stuff.menuData.background_sprite:fit_size_to_width() + return id + end + env.hook.remove_net_event_hook = function(id) + local success = remove_net_event_hook(id) + if success then + f.data.net_hooks[id] = nil end - end) - - menu_configuration_features.backgroundoffsetx = menu.add_feature("Background pos X", "autoaction_value_i", menu_configuration_features.backgroundparent.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - stuff.menuData.background_sprite.offset.x = num/graphics.get_screen_width() - f.value = num + return success + end + env.event.add_event_listener = function(eventName, callback) + local id = add_event_listener(eventName, callback) + if id then + f.data.events[eventName] = f.data.events[eventName] or {} + f.data.events[eventName][id] = true + if eventName == "exit" then + f.data.exits[id] = callback end end - stuff.menuData.background_sprite.offset.x = f.value/graphics.get_screen_width() - end) - menu_configuration_features.backgroundoffsetx.max = graphics.get_screen_width() - menu_configuration_features.backgroundoffsetx.mod = 1 - menu_configuration_features.backgroundoffsetx.min = -graphics.get_screen_width() - menu_configuration_features.backgroundoffsetx.value = math.floor(stuff.menuData.background_sprite.offset.x*graphics.get_screen_width()) - - menu_configuration_features.backgroundoffsety = menu.add_feature("Background pos Y", "autoaction_value_i", menu_configuration_features.backgroundparent.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - stuff.menuData.background_sprite.offset.y = num/graphics.get_screen_height() - f.value = num + return id + end + env.event.remove_event_listener = function(eventName, id) + local success = remove_event_listener(eventName, id) + if success and f.data.events[eventName] then + f.data.events[eventName][id] = nil + if eventName == "exit" then + f.data.exits[id] = nil end end - stuff.menuData.background_sprite.offset.y = f.value/graphics.get_screen_height() - end) - menu_configuration_features.backgroundoffsety.max = graphics.get_screen_height() - menu_configuration_features.backgroundoffsety.mod = 1 - menu_configuration_features.backgroundoffsety.min = -graphics.get_screen_height() - menu_configuration_features.backgroundoffsety.value = math.floor(stuff.menuData.background_sprite.offset.y*graphics.get_screen_height()) - - menu_configuration_features.backgroundsize = menu.add_feature("Background Size", "autoaction_value_f", menu_configuration_features.backgroundparent.id, function(f) - stuff.menuData.background_sprite.size = f.value - end) - menu_configuration_features.backgroundsize.max = 1 - menu_configuration_features.backgroundsize.mod = 0.01 - menu_configuration_features.backgroundsize.value = stuff.menuData.background_sprite.size - - -- Footer - menu_configuration_features.footer = menu.add_feature("Footer", "parent", menu_configuration_features.cheesemenuparent.id) - - menu_configuration_features.footer_size = menu.add_feature("Footer Size", "autoaction_value_i", menu_configuration_features.footer.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - stuff.menuData.footer.footer_size = num/graphics.get_screen_height() - f.value = num + return success + end + env.console.register_command = function(name, ...) + if register_command(name, ...) then + f.data.commands[name] = true + return true + end + return false + end + env.console.remove_command = function(name) + if remove_command(name) then + for i=FirstChild,Parent.child_count do + local feat = Parent.children[i] + if feat.data and feat.data.commands then + feat.data.commands[name] = nil + end + end + return true + end + return false + end + env.load = function(chunk, chunkname, mode, env2) + return og_load(chunk, chunkname or "=(load)", mode or "bt", env2 or env) + end + env.dofile = function(filename) + return og__loadfile(filename, "bt", env)() + end + env.loadfile = function(filename, mode, env2) + return og__loadfile(filename, mode or "bt", env2 or env) + end + env._loadfile = function(filename, mode, env) + return og__loadfile(filename, mode or "bt", env or env) + end + local loaders = {} + local loaded = {} + env.require = function(Library) + assert(Library ~= nil, "You must pass a Library name") + assert(type(Library) == "string", "Library name must be a string") + if loaders[Library] then + local status, result = og_pcall(loaders[Library]) + if status then + if result == nil then + return true + else + loaded[Library] = result + return loaded[Library] + end + end + end + local libParts = {} + for part in Library:gmatch("[^.]+") do + libParts[#libParts + 1] = part + end + local subDirTbl = {} + if #libParts > 1 then + for i=1,#libParts-1 do + subDirTbl[#subDirTbl + 1] = libParts[i] + end + end + local subDir = table.concat(subDirTbl, "/") .. "/" + local lib = libParts[#libParts] + for rootDir in env.package.path:gmatch("[^;]+") do + local path = rootDir:gsub("%?", subDir .. lib) + if utils.file_exists(path) then + local chunk, err = og__loadfile(path, "bt", env) + assert(chunk, "Failed to load \"" .. Library .. "\": " .. tostring(err)) + local status, result = og_pcall(chunk) + assert(status, "Failed to exec \"" .. Library .. "\": " .. tostring(result)) + loaders[Library] = chunk + if result == nil then + return true + else + loaded[Library] = result + return loaded[Library] + end end end - stuff.menuData.footer.footer_size = f.value/graphics.get_screen_height() - end) - menu_configuration_features.footer_size.max = graphics.get_screen_height() - menu_configuration_features.footer_size.mod = 1 - menu_configuration_features.footer_size.min = 0 - menu_configuration_features.footer_size.value = math.floor(stuff.menuData.footer.footer_size*graphics.get_screen_height()) - - menu_configuration_features.footer_y_offset = menu.add_feature("Footer Y Offset", "autoaction_value_i", menu_configuration_features.footer.id, function(f) - stuff.menuData.footer.footer_y_offset = (f.value/graphics.get_screen_height()) - end) - menu_configuration_features.footer_y_offset.max = 100 - menu_configuration_features.footer_y_offset.mod = 1 - menu_configuration_features.footer_y_offset.min = -100 - menu_configuration_features.footer_y_offset.value = math.floor(stuff.menuData.footer.footer_y_offset*graphics.get_screen_height()) + error("Failed to find library with name \"" .. Library .. "\"") + end + env.clear_lib_cache = function(Library) + if Library then + local retVal = loaders[Library] ~= nil and loaded[Library] ~= nil + loaders[Library] = nil + loaded[Library] = nil + return retVal + else + loaders = {} + loaded = {} + return true + end + end + env.get_lib_cache = function() + local cache = {} + for k,v in pairs(loaded) do + cache[k] = v + end + return cache + end + f.data.env = env - menu_configuration_features.footerPadding = menu.add_feature("Padding", "autoaction_value_i", menu_configuration_features.footer.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - stuff.menuData.footer.padding = num/graphics.get_screen_width() - f.value = num - end + local chunk, err = og__loadfile(Filepath, "bt", f.data.env) + if chunk then + local status, result = og_pcall(chunk) + if not status then + menu.create_thread(UnloadScript, f) + notify("Error executing script: " .. Filename .. "\n" .. tostring(result), 0xFF0000FF) + else + notify("Loaded script: " .. Filename, 0xFF00FF00) + LoadedScripts[Filename] = true end - stuff.menuData.footer.padding = f.value/graphics.get_screen_width() - end) - menu_configuration_features.footerPadding.max = graphics.get_screen_width() - menu_configuration_features.footerPadding.mod = 1 - menu_configuration_features.footerPadding.min = -graphics.get_screen_width() - menu_configuration_features.footerPadding.value = math.floor(stuff.menuData.footer.padding*graphics.get_screen_width()) + else + menu.create_thread(UnloadScript, f) + notify("Error loading script: " .. Filename .. "\n" .. err, 0xFF0000FF) + end + end + else + if f.data then + menu.create_thread(UnloadScript, f) + end + end +end - menu_configuration_features.draw_footer = menu.add_feature("Draw footer", "toggle", menu_configuration_features.footer.id, function(f) - stuff.menuData.footer.draw_footer = f.on - end) - menu_configuration_features.draw_footer.on = stuff.menuData.footer.draw_footer +local function CaseInsensitiveSort(a, b) + return tostring(a):lower() < tostring(b):lower() +end - menu_configuration_features.footer_pos_related_to_background = menu.add_feature("Footer position based on background", "toggle", menu_configuration_features.footer.id, function(f) - stuff.menuData.footer.footer_pos_related_to_background = f.on - end) - menu_configuration_features.footer_pos_related_to_background.on = stuff.menuData.footer.footer_pos_related_to_background +local function LoadScripts(feat) + if FilterFeat then + FilterFeat.data = "" + FilterFeat.name = "Filter: " + end - menu_configuration_features.footer_text = menu.add_feature("Footer Text", "action", menu_configuration_features.footer.id, function() - local status, text = input.get("Footer Text", "", 50, 0) - if status == 0 then - stuff.menuData.footer.footer_text = tostring(text) - end - end) + local files = utils.get_all_files_in_directory(Paths.Scripts, "lua") + local files2 = {} + for i=1,#files do + files2[files[i]] = true + end + local files3 = utils.get_all_files_in_directory(Paths.Scripts, "luac") + for i=1,#files3 do + if not files2[files3[i]] then + files[#files + 1] = files3[i] + files2[files3[i]] = true + end + end + table.sort(files, CaseInsensitiveSort) + local threads = {} + for i=Parent.child_count,FirstChild,-1 do + if not files2[Parent.children[i].name] then + threads[#threads + 1] = create_thread(DeleteFeature, Parent.children[i]) + else + files2[Parent.children[i].name] = false + Parent.children[i].hidden = false + end + end + for i=AutoloadParent.child_count,AutoloadFirstChild,-1 do + threads[#threads + 1] = create_thread(DeleteFeature, AutoloadParent.children[i]) + end + local waiting = true + while waiting do + local running = false + for i=1,#threads do + running = running or (not menu.has_thread_finished(threads[i])) + end + waiting = running + system_wait(0) + end + for i=1,#files do + if not ExcludedScripts[files[i]:lower()] then + if files2[files[i]] then + menu_originals.add_feature(files[i], "toggle", ParentId, LoadScript, f) + end + local autoloadFeat = menu_originals.add_feature(files[i], "value_i", AutoloadParentId) + autoloadFeat.min = 1 + autoloadFeat.max = 999 + autoloadFeat.mod = 1 + local val = AutoloadTbl[files[i]] + if val then + autoloadFeat.value = type(val) == "number" and val or 1 + autoloadFeat.on = true + else + autoloadFeat.value = 1 + end + end + end +end - -- Fonts - local fontStrData = { - "Menu Head", - "Menu Tab", - "Menu Entry", - "Menu Foot", - "Script 1", - "Script 2", - "Script 3", - "Script 4", - "Script 5", - } - menu_configuration_features.fonts = menu.add_feature("Fonts", "parent", menu_configuration_features.cheesemenuparent.id) +local ExitFeat = menu_originals.add_feature("Exit Listener", "toggle", ParentId, function(f) + if not f.on then + print("Exit Listener Feat Off") + Exiting = true + end +end) +ExitFeat.hidden = true +ExitFeat.on = true - menu_configuration_features.text_font = menu.add_feature("Text Font", "autoaction_value_str", menu_configuration_features.fonts.id, function(f) - stuff.menuData.fonts.text = f.value - end) - menu_configuration_features.text_font:set_str_data(fontStrData) - menu_configuration_features.text_font.value = stuff.menuData.fonts.text +local delayFeat - menu_configuration_features.footer_font = menu.add_feature("Footer Font", "autoaction_value_str", menu_configuration_features.fonts.id, function(f) - stuff.menuData.fonts.footer = f.value - end) - menu_configuration_features.footer_font:set_str_data(fontStrData) - menu_configuration_features.footer_font.value = stuff.menuData.fonts.footer +menu_originals.add_feature("Save Autoload Scripts", "action", AutoloadParentId, function(f) + AutoloadTbl = { + ["autoload_delay_between_scripts"] = delayFeat.value + } + for i=AutoloadFirstChild,AutoloadParent.child_count do + local child = AutoloadParent.children[i] + if child.on then + AutoloadTbl[child.name] = child.value + end + end + Settings.Save(ScriptName, AutoloadTbl) + notify("Saved autoload scripts.", 0xFF00FF00) +end) - menu_configuration_features.hint_font = menu.add_feature("Hint Font", "autoaction_value_str", menu_configuration_features.fonts.id, function(f) - stuff.menuData.fonts.hint = f.value - func.rewrap_hints(f.value) - end) - menu_configuration_features.hint_font:set_str_data(fontStrData) - menu_configuration_features.hint_font.value = stuff.menuData.fonts.hint +delayFeat = menu_originals.add_feature("Delay between scripts (ms)", "action_value_i", AutoloadParentId, function(f) + local r, s + repeat + r, s = input.get("Enter delay", f.value, 4, eInputType.IT_NUM) + if r == 2 then return HANDLER_POP end + system_wait(0) + until r == 0 - -- Hotkeys - menu_configuration_features.hotkeyparent = menu.add_feature("Hotkey notifications", "parent", menu_configuration_features.cheesemenuparent.id) + local num = tonumber(s) + if num and num >= f.min and num <= f.max then + f.value = num + end +end) +delayFeat.min = 0 +delayFeat.max = 1000 +delayFeat.mod = 1 +local delayVal = AutoloadTbl["autoload_delay_between_scripts"] +if type(delayVal) ~= "number" or delayVal < delayFeat.min then + delayVal = delayFeat.min +elseif delayVal > delayFeat.max then + delayVal = delayFeat.max +end +delayFeat.value = delayVal - menu.add_feature("Toggle notification", "toggle", menu_configuration_features.hotkeyparent.id, function(f) - stuff.hotkey_notifications.toggle = f.on - end).on = stuff.hotkey_notifications.toggle - menu.add_feature("Action notification", "toggle", menu_configuration_features.hotkeyparent.id, function(f) - stuff.hotkey_notifications.action = f.on - end).on = stuff.hotkey_notifications.action +local RefreshFeat = menu_originals.add_feature("Refresh Scripts", "action", ParentId, function(f) + LoadScripts(f) + notify("Refreshed scripts list.", 0xFF00FF00) +end) - -- Colors - local colorParent = menu.add_feature("Colors", "parent", menu_configuration_features.cheesemenuparent.id) - do - local tempColor = {} - for k, v in pairs(stuff.menuData.color) do - tempColor[#tempColor+1] = {k, v, sortname = k:gsub("feature_([^s])", "feature_a%1")} - end - table.sort(tempColor, function(a, b) return a["sortname"] < b["sortname"] end) +local function FocusFeat(f) + if f.data.parent then + f.data.parent:toggle() + end + f.data:select() +end - for _, v in pairs(tempColor) do - menu_configuration_features[v[1]] = {} - local vParent = menu.add_feature(v[1], "parent", colorParent.id) +local function ToggleFeat(f) + f.data:toggle() +end - menu_configuration_features[v[1]].r = menu.add_feature("Red", "autoaction_value_i", vParent.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - f.value = num - end - end - stuff.menuData.color:set_color(v[1], f.value) - end) - menu_configuration_features[v[1]].r.max = 255 - if type(v[2]) == "table" then - menu_configuration_features[v[1]].r.value = v[2].r - else - menu_configuration_features[v[1]].r.value = func.convert_int_to_rgba(v[2], "r") - end +local SearchParentId = menu_originals.add_feature("Search Script Features", "parent", ParentId).id +menu_originals.add_feature("Filter: ", "action", SearchParentId, function(f) + local r, s + repeat + r, s = input.get("Enter search query", f.data, 64, 0) + if r == 2 then return HANDLER_POP end + system_wait(0) + until r == 0 - menu_configuration_features[v[1]].g = menu.add_feature("Green", "autoaction_value_i", vParent.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - f.value = num - end - end - stuff.menuData.color:set_color(v[1], nil, f.value) - end) - menu_configuration_features[v[1]].g.max = 255 - if type(v[2]) == "table" then - menu_configuration_features[v[1]].g.value = v[2].g - else - menu_configuration_features[v[1]].g.value = func.convert_int_to_rgba(v[2], "g") - end + local threads = {} + for i=f.parent.child_count,2,-1 do + threads[#threads + 1] = create_thread(DeleteFeature, f.parent.children[i]) + end - menu_configuration_features[v[1]].b = menu.add_feature("Blue", "autoaction_value_i", vParent.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - f.value = num - end - end - stuff.menuData.color:set_color(v[1], nil, nil, f.value) - end) - menu_configuration_features[v[1]].b.max = 255 - if type(v[2]) == "table" then - menu_configuration_features[v[1]].b.value = v[2].b - else - menu_configuration_features[v[1]].b.value = func.convert_int_to_rgba(v[2], "b") - end + local waiting = true + while waiting do + local running = false + for i=1,#threads do + running = running or (not menu.has_thread_finished(threads[i])) + end + waiting = running + system_wait(0) + end - menu_configuration_features[v[1]].a = menu.add_feature("Alpha", "autoaction_value_i", vParent.id, function(f) - if cheeseUtils.get_key(0x65):is_down() or cheeseUtils.get_key(0x0D):is_down() then - local stat, num = input.get("num", "", 10, 3) - if stat == 0 and tonumber(num) then - f.value = num - end + s = Trim(s) + if s:len() == 0 then + f.data = "" + f.name = "Filter: " + return HANDLER_POP + end + + local count = 0 + for i=4,RefreshFeat.parent.child_count do + local child = RefreshFeat.parent.children[i] + if child.data and child.data.features and type(child.data.features) == "table" then + for j=1,#child.data.features do + local feat = child.data.features[j] + if feat then + if feat.name:lower():find(s:lower(), 1, true) then + if feat.type == 2048 then + menu_originals.add_feature(FileNameWithoutExtension(child.name) .. " | " .. feat.name, "parent", SearchParentId, ToggleFeat).data = feat + else + menu_originals.add_feature(FileNameWithoutExtension(child.name) .. " | " .. feat.name, "action", SearchParentId, FocusFeat).data = feat end - stuff.menuData.color:set_color(v[1], nil, nil, nil, f.value) - end) - menu_configuration_features[v[1]].a.max = 255 - if type(v[2]) == "table" then - menu_configuration_features[v[1]].a.value = v[2].a - else - menu_configuration_features[v[1]].a.value = func.convert_int_to_rgba(v[2], "a") + count = count + 1 end end end + end + end - -- loading default ui & settings - func.load_ui("default") - func.load_settings() + f.data = s + f.name = "Filter: <" .. s .. "> (" .. count .. ")" +end).data = "" - --changing menu functions to ui functions - local menu_get_feature_by_hierarchy_key = menu.get_feature_by_hierarchy_key - menu_originals = setmetatable({ - --get_feature_by_hierarchy_key = menu.get_feature_by_hierarchy_key, - add_feature = menu.add_feature, - add_player_feature = menu.add_player_feature, - delete_feature = menu.delete_feature, - delete_player_feature = menu.delete_player_feature, - get_player_feature = menu.get_player_feature, - }, {__newindex = function() end}) - menu.add_feature = func.add_feature - menu.add_player_feature = func.add_player_feature - menu.delete_feature = func.delete_feature - menu.delete_player_feature = func.delete_player_feature - menu.get_player_feature = func.get_player_feature - menu.get_feature_by_hierarchy_key = function(hierarchy_key) - if string.find(hierarchy_key:lower(), "trusted") or string.find(hierarchy_key:lower(), "Proddy's Script Manager") then - return +FilterFeat = menu_originals.add_feature("Filter: ", "action", ParentId, function(f) + local r, s + repeat + r, s = input.get("Enter search query", f.data, 64, 0) + if r == 2 then return HANDLER_POP end + system_wait(0) + until r == 0 + + s = Trim(s) + if s:len() == 0 then + f.data = "" + f.name = "Filter: " + for i=f.parent.child_count,FirstChild,-1 do + f.parent.children[i].hidden = false end - local feat, duplicate - feat = menu_get_feature_by_hierarchy_key(hierarchy_key) - if feat then - return feat + return HANDLER_POP + end + + local count = 0 + for i=f.parent.child_count,FirstChild,-1 do + if f.parent.children[i].name:lower():find(s, 1, true) then + f.parent.children[i].hidden = false + count = count + 1 else - feat, duplicate = func.get_feature_by_hierarchy_key(hierarchy_key) - if duplicate then - return feat[1] - else - return feat - end + f.parent.children[i].hidden = true end end - cheeseUIdata = stuff.menuData - -- - func.set_player_feat_parent("Online Players", 0) - -- Proddy's Script Manager - gltw.read("Trusted Flags", stuff.path.cheesemenu, stuff, true, true) - menu.is_trusted_mode_enabled = function(flag) - if not flag then - return stuff.trusted_mode & 7 == 7, stuff.trusted_mode_notification - else - return stuff.trusted_mode & flag == flag, stuff.trusted_mode_notification - end - end + f.data = s + f.name = "Filter: <" .. s .. "> (" .. count .. ")" +end) +FilterFeat.data = "" - dofile("\\scripts\\cheesemenu\\libs\\Proddy's Script Manager.lua") +ProddysScriptManager = true - do - local trusted_parent = menu_get_feature_by_hierarchy_key("local.script_features.cheese_menu.proddy_s_script_manager.trusted_mode") +create_thread(function(f) + FirstChild = Parent.child_count + 1 + AutoloadFirstChild = AutoloadParent.child_count + 1 + LoadScripts(f) - menu_originals.add_feature("Save Trusted Flags", "action", trusted_parent.id, function() - gltw.write({trusted_mode = stuff.trusted_mode, trusted_mode_notification = stuff.trusted_mode_notification}, "Trusted Flags", stuff.path.cheesemenu, nil, nil, true) - menu.notify("Saved Successfully", "Cheese Menu", 2, 0x00ff00) - end) + local delay = 0 + local autoload = {} + for k,v in pairs(AutoloadTbl) do + if k == "autoload_delay_between_scripts" then + if type(v) == "number" and v >= 0 then + delay = v + end + else + if type(v) ~= "number" then v = 1 end + autoload[v] = autoload[v] or {} + autoload[v][#autoload[v] + 1] = k + end + end - menu_originals.add_feature("Trusted Flags Notification", "toggle", trusted_parent.id, function(f) - stuff.trusted_mode_notification = f.on - end).on = stuff.trusted_mode_notification + print("Autoloading with delay: " .. delay) - local trusted_names = { - [0] = "Stats", - [1] = "Globals / Locals", - [2] = "Natives", - [3] = "HTTP", - [4] = "Memory" - } + if #autoload > 0 then + local scripts = {} + for i=FirstChild,Parent.child_count do + local feat = Parent.children[i] + scripts[feat.name] = feat + end - for i = 0, 4 do - menu_originals.add_feature(trusted_names[i], "toggle", trusted_parent.id, function(f) - if f.on then - stuff.trusted_mode = stuff.trusted_mode | 1 << i - else - stuff.trusted_mode = stuff.trusted_mode ~ 1 << i - end - end).on = stuff.trusted_mode & 1 << i ~= 0 + local ids = {} + for k in pairs(autoload) do + ids[#ids + 1] = k + end + table.sort(ids) + + for i=1,#ids do + local tbl = autoload[ids[i]] + for j=1,#tbl do + local script = scripts[tbl[j]] + if script then + system_wait(delay) + print("Enabled autoload script: " .. script.name) + script.on = true + end end end - -- -end -if httpTrustedOff then - loadCurrentMenu() -end]=], + end +end, RefreshFeat) + +--notify(ScriptName .. " v" .. Version .. " loaded.", 0xFF0FF00)]=], ["Get Input.lua"] = [=[--Made by GhostOne local cheeseUtils = require("cheesemenu.libs.CheeseUtilities") From 84edc9df866bcf37cc084fdfa799b35e10dc461f Mon Sep 17 00:00:00 2001 From: GhustOne <71855034+GhustOne@users.noreply.github.com> Date: Thu, 5 Jan 2023 23:41:02 +0300 Subject: [PATCH 10/11] Update CMAutoUpdater.lua --- CMAutoUpdater.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMAutoUpdater.lua b/CMAutoUpdater.lua index 45b4521..6c2e2fd 100644 --- a/CMAutoUpdater.lua +++ b/CMAutoUpdater.lua @@ -9,7 +9,7 @@ local filePaths = { ["Proddy's Script Manager.lua"] = appdata_path.."\\scripts\\cheesemenu\\libs\\Proddy's Script Manager.lua", } -local responseCode, responseBody = web.get([[https://raw.githubusercontent.com/GhustOne/CheeseMenu/main/aioUpdate.lua]]) +local responseCode, responseBody = web.get([[https://raw.githubusercontent.com/GhustOne/CheeseMenu/dev/aioUpdate.lua]]) if responseCode ~= 200 then print("Failed to download update.") status = false From 6a9c1f162749d1a2c397b685523257308a7b1a31 Mon Sep 17 00:00:00 2001 From: GhustOne <71855034+GhustOne@users.noreply.github.com> Date: Thu, 5 Jan 2023 23:46:28 +0300 Subject: [PATCH 11/11] Update CMAutoUpdater.lua --- CMAutoUpdater.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMAutoUpdater.lua b/CMAutoUpdater.lua index 6c2e2fd..45b4521 100644 --- a/CMAutoUpdater.lua +++ b/CMAutoUpdater.lua @@ -9,7 +9,7 @@ local filePaths = { ["Proddy's Script Manager.lua"] = appdata_path.."\\scripts\\cheesemenu\\libs\\Proddy's Script Manager.lua", } -local responseCode, responseBody = web.get([[https://raw.githubusercontent.com/GhustOne/CheeseMenu/dev/aioUpdate.lua]]) +local responseCode, responseBody = web.get([[https://raw.githubusercontent.com/GhustOne/CheeseMenu/main/aioUpdate.lua]]) if responseCode ~= 200 then print("Failed to download update.") status = false