Files
2026-03-31 10:27:04 +03:00

330 lines
9.8 KiB
Lua
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
local PLUGIN = PLUGIN
-- Координаты баз для запрета авиаударов
local BASE_RF = {
min = Vector(-12686, 4350, -10000),
max = Vector(-8714, 12126, 10000)
}
local BASE_UK = {
min = Vector(9778, 2972, -10000),
max = Vector(13576, 10852, 10000)
}
local function IsInBase(pos)
if (pos:WithinAABox(BASE_RF.min, BASE_RF.max)) then return true end
if (pos:WithinAABox(BASE_UK.min, BASE_UK.max)) then return true end
return false
end
function PLUGIN:SpawnAirdrop(weapon)
local center = Vector(0, 0, 0)
local players = player.GetAll()
if (#players > 0) then
local targetPlayer = players[math.random(#players)]
center = targetPlayer:GetPos()
end
local angle = math.random(0, 360)
local radian = math.rad(angle)
local altitude = math.random(2000, 2500)
local startPos = center + Vector(math.cos(radian) * 15000, math.sin(radian) * 15000, 0)
startPos.z = altitude
local endPos = center - Vector(math.cos(radian) * 15000, math.sin(radian) * 15000, 0)
endPos.z = altitude
util.PrecacheModel(ix.config.Get("airdropPlaneModel", "models/gunkov2056/su25.mdl"))
local plane = ents.Create("prop_dynamic")
plane:SetModel(ix.config.Get("airdropPlaneModel", "models/gunkov2056/su25.mdl"))
plane:SetPos(startPos)
local angles = (endPos - startPos):Angle()
plane:SetAngles(angles)
plane:SetMoveType(MOVETYPE_FLY)
plane:Spawn()
plane:Activate()
print("[Airdrop] Спавн самолета: " .. plane:GetModel() .. " на " .. tostring(startPos))
local speed = 2500
local distance = startPos:Distance(endPos)
local duration = distance / speed
local dropFrac = math.Rand(0.45, 0.55)
local dropped = false
local startTime = CurTime()
plane:EmitSound("su25/su25.wav", 150, 100, 1, CHAN_AUTO)
timer.Create("AirdropPlaneMove_" .. plane:EntIndex(), 0.05, 0, function()
if (!IsValid(plane)) then return end
local elapsed = CurTime() - startTime
local frac = elapsed / duration
if (frac >= 1) then
plane:StopSound("su25/su25.wav")
plane:Remove()
timer.Remove("AirdropPlaneMove_" .. plane:EntIndex())
return
end
plane:SetPos(LerpVector(frac, startPos, endPos))
if (!dropped and frac >= dropFrac) then
dropped = true
self:DropCrate(plane:GetPos(), weapon)
end
end)
end
function PLUGIN:SpawnAirstrike()
ix.util.Notify("Внимание! Обнаружена воздушная угроза. Авиаудар через 30 секунд!", nil, "all")
timer.Simple(30, function()
local targetPos = Vector(0, 0, 0)
local players = player.GetAll()
local attempts = 0
-- Ищем валидную точку для удара (не в базе)
repeat
if (#players > 0) then
targetPos = players[math.random(#players)]:GetPos()
else
targetPos = Vector(math.random(-10000, 10000), math.random(-10000, 10000), 0)
end
attempts = attempts + 1
until (!IsInBase(targetPos) or attempts > 10)
if (IsInBase(targetPos)) then return end -- Отмена если не нашли безопасную точку
local angle = math.random(0, 360)
local radian = math.rad(angle)
local altitude = math.random(2000, 2500)
local startPos = targetPos + Vector(math.cos(radian) * 15000, math.sin(radian) * 15000, 0)
startPos.z = altitude
local endPos = targetPos - Vector(math.cos(radian) * 15000, math.sin(radian) * 15000, 0)
endPos.z = altitude
util.PrecacheModel(ix.config.Get("airstrikePlaneModel", "models/gunkov2056/su25.mdl"))
local plane = ents.Create("prop_dynamic")
plane:SetModel(ix.config.Get("airstrikePlaneModel", "models/gunkov2056/su25.mdl"))
plane:SetPos(startPos)
plane:SetAngles((endPos - startPos):Angle())
plane:SetMoveType(MOVETYPE_FLY)
plane:Spawn()
plane:Activate()
print("[Airstrike] Спавн самолета: " .. plane:GetModel() .. " на " .. tostring(startPos))
local speed = 3000
local duration = startPos:Distance(endPos) / speed
local dropped = false
local startTime = CurTime()
plane:EmitSound("su25/su25.wav", 150, 100, 1, CHAN_AUTO)
timer.Create("AirstrikePlaneMove_" .. plane:EntIndex(), 0.05, 0, function()
if (!IsValid(plane)) then return end
local elapsed = CurTime() - startTime
local frac = elapsed / duration
if (frac >= 1) then
plane:StopSound("su25/su25.wav")
plane:Remove()
timer.Remove("AirstrikePlaneMove_" .. plane:EntIndex())
return
end
plane:SetPos(LerpVector(frac, startPos, endPos))
if (!dropped and frac >= 0.5) then
dropped = true
self:DropBomb(plane:GetPos(), plane:GetForward() * speed)
end
end)
end)
end
function PLUGIN:DropBomb(pos, velocity)
local bomb = ents.Create("sw_bomb_fab250m62_v3")
if (!IsValid(bomb)) then
-- Если энтити нет, создадим обычный взрыв для теста
local exp = ents.Create("env_explosion")
exp:SetPos(pos)
exp:SetKeyValue("iMagnitude", "300")
exp:Spawn()
exp:Fire("Explode", 0, 0)
return
end
bomb:SetPos(pos)
bomb:SetAngles(velocity:Angle())
bomb:Spawn()
bomb:Activate()
local phys = bomb:GetPhysicsObject()
if (IsValid(phys)) then
phys:SetVelocity(velocity)
end
end
function PLUGIN:DropCrate(pos, weapon)
if (!weapon) then
local weaponsConfig = ix.config.Get("airdropWeapons", "")
local weapons = {}
if (type(weaponsConfig) == "string" and weaponsConfig:Trim() != "") then
for _, v in pairs(string.Split(weaponsConfig, "\n")) do
local s = v:Trim()
if (s != "") then
table.insert(weapons, s)
end
end
end
-- Если конфиг пустой или старый, берем список по умолчанию
if (#weapons == 0) then
weapons = {
"tacrp_io_degala",
"tacrp_io_fiveseven",
"tacrp_mr96",
"tacrp_pdw",
"tacrp_superv",
"tacrp_sd_aac_hb",
"tacrp_ak_ak12",
"tacrp_ak_an94",
"tacrp_sg551",
"tacrp_io_xm8car",
"tacrp_hk417",
"tacrp_io_scarh",
"tacrp_mg4",
"tacrp_io_xm8lmg",
"tacrp_io_sg550r",
"tacrp_io_sl8",
"tacrp_io_sg550",
"tacrp_io_vss",
"tacrp_as50",
"tacrp_ex_hecate",
"tacrp_civ_m320"
}
end
weapon = weapons[math.random(#weapons)]
end
local crate = ents.Create("ix_airdrop")
if (!IsValid(crate)) then
print("[Airdrop] ОШИБКА: Не удалось создать энтити ix_airdrop!")
return
end
crate:SetPos(pos)
crate:SetAngles(Angle(0, math.random(0, 360), 0))
crate:Spawn()
crate.ixWeapon = weapon
-- Создаем парашют
util.PrecacheModel("models/jessev92/bf2/parachute.mdl")
local parachute = ents.Create("prop_dynamic")
parachute:SetModel("models/jessev92/bf2/parachute.mdl")
parachute:SetPos(crate:GetPos() + Vector(0, 0, 50))
parachute:SetParent(crate)
parachute:Spawn()
crate.ixParachute = parachute
local phys = crate:GetPhysicsObject()
if (IsValid(phys)) then
phys:Wake()
phys:SetVelocity(Vector(0, 0, -200)) -- Скорость падения
phys:SetDragCoefficient(5)
phys:SetAngleDragCoefficient(100)
end
local function StartSmoke()
if (!IsValid(crate)) then return end
local smoke = ents.Create("env_smokestack")
smoke:SetPos(crate:GetPos())
smoke:SetAngles(Angle(-90, 0, 0))
smoke:SetKeyValue("InitialState", "1")
smoke:SetKeyValue("rendercolor", "255 100 0")
smoke:SetKeyValue("renderamt", "255")
smoke:SetKeyValue("SmokeMaterial", "particle/smokesprites_0001.vmt")
smoke:SetKeyValue("BaseSpread", "20")
smoke:SetKeyValue("SpreadSpeed", "10")
smoke:SetKeyValue("Speed", "80")
smoke:SetKeyValue("StartSize", "30")
smoke:SetKeyValue("EndSize", "120")
smoke:SetKeyValue("Rate", "40")
smoke:SetKeyValue("JetLength", "300")
smoke:Spawn()
smoke:Activate()
smoke:SetParent(crate)
crate.ixSmoke = smoke
ix.util.Notify("Аирдроп приземлился! Ищите оранжевый дым.", nil, "all")
end
-- Принудительно держим ящик ровно во время падения
timer.Create("AirdropUpright_" .. crate:EntIndex(), 0.1, 0, function()
if (!IsValid(crate)) then
timer.Remove("AirdropUpright_" .. crate:EntIndex())
return
end
local phys = crate:GetPhysicsObject()
if (IsValid(phys) and phys:IsMotionEnabled()) then
crate:SetAngles(Angle(0, crate:GetAngles().y, 0))
phys:SetAngleVelocity(Vector(0, 0, 0))
else
timer.Remove("AirdropUpright_" .. crate:EntIndex())
end
end)
timer.Create("AirdropLand_" .. crate:EntIndex(), 0.2, 0, function()
if (!IsValid(crate)) then
timer.Remove("AirdropLand_" .. crate:EntIndex())
return
end
local phys = crate:GetPhysicsObject()
if (!IsValid(phys)) then return end
-- Если скорость мала или мы коснулись земли
local tr = util.TraceLine({
start = crate:GetPos() + Vector(0, 0, 10),
endpos = crate:GetPos() - Vector(0, 0, 40),
filter = crate
})
if (tr.Hit or phys:GetVelocity():Length() < 5) then
phys:EnableMotion(false)
crate:SetPos(tr.HitPos)
crate:SetAngles(Angle(0, crate:GetAngles().y, 0))
if (IsValid(crate.ixParachute)) then
crate.ixParachute:Remove()
end
StartSmoke()
timer.Remove("AirdropLand_" .. crate:EntIndex())
timer.Remove("AirdropUpright_" .. crate:EntIndex())
end
end)
timer.Simple(900, function()
if (IsValid(crate)) then
if (IsValid(crate.ixSmoke)) then crate.ixSmoke:Remove() end
crate:Remove()
end
end)
end
function PLUGIN:Initialize()
self:SetupAirdropTimer()
self:SetupAirstrikeTimer()
end
function PLUGIN:SetupAirdropTimer()
local delay = math.random(ix.config.Get("airdropMinInterval", 3600), ix.config.Get("airdropMaxInterval", 7200))
timer.Create("ixAirdropTimer", delay, 1, function()
self:SpawnAirdrop()
self:SetupAirdropTimer()
end)
end
function PLUGIN:SetupAirstrikeTimer()
local delay = math.random(ix.config.Get("airstrikeMinInterval", 1800), ix.config.Get("airstrikeMaxInterval", 3600))
timer.Create("ixAirstrikeTimer", delay, 1, function()
self:SpawnAirstrike()
self:SetupAirstrikeTimer()
end)
end