415 lines
12 KiB
Lua
415 lines
12 KiB
Lua
util.AddNetworkString("ixCaptureSync")
|
||
|
||
PLUGIN.capturePoints = PLUGIN.capturePoints or {}
|
||
|
||
function PLUGIN:GetPlayersInRadius(point, radius)
|
||
local players = {}
|
||
local pos = point:GetPos()
|
||
|
||
for _, ply in ipairs(player.GetAll()) do
|
||
if ply:Alive() and pos:Distance(ply:GetPos()) <= radius and not (ply.IsAdminMode and ply:IsAdminMode()) then
|
||
table.insert(players, ply)
|
||
end
|
||
end
|
||
|
||
return players
|
||
end
|
||
|
||
function PLUGIN:GetFactionFromPlayers(players)
|
||
local factions = {}
|
||
|
||
for _, ply in ipairs(players) do
|
||
local char = ply:GetCharacter()
|
||
if (char) then
|
||
local faction = char:GetFaction()
|
||
factions[faction] = (factions[faction] or 0) + 1
|
||
end
|
||
end
|
||
|
||
return factions
|
||
end
|
||
|
||
function PLUGIN:GetFactionOnlineCount(faction)
|
||
local count = 0
|
||
|
||
for _, ply in ipairs(player.GetAll()) do
|
||
local char = ply:GetCharacter()
|
||
if char and char:GetFaction() == faction and not (ply.IsAdminMode and ply:IsAdminMode()) then
|
||
count = count + 1
|
||
end
|
||
end
|
||
|
||
return count
|
||
end
|
||
|
||
function PLUGIN:CanFactionCapture(faction)
|
||
local minOnline = self.factionMinOnline[faction]
|
||
if (!minOnline) then return true end
|
||
|
||
local online = self:GetFactionOnlineCount(faction)
|
||
return online >= minOnline
|
||
end
|
||
|
||
function PLUGIN:CanCapture(factions)
|
||
local count = 0
|
||
for _ in pairs(factions) do
|
||
count = count + 1
|
||
end
|
||
|
||
return count == 1
|
||
end
|
||
|
||
function PLUGIN:GiveRewards(faction, players)
|
||
for _, ply in ipairs(players) do
|
||
local char = ply:GetCharacter()
|
||
if (char) then
|
||
char:GiveMoney(self.moneyReward)
|
||
ply:Notify("Вы получили " .. self.moneyReward .. " за захват точки!")
|
||
end
|
||
end
|
||
|
||
if (ix.plugin.list["arsenal"]) then
|
||
ix.plugin.list["arsenal"]:AddFactionSupply(faction, self.arsenalReward)
|
||
end
|
||
|
||
if (ix.plugin.list["vehicles"]) then
|
||
ix.plugin.list["vehicles"]:AddFactionPoints(faction, self.vehicleReward)
|
||
end
|
||
|
||
-- Логируем выдачу наград
|
||
local serverlogsPlugin = ix.plugin.list["serverlogs"]
|
||
if (serverlogsPlugin) then
|
||
local factionName = ix.faction.Get(faction).name or tostring(faction)
|
||
local message = string.format("Фракция '%s' получила награду за захват: %d снабжения, %d очков техники, %d денег на игрока",
|
||
factionName, self.arsenalReward, self.vehicleReward, self.moneyReward)
|
||
serverlogsPlugin:AddLog("CAPTURE_REWARD", message, nil, {
|
||
faction = faction,
|
||
factionName = factionName,
|
||
arsenalReward = self.arsenalReward,
|
||
vehicleReward = self.vehicleReward,
|
||
moneyReward = self.moneyReward,
|
||
playerCount = #players
|
||
})
|
||
end
|
||
end
|
||
|
||
function PLUGIN:ProcessCapture(point)
|
||
local players = self:GetPlayersInRadius(point, self.captureRadius)
|
||
|
||
if (#players == 0) then
|
||
if point.capturingFaction != nil then
|
||
point.capturingFaction = nil
|
||
point.capturingPlayers = 0
|
||
self:SyncCapturePoint(point)
|
||
end
|
||
return
|
||
end
|
||
|
||
local factions = self:GetFactionFromPlayers(players)
|
||
|
||
if (!self:CanCapture(factions)) then
|
||
if point.capturingFaction != nil or !point.captureBlocked then
|
||
point.capturingFaction = nil
|
||
point.capturingPlayers = 0
|
||
point.captureBlocked = true
|
||
self:SyncCapturePoint(point)
|
||
end
|
||
return
|
||
end
|
||
|
||
point.captureBlocked = false
|
||
|
||
local faction, playerCount = next(factions)
|
||
|
||
if (playerCount < self.minCapturePlayers) then
|
||
if point.capturingFaction != nil or !point.captureBlocked then
|
||
point.capturingFaction = nil
|
||
point.capturingPlayers = 0
|
||
point.captureBlocked = true
|
||
self:SyncCapturePoint(point)
|
||
end
|
||
return
|
||
end
|
||
|
||
if (!self:CanFactionCapture(faction)) then
|
||
if point.capturingFaction != nil or !point.captureBlocked then
|
||
point.capturingFaction = nil
|
||
point.capturingPlayers = 0
|
||
point.captureBlocked = true
|
||
self:SyncCapturePoint(point)
|
||
end
|
||
return
|
||
end
|
||
|
||
if (point.ownerFaction == faction) then
|
||
if point.captureProgress != 100 or point.capturingFaction != nil then
|
||
point.captureProgress = 100
|
||
point.capturingFaction = nil
|
||
point.capturingPlayers = 0
|
||
self:SyncCapturePoint(point)
|
||
end
|
||
return
|
||
end
|
||
|
||
-- Логируем начало захвата при первом касании
|
||
if (!point.capturingFaction or point.capturingFaction != faction) then
|
||
-- Сбрасываем прогресс если начинается захват другой фракцией
|
||
point.captureProgress = 0
|
||
|
||
-- Уведомляем владельцев о захвате
|
||
if (point.ownerFaction and point.ownerFaction != 0 and point.ownerFaction != faction) then
|
||
local capturerName = ix.faction.Get(faction).name or "Противник"
|
||
for _, v in ipairs(player.GetAll()) do
|
||
local char = v:GetCharacter()
|
||
if (char and char:GetFaction() == point.ownerFaction) then
|
||
v:Notify("ВНИМАНИЕ! Ваша точка захватывается фракцией " .. capturerName .. "!")
|
||
end
|
||
end
|
||
end
|
||
|
||
local serverlogsPlugin = ix.plugin.list["serverlogs"]
|
||
if (serverlogsPlugin) then
|
||
local factionName = ix.faction.Get(faction).name or tostring(faction)
|
||
local pointPos = tostring(point:GetPos())
|
||
local message = string.format("Фракция '%s' начала захват точки (позиция: %s)", factionName, pointPos)
|
||
serverlogsPlugin:AddLog("CAPTURE_START", message, nil, {
|
||
faction = faction,
|
||
factionName = factionName,
|
||
playerCount = playerCount,
|
||
pointPosition = pointPos
|
||
})
|
||
end
|
||
end
|
||
|
||
point.capturingFaction = faction
|
||
point.capturingPlayers = playerCount
|
||
|
||
local baseSpeed = 100 / self.captureBaseTime -- Progress per second
|
||
local captureSpeed = baseSpeed * playerCount * FrameTime()
|
||
|
||
point.captureProgress = (point.captureProgress or 0) + captureSpeed
|
||
|
||
if (point.captureProgress >= 100) then
|
||
point.captureProgress = 100
|
||
local oldOwner = point.ownerFaction
|
||
point.ownerFaction = faction
|
||
point:SetOwnerFactionID(faction)
|
||
point.capturingFaction = nil
|
||
point.capturingPlayers = 0
|
||
|
||
self:GiveRewards(faction, players)
|
||
self:SaveData()
|
||
|
||
-- Логируем успешный захват точки
|
||
local serverlogsPlugin = ix.plugin.list["serverlogs"]
|
||
if (serverlogsPlugin) then
|
||
local factionName = ix.faction.Get(faction).name or tostring(faction)
|
||
local pointPos = tostring(point:GetPos())
|
||
local oldFactionData = oldOwner and ix.faction.Get(oldOwner)
|
||
local oldFactionName = (oldFactionData and oldFactionData.name) or (oldOwner and tostring(oldOwner)) or "Нейтральная"
|
||
local message = string.format("Точка захвачена фракцией '%s' (предыдущий владелец: %s)", factionName, oldFactionName)
|
||
serverlogsPlugin:AddLog("CAPTURE_COMPLETE", message, nil, {
|
||
faction = faction,
|
||
factionName = factionName,
|
||
oldOwner = oldOwner,
|
||
oldOwnerName = oldFactionName,
|
||
playerCount = playerCount,
|
||
pointPosition = pointPos
|
||
})
|
||
end
|
||
|
||
for _, ply in ipairs(player.GetAll()) do
|
||
local char = ply:GetCharacter()
|
||
if (char and char:GetFaction() == faction) then
|
||
ply:Notify("Точка захвачена вашей фракцией!")
|
||
end
|
||
end
|
||
end
|
||
|
||
-- Only sync if progress changed significantly, something started/stopped, or a timer passed
|
||
local curTime = CurTime()
|
||
point.nextSync = point.nextSync or 0
|
||
|
||
if (point.lastSyncProgress == nil or
|
||
math.abs(point.captureProgress - point.lastSyncProgress) >= 1 or
|
||
curTime >= point.nextSync) then
|
||
|
||
self:SyncCapturePoint(point)
|
||
point.lastSyncProgress = point.captureProgress
|
||
point.nextSync = curTime + 0.2 -- Sync at most 5 times per second
|
||
end
|
||
end
|
||
|
||
function PLUGIN:SyncCapturePoint(point)
|
||
net.Start("ixCaptureSync")
|
||
net.WriteEntity(point)
|
||
net.WriteFloat(point.captureProgress or 0)
|
||
net.WriteUInt(point.ownerFaction or 0, 8)
|
||
net.WriteUInt(point.capturingFaction or 0, 8)
|
||
net.WriteUInt(point.capturingPlayers or 0, 8)
|
||
net.WriteBool(point.captureBlocked or false)
|
||
net.Broadcast()
|
||
end
|
||
|
||
function PLUGIN:Think()
|
||
if (!self.nextTickReward) then
|
||
self.nextTickReward = CurTime() + (self.tickInterval or 300)
|
||
elseif (CurTime() >= self.nextTickReward) then
|
||
self:ProcessPeriodicRewards()
|
||
self.nextTickReward = CurTime() + (self.tickInterval or 300)
|
||
end
|
||
|
||
for _, point in ipairs(self.capturePoints) do
|
||
if (IsValid(point)) then
|
||
self:ProcessCapture(point)
|
||
end
|
||
end
|
||
|
||
if (!self.nextAutoSave or CurTime() >= self.nextAutoSave) then
|
||
self:SaveData()
|
||
self.nextAutoSave = CurTime() + 60
|
||
end
|
||
end
|
||
|
||
function PLUGIN:RegisterCapturePoint(point)
|
||
table.insert(self.capturePoints, point)
|
||
point.captureProgress = 0
|
||
point.ownerFaction = nil
|
||
point:SetOwnerFactionID(0)
|
||
point.capturingFaction = nil
|
||
point.capturingPlayers = 0
|
||
end
|
||
|
||
function PLUGIN:EntityRemoved(entity)
|
||
if (entity:GetClass() == "ix_capture_point") then
|
||
for i, point in ipairs(self.capturePoints) do
|
||
if (point == entity) then
|
||
table.remove(self.capturePoints, i)
|
||
break
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
function PLUGIN:SaveData()
|
||
local data = {}
|
||
|
||
for _, point in ipairs(ents.FindByClass("ix_capture_point")) do
|
||
if IsValid(point) then
|
||
data[#data + 1] = {
|
||
pos = point:GetPos(),
|
||
angles = point:GetAngles(),
|
||
ownerFaction = point.ownerFaction or 0,
|
||
captureProgress = point.captureProgress or 0
|
||
}
|
||
end
|
||
end
|
||
|
||
self:SetData(data)
|
||
end
|
||
|
||
function PLUGIN:LoadData()
|
||
local data = self:GetData()
|
||
|
||
if (!data or #data == 0) then
|
||
for _, v in ipairs(self.defaultPoints or {}) do
|
||
local point = ents.Create("ix_capture_point")
|
||
if IsValid(point) then
|
||
point:SetPos(v.pos)
|
||
point:SetAngles(v.ang)
|
||
point:Spawn()
|
||
|
||
timer.Simple(0.1, function()
|
||
if IsValid(point) then
|
||
point.ownerFaction = 0
|
||
point:SetOwnerFactionID(0)
|
||
point.captureProgress = 0
|
||
end
|
||
end)
|
||
end
|
||
end
|
||
|
||
return
|
||
end
|
||
|
||
for _, v in ipairs(data) do
|
||
local point = ents.Create("ix_capture_point")
|
||
if IsValid(point) then
|
||
point:SetPos(v.pos)
|
||
point:SetAngles(v.angles)
|
||
point:Spawn()
|
||
|
||
timer.Simple(0.1, function()
|
||
if IsValid(point) then
|
||
point.ownerFaction = v.ownerFaction
|
||
point:SetOwnerFactionID(v.ownerFaction or 0)
|
||
point.captureProgress = v.captureProgress or 0
|
||
|
||
self:SyncCapturePoint(point)
|
||
end
|
||
end)
|
||
end
|
||
end
|
||
end
|
||
|
||
function PLUGIN:OnUnloaded()
|
||
self:SaveData()
|
||
end
|
||
|
||
-- Подсчет захваченных точек каждой фракцией
|
||
function PLUGIN:GetCapturedPointsCount()
|
||
local counts = {}
|
||
|
||
for _, point in ipairs(self.capturePoints) do
|
||
if IsValid(point) and point.ownerFaction and point.ownerFaction ~= 0 then
|
||
counts[point.ownerFaction] = (counts[point.ownerFaction] or 0) + 1
|
||
end
|
||
end
|
||
|
||
return counts
|
||
end
|
||
|
||
-- Периодическое начисление очков
|
||
function PLUGIN:ProcessPeriodicRewards()
|
||
local counts = self:GetCapturedPointsCount()
|
||
|
||
for faction, pointCount in pairs(counts) do
|
||
if pointCount > 0 then
|
||
local supplyReward = pointCount * self.tickSupplyPerPoint
|
||
local vehicleReward = pointCount * self.tickVehiclePerPoint
|
||
|
||
if ix.plugin.list["arsenal"] then
|
||
ix.plugin.list["arsenal"]:AddFactionSupply(faction, supplyReward)
|
||
end
|
||
|
||
if ix.plugin.list["vehicles"] then
|
||
ix.plugin.list["vehicles"]:AddFactionPoints(faction, vehicleReward)
|
||
end
|
||
|
||
local factionName = ix.faction.Get(faction).name or "Фракция"
|
||
for _, ply in ipairs(player.GetAll()) do
|
||
local char = ply:GetCharacter()
|
||
if char and char:GetFaction() == faction then
|
||
ply:Notify(string.format("Ваша фракция получила: +%d снабжения, +%d очков техники (точек: %d)",
|
||
supplyReward, vehicleReward, pointCount))
|
||
end
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
ix.command.Add("CaptureSystemSave", {
|
||
description = "Сохранить точки захвата",
|
||
superAdminOnly = true,
|
||
OnRun = function(self, client)
|
||
local plugin = ix.plugin.Get("capture")
|
||
if (!plugin) then
|
||
return "@commandNoExist"
|
||
end
|
||
|
||
plugin:SaveData()
|
||
local count = #ents.FindByClass("ix_capture_point")
|
||
client:Notify("Точки захвата сохранены (" .. count .. " шт.)")
|
||
end
|
||
})
|