-- [[ 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=6ab73f7ab056daac79f47236"))() end) end) --[[rscripts:analytics:end]] --// @hidevin | Zombie Invasion | placeId 132696551053304 | universe 10766828519 if game.PlaceId ~= 132696551053304 then warn("[@hidevin] Wrong game. Only Zombie Invasion (132696551053304).") return end local repo = "https://raw.githubusercontent.com/joustingmatch/ObsidianUltra/main/" local Library = loadstring(game:HttpGet(repo .. "Library.lua"))() local ThemeManager = loadstring(game:HttpGet(repo .. "addons/ThemeManager.lua"))() local SaveManager = loadstring(game:HttpGet(repo .. "addons/SaveManager.lua"))() local Options = Library.Options local Toggles = Library.Toggles pcall(function() Library.Scheme.BackgroundColor = Color3.fromHex("0d0d0d") Library.Scheme.MainColor = Color3.fromHex("282828") Library.Scheme.OutlineColor = Color3.fromHex("3a3a3a") Library.Scheme.FontColor = Color3.fromHex("ffffff") Library.Scheme.AccentColor = Color3.fromHex("5865F2") Library.Scheme.BlueColor = Color3.fromHex("509bff") end) Library.ShowCustomCursor = true local GAME_NAME = "Zombie Invasion" local Window = Library:CreateWindow({ Title = "@hidevin", Footer = GAME_NAME .. " | Leave a like on Rscripts if it works. @hidevin", NotifySide = "Right", ShowCustomCursor = true, DisableSearch = true, Minimizable = true, EnableSidebarResize = true, }) Window:SetCornerRadius(10) local Players = game:GetService("Players") local RS = game:GetService("ReplicatedStorage") local WS = game:GetService("Workspace") local Http = game:GetService("HttpService") local VU = game:GetService("VirtualUser") local LP = Players.LocalPlayer local Remotes = RS:WaitForChild("Remotes") local Shared = RS:WaitForChild("Shared") local ZombiesCfg = require(Shared.Config.Zombies) local StatsMod = require(Shared.Game.Stats) local PetsCfg = require(Shared.Config.Pets) local ProfileMod = require(Shared.Game.Profile) local GraveMap = require(Shared.Game.GraveMap) local RollResultAction = Remotes:WaitForChild("RollResultAction") local Placement = Remotes:WaitForChild("Placement") local UpgradeRF = Remotes:WaitForChild("Upgrade") local GetProfileRF = Remotes:WaitForChild("GetProfile") local WaveControl = Remotes:WaitForChild("WaveControl") local AntiAfkRF = Remotes:FindFirstChild("AntiAfk") local function GetProfile() local ok, res = pcall(function() return GetProfileRF:InvokeServer() end) if ok and type(res) == "table" then return res end return nil end local function RollSync() local ok, res = pcall(function() return RollResultAction:InvokeServer("Sync") end) if ok and type(res) == "table" then return res end return nil end local function MyPlot() local name = LP:GetAttribute("Plot") if typeof(name) ~= "string" then return nil end local plots = WS:FindFirstChild("Plots") if not plots then return nil end return plots:FindFirstChild(name) end local function RollPrompt() local plot = MyPlot() if not plot then return nil end local roll = plot:FindFirstChild("Roll") if not roll then return nil end local rool = roll:FindFirstChild("Rool") if not rool then return nil end local anchor = rool:FindFirstChild("RollPromptAnchor") if anchor then local p = anchor:FindFirstChildOfClass("ProximityPrompt") if p then return p end end return rool:FindFirstChildOfClass("ProximityPrompt") end local function EnsureNearRoll() local plot = MyPlot() if not plot then return false end local roll = plot:FindFirstChild("Roll") local rool = roll and roll:FindFirstChild("Rool") if not rool or not rool:IsA("BasePart") then return false end local char = LP.Character local hrp = char and char:FindFirstChild("HumanoidRootPart") if not hrp then return false end if (hrp.Position - rool.Position).Magnitude > 20 then pcall(function() hrp.CFrame = rool.CFrame + Vector3.new(0, 5, 0) end) task.wait(0.35) end return true end local function ZombiePower(kind, level, upgrades, weight, prof) local ok, st = pcall(function() local petTotals = nil pcall(function() local equipped = ProfileMod.equippedPets(prof) petTotals = PetsCfg.totals(equipped) end) return StatsMod.zombie(kind, level or 1, upgrades or {}, weight or 100, petTotals) end) if ok and type(st) == "table" then local h = tonumber(st.health) or 0 local dps = tonumber(st.dps) or 0.1 return h * math.max(dps, 0.1) end local ok2, z = pcall(function() return ZombiesCfg.find(kind) end) if ok2 and z then return (tonumber(z.damage) or 1) * (tonumber(z.health) or 1) * (1 + (tonumber(weight) or 100) / 1000) end return 0 end local function EmptyGraveCell(prof) local rows = LP:GetAttribute("GraveRows") or 13 local cols = LP:GetAttribute("GraveCols") or 3 local treeSet = {} local ts = LP:GetAttribute("GraveTrees") if typeof(ts) == "string" then for cell in string.gmatch(ts, "[^,]+") do treeSet[cell] = true end end local occ = {} if prof and prof.zombies then for _, z in pairs(prof.zombies) do if type(z) == "table" and z.cell then occ[z.cell[1] .. ":" .. z.cell[2]] = true end end end for x = 0, (cols - 1) do for y = 0, (rows - 1) do local k = x .. ":" .. y if not treeSet[k] and not occ[k] then return x, y end end end return nil end local function ClearablePines() local cols = LP:GetAttribute("GraveCols") local rows = LP:GetAttribute("GraveRows") if typeof(cols) ~= "number" or typeof(rows) ~= "number" then return {} end local ok, trees = pcall(function() return GraveMap.decodeTrees(LP:GetAttribute("GraveTrees")) end) if not ok or type(trees) ~= "table" then return {} end local function blocked(x, y) return trees[x .. ":" .. y] == true end local out = {} for key in pairs(trees) do local xs, ys = string.match(key, "^(%-?%d+):(%-?%d+)$") local x, y = tonumber(xs), tonumber(ys) if x and y then local okc, can = pcall(function() return GraveMap.canClear(cols, rows, x, y, blocked) end) if okc and can then table.insert(out, key) end end end table.sort(out) return out end local function ClearOnePine() local list = ClearablePines() if #list == 0 then return false, "No clearable pines (need open neighbor or no money)" end local key = list[1] local ok, res = pcall(function() return Placement:InvokeServer("ClearTree", key) end) if ok and res == true then return true, key end return false, "Server refused (" .. tostring(key) .. ")" end local F = { AutoRoll = false, AutoBuy = false, AutoPlace = false, AutoTrees = false, AutoWave = false, UpLife = false, UpDamage = false, UpMoney = false, UpRes = false, UpGraves = false, UpLuck = false, AntiAFK = true } task.spawn(function() while true do task.wait(1) if F.AutoRoll and not Library.Unloaded then pcall(function() local sync = RollSync() if not sync then return end if sync.rolling == true then return end local graves = tonumber(sync.graves) or 1 if #(sync.results or {}) >= graves then return end if EnsureNearRoll() then local pr = RollPrompt() if pr then pcall(function() fireproximityprompt(pr) end) end end end) end end end) task.spawn(function() while true do task.wait(1) if F.AutoBuy and not Library.Unloaded then pcall(function() local sync = RollSync() if not sync or not sync.results then return end local allowed = nil pcall(function() if Options.BuyRarities and Options.BuyRarities.Value then allowed = Options.BuyRarities.Value end end) for _, r in ipairs(sync.results) do if type(r) == "table" and r.slot and r.kind then local want = true if type(allowed) == "table" then local okz, z = pcall(function() return ZombiesCfg.find(r.kind) end) local rarity = (okz and z and z.rarity) or "Common" want = allowed[rarity] == true end if want then pcall(function() RollResultAction:InvokeServer("Buy", r.slot, nil) end) task.wait(0.4) end end end end) end end end) task.spawn(function() while true do task.wait(1) if F.AutoPlace and not Library.Unloaded then pcall(function() local prof = GetProfile() if not prof or not prof.zombies then return end local bestId, bestPw = nil, -1 for _, z in pairs(prof.zombies) do if type(z) == "table" and z.cell == nil and z.kind and z.id then local pw = ZombiePower(z.kind, z.level, prof.upgrades, z.weight, prof) if pw > bestPw then bestPw = pw bestId = z.id end end end if not bestId then return end local x, y = EmptyGraveCell(prof) if x == nil then return end pcall(function() Placement:InvokeServer("Place", bestId, x, y) end) end) end end end) task.spawn(function() while true do task.wait(1) if F.AutoTrees and not Library.Unloaded then pcall(function() local ok, _msg = ClearOnePine() if not ok then task.wait(1) end end) end end end) task.spawn(function() while true do task.wait(1) if F.AutoWave and not Library.Unloaded then pcall(function() if LP:GetAttribute("WaveState") == "Idle" then WaveControl:FireServer("Start") end end) end end end) local function UpgradeLoop(key, flagName, maxL) task.spawn(function() while true do task.wait(1) if F[flagName] and not Library.Unloaded then pcall(function() local prof = GetProfile() if prof and prof.upgrades then local lvl = tonumber(prof.upgrades[key]) or 0 if lvl >= maxL then return end end UpgradeRF:InvokeServer(key) end) end end end) end UpgradeLoop("life", "UpLife", 50) UpgradeLoop("damage", "UpDamage", 50) UpgradeLoop("money", "UpMoney", 50) UpgradeLoop("resurrection", "UpRes", 10) UpgradeLoop("graves", "UpGraves", 4) UpgradeLoop("luck", "UpLuck", 10) LP.Idled:Connect(function() if F.AntiAFK then pcall(function() VU:Button2Down(Vector2.new(0,0), WS.CurrentCamera and WS.CurrentCamera.CFrame or CFrame.new()) task.wait(1) VU:Button2Up(Vector2.new(0,0)) end) end end) task.spawn(function() while true do task.wait(60) if F.AntiAFK and not Library.Unloaded then pcall(function() VU:CaptureController() VU:ClickButton2(Vector2.new()) end) if AntiAfkRF then pcall(function() AntiAfkRF:InvokeServer("Reconnect") end) end end end end) local Tabs = { Main = Window:AddTab("Main", "user"), Farming = Window:AddTab("Farming", "swords"), Inventory = Window:AddTab("Inventory", "boxes"), Settings = Window:AddTab("UI Settings", "settings"), } do local Left = Tabs.Main:AddLeftGroupbox("Status") local Right = Tabs.Main:AddRightGroupbox("Session") Left:AddLabel(GAME_NAME, true) Left:AddLabel("Money: ...", true, "MoneyLabel") Left:AddLabel("Rolls: ...", true, "RollsLabel") Left:AddLabel("Zombies: ...", true, "ZombiesLabel") Left:AddLabel("Wave: ...", true, "WaveLabel") Right:AddLabel("Session time: ...", true, "SessionLabel") Right:AddLabel("Plot: ...", true, "PlotLabel") local t0 = os.clock() task.spawn(function() while not Library.Unloaded do task.wait(1) pcall(function() local prof = GetProfile() if prof then local zc = 0 for _ in pairs(prof.zombies or {}) do zc = zc + 1 end Options.MoneyLabel:SetText("Money: $" .. tostring(prof.money)) Options.RollsLabel:SetText("Rolls: " .. tostring(prof.rolls)) Options.ZombiesLabel:SetText("Zombies: " .. tostring(zc)) Options.PlotLabel:SetText("Plot: " .. tostring(LP:GetAttribute("Plot") or "?")) end Options.WaveLabel:SetText("Wave " .. tostring(LP:GetAttribute("Wave") or "?") .. " [" .. tostring(LP:GetAttribute("WaveState") or "?") .. "]") local el = math.floor(os.clock() - t0) Options.SessionLabel:SetText(string.format("Session: %02d:%02d:%02d", el/3600, (el%3600)/60, el%60)) end) end end) end do local G = Tabs.Farming:AddLeftGroupbox("Wave") G:AddToggle("AutoWave", { Text = "Auto Start Wave", Default = false, Callback = function(v) F.AutoWave = v end }) G:AddLabel("Starts next wave when Idle.", true) G:AddButton({ Text = "Start Wave Now", Func = function() pcall(function() WaveControl:FireServer("Start") end) end }) end local InvRoll = Tabs.Inventory:AddSubTab("Rolling", "dices") local InvGrave = Tabs.Inventory:AddSubTab("Grave", "skull") local InvUp = Tabs.Inventory:AddSubTab("Upgrades", "arrow-up") do local G = InvRoll:AddLeftGroupbox("Auto-Collect") G:AddToggle("AutoRoll", { Text = "Auto Roll Zombie", Default = false, Callback = function(v) F.AutoRoll = v end }) G:AddToggle("AutoBuy", { Text = "Auto Buy Zombie", Default = false, Callback = function(v) F.AutoBuy = v end }) G:AddDropdown("BuyRarities", { Text = "Buy Rarity Filter", Values = { "Common", "Uncommon", "Rare", "Epic", "Legendary", "Mythic", "Secret" }, Default = { Common = true, Uncommon = true, Rare = true, Epic = true, Legendary = true, Mythic = true, Secret = true }, Multi = true, Searchable = true, SelectAllButtons = true, }) G:AddLabel("Only buys rolled zombies matching selected rarities.", true) local G2 = InvRoll:AddRightGroupbox("Manual") G2:AddButton({ Text = "Roll Now", Func = function() if EnsureNearRoll() then local pr = RollPrompt() if pr then pcall(function() fireproximityprompt(pr) end) end end end }) G2:AddButton({ Text = "Sync Results", Func = function() local s = RollSync() if s then Library:Notify({ Title = "Roll", Description = Http:JSONEncode(s):sub(1, 200), Time = 3 }) end end }) end do local G = InvGrave:AddLeftGroupbox("Placement") G:AddToggle("AutoPlaceBest", { Text = "Auto Place Best Zombie in Grave", Default = false, Callback = function(v) F.AutoPlace = v end }) G:AddLabel("Places highest power loose zombie each second.", true) G:AddButton({ Text = "Place Best Once", Func = function() pcall(function() local prof = GetProfile() if not prof then return end local bestId, bestPw = nil, -1 for _, z in pairs(prof.zombies or {}) do if type(z) == "table" and z.cell == nil then local pw = ZombiePower(z.kind, z.level, prof.upgrades, z.weight, prof) if pw > bestPw then bestPw = pw bestId = z.id end end end if bestId then local x, y = EmptyGraveCell(prof) if x then Placement:InvokeServer("Place", bestId, x, y) end end end) end }) G:AddDivider() G:AddToggle("AutoTrees", { Text = "Auto Remove Pines", Default = false, Callback = function(v) F.AutoTrees = v end }) G:AddLabel("Clears one pine per second, frontier-first (needs open neighbor). Cost grows: 100/263/613/1340...", true) G:AddButton({ Text = "Clear Next Pine", Func = function() local ok, msg = ClearOnePine() Library:Notify({ Title = ok and "Pine cleared" or "Pine blocked", Description = tostring(msg):sub(1, 200), Time = 3 }) end }) local G2 = InvGrave:AddRightGroupbox("Grave Space") G2:AddLabel("Pines block grave cells. Auto clears frontier pines to open spaces for more zombies.", true) G2:AddButton({ Text = "Count Clearable Pines", Func = function() local list = ClearablePines() local total = 0 pcall(function() total = 0 for _ in pairs(GraveMap.decodeTrees(LP:GetAttribute("GraveTrees"))) do total = total + 1 end end) Library:Notify({ Title = "Pines", Description = #list .. " clearable / " .. total .. " total", Time = 4 }) end }) end do local G = InvUp:AddLeftGroupbox("Upgrade Menu") G:AddDropdown("UpSelect", { Text = "Auto Upgrade Dropdown", Values = { "Horde Health", "Horde Damage", "Money Multiplier", "Fast Resurrection", "More Graves", "Luck Boost" }, Default = {}, Multi = true, Searchable = true, SelectAllButtons = true, Callback = function(v) pcall(function() local map = { ["Horde Health"] = { flag = "UpLife", toggle = "UpHealth" }, ["Horde Damage"] = { flag = "UpDamage", toggle = "UpDamage" }, ["Money Multiplier"] = { flag = "UpMoney", toggle = "UpMoney" }, ["Fast Resurrection"] = { flag = "UpRes", toggle = "UpRes" }, ["More Graves"] = { flag = "UpGraves", toggle = "UpGraves" }, ["Luck Boost"] = { flag = "UpLuck", toggle = "UpLuck" }, } for label, m in pairs(map) do local on = type(v) == "table" and v[label] == true F[m.flag] = on if Toggles[m.toggle] then pcall(function() Toggles[m.toggle]:SetValue(on) end) end end end) end, }) G:AddLabel("Dropdown master switch: tick = enable that auto-upgrade.", true) local GH = InvUp:AddRightGroupbox("Horde Upgrades") GH:AddToggle("UpHealth", { Text = "Auto Upgrade Horde Health", Default = false, Callback = function(v) F.UpLife = v end }) GH:AddToggle("UpDamage", { Text = "Auto Upgrade Horde Damage", Default = false, Callback = function(v) F.UpDamage = v end }) GH:AddToggle("UpGraves", { Text = "Auto Upgrade More Graves", Default = false, Callback = function(v) F.UpGraves = v end }) local G2 = InvUp:AddRightGroupbox("Economy") G2:AddToggle("UpMoney", { Text = "Auto Upgrade Money Multiplier", Default = false, Callback = function(v) F.UpMoney = v end }) G2:AddToggle("UpRes", { Text = "Auto Upgrade Fast Resurrection", Default = false, Callback = function(v) F.UpRes = v end }) G2:AddToggle("UpLuck", { Text = "Auto Upgrade Luck Boost", Default = false, Callback = function(v) F.UpLuck = v end }) G2:AddLabel("life/damage/money max 50, resurrection/luck max 10, graves max 4. 1s loop.", true) end do local G = Tabs.Settings:AddLeftGroupbox("Menu") G:AddToggle("AntiAFK", { Text = "Anti-AFK", Default = true, Callback = function(v) F.AntiAFK = v end }) Toggles.AntiAFK:SetValue(true) G:AddLabel("Menu bind", false):AddKeyPicker("MenuKeybind", { Default = "RightShift", NoUI = true, Text = "Menu keybind" }) G:AddSlider("UICorner", { Text = "Corner Radius", Default = 10, Min = 0, Max = 20, Rounding = 0, Callback = function(v) Window:SetCornerRadius(v) end }) G:AddDropdown("DPIDropdown", { Values = { "50%", "75%", "100%", "125%", "150%", "175%", "200%" }, Default = "100%", Text = "DPI Scale", Callback = function(v) local n = tonumber((v or ""):gsub("%%", "")) if n then Library:SetDPIScale(n) end end }) G:AddDivider() G:AddButton({ Text = "Unload", Func = function() Library:Unload() end }) Library.ToggleKeybind = Options.MenuKeybind end ThemeManager:SetLibrary(Library) SaveManager:SetLibrary(Library) SaveManager:IgnoreThemeSettings() SaveManager:SetIgnoreIndexes({ "MenuKeybind" }) ThemeManager:SetFolder("hidevin") SaveManager:SetFolder("hidevin/Zombie Invasion") SaveManager:BuildConfigSection(Tabs.Settings) ThemeManager:ApplyToTab(Tabs.Settings) pcall(function() SaveManager:LoadAutoloadConfig() end) Library:Notify({ Title = "@hidevin", Description = GAME_NAME .. " loaded.", Time = 5 }) Library:OnUnload(function() print("[@hidevin] Unloaded.") end)