--[[ МОНСТРЫ (Script → ServerScriptService, имя "Monsters") Наблюдатель ходит по 1–3 этажу и не может двигаться, пока ты на него СМОТРИШЬ. Ползун сидит в подвале и замирает, когда на него СВЕТИТ фонарик. Поймает: берёт в руки, поднимает, отрывает голову, тело падает. ]] local Players = game:GetService("Players") local RunService = game:GetService("RunService") local PathfindingService = game:GetService("PathfindingService") local ReplicatedStorage = game:GetService("ReplicatedStorage") local TweenService = game:GetService("TweenService") local Debris = game:GetService("Debris") local remote = ReplicatedStorage:FindFirstChild("ItemRemote") or Instance.new("RemoteEvent") remote.Name = "ItemRemote" remote.Parent = ReplicatedStorage local BY, L1, L2 = -9.2, 1.4, 12 local CATCH_DIST = 3.6 local SIGHT_MEMORY = 0.35 -- сколько секунд действует «на меня смотрят/светят» local M = Enum.Material local BALL = Enum.PartType.Ball local rng = Random.new() local sin, cos, abs, max, min, clamp = math.sin, math.cos, math.abs, math.max, math.min, math.clamp local oldF = workspace:FindFirstChild("Monsters") if oldF then oldF:Destroy() end local folder = Instance.new("Folder") folder.Name = "Monsters" folder.Parent = workspace local DEFS = { Watcher = { -- высокий, бледный, длинные руки speed = 13, freq = 1.5, home = Vector3.new(8, L2, 6), agentH = 5, skin = Color3.fromRGB(200, 195, 185), dark = Color3.fromRGB(55, 45, 45), eye = Color3.fromRGB(255, 20, 20), tL = 2.3, sL = 2.3, legW = 0.5, torsoL = 2.8, torsoW = 1.6, torsoD = 0.8, shW = 1.0, neckL = 0.7, head = Vector3.new(1, 1.35, 1.1), uL = 2.5, fL = 2.4, armW = 0.36, lean = 0.12, knee = 0.15, walkLean = 0.15, armSwing = 0.35, grabLean = 0.25, holdDist = 3.1, lift = 2.2, }, Crawler = { -- сгорбленный, тёмный, ходит на четвереньках speed = 11, freq = 2.4, home = Vector3.new(-6, BY, 6), agentH = 4.5, skin = Color3.fromRGB(45, 40, 38), dark = Color3.fromRGB(18, 15, 15), eye = Color3.fromRGB(220, 255, 80), tL = 1.4, sL = 1.5, legW = 0.6, torsoL = 2.8, torsoW = 1.5, torsoD = 1.1, shW = 0.9, neckL = 0.6, head = Vector3.new(1.1, 1, 1.3), uL = 2.0, fL = 2.1, armW = 0.42, lean = 1.15, knee = 0.9, walkLean = 0.05, armSwing = 0.5, grabLean = 0.3, holdDist = 2.4, lift = 1.2, }, } local WANDER = { Watcher = { Vector3.new(-8, L1, -6), Vector3.new(6, L1, -9), Vector3.new(8, L1, 5), Vector3.new(-6, L1, 8), Vector3.new(-8, L2, 0), Vector3.new(6, L2, -8), Vector3.new(6, L2, 8), Vector3.new(-6, L2, 6), Vector3.new(0, 22.6, 0), Vector3.new(8, 22.6, 2), Vector3.new(-8, 22.6, -4), }, Crawler = { Vector3.new(-6, BY, 6), Vector3.new(6, BY, -2), Vector3.new(-10, BY, -6), Vector3.new(0, BY, 6), Vector3.new(12, BY, 2), }, } ---------------------------------------------------------------- МОДЕЛЬ local function build(name, d) local model = Instance.new("Model") model.Name = name local rig = {} local function add(joint, size, offset, color, mat, shape) local p = Instance.new("Part") p.Size, p.Color, p.Material = size, color or d.skin, mat or M.SmoothPlastic if shape then p.Shape = shape end p.Anchored, p.CanCollide, p.CanTouch = true, false, false p.TopSurface, p.BottomSurface = Enum.SurfaceType.Smooth, Enum.SurfaceType.Smooth p.Parent = model table.insert(rig, {p, joint, offset}) return p end local k, h = d.dark, d.head add("pelvis", Vector3.new(d.torsoW * 0.9, 0.6, d.torsoD), CFrame.new(), k, M.Fabric) local torso = add("torso", Vector3.new(d.torsoW, d.torsoL, d.torsoD), CFrame.new(0, d.torsoL / 2, 0)) torso.Name = "Torso" for i = 1, 5 do add("torso", Vector3.new(0.28, 0.28, 0.28), CFrame.new(0, i * d.torsoL / 6, d.torsoD / 2), k, nil, BALL) end for i = 1, 3 do add("torso", Vector3.new(d.torsoW * 0.8, 0.12, 0.12), CFrame.new(0, d.torsoL * (0.4 + i * 0.13), -d.torsoD / 2), k) end add("neck", Vector3.new(0.35, d.neckL + 0.3, 0.35), CFrame.new(0, d.neckL / 2, 0)) local head = add("head", h, CFrame.new(0, h.Y / 2, 0)) head.Name = "Head" add("head", Vector3.new(h.X * 1.02, 0.18, 0.25), CFrame.new(0, h.Y * 0.7, -h.Z / 2 + 0.05), k) for _, sx in ipairs({-1, 1}) do add("head", Vector3.new(0.34, 0.3, 0.1), CFrame.new(sx * h.X * 0.24, h.Y * 0.56, -h.Z / 2 - 0.01), Color3.new(0, 0, 0)) add("head", Vector3.new(0.16, 0.16, 0.16), CFrame.new(sx * h.X * 0.24, h.Y * 0.56, -h.Z / 2 - 0.06), d.eye, M.Neon, BALL) end add("head", Vector3.new(h.X * 0.7, 0.14, 0.1), CFrame.new(0, h.Y * 0.2, -h.Z / 2 - 0.01), Color3.fromRGB(40, 0, 0)) add("jaw", Vector3.new(h.X * 0.85, 0.3, h.Z * 0.75), CFrame.new(0, -0.15, -h.Z * 0.3)) for i = -2, 2 do add("jaw", Vector3.new(0.08, 0.22, 0.08), CFrame.new(i * 0.13, 0.1, -h.Z * 0.64), Color3.fromRGB(230, 225, 200)) end for _, s in ipairs({"L", "R"}) do add("sh" .. s, Vector3.new(d.armW, d.uL, d.armW), CFrame.new(0, -d.uL / 2, 0)) add("el" .. s, Vector3.new(d.armW, d.armW, d.armW) * 1.25, CFrame.new(), nil, nil, BALL) add("el" .. s, Vector3.new(d.armW * 0.85, d.fL, d.armW * 0.85), CFrame.new(0, -d.fL / 2, 0)) local hand = add("hand" .. s, Vector3.new(d.armW * 1.5, 0.45, 0.25), CFrame.new(0, -0.2, 0)) hand.Name = "Hand" .. s for f = -1, 1 do add("hand" .. s, Vector3.new(0.08, 0.9, 0.08), CFrame.new(f * 0.17, -0.75, -0.05) * CFrame.Angles(0.25, 0, f * 0.12), k) end add("hip" .. s, Vector3.new(d.legW, d.tL, d.legW), CFrame.new(0, -d.tL / 2, 0), k, M.Fabric) add("kn" .. s, Vector3.new(d.legW * 0.8, d.sL, d.legW * 0.8), CFrame.new(0, -d.sL / 2, 0)) add("ft" .. s, Vector3.new(d.legW * 1.1, 0.3, 1.1), CFrame.new(0, -0.15, -0.3)) end local light = Instance.new("PointLight") light.Color, light.Brightness, light.Range = d.eye, 1.2, 7 light.Parent = head model.PrimaryPart = torso model.Parent = folder return model, rig end ---------------------------------------------------------------- АНИМАЦИЯ (кости считаются вручную) local function joints(m) local d, c = m.def, m.cur local hipH = (d.tL + d.sL) * cos(d.knee / 2) + 0.3 local root = CFrame.new(m.pos) * CFrame.Angles(0, m.yaw, 0) local J = {} J.pelvis = root * CFrame.new(0, hipH + c.hipY, 0) * CFrame.Angles(0, c.twist * 0.4, 0) J.torso = J.pelvis * CFrame.new(0, 0.2, 0) * CFrame.Angles(-c.lean, c.twist, c.sway) local top = J.torso * CFrame.new(0, d.torsoL, 0) J.neck = top * CFrame.Angles(c.lean * 0.8 + c.headP * 0.4, c.headY * 0.3, 0) J.head = J.neck * CFrame.new(0, d.neckL, 0) * CFrame.Angles(c.lean * 0.2 + c.headP * 0.6, c.headY * 0.7, c.headR) J.jaw = J.head * CFrame.new(0, d.head.Y * 0.22, -d.head.Z * 0.15) * CFrame.Angles(-c.jaw, 0, 0) for _, s in ipairs({"L", "R"}) do local sx = s == "L" and -1 or 1 J["sh" .. s] = top * CFrame.new(sx * d.shW, -0.25, 0) * CFrame.Angles(c.lean + c[s .. "armP"], 0, sx * c[s .. "armO"]) J["el" .. s] = J["sh" .. s] * CFrame.new(0, -d.uL, 0) * CFrame.Angles(c[s .. "elb"], 0, 0) J["hand" .. s] = J["el" .. s] * CFrame.new(0, -d.fL, 0) * CFrame.Angles(c[s .. "elb"] * 0.4, c[s .. "wrist"], 0) local legP, knee = c[s .. "leg"], c[s .. "knee"] J["hip" .. s] = J.pelvis * CFrame.new(sx * d.torsoW * 0.3, 0, 0) * CFrame.Angles(legP, 0, sx * 0.05) J["kn" .. s] = J["hip" .. s] * CFrame.new(0, -d.tL, 0) * CFrame.Angles(-knee, 0, 0) J["ft" .. s] = J["kn" .. s] * CFrame.new(0, -d.sL, 0) * CFrame.Angles(knee - legP, 0, 0) end return J end local function apply(m) local J = joints(m) local parts, cfs = m.parts, m.cfs for i, r in ipairs(m.rig) do cfs[i] = J[r[2]] * r[3] end workspace:BulkMoveTo(parts, cfs, Enum.BulkMoveMode.FireCFrameChanged) m.J = J end -- целевая поза: idle/ходьба/хватание; плавно смешивается с текущей local function animate(m, dt, t, moving) local d, g = m.def, {} local crawler = m.name == "Crawler" m.walk += ((moving and 1 or 0) - m.walk) * min(1, dt * 6) local w = m.walk if moving then m.phase += dt * d.freq * math.pi * 2 * (m.hunting and 1 or 0.6) end local ph = m.phase local breath = sin(t * 1.8) if t > m.nextTwitch then -- резкие подёргивания головой m.nextTwitch = t + rng:NextNumber(crawler and 0.3 or 1.5, crawler and 1.4 or 4) m.twitch = Vector3.new(rng:NextNumber(-0.5, 0.5), rng:NextNumber(-0.9, 0.9), rng:NextNumber(-0.6, 0.6)) end m.twitch *= 0.93 g.lean = d.lean + d.walkLean * w + breath * 0.02 g.twist = sin(ph) * 0.15 * w g.sway = sin(t * 1.1) * 0.04 + sin(ph) * 0.05 * w g.hipY = (abs(cos(ph)) - 1) * 0.18 * w + breath * 0.04 g.headP = m.twitch.X + (crawler and 0.15 or -0.1) g.headY = sin(t * 0.45) * 0.7 * (1 - w) + m.twitch.Y g.headR = sin(t * 0.37) * 0.35 + m.twitch.Z + sin(ph * 2) * 0.08 * w g.jaw = crawler and (0.2 + abs(sin(t * 9)) * 0.25) or (0.08 + max(0, breath) * 0.12 + 0.2 * w) local swing = sin(ph) * d.armSwing * w for _, s in ipairs({"L", "R"}) do local sgn = s == "L" and 1 or -1 g[s .. "armP"] = -swing * sgn + sin(t * 0.9 + sgn) * 0.05 g[s .. "armO"] = crawler and 0.22 or 0.1 + breath * 0.02 g[s .. "elb"] = crawler and 0.35 + max(0, swing * sgn) * 0.6 or 0.25 + max(0, -swing * sgn) * 0.5 g[s .. "wrist"] = sin(t * 2 + sgn) * 0.2 g[s .. "leg"] = d.knee / 2 + sin(ph) * 0.55 * w * sgn g[s .. "knee"] = d.knee + max(0, cos(ph) * sgn) * 0.9 * w end if m.grabT then -- ХВАТАНИЕ local gt = m.grabT local lift = clamp((gt - 0.5) / 1.1, 0, 1) local shake = (gt > 0.5 and gt < 2.2) and rng:NextNumber(-0.08, 0.08) or 0 g.lean, g.twist, g.sway = d.grabLean, shake, shake g.hipY = crawler and 0.6 or 0 g.headP, g.headY = gt > 2.2 and 0.45 or -0.15, gt > 2.2 and 0.35 or 0 g.headR = 0.3 + shake * 2 g.jaw = gt > 2.2 and 0.95 or 0.35 + abs(sin(gt * 18)) * 0.25 for _, s in ipairs({"L", "R"}) do g[s .. "armP"] = 1.2 + lift * 0.35 + shake g[s .. "armO"] = -0.18 g[s .. "elb"] = 0.7 - lift * 0.2 g[s .. "wrist"] = 0 g[s .. "leg"], g[s .. "knee"] = d.knee / 2 + 0.1, d.knee + 0.1 end if gt > 1.6 and gt < 2.2 then g.Rwrist = (gt - 1.6) * 4; g.RarmP = 1.7 end if gt >= 2.2 then g.RarmP, g.RarmO, g.Relb = 2.7, 0.45, 0.15 end -- поднимает голову трофеем if gt >= 2.9 then g.LarmP, g.Lelb = 0.4, 0.5 end end local k = min(1, dt * (m.grabT and 12 or 8)) for key, v in pairs(g) do local cur = m.cur[key] or v m.cur[key] = cur + (v - cur) * k end apply(m) end ---------------------------------------------------------------- МОНСТРЫ local monsters = {} local function spawnMonster(name) local d = DEFS[name] local model, rig = build(name, d) local m = { name = name, def = d, model = model, rig = rig, parts = {}, cfs = {}, cur = {}, pos = d.home, yaw = rng:NextNumber(0, 6.28), walk = 0, phase = 0, nextTwitch = 0, twitch = Vector3.zero, lookedAt = 0, litAt = 0, alive = true, path = PathfindingService:CreatePath({AgentRadius = 1.6, AgentHeight = d.agentH, AgentCanJump = false, WaypointSpacing = 3}), } for i, r in ipairs(rig) do m.parts[i] = r[1] end animate(m, 1, 0, false) table.insert(monsters, m) return m end spawnMonster("Watcher") spawnMonster("Crawler") local function frozen(m) local now = os.clock() if m.name == "Watcher" then return now - m.lookedAt < SIGHT_MEMORY end return now - m.litAt < SIGHT_MEMORY end -- клиент каждые 0.15 с сообщает: на кого смотрю, на кого свечу remote.OnServerEvent:Connect(function(_, action, looking, lit) if action ~= "sight" then return end local now = os.clock() for _, m in ipairs(monsters) do if type(looking) == "table" and table.find(looking, m.name) then m.lookedAt = now end if type(lit) == "table" and table.find(lit, m.name) then m.litAt = now end end end) local caught = {} local function aliveHRP(p) local char = p.Character local hum = char and char:FindFirstChildOfClass("Humanoid") local hrp = char and char:FindFirstChild("HumanoidRootPart") if hum and hrp and hum.Health > 0 and not caught[p] then return hrp, hum end return nil end local function findTarget(m) local best, bestD for _, p in ipairs(Players:GetPlayers()) do local hrp = aliveHRP(p) if hrp then local pos = hrp.Position local inHouse = abs(pos.X) < 20.5 and abs(pos.Z) < 15.5 local ok = inHouse and ((m.name == "Watcher" and pos.Y > L1 + 1) or (m.name == "Crawler" and pos.Y < L1 + 1)) local dist = (pos - m.pos).Magnitude if ok and (not bestD or dist < bestD) then best, bestD = p, dist end end end return best end ---------------------------------------------------------------- ПОИМКА local function blood(parent, rate, life) local pe = Instance.new("ParticleEmitter") pe.Color = ColorSequence.new(Color3.fromRGB(150, 0, 0), Color3.fromRGB(60, 0, 0)) pe.Size = NumberSequence.new(0.3, 0.05) pe.Lifetime = NumberRange.new(0.5, 1) pe.Speed = NumberRange.new(4, 10) pe.SpreadAngle = Vector2.new(35, 35) pe.Acceleration = Vector3.new(0, -45, 0) pe.Rate = rate pe.Parent = parent Debris:AddItem(pe, life) return pe end local function catch(m, player) local hrp, hum = aliveHRP(player) if not hrp then return end local char = player.Character local head = char:FindFirstChild("Head") local neck for _, j in ipairs(char:GetDescendants()) do if j:IsA("Motor6D") and j.Name == "Neck" then neck = j end end caught[player], m.busy, m.wps = true, true, nil hum.RequiresNeck = false hrp.Anchored = true local flat = Vector3.new(hrp.Position.X - m.pos.X, 0, hrp.Position.Z - m.pos.Z) if flat.Magnitude > 0.1 then m.yaw = math.atan2(-flat.X, -flat.Z) end local fwd = CFrame.Angles(0, m.yaw, 0).LookVector local rest = hum.RigType == Enum.HumanoidRigType.R15 and hum.HipHeight + hrp.Size.Y / 2 or 3 local base = m.pos + fwd * m.def.holdDist local neckC0 = neck and neck.C0 remote:FireClient(player, "caught", m.model) m.grabT = 0 local ripped, dropped = false, false local t0 = os.clock() while true do local dt = RunService.Heartbeat:Wait() local gt = os.clock() - t0 m.grabT = gt animate(m, dt, os.clock(), false) local lift = clamp((gt - 0.5) / 1.1, 0, 1) * m.def.lift local shake = (gt > 0.5 and gt < 2.2) and Vector3.new(rng:NextNumber(-1, 1), rng:NextNumber(-1, 1), 0) * 0.12 or Vector3.zero if hrp.Anchored then local p = base + Vector3.new(0, rest + lift, 0) + shake local look = m.J.head.Position hrp.CFrame = CFrame.lookAt(p, Vector3.new(look.X, p.Y, look.Z)) end if neck and neck.Parent and gt > 1.6 then -- выкручивает голову neck.C0 = neckC0 * CFrame.Angles(0, (gt - 1.6) / 0.6 * 2.2, 0) end if gt >= 2.2 and not ripped and head then -- ОТРЫВАЕТ ripped = true if neck then neck:Destroy() end head.Anchored, head.CanCollide = true, false local torso = char:FindFirstChild("UpperTorso") or char:FindFirstChild("Torso") if torso then blood(torso, 250, 1.6) end blood(head, 60, 4) remote:FireClient(player, "rip") end if ripped and not dropped and head then local hand = m.J.handR.Position head.CFrame = CFrame.lookAt(hand - Vector3.new(0, 0.6, 0), m.J.head.Position) end if gt >= 2.9 and hrp.Anchored then -- тело падает на пол hrp.Anchored = false hrp.AssemblyLinearVelocity = fwd * 6 hum.Health = 0 local pool = Instance.new("Part") pool.Shape, pool.Anchored, pool.CanCollide = Enum.PartType.Cylinder, true, false pool.Color, pool.Material = Color3.fromRGB(70, 0, 0), M.Glass pool.Size = Vector3.new(0.05, 0.5, 0.5) pool.CFrame = CFrame.new(base + fwd * 1.5 + Vector3.new(0, 0.03, 0)) * CFrame.Angles(0, 0, math.rad(90)) pool.Parent = workspace TweenService:Create(pool, TweenInfo.new(4), {Size = Vector3.new(0.05, 6, 6)}):Play() Debris:AddItem(pool, 60) end if gt >= 3.6 and not dropped and head then -- бросает голову dropped = true head.Anchored, head.CanCollide = false, true head.AssemblyLinearVelocity = fwd * 4 + Vector3.new(0, 5, 0) head.AssemblyAngularVelocity = Vector3.new(rng:NextNumber(-6, 6), 0, rng:NextNumber(-6, 6)) end if gt >= 4.6 then break end end m.grabT, m.busy = nil, false end Players.PlayerAdded:Connect(function(p) p.CharacterAdded:Connect(function() caught[p] = nil end) end) for _, p in ipairs(Players:GetPlayers()) do p.CharacterAdded:Connect(function() caught[p] = nil end) end Players.PlayerRemoving:Connect(function(p) caught[p] = nil end) ---------------------------------------------------------------- МОЗГ (путь) И ДВИЖЕНИЕ local function computePath(m, goal) local ok = pcall(function() m.path:ComputeAsync(m.pos + Vector3.new(0, 1, 0), goal) end) if ok and m.path.Status == Enum.PathStatus.Success then m.wps, m.wi = m.path:GetWaypoints(), 2 return true end m.wps = nil return false end for _, m in ipairs(monsters) do task.spawn(function() while m.alive do local delay = 0.35 if not m.busy then local target = findTarget(m) m.target, m.hunting = target, target ~= nil if target then local hrp = aliveHRP(target) if hrp then computePath(m, hrp.Position - Vector3.new(0, 2.5, 0)) end elseif not m.wps or m.wi > #m.wps then local list = WANDER[m.name] computePath(m, list[rng:NextInteger(1, #list)]) delay = rng:NextNumber(1.5, 4) -- постоять перед новым маршрутом end end task.wait(delay) end end) end local function stepMonster(m, dt, t) if m.busy or not m.alive then return end if frozen(m) then return end -- статуя: ни шага, ни движения local speed = m.def.speed * (m.hunting and 1 or 0.45) local moveTo if m.wps and m.wi <= #m.wps then local wp = m.wps[m.wi].Position if (wp - m.pos).Magnitude < 0.7 then m.wi += 1 else moveTo = wp end end local hrp = m.target and aliveHRP(m.target) if hrp then local feet = hrp.Position - Vector3.new(0, 2.6, 0) local flat = Vector3.new(feet.X - m.pos.X, 0, feet.Z - m.pos.Z) local dy = abs(feet.Y - m.pos.Y) if dy < 3 and flat.Magnitude < 7 then moveTo = Vector3.new(feet.X, m.pos.Y, feet.Z) end if dy < 4.5 and flat.Magnitude < CATCH_DIST then task.spawn(catch, m, m.target) return end end local moving = false if moveTo then local delta = moveTo - m.pos if delta.Magnitude > 0.05 then m.pos += delta.Unit * min(delta.Magnitude, speed * dt) moving = true if Vector3.new(delta.X, 0, delta.Z).Magnitude > 0.1 then local want = math.atan2(-delta.X, -delta.Z) local diff = (want - m.yaw + math.pi) % (math.pi * 2) - math.pi m.yaw += diff * min(1, dt * 8) end end end animate(m, dt, t, moving) end RunService.Heartbeat:Connect(function(dt) local t = os.clock() for _, m in ipairs(monsters) do stepMonster(m, dt, t) end end) ---------------------------------------------------------------- АМУЛЕТ ПРОГОНЯЕТ ИХ workspace:GetAttributeChangedSignal("MonstersGone"):Connect(function() if not workspace:GetAttribute("MonstersGone") then return end for _, m in ipairs(monsters) do m.alive = false for _, p in ipairs(m.parts) do TweenService:Create(p, TweenInfo.new(2.5), {Transparency = 1, CFrame = p.CFrame * CFrame.new(0, -3, 0)}):Play() end Debris:AddItem(m.model, 3) end end)