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) -- Считаем количество противников (игроков не из захватывающей фракции) local enemyCount = 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 enemyCount = enemyCount + 1 end end local canGiveMoney = enemyCount >= 5 for _, ply in ipairs(players) do local char = ply:GetCharacter() if (char) then if (canGiveMoney) then char:GiveMoney(self.moneyReward) ply:Notify("Вы получили " .. self.moneyReward .. " за захват точки!") else ply:Notify("Денежная награда не выдана: необходимо минимум 5 противников онлайн.") end 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 })