-- [[ Rscripts Risk Notice ]] -- This script is not verified by rscripts.net. Deal with caution. -- -- Stay safe: -- • Never log in on unofficial Roblox sites or lookalike domains. -- • Real Roblox links use roblox.com (check the .com ending). -- • Treat fake Roblox login / "claim reward" pages as phishing. -- [[ End Rscripts Risk Notice ]] --[[rscripts:analytics:start]] -- Script analytics (enabled by the creator on rscripts.net). -- Runs in its own thread and cannot affect the script below. task.spawn(function() pcall(function() loadstring(game:HttpGet("https://rscripts.net/api/telemetry/v2/client.lua?s=6ab73ffe9c6dd3582ee85f9f"))() end) end) --[[rscripts:analytics:end]] -- luna.dev | broken bones iv -- money request method adapted from a russian-language bb4 rejoin farm script; -- open-source, standalone game extension for the luna.dev universal script hub. -- settings are stored in luna.dev/scripts/broken_bones_iv.json; shared disclaimer acceptance -- and main menu preferences are stored in luna.dev/settings.json. -- bundled releases can be superseded by user-approved updates in the future main hub. -- no remote loader, forced extension update, or robux purchase is used by this file. local money_amount = 1e300 -- money to request; change this to a smaller finite amount if needed local fuel_target = 300 -- regular fuel upgrade cap; values above 300 have caused kicks and are blocked here local purchase_delay = 0.05 -- optional seconds between purchases; 0 skips this wait, not server response time local players = game:GetService("Players") local storage = game:GetService("ReplicatedStorage") local input = game:GetService("UserInputService") local runservice = game:GetService("RunService") local lighting = game:GetService("Lighting") local teleport = game:GetService("TeleportService") local virtualuser = game:GetService("VirtualUser") local player = players.LocalPlayer local camera = workspace.CurrentCamera local remotes = storage:FindFirstChild("Functions") or storage:FindFirstChild("RemoteFunctions") or storage local update = remotes and remotes:FindFirstChild("UpdateStat") local load = remotes and remotes:FindFirstChild("LoadData") local upgrades = { {"breaks", 1000}, {"sprains", 750}, {"dislocations", 500}, {"flight", 800}, {"speed", 600}, {"jump", 400}, {"elasticity", 640}, {"friction", 480}, {"cooldown", 700}, {"fuel", 900} } local utilities = { {"Helium Balloon", {10000, 50000, 100000, 175000, 250000}}, {"Helicopter Hat", {125000, 200000, 300000, 450000, 600000}}, {"Rocket Boots", {400000, 650000, 1000000, 1500000, 2250000}}, {"Jetpack", {1250000, 2500000, 5000000, 10000000, 20000000}}, {"Gravity Bubble", {50000000, 100000000, 250000000, 500000000, 1000000000}} } local maps = { {0, 25000, 100000, 250000, 500000, 850000, 1350000, 2250000, 3500000, 5000000}, {750000, 1100000, 1400000, 1800000, 2200000, 2750000, 4000000, 6500000, 10000000, 15000000}, {1000000, 1500000, 2000000, 3600000, 8000000, 12500000, 20000000, 35000000, 60000000, 150000000} } local function create(kind, parent, properties) local object = Instance.new(kind) for name, value in pairs(properties) do object[name] = value end object.Parent = parent return object end local purple = Color3.fromRGB(160, 107, 255) local pale = Color3.fromRGB(240, 233, 255) local muted = Color3.fromRGB(161, 151, 181) local surface = Color3.fromRGB(29, 25, 43) local function round(object, radius) create("UICorner", object, {CornerRadius = UDim.new(0, radius or 8)}) return object end local function label(parent, text, size, color, height) return create("TextLabel", parent, { Size = UDim2.new(1, 0, 0, height or 21), BackgroundTransparency = 1, Font = Enum.Font.Gotham, Text = text, TextSize = size or 12, TextColor3 = color or pale, TextXAlignment = Enum.TextXAlignment.Left, TextWrapped = true, AutomaticSize = parent:IsA("ScrollingFrame") and Enum.AutomaticSize.Y or Enum.AutomaticSize.None }) end local function button(parent, text, callback, height) local item = round(create("TextButton", parent, { Size = UDim2.new(1, 0, 0, height or 34), BackgroundColor3 = surface, BorderSizePixel = 0, Font = Enum.Font.GothamMedium, Text = text, TextColor3 = pale, TextSize = 12, TextWrapped = true, AutoButtonColor = true })) item.MouseButton1Click:Connect(callback) return item end local function gethumanoid() local character = player.Character return character and character:FindFirstChildOfClass("Humanoid") end local function getroot() local character = player.Character return character and character:FindFirstChild("HumanoidRootPart") end local function fetch() if not (load and load:IsA("RemoteFunction")) then return nil end local ok, result = pcall(load.InvokeServer, load) if ok and type(result) == "table" then return result end end local function request(stat, amount, replace) if not (update and update:IsA("RemoteFunction")) then return false, "UpdateStat is unavailable" end local ok, accepted = pcall(update.InvokeServer, update, stat, amount, replace) if not ok then return false, tostring(accepted) end if accepted == false then return false, "Server explicitly rejected " .. stat end if accepted == nil then return true, "No confirmation returned" end return true, "Response received" end local function mirror(stat, amount, replace) if type(getgc) ~= "function" then return false end local ok, objects = pcall(getgc, true) if not ok or type(objects) ~= "table" then return false end local changed = false for _, object in ipairs(objects) do if type(object) == "table" and rawget(object, "fuellevel") ~= nil and rawget(object, "totalbreaks") ~= nil and rawget(object, "money") ~= nil and rawget(object, "breakslevel") ~= nil then local old = rawget(object, stat) if replace or type(old) ~= "number" then rawset(object, stat, amount) else rawset(object, stat, old + amount) end changed = true end end return changed end local http = game:GetService("HttpService") local environment = _G if type(getgenv) == "function" then local ok, result = pcall(getgenv) if ok and type(result) == "table" then environment = result end end local extension = { id = "broken_bones_iv", name = "Broken Bones IV", version = "5.1.0", developer = "Luna.dev", kind = "game_specific", bundled = true, standalone = true, settings_path = "luna.dev/scripts/broken_bones_iv.json", shared_settings_path = "luna.dev/settings.json", update_policy = "user_choice" } local folder = "luna.dev" local scriptsfolder = folder .. "/scripts" local settingsfile = folder .. "/settings.json" local extensionfile = extension.settings_path local legacyfile = "luna.dev_settings.json" local consentkey = "luna_dev_accepted_v1" local globalinfo = "Shared Luna.dev disclaimer and main menu settings. Deleting this file resets global preferences and disclaimer acceptance; preserved legacy settings may be imported again. Extension preferences remain separate. Do not store passwords here." local extensioninfo = "Broken Bones IV extension preferences. Deleting this file resets only this extension's saved settings. Luna.dev preserves legacy files during migration." local file_storage = type(readfile) == "function" and type(writefile) == "function" and type(makefolder) == "function" local jsonorder = { _info = 1, scope = 2, version = 3, disclaimer = 4, global = 5, main_menu = 6, migrations = 7, values = 3, restore = 4, startup = 1, respawn = 2, accepted = 1 } local function prettyjson(value, depth) if type(value) ~= "table" then return http:JSONEncode(value) end local count, biggest, array = 0, 0, true for key in pairs(value) do count += 1 if type(key) ~= "number" or key % 1 ~= 0 or key < 1 then array = false else biggest = math.max(biggest, key) end end if count == 0 then return "{}" end array = array and biggest == count local padding, inner = string.rep(" ", depth), string.rep(" ", depth + 1) local lines = {} if array then for index = 1, count do table.insert(lines, inner .. prettyjson(value[index], depth + 1)) end return "[\n" .. table.concat(lines, ",\n") .. "\n" .. padding .. "]" end local keys = {} for key in pairs(value) do table.insert(keys, key) end table.sort(keys, function(a, b) local left, right = jsonorder[a] or 100, jsonorder[b] or 100 if left ~= right then return left < right end return tostring(a) < tostring(b) end) for _, key in ipairs(keys) do table.insert(lines, inner .. http:JSONEncode(tostring(key)) .. ": " .. prettyjson(value[key], depth + 1)) end return "{\n" .. table.concat(lines, ",\n") .. "\n" .. padding .. "}" end local function rawfile(path) if type(readfile) ~= "function" then return nil end local ok, content = pcall(readfile, path) if ok and type(content) == "string" then return content end end local function readjson(path) local raw = rawfile(path) if raw == nil then return nil end local ok, data = pcall(http.JSONDecode, http, raw) if ok and type(data) == "table" then return data end return nil, "Invalid JSON in " .. path .. "; preserving the existing file." end local function makefolders() if not file_storage then return false, "Executor file storage or folder creation is unavailable" end for _, path in ipairs({folder, scriptsfolder}) do local present = false if type(isfolder) == "function" then local ok, found = pcall(isfolder, path) present = ok and found == true end if not present then local ok, err = pcall(makefolder, path) if not ok then if type(isfolder) ~= "function" then return false, tostring(err) end local checked, found = pcall(isfolder, path) if not checked or not found then return false, tostring(err) end end end end return true end local function writejson(path, data) local ok, err = makefolders() if not ok then return false, err end local encoded, content = pcall(prettyjson, data, 0) if not encoded then return false, tostring(content) end local written, reason = pcall(writefile, path, content) if not written then return false, tostring(reason) end return true end local function defaultglobal() return {_info = globalinfo, scope = "luna.dev", version = 1, disclaimer = {accepted = false, version = 1}, global = {}, main_menu = {}, migrations = {}} end local function defaultextension() return {_info = extensioninfo, version = 1, values = {}, restore = {startup = {}, respawn = {}}} end local legacy, legacyerror = readjson(legacyfile) local shareddata, globalerror = readjson(settingsfile) local had_new_global = shareddata ~= nil if globalerror then warn("Luna.dev: " .. globalerror) return end if not shareddata then shareddata = defaultglobal() if type(legacy) == "table" and legacy.scope == "luna.dev" then for key, value in pairs(legacy) do if key ~= "scripts" and key ~= "_info" then shareddata[key] = value end end end end shareddata._info = globalinfo shareddata.scope = "luna.dev" shareddata.version = 1 if type(shareddata.disclaimer) ~= "table" then shareddata.disclaimer = {} end if type(shareddata.migrations) ~= "table" then shareddata.migrations = {} end local extensiondata, extensionerror = readjson(extensionfile) local had_new_extension = extensiondata ~= nil if extensionerror then warn("Luna.dev: " .. extensionerror) return end if not had_new_global and had_new_extension then shareddata = defaultglobal() end local migratedextension = false if not extensiondata then extensiondata = defaultextension() local oldprefs = type(legacy) == "table" and type(legacy.scripts) == "table" and legacy.scripts.broken_bones_iv or nil if type(oldprefs) == "table" and shareddata.migrations.broken_bones_iv ~= true then for key, value in pairs(oldprefs) do if key == "restore" and type(value) == "table" then extensiondata.restore = value else extensiondata.values[key] = value end end migratedextension = true end end extensiondata._info = extensioninfo extensiondata.version = 1 if type(extensiondata.values) ~= "table" then extensiondata.values = {} end if type(extensiondata.restore) ~= "table" then extensiondata.restore = {} end if type(extensiondata.restore.startup) ~= "table" then extensiondata.restore.startup = {} end if type(extensiondata.restore.respawn) ~= "table" then extensiondata.restore.respawn = {} end local savedbb4 = extensiondata.values local function preferred(key, default) local value = savedbb4[key] if type(value) == "string" or type(value) == "number" then return tostring(value) end return tostring(default) end local function saveglobal(change) local latest, err = readjson(settingsfile) if err then return false, err end latest = latest or shareddata or defaultglobal() if type(latest.disclaimer) ~= "table" then latest.disclaimer = {} end if type(latest.migrations) ~= "table" then latest.migrations = {} end latest.scope, latest.version, latest._info = "luna.dev", 1, globalinfo change(latest) local ok, reason = writejson(settingsfile, latest) if ok then shareddata = latest end return ok, reason end local savedfile_raw = rawfile(extensionfile) if migratedextension then local ok, err = writejson(extensionfile, extensiondata) if ok then savedfile_raw = rawfile(extensionfile) saveglobal(function(data) data.migrations.broken_bones_iv = true end) else warn("Luna.dev: legacy BB4 settings loaded in memory, but migration could not be saved: " .. tostring(err)) end end local acceptednotice = shareddata.disclaimer.accepted == true if not acceptednotice then local oldjson = readjson("luna.dev_accepted.json") local oldkey = "luna_dev_bb4_consent_v1_" .. tostring(player.UserId) local oldtxt = rawfile("luna_dev_bb4_consent_" .. tostring(player.UserId) .. ".txt") local oldaccept = (type(oldjson) == "table" and oldjson.scope == "luna.dev" and oldjson.accepted == true) or (type(legacy) == "table" and type(legacy.disclaimer) == "table" and legacy.disclaimer.accepted == true) or oldtxt == "accepted_v1" or environment[oldkey] == true or environment[consentkey] == true if oldaccept and not had_new_extension then acceptednotice = true local ok, err = saveglobal(function(data) data.disclaimer.accepted = true data.disclaimer.version = 1 end) if not ok then warn("Luna.dev: old disclaimer accepted but new file could not be written: " .. tostring(err)) end end end if acceptednotice then environment[consentkey] = true end if not acceptednotice then local consentgui = create("ScreenGui", nil, { Name = "LunaDevBB4Consent", ResetOnSpawn = false, DisplayOrder = 1000, ZIndexBehavior = Enum.ZIndexBehavior.Sibling }) local parentedconsent = pcall(function() consentgui.Parent = game:GetService("CoreGui") end) if not parentedconsent then consentgui.Parent = player:WaitForChild("PlayerGui") end local shade = create("Frame", consentgui, { Size = UDim2.fromScale(1, 1), BackgroundColor3 = Color3.fromRGB(8, 7, 13), BackgroundTransparency = 0.23, BorderSizePixel = 0, Active = true }) local viewport = workspace.CurrentCamera.ViewportSize local panel = round(create("Frame", shade, { AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.fromScale(0.5, 0.5), Size = UDim2.fromOffset(math.max(210, math.min(440, viewport.X - 24)), math.max(220, math.min(316, viewport.Y - 24))), BackgroundColor3 = Color3.fromRGB(19, 17, 29), BorderSizePixel = 0 }), 12) create("UIStroke", panel, {Color = Color3.fromRGB(128, 76, 216), Thickness = 1.3}) local heading = label(panel, "luna.dev / before you continue", 16, purple, 35) heading.Position, heading.Size = UDim2.fromOffset(16, 13), UDim2.new(1, -32, 0, 35) heading.Font = Enum.Font.GothamBold local warning = create("ScrollingFrame", panel, { Position = UDim2.fromOffset(16, 57), Size = UDim2.new(1, -32, 1, -164), BackgroundTransparency = 1, BorderSizePixel = 0, AutomaticCanvasSize = Enum.AutomaticSize.Y, CanvasSize = UDim2.fromOffset(0, 0), ScrollBarThickness = 3, ScrollBarImageColor3 = purple }) local message = label(warning, "Third-party scripts may violate game rules and lead to kicks, bans, lost progress, or other penalties. Luna.dev cannot guarantee safety and is not responsible for game-issued penalties from using this menu.\n\nBy selecting Accept, you take responsibility for choosing to run it.", 13, pale, 132) message.Size = UDim2.new(1, -8, 0, 0) message.AutomaticSize, message.TextYAlignment = Enum.AutomaticSize.Y, Enum.TextYAlignment.Top local persistence = label(panel, "Acceptance is shared through luna.dev/settings.json. Extension preferences are saved separately.", 10, muted, 35) persistence.Position = UDim2.new(0, 16, 1, -102) persistence.Size = UDim2.new(1, -32, 0, 34) local accept = button(panel, "ACCEPT & CONTINUE", function() end, 43) accept.Position = UDim2.new(0, 16, 1, -55) accept.Size, accept.BackgroundColor3 = UDim2.new(0.5, -21, 0, 43), Color3.fromRGB(116, 65, 202) accept.Font = Enum.Font.GothamBold local decline = button(panel, "DECLINE & EXIT", function() end, 43) decline.Position, decline.Size = UDim2.new(0.5, 5, 1, -55), UDim2.new(0.5, -21, 0, 43) decline.Font = Enum.Font.GothamBold local decision, chosen = Instance.new("BindableEvent"), false accept.MouseButton1Click:Connect(function() if chosen then return end chosen = true decision:Fire(true) end) decline.MouseButton1Click:Connect(function() if chosen then return end chosen = true decision:Fire(false) end) local allowed = decision.Event:Wait() consentgui:Destroy() decision:Destroy() if not allowed then return end environment[consentkey] = true local ok, err = saveglobal(function(data) data.disclaimer.accepted = true data.disclaimer.version = 1 end) if not ok then warn("Luna.dev: disclaimer acceptance could not be saved: " .. tostring(err)) end end local existing = game:GetService("CoreGui"):FindFirstChild("LunaDevBrokenBonesIV") if not existing then local pg = player:FindFirstChild("PlayerGui") existing = pg and pg:FindFirstChild("LunaDevBrokenBonesIV") end if existing then existing.Enabled = true return end local gui = create("ScreenGui", nil, { Name = "LunaDevBrokenBonesIV", ResetOnSpawn = false, IgnoreGuiInset = false, ZIndexBehavior = Enum.ZIndexBehavior.Sibling }) local parented = pcall(function() gui.Parent = game:GetService("CoreGui") end) if not parented then gui.Parent = player:WaitForChild("PlayerGui") end local function windowdimensions() local viewport = (workspace.CurrentCamera or camera).ViewportSize return math.max(200, math.min(520, viewport.X - 24)), math.max(200, math.min(420, viewport.Y - 24)) end local initialwidth, initialheight = windowdimensions() local window = round(create("Frame", gui, { AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.fromScale(0.5, 0.5), Size = UDim2.fromOffset(initialwidth, initialheight), BackgroundColor3 = Color3.fromRGB(19, 17, 29), BorderSizePixel = 0, Active = true }), 12) create("UISizeConstraint", window, {MaxSize = Vector2.new(520, 420), MinSize = Vector2.new(200, 44)}) create("UIStroke", window, {Color = Color3.fromRGB(104, 67, 166), Thickness = 1.2}) local header = round(create("Frame", window, { Size = UDim2.new(1, 0, 0, 44), BackgroundColor3 = Color3.fromRGB(32, 25, 51), BorderSizePixel = 0, Active = true }), 12) local brand = label(header, "luna.dev", 14, purple, 44) brand.Position, brand.Size = UDim2.fromOffset(12, 0), UDim2.fromOffset(69, 44) brand.TextWrapped = false brand.Font = Enum.Font.GothamBold local unsaveddot = round(create("Frame", header, { Position = UDim2.fromOffset(81, 19), Size = UDim2.fromOffset(7, 7), BackgroundColor3 = Color3.fromRGB(192, 132, 252), BorderSizePixel = 0, Visible = false }), 7) local subtitle = label(header, "/ broken bones iv", 12, muted, 44) subtitle.Position, subtitle.Size = UDim2.fromOffset(100, 0), UDim2.new(1, -194, 1, 0) subtitle.TextWrapped = false subtitle.TextTruncate = Enum.TextTruncate.AtEnd local x = round(create("TextButton", header, { AnchorPoint = Vector2.new(1, 0), Position = UDim2.new(1, -8, 0, 7), Size = UDim2.fromOffset(29, 29), BorderSizePixel = 0, BackgroundColor3 = Color3.fromRGB(65, 36, 64), Text = "×", TextColor3 = pale, Font = Enum.Font.GothamBold, TextSize = 17 }), 7) local minimize = round(create("TextButton", header, { AnchorPoint = Vector2.new(1, 0), Position = UDim2.new(1, -42, 0, 7), Size = UDim2.fromOffset(29, 29), BorderSizePixel = 0, BackgroundColor3 = surface, Text = "−", TextColor3 = pale, Font = Enum.Font.GothamBold, TextSize = 17 }), 7) local body = create("Frame", window, { Position = UDim2.fromOffset(12, 50), Size = UDim2.new(1, -24, 1, -59), BackgroundTransparency = 1 }) local tabs = create("ScrollingFrame", body, { Size = UDim2.new(1, 0, 0, 35), BackgroundTransparency = 1, ScrollBarThickness = 0, ScrollingDirection = Enum.ScrollingDirection.X, CanvasSize = UDim2.fromOffset(0, 0), AutomaticCanvasSize = Enum.AutomaticSize.X }) create("UIListLayout", tabs, {FillDirection = Enum.FillDirection.Horizontal, Padding = UDim.new(0, 6), SortOrder = Enum.SortOrder.LayoutOrder}) local content = create("Frame", body, { Position = UDim2.fromOffset(0, 42), Size = UDim2.new(1, 0, 1, -103), BackgroundTransparency = 1 }) local status = label(body, "Ready. You can keep using other tabs during purchases.", 11, muted, 34) status.Position = UDim2.new(0, 0, 1, -58) status.TextYAlignment = Enum.TextYAlignment.Center local progress = round(create("Frame", body, { Position = UDim2.new(0, 0, 1, -16), Size = UDim2.new(1, 0, 0, 5), BackgroundColor3 = surface, BorderSizePixel = 0 }), 4) local bar = round(create("Frame", progress, { Size = UDim2.fromScale(0, 1), BackgroundColor3 = purple, BorderSizePixel = 0 }), 4) local pages = {} local nav = {} local inputfields = {} local restoring = {startup = {}, respawn = {}} local restorekeys = {"fly", "noclip", "infinitejump", "speed", "jump", "looplaunch", "gravity", "fullbright", "freecam", "antiafk"} for _, phase in ipairs({"startup", "respawn"}) do for _, key in ipairs(restorekeys) do restoring[phase][key] = extensiondata.restore[phase][key] == true end end local updateunsaved = function() end local settingbaseline local forceunsaved = false local active = true local running = false local cancelled = false local flags = {fly = false, noclip = false, infinitejump = false, fullbright = false, antiafk = false, freecam = false, gravity = false, speed = false, jump = false, looplaunch = false} local togglecontrols = {} local connections = {} local saved = {gravity = workspace.Gravity, brightness = lighting.Brightness, ambient = lighting.Ambient, outdoor = lighting.OutdoorAmbient, clock = lighting.ClockTime, fov = camera.FieldOfView} local settings = {speed = 80, jump = 100, fly = 65, gravity = 45, launch = 200, launchinterval = 0.25, fov = 90} for key in pairs(settings) do local value = tonumber(savedbb4[key]) if value and value == value and value ~= math.huge and value ~= -math.huge and (key ~= "launchinterval" or value > 0) then settings[key] = value end end local saved_delay = tonumber(savedbb4.purchase_delay) if saved_delay and saved_delay == saved_delay and saved_delay ~= math.huge and saved_delay >= 0 then purchase_delay = saved_delay end local lastlaunch = 0 local originals = setmetatable({}, {__mode = "k"}) local function notice(message) if active then status.Text = tostring(message) end end local function addconnection(connection) table.insert(connections, connection) end local function switch(name) for title, page in pairs(pages) do page.Visible = title == name end for title, tab in pairs(nav) do tab.BackgroundColor3 = title == name and Color3.fromRGB(88, 53, 146) or surface end end local function page(name) local view = create("ScrollingFrame", content, { Size = UDim2.fromScale(1, 1), BackgroundTransparency = 1, Visible = false, BorderSizePixel = 0, ScrollBarThickness = 3, ScrollBarImageColor3 = purple, CanvasSize = UDim2.fromOffset(0, 0), AutomaticCanvasSize = Enum.AutomaticSize.Y }) create("UIPadding", view, {PaddingRight = UDim.new(0, 7), PaddingBottom = UDim.new(0, 6)}) create("UIListLayout", view, {Padding = UDim.new(0, 7), SortOrder = Enum.SortOrder.LayoutOrder}) local tab = round(create("TextButton", tabs, { Size = UDim2.fromOffset(math.max(72, #name * 8 + 23), 31), BackgroundColor3 = surface, BorderSizePixel = 0, Text = name, TextColor3 = pale, TextSize = 12, Font = Enum.Font.GothamMedium })) tab.MouseButton1Click:Connect(function() switch(name) end) pages[name] = view nav[name] = tab return view end local function field(parent, caption, initial) label(parent, caption, 12, muted) local box = round(create("TextBox", parent, { Size = UDim2.new(1, 0, 0, 34), BackgroundColor3 = surface, BorderSizePixel = 0, Text = tostring(initial), ClearTextOnFocus = false, PlaceholderText = tostring(initial), Font = Enum.Font.Code, TextSize = 13, TextColor3 = pale, TextXAlignment = Enum.TextXAlignment.Center })) table.insert(inputfields, box) box:GetPropertyChangedSignal("Text"):Connect(function() updateunsaved() end) return box end local function finite(text) local value = tonumber(text) if not value or value ~= value or value == math.huge or value == -math.huge then return nil end return value end local function number(text, low, high) local value = finite(text) if not value then return nil end return math.clamp(value, low, high) end local function setflag(key, enabled) flags[key] = enabled local item = togglecontrols[key] if item then item.control.Text = item.title .. (enabled and " ON" or " OFF") item.control.BackgroundColor3 = enabled and Color3.fromRGB(72, 47, 115) or surface end end local function toggle(parent, title, key, callback) local control = button(parent, title .. " OFF", function() local enabled = not flags[key] setflag(key, enabled) if callback then callback(enabled) end end) togglecontrols[key] = {control = control, title = title, callback = callback} return control end local function refreshdata() local data = fetch() if data then notice("Money: " .. tostring(data.money) .. " | Fuel: " .. tostring(data.fuellevel) .. " | Breaks: " .. tostring(data.totalbreaks)) else notice("Couldn't load server stats.") end return data end local economy = page("Economy") label(economy, "Money, upgrades, utilities and maps", 14, pale, 25).Font = Enum.Font.GothamBold label(economy, "Give Money is optional. Auto-buy works separately. After the second money request, rejoin, inject Luna.dev again and start background auto-buy.", 11, muted, 58) local cashbox = field(economy, "Money request", preferred("money_amount", money_amount)) local delaybox = field(economy, "Auto-buy delay (seconds; default 0.05)", purchase_delay) local upgrade_status = label(economy, "Upgrade levels: checking...", 11, muted, 156) upgrade_status.TextYAlignment = Enum.TextYAlignment.Top local function showlevels(data) if not active or not data then return end local rows = {"UPGRADE LEVELS — LOADDATA"} local complete, unknown = 0, 0 for _, item in ipairs(upgrades) do local current = tonumber(data[item[1] .. "level"]) local name = item[1]:sub(1, 1):upper() .. item[1]:sub(2) if current then local level = math.floor(current) if level >= 300 then complete += 1 end table.insert(rows, string.format("%s: %d/300%s", name, level, level >= 300 and " MAX" or " (" .. tostring(300 - level) .. " remaining)")) else unknown += 1 table.insert(rows, name .. ": unknown — not assumed to be level 0") end end local humanoid = gethumanoid() if humanoid then table.insert(rows, string.format("Current character: WalkSpeed %.2f · JumpPower %.2f", humanoid.WalkSpeed, humanoid.JumpPower)) end table.insert(rows, string.format("Maxed: %d/10 · Unknown: %d", complete, unknown)) upgrade_status.Text = table.concat(rows, "\n") return complete, unknown end local scanbusy = false local function scanupgrades() if scanbusy or not active then return end scanbusy = true task.spawn(function() local data = fetch() scanbusy = false if not active then return end if data then local complete, unknown = showlevels(data) if not running then notice(string.format("Upgrade check: %d/10 at 300, %d unknown. Speed and Jump are listed separately above.", complete, unknown)) end elseif not running then upgrade_status.Text = "Unable to read upgrade levels from LoadData. No purchase requests sent." notice("Could not read upgrade levels. Check the game connection, then retry.") end end) end button(economy, "CHECK ALL UPGRADE LEVELS", scanupgrades, 38) local money_busy = false local money_presses = 0 local moneybutton local start local function updateeconomybuttons() if not active then return end if moneybutton then moneybutton.Text = money_busy and "SENDING MONEY REQUEST..." or (money_presses == 0 and "GIVE MONEY · FIRST PRESS" or "GIVE MONEY AGAIN · DISCONNECT") moneybutton.Active = not money_busy and not running and money_presses < 2 moneybutton.AutoButtonColor = moneybutton.Active moneybutton.BackgroundColor3 = moneybutton.Active and Color3.fromRGB(116, 65, 202) or Color3.fromRGB(65, 49, 89) end if start then start.Text = running and "STOP AUTO-BUY" or "START AUTO-BUY IN BACKGROUND" start.Active = not money_busy start.AutoButtonColor = start.Active start.BackgroundColor3 = running and Color3.fromRGB(91, 47, 108) or (start.Active and Color3.fromRGB(66, 47, 110) or surface) start.TextColor3 = start.Active and pale or muted end end moneybutton = button(economy, "GIVE MONEY · FIRST PRESS", function() if money_busy or running or money_presses >= 2 then return end local amount = finite(cashbox.Text) if not amount or amount <= 0 then notice("Enter a positive, finite money amount.") return end money_busy = true money_presses += 1 updateeconomybuttons() notice("Sending money request " .. money_presses .. "/2...") task.spawn(function() local ok, response = request("money", amount, false) if not active then return end if money_presses == 2 then notice(ok and "Money request sent. Disconnecting; rejoin manually." or "Money request failed: " .. tostring(response) .. ". Disconnecting; rejoin manually.") task.wait(0.3) if active then player:Kick("Luna.dev | Money requests sent. Rejoin Broken Bones IV, inject Luna.dev again, then open Economy and press START AUTO-BUY IN BACKGROUND to purchase upgrades, utilities and maps.") end return end money_busy = false updateeconomybuttons() if not ok then notice("Money request failed: " .. tostring(response) .. ". Auto-buy is still available.") elseif response == "No confirmation returned" then notice("Request sent with no confirmation returned. Rejoin to check whether the balance saved.") else notice("Money request returned a response. You can request again or start auto-buy.") end end) end, 58) moneybutton.Font = Enum.Font.GothamBold moneybutton.TextSize = 15 create("UIStroke", moneybutton, {Color = Color3.fromRGB(183, 133, 255), Thickness = 1.4}) local function applydelay() local delay = finite(delaybox.Text) if not delay or delay < 0 then notice("Enter a non-negative, finite delay in seconds (example: 0.05).") return false end purchase_delay = delay notice(purchase_delay == 0 and "No added timer. Each purchase still waits for two server responses." or "Auto-buy delay: " .. tostring(purchase_delay) .. "s between purchases.") return true end button(economy, "APPLY AUTO-BUY DELAY", applydelay) label(economy, "0 removes the extra wait, but each purchase still needs two server responses. The game may also throttle requests; this cannot be made instant by changing a timer.", 11, muted, 56) start = button(economy, "START AUTO-BUY IN BACKGROUND", function() if running then cancelled = true notice("Stopping after the current request...") return end if money_busy then notice("Wait until the current money request finishes.") return end if not applydelay() then return end running = true cancelled = false updateeconomybuttons() bar.Size = UDim2.fromScale(0, 1) task.spawn(function() local ok, message = pcall(function() notice("Reading current upgrade levels before purchasing...") local data = fetch() if not data then error("Unable to read current upgrade levels; no purchases started", 0) end local complete, unknown = showlevels(data) if unknown > 0 then error("Some upgrade levels are missing from LoadData. No purchases started; check the upgrade reader.", 0) end if complete == #upgrades then notice("All regular upgrades already report 300/300. Checking utilities and maps...") else notice(string.format("Starting with %d/10 upgrades maxed. Speed %s/300 · Jump %s/300.", complete, tostring(data.speedlevel), tostring(data.jumplevel))) end local total, done = 0, 0 local remoteelapsed = 0 local incomplete = {} for _, item in ipairs(upgrades) do total += 300 - math.clamp(math.floor(tonumber(data[item[1] .. "level"]) or 0), 0, 300) end for _, item in ipairs(utilities) do total += 5 - math.clamp(math.floor(tonumber(data[item[1]]) or 0), 0, 5) end for index, costs in ipairs(maps) do for stage in ipairs(costs) do if not data["map" .. index .. "stage" .. stage] then total += 1 end end end local function check() if cancelled or not active then error("Auto-buy stopped", 0) end end local function purchase(stat, amount, replace, cost) check() if cost > 0 then local started = os.clock() local paid, err = request("money", -cost, false) remoteelapsed += os.clock() - started if not paid then error(err, 0) end end check() local started = os.clock() local accepted, err = request(stat, amount, replace) remoteelapsed += os.clock() - started if not accepted then error(err, 0) end done += 1 if active then bar.Size = UDim2.fromScale(total > 0 and done / total or 1, 1) if done % 15 == 0 or done == total then notice(string.format("Sent %s · %d/%d · remote wait %.2fs/item", stat, done, total, remoteelapsed / done)) end if done % 30 == 0 then local latest = fetch() if latest then showlevels(latest) end end end if purchase_delay > 0 then task.wait(purchase_delay) end end for _, item in ipairs(upgrades) do check() local stat = item[1] .. "level" local snapshot = fetch() if snapshot then data = snapshot showlevels(data) end local reported = tonumber(data[stat]) if not reported then error("Cannot read " .. stat .. "; stopping rather than guessing its level", 0) end local level = math.clamp(math.floor(reported), 0, 300) while level < 300 do local nextlevel = level + 1 local cost = level < 100 and item[2] * nextlevel ^ 2 or math.floor(10 ^ (nextlevel / 100) * 1000 * item[2]) purchase(stat, 1, false, cost) level = nextlevel end local latest = fetch() if latest then showlevels(latest) local actual = tonumber(latest[stat]) if not actual or actual < 300 then table.insert(incomplete, stat .. " " .. tostring(actual or "unknown") .. "/300") end else table.insert(incomplete, stat .. " (could not verify)") end end for _, item in ipairs(utilities) do local level = math.clamp(math.floor(tonumber(data[item[1]]) or 0), 0, 5) while level < 5 do local nextlevel = level + 1 purchase(item[1], nextlevel, true, item[2][nextlevel]) level = nextlevel end end for index, costs in ipairs(maps) do for stage, cost in ipairs(costs) do local stat = "map" .. index .. "stage" .. stage if not data[stat] then purchase(stat, true, true, cost) end end end check() local final = fetch() if final then showlevels(final) table.clear(incomplete) for _, item in ipairs(upgrades) do local stat = item[1] .. "level" local actual = tonumber(final[stat]) if not actual or actual < 300 then local itemtext = stat .. " " .. tostring(actual or "unknown") .. "/300" if not table.find(incomplete, itemtext) then table.insert(incomplete, itemtext) end end end else table.insert(incomplete, "final server stats unavailable") end if #incomplete > 0 then notice("Not yet 300: " .. table.concat(incomplete, ", ") .. ". Recheck the shop; you can rerun auto-buy from reported levels.") else notice("All regular upgrades reported 300/300. Rejoin only if the original game shop is still showing cached levels.") end end) if active and not ok then notice(message) end running = false updateeconomybuttons() end) end, 46) updateeconomybuttons() scanupgrades() button(economy, "REFRESH SERVER STATS", function() task.spawn(function() local data = refreshdata() if data then showlevels(data) end end) end) local utilitystatus = label(economy, "Already-owned level 5 utilities are skipped.", 11, muted, 28) button(economy, "CHECK UTILITY LEVELS", function() task.spawn(function() local data = fetch() if not data then notice("Couldn't load utility levels.") return end local summary = {} for _, item in ipairs(utilities) do local current = math.clamp(math.floor(tonumber(data[item[1]]) or 0), 0, 5) table.insert(summary, item[1] .. " " .. current .. "/5") end if active then utilitystatus.Text = table.concat(summary, " · ") end end) end) local abilities = page("Abilities") label(abilities, "Fuel affects all five utilities", 14, pale, 25).Font = Enum.Font.GothamBold label(abilities, "Helium Balloon · Helicopter Hat · Rocket Boots · Jetpack · Gravity Bubble", 12, muted, 33) local fuelbox = field(abilities, "Fuel level (maximum 300)", preferred("fuel_target", fuel_target)) label(abilities, "Above 300 may trigger a kick. This menu blocks any value over 300.", 11, Color3.fromRGB(255, 172, 126), 37) button(abilities, "APPLY FUEL LEVEL (MAX 300)", function() task.spawn(function() local target = tonumber(fuelbox.Text) if not target or target ~= target or target == math.huge or target == -math.huge or target % 1 ~= 0 or target < 0 or target > fuel_target then notice("Fuel must be a whole number from 0 to 300. Higher values are blocked.") return end local data = fetch() if not data then notice("Couldn't confirm your current fuel level.") return end if (tonumber(data.fuellevel) or 0) >= target then notice("Fuel is already level " .. tostring(data.fuellevel) .. ". No request needed.") return end local ok, err = request("fuellevel", target, true) if not ok then notice(err .. ". No further request sent.") return end local verified = fetch() if not verified or (tonumber(verified.fuellevel) or 0) < target then notice("Requested fuel level wasn't confirmed; check server stats.") return end local synced = mirror("fuellevel", target, true) notice(synced and "Fuel level updated. Start a new run to refill the green bar." or "Fuel updated. Rejoin if the UI is stale, then start a new run.") end) end, 40) label(abilities, "Level 300 is the normal currency upgrade ceiling, not infinite fuel. All utilities share this bonus; a run that's already active keeps its original countdown.", 11, muted, 62) local experience = page("XP helper") label(experience, "Levels are calculated from total breaks", 14, pale, 25).Font = Enum.Font.GothamBold label(experience, "Direct totalbreaks requests caused kicks. XP helper is read-only: earn breaks through regular runs, then refresh progress here.", 11, Color3.fromRGB(255, 172, 126), 61) local levelbox = field(experience, "Target level (1–1395)", preferred("xp_target", 500)) local estimate = label(experience, "Enter a target to calculate your remaining breaks.", 12, muted, 67) local function breaksforlevel(level) if level <= 1 then return 0 end if level < 100 then return math.ceil(((level - 1) * 6.141934860599844) ^ 2.1552185512626503) end return math.ceil(10 ^ (level / 100) * 100000) end local function levelforbreaks(total) if total <= 0 then return 1 end if total < 1000000 then return math.floor(total ^ 0.463990067 / 6.141934860599844 + 1) end return math.floor(math.log10(total / 100000) * 100) end local function formatvalue(value) if value < 1e9 then return string.format("%.0f", value) end return string.format("%.5g", value) end local xploading = false button(experience, "REFRESH XP PROGRESS", function() if xploading then return end local target = finite(levelbox.Text) if not target or target % 1 ~= 0 or target < 1 or target > 1395 then notice("Enter a whole target level from 1 to 1395") return end xploading = true task.spawn(function() local data = fetch() xploading = false if not active then return end if not data or type(data.totalbreaks) ~= "number" then notice("Couldn't read current total breaks") return end local current = math.max(0, data.totalbreaks) local required = breaksforlevel(target) estimate.Text = "Current level: " .. formatvalue(levelforbreaks(current)) .. " • Total breaks: " .. formatvalue(current) .. "\nTarget level: " .. tostring(target) .. " • Needed: " .. formatvalue(math.max(0, required - current)) notice(current >= required and "Target level reached." or "XP progress refreshed. No stat changes sent.") end) end, 40) local movement = page("Movement") label(movement, "Local movement controls", 14, pale, 25).Font = Enum.Font.GothamBold label(movement, "Suggested starting values (not safe/anti-kick guarantees): walk 24–80, jump 50–120, fly 30–100, gravity 50–196.2, launch 100–500. No script-imposed upper limits; extreme values can kick you or destabilize physics.", 11, Color3.fromRGB(255, 172, 126), 98) local speedbox = field(movement, "Walk speed · suggested 24–80", settings.speed) local jumpbox = field(movement, "Jump power · suggested 50–120", settings.jump) local flybox = field(movement, "Fly speed · suggested 30–100", settings.fly) local gravitybox = field(movement, "Local gravity · suggested 50–196.2", settings.gravity) local launchbox = field(movement, "Launch strength · suggested 100–500", settings.launch) local intervalbox = field(movement, "Loop launch interval (seconds) · suggested 0.25–1", settings.launchinterval) local function applymovement() local values = { speed = finite(speedbox.Text), jump = finite(jumpbox.Text), fly = finite(flybox.Text), gravity = finite(gravitybox.Text), launch = finite(launchbox.Text), launchinterval = finite(intervalbox.Text) } for key, value in pairs(values) do if not value then return false, "Invalid " .. key .. ": use a finite number" end end if values.launchinterval <= 0 then return false, "Loop interval must be greater than zero" end for key, value in pairs(values) do settings[key] = value end return true end local function applyandnotice() local ok, err = applymovement() if not ok then notice(err) return false end if flags.gravity then local applied, reason = pcall(function() workspace.Gravity = settings.gravity end) if not applied then setflag("gravity", false) notice("Gravity rejected: " .. tostring(reason)) return false end end notice("Movement values updated. Extreme values may fail or trigger a game kick.") return true end button(movement, "APPLY MOVEMENT VALUES", applyandnotice) toggle(movement, "Walk speed override", "speed", function(on) if on then if not applymovement() then setflag("speed", false) notice("Enter finite movement values first") return end local humanoid = gethumanoid() if humanoid and not originals[humanoid] then originals[humanoid] = {speed = humanoid.WalkSpeed, jump = humanoid.JumpPower, usejump = humanoid.UseJumpPower} end else local humanoid = gethumanoid() if humanoid and originals[humanoid] then humanoid.WalkSpeed = originals[humanoid].speed end end end) toggle(movement, "Jump power override", "jump", function(on) if on then if not applymovement() then setflag("jump", false) notice("Enter finite movement values first") return end local humanoid = gethumanoid() if humanoid and not originals[humanoid] then originals[humanoid] = {speed = humanoid.WalkSpeed, jump = humanoid.JumpPower, usejump = humanoid.UseJumpPower} end else local humanoid = gethumanoid() if humanoid and originals[humanoid] then humanoid.JumpPower = originals[humanoid].jump humanoid.UseJumpPower = originals[humanoid].usejump end end end) toggle(movement, "Infinite jump", "infinitejump") toggle(movement, "Fly (WASD / Space / Ctrl)", "fly", function(on) if on and not applymovement() then setflag("fly", false) notice("Enter finite movement values first") return end notice(on and "Fly enabled; use movement keys." or "Fly disabled.") end) toggle(movement, "Noclip", "noclip") toggle(movement, "Gravity override", "gravity", function(on) if on and not applymovement() then setflag("gravity", false) notice("Enter finite movement values first") return end local ok, err = pcall(function() workspace.Gravity = on and settings.gravity or saved.gravity end) if not ok then setflag("gravity", false) notice("Gravity rejected: " .. tostring(err)) end end) local function launchonce() local root = getroot() if not root then return false, "Character isn't ready" end if root.Anchored then return false, "Character is anchored" end local ok, err = pcall(function() root.AssemblyLinearVelocity += workspace.CurrentCamera.CFrame.LookVector * settings.launch end) if not ok then return false, "Launch rejected: " .. tostring(err) end return true end button(movement, "LAUNCH IN LOOK DIRECTION", function() local ok, err = applymovement() if not ok then notice(err) return end local launched, reason = launchonce() notice(launched and "Launched in camera look direction." or reason) end) toggle(movement, "LOOP LAUNCH IN LOOK DIRECTION", "looplaunch", function(on) if on then local ok, err = applymovement() if not ok then setflag("looplaunch", false) notice(err) return end lastlaunch = 0 notice("Loop launch enabled. Toggle OFF to stop; fly may overwrite velocity.") else notice("Loop launch stopped.") end end) local mapbox = field(movement, "Map (1–3) / stage (1–10), e.g. 3,10", preferred("map_stage", "1,1")) button(movement, "TELEPORT TO MAP STAGE", function() local a, b = mapbox.Text:match("^%s*(%d+)%s*,%s*(%d+)%s*$") local map, stage = tonumber(a), tonumber(b) if not map or not stage or map < 1 or map > 3 or stage < 1 or stage > 10 then notice("Use map,stage (example: 3,10)") return end local folder = storage:FindFirstChild("Map" .. map .. "Spawns") local spot = folder and folder:FindFirstChild("Stage" .. stage) local root = getroot() if root and spot and spot:IsA("Vector3Value") then root.CFrame = CFrame.new(spot.Value + Vector3.new(0, 5, 0)) notice("Local teleport sent to map " .. map .. ", stage " .. stage) else notice("Spawn or character wasn't found") end end) local gameplay = page("Gameplay") label(gameplay, "Physics and session tools", 14, pale, 25).Font = Enum.Font.GothamBold button(gameplay, "LOCAL RAGDOLL", function() local humanoid = gethumanoid() if humanoid then humanoid:ChangeState(Enum.HumanoidStateType.Physics) end end) button(gameplay, "STAND UP", function() local humanoid = gethumanoid() if humanoid then humanoid:ChangeState(Enum.HumanoidStateType.GettingUp) end end) toggle(gameplay, "Anti-AFK", "antiafk") label(gameplay, "The game controls the normal crash/ragdoll cycle. Local physics may be overridden while a run is active.", 11, muted, 48) local visuals = page("Visuals") label(visuals, "Local visual controls", 14, pale, 25).Font = Enum.Font.GothamBold local fovbox = field(visuals, "Field of view", settings.fov) toggle(visuals, "Fullbright", "fullbright", function(on) lighting.Brightness = on and 4 or saved.brightness lighting.Ambient = on and Color3.new(1, 1, 1) or saved.ambient lighting.OutdoorAmbient = on and Color3.new(1, 1, 1) or saved.outdoor lighting.ClockTime = on and 12 or saved.clock end) button(visuals, "APPLY FOV", function() settings.fov = number(fovbox.Text, 40, 120) or 90 camera.FieldOfView = settings.fov end) button(visuals, "RESET FOV", function() camera.FieldOfView = saved.fov end) toggle(visuals, "Freecam (RMB + WASD)", "freecam", function(on) if on then camera.CameraType = Enum.CameraType.Scriptable else camera.CameraType = Enum.CameraType.Custom camera.CameraSubject = gethumanoid() end end) local restorepage = page("Restore") label(restorepage, "Feature restoration", 14, pale, 25).Font = Enum.Font.GothamBold label(restorepage, "Choose each feature's startup and respawn behaviour. Respawn only restores features that were enabled before death. Changes save only when you press Save Settings.", 11, muted, 76) local restorelabels = { fly = "Fly", noclip = "Noclip", infinitejump = "Infinite jump", speed = "WalkSpeed", jump = "JumpPower", looplaunch = "Loop launch", gravity = "Gravity", fullbright = "Fullbright", freecam = "Freecam", antiafk = "Anti-AFK" } for _, key in ipairs(restorekeys) do label(restorepage, restorelabels[key], 12, pale, 22).Font = Enum.Font.GothamMedium for _, phase in ipairs({"startup", "respawn"}) do local control local function repaint() control.Text = (phase == "startup" and "On injection" or "After respawn") .. (restoring[phase][key] and " · ON" or " · OFF") control.BackgroundColor3 = restoring[phase][key] and Color3.fromRGB(72, 47, 115) or surface end control = button(restorepage, "", function() restoring[phase][key] = not restoring[phase][key] repaint() updateunsaved() end, 30) repaint() end end local function settingssignature() local pieces = {} for _, entry in ipairs(inputfields) do table.insert(pieces, entry.Text) end for _, phase in ipairs({"startup", "respawn"}) do for _, key in ipairs(restorekeys) do table.insert(pieces, restoring[phase][key] and "1" or "0") end end return http:JSONEncode(pieces) end local function isdirty() return forceunsaved or (settingbaseline ~= nil and settingssignature() ~= settingbaseline) end updateunsaved = function() if not active then return end unsaveddot.Visible = isdirty() end local function confirmation(title, description, yes, no) local overlay = create("Frame", gui, { Size = UDim2.fromScale(1, 1), BackgroundColor3 = Color3.fromRGB(5, 5, 9), BackgroundTransparency = 0.25, BorderSizePixel = 0, Active = true, ZIndex = 90 }) local panel = round(create("Frame", overlay, { AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.fromScale(0.5, 0.5), Size = UDim2.fromOffset(math.max(215, math.min(405, camera.ViewportSize.X - 22)), 205), BackgroundColor3 = Color3.fromRGB(24, 20, 36), BorderSizePixel = 0, ZIndex = 91 }), 10) create("UIStroke", panel, {Color = purple, Thickness = 1.2}) local headline = label(panel, title, 15, pale, 31) headline.Position, headline.Size, headline.ZIndex = UDim2.fromOffset(14, 13), UDim2.new(1, -28, 0, 31), 92 headline.Font = Enum.Font.GothamBold local explanation = label(panel, description, 12, muted, 78) explanation.Position, explanation.Size, explanation.ZIndex = UDim2.fromOffset(14, 51), UDim2.new(1, -28, 0, 78), 92 explanation.TextYAlignment = Enum.TextYAlignment.Top local done = Instance.new("BindableEvent") local decision local left = button(panel, no or "KEEP EDITING", function() if decision ~= nil then return end decision = false done:Fire(false) end, 42) left.Position, left.Size, left.ZIndex = UDim2.new(0, 14, 1, -55), UDim2.new(0.5, -21, 0, 42), 92 local right = button(panel, yes or "CONTINUE", function() if decision ~= nil then return end decision = true done:Fire(true) end, 42) right.Position, right.Size, right.ZIndex = UDim2.new(0.5, 7, 1, -55), UDim2.new(0.5, -21, 0, 42), 92 right.BackgroundColor3 = Color3.fromRGB(116, 65, 202) local result = done.Event:Wait() overlay:Destroy() done:Destroy() return result end local function requestclose() if isdirty() and not confirmation("Unsaved settings", "Closing Luna.dev will discard changes made since the last Save Settings.", "CLOSE WITHOUT SAVING", "KEEP EDITING") then return end gui:Destroy() end local options = page("Settings") label(options, "Menu and session", 14, pale, 25).Font = Enum.Font.GothamBold label(options, "Universal acceptance: luna.dev/settings.json. This extension: luna.dev/scripts/broken_bones_iv.json. All files are readable, indented JSON. Older settings files are retained.", 11, muted, 80) local settingsstatus = label(options, "Changes are not saved automatically. The dot beside luna.dev means your settings have unsaved changes.", 11, muted, 58) local function extensionprefs() local amount, delay = finite(cashbox.Text), finite(delaybox.Text) local fuel, xp, view = finite(fuelbox.Text), finite(levelbox.Text), finite(fovbox.Text) local move = { speed = finite(speedbox.Text), jump = finite(jumpbox.Text), fly = finite(flybox.Text), gravity = finite(gravitybox.Text), launch = finite(launchbox.Text), launchinterval = finite(intervalbox.Text) } if not amount or amount <= 0 or not delay or delay < 0 then return nil, "Enter a positive money amount and non-negative auto-buy delay." end if not fuel or fuel % 1 ~= 0 or fuel < 0 or fuel > 300 then return nil, "Fuel target must be a whole number between 0 and 300." end if not xp or xp % 1 ~= 0 or xp < 1 or xp > 1395 then return nil, "XP target must be a whole number between 1 and 1395." end if not view or view < 40 or view > 120 then return nil, "FOV must be between 40 and 120." end for key, value in pairs(move) do if not value then return nil, "Invalid movement value: " .. key end end if move.launchinterval <= 0 then return nil, "Launch interval must be positive." end local map, stage = mapbox.Text:match("^%s*(%d+)%s*,%s*(%d+)%s*$") if not map or not stage or tonumber(map) > 3 or tonumber(map) < 1 or tonumber(stage) > 10 or tonumber(stage) < 1 then return nil, "Map/stage must be 1,1 through 3,10." end local values = { money_amount = cashbox.Text, purchase_delay = delaybox.Text, fuel_target = fuelbox.Text, xp_target = levelbox.Text, fov = fovbox.Text, map_stage = mapbox.Text, speed = speedbox.Text, jump = jumpbox.Text, fly = flybox.Text, gravity = gravitybox.Text, launch = launchbox.Text, launchinterval = intervalbox.Text } local restore = {startup = {}, respawn = {}} for _, phase in ipairs({"startup", "respawn"}) do for _, key in ipairs(restorekeys) do restore[phase][key] = restoring[phase][key] == true end end return {values = values, restore = restore}, {delay = delay, move = move, fov = view} end local function resetextensionfile() local default = defaultextension() local ok, err = writejson(extensionfile, default) if ok then savedfile_raw = rawfile(extensionfile) forceunsaved = true updateunsaved() settingsstatus.Text = "Saved BB4 preferences reset. Current inputs remain unchanged. Reinject to use defaults." notice("Only BB4 settings were reset; your current session remains unchanged.") end return ok, err end local function savesettings() local prefs, values = extensionprefs() if not prefs then notice(values) return end local currentraw = rawfile(extensionfile) if currentraw ~= savedfile_raw then if not confirmation("Saved settings changed", "This extension's saved file was reset or changed elsewhere. Saving now will overwrite that change.", "SAVE ANYWAY", "CANCEL") then return end end local data, err = readjson(extensionfile) if err then notice(err) return end data = data or defaultextension() data._info, data.version = extensioninfo, 1 data.values, data.restore = prefs.values, prefs.restore local ok, reason = writejson(extensionfile, data) if not ok then settingsstatus.Text = "Couldn't save: " .. tostring(reason) notice("Save Settings failed: " .. tostring(reason)) return end savedfile_raw = rawfile(extensionfile) purchase_delay = values.delay for key, value in pairs(values.move) do settings[key] = value end settings.fov = values.fov settingbaseline, forceunsaved = settingssignature(), false updateunsaved() settingsstatus.Text = "Saved to luna.dev/scripts/broken_bones_iv.json. Other extensions are unchanged." notice("BB4 settings saved.") end button(options, "SAVE SETTINGS", savesettings, 42) button(options, "RESET SAVED BB4 SETTINGS", function() if not confirmation("Reset Broken Bones IV?", "Reset only this extension's saved JSON. Your current session remains unchanged. Older files are preserved.", "RESET BB4", "CANCEL") then return end local ok, err = resetextensionfile() if not ok then notice("Couldn't reset BB4 settings: " .. tostring(err)) end end, 36) button(options, "REJOIN TO REFRESH GAME DATA", function() cancelled = true notice("Rejoining...") if #players:GetPlayers() > 1 then teleport:TeleportToPlaceInstance(game.PlaceId, game.JobId, player) else teleport:Teleport(game.PlaceId, player) end end) button(options, "DESTROY LUNA.DEV MENU", requestclose) label(options, "Money method credit: original Russian-language BB4 ReJoin Farm script (author unknown; no credit was listed in the supplied code).", 11, muted, 58) label(options, "RightShift hides the window without discarding changes. Minimize keeps purchases active; closing warns about unsaved settings and cancels purchases. The second Give Money press disconnects you.", 11, muted, 64) local dragging, origin, initial = false, nil, nil addconnection(header.InputBegan:Connect(function(pointer) if pointer.UserInputType ~= Enum.UserInputType.MouseButton1 and pointer.UserInputType ~= Enum.UserInputType.Touch then return end dragging = true origin, initial = pointer.Position, window.Position addconnection(pointer.Changed:Connect(function() if pointer.UserInputState == Enum.UserInputState.End then dragging = false end end)) end)) addconnection(input.InputChanged:Connect(function(pointer) if not dragging then return end if pointer.UserInputType ~= Enum.UserInputType.MouseMovement and pointer.UserInputType ~= Enum.UserInputType.Touch then return end local delta = pointer.Position - origin window.Position = UDim2.new(initial.X.Scale, initial.X.Offset + delta.X, initial.Y.Scale, initial.Y.Offset + delta.Y) end)) local function fitwindow() local width, height = windowdimensions() window.Size = UDim2.fromOffset(width, body.Visible and height or 44) end minimize.MouseButton1Click:Connect(function() body.Visible = not body.Visible fitwindow() minimize.Text = body.Visible and "−" or "+" end) addconnection(camera:GetPropertyChangedSignal("ViewportSize"):Connect(fitwindow)) x.MouseButton1Click:Connect(requestclose) addconnection(input.InputBegan:Connect(function(key, processed) if key.KeyCode == Enum.KeyCode.RightShift and not processed then window.Visible = not window.Visible end if flags.infinitejump and not processed and key.KeyCode == Enum.KeyCode.Space then local humanoid = gethumanoid() if humanoid then humanoid:ChangeState(Enum.HumanoidStateType.Jumping) end end end)) addconnection(player.Idled:Connect(function() if not flags.antiafk then return end pcall(function() virtualuser:CaptureController() virtualuser:ClickButton2(Vector2.new()) end) end)) local lastparts = {} addconnection(runservice.Heartbeat:Connect(function(delta) if not active then return end local humanoid = gethumanoid() local root = getroot() if humanoid and (flags.speed or flags.jump) and not originals[humanoid] then originals[humanoid] = {speed = humanoid.WalkSpeed, jump = humanoid.JumpPower, usejump = humanoid.UseJumpPower} end if flags.speed and humanoid then local ok, err = pcall(function() humanoid.WalkSpeed = settings.speed end) if not ok then setflag("speed", false) notice("Walk speed rejected: " .. tostring(err)) end end if flags.jump and humanoid then local ok, err = pcall(function() humanoid.UseJumpPower = true humanoid.JumpPower = settings.jump end) if not ok then setflag("jump", false) notice("Jump power rejected: " .. tostring(err)) end end if flags.gravity then local ok, err = pcall(function() workspace.Gravity = settings.gravity end) if not ok then setflag("gravity", false) notice("Gravity rejected: " .. tostring(err)) end end if flags.noclip and player.Character then for _, part in ipairs(player.Character:GetDescendants()) do if part:IsA("BasePart") then if lastparts[part] == nil then lastparts[part] = part.CanCollide end part.CanCollide = false end end elseif next(lastparts) then for part, collide in pairs(lastparts) do if part.Parent then part.CanCollide = collide end lastparts[part] = nil end end if flags.fly and root and not root.Anchored then local direction = Vector3.zero local cf = camera.CFrame if input:IsKeyDown(Enum.KeyCode.W) then direction += cf.LookVector end if input:IsKeyDown(Enum.KeyCode.S) then direction -= cf.LookVector end if input:IsKeyDown(Enum.KeyCode.D) then direction += cf.RightVector end if input:IsKeyDown(Enum.KeyCode.A) then direction -= cf.RightVector end if input:IsKeyDown(Enum.KeyCode.Space) then direction += Vector3.yAxis end if input:IsKeyDown(Enum.KeyCode.LeftControl) then direction -= Vector3.yAxis end local ok, err = pcall(function() root.AssemblyLinearVelocity = direction.Magnitude > 0 and direction.Unit * settings.fly or Vector3.zero end) if not ok then setflag("fly", false) notice("Fly rejected: " .. tostring(err)) end end if flags.looplaunch then lastlaunch += delta if lastlaunch >= settings.launchinterval then lastlaunch = 0 local ok, err = launchonce() if not ok then setflag("looplaunch", false) notice(err .. ". Loop launch stopped.") end end end if flags.freecam and camera then local direction = Vector3.zero local cf = camera.CFrame if input:IsKeyDown(Enum.KeyCode.W) then direction += cf.LookVector end if input:IsKeyDown(Enum.KeyCode.S) then direction -= cf.LookVector end if input:IsKeyDown(Enum.KeyCode.D) then direction += cf.RightVector end if input:IsKeyDown(Enum.KeyCode.A) then direction -= cf.RightVector end if input:IsMouseButtonPressed(Enum.UserInputType.MouseButton2) then local mouse = input:GetMouseDelta() cf *= CFrame.Angles(0, -mouse.X * 0.002, 0) cf *= CFrame.Angles(-mouse.Y * 0.002, 0, 0) end camera.CFrame = cf + (direction.Magnitude > 0 and direction.Unit * delta * 80 or Vector3.zero) end end)) local characterkeys = {fly = true, noclip = true, infinitejump = true, speed = true, jump = true, looplaunch = true} local restoreonrespawn = nil local function activatefeature(key) if flags[key] then return end local item = togglecontrols[key] if not item then return end setflag(key, true) if item.callback then item.callback(true) end end addconnection(player.CharacterRemoving:Connect(function() local snapshot = {} for _, key in ipairs(restorekeys) do snapshot[key] = restoring.respawn[key] and flags[key] == true if characterkeys[key] then setflag(key, false) end end restoreonrespawn = snapshot end)) addconnection(player.CharacterAdded:Connect(function(character) local snapshot = restoreonrespawn restoreonrespawn = nil if not snapshot then return end task.spawn(function() local humanoid = character:WaitForChild("Humanoid", 15) local root = character:WaitForChild("HumanoidRootPart", 15) if not active or player.Character ~= character or not humanoid or not root then return end for _, key in ipairs(restorekeys) do if snapshot[key] then activatefeature(key) end end end) end)) local registry = environment.luna_dev_extensions if type(registry) ~= "table" then registry = {} environment.luna_dev_extensions = registry end registry[extension.id] = { metadata = extension, gui = gui, isDirty = isdirty, resetSaved = resetextensionfile, close = requestclose, settingsPath = extensionfile } settingbaseline = settingssignature() updateunsaved() task.spawn(function() local character = player.Character or player.CharacterAdded:Wait() if not active then return end if not character:WaitForChild("Humanoid", 15) or not character:WaitForChild("HumanoidRootPart", 15) then return end if not active or player.Character ~= character then return end for _, key in ipairs(restorekeys) do if restoring.startup[key] then activatefeature(key) end end end) gui.Destroying:Connect(function() if registry[extension.id] and registry[extension.id].gui == gui then registry[extension.id] = nil end active = false cancelled = true for _, connection in ipairs(connections) do connection:Disconnect() end for part, collide in pairs(lastparts) do if part.Parent then part.CanCollide = collide end end workspace.Gravity = saved.gravity lighting.Brightness = saved.brightness lighting.Ambient = saved.ambient lighting.OutdoorAmbient = saved.outdoor lighting.ClockTime = saved.clock camera.FieldOfView = saved.fov if flags.freecam then camera.CameraType = Enum.CameraType.Custom camera.CameraSubject = gethumanoid() end local humanoid = gethumanoid() if humanoid and originals[humanoid] then if flags.speed then pcall(function() humanoid.WalkSpeed = originals[humanoid].speed end) end if flags.jump then pcall(function() humanoid.JumpPower = originals[humanoid].jump humanoid.UseJumpPower = originals[humanoid].usejump end) end end end) switch("Economy")