--[[ ПРЕДМЕТЫ (Script → ServerScriptService, имя "Items") Батарейки, записки, ключ, амулет + сундук в подвале. Модели кладутся в ReplicatedStorage.ItemModels — клиент берёт их для рук и иконок. ]] local ReplicatedStorage = game:GetService("ReplicatedStorage") local Players = game:GetService("Players") local TweenService = game:GetService("TweenService") local MAX_SLOTS = 5 local BY, L1, L2, L3 = -9.2, 1.4, 12, 22.6 local M = Enum.Material local CYL, BALL = Enum.PartType.Cylinder, Enum.PartType.Ball local GOLD = Color3.fromRGB(200, 160, 60) local BRASS = Color3.fromRGB(170, 130, 60) local remote = ReplicatedStorage:FindFirstChild("ItemRemote") or Instance.new("RemoteEvent") remote.Name = "ItemRemote" remote.Parent = ReplicatedStorage workspace:SetAttribute("MonstersGone", false) for _, n in ipairs({"ItemModels"}) do local o = ReplicatedStorage:FindFirstChild(n) if o then o:Destroy() end end local templates = Instance.new("Folder") templates.Name = "ItemModels" templates.Parent = ReplicatedStorage local oldF = workspace:FindFirstChild("Items") if oldF then oldF:Destroy() end local folder = Instance.new("Folder") folder.Name = "Items" folder.Parent = workspace ---------------------------------------------------------------- КОНСТРУКТОР МОДЕЛЕЙ -- деталь модели; cf — относительно центра модели; приваривается к Handle local function part(model, size, cf, color, mat, shape, props) local p = Instance.new(props and props.Class or "Part") if shape then p.Shape = shape end p.Size, p.CFrame, p.Color, p.Material = size, cf, color, mat or M.SmoothPlastic p.Anchored, p.CanCollide, p.Massless = true, false, true p.TopSurface, p.BottomSurface = Enum.SurfaceType.Smooth, Enum.SurfaceType.Smooth if props then for k, v in pairs(props) do if k ~= "Class" then p[k] = v end end end p.Parent = model local h = model.PrimaryPart if h and h ~= p then local w = Instance.new("WeldConstraint") w.Part0, w.Part1, w.Parent = h, p, p end return p end local function newModel(id, handleSize) local m = Instance.new("Model") m.Name = id local h = Instance.new("Part") h.Name, h.Size, h.Transparency, h.Anchored, h.CanCollide = "Handle", handleSize, 1, true, true h.CFrame = CFrame.new() h.Parent = m m.PrimaryPart = h m.Parent = templates return m end local UP = CFrame.Angles(0, 0, math.rad(90)) -- цилиндр стоймя -- БАТАРЕЙКА: чёрный корпус, золотой верх, этикетка, клемма, индикатор do local m = newModel("battery", Vector3.new(0.5, 1.25, 0.5)) part(m, Vector3.new(0.85, 0.48, 0.48), CFrame.new(0, -0.12, 0) * UP, Color3.fromRGB(25, 25, 28), M.SmoothPlastic, CYL) part(m, Vector3.new(0.3, 0.485, 0.485), CFrame.new(0, 0.42, 0) * UP, GOLD, M.Metal, CYL) part(m, Vector3.new(0.35, 0.495, 0.495), CFrame.new(0, -0.05, 0) * UP, Color3.fromRGB(220, 120, 30), M.SmoothPlastic, CYL) part(m, Vector3.new(0.08, 0.5, 0.5), CFrame.new(0, 0.15, 0) * UP, Color3.fromRGB(80, 200, 90), M.Neon, CYL, {Transparency = 0.3}) part(m, Vector3.new(0.1, 0.2, 0.2), CFrame.new(0, 0.6, 0) * UP, Color3.fromRGB(190, 190, 195), M.Metal, CYL) part(m, Vector3.new(0.04, 0.42, 0.42), CFrame.new(0, -0.56, 0) * UP, Color3.fromRGB(150, 150, 155), M.Metal, CYL) local l = Instance.new("PointLight") l.Color, l.Brightness, l.Range, l.Parent = Color3.fromRGB(90, 255, 110), 0.4, 3, m.PrimaryPart end -- ЗАПИСКА: мятая бумага, строчки, загнутый уголок, кровавый отпечаток do local m = newModel("note", Vector3.new(1.4, 0.06, 1.8)) local paper = part(m, Vector3.new(1.4, 0.04, 1.8), CFrame.Angles(0, 0, math.rad(1.5)), Color3.fromRGB(225, 215, 185), M.SmoothPlastic) local gui = Instance.new("SurfaceGui") gui.Face, gui.CanvasSize, gui.LightInfluence, gui.Parent = Enum.NormalId.Top, Vector2.new(140, 180), 1, paper for i = 1, 9 do local line = Instance.new("Frame") line.BorderSizePixel, line.BackgroundColor3 = 0, Color3.fromRGB(40, 35, 60) line.Size = UDim2.fromOffset(math.random(60, 110), 2) line.Position = UDim2.fromOffset(14, 14 + i * 16) line.Rotation = math.random(-3, 3) line.Parent = gui end part(m, Vector3.new(0.04, 0.3, 0.3), CFrame.new(0.55, 0.03, 0.75) * CFrame.Angles(0, math.rad(-45), math.rad(90)), Color3.fromRGB(200, 190, 160), M.SmoothPlastic, nil, {Class = "WedgePart"}) part(m, Vector3.new(0.02, 0.38, 0.32), CFrame.new(-0.35, 0.03, -0.5) * CFrame.Angles(0, 0.4, math.rad(90)), Color3.fromRGB(110, 10, 10), M.SmoothPlastic, CYL, {Transparency = 0.15}) part(m, Vector3.new(0.02, 0.12, 0.12), CFrame.new(-0.1, 0.03, -0.25) * CFrame.Angles(0, 0, math.rad(90)), Color3.fromRGB(110, 10, 10), M.SmoothPlastic, CYL) part(m, Vector3.new(1.3, 0.045, 0.03), CFrame.new(0, 0.005, 0.1), Color3.fromRGB(200, 190, 160), M.SmoothPlastic) -- сгиб end -- КЛЮЧ: кольцо, стержень, бородка, бирка do local m = newModel("key", Vector3.new(0.6, 0.15, 1.7)) for i = 0, 9 do local a = i / 10 * math.pi * 2 part(m, Vector3.new(0.09, 0.09, 0.17), CFrame.new(math.cos(a) * 0.24, 0, 0.55 + math.sin(a) * 0.24) * CFrame.Angles(0, -a, 0), BRASS, M.Metal) end part(m, Vector3.new(1.0, 0.09, 0.09), CFrame.new(0, 0, -0.15) * CFrame.Angles(0, math.rad(90), 0), BRASS, M.Metal, CYL) part(m, Vector3.new(0.18, 0.18, 0.18), CFrame.new(0, 0, 0.3), BRASS, M.Metal, BALL) part(m, Vector3.new(0.28, 0.06, 0.12), CFrame.new(0.12, 0, -0.55), BRASS, M.Metal) part(m, Vector3.new(0.2, 0.06, 0.1), CFrame.new(0.1, 0, -0.38), BRASS, M.Metal) part(m, Vector3.new(0.3, 0.03, 0.4), CFrame.new(-0.25, 0, 0.95) * CFrame.Angles(0, 0.5, 0), Color3.fromRGB(150, 30, 25), M.Fabric) end -- АМУЛЕТ: золотая оправа, светящийся камень, цепочка do local m = newModel("amulet", Vector3.new(0.9, 0.25, 1.6)) part(m, Vector3.new(0.1, 0.6, 0.6), CFrame.new(0, -0.04, 0) * UP, GOLD, M.Metal, CYL) for i = 0, 11 do local a = i / 12 * math.pi * 2 part(m, Vector3.new(0.12, 0.12, 0.14), CFrame.new(math.cos(a) * 0.33, 0.02, math.sin(a) * 0.33) * CFrame.Angles(0, -a, 0), GOLD, M.Metal) end local gem = part(m, Vector3.new(0.36, 0.36, 0.36), CFrame.new(0, 0.06, 0), Color3.fromRGB(230, 20, 40), M.Neon, BALL) for i = 1, 9 do part(m, Vector3.new(0.07, 0.07, 0.07), CFrame.new(math.sin(i * 0.7) * 0.12, 0, -0.38 - i * 0.09), GOLD, M.Metal, BALL) end local l = Instance.new("PointLight") l.Color, l.Brightness, l.Range, l.Parent = Color3.fromRGB(255, 40, 60), 1.2, 7, gem end ---------------------------------------------------------------- ДАННЫЕ local ITEMS = { battery = "Батарейка", note = "Записка", key = "Ключ", amulet = "Амулет", } local NOTES = { "Они пришли, когда мы открыли подвал. Высокий бродит по комнатам. Пока ты СМОТРИШЬ на него — он не может двинуться. Не отводи взгляд.", "Тот, что внизу, ползает в темноте. Он боится света. Свети ему в лицо фонариком — и он замрёт. Береги батарейки.", "Ключ от сундука я спрятал на чердаке. В сундуке, в подвале, лежит амулет. Только он прогонит их.", "Если ты это читаешь — беги. Когда он тебя схватит, он берёт тебя в руки... Я слышал, как это было с Томом.", } local function makeData(id, text) return {id = id, name = ITEMS[id], text = text} end local inventories = {} local function send(player) remote:FireClient(player, "inv", inventories[player] or {}) end local function msg(player, text) remote:FireClient(player, "msg", text) end Players.PlayerAdded:Connect(function(p) inventories[p] = {} end) Players.PlayerRemoving:Connect(function(p) inventories[p] = nil end) for _, p in ipairs(Players:GetPlayers()) do inventories[p] = {} end local function spawnItem(data, cf, anchored) local m = templates[data.id]:Clone() m:PivotTo(cf) for _, p in ipairs(m:GetDescendants()) do if p:IsA("BasePart") then p.Anchored = anchored and true or false end end m.Parent = folder local prompt = Instance.new("ProximityPrompt") prompt.ActionText, prompt.ObjectText = "Подобрать", data.name prompt.MaxActivationDistance, prompt.RequiresLineOfSight = 7, false prompt.Parent = m.PrimaryPart prompt.Triggered:Connect(function(player) local inv = inventories[player] if not inv or not m.Parent then return end if #inv >= MAX_SLOTS then msg(player, "Карманы полны. Выбрось что-нибудь (G)"); return end m:Destroy() table.insert(inv, data) send(player) if data.id == "amulet" then workspace:SetAttribute("MonstersGone", true) remote:FireClient(player, "win") end end) return m end remote.OnServerEvent:Connect(function(player, action, slot) local inv = inventories[player] if not inv then return end if action == "sync" then send(player); return end if typeof(slot) ~= "number" or not inv[slot] then return end local item = inv[slot] if action == "use" and item.id == "battery" then table.remove(inv, slot) send(player) remote:FireClient(player, "battery") elseif action == "drop" then local hrp = player.Character and player.Character:FindFirstChild("HumanoidRootPart") if not hrp then return end table.remove(inv, slot) send(player) local params = RaycastParams.new() params.FilterDescendantsInstances = {player.Character} local look = hrp.CFrame.LookVector local hit = workspace:Raycast(hrp.Position, look * 2.5, params) local pos = hit and (hit.Position - look * 0.6) or (hrp.Position + look * 2.5) spawnItem(item, CFrame.new(pos) * CFrame.Angles(0, math.random() * 6.28, 0), false) end end) ---------------------------------------------------------------- РАССТАНОВКА local function at(x, y, z, yaw) return CFrame.new(x, y, z) * CFrame.Angles(0, math.rad(yaw or math.random(0, 360)), 0) end spawnItem(makeData("battery"), at(-7, L1 + 2.2, -8), true) -- столик в гостиной spawnItem(makeData("battery"), at(9, BY + 3.8, -6), true) -- стол в подвале spawnItem(makeData("battery"), at(8, L2 + 3.8, -13), true) -- письменный стол spawnItem(makeData("battery"), at(4, L3 + 0.65, 2), true) -- чердак spawnItem(makeData("note", NOTES[1]), at(4, L1 + 3.25, -6), true) spawnItem(makeData("note", NOTES[2]), at(11, BY + 3.25, -5.5), true) spawnItem(makeData("note", NOTES[3]), at(-9, L2 + 2.65, -10), true) spawnItem(makeData("note", NOTES[4]), at(-6, L3 + 0.05, -13), true) spawnItem(makeData("key"), at(13, L3 + 0.1, -13.5), true) ---------------------------------------------------------------- СУНДУК В ПОДВАЛЕ local chestModel = Instance.new("Model") chestModel.Name = "Chest" chestModel.Parent = folder local chestCF = CFrame.new(-3, BY, 12.5) -- перёд смотрит на -Z local WOOD, IRON = Color3.fromRGB(80, 50, 30), Color3.fromRGB(45, 45, 48) local function cpart(size, cf, color, mat) local p = Instance.new("Part") p.Size, p.CFrame, p.Color, p.Material, p.Anchored = size, chestCF * cf, color, mat, true p.Parent = chestModel return p end cpart(Vector3.new(3, 0.2, 2), CFrame.new(0, 0.1, 0), WOOD, M.WoodPlanks) local front = cpart(Vector3.new(3, 1.4, 0.15), CFrame.new(0, 0.7, -0.93), WOOD, M.WoodPlanks) cpart(Vector3.new(3, 1.4, 0.15), CFrame.new(0, 0.7, 0.93), WOOD, M.WoodPlanks) cpart(Vector3.new(0.15, 1.4, 2), CFrame.new(-1.43, 0.7, 0), WOOD, M.WoodPlanks) cpart(Vector3.new(0.15, 1.4, 2), CFrame.new(1.43, 0.7, 0), WOOD, M.WoodPlanks) for _, x in ipairs({-1, 1}) do cpart(Vector3.new(0.2, 1.42, 2.05), CFrame.new(x, 0.7, 0), IRON, M.Metal) end cpart(Vector3.new(0.4, 0.5, 0.15), CFrame.new(0, 1.05, -1.02), BRASS, M.Metal).Name = "Lock" local hinge = chestCF * CFrame.new(0, 1.4, 0.95) local lid = Instance.new("Part") lid.Size, lid.Color, lid.Material, lid.Anchored = Vector3.new(3.05, 0.3, 2), WOOD, M.WoodPlanks, true lid.CFrame = hinge * CFrame.new(0, 0.15, -1) lid.Parent = chestModel for _, x in ipairs({-1, 1}) do local b = Instance.new("Part") b.Size, b.Color, b.Material, b.CanCollide, b.Massless = Vector3.new(0.2, 0.34, 2.05), IRON, M.Metal, false, true b.CFrame = lid.CFrame * CFrame.new(x, 0, 0) b.Parent = chestModel local w = Instance.new("WeldConstraint") w.Part0, w.Part1, w.Parent = lid, b, b end local prompt = Instance.new("ProximityPrompt") prompt.ActionText, prompt.ObjectText = "Открыть", "Сундук" prompt.MaxActivationDistance, prompt.RequiresLineOfSight = 7, false prompt.Parent = front local opened = false prompt.Triggered:Connect(function(player) if opened then return end local inv = inventories[player] local keySlot for i, it in ipairs(inv or {}) do if it.id == "key" then keySlot = i end end if not keySlot then msg(player, "Заперто. Нужен ключ."); return end opened = true prompt.Enabled = false table.remove(inv, keySlot) send(player) msg(player, "Ключ подошёл…") TweenService:Create(lid, TweenInfo.new(1.2, Enum.EasingStyle.Back, Enum.EasingDirection.Out), {CFrame = hinge * CFrame.Angles(math.rad(100), 0, 0) * CFrame.new(0, 0.15, -1)}):Play() task.wait(0.6) spawnItem(makeData("amulet"), chestCF * CFrame.new(0, 0.35, 0), true) end)