166 lines
6.0 KiB
Lua
166 lines
6.0 KiB
Lua
local deathSounds = {
|
||
Sound("vo/npc/male01/pain07.wav"),
|
||
Sound("vo/npc/male01/pain08.wav"),
|
||
Sound("vo/npc/male01/pain09.wav")
|
||
}
|
||
|
||
-- Кастомные спавны по spec_def подразделений
|
||
-- Helix ставит позицию игрока внутри хука PlayerLoadout (spawns.lua)
|
||
-- Арсенал-плагин вызывает PostPlayerLoadout после полной загрузки персонажа
|
||
-- Поэтому перехватываем PostPlayerLoadout чтобы перебить позицию Helix'а
|
||
|
||
-- Поиск свободной точки рядом с базовой, чтобы игроки не спавнились друг в друге
|
||
local function FindClearSpawnPos(basePos)
|
||
-- Сначала проверяем саму базовую точку
|
||
local isClear = true
|
||
for _, ply in ipairs(player.GetAll()) do
|
||
if ply:Alive() and ply:GetPos():DistToSqr(basePos) < 2500 then -- 50^2
|
||
isClear = false
|
||
break
|
||
end
|
||
end
|
||
if isClear then return basePos end
|
||
|
||
-- Если занята — ищем свободную позицию по кругу вокруг базовой точки
|
||
local offsets = {60, 120, 180}
|
||
for _, radius in ipairs(offsets) do
|
||
for angle = 0, 315, 45 do
|
||
local rad = math.rad(angle)
|
||
local testPos = basePos + Vector(math.cos(rad) * radius, math.sin(rad) * radius, 0)
|
||
|
||
local clear = true
|
||
for _, ply in ipairs(player.GetAll()) do
|
||
if ply:Alive() and ply:GetPos():DistToSqr(testPos) < 2500 then
|
||
clear = false
|
||
break
|
||
end
|
||
end
|
||
|
||
if clear then return testPos end
|
||
end
|
||
end
|
||
|
||
-- Если вообще всё занято — спавним на базовой точке
|
||
return basePos
|
||
end
|
||
|
||
hook.Add("DoPlayerDeath", "YaEbal", function(client, attacker, damageinfo)
|
||
-- Даем другим хукам (MedicMod) возможность сработать
|
||
client:AddDeaths(1)
|
||
end)
|
||
|
||
hook.Add("PlayerDeath", "YaEbal", function(client, inflictor, attacker)
|
||
-- Мы перенесли основную логику в плагин death_screen
|
||
-- Просто логируем смерть
|
||
|
||
local character = client:GetCharacter()
|
||
|
||
if (character) then
|
||
if (IsValid(client.ixRagdoll)) then
|
||
client.ixRagdoll.ixIgnoreDelete = true
|
||
client:SetLocalVar("blur", nil)
|
||
|
||
if (hook.Run("ShouldRemoveRagdollOnDeath", client) != false) then
|
||
client.ixRagdoll:Remove()
|
||
end
|
||
end
|
||
|
||
--[[
|
||
-- Отправка экрана смерти Murder Drones
|
||
if ix.config.Get("deathScreenEnabled") then
|
||
client.ixDeathTime = RealTime()
|
||
|
||
local killerName = "Неизвестно"
|
||
if IsValid(attacker) and attacker:IsPlayer() then
|
||
killerName = attacker:GetName()
|
||
elseif IsValid(attacker) then
|
||
killerName = attacker:GetClass()
|
||
end
|
||
|
||
net.Start("ixDeathScreen")
|
||
net.WriteFloat(RespawnTime[client:GetUserGroup()])
|
||
net.WriteString(killerName)
|
||
net.Send(client)
|
||
end
|
||
]]
|
||
|
||
-- client:SetNetVar("deathStartTime", CurTime())
|
||
-- client:SetNetVar("deathTime", CurTime() + RespawnTime[client:GetUserGroup()])
|
||
|
||
character:SetData("health", nil)
|
||
|
||
-- Звук смерти (с учетом настройки экрана смерти)
|
||
if not ix.config.Get("deathScreenDisableSound") then
|
||
local deathSound = hook.Run("GetPlayerDeathSound", client)
|
||
|
||
if (deathSound != false) then
|
||
deathSound = deathSound or deathSounds[math.random(1, #deathSounds)]
|
||
|
||
if (client:IsFemale() and !deathSound:find("female")) then
|
||
deathSound = deathSound:gsub("male", "female")
|
||
end
|
||
|
||
client:EmitSound(deathSound)
|
||
end
|
||
end
|
||
|
||
local weapon = IsValid(attacker) and attacker:IsPlayer() and attacker:GetActiveWeapon()
|
||
local attackerName = IsValid(attacker) and (attacker:IsPlayer() and attacker:GetName() or attacker:GetClass()) or "Unknown"
|
||
|
||
ix.log.Add(client, "playerDeath", attackerName, IsValid(weapon) and weapon:GetClass())
|
||
end
|
||
end)
|
||
|
||
-- Блокировка возрождения на время показа экрана смерти
|
||
hook.Add("PlayerDeathThink", "ixDeathScreenBlock", function(client)
|
||
if ix.config.Get("deathScreenEnabled") then
|
||
local duration = RespawnTime[client:GetUserGroup()] or 60
|
||
if (client.ixDeathTime or 0) + duration > RealTime() then
|
||
return false
|
||
end
|
||
end
|
||
end)
|
||
|
||
-- Ограничение спавна различных элементов из Q-меню только для суперадминов
|
||
function Schema:PlayerSpawnSENT(client, class)
|
||
local userGroup = string.lower(client:GetUserGroup() or "user")
|
||
if not (userGroup == "superadmin" or AdminPrivs[userGroup]) then
|
||
client:Notify("Спавн энтити доступен только администрации!")
|
||
return false
|
||
end
|
||
end
|
||
|
||
function Schema:PlayerSpawnSWEP(client, class, info)
|
||
local userGroup = string.lower(client:GetUserGroup() or "user")
|
||
if not (client:IsSuperAdmin() or AdminPrivs[userGroup]) then
|
||
client:Notify("Выдача оружия из Q-меню доступна только администрации!")
|
||
return false
|
||
end
|
||
end
|
||
|
||
function Schema:PlayerSpawnNPC(client, class, weapon)
|
||
local userGroup = string.lower(client:GetUserGroup() or "user")
|
||
if not (client:IsSuperAdmin() or AdminPrivs[userGroup]) then
|
||
client:Notify("Спавн NPC доступен только администрации!")
|
||
return false
|
||
end
|
||
end
|
||
|
||
function Schema:PlayerSpawnVehicle(client, class, name, table)
|
||
local userGroup = string.lower(client:GetUserGroup() or "user")
|
||
if not (client:IsSuperAdmin() or AdminPrivs[userGroup]) then
|
||
client:Notify("Спавн машин из Q-меню доступен только администрации!")
|
||
return false
|
||
end
|
||
end
|
||
|
||
function Schema:PlayerSpawnProp(client, model)
|
||
local userGroup = string.lower(client:GetUserGroup() or "user")
|
||
if (client:IsSuperAdmin() or AdminPrivs[userGroup]) then
|
||
return true
|
||
end
|
||
|
||
client:Notify("Спавн пропов доступен только администрации!")
|
||
return false
|
||
end
|