Иконка ресурса

FREE TeamBattlePro : 1.4.2 1.4.2

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Oxide.Core;
using Oxide.Core.Plugins;
using System.Collections.Generic;
using System;
using UnityEngine;
using Oxide.Game.Rust.Cui;
using Network;
using Facepunch;

namespace Oxide.Plugins
{
    [Info("TeamBattlePro", "YourName", "1.4.2")]
    [Description("Продвинутая система командных сражений")]
    public class TeamBattlePro : RustPlugin
        #region Конфигурация
        
        private const int MAX_ROOMS = 4;
        private const int MAX_TEAM_PLAYERS = 5;
        private const int DEFAULT_COUNTDOWN = 60;
        private const int FAST_COUNTDOWN = 10;
        private const float RESPAWN_DELAY = 2f;

        private const string BG_COLOR = "0.12 0.12 0.15 0.98";
        private const string TITLE_COLOR = "0.9 0.9 0.9 1";
        private const string BUTTON_BLUE = "0.2 0.3 0.8 1";
        private const string BUTTON_RED = "0.8 0.2 0.2 1";
        private const string BUTTON_GREEN = "0.2 0.8 0.2 1";
        private const string BUTTON_DISABLED = "0.3 0.3 0.3 0.5";

        private readonly Dictionary<int, Tuple<Vector3, Vector3>> RoomSpawns = new Dictionary<int, Tuple<Vector3, Vector3>>
        {
            [1] = Tuple.Create(new Vector3(1005, 17, -310), new Vector3(1033, 17, -266)),
            [2] = Tuple.Create(new Vector3(500, 10, 200), new Vector3(600, 10, 200)),
            [3] = Tuple.Create(new Vector3(-150, 10, 400), new Vector3(-250, 10, 400)),
            [4] = Tuple.Create(new Vector3(-300, 10, -200), new Vector3(-400, 10, -200))
        };

        #endregion

        #region Данные

        private Dictionary<int, Dictionary<string, List<BasePlayer>>> Rooms = new Dictionary<int, Dictionary<string, List<BasePlayer>>>();
        private Dictionary<int, Timer> RoomTimers = new Dictionary<int, Timer>();
        private Dictionary<int, int> RoomCountdowns = new Dictionary<int, int>();
        private Dictionary<int, bool> RoomLocked = new Dictionary<int, bool>();
        private Dictionary<BasePlayer, Tuple<int, string>> PlayerData = new Dictionary<BasePlayer, Tuple<int, string>>();

        #endregion

        #region Инициализация

        void Init()
        {
            for (int i = 1; i <= MAX_ROOMS; i++)
            {
                Rooms[i] = new Dictionary<string, List<BasePlayer>>
                {
                    ["Team1"] = new List<BasePlayer>(),
                    ["Team2"] = new List<BasePlayer>()
                };
                RoomCountdowns[i] = DEFAULT_COUNTDOWN;
                RoomLocked[i] = false;
            }
        }

        void Unload()
        {
            foreach (var timer in RoomTimers.Values) timer?.Destroy();
            RoomTimers.Clear();
            PlayerData.Clear();
            Rooms.Clear();
            RoomCountdowns.Clear();
            RoomLocked.Clear();
        }

        #endregion

        #region Команды

        [ChatCommand("play")]
        void PlayCommand(BasePlayer player, string command, string[] args)
        {
            DestroyUI(player);
            ShowRoomSelection(player);
        }

        [ConsoleCommand("teambattlepro.selectroom")]
        void SelectRoomCMD(ConsoleSystem.Arg arg)
        {
            var player = arg.Player() as BasePlayer;
            if (player == null) return;

            if (!int.TryParse(arg.Args?[0], out int roomId) || roomId < 1 || roomId > MAX_ROOMS)
            {
                player.ChatMessage("Некорректный номер комнаты!");
                return;
            }

            if (RoomLocked[roomId])
            {
                player.ChatMessage("Комната уже в игре!");
                return;
            }

            DestroyUI(player);
            ShowTeamSelection(player, roomId);
        }

        [ConsoleCommand("teambattlepro.selectteam")]
        void SelectTeamCMD(ConsoleSystem.Arg arg)
        {
            var player = arg.Player() as BasePlayer;
            if (player == null) return;

            if (!int.TryParse(arg.Args?[0], out int roomId) || roomId < 1 || roomId > MAX_ROOMS)
            {
                player.ChatMessage("Ошибка выбора комнаты!");
                return;
            }

            if (RoomLocked[roomId])
            {
                player.ChatMessage("Игра уже началась!");
                return;
            }

            string team = arg.Args?[1];
            if (string.IsNullOrEmpty(team) || !Rooms[roomId].ContainsKey(team))
            {
                player.ChatMessage("Ошибка выбора команды!");
                return;
            }

            if (Rooms[roomId][team].Count >= MAX_TEAM_PLAYERS)
            {
                player.ChatMessage("Команда заполнена!");
                return;
            }

            RemovePlayerFromAllRooms(player);
            Rooms[roomId][team].Add(player);
            PlayerData[player] = Tuple.Create(roomId, team);
            player.ChatMessage($"<color=#00FF00>Вы в команде {team} (Комната {roomId})</color>");
            
            UpdateRoomUI(roomId);
            ManageRoomTimer(roomId);
        }

        [ConsoleCommand("teambattlepro.leaveroom")]
        void LeaveRoomCMD(ConsoleSystem.Arg arg)
        {
            var player = arg.Player() as BasePlayer;
            if (player == null) return;

            if (!PlayerData.TryGetValue(player, out var data))
            {
                player.ChatMessage("Вы не в комнате!");
                return;
            }

            if (RoomLocked[data.Item1])
            {
                player.ChatMessage("Нельзя выйти во время игры!");
                return;
            }

            RemovePlayerFromAllRooms(player);
            DestroyUI(player);
            player.ChatMessage("<color=#FFA500>Вы покинули комнату</color>");
            ManageRoomTimer(data.Item1);
        }

        [ConsoleCommand("teambattlepro.closeui")]
        void CloseUICMD(ConsoleSystem.Arg arg)
        {
            var player = arg.Player() as BasePlayer;
            if (player != null) DestroyUI(player);
        }

        #endregion

        #region UI

        void ShowRoomSelection(BasePlayer player)
        {
            var cui = new CuiElementContainer();
            string panel = cui.Add(new CuiPanel
            {
                Image = { Color = BG_COLOR },
                RectTransform = { AnchorMin = "0.25 0.2", AnchorMax = "0.75 0.8" },
                CursorEnabled = true
            }, "Overlay", "RoomSelectPanel");

            cui.Add(new CuiLabel
            {
                Text = { Text = "⚔ ВЫБОР КОМНАТЫ", FontSize = 22, Align = TextAnchor.MiddleCenter, Color = TITLE_COLOR },
                RectTransform = { AnchorMin = "0.1 0.88", AnchorMax = "0.9 0.95" }
            }, panel, "Title");

            for (int i = 1; i <= MAX_ROOMS; i++)
            {
                int playersCount = Rooms[i]["Team1"].Count + Rooms[i]["Team2"].Count;
                bool isLocked = RoomLocked[i];
                string status = isLocked ? "🔒 ИДЕТ ИГРА" : $"👥 {playersCount}/{MAX_TEAM_PLAYERS*2}";

                cui.Add(new CuiButton
                {
                    Button = { 
                        Command = isLocked ? "" : $"teambattlepro.selectroom {i}", 
                        Color = isLocked ? BUTTON_DISABLED : BUTTON_GREEN,
                        Close = panel
                    },
                    RectTransform = { AnchorMin = $"0.1 {0.75 - (i * 0.15)}", AnchorMax = $"0.9 {0.85 - (i * 0.15)}" },
                    Text = { 
                        Text = $"🏟 КОМНАТА {i}\n{status}", 
                        FontSize = 16, 
                        Align = TextAnchor.MiddleCenter,
                        Color = "1 1 1 1"
                    }
                }, panel, $"RoomBtn_{i}");
            }

            cui.Add(new CuiButton
            {
                Button = { Command = "teambattlepro.closeui", Color = BUTTON_RED, Close = panel },
                RectTransform = { AnchorMin = "0.1 0.05", AnchorMax = "0.9 0.12" },
                Text = { Text = "✖ ЗАКРЫТЬ", FontSize = 14, Align = TextAnchor.MiddleCenter }
            }, panel, "CloseBtn");

            CuiHelper.AddUi(player, cui);
        }

        void ShowTeamSelection(BasePlayer player, int roomId)
        {
            var cui = new CuiElementContainer();
            string panel = cui.Add(new CuiPanel
            {
                Image = { Color = BG_COLOR },
                RectTransform = { AnchorMin = "0.25 0.2", AnchorMax = "0.75 0.8" },
                CursorEnabled = true
            }, "Overlay", "TeamSelectPanel");

            cui.Add(new CuiLabel
            {
                Text = { 
                    Text = $"⏳ КОМНАТА {roomId} - СТАРТ ЧЕРЕЗ: {RoomCountdowns[roomId]} СЕК", 
                    FontSize = 18, 
                    Align = TextAnchor.MiddleCenter,
                    Color = TITLE_COLOR
                },
                RectTransform = { AnchorMin = "0.1 0.88", AnchorMax = "0.9 0.95" }
            }, panel, "Title");

            CreateTeamButton(cui, panel, roomId, "Team1", "🔵 КОМАНДА 1", BUTTON_BLUE, "0.1 0.6", "0.9 0.75");
            CreateTeamButton(cui, panel, roomId, "Team2", "🔴 КОМАНДА 2", BUTTON_RED, "0.1 0.35", "0.9 0.5");

            cui.Add(new CuiButton
            {
                Button = { Command = "teambattlepro.leaveroom", Color = BUTTON_RED, Close = panel },
                RectTransform = { AnchorMin = "0.1 0.1", AnchorMax = "0.9 0.2" },
                Text = { Text = "🚪 ПОКИНУТЬ КОМНАТУ", FontSize = 14, Align = TextAnchor.MiddleCenter }
            }, panel, "LeaveBtn");

            CuiHelper.AddUi(player, cui);
        }

        void CreateTeamButton(CuiElementContainer cui, string panel, int roomId, string team, string text, string color, string min, string max)
        {
            bool isFull = Rooms[roomId][team].Count >= MAX_TEAM_PLAYERS;
            bool isLocked = RoomLocked[roomId];
            
            cui.Add(new CuiButton
            {
                Button = { 
                    Command = (isFull || isLocked) ? "" : $"teambattlepro.selectteam {roomId} {team}", 
                    Color = isLocked ? BUTTON_DISABLED : (isFull ? BUTTON_DISABLED : color),
                    Close = panel
                },
                RectTransform = { AnchorMin = min, AnchorMax = max },
                Text = { 
                    Text = $"{text}\n({Rooms[roomId][team].Count}/{MAX_TEAM_PLAYERS})", 
                    FontSize = 14, 
                    Align = TextAnchor.MiddleCenter,
                    Color = "1 1 1 1"
                }
            }, panel, $"{team}Btn");
        }

        void DestroyUI(BasePlayer player)
        {
            CuiHelper.DestroyUi(player, "RoomSelectPanel");
            CuiHelper.DestroyUi(player, "TeamSelectPanel");
        }

        #endregion

        #region Логика игры

        void RemovePlayerFromAllRooms(BasePlayer player)
        {
            if (PlayerData.TryGetValue(player, out var data))
            {
                Rooms[data.Item1][data.Item2].Remove(player);
                PlayerData.Remove(player);
            }
        }

        void UpdateRoomUI(int roomId)
        {
            foreach (var team in Rooms[roomId])
            {
                foreach (var player in team.Value)
                {
                    DestroyUI(player);
                    ShowTeamSelection(player, roomId);
                }
            }
        }

        void ManageRoomTimer(int roomId)
        {
            int playersCount = Rooms[roomId]["Team1"].Count + Rooms[roomId]["Team2"].Count;
            
            if (playersCount == 0)
            {
                ResetTimer(roomId);
                return;
            }

            RoomCountdowns[roomId] = playersCount >= MAX_TEAM_PLAYERS*2 ? FAST_COUNTDOWN : DEFAULT_COUNTDOWN;

            if (!RoomTimers.ContainsKey(roomId))
            {
                StartRoomCountdown(roomId);
            }
        }

        void StartRoomCountdown(int roomId)
        {
            RoomTimers[roomId] = timer.Every(1f, () => 
            {
                if (RoomLocked[roomId])
                {
                    ResetTimer(roomId);
                    return;
                }

                RoomCountdowns[roomId]--;
                UpdateRoomUI(roomId);

                if (RoomCountdowns[roomId] <= 0)
                {
                    StartGame(roomId);
                    return;
                }

                if (Rooms[roomId]["Team1"].Count + Rooms[roomId]["Team2"].Count == 0)
                {
                    ResetTimer(roomId);
                }
            });
        }

        void ResetTimer(int roomId)
        {
            if (RoomTimers.TryGetValue(roomId, out Timer t))
            {
                t.Destroy();
                RoomTimers.Remove(roomId);
            }
            RoomCountdowns[roomId] = DEFAULT_COUNTDOWN;
        }

        void StartGame(int roomId)
        {
            RoomLocked[roomId] = true;
            Puts($"Игра началась в комнате {roomId}");

            TeleportTeams(roomId);

            /* При необходимости выдачи снаряжения раскомментируйте
            foreach (var team in Rooms[roomId])
            {
                foreach (var player in team.Value)
                {
                    player.inventory.Strip();
                    //GiveItem(player, "rifle.ak", 1, true);
                    //GiveItem(player, "ammo.rifle", 150, false);
                }
            }
            */

            foreach (var team in Rooms[roomId])
            {
                foreach (var player in team.Value)
                {
                    player.ChatMessage($"<color=#00FF00>⚔ БИТВА НАЧАЛАСЬ! ВАША КОМАНДА: {team.Key}</color>");
                    DestroyUI(player);
                }
            }

            timer.Once(300f, () => ResetRoom(roomId));
        }

        void TeleportTeams(int roomId)
        {
            if (!RoomSpawns.TryGetValue(roomId, out var spawns))
            {
                Puts($"Ошибка: спавны для комнаты {roomId} не найдены!");
                return;
            }

            for (int i = 0; i < Rooms[roomId]["Team1"].Count; i++)
            {
                var player = Rooms[roomId]["Team1"][i];
                Vector3 spawnPos = spawns.Item1 + new Vector3(i * 2f, 0, 0);
                SafeTeleport(player, spawnPos);
            }

            for (int i = 0; i < Rooms[roomId]["Team2"].Count; i++)
            {
                var player = Rooms[roomId]["Team2"][i];
                Vector3 spawnPos = spawns.Item2 + new Vector3(i * 2f, 0, 0);
                SafeTeleport(player, spawnPos);
            }
        }

        void SafeTeleport(BasePlayer player, Vector3 position)
        {
            try
            {
                if (position.y < 1) position.y = TerrainMeta.HeightMap.GetHeight(position);
                player.Teleport(position);
                player.ClientRPCPlayer(null, player, "StartLoading");
                player.SendNetworkUpdateImmediate();
                // Убрали player.UpdatePlayerCollider(true) - метода нет в API
            }
            catch (Exception ex)
            {
                Puts($"Ошибка телепортации: {ex}");
            }
        }

        void OnPlayerDeath(BasePlayer player, HitInfo info)
        {
            if (!PlayerData.TryGetValue(player, out var data)) return;
            if (!RoomLocked[data.Item1]) return;

            timer.Once(RESPAWN_DELAY, () =>
            {
                if (player.IsDead() || !player.IsConnected) return;

                Vector3 spawnPos = data.Item2 == "Team1"
                    ? RoomSpawns[data.Item1].Item1
                    : RoomSpawns[data.Item1].Item2;

                SafeTeleport(player, spawnPos);
                player.Heal(100f);

                /* При необходимости выдачи снаряжения после смерти раскомментируйте
                player.inventory.Strip();
                GiveItem(player, "rifle.ak", 1, true);
                GiveItem(player, "ammo.rifle", 100, false);
                */
            });
        }

        void GiveItem(BasePlayer player, string shortname, int amount, bool toBelt)
        {
            var item = ItemManager.CreateByName(shortname, amount);
            if (item == null) return;

            if (toBelt)
                item.MoveToContainer(player.inventory.containerBelt);
            else
                item.MoveToContainer(player.inventory.containerMain);

            player.SendNetworkUpdateImmediate();
        }

        void ResetRoom(int roomId)
        {
            foreach (var team in Rooms[roomId])
            {
                foreach (var player in team.Value)
                {
                    PlayerData.Remove(player);
                }
                team.Value.Clear();
            }
            RoomLocked[roomId] = false;
            RoomCountdowns[roomId] = DEFAULT_COUNTDOWN;
            Puts($"Комната {roomId} сброшена");
        }

        #endregion
    }
}

Автор
15FPS
Скачиваний
0
Просмотры
1
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок
Сверху