Загрузка данных


-- BillCipherAI (Script в ServerScriptService)
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")

-- ═══════════════════════════════════════════
-- СОЗДАЁМ БИЛЛА ШИФРА
-- ═══════════════════════════════════════════

local function createBill()
    local bill = Instance.new("Model")
    bill.Name = "BillCipher"

    -- Основное тело — жёлтый треугольник (симулируем через клин)
    local body = Instance.new("WedgePart")
    body.Name = "Body"
    body.Size = Vector3.new(2, 3, 0.3)
    body.BrickColor = BrickColor.new("Bright yellow")
    body.Material = Enum.Material.Neon
    body.Anchored = false
    body.CanCollide = false
    body.CastShadow = true
    body.Parent = bill

    -- Глаз (белый с чёрным зрачком)
    local eye = Instance.new("SpherePartOperation") -- если нет CSG, используем шар
    -- Fallback: обычный Part
    local eyeWhite = Instance.new("Part")
    eyeWhite.Name = "EyeWhite"
    eyeWhite.Shape = Enum.PartType.Ball
    eyeWhite.Size = Vector3.new(0.7, 0.7, 0.3)
    eyeWhite.BrickColor = BrickColor.new("White")
    eyeWhite.Material = Enum.Material.SmoothPlastic
    eyeWhite.CanCollide = false
    eyeWhite.Anchored = false
    eyeWhite.Parent = bill

    local pupil = Instance.new("Part")
    pupil.Name = "Pupil"
    pupil.Shape = Enum.PartType.Ball
    pupil.Size = Vector3.new(0.35, 0.35, 0.3)
    pupil.BrickColor = BrickColor.new("Black")
    pupil.Material = Enum.Material.SmoothPlastic
    pupil.CanCollide = false
    pupil.Anchored = false
    pupil.Parent = bill

    -- Цилиндр (шляпа)
    local hat = Instance.new("Part")
    hat.Name = "Hat"
    hat.Shape = Enum.PartType.Cylinder
    hat.Size = Vector3.new(0.6, 1.2, 1.2)
    hat.BrickColor = BrickColor.new("Black")
    hat.Material = Enum.Material.SmoothPlastic
    hat.CanCollide = false
    hat.Anchored = false
    hat.Parent = bill

    -- Поля шляпы
    local brim = Instance.new("Part")
    brim.Name = "Brim"
    brim.Shape = Enum.PartType.Cylinder
    brim.Size = Vector3.new(0.2, 1.8, 1.8)
    brim.BrickColor = BrickColor.new("Black")
    brim.Material = Enum.Material.SmoothPlastic
    brim.CanCollide = false
    brim.Anchored = false
    brim.Parent = bill

    -- Руки (тонкие палки)
    local function createArm(side)
        local arm = Instance.new("Part")
        arm.Name = "Arm" .. side
        arm.Size = Vector3.new(0.15, 1.4, 0.15)
        arm.BrickColor = BrickColor.new("Bright yellow")
        arm.Material = Enum.Material.Neon
        arm.CanCollide = false
        arm.Anchored = false
        arm.Parent = bill

        -- Перчатка (белый шар на конце)
        local glove = Instance.new("Part")
        glove.Name = "Glove" .. side
        glove.Shape = Enum.PartType.Ball
        glove.Size = Vector3.new(0.3, 0.3, 0.3)
        glove.BrickColor = BrickColor.new("White")
        glove.Material = Enum.Material.SmoothPlastic
        glove.CanCollide = false
        glove.Anchored = false
        glove.Parent = bill

        return arm, glove
    end

    local armL, gloveL = createArm("L")
    local armR, gloveR = createArm("R")

    -- Ноги
    local function createLeg(side)
        local leg = Instance.new("Part")
        leg.Name = "Leg" .. side
        leg.Size = Vector3.new(0.15, 1.0, 0.15)
        leg.BrickColor = BrickColor.new("Black")
        leg.Material = Enum.Material.SmoothPlastic
        leg.CanCollide = false
        leg.Anchored = false
        leg.Parent = bill

        local shoe = Instance.new("Part")
        shoe.Name = "Shoe" .. side
        shoe.Size = Vector3.new(0.4, 0.2, 0.5)
        shoe.BrickColor = BrickColor.new("Black")
        shoe.Material = Enum.Material.SmoothPlastic
        shoe.CanCollide = false
        shoe.Anchored = false
        shoe.Parent = bill

        return leg, shoe
    end

    local legL, shoeL = createLeg("L")
    local legR, shoeR = createLeg("R")

    -- Bow tie (галстук-бабочка)
    local bowtie = Instance.new("Part")
    bowtie.Name = "Bowtie"
    bowtie.Size = Vector3.new(0.5, 0.2, 0.1)
    bowtie.BrickColor = BrickColor.new("Black")
    bowtie.Material = Enum.Material.SmoothPlastic
    bowtie.CanCollide = false
    bowtie.Anchored = false
    bowtie.Parent = bill

    -- PrimaryPart = тело
    bill.PrimaryPart = body

    -- Сварка всех частей к телу через WeldConstraints
    local function weld(part0, part1, offset)
        local wc = Instance.new("WeldConstraint")
        wc.Part0 = part0
        wc.Part1 = part1
        wc.Parent = part0
        -- Задаём относительную позицию через CFrame перед сваркой
        part1.CFrame = part0.CFrame * offset
    end

    -- Позиционируем части относительно тела
    body.CFrame = CFrame.new(0, 5, 0)

    eyeWhite.CFrame  = body.CFrame * CFrame.new(0, 0.3, -0.2)
    pupil.CFrame     = body.CFrame * CFrame.new(0, 0.3, -0.35)
    hat.CFrame       = body.CFrame * CFrame.new(0, 1.8, 0) * CFrame.Angles(0, 0, math.rad(90))
    brim.CFrame      = body.CFrame * CFrame.new(0, 1.45, 0) * CFrame.Angles(0, 0, math.rad(90))
    bowtie.CFrame    = body.CFrame * CFrame.new(0, -0.8, -0.2)
    armL.CFrame      = body.CFrame * CFrame.new(-1.2, 0, 0) * CFrame.Angles(0, 0, math.rad(30))
    armR.CFrame      = body.CFrame * CFrame.new( 1.2, 0, 0) * CFrame.Angles(0, 0, math.rad(-30))
    gloveL.CFrame    = body.CFrame * CFrame.new(-1.9, -0.6, 0)
    gloveR.CFrame    = body.CFrame * CFrame.new( 1.9, -0.6, 0)
    legL.CFrame      = body.CFrame * CFrame.new(-0.4, -2.0, 0)
    legR.CFrame      = body.CFrame * CFrame.new( 0.4, -2.0, 0)
    shoeL.CFrame     = body.CFrame * CFrame.new(-0.4, -2.55, 0.1)
    shoeR.CFrame     = body.CFrame * CFrame.new( 0.4, -2.55, 0.1)

    -- Свариваем
    local parts = {eyeWhite, pupil, hat, brim, bowtie, armL, armR, gloveL, gloveR, legL, legR, shoeL, shoeR}
    for _, p in ipairs(parts) do
        local wc = Instance.new("WeldConstraint")
        wc.Part0 = body
        wc.Part1 = p
        wc.Parent = body
    end

    bill.Parent = workspace
    return bill
end

-- ═══════════════════════════════════════════
-- ХИЖИНА ЧУДЕС — базовая структура
-- ═══════════════════════════════════════════

local function buildCabin()
    local cabin = Instance.new("Model")
    cabin.Name = "MysteryShack"
    
    local WOOD = BrickColor.new("Reddish brown")
    local ROOF = BrickColor.new("Dark orange")
    local FLOOR_MAT = Enum.Material.WoodPlanks

    -- Пол
    local floor = Instance.new("Part")
    floor.Name = "Floor"
    floor.Size = Vector3.new(30, 1, 20)
    floor.CFrame = CFrame.new(0, 0.5, 0)
    floor.BrickColor = WOOD
    floor.Material = FLOOR_MAT
    floor.Anchored = true
    floor.Parent = cabin

    -- Стены
    local wallsData = {
        -- {name, size, position, rotation}
        {"WallFront",  Vector3.new(30, 12, 1),  CFrame.new(0,  6.5, -10)},
        {"WallBack",   Vector3.new(30, 12, 1),  CFrame.new(0,  6.5,  10)},
        {"WallLeft",   Vector3.new(1,  12, 20), CFrame.new(-15, 6.5,  0)},
        {"WallRight",  Vector3.new(1,  12, 20), CFrame.new( 15, 6.5,  0)},
    }

    for _, data in ipairs(wallsData) do
        local wall = Instance.new("Part")
        wall.Name = data[1]
        wall.Size = data[2]
        wall.CFrame = data[3]
        wall.BrickColor = WOOD
        wall.Material = FLOOR_MAT
        wall.Anchored = true
        wall.Parent = cabin
    end

    -- Потолок
    local ceiling = Instance.new("Part")
    ceiling.Size = Vector3.new(30, 1, 20)
    ceiling.CFrame = CFrame.new(0, 13, 0)
    ceiling.BrickColor = WOOD
    ceiling.Material = FLOOR_MAT
    ceiling.Anchored = true
    ceiling.Name = "Ceiling"
    ceiling.Parent = cabin

    -- Крыша (два ската через WedgePart)
    local roofL = Instance.new("WedgePart")
    roofL.Size = Vector3.new(30, 5, 12)
    roofL.CFrame = CFrame.new(0, 16.5, -4) * CFrame.Angles(0, 0, math.rad(0))
    roofL.BrickColor = ROOF
    roofL.Material = Enum.Material.SmoothPlastic
    roofL.Anchored = true
    roofL.Parent = cabin

    local roofR = Instance.new("WedgePart")
    roofR.Size = Vector3.new(30, 5, 12)
    roofR.CFrame = CFrame.new(0, 16.5, 4) * CFrame.Angles(0, math.rad(180), 0)
    roofR.BrickColor = ROOF
    roofR.Material = Enum.Material.SmoothPlastic
    roofR.Anchored = true
    roofR.Parent = cabin

    -- Дверной проём в передней стене (вырезаем через PartOperation если доступно, иначе делаем две колонны)
    -- Простой вариант: два куска стены по бокам от двери
    workspace.WallFront and (workspace.WallFront:Destroy()) -- если уже есть

    -- Боковые куски передней стены (дверь 4x8 по центру)
    local frontLeft = Instance.new("Part")
    frontLeft.Size = Vector3.new(13, 12, 1)
    frontLeft.CFrame = CFrame.new(-8.5, 6.5, -10)
    frontLeft.BrickColor = WOOD
    frontLeft.Material = FLOOR_MAT
    frontLeft.Anchored = true
    frontLeft.Parent = cabin

    local frontRight = Instance.new("Part")
    frontRight.Size = Vector3.new(13, 12, 1)
    frontRight.CFrame = CFrame.new(8.5, 6.5, -10)
    frontRight.BrickColor = WOOD
    frontRight.Material = FLOOR_MAT
    frontRight.Anchored = true
    frontRight.Parent = cabin

    local frontTop = Instance.new("Part")
    frontTop.Size = Vector3.new(4, 4, 1)
    frontTop.CFrame = CFrame.new(0, 11, -10)
    frontTop.BrickColor = WOOD
    frontTop.Material = FLOOR_MAT
    frontTop.Anchored = true
    frontTop.Parent = cabin

    -- Мебель: прилавок
    local counter = Instance.new("Part")
    counter.Size = Vector3.new(8, 3, 2)
    counter.CFrame = CFrame.new(0, 2.5, 5)
    counter.BrickColor = WOOD
    counter.Material = FLOOR_MAT
    counter.Anchored = true
    counter.Parent = cabin

    -- Полки
    for i = 1, 3 do
        local shelf = Instance.new("Part")
        shelf.Size = Vector3.new(10, 0.3, 2)
        shelf.CFrame = CFrame.new(-14, 3 + i * 2.5, 0)
        shelf.BrickColor = WOOD
        shelf.Material = FLOOR_MAT
        shelf.Anchored = true
        shelf.Parent = cabin
    end

    -- Знак "Mystery Shack"
    local sign = Instance.new("Part")
    sign.Size = Vector3.new(12, 3, 0.3)
    sign.CFrame = CFrame.new(0, 14, -10.2)
    sign.BrickColor = BrickColor.new("Bright yellow")
    sign.Material = Enum.Material.SmoothPlastic
    sign.Anchored = true
    sign.Parent = cabin

    local signGui = Instance.new("SurfaceGui")
    signGui.Face = Enum.NormalId.Front
    signGui.Parent = sign

    local signLabel = Instance.new("TextLabel")
    signLabel.Size = UDim2.new(1, 0, 1, 0)
    signLabel.BackgroundTransparency = 1
    signLabel.Text = "MYSTERY SHACK"
    signLabel.TextColor3 = Color3.fromRGB(50, 20, 0)
    signLabel.TextScaled = true
    signLabel.Font = Enum.Font.Antique
    signLabel.Parent = signGui

    -- Лесной фон снаружи (зелёная плоскость)
    local ground = Instance.new("Part")
    ground.Size = Vector3.new(500, 1, 500)
    ground.CFrame = CFrame.new(0, -0.5, 0)
    ground.BrickColor = BrickColor.new("Forest green")
    ground.Material = Enum.Material.Grass
    ground.Anchored = true
    ground.Parent = cabin

    -- Несколько деревьев
    local function makeTree(x, z)
        local trunk = Instance.new("Part")
        trunk.Shape = Enum.PartType.Cylinder
        trunk.Size = Vector3.new(8, 1.5, 1.5)
        trunk.CFrame = CFrame.new(x, 4, z) * CFrame.Angles(0, 0, math.rad(90))
        trunk.BrickColor = BrickColor.new("Reddish brown")
        trunk.Material = Enum.Material.SmoothPlastic
        trunk.Anchored = true
        trunk.Parent = cabin

        local leaves = Instance.new("Part")
        leaves.Shape = Enum.PartType.Ball
        leaves.Size = Vector3.new(8, 8, 8)
        leaves.CFrame = CFrame.new(x, 9, z)
        leaves.BrickColor = BrickColor.new("Forest green")
        leaves.Material = Enum.Material.Grass
        leaves.Anchored = true
        leaves.Parent = cabin
    end

    local treePositions = {
        {-30, -25}, {30, -25}, {-40, 0}, {40, 0},
        {-35, 20}, {35, 20}, {-25, 30}, {25, 30},
        {-50, -15}, {50, -15}
    }
    for _, pos in ipairs(treePositions) do
        makeTree(pos[1], pos[2])
    end

    cabin.Parent = workspace
    return cabin
end

-- ═══════════════════════════════════════════
-- ЛОГИКА ПРЕСЛЕДОВАНИЯ
-- ═══════════════════════════════════════════

local CHASE_SPEED        = 14   -- studs/sec
local TELEPORT_DIST      = 60   -- дальше этого Билл телепортируется ближе
local JUMPSCARE_DIST     = 4    -- дистанция крика
local PATROL_RADIUS      = 8    -- радиус патруля когда игроков нет
local ROTATION_SPEED     = 5    -- скорость поворота к игроку

-- Звуки (ID из Roblox Asset Library — публичные)
local LAUGH_SOUND_ID   = "rbxassetid://5615086548"  -- смех Билла (можно заменить)
local SCREAM_SOUND_ID  = "rbxassetid://1448796680"  -- крик

local billModel = nil
local jumpscareCooldown = {}  -- {[player] = timestamp}

local function playSound(soundId, parent)
    local s = Instance.new("Sound")
    s.SoundId = soundId
    s.Volume = 1
    s.RollOffMaxDistance = 60
    s.Parent = parent or workspace
    s:Play()
    game:GetService("Debris"):AddItem(s, 5)
end

local function getClosestPlayer(from)
    local closest, closestDist = nil, math.huge
    for _, p in ipairs(Players:GetPlayers()) do
        local char = p.Character
        if char then
            local root = char:FindFirstChild("HumanoidRootPart")
            if root then
                local dist = (root.Position - from).Magnitude
                if dist < closestDist then
                    closest = p
                    closestDist = dist
                end
            end
        end
    end
    return closest, closestDist
end

local function jumpScare(player)
    local now = tick()
    if jumpscareCooldown[player] and (now - jumpscareCooldown[player]) < 10 then return end
    jumpscareCooldown[player] = now

    -- Отправляем RemoteEvent игроку для эффекта экрана
    local re = game:GetService("ReplicatedStorage"):FindFirstChild("BillJumpScare")
    if re then
        re:FireClient(player)
    end
end

-- ═══════════════════════════════════════════
-- АНИМАЦИЯ БИЛЛА (вращение + покачивание)
-- ═══════════════════════════════════════════

local function animateBill(bill, dt, time)
    if not bill or not bill.PrimaryPart then return end
    -- Левитация
    local hover = math.sin(time * 2) * 0.3
    local currentCF = bill.PrimaryPart.CFrame
    bill:SetPrimaryPartCFrame(
        CFrame.new(currentCF.X, 5 + hover, currentCF.Z) *
        CFrame.Angles(0, currentCF:ToEulerAnglesYXZ(), 0)
    )
end

-- ═══════════════════════════════════════════
-- JUMPSSCARE REMOTE EVENT
-- ═══════════════════════════════════════════

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local jumpScareRE = Instance.new("RemoteEvent")
jumpScareRE.Name = "BillJumpScare"
jumpScareRE.Parent = ReplicatedStorage

-- ═══════════════════════════════════════════
-- MAIN LOOP
-- ═══════════════════════════════════════════

-- Строим хижину и создаём Билла при старте
buildCabin()
wait(2)  -- ждём загрузки карты
billModel = createBill()

-- Ставим Билла в случайное место снаружи
if billModel and billModel.PrimaryPart then
    billModel:SetPrimaryPartCFrame(CFrame.new(40, 5, 40))
end

local lastLaugh = 0
local time = 0

RunService.Heartbeat:Connect(function(dt)
    time = time + dt

    if not billModel or not billModel.PrimaryPart then return end

    local billRoot = billModel.PrimaryPart
    local billPos = billRoot.Position

    local target, dist = getClosestPlayer(billPos)

    if target then
        local targetChar = target.Character
        local targetRoot = targetChar and targetChar:FindFirstChild("HumanoidRootPart")

        if targetRoot then
            local targetPos = targetRoot.Position

            -- Телепорт если слишком далеко (чтобы не терять игрока)
            if dist > TELEPORT_DIST then
                local offset = Vector3.new(math.random(-15, 15), 0, math.random(-15, 15))
                billModel:SetPrimaryPartCFrame(CFrame.new(targetPos + offset + Vector3.new(0, 5, 0)))
                return
            end

            -- Движение к игроку
            local direction = (targetPos - billPos)
            direction = Vector3.new(direction.X, 0, direction.Z).Unit

            local newPos = billPos + direction * CHASE_SPEED * dt
            newPos = Vector3.new(newPos.X, 5 + math.sin(time * 2) * 0.3, newPos.Z)

            -- Поворот к игроку
            local lookAt = CFrame.lookAt(newPos, Vector3.new(targetPos.X, newPos.Y, targetPos.Z))
            billModel:SetPrimaryPartCFrame(lookAt)

            -- Смех каждые 8 секунд
            if tick() - lastLaugh > 8 then
                lastLaugh = tick()
                playSound(LAUGH_SOUND_ID, billRoot)
            end

            -- Джамп-скер при близком контакте
            if dist < JUMPSCARE_DIST then
                jumpScare(target)
                playSound(SCREAM_SOUND_ID, billRoot)
                -- Отталкиваем игрока
                local humanoid = targetChar:FindFirstChildOfClass("Humanoid")
                local hrp = targetChar:FindFirstChild("HumanoidRootPart")
                if hrp then
                    hrp.Velocity = (targetPos - billPos).Unit * 50 + Vector3.new(0, 20, 0)
                end
            end
        end
    else
        -- Патруль когда игроков нет
        local angle = time * 0.5
        local patrolPos = Vector3.new(
            math.sin(angle) * PATROL_RADIUS,
            5 + math.sin(time * 2) * 0.3,
            math.cos(angle) * PATROL_RADIUS
        )
        local lookDir = Vector3.new(math.cos(angle), 0, -math.sin(angle))
        billModel:SetPrimaryPartCFrame(
            CFrame.new(patrolPos) * CFrame.fromMatrix(Vector3.zero, lookDir:Cross(Vector3.yAxis) * -1, Vector3.yAxis, -lookDir)
        )
    end
end)