--// Serviços principais
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local player = Players.LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()
local hrp = char:WaitForChild("HumanoidRootPart")
local humanoid = char:WaitForChild("Humanoid")

--// Configurações
local alturas = {
    Floppa = 5.5,
    ["Golden Floppa"] = 5.5,
    ["Big Floppa"] = 10
}
local monstroSelecionado = "Floppa"

-- nomes permitidos (validação extra)
local allowedNames = {
    Floppa = true,
    ["Golden Floppa"] = true,
    ["Big Floppa"] = true
}

--// Variáveis de controle
local alvo = nil
local conn = nil
local attackLoop = nil
local questConn = nil
local lastAmount = nil
local debounce = false
local gettingQuest = false
local autofarmOn = false
local autoQuestLoop = nil

--// Monitoramento restrito: apenas modelos em workspace.Monster com name permitido e igual ao selecionado
local aliveMonsters = {}
local monsterFolder = workspace:FindFirstChild("Monster")
local monsterFolderWatcher = nil
local modelChildWatchers = {}

local function modelNameAllowed(name)
    return allowedNames[name] == true
end

local function tryRegisterModel(model)
    if not model or not model:IsA("Model") then return end
    if model == player.Character then return end
    if not modelNameAllowed(model.Name) then return end -- validação extra: só nomes permitidos
    if model.Name ~= monstroSelecionado then return end -- filtra pelo nome selecionado

    local lower = model:FindFirstChild("LowerTorso")
    local hum = model:FindFirstChild("Humanoid")
    if lower and hum and hum.Health and hum.Health > 0 then
        aliveMonsters[model] = lower
    else
        aliveMonsters[model] = nil
    end
end

local function ensureModelListeners(model)
    if not model or not model:IsA("Model") then return end
    if not modelNameAllowed(model.Name) then return end -- só cria listeners para nomes permitidos
    if model.Name ~= monstroSelecionado then return end -- só cria listeners para o tipo selecionado
    if modelChildWatchers[model] then return end
    modelChildWatchers[model] = {}

    local childAddedConn = model.ChildAdded:Connect(function(child)
        task.wait(0.05)
        if child.Name == "Humanoid" or child.Name == "LowerTorso" then
            tryRegisterModel(model)
            local hum = model:FindFirstChild("Humanoid")
            if hum and not hum:FindFirstChild("__aliveListener") then
                local tag = Instance.new("BoolValue")
                tag.Name = "__aliveListener"
                tag.Parent = hum
                local healthConn = hum:GetPropertyChangedSignal("Health"):Connect(function()
                    if hum.Health and hum.Health > 0 then
                        aliveMonsters[model] = model:FindFirstChild("LowerTorso")
                    else
                        aliveMonsters[model] = nil
                    end
                end)
                table.insert(modelChildWatchers[model], healthConn)
            end
        end
    end)
    table.insert(modelChildWatchers[model], childAddedConn)

    local hum = model:FindFirstChild("Humanoid")
    if hum and not hum:FindFirstChild("__aliveListener") then
        local tag = Instance.new("BoolValue")
        tag.Name = "__aliveListener"
        tag.Parent = hum
        local healthConn = hum:GetPropertyChangedSignal("Health"):Connect(function()
            if hum.Health and hum.Health > 0 then
                aliveMonsters[model] = model:FindFirstChild("LowerTorso")
            else
                aliveMonsters[model] = nil
            end
        end)
        table.insert(modelChildWatchers[model], healthConn)
    end
end

local function unregisterModel(model)
    if not model then return end
    aliveMonsters[model] = nil
    local conns = modelChildWatchers[model]
    if conns then
        for _, c in ipairs(conns) do
            pcall(function() c:Disconnect() end)
        end
        modelChildWatchers[model] = nil
    end
end

local function initMonsterFolderWatchers()
    monsterFolder = workspace:FindFirstChild("Monster")
    if not monsterFolder then return end

    -- registra apenas modelos com nome permitido e igual ao selecionado
    for _, m in ipairs(monsterFolder:GetChildren()) do
        tryRegisterModel(m)
        ensureModelListeners(m)
    end

    -- ChildAdded: registra novo modelo se o nome for permitido (e depois tryRegisterModel filtra por selecionado)
    monsterFolderWatcher = monsterFolder.ChildAdded:Connect(function(child)
        task.wait(0.05)
        if modelNameAllowed(child.Name) then
            tryRegisterModel(child)
            ensureModelListeners(child)
        end
    end)

    -- ChildRemoved: remove da tabela e limpa listeners
    monsterFolder.ChildRemoved:Connect(function(child)
        unregisterModel(child)
    end)
end

local function cleanupMonsterWatchers()
    if monsterFolderWatcher then
        pcall(function() monsterFolderWatcher:Disconnect() end)
        monsterFolderWatcher = nil
    end
    for model, _ in pairs(aliveMonsters) do
        aliveMonsters[model] = nil
    end
    for model, conns in pairs(modelChildWatchers) do
        for _, c in ipairs(conns) do
            pcall(function() c:Disconnect() end)
        end
        modelChildWatchers[model] = nil
    end
end

local function refreshMonsterWatchers()
    cleanupMonsterWatchers()
    aliveMonsters = {}
    modelChildWatchers = {}
    initMonsterFolderWatchers()
end

-- inicializa pela primeira vez
initMonsterFolderWatchers()

-- Atualizar referências após respawn
player.CharacterAdded:Connect(function(newChar)
    char = newChar
    hrp = char:WaitForChild("HumanoidRootPart")
    humanoid = char:WaitForChild("Humanoid")
end)

-- Funções auxiliares de combate e seleção
local function escolherMonstro()
    local maisProximo = nil
    local menorDist = math.huge
    for model, torso in pairs(aliveMonsters) do
        if model and model.Name == monstroSelecionado and torso and torso.Parent then
            local dist = (torso.Position - hrp.Position).Magnitude
            if dist < menorDist then
                menorDist = dist
                maisProximo = torso
            end
        else
            if not (torso and torso.Parent) then
                aliveMonsters[model] = nil
            end
        end
    end
    return maisProximo
end

local function equipCombat()
    local tool = player.Backpack:FindFirstChild("Combat") or player.Character:FindFirstChild("Combat")
    if tool and tool.Parent == player.Backpack then
        tool.Parent = player.Character
    end
    return tool
end

local function iniciarAtaque()
    if attackLoop then return end
    attackLoop = RunService.RenderStepped:Connect(function()
        local tool = equipCombat()
        if tool then
            pcall(function() tool:Activate() end)
        end
    end)
end

local function pararAtaque()
    if attackLoop then attackLoop:Disconnect(); attackLoop = nil end
end

-- Interação com NPC de quest
local function tpPegarQuest()
    local npcName = "Floppa Quest 1"
    if monstroSelecionado == "Golden Floppa" then
        npcName = "Floppa Quest 2"
    elseif monstroSelecionado == "Big Floppa" then
        npcName = "Floppa Quest 3"
    end

    local questsRoot = workspace:FindFirstChild("NPCs") and workspace.NPCs:FindFirstChild("Quests_Npc")
    if not questsRoot then return false end

    local floppaNpc = questsRoot:FindFirstChild(npcName)
    local block = floppaNpc and floppaNpc:FindFirstChild("Block")
    local prompt = block and block:FindFirstChild("QuestPrompt")
    if not (floppaNpc and block and prompt and prompt:IsA("ProximityPrompt") and prompt.Enabled) then
        return false
    end

    local original = hrp.CFrame
    hrp.AssemblyLinearVelocity = Vector3.zero
    humanoid.AutoRotate = false

    hrp.CFrame = block.CFrame + Vector3.new(0, 5, 0)
    task.wait(0.25)

    prompt:InputHoldBegin()
    task.wait(math.max(0.2, prompt.HoldDuration or 0))
    prompt:InputHoldEnd()

    task.wait(0.25)
    hrp.CFrame = original
    humanoid.AutoRotate = true

    return true
end

-- Flutuar apenas sobre monstros vivos e do tipo selecionado
local function iniciarFlutuar()
    if conn then return end
    conn = RunService.RenderStepped:Connect(function()
        if not alvo or not alvo.Parent then
            alvo = escolherMonstro()
        else
            local monParent = alvo.Parent
            local monHum = monParent and monParent:FindFirstChild("Humanoid")
            if not monHum or monHum.Health <= 0 or monParent.Name ~= monstroSelecionado then
                aliveMonsters[monParent] = nil
                alvo = escolherMonstro()
            end
        end

        if alvo and alvo.Parent then
            local monHum = alvo.Parent:FindFirstChild("Humanoid")
            if monHum and monHum.Health > 0 and alvo.Parent.Name == monstroSelecionado then
                hrp.AssemblyLinearVelocity = Vector3.zero
                hrp.CFrame = alvo.CFrame + Vector3.new(0, alturas[monstroSelecionado] or 8, 0)
            end
        end
    end)
end

local function pararFlutuar()
    if conn then conn:Disconnect(); conn, alvo = nil, nil end
end

-- Monitor de quest
local function pararMonitorQuest()
    if questConn then
        pcall(function() questConn:Disconnect() end)
        questConn = nil
    end
    lastAmount = nil
    debounce = false
end

local function pegarQuestBigFloppaComEspera(timeout)
    if gettingQuest then return false end
    gettingQuest = true
    pararMonitorQuest()
    local ok = tpPegarQuest()
    if not ok then
        task.wait(0.4)
        ok = tpPegarQuest()
    end

    local questFolder = player:FindFirstChild("QuestFolder")
    local slot = questFolder and questFolder:FindFirstChild("QuestSlot1")
    local start = tick()
    timeout = timeout or 3
    if slot then
        while tick() - start < timeout do
            local need = slot:FindFirstChild("Need")
            if need and need.Value == 1 then break end
            task.wait(0.12)
        end
    end
    gettingQuest = false
    return ok
end

local function reiniciarCiclo()
    pararFlutuar()
    pararAtaque()
    task.wait(0.3)

    if monstroSelecionado == "Big Floppa" then
        pegarQuestBigFloppaComEspera(3)
        task.wait(0.2)
        iniciarAtaque()
        iniciarFlutuar()
        iniciarMonitorQuest()
    else
        tpPegarQuest()
        iniciarAtaque()
        iniciarFlutuar()
    end
end

function iniciarMonitorQuest()
    if questConn then return end
    local questFolder = player:WaitForChild("QuestFolder")
    local slot = questFolder:WaitForChild("QuestSlot1")

    if monstroSelecionado == "Big Floppa" then
        local need = slot:FindFirstChild("Need")
        lastAmount = need and need.Value or 999
        if need then
            questConn = need:GetPropertyChangedSignal("Value"):Connect(function()
                local newValue = need.Value
                if not debounce and lastAmount == 1 and newValue == 999 then
                    debounce = true
                    reiniciarCiclo()
                    task.wait(0.5)
                    debounce = false
                end
                lastAmount = newValue
            end)
        else
            local watcher
            watcher = slot.ChildAdded:Connect(function(child)
                if child.Name == "Need" then
                    watcher:Disconnect()
                    iniciarMonitorQuest()
                end
            end)
        end
    else
        local amount = slot:FindFirstChild("Amount")
        lastAmount = amount and amount.Value or 0
        if amount then
            questConn = amount:GetPropertyChangedSignal("Value"):Connect(function()
                local newValue = amount.Value
                if monstroSelecionado == "Golden Floppa" then
                    if not debounce and lastAmount > 0 and newValue == 0 then
                        debounce = true
                        reiniciarCiclo()
                        task.wait(0.5)
                        debounce = false
                    end
                else
                    if not debounce and lastAmount > 0 and newValue == 0 then
                        debounce = true
                        reiniciarCiclo()
                        task.wait(0.5)
                        debounce = false
                    end
                end
                lastAmount = newValue
            end)
        else
            local watcher
            watcher = slot.ChildAdded:Connect(function(child)
                if child.Name == "Amount" then
                    watcher:Disconnect()
                    iniciarMonitorQuest()
                end
            end)
        end
    end
end

-- Auto-quest loop para Big Floppa
local function iniciarAutoQuestLoop()
    if autoQuestLoop then return end
    autoQuestLoop = task.spawn(function()
        while autofarmOn do
            if monstroSelecionado == "Big Floppa" and not gettingQuest then
                local questFolder = player:FindFirstChild("QuestFolder")
                local slot = questFolder and questFolder:FindFirstChild("QuestSlot1")
                if slot then
                    local need = slot:FindFirstChild("Need")
                    if need and need.Value == 999 then
                        pegarQuestBigFloppaComEspera(4)
                        task.wait(0.25)
                    end
                end
            end
            task.wait(0.5)
        end
        autoQuestLoop = nil
    end)
end

local function pararAutoQuestLoop()
    autofarmOn = false
end

--// Interface Rayfield
local Rayfield = loadstring(game:HttpGet('https://[Log in to view URL]'))()
local Window = Rayfield:CreateWindow({
   Name = "Autofarm Floppa",
   Icon = 0,
   LoadingTitle = "Carregando...",
   LoadingSubtitle = "Autofarm Script",
   ShowText = "Autofarm Floppa",
   Theme = "Default",
   ToggleUIKeybind = "K",
})

local MainTab = Window:CreateTab("Autofarm", 4483362458)

MainTab:CreateSlider({
   Name = "Velocidade",
   Range = {0, 300},
   Increment = 1,
   Suffix = "WalkSpeed",
   CurrentValue = 16,
   Flag = "SliderVelocidade",
   Callback = function(Value)
      if humanoid and humanoid.Parent then
          humanoid.WalkSpeed = Value
      end
   end,
})

-- Dropdown com callback que reinicia watchers filtrados
MainTab:CreateDropdown({
   Name = "Selecionar monstro",
   Options = {"Floppa","Golden Floppa","Big Floppa"},
   CurrentOption = {"Floppa"},
   MultipleOptions = false,
   Flag = "MonstroDropdown",
   Callback = function(Options)
      if Options and Options[1] then
          monstroSelecionado = Options[1]
          alvo = nil
          -- reinicia watchers para filtrar apenas o novo tipo
          refreshMonsterWatchers()
          -- se autofarm ativo, reinicia flutuar e monitor de quest para aplicar filtro imediatamente
          if Window.Flags and Window.Flags.ToggleAutofarm and Window.Flags.ToggleAutofarm.Value then
              pararFlutuar()
              task.wait(0.08)
              iniciarFlutuar()
              pararMonitorQuest()
              task.wait(0.08)
              iniciarMonitorQuest()
          end
      end
   end,
})

MainTab:CreateToggle({
   Name = "Autofarm",
   CurrentValue = false,
   Flag = "ToggleAutofarm",
   Callback = function(Value)
      if Value then
         autofarmOn = true

         local questFolder = player:FindFirstChild("QuestFolder")
         local slot = questFolder and questFolder:FindFirstChild("QuestSlot1")
         local amount = slot and slot:FindFirstChild("Amount")
         local need = slot and slot:FindFirstChild("Need")

         if monstroSelecionado == "Big Floppa" then
             if need and need.Value == 999 then
                 pegarQuestBigFloppaComEspera(4)
                 task.wait(0.2)
             end
         else
             if amount and amount.Value == 0 then
                 pararFlutuar()
                 pararAtaque()
                 task.wait(0.3)
                 tpPegarQuest()
                 task.wait(0.3)
             end
         end

         iniciarAtaque()
         iniciarFlutuar()
         iniciarMonitorQuest()
         iniciarAutoQuestLoop()
      else
         pararFlutuar()
         pararAtaque()
         pararMonitorQuest()
         pararAutoQuestLoop()
      end
   end,
})

Embed on website

To embed this project on your website, copy the following code and paste it into your website's HTML: