local RunService = game:GetService("RunService") ------------------------------------------------------------------ -- SERVER HALF (runs only when this code is in ServerScriptService) ------------------------------------------------------------------ if RunService:IsServer() then local Players = game:GetService("Players") local ReplicatedStorage = game:GetService("ReplicatedStorage") -- ===== Settings ===== local ALLOWED_USER_IDS = {} -- add your UserId (and testers). The place owner is always allowed. local FUEL_FILL_TO = nil -- e.g. 100; only used when no Max/Capacity value is found local EXTRA_FUEL_NAMES = {} -- exact name(s) of your fuel value, e.g. { "Juice", "BikeGas" } local SCAN_INTERVAL = 0.5 -- seconds between searches for fuel values local AUTO_DROPS_NEEDED = 3 -- scans in a row a number must fall before auto-detect locks it local PRINT_DEBUG = true -- print what gets locked to the Output window -- ==================== local FUEL_WORDS = { "fuel", "petrol", "gasoline", "tank", "energy", "juice", "battery" } local IGNORE_WORDS = { "rate", "use", "usage", "drain", "consum", "burn", "cost", "price", "efficien", "pedal", "throttle" } local extraSet = {} for _, nm in ipairs(EXTRA_FUEL_NAMES) do extraSet[string.lower(nm)] = true end local remote = Instance.new("RemoteEvent") remote.Name = "InfiniteFuelToggle" remote.Parent = ReplicatedStorage local function isAllowed(player) if RunService:IsStudio() then return true end if game.CreatorType == Enum.CreatorType.User and player.UserId == game.CreatorId then return true end return table.find(ALLOWED_USER_IDS, player.UserId) ~= nil end -- "current" = fuel level, "max" = capacity, nil = not fuel related local function classify(name) local n = string.lower(name) if extraSet[n] then return "current" end local matches = n == "gas" or string.find(n, "^gas") ~= nil or string.find(n, "gas$") ~= nil for _, word in ipairs(FUEL_WORDS) do if string.find(n, word, 1, true) then matches = true break end end if not matches then return nil end if string.find(n, "max", 1, true) or string.find(n, "capacity", 1, true) then return "max" end for _, word in ipairs(IGNORE_WORDS) do if string.find(n, word, 1, true) then return nil end end return "current" end local function readNumber(obj, attr) local v if attr then v = obj:GetAttribute(attr) else v = obj.Value end return type(v) == "number" and v or nil end local function write(obj, attr, value) if attr then obj:SetAttribute(attr, value) else obj.Value = value end end local function enforce(entry) if not entry.obj.Parent then return end local current = readNumber(entry.obj, entry.attr) if not current then return end local target if entry.max and entry.max.obj.Parent then target = readNumber(entry.max.obj, entry.max.attr) end target = target or FUEL_FILL_TO if target then entry.seen = target if current < target then write(entry.obj, entry.attr, target) end elseif current > entry.seen then entry.seen = current -- no max known: a refuel raises the held level elseif current < entry.seen then write(entry.obj, entry.attr, entry.seen) end end -- state[player] = { entries = { [obj] = { [key] = entry } }, list = {}, last = 0, watch = {} } local state = {} local VALUE_KEY = "\0value" local function dropState(s) for _, byObj in pairs(s.entries) do for _, entry in pairs(byObj) do if entry.conn then entry.conn:Disconnect() end end end end local function topModel(part) local model = part:FindFirstAncestorOfClass("Model") while model and model.Parent and model.Parent:IsA("Model") do model = model.Parent end return model end local function pathOf(obj, attr) return obj:GetFullName() .. (attr and ("." .. attr) or "") end local function register(s, item, auto, maxRef) local byObj = s.entries[item.obj] if not byObj then byObj = {} s.entries[item.obj] = byObj end local key = item.attr or VALUE_KEY local entry = byObj[key] if not entry then entry = { obj = item.obj, attr = item.attr, seen = item.value, auto = auto } byObj[key] = entry local signal if item.attr then signal = item.obj:GetAttributeChangedSignal(item.attr) else signal = item.obj:GetPropertyChangedSignal("Value") end entry.conn = signal:Connect(function() enforce(entry) -- put it back the moment something lowers it end) if PRINT_DEBUG then print("[InfiniteFuel/server] locking" .. (auto and " (auto-detected)" or "") .. ":", pathOf(item.obj, item.attr), "=", item.value) end end entry.max = maxRef or entry.max return entry end local function scan(player, s) local currents, maxes, numeric = {}, {}, {} local function consider(inst) if inst:IsA("NumberValue") or inst:IsA("IntValue") then local kind = classify(inst.Name) if kind == "current" then table.insert(currents, { obj = inst, value = inst.Value }) elseif kind == "max" then table.insert(maxes, { obj = inst }) else table.insert(numeric, { obj = inst, value = inst.Value }) end end for name, value in pairs(inst:GetAttributes()) do if type(value) == "number" then local kind = classify(name) if kind == "current" then table.insert(currents, { obj = inst, attr = name, value = value }) elseif kind == "max" then table.insert(maxes, { obj = inst, attr = name }) elseif name ~= "InfiniteFuel" then table.insert(numeric, { obj = inst, attr = name, value = value }) end end end end local function scanTree(root) consider(root) for _, inst in ipairs(root:GetDescendants()) do consider(inst) end end local character = player.Character local humanoid = character and character:FindFirstChildOfClass("Humanoid") local seat = humanoid and humanoid.SeatPart if seat then local bike = topModel(seat) if bike then scanTree(bike) end end if character then scanTree(character) end scanTree(player) local function container(item) return item.attr and item.obj or item.obj.Parent end local maxByContainer = {} for _, m in ipairs(maxes) do local c = container(m) if c and not maxByContainer[c] then maxByContainer[c] = m end end local seenNow = {} for _, item in ipairs(currents) do local entry = register(s, item, false, maxByContainer[container(item)]) seenNow[entry] = true end -- Nothing matched a fuel name: lock any number that keeps falling if #currents == 0 then for _, item in ipairs(numeric) do local byObj = s.watch[item.obj] if not byObj then byObj = {} s.watch[item.obj] = byObj end local key = item.attr or VALUE_KEY local w = byObj[key] if not w then byObj[key] = { last = item.value, drops = 0 } else if item.value < w.last then w.drops += 1 elseif item.value > w.last then w.drops = 0 end w.last = item.value if w.drops >= AUTO_DROPS_NEEDED and item.value > 0 then local entry = register(s, item, true) seenNow[entry] = true end end end end local list = {} for obj, byObj in pairs(s.entries) do for key, entry in pairs(byObj) do if (seenNow[entry] or entry.auto) and entry.obj.Parent then table.insert(list, entry) else if entry.conn then entry.conn:Disconnect() end byObj[key] = nil end end if next(byObj) == nil then s.entries[obj] = nil end end s.list = list for _, entry in ipairs(list) do enforce(entry) end end remote.OnServerEvent:Connect(function(player, on) if not isAllowed(player) then return end if on == true then player:SetAttribute("InfiniteFuel", true) -- hook for your own drain code if not state[player] then state[player] = { entries = {}, list = {}, last = -math.huge, watch = {} } end else player:SetAttribute("InfiniteFuel", nil) local s = state[player] if s then dropState(s) state[player] = nil end end end) Players.PlayerRemoving:Connect(function(player) local s = state[player] if s then dropState(s) state[player] = nil end end) RunService.Heartbeat:Connect(function() local now = os.clock() for player, s in pairs(state) do if now - s.last >= SCAN_INTERVAL then s.last = now scan(player, s) end for _, entry in ipairs(s.list) do enforce(entry) end end end) return end ------------------------------------------------------------------ -- CLIENT HALF (the GUI) ------------------------------------------------------------------ local Players = game:GetService("Players") local RunService = game:GetService("RunService") local UserInputService = game:GetService("UserInputService") local player = Players.LocalPlayer local playerGui = player:WaitForChild("PlayerGui") -- ===== Settings you can tweak ===== local DEFAULT_KEY = Enum.KeyCode.Q local TARGET_PITCH_DEG = 40 -- how high the front wheel lifts local GAIN = 6 -- how fast it rotates toward the target local MAX_RATE = 6 -- max rotation speed in radians/sec local RESPONSE = 30 -- how hard it takes over the bike's rotation local ROLL_GAIN = 12 -- how hard it fights the bike falling sideways local STEER_ROLL_FACTOR = 0.25 -- side-balance strength while you're steering (lower = freer turning) local AUTO_DETECT_FRONT = true -- learn the bike's front from the direction it drives local DETECT_SPEED = 12 -- studs/sec needed to learn the front local FRONT_IS_REVERSED = false -- only used when AUTO_DETECT_FRONT is false local REQUIRE_THROTTLE = false -- true = only wheelie while holding forward local MIN_SPEED = 0 -- studs/sec needed before the wheelie starts local FUEL_SCAN_INTERVAL = 1 -- seconds between searches for fuel values local EXTRA_FUEL_NAMES = {} -- exact name(s) of your fuel value, e.g. { "Juice" } (also set it in the server half above) local FUEL_FILL_TO = nil -- (also set it in the server half above) only used if no Max/Capacity value is found next to your fuel value. -- Set to your tank size (e.g. 100) to fill to that instead of the level you had. -- ================================== local toggleKey = DEFAULT_KEY local enabled = false local rebinding = false local infFuel = false local fuelFound = 0 local fuelResetRequested = false -- Optional: the server script (InfiniteFuelServer) creates this so the fuel is -- kept full on the SERVER too, which is what makes it stick if the server owns fuel. local ReplicatedStorage = game:GetService("ReplicatedStorage") local fuelRemote = nil task.spawn(function() fuelRemote = ReplicatedStorage:WaitForChild("InfiniteFuelToggle", 10) if fuelRemote and infFuel then fuelRemote:FireServer(true) end end) ------------------------------------------------------------------ -- GUI ------------------------------------------------------------------ local TweenService = game:GetService("TweenService") local THEME = { panel = Color3.fromRGB(16, 16, 22), header = Color3.fromRGB(23, 23, 31), row = Color3.fromRGB(26, 26, 36), rowHover = Color3.fromRGB(34, 34, 46), chip = Color3.fromRGB(42, 42, 57), trackOff = Color3.fromRGB(60, 60, 78), text = Color3.fromRGB(240, 240, 246), subtext = Color3.fromRGB(135, 135, 155), accent = Color3.fromRGB(255, 106, 43), accent2 = Color3.fromRGB(255, 176, 60), good = Color3.fromRGB(72, 200, 120), warn = Color3.fromRGB(240, 192, 64), idle = Color3.fromRGB(105, 105, 125), dark = Color3.fromRGB(20, 20, 24), } local PANEL_W, HEADER_H, BODY_H = 270, 46, 232 local TWEEN_INFO = TweenInfo.new(0.18, Enum.EasingStyle.Quad, Enum.EasingDirection.Out) local function tween(inst, props, info) TweenService:Create(inst, info or TWEEN_INFO, props):Play() end local function addCorner(inst, radius) local c = Instance.new("UICorner") c.CornerRadius = UDim.new(0, radius) c.Parent = inst return c end local function addStroke(inst, transparency) local s = Instance.new("UIStroke") s.Color = Color3.new(1, 1, 1) s.Transparency = transparency s.Thickness = 1 s.ApplyStrokeMode = Enum.ApplyStrokeMode.Border s.Parent = inst return s end local function makeLabel(parent, props) local l = Instance.new("TextLabel") l.BackgroundTransparency = 1 l.BorderSizePixel = 0 l.TextXAlignment = Enum.TextXAlignment.Left l.TextColor3 = THEME.text for k, v in pairs(props) do l[k] = v end l.Parent = parent return l end local gui = Instance.new("ScreenGui") gui.Name = "AutoWheelieGui" gui.ResetOnSpawn = false gui.Parent = playerGui local frame = Instance.new("Frame") frame.Name = "Panel" frame.Size = UDim2.fromOffset(PANEL_W, HEADER_H + BODY_H) frame.Position = UDim2.new(1, -(PANEL_W + 20), 1, -(HEADER_H + BODY_H + 20)) -- bottom-right corner frame.BackgroundColor3 = THEME.panel frame.BorderSizePixel = 0 frame.ClipsDescendants = true frame.Parent = gui addCorner(frame, 14) addStroke(frame, 0.88) -- Title bar (also the drag handle) local title = Instance.new("Frame") title.Name = "TitleBar" title.Size = UDim2.new(1, 0, 0, HEADER_H) title.BackgroundColor3 = THEME.header title.BorderSizePixel = 0 title.Active = true -- lets it catch mouse/touch input title.Parent = frame local titleDot = Instance.new("Frame") titleDot.Size = UDim2.fromOffset(10, 10) titleDot.Position = UDim2.new(0, 16, 0.5, -5) titleDot.BackgroundColor3 = THEME.accent titleDot.BorderSizePixel = 0 titleDot.Parent = title addCorner(titleDot, 5) makeLabel(title, { Name = "Title", Size = UDim2.new(1, -90, 1, 0), Position = UDim2.fromOffset(34, 0), Font = Enum.Font.GothamBold, TextSize = 15, Text = "Auto Wheelie", }) local minButton = Instance.new("TextButton") minButton.Name = "Minimize" minButton.Size = UDim2.fromOffset(28, 28) minButton.Position = UDim2.new(1, -40, 0.5, -14) minButton.BackgroundColor3 = THEME.chip minButton.BorderSizePixel = 0 minButton.AutoButtonColor = false minButton.Font = Enum.Font.GothamBold minButton.TextSize = 16 minButton.TextColor3 = THEME.text minButton.Text = "–" minButton.Parent = title addCorner(minButton, 8) -- thin accent line under the title bar local accentLine = Instance.new("Frame") accentLine.Size = UDim2.new(1, 0, 0, 2) accentLine.Position = UDim2.new(0, 0, 1, -2) accentLine.BackgroundColor3 = Color3.new(1, 1, 1) accentLine.BorderSizePixel = 0 accentLine.Parent = title local accentGradient = Instance.new("UIGradient") accentGradient.Color = ColorSequence.new(THEME.accent, THEME.accent2) accentGradient.Transparency = NumberSequence.new({ NumberSequenceKeypoint.new(0, 0), NumberSequenceKeypoint.new(1, 0.7), }) accentGradient.Parent = accentLine -- Body local body = Instance.new("Frame") body.Name = "Body" body.Position = UDim2.fromOffset(0, HEADER_H) body.Size = UDim2.new(1, 0, 0, BODY_H) body.BackgroundTransparency = 1 body.BorderSizePixel = 0 body.Parent = frame local padding = Instance.new("UIPadding") padding.PaddingTop = UDim.new(0, 10) padding.PaddingBottom = UDim.new(0, 10) padding.PaddingLeft = UDim.new(0, 10) padding.PaddingRight = UDim.new(0, 10) padding.Parent = body local layout = Instance.new("UIListLayout") layout.Padding = UDim.new(0, 8) layout.SortOrder = Enum.SortOrder.LayoutOrder layout.Parent = body local function makeRowFrame(className, order) local row = Instance.new(className) row.LayoutOrder = order row.Size = UDim2.new(1, 0, 0, 50) row.BackgroundColor3 = THEME.row row.BorderSizePixel = 0 if className == "TextButton" then row.AutoButtonColor = false row.Text = "" end row.Parent = body addCorner(row, 10) addStroke(row, 0.94) return row end local function makeRowText(row, name, sub) local nameLabel = makeLabel(row, { Position = UDim2.fromOffset(14, 9), Size = UDim2.new(1, -90, 0, 17), Font = Enum.Font.GothamBold, TextSize = 14, Text = name, }) local subLabel = makeLabel(row, { Position = UDim2.fromOffset(14, 27), Size = UDim2.new(1, -90, 0, 14), Font = Enum.Font.Gotham, TextSize = 12, TextColor3 = THEME.subtext, TextTruncate = Enum.TextTruncate.AtEnd, Text = sub, }) return nameLabel, subLabel end -- A row with an on/off switch on the right local function makeToggleRow(order, name, sub) local row = makeRowFrame("TextButton", order) local _, subLabel = makeRowText(row, name, sub) local track = Instance.new("Frame") track.Size = UDim2.fromOffset(40, 22) track.Position = UDim2.new(1, -54, 0.5, -11) track.BackgroundColor3 = THEME.trackOff track.BorderSizePixel = 0 track.Parent = row addCorner(track, 11) local knob = Instance.new("Frame") knob.Size = UDim2.fromOffset(16, 16) knob.Position = UDim2.new(0, 3, 0.5, -8) knob.BackgroundColor3 = Color3.new(1, 1, 1) knob.BorderSizePixel = 0 knob.Parent = track addCorner(knob, 8) row.MouseEnter:Connect(function() tween(row, { BackgroundColor3 = THEME.rowHover }) end) row.MouseLeave:Connect(function() tween(row, { BackgroundColor3 = THEME.row }) end) return { row = row, sub = subLabel, track = track, knob = knob } end local function setSwitch(r, on, color) tween(r.track, { BackgroundColor3 = on and color or THEME.trackOff }) tween(r.knob, { Position = on and UDim2.new(0, 21, 0.5, -8) or UDim2.new(0, 3, 0.5, -8) }) end local toggleRow = makeToggleRow(1, "Auto Wheelie", "Lifts and holds the front wheel") local fuelRow = makeToggleRow(2, "Infinite Fuel", "Keeps the tank full") -- Keybind row (key chip on the right) local keyRowFrame = makeRowFrame("Frame", 3) local _, keySub = makeRowText(keyRowFrame, "Toggle Key", "Click the key to change it") local keyButton = Instance.new("TextButton") keyButton.Size = UDim2.fromOffset(96, 30) keyButton.Position = UDim2.new(1, -108, 0.5, -15) keyButton.BackgroundColor3 = THEME.chip keyButton.BorderSizePixel = 0 keyButton.AutoButtonColor = false keyButton.Font = Enum.Font.GothamBold keyButton.TextSize = 12 keyButton.TextColor3 = THEME.text keyButton.TextTruncate = Enum.TextTruncate.AtEnd keyButton.Parent = keyRowFrame addCorner(keyButton, 8) addStroke(keyButton, 0.9) -- Status pill local statusRow = Instance.new("Frame") statusRow.LayoutOrder = 4 statusRow.Size = UDim2.new(1, 0, 0, 38) statusRow.BackgroundColor3 = THEME.row statusRow.BorderSizePixel = 0 statusRow.Parent = body addCorner(statusRow, 10) local statusDot = Instance.new("Frame") statusDot.Size = UDim2.fromOffset(8, 8) statusDot.Position = UDim2.new(0, 14, 0.5, -4) statusDot.BackgroundColor3 = THEME.idle statusDot.BorderSizePixel = 0 statusDot.Parent = statusRow addCorner(statusDot, 4) local statusLabel = makeLabel(statusRow, { Position = UDim2.fromOffset(30, 0), Size = UDim2.new(1, -40, 1, 0), Font = Enum.Font.Gotham, TextSize = 12, TextWrapped = true, TextTruncate = Enum.TextTruncate.AtEnd, TextColor3 = THEME.subtext, Text = "Off", }) local lastStatus = "" local function setStatus(text) if text ~= lastStatus then lastStatus = text statusLabel.Text = string.upper(string.sub(text, 1, 1)) .. string.sub(text, 2) local color = THEME.warn if text == "off" then color = THEME.idle elseif string.sub(text, 1, 7) == "holding" then color = THEME.good end tween(statusDot, { BackgroundColor3 = color }) end end local function updateUI() setSwitch(toggleRow, enabled, THEME.accent) if infFuel then if fuelFound > 0 then fuelRow.sub.Text = fuelFound .. (fuelFound == 1 and " fuel value found" or " fuel values found") if fuelRemote then fuelRow.sub.Text = fuelRow.sub.Text .. " + server" end setSwitch(fuelRow, true, THEME.accent) else fuelRow.sub.Text = "No fuel values found" setSwitch(fuelRow, true, THEME.warn) end else fuelRow.sub.Text = "Keeps the tank full" setSwitch(fuelRow, false, THEME.accent) end if rebinding then keyButton.Text = "Press a key..." keySub.Text = "Esc to cancel" tween(keyButton, { BackgroundColor3 = THEME.warn, TextColor3 = THEME.dark }) else keyButton.Text = toggleKey.Name keySub.Text = "Click the key to change it" tween(keyButton, { BackgroundColor3 = THEME.chip, TextColor3 = THEME.text }) end end local function setEnabled(value) enabled = value updateUI() end toggleRow.row.Activated:Connect(function() setEnabled(not enabled) end) keyButton.Activated:Connect(function() rebinding = not rebinding -- click again to cancel updateUI() end) fuelRow.row.Activated:Connect(function() infFuel = not infFuel player:SetAttribute("InfiniteFuel", infFuel or nil) -- hook for your own drain code fuelFound = 0 fuelResetRequested = true -- fuel code clears and rescans on the next frame if fuelRemote then fuelRemote:FireServer(infFuel) end updateUI() end) -- Minimize / expand local minimized = false minButton.MouseEnter:Connect(function() tween(minButton, { BackgroundColor3 = THEME.trackOff }) end) minButton.MouseLeave:Connect(function() tween(minButton, { BackgroundColor3 = THEME.chip }) end) minButton.Activated:Connect(function() minimized = not minimized minButton.Text = minimized and "+" or "–" tween(frame, { Size = UDim2.fromOffset(PANEL_W, minimized and HEADER_H or (HEADER_H + BODY_H)), }, TweenInfo.new(0.22, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)) end) updateUI() ------------------------------------------------------------------ -- Dragging (click and hold the title bar) ------------------------------------------------------------------ local dragging = false local dragStart = Vector2.zero local startPos = frame.Position title.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then dragging = true dragStart = Vector2.new(input.Position.X, input.Position.Y) startPos = frame.Position input.Changed:Connect(function() if input.UserInputState == Enum.UserInputState.End then dragging = false end end) end end) UserInputService.InputChanged:Connect(function(input) if not dragging then return end if input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch then local delta = Vector2.new(input.Position.X, input.Position.Y) - dragStart frame.Position = UDim2.new( startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y ) end end) ------------------------------------------------------------------ -- Keybind handling ------------------------------------------------------------------ UserInputService.InputBegan:Connect(function(input, gameProcessed) -- While rebinding, the next keyboard key becomes the new toggle key if rebinding then if input.UserInputType == Enum.UserInputType.Keyboard then if input.KeyCode ~= Enum.KeyCode.Escape then toggleKey = input.KeyCode end rebinding = false updateUI() end return end if gameProcessed then return end if input.KeyCode == toggleKey then setEnabled(not enabled) end end) ------------------------------------------------------------------ -- Finding the bike ------------------------------------------------------------------ local vehicleCache = { root = nil, result = false, checkedAt = 0 } -- True if the physics assembly includes parts that aren't part of the character local function carriesVehicle(root, character) local now = os.clock() if vehicleCache.root == root and now - vehicleCache.checkedAt < 1 then return vehicleCache.result end local result = false for _, part in ipairs(root:GetConnectedParts(true)) do if not part:IsDescendantOf(character) then result = true break end end vehicleCache.root = root vehicleCache.result = result vehicleCache.checkedAt = now return result end -- Returns: referencePart (for orientation), root (physics body to rotate) local function getVehicle() local character = player.Character if not character then return nil end local humanoid = character:FindFirstChildOfClass("Humanoid") local hrp = character:FindFirstChild("HumanoidRootPart") if not humanoid or not hrp then return nil end -- Normal case: you're sitting in a Seat or VehicleSeat local seat = humanoid.SeatPart if seat and seat:IsA("BasePart") then return seat, seat.AssemblyRootPart end -- Fallback: the character is welded/attached to the bike (no seat) local root = hrp.AssemblyRootPart if root and not root.Anchored and carriesVehicle(root, character) then return hrp, root end return nil end local function topModel(part) local model = part:FindFirstAncestorOfClass("Model") while model and model.Parent and model.Parent:IsA("Model") do model = model.Parent end return model end ------------------------------------------------------------------ -- Infinite fuel -- Freezes your fuel at whatever level it's at when you turn it on (if you -- refuel higher, it holds that new level). It looks on your bike and your -- player for number values / attributes whose names look like fuel (fuel, -- petrol, gasoline, gas, tank) and locks them: -- * the moment the game lowers one, a change listener puts it right back -- (same frame, before it's drawn), plus a per-frame check -- * the locked level is remembered between scans so it can't creep down -- If nothing matches a fuel name, it watches every number on your bike and -- player, and any value that keeps falling gets locked (auto-detect). -- Everything it finds is printed to the Output window. -- This only sticks if your game's fuel lives on the client or replicates from -- it. If your server owns the fuel, change it in the server script instead. ------------------------------------------------------------------ local fuelLookup = {} -- [instance][attributeName or VALUE_KEY] = entry local fuelList = {} local fuelWatch = setmetatable({}, { __mode = "k" }) -- [instance][key] = { last, drops } local fuelDumped = false local lastFuelScan = -math.huge local VALUE_KEY = "\0value" local AUTO_DROPS_NEEDED = 3 -- scans in a row a value must fall before auto-detect locks it local FUEL_WORDS = { "fuel", "petrol", "gasoline", "tank", "energy", "juice", "battery" } local IGNORE_WORDS = { "rate", "use", "usage", "drain", "consum", "burn", "cost", "price", "efficien", "pedal", "throttle" } local extraSet = {} for _, nm in ipairs(EXTRA_FUEL_NAMES) do extraSet[string.lower(nm)] = true end -- returns "current" for a fuel level, "max" for a capacity, nil for anything else local function classifyFuelName(name) local n = string.lower(name) if extraSet[n] then return "current" end local matches = n == "gas" or string.find(n, "^gas") ~= nil or string.find(n, "gas$") ~= nil for _, word in ipairs(FUEL_WORDS) do if string.find(n, word, 1, true) then matches = true break end end if not matches then return nil end if string.find(n, "max", 1, true) or string.find(n, "capacity", 1, true) then return "max" end for _, word in ipairs(IGNORE_WORDS) do if string.find(n, word, 1, true) then return nil end end return "current" end local function fuelPath(obj, attr) return obj:GetFullName() .. (attr and ("." .. attr) or "") end local function readNumber(obj, attr) local v if attr then v = obj:GetAttribute(attr) else v = obj.Value end return type(v) == "number" and v or nil end local function writeEntry(entry, value) if entry.attr then entry.obj:SetAttribute(entry.attr, value) else entry.obj.Value = value end end -- The level to hold: the tank's Max/Capacity value if we found one, else FUEL_FILL_TO local function fuelTarget(entry) local m = entry.max if m and m.obj.Parent then local cap = readNumber(m.obj, m.attr) if cap then return cap end end return FUEL_FILL_TO end local function enforce(entry) if not infFuel or not entry.obj.Parent then return end local current = readNumber(entry.obj, entry.attr) if not current then return end local target = fuelTarget(entry) if target then -- Keep it at max: anything below the target gets put straight back entry.seen = target if current < target then writeEntry(entry, target) end else -- No max known: hold the highest level seen (a refuel raises it) if current > entry.seen then entry.seen = current elseif current < entry.seen then writeEntry(entry, entry.seen) end end end local function dropEntry(entry) if entry.conn then entry.conn:Disconnect() entry.conn = nil end end local function clearFuel() for _, byObj in pairs(fuelLookup) do for _, entry in pairs(byObj) do dropEntry(entry) end end fuelLookup, fuelList = {}, {} fuelWatch = setmetatable({}, { __mode = "k" }) fuelDumped = false end local function registerTarget(found, obj, attr, value, auto, maxRef) local byObj = fuelLookup[obj] if not byObj then byObj = {} fuelLookup[obj] = byObj end local key = attr or VALUE_KEY local entry = byObj[key] if not entry then entry = { obj = obj, attr = attr, seen = value, auto = auto, max = maxRef } byObj[key] = entry local signal if attr then signal = obj:GetAttributeChangedSignal(attr) else signal = obj:GetPropertyChangedSignal("Value") end entry.conn = signal:Connect(function() enforce(entry) -- put it back the instant something lowers it end) print("[AutoWheelie] locking fuel" .. (auto and " (auto-detected)" or "") .. ":", fuelPath(obj, attr), "=", value, maxRef and ("(max: " .. fuelPath(maxRef.obj, maxRef.attr) .. ")") or "(no max value found)") enforce(entry) -- fill it right now elseif maxRef then entry.max = maxRef end found[entry] = true end local function scanFuel(bikeModel) local found = {} local numeric = {} -- every other number we saw (for the Output dump and auto-detect) local currents, maxes = {}, {} local function consider(inst) if inst:IsA("NumberValue") or inst:IsA("IntValue") then local kind = classifyFuelName(inst.Name) if kind == "current" then table.insert(currents, { obj = inst, value = inst.Value }) elseif kind == "max" then table.insert(maxes, { obj = inst, value = inst.Value }) elseif kind == nil then table.insert(numeric, { obj = inst, value = inst.Value }) end end for name, value in pairs(inst:GetAttributes()) do if type(value) == "number" then local kind = classifyFuelName(name) if kind == "current" then table.insert(currents, { obj = inst, attr = name, value = value }) elseif kind == "max" then table.insert(maxes, { obj = inst, attr = name, value = value }) elseif kind == nil then table.insert(numeric, { obj = inst, attr = name, value = value }) end end end end local function scanTree(rootInst) consider(rootInst) for _, inst in ipairs(rootInst:GetDescendants()) do consider(inst) end end if bikeModel then scanTree(bikeModel) end if player.Character then scanTree(player.Character) end -- the Player itself (stats folders etc.), but not our own GUI consider(player) for _, child in ipairs(player:GetChildren()) do if child ~= playerGui then scanTree(child) end end -- Pair each fuel level with a Max/Capacity value that lives in the same place local function container(item) return item.attr and item.obj or item.obj.Parent end local maxByContainer = {} for _, m in ipairs(maxes) do local c = container(m) if c and not maxByContainer[c] then maxByContainer[c] = m end end for _, item in ipairs(currents) do registerTarget(found, item.obj, item.attr, item.value, false, maxByContainer[container(item)]) end -- Nothing matched a fuel name: dump what we can see, and lock anything that keeps falling if next(found) == nil then if not fuelDumped then fuelDumped = true print(string.format("[AutoWheelie] no fuel-named values found. %d other numbers on your bike/player:", #numeric)) for i, item in ipairs(numeric) do if i > 60 then print(" ...and " .. (#numeric - 60) .. " more") break end print(" " .. fuelPath(item.obj, item.attr), "=", item.value) end end for _, item in ipairs(numeric) do local byObj = fuelWatch[item.obj] if not byObj then byObj = {} fuelWatch[item.obj] = byObj end local key = item.attr or VALUE_KEY local state = byObj[key] if not state then byObj[key] = { last = item.value, drops = 0 } else if item.value < state.last then state.drops += 1 elseif item.value > state.last then state.drops = 0 end state.last = item.value if state.drops >= AUTO_DROPS_NEEDED and item.value > 0 then registerTarget(found, item.obj, item.attr, item.value, true) end end end end -- keep entries we still see (so their locked level survives), drop the rest local list = {} for obj, byObj in pairs(fuelLookup) do for key, entry in pairs(byObj) do if (found[entry] or entry.auto) and entry.obj.Parent then table.insert(list, entry) else dropEntry(entry) byObj[key] = nil end end if next(byObj) == nil then fuelLookup[obj] = nil end end fuelList = list if fuelFound ~= #list then fuelFound = #list updateUI() end end RunService.Heartbeat:Connect(function() if fuelResetRequested then fuelResetRequested = false clearFuel() lastFuelScan = -math.huge end if not infFuel then return end local now = os.clock() if now - lastFuelScan >= FUEL_SCAN_INTERVAL then lastFuelScan = now local _, bikeRoot = getVehicle() scanFuel(bikeRoot and topModel(bikeRoot) or nil) end for _, entry in ipairs(fuelList) do enforce(entry) end end) RunService.RenderStepped:Connect(function() if not infFuel then return end for _, entry in ipairs(fuelList) do enforce(entry) end end) ------------------------------------------------------------------ -- Wheelie logic (runs before each physics step) ------------------------------------------------------------------ local fallbackDirection = FRONT_IS_REVERSED and -1 or 1 local targetPitch = math.rad(TARGET_PITCH_DEG) local localForward = nil -- the bike's front, stored relative to the reference part local calibratedRoot = nil -- which bike localForward belongs to RunService.Stepped:Connect(function(_, dt) if not enabled then setStatus("off") return end local ref, root = getVehicle() if not ref or not root then localForward = nil calibratedRoot = nil setStatus("can't find your bike. Sit on it (or get on it) first") return end if root.Anchored then setStatus("bike is anchored, so it can't move") return end -- New bike? Forget what we learned about the old one if calibratedRoot ~= root then calibratedRoot = root localForward = nil end local cf = ref.CFrame -- Learn which way is "front" from the way the bike actually drives if AUTO_DETECT_FRONT and not localForward then local vel = root.AssemblyLinearVelocity local flat = Vector3.new(vel.X, 0, vel.Z) local reversing = ref:IsA("VehicleSeat") and ref.Throttle < 0 if flat.Magnitude >= DETECT_SPEED and not reversing then local dirUnit = flat.Unit local best, bestDot = nil, 0.8 local candidates = { cf.LookVector, -cf.LookVector, cf.RightVector, -cf.RightVector } for _, c in ipairs(candidates) do local d = c:Dot(dirUnit) if d > bestDot then best, bestDot = c, d end end if best then localForward = cf:VectorToObjectSpace(best) end end if not localForward then setStatus("drive forward a bit so I can find the bike's front") return end end local forward if AUTO_DETECT_FRONT then forward = cf:VectorToWorldSpace(localForward) else forward = cf.LookVector * fallbackDirection end local forwardSpeed = root.AssemblyLinearVelocity:Dot(forward) if REQUIRE_THROTTLE and ref:IsA("VehicleSeat") and ref.Throttle <= 0 then setStatus("hold forward to wheelie") return end if math.abs(forwardSpeed) < MIN_SPEED then setStatus("go faster to wheelie") return end -- Axis that tips the nose up (forward x up). Positive rotation = nose up. local axis = forward:Cross(cf.UpVector) local pitch = math.asin(math.clamp(forward.Y, -1, 1)) local desiredRate = math.clamp((targetPitch - pitch) * GAIN, -MAX_RATE, MAX_RATE) local angVel = root.AssemblyAngularVelocity local blend = math.clamp(dt * RESPONSE, 0, 1) -- Pitch: hold the front wheel at the target angle local currentRate = angVel:Dot(axis) local newVel = angVel + axis * (desiredRate - currentRate) * blend -- Roll: keep the bike from falling sideways. This is weakened while you steer -- so turning still works. Turning (yaw) is never touched. local levelRight = forward:Cross(Vector3.yAxis) if levelRight.Magnitude > 0.1 then levelRight = levelRight.Unit local steering = false if ref:IsA("VehicleSeat") and math.abs(ref.SteerFloat) > 0.1 then steering = true else local character = player.Character local humanoid = character and character:FindFirstChildOfClass("Humanoid") if humanoid and math.abs(humanoid.MoveDirection:Dot(levelRight)) > 0.3 then steering = true end end local gain = steering and ROLL_GAIN * STEER_ROLL_FACTOR or ROLL_GAIN local rollError = forward:Dot(axis:Cross(levelRight)) local desiredRoll = math.clamp(rollError * gain, -MAX_RATE, MAX_RATE) local currentRoll = angVel:Dot(forward) newVel += forward * (desiredRoll - currentRoll) * blend end root.AssemblyAngularVelocity = newVel local bikeName = (topModel(root) or root).Name setStatus(string.format("holding wheelie on %s (%d°)", bikeName, math.floor(math.deg(pitch) + 0.5))) end)