-- [[ 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 ]] local WindUI = loadstring(game:HttpGet("https://github.com/Footagesus/WindUI/releases/latest/download/main.lua"))() local Players = game:GetService("Players") local RunService = game:GetService("RunService") local UserInputService = game:GetService("UserInputService") local CoreGui = game:GetService("CoreGui") local HttpService = game:GetService("HttpService") local TeleportService = game:GetService("TeleportService") local Settings = { Aimbot = false, AimKey = "Always", Hitbox = "Head", FOV = 90, Smooth = 50, MaxDist = 300, WallCheck = false, ESP = false, Box = true, HealthBar = true, Name = true, Tracer = false, Distance = false, FOVCircle = false, ESPRange = 10000, TextSize = 13, TeamCheck = true, ESPColor = Color3.fromRGB(255, 80, 80), Effect = "None", Rate = 150, Wind = 0, PSize = 3, } WindUI:SetParent(CoreGui) WindUI:SetNotificationLower(true) local Window = WindUI:CreateWindow({ Title = "RIVALS External", Icon = "crosshair", Author = "aim · visuals · weather · settings", Folder = "RivalsExternal", Size = UDim2.fromOffset(620, 480), MinSize = Vector2.new(560, 380), MaxSize = Vector2.new(860, 600), Transparent = true, Theme = "Dark", Resizable = true, SideBarWidth = 180, Radius = 18, ToggleKey = Enum.KeyCode.LeftShift, Acrylic = false, }) local TabAim = Window:Tab({ Title = "Aim", Icon = "crosshair" }) local TabVisuals = Window:Tab({ Title = "Visuals", Icon = "eye" }) local TabWeather = Window:Tab({ Title = "Weather", Icon = "cloud-snow" }) local TabServers = Window:Tab({ Title = "Servers", Icon = "server" }) local TabSettings = Window:Tab({ Title = "Settings", Icon = "sliders-horizontal" }) local aimbotToggle = TabAim:Toggle({ Title = "Aimbot", Desc = "Snaps your crosshair to the best target", Icon = "target", Value = false, Callback = function(v) Settings.Aimbot = v if v then WindUI:Notify({ Title = "Aimbot enabled", Content = "Key: " .. Settings.AimKey, Duration = 2, Icon = "target" }) end end, }) TabAim:Dropdown({ Title = "Aim Key", Desc = "When to aim at the target", Values = { "Always", "Left Click", "Right Click", "Q" }, Value = "Always", Callback = function(v) Settings.AimKey = v end, }) TabAim:Dropdown({ Title = "Hitbox", Desc = "Which part of the target to aim at", Values = { "Head", "Body" }, Value = "Head", Callback = function(v) Settings.Hitbox = v end, }) TabAim:Slider({ Title = "FOV", Desc = "Aim assist field of view in degrees", Value = { Min = 1, Max = 360, Default = 90 }, Step = 1, Flag = "aim_fov", Callback = function(v) Settings.FOV = v end, }) TabAim:Slider({ Title = "Smoothness", Desc = "Higher feels snappier, lower is smoother", Value = { Min = 0, Max = 100, Default = 50 }, Step = 1, Flag = "aim_smooth", Callback = function(v) Settings.Smooth = v end, }) TabAim:Slider({ Title = "Max Distance", Desc = "Maximum studs to aim at a target", Value = { Min = 10, Max = 3000, Default = 300 }, Step = 5, Flag = "aim_dist", Callback = function(v) Settings.MaxDist = v end, }) TabAim:Toggle({ Title = "Visible Only", Desc = "Ignore targets behind walls", Value = false, Callback = function(v) Settings.WallCheck = v end, }) TabVisuals:Toggle({ Title = "ESP", Desc = "Draw targets through walls", Icon = "scan-eye", Value = false, Callback = function(v) Settings.ESP = v if v then WindUI:Notify({ Title = "ESP enabled", Content = "Drawing targets through walls", Duration = 2, Icon = "scan-eye" }) end end, }) TabVisuals:Toggle({ Title = "Box", Value = true, Callback = function(v) Settings.Box = v end, }) TabVisuals:Toggle({ Title = "Health Bar", Value = true, Callback = function(v) Settings.HealthBar = v end, }) TabVisuals:Toggle({ Title = "Name", Value = true, Callback = function(v) Settings.Name = v end, }) TabVisuals:Toggle({ Title = "Tracer", Value = false, Callback = function(v) Settings.Tracer = v end, }) TabVisuals:Toggle({ Title = "Distance", Value = false, Callback = function(v) Settings.Distance = v end, }) TabVisuals:Toggle({ Title = "FOV Circle", Desc = "Show the aim FOV on screen", Value = false, Callback = function(v) Settings.FOVCircle = v end, }) TabVisuals:Slider({ Title = "ESP Range", Value = { Min = 50, Max = 10000, Default = 10000 }, Step = 50, Flag = "esp_range", Callback = function(v) Settings.ESPRange = v end, }) TabVisuals:Slider({ Title = "Text Size", Value = { Min = 10, Max = 24, Default = 13 }, Step = 1, Flag = "esp_text", Callback = function(v) Settings.TextSize = v end, }) TabVisuals:Dropdown({ Title = "ESP Color", Values = { "Red", "Orange", "Yellow", "Green", "Cyan", "Blue", "Purple", "Pink", "White" }, Value = "Red", Callback = function(v) local map = { Red = Color3.fromRGB(255, 80, 80), Orange = Color3.fromRGB(255, 160, 60), Yellow = Color3.fromRGB(255, 220, 70), Green = Color3.fromRGB(80, 255, 130), Cyan = Color3.fromRGB(80, 230, 255), Blue = Color3.fromRGB(90, 130, 255), Purple = Color3.fromRGB(190, 90, 255), Pink = Color3.fromRGB(255, 90, 200), White = Color3.fromRGB(230, 230, 230), } Settings.ESPColor = map[v] or Settings.ESPColor end, }) TabVisuals:Toggle({ Title = "Team Check", Desc = "Only draw enemies (TeamID differs)", Value = true, Callback = function(v) Settings.TeamCheck = v end, }) TabWeather:Dropdown({ Title = "Effect", Desc = "Weather overlay drawn on your screen", Values = { "None", "Rain", "Snow", "Storm" }, Value = "None", Callback = function(v) Settings.Effect = v end, }) TabWeather:Slider({ Title = "Rate", Desc = "Particle density / intensity", Value = { Min = 10, Max = 500, Default = 150 }, Step = 10, Flag = "wx_rate", Callback = function(v) Settings.Rate = v end, }) TabWeather:Slider({ Title = "Wind", Desc = "Horizontal drift, negative blows left", Value = { Min = -80, Max = 80, Default = 0 }, Step = 2, Flag = "wx_wind", Callback = function(v) Settings.Wind = v end, }) TabWeather:Slider({ Title = "Particle Size", Value = { Min = 1, Max = 8, Default = 3 }, Step = 1, Flag = "wx_size", Callback = function(v) Settings.PSize = v end, }) -- ============================== server changer ============================== local serverList = {} local serverLabels = {} local serverSelected = nil local serverDropdown = nil local function hopTo(jobId, force) if not jobId or jobId == "" then WindUI:Notify({ Title = "No server", Content = "Refresh and pick a server first.", Duration = 3, Icon = "triangle-alert" }) return end if jobId == game.JobId and not force then WindUI:Notify({ Title = "Already there", Content = "You are already in that server.", Duration = 3, Icon = "info" }) return end WindUI:Notify({ Title = "Joining server", Content = string.sub(jobId, 1, 8) .. "…", Duration = 3, Icon = "send" }) local ok = pcall(function() TeleportService:TeleportToPlaceInstance(game.PlaceId, jobId, Players.LocalPlayer) end) if not ok then local ok2, err2 = pcall(function() TeleportService:TeleportToPlaceInstance(game.PlaceId, jobId) end) if not ok2 then WindUI:Notify({ Title = "Teleport failed", Content = tostring(err2), Duration = 4, Icon = "triangle-alert" }) end end end local function fetchServers() local raw = game:HttpGet("https://games.roblox.com/v1/games/" .. game.PlaceId .. "/servers/Public?limit=100") local data = HttpService:JSONDecode(raw) local out = {} for _, s in ipairs(data.data or {}) do if s.id and (s.playing or 0) < (s.maxPlayers or 0) then out[#out + 1] = s end end return out end local function buildServerDropdown() if serverDropdown then pcall(function() serverDropdown:Destroy() end) end local labels = {} serverLabels = {} for _, s in ipairs(serverList) do if s.id ~= game.JobId then local label = string.format("%d/%d · %dms · %s", s.playing or 0, s.maxPlayers or 0, s.ping or 0, string.sub(s.id, 1, 8)) labels[#labels + 1] = label serverLabels[label] = s.id end end if #labels == 0 then labels = { "No open servers found" } end serverDropdown = TabServers:Dropdown({ Title = "Server", Desc = "Pick one, then press Join Selected", Values = labels, Value = labels[1], Callback = function(v) serverSelected = serverLabels[v] end, }) serverSelected = serverLabels[labels[1]] end local function refreshServers(silent) local ok, res = pcall(fetchServers) if not ok then WindUI:Notify({ Title = "Server list failed", Content = tostring(res), Duration = 5, Icon = "triangle-alert" }) return end serverList = res buildServerDropdown() if not silent then WindUI:Notify({ Title = "Servers refreshed", Content = #serverList .. " joinable servers found", Duration = 3, Icon = "refresh-cw" }) end end local function hopStrategy(pick) if #serverList == 0 then refreshServers(true) end local chosen = nil for _, s in ipairs(serverList) do if s.id ~= game.JobId and (not chosen or pick(s, chosen)) then chosen = s end end if chosen then hopTo(chosen.id) else WindUI:Notify({ Title = "No server", Content = "No other server available.", Duration = 3, Icon = "triangle-alert" }) end end local function randomHop() if #serverList == 0 then refreshServers(true) end local pool = {} for _, s in ipairs(serverList) do if s.id ~= game.JobId then pool[#pool + 1] = s end end if #pool > 0 then hopTo(pool[math.random(1, #pool)].id) else WindUI:Notify({ Title = "No server", Content = "No other server available.", Duration = 3, Icon = "triangle-alert" }) end end TabServers:Button({ Title = "Refresh Server List", Desc = "Fetch live servers for this place", Icon = "refresh-cw", Callback = function() refreshServers(false) end, }) TabServers:Button({ Title = "Join Selected", Desc = "Teleport to the highlighted server", Icon = "arrow-right", Callback = function() if not serverSelected then refreshServers(true) end hopTo(serverSelected) end, }) TabServers:Button({ Title = "Hop — Lowest Ping", Icon = "zap", Callback = function() hopStrategy(function(s, b) return (s.ping or 9999) < (b.ping or 9999) end) end, }) TabServers:Button({ Title = "Hop — Fewest Players", Icon = "users", Callback = function() hopStrategy(function(s, b) return (s.playing or 0) < (b.playing or 0) end) end, }) TabServers:Button({ Title = "Random Hop", Icon = "shuffle", Callback = function() randomHop() end, }) TabServers:Button({ Title = "Rejoin Same Server", Desc = game.JobId, Icon = "rotate-ccw", Callback = function() hopTo(game.JobId, true) end, }) TabServers:Button({ Title = "Copy Job ID", Icon = "copy", Callback = function() if setclipboard then pcall(setclipboard, game.JobId) WindUI:Notify({ Title = "Copied", Content = game.JobId, Duration = 3, Icon = "clipboard-check" }) end end, }) TabSettings:Slider({ Title = "Window Transparency", Desc = "The black-glass effect", Value = { Min = 0, Max = 70, Default = 25 }, Step = 5, Flag = "ui_transp", Callback = function(v) Window:SetBackgroundTransparency(v / 100) end, }) TabSettings:Slider({ Title = "UI Scale", Value = { Min = 50, Max = 150, Default = 100 }, Step = 5, Flag = "ui_scale", Callback = function(v) Window:SetUIScale(v / 100) end, }) TabSettings:Dropdown({ Title = "Theme", Values = { "Dark", "Light" }, Value = "Dark", Callback = function(v) Window:SetTheme(v) end, }) TabSettings:Dropdown({ Title = "Menu Toggle Key", Desc = "LeftShift / RightShift work too", Values = { "LeftShift", "RightShift", "Delete", "LeftControl", "K", "V", "F2" }, Value = "LeftShift", Callback = function(v) local key = Enum.KeyCode[v] if key then Window:SetToggleKey(key) end end, }) TabSettings:Button({ Title = "Disable All Features", Desc = "Turns off aimbot, ESP and FOV circle", Callback = function() Settings.Aimbot = false Settings.ESP = false Settings.FOVCircle = false end, }) -- everything from here down is the machinery behind the menu ----------------------------------- local drawObjs = {} local fovCircle = nil -- --------------------------------------------------------------------------- -- weather engine (screen-space particles via Drawing) -- --------------------------------------------------------------------------- local weatherPool = {} -- array of particles local weatherObjs = {} -- array of Drawing objects (parallel) local weatherCount = 0 local weatherEffect = "None" local function clearWeather() for _, obj in ipairs(weatherObjs) do pcall(function() obj:Remove() end) end weatherObjs = {} weatherPool = {} weatherCount = 0 weatherEffect = "None" end local function buildWeather(vp) clearWeather() local n = math.floor(Settings.Rate) local effect = Settings.Effect local wind = Settings.Wind local size = Settings.PSize local vpW = (vp and vp.X) or (workspace.CurrentCamera and workspace.CurrentCamera.ViewportSize.X) or 1920 local vpH = (vp and vp.Y) or (workspace.CurrentCamera and workspace.CurrentCamera.ViewportSize.Y) or 1080 weatherEffect = effect for i = 1, n do local obj if effect == "Rain" or effect == "Storm" then local line = Drawing.new("Line") line.Color = Color3.fromRGB(150, 190, 255) line.Thickness = effect == "Storm" and math.max(size + 3, 3) or math.max(size - 1, 1) line.Transparency = effect == "Storm" and 0.35 or 0.45 line.Visible = false obj = line else local dot = Drawing.new("Circle") dot.Color = Color3.fromRGB(255, 255, 255) dot.Thickness = 1 dot.Transparency = 0.25 dot.Filled = true dot.Visible = false obj = dot end weatherObjs[i] = obj weatherPool[i] = { x = math.random() * vpW, y = math.random() * vpH, velx = wind * 1.2 + (math.random() - 0.5) * 40, vely = (effect == "Snow") and (40 + math.random() * 45) or (220 + math.random() * 160), drift = (math.random() - 0.5) * 2, phase = math.random() * math.pi * 2, rad = (size + math.random() * 2) / (effect == "Snow" and 2 or 1), } end weatherCount = n end local function updateWeather(dt, vp) if Settings.Effect == "None" then if weatherCount > 0 then clearWeather() end return end if weatherEffect ~= Settings.Effect or weatherCount ~= math.floor(Settings.Rate) then buildWeather(vp) end local wind = Settings.Wind local sp = Settings.PSize / 3 local vpW, vpH = vp.X, vp.Y for i = 1, weatherCount do local p = weatherPool[i] local obj = weatherObjs[i] p.phase = p.phase + dt * 3 p.x = p.x + (p.velx + math.sin(p.phase) * p.drift * 30) * dt p.y = p.y + p.vely * dt if p.x < -60 or p.x > vpW + 60 or p.y > vpH + 80 then p.x = math.random() * (vpW + 120) - 60 p.y = -math.random() * 80 end obj.Visible = true if Settings.Effect == "Snow" then obj.Position = Vector2.new(p.x, p.y) obj.Radius = p.rad * (Settings.PSize / 3) else obj.From = Vector2.new(p.x - wind * 4, p.y) obj.To = Vector2.new(p.x + sp * 40 - wind * 4, p.y + sp * 40) end end end local function playerTeam(p) local ok, v = pcall(function() return p:GetAttribute("TeamID") end) return ok and v or nil end local function isEnemy(p) if p == Players.LocalPlayer then return false end local char = p.Character if not char then return false end local hum = char:FindFirstChildOfClass("Humanoid") if not hum or hum.Health <= 0 then return false end if not char:FindFirstChild("HumanoidRootPart") then return false end if Settings.TeamCheck then local me = playerTeam(Players.LocalPlayer) local them = playerTeam(p) if me and them and me == them then return false end end return true end local function hasLineOfSight(from, to) local params = RaycastParams.new() params.FilterType = Enum.RaycastFilterType.Exclude params.FilterDescendantsInstances = { Players.LocalPlayer.Character } local result = workspace:Raycast(from, to - from, params) if not result then return true end local playerHit = result.Instance and result.Instance:FindFirstAncestorOfClass("Model") local hitChar = playerHit and Players:GetPlayerFromCharacter(playerHit) return hitChar ~= nil end local function initESP(p) local d = {} d.box = Drawing.new("Square") d.box.Thickness = 1.4 d.box.Filled = false d.box.Visible = false d.line = Drawing.new("Line") d.line.Thickness = 1.2 d.line.Visible = false d.name = Drawing.new("Text") d.name.Center = true d.name.Outline = true d.name.Visible = false d.hbg = Drawing.new("Square") d.hbg.Filled = true d.hbg.Color = Color3.fromRGB(20, 20, 20) d.hbg.Visible = false d.hp = Drawing.new("Square") d.hp.Filled = true d.hp.Visible = false d.dist = Drawing.new("Text") d.dist.Center = true d.dist.Outline = true d.dist.Visible = false drawObjs[p] = d return d end local function clearESP() for _, d in pairs(drawObjs) do for _, obj in pairs(d) do pcall(function() obj:Remove() end) end end drawObjs = {} end local function makeFOVCircle() if fovCircle then pcall(function() fovCircle:Remove() end) end fovCircle = Drawing.new("Circle") fovCircle.Color = Color3.fromRGB(255, 255, 255) fovCircle.Thickness = 1.2 fovCircle.Filled = false fovCircle.Transparency = 0.55 fovCircle.Visible = false end local function fovRadiusPx(cam, fovDeg) local vp = cam.ViewportSize local halfDeg = math.rad(fovDeg / 2) local camHalf = math.rad(cam.FieldOfView / 2) return (math.tan(halfDeg) / math.tan(camHalf)) * (vp.Y / 2) end local function updateFOVCircle(cam) if not fovCircle then makeFOVCircle() end if not Settings.FOVCircle then if fovCircle.Visible then fovCircle.Visible = false end return end local vp = cam.ViewportSize fovCircle.Radius = fovRadiusPx(cam, Settings.FOV) fovCircle.Position = Vector2.new(vp.X / 2, vp.Y / 2) fovCircle.Visible = true end local function espFrame() local cam = workspace.CurrentCamera if not cam then return end local vp = cam.ViewportSize for _, d in pairs(drawObjs) do d.box.Visible = false d.line.Visible = false d.name.Visible = false d.hbg.Visible = false d.hp.Visible = false d.dist.Visible = false end for _, p in ipairs(Players:GetPlayers()) do if not isEnemy(p) then continue end local char = p.Character local hrp = char:FindFirstChild("HumanoidRootPart") local hum = char:FindFirstChildOfClass("Humanoid") if not hrp or not hum then continue end local dist = (cam.CFrame.Position - hrp.Position).Magnitude if dist > Settings.ESPRange then continue end local depth = dist local px = vp.Y / 2 / (depth * math.tan(math.rad(cam.FieldOfView / 2))) local csp = cam:WorldToViewportPoint(hrp.Position + Vector3.new(0, 3, 0)) if csp.Z < 1 then continue end local boxW = 2.2 * px * (3.5 / 2.2) local boxH = 5.2 * px local left = csp.X - boxW / 2 local top = csp.Y - boxH / 2 local bottom = csp.Y + boxH / 2 local d = drawObjs[p] or initESP(p) if Settings.Box then d.box.Color = Settings.ESPColor d.box.Position = Vector2.new(left, top) d.box.Size = Vector2.new(boxW, boxH) d.box.Visible = true end if Settings.Tracer then local hsp = cam:WorldToViewportPoint(hrp.Position) d.line.Color = Settings.ESPColor d.line.From = Vector2.new(vp.X / 2, vp.Y) d.line.To = Vector2.new(hsp.X, hsp.Y) d.line.Visible = true end if Settings.Name then d.name.Color = Color3.fromRGB(255, 255, 255) d.name.Text = p.DisplayName d.name.Size = Settings.TextSize d.name.Position = Vector2.new(csp.X, top - Settings.TextSize - 4) d.name.Visible = true end if Settings.HealthBar then local heal = math.clamp(hum.Health / hum.MaxHealth, 0, 1) d.hbg.Position = Vector2.new(left - 7, top + 1) d.hbg.Size = Vector2.new(3, math.max(boxH - 2, 1)) d.hbg.Visible = true d.hp.Color = Color3.fromRGB(80, 235, 120):Lerp(Color3.fromRGB(235, 60, 60), 1 - heal) d.hp.Position = Vector2.new(left - 7, bottom - 1 - (boxH - 2) * heal) d.hp.Size = Vector2.new(3, math.max((boxH - 2) * heal, 1)) d.hp.Visible = true end if Settings.Distance then d.dist.Color = Settings.ESPColor d.dist.Text = string.format("%.0f studs", dist) d.dist.Size = Settings.TextSize - 2 d.dist.Position = Vector2.new(csp.X, bottom + 2) d.dist.Visible = true end end end local function hitboxPart(char) if Settings.Hitbox == "Head" then return char:FindFirstChild("HitboxHead") or char:FindFirstChild("Head") or char:FindFirstChild("PhysicalHitboxHead") or char:FindFirstChild("HumanoidRootPart") end return char:FindFirstChild("HitboxBody") or char:FindFirstChild("HitboxBodySmall") or char:FindFirstChild("HumanoidRootPart") end local function bestTarget(cam, center, radius) local best, bestScore = nil, math.huge local camPos = cam.CFrame.Position for _, p in ipairs(Players:GetPlayers()) do if not isEnemy(p) then continue end local char = p.Character local hrp = char:FindFirstChild("HumanoidRootPart") if not hrp then continue end local dist = (camPos - hrp.Position).Magnitude if dist > Settings.MaxDist then continue end local part = hitboxPart(char) if not part then continue end if Settings.WallCheck and not hasLineOfSight(camPos, part.Position) then continue end local sp = cam:WorldToViewportPoint(part.Position) if sp.Z < 1 then continue end local screen = Vector2.new(sp.X, sp.Y) local off = (screen - center).Magnitude if off <= radius and off < bestScore then best, bestScore = part, off end end return best end local function aimActive() local k = Settings.AimKey if k == "Left Click" then return UserInputService:IsMouseButtonPressed(Enum.UserInputType.MouseButton1) elseif k == "Right Click" then return UserInputService:IsMouseButtonPressed(Enum.UserInputType.MouseButton2) elseif k == "Q" then return UserInputService:IsKeyDown(Enum.KeyCode.Q) end return true end RunService.RenderStepped:Connect(function(dt) local cam = workspace.CurrentCamera if not cam then return end local vp = cam.ViewportSize updateWeather(dt, vp) if Settings.FOVCircle then updateFOVCircle(cam) elseif fovCircle and fovCircle.Visible then fovCircle.Visible = false end if Settings.ESP then espFrame() else clearESP() end if Settings.Aimbot and aimActive() then local vp = cam.ViewportSize local center = Vector2.new(vp.X / 2, vp.Y / 2) local target = bestTarget(cam, center, fovRadiusPx(cam, Settings.FOV)) if target then local goal = CFrame.lookAt(cam.CFrame.Position, target.Position) local spd = Settings.Smooth / 100 local alpha = 1 - (1 - spd) ^ (dt * 60) if spd >= 0.995 then cam.CFrame = goal else cam.CFrame = cam.CFrame:Lerp(goal, alpha) end end end end) Players.PlayerRemoving:Connect(function(p) local d = drawObjs[p] if d then for _, obj in pairs(d) do pcall(function() obj:Remove() end) end drawObjs[p] = nil end end) pcall(function() game:BindToClose(function() clearESP() clearWeather() if fovCircle then pcall(function() fovCircle:Remove() end) fovCircle = nil end end) end) makeFOVCircle() WindUI:Notify({ Title = "RIVALS External loaded", Content = "Hold Shift to open / close the menu.", Duration = 4, Icon = "sparkles", })