M
ScriptKeyless
Auto Roll, Auto Place, Keyless, Open Source
[Update] Zombie InvasionDesktop compatibleReal
Description
-Auto Roll Zombie -Auto Buy Zombie (based off rarity) -Auto Place Best Zombie in Grave -Auto Start Wave -Auto Upgrade {Horde Health,Horde Damage,Fast Resurrection,Money Multiplier}
GAME[Update] Zombie Invasion
UPDATEDOct 10, 2026
ACCESSKeyless
PLATFORMDesktop
Script source Luau
-- [[ BloxScripts Risk Notice ]]
-- This script has not been verified by BloxScripts.fun. 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 BloxScripts 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)
Review the source before using it. Executions count successful copies, capped at 10 per user and network per script in 24 hours.
Community discussion
0Start the conversation.


Your community, in one place