add sborka
This commit is contained in:
329
garrysmod/gamemodes/militaryrp/plugins/airdrop/sv_plugin.lua
Normal file
329
garrysmod/gamemodes/militaryrp/plugins/airdrop/sv_plugin.lua
Normal file
@@ -0,0 +1,329 @@
|
||||
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
|
||||
Reference in New Issue
Block a user