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

FREE Skills : 0.0.2 0.0.2

Нет прав для скачивания
C#:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using ConVar;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using Rust.Ai;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("Skills", "Oxide Россия - oxide-russia.ru", "0.0.2")]
    public class Skills : RustPlugin
    {
        [PluginReference] private Plugin ImageLibrary;
        
        #region Classes

        private class Skill
        {
            [JsonProperty("Название скилла")]
            public string Name;
            [JsonProperty("Описание скилла")]
            public string Description;
            [JsonProperty("Информация дл GUI")]
            public string ActionName;
            [JsonProperty("URL изображения")]
            public string URL;
            
            [JsonProperty("Необходимые уровни для прокачки")]
            public Dictionary<float, int> skillAction = new Dictionary<float,int>();
        }

        private class PlayerSkills
        {
            internal class SkillProgress
            {
                [JsonProperty("Текущий уровень очков")]
                public int CurrentPoints;
                [JsonProperty("Общее количество очков")]
                public int TotalPoints;
                
                public SkillProgress(int startPoints, int totalPoints)
                {
                    CurrentPoints = startPoints;
                    TotalPoints = totalPoints;
                }
            }

            [JsonProperty("Следующая смена")]
            public double NextChange;
            
            [JsonProperty("Имя активного скилла")]
            public string ActiveSkill;
            [JsonProperty("Активный уровень")] 
            public float ActiveLevel;
            [JsonProperty("Улучшаемый уровень")] 
            public float ProgressLevel;

            [JsonProperty("Уровень прокачки различных скиллов")]
            public Dictionary<string, Dictionary<float, SkillProgress>> skillLevels = new Dictionary<string, Dictionary<float, SkillProgress>>();

            public void Switch(BasePlayer player, string newSkill)
            {
                if (NextChange > LogTime())
                {
                    player.ChatMessage($"Следующая самена нвыка доступна через <color=#7B68EE>{(NextChange - LogTime()).ToString("F0")} секунд</color>!");
                    return;
                }

                ActiveSkill = newSkill;
                ActiveLevel = GetCurrentLevel(newSkill);
                ProgressLevel = GetProgressLevel(newSkill);
                NextChange = LogTime() + CONF_SwitchTime;
                
                player.ChatMessage($"Вы успешно изменили навык на <color=#7B68EE>{instance.publicSkills[ActiveSkill].Name}</color>\n" +
                                   $"Прогресс изучения навыка: <color=#7B68EE>{((float) skillLevels[ActiveSkill][ProgressLevel].CurrentPoints / skillLevels[ActiveSkill][ProgressLevel].TotalPoints * 100).ToString("F1")}%</color>");
            }
            
            /// <summary>
            /// Добавление определенного количество очков для пользователя
            /// </summary>
            /// <param name="player">Пользователь для которого мы добавляем очки</param>
            /// <param name="amount">Количество очков для прокачки</param>
            public void AddPoints(BasePlayer player, int amount)
            {
                Stopwatch x = new Stopwatch();
                x.Start();
                if (!skillLevels.ContainsKey(ActiveSkill))
                {
                    // Interface.Oxide.LogWarning($"Error #1 | Try add {amount} to {ActiveSkill}, player don't have it!");
                    return;
                }

                var currentProgress = skillLevels[ActiveSkill][ProgressLevel];
                
                // Добавляем новые очки, только если не хватает до конца уровня
                if (ActiveLevel != ProgressLevel)
                {
                    currentProgress.CurrentPoints += amount;
                    instance.UI_CurrentProgress(player, false, progressUpdate: true);
                }

                // Если переваливаем за конец уровня
                if (currentProgress.CurrentPoints >= currentProgress.TotalPoints)
                {
                    // И количесвто очков текущих != финальному (11 из 10 например)
                    if (ActiveLevel != ProgressLevel)
                    {
                        // Повышаем человеку уровень и приравниваем очки
                        currentProgress.CurrentPoints = currentProgress.TotalPoints;
                        ActiveLevel = GetCurrentLevel(ActiveSkill);
                        ProgressLevel = GetProgressLevel(ActiveSkill);
                        // Interface.Oxide.LogWarning($"DEBUG | Player {player.displayName} successful finished his level [A: {ActiveLevel} / P {ProgressLevel}]");
                        
                        player.ChatMessage($"Вы улучшили навык <color=#7B68EE>{instance.publicSkills[ActiveSkill].Name}</color> до <color=#7B68EE>{skillLevels[ActiveSkill].Keys.ToList().IndexOf(ActiveLevel) + 1}-ого</color> уровня!");
                        instance.UI_CurrentProgress(player);
                    }
                }
                else
                {
                    // Interface.Oxide.LogWarning($"DEBUG | Player {player.displayName} now have {currentProgress.CurrentPoints} / {currentProgress.TotalPoints} [{ProgressLevel}]");
                }
                x.Stop();
                // Interface.Oxide.LogWarning($"DEBUG | Player {player.displayName} successful got point [{x.Elapsed.TotalSeconds} ms]");
            }

            /// <summary>
            /// Получение текущего уровня прокачки для игрока
            /// </summary>
            /// <param name="name">Имя скилла</param>
            /// <returns>Получаем процентное значение</returns>
            public float GetProgressLevel(string name)
            {
                if (!skillLevels.ContainsKey(name))
                {
                    // Interface.Oxide.LogWarning($"Error #2 | Try get MaxLevel from {name}, player don't have it!");
                    return -1;
                }

                for (int i = 0; i < skillLevels[name].Count; i++)
                {
                    SkillProgress progress = skillLevels[name].ElementAt(i).Value;
                    
                    if (progress.CurrentPoints < progress.TotalPoints)
                        return skillLevels[name].ElementAt(i).Key;
                }

                return skillLevels[name].Last().Key;
            }

            /// <summary>
            /// Получение текущего активного уровня для игрока
            /// </summary>
            /// <param name="name">Имя скилла</param>
            /// <returns>Получаем процентное значение</returns>
            public float GetCurrentLevel(string name)
            {
                if (!skillLevels.ContainsKey(name))
                {
                    // Interface.Oxide.LogWarning($"Error #2 | Try get CurrentLevel from {name}, player don't have it!");
                    return -1;
                }

                for (int i = 0; i < skillLevels[name].Count; i++)
                {
                    SkillProgress progress = skillLevels[name].ElementAt(i).Value;
                    
                    if (progress.CurrentPoints < progress.TotalPoints)
                        return skillLevels[name].ElementAt(i-1).Key;
                }

                return skillLevels[name].Last().Key;
            }
        }

        #endregion

        #region Variables

        #region Configuration

        [JsonProperty("Интервал смены навыка")]
        public static float CONF_SwitchTime = 60;
        [JsonProperty("Увеличенный удар критом")]
        public static float CONF_KritMultiplier = 1.6f;
        
        [JsonProperty("Количество очков за убийство игрока")]
        public static int CONF_PlayerKill = 1;
        [JsonProperty("Количество очков за убийство животного")]
        public static int CONF_AnimalKill = 1;
        [JsonProperty("Количество очков за добычу ресурсов")]
        public static int CONF_Dispenser = 1;
        [JsonProperty("Количество очков за поднятие ресурса")]
        public static int CONF_GatherUp = 1;
        [JsonProperty("Количество очков за открытие ящика с лутом")]
        public static int CONF_LootEntry = 1;
        [JsonProperty("Количество очков за уничтожение бочки")]
        public static int CONF_BarDestroy = 1;
        [JsonProperty("Количество очков за урон по вертолёту")]
        public static int CONF_HeliDamage = 1;

        #endregion

        [JsonProperty("Слой для меню выбора скилла")]
        private string MenuLayer = "UI_InterfaceMenuLayer";
        [JsonProperty("Слой для отображения текущего скилла")]
        private string CurrentLayer = "UI_InterfaceCurrentLevel";
        
        [JsonProperty("Конкретный экземпляр")] 
        private static Skills instance;
        [JsonProperty("Игроки и их скиллы")]
        private Dictionary<ulong, PlayerSkills> playerSkills = new Dictionary<ulong, PlayerSkills>();
        [JsonProperty("Общая информация о скиллах")]
        private Dictionary<string, Skill> publicSkills = new Dictionary<string, Skill>
        {
            ["ProtectFromDamage"] = new Skill
            {
                Name = "Щит",
                URL = "https://i.imgur.com/RYeLsQu.png",
                ActionName = "защита",
                Description = "Увеличивает вашу защиту от любого получаемого урона",
                skillAction = new Dictionary<float, int>
                {
                    [6f] = -1,
                    [9f] = 50,
                    [12f] = 100,
                    [15f] = 150,
                    [18f] = 200
                }
            },
            ["AddMoreDamage"] = new Skill
            {
                Name = "Ярость",
                URL = "https://i.imgur.com/1Um5Xzy.png",
                ActionName = "урон",
                Description = "Увеличивает наносимый вами урон по игрокам и животным",
                skillAction = new Dictionary<float, int>
                {
                    [6f] = -1,
                    [9f] = 50,
                    [12f] = 100,
                    [15f] = 150,
                    [18f] = 200
                }
            },
            ["RegenerateHP"] = new Skill
            {
                Name = "Вампиризм",
                URL = "https://i.imgur.com/7PV5Qsh.png",
                ActionName = "реген",
                Description = "Восстанавливает HP в процентах от нанесенного вами урона по игрокам и животным",
                skillAction = new Dictionary<float, int>
                {
                    [7f] = -1,
                    [10.5f] = 50,
                    [14f] = 100,
                    [17.5f] = 150,
                    [21f] = 200
                }
            },
            ["YouCanDodgeAttack"] = new Skill
            {
                Name = "Провидец",
                URL = "https://i.imgur.com/kI1XmnD.png",
                ActionName = "шанс",
                Description = "Даёт вам шанс уклониться от каждой вражеской атаки",
                skillAction = new Dictionary<float, int>
                {
                    [5f] = -1,
                    [7.5f] = 50,
                    [10f] = 100,
                    [12.5f] = 150,
                    [15f] = 200
                }
            },
            ["AdditionalDamageFromKrit"] = new Skill
            {
                Name = "Криты",
                URL = "https://i.imgur.com/AMXPFKm.png",
                ActionName = "шанс",
                Description = "Даёт вам шанс при каждой атаке нанести x{0} урона игрокам и животным",
                skillAction = new Dictionary<float, int>
                {
                    [5f] = -1,
                    [7.5f] = 50,
                    [10f] = 100,
                    [12.5f] = 150,
                    [15f] = 200
                }
            },
            ["ReturnSomeDamage"] = new Skill
            {
                Name = "Шипы",
                URL = "https://i.imgur.com/MEWZtC2.png",
                ActionName = "возврат",
                Description = "Возвращает часть полученного вами урона обратно врагу",
                skillAction = new Dictionary<float, int>
                {
                    [9f] = -1,
                    [13.5f] = 50,
                    [18f] = 100,
                    [22.5f] = 150,
                    [27f] = 200
                }
            },
        };

        #endregion

        #region Initialization

        private void OnServerInitialized()
        {
            instance = this;
            
            if (Interface.Oxide.DataFileSystem.ExistsDatafile("Skills/SkillList"))
            {
                publicSkills = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<string, Skill>>("Skills/SkillList");
                // PrintWarning($"Загружена информация о {publicSkills.Count} скиллах.");
            }
            else
            {
                Interface.Oxide.DataFileSystem.WriteObject("Skills/SkillList", publicSkills);
                // PrintWarning($"Загружены стандартные настройки скиллов");
            }

            if (Interface.Oxide.DataFileSystem.ExistsDatafile("Skills/PlayerSkills"))
            {
                playerSkills = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<ulong, PlayerSkills>>("Skills/PlayerSkills");
                // PrintWarning($"Загружена информация о {playerSkills.Count} игроках.");
            }

            foreach (var check in publicSkills)
                ImageLibrary.Call("AddImage", check.Value.URL, check.Key);

            ListHashSet<BasePlayer> onlineplayers = BasePlayer.activePlayerList as ListHashSet<BasePlayer>;
            foreach (BasePlayer player in onlineplayers.ToArray())
            {
                OnPlayerConnected(player);
            }
        }

        private void OnNewSave(string filename) => Save();
        private void Unload() => Save();

        private void Save()
        {
            Interface.Oxide.DataFileSystem.WriteObject("Skills/SkillList", publicSkills);
            Interface.Oxide.DataFileSystem.WriteObject("Skills/PlayerSkills", playerSkills);
            // PrintWarning($"Сохранена информация об успехах игроков");
        }

        #endregion

        #region Hooks

        private void OnPlayerConnected(BasePlayer player)
        {
            if (player.IsReceivingSnapshot)
            {
                NextTick(() =>
                {
                    OnPlayerConnected(player);
                    return;
                });
                return;
            }
            Stopwatch x = new Stopwatch();
            x.Start();
            if (!playerSkills.ContainsKey(player.userID))
            {
                PlayerSkills newPlayerSkill = new PlayerSkills();
                foreach (var skill in publicSkills)
                {
                    Dictionary<float, PlayerSkills.SkillProgress> skillPoints = new Dictionary<float, PlayerSkills.SkillProgress>();
                    foreach (var skillPoint in skill.Value.skillAction)
                        skillPoints.Add(skillPoint.Key, new PlayerSkills.SkillProgress(0, skillPoint.Value));
                    
                    newPlayerSkill.skillLevels.Add(skill.Key, skillPoints);
                }
                newPlayerSkill.ActiveSkill = newPlayerSkill.skillLevels.Keys.ToList().GetRandom();
                newPlayerSkill.ActiveLevel = newPlayerSkill.GetCurrentLevel(newPlayerSkill.ActiveSkill);
                newPlayerSkill.ProgressLevel = newPlayerSkill.GetProgressLevel(newPlayerSkill.ActiveSkill);
                newPlayerSkill.NextChange = LogTime();
                
                playerSkills.Add(player.userID, newPlayerSkill);
                player.ChatMessage($"Вам активирован случайный скилл <color=#7B68EE>{publicSkills[newPlayerSkill.ActiveSkill].Name}</color>\n" +
                                   $"Используйте <color=#7B68EE>/skill</color>, чтобы узнать подробности.");
            }
            x.Stop();
            // PrintWarning($"DEBUG | {player.displayName} successful get all Skills [{x.Elapsed.TotalSeconds} ms]");
            // PrintWarning($"DEBUG | Active skill {playerSkills[player.userID].ActiveSkill} [C: {playerSkills[player.userID].ActiveLevel} / P: {playerSkills[player.userID].ProgressLevel}]");
            
            CuiHelper.DestroyUi(player, CurrentLayer);
            CuiElementContainer container = new CuiElementContainer();

            container.Add(new CuiPanel
            {
                CursorEnabled = false,
                RectTransform = { AnchorMin = "0.0105 0.038", AnchorMax = "0 0.038", OffsetMax = "188 27" },
                Image = { Color = "0.32 0.32 0.41 0.22" }
            }, "Hud", CurrentLayer);
            
            CuiHelper.AddUi(player, container);
            
            UI_CurrentProgress(player);
        }

        #region SkillRealization

        private void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info)
        {
            try
            {
                if (info != null && entity is BaseHelicopter && info.Initiator is BasePlayer &&
                    info.InitiatorPlayer.GetComponent<NPCPlayer>() == null)
                {
                    playerSkills[info.InitiatorPlayer.userID].AddPoints(info.InitiatorPlayer, CONF_HeliDamage);
                    return;
                }

                // Начинаем отрабатывать если речь идёт об игроке и он не NPC
                if (entity is BasePlayer && entity.GetComponent<NPCPlayer>() == null && info != null)
                {
                    BasePlayer player = entity as BasePlayer;
                    BasePlayer target = null;

                    // Сразу берем и проверяем инициатора
                    if (info.Initiator is BasePlayer && info.Initiator.GetComponent<NPCPlayer>() == null)
                        target = info.InitiatorPlayer;

                    // Снижаем нагрузку за счёт не рассчитывания маленького урона
                    if (info.damageTypes.Total() < 5)
                        return;
                    
                    // Продолжаем работать, если у игрока есть скиллы
                    if (playerSkills.ContainsKey(player.userID))
                    {
                        // PrintWarning($"DEBUG | Start working on target skills [{player.displayName}]");
                        PlayerSkills playerSkill = this.playerSkills[player.userID];

                        switch (playerSkill.ActiveSkill.ToLower())
                        {
                            case "protectfromdamage":
                            {
                                // PrintWarning(
                                //    $"DEBUG | {player.displayName} should get {info.damageTypes.Total()} damage, but {playerSkill.ActiveSkill} active");
                                float protectMultiplier = 1 - playerSkill.ActiveLevel / 100;
                                info.damageTypes.ScaleAll(protectMultiplier);

                                // PrintWarning(
                                //    $"DEBUG | {player.displayName} will protect {playerSkill.ActiveLevel}% from his skill [{info.damageTypes.Total()}]");
                                break;
                            }
                            case "addmoredamage":
                            {
                                // NOTHING HERE, PLAYER GET DAMAGE, NO REASON TO COUNT HIS ADDITIONAL DAMAGE
                                break;
                            }
                            case "regeneratehp":
                            {
                                // NOTHING HERE, PLAYER GET DAMAGE, NO REASON TO COUNT HIS ADDITIONAL DAMAGE
                                break;
                            }
                            case "youcandodgeattack":
                            {
                                // PrintWarning(
                                //    $"DEBUG | {player.displayName} [{player.health} HP] should get {info.damageTypes.Total()} damage, but {playerSkill.ActiveSkill} active");

                                int generateNumber = Core.Random.Range(0, 100);
                                if (generateNumber <= playerSkill.ActiveLevel)
                                {
                                    player.ChatMessage(
                                        $"Навык <color=#7B68EE>{publicSkills[playerSkill.ActiveSkill].Name}</color> помог вам уклониться от атаки!");
                                    // PrintWarning(
                                    //    $"DEBUG | {player.displayName} won! {generateNumber} <= {playerSkill.ActiveLevel}! Damage is null!");
                                    info.damageTypes.ScaleAll(0);
                                    // PrintWarning(
                                    //    $"DEBUG | {player.displayName} won! {generateNumber} <= {playerSkill.ActiveLevel}! Damage is null! [{player.health} HP]");
                                }
                                else
                                {
                                    // PrintWarning(
                                    //    $"DEBUG | {player.displayName} lose! {generateNumber} > {playerSkill.ActiveLevel}! Damage is null!");
                                }

                                break;
                            }
                            case "additionaldamagefromkrit":
                            {
                                // NOTHING HERE, PLAYER GET DAMAGE, NO REASON TO COUNT HIS ADDITIONAL DAMAGE
                                break;
                            }
                            case "returnsomedamage":
                            {
                                // PrintWarning(
                                //    $"DEBUG | {player.displayName} will get {info.damageTypes.Total()} damage, but {playerSkill.ActiveSkill} active");
                                if (target != null)
                                {
                                    // PrintWarning(
                                    //    $"DEBUG | {target.displayName} will get {playerSkill.ActiveLevel}% from given damage!");
                                    target.Hurt(info.damageTypes.Total() * (playerSkill.ActiveLevel / 100));
                                }

                                break;
                            }
                            default:
                            {
                                // PrintWarning($"DEBUG | {player.displayName} have unknow skill");
                                break;
                            }
                        }

                        if (target != null && playerSkills.ContainsKey(target.userID))
                        {
                            // PrintWarning($"DEBUG | Start working on target skills [{target.displayName}]");
                            PlayerSkills targetSkill = this.playerSkills[target.userID];

                            switch (targetSkill.ActiveSkill.ToLower())
                            {
                                case "protectfromdamage":
                                {
                                    // NOTHING HERE, PLAYER GET DAMAGE, NO REASON TO COUNT HIS PROTECTION DAMAGE
                                    break;
                                }
                                case "addmoredamage":
                                {
                                    // PrintWarning(
                                    //    $"DEBUG | {player.displayName} should get {info.damageTypes.Total()} damage, but {target.displayName}'s {targetSkill.ActiveSkill} active");
                                    float damageMultiplier = 1 + targetSkill.ActiveLevel / 100;
                                    info.damageTypes.ScaleAll(damageMultiplier);

                                    // PrintWarning(
                                    //    $"DEBUG | {player.displayName} will get additional {targetSkill.ActiveLevel}% from {target.displayName}' skill [{info.damageTypes.Total()}]");
                                    break;
                                }
                                case "regeneratehp":
                                {
                                    // PrintWarning(
                                    //    $"DEBUG | {target.displayName} [{target.health} HP] will get {info.damageTypes.Total() * (targetSkill.ActiveLevel / 100)} HP, cause of {targetSkill.ActiveSkill} active");
                                    target.Heal(info.damageTypes.Total() * (targetSkill.ActiveLevel / 100));
                                    // PrintWarning($"DEBUG | {target.displayName} now have {target.health} HP");
                                    break;
                                }
                                case "youcandodgeattack":
                                {
                                    // NOTHING HERE, PLAYER GET DAMAGE, NO REASON TO COUNT HIS PROTECTION DAMAGE
                                    break;
                                }
                                case "additionaldamagefromkrit":
                                {
                                    // PrintWarning(
                                    //    $"DEBUG | {target.displayName} can give more {info.damageTypes.Total() * CONF_KritMultiplier} damage [{info.damageTypes.Total()} start], cause of {targetSkill.ActiveSkill} active");

                                    int randomAmount = Oxide.Core.Random.Range(0, 100);
                                    if (randomAmount <= targetSkill.ActiveLevel)
                                    {
                                        target.ChatMessage(
                                            $"Навык <color=#7B68EE>{publicSkills[targetSkill.ActiveSkill].Name}</color> помог вам нанести дополнительный урон!");
                                        // PrintWarning(
                                        //    $"DEBUG | {target.displayName} BINGO [{randomAmount}]! He will give additional damage {info.damageTypes.Total()} -> {info.damageTypes.Total() * (CONF_KritMultiplier)}");
                                        info.damageTypes.ScaleAll((CONF_KritMultiplier));
                                    }
                                    else
                                    {
                                        // PrintWarning(
                                        //    $"DEBUG | {target.displayName} LOSE [{randomAmount}].No additional damage!");
                                    }

                                    break;
                                }
                                case "returnsomedamage":
                                {
                                    // NOTHING HERE, PLAYER GET DAMAGE, NO REASON TO COUNT HIS PROTECTION DAMAGE
                                    break;
                                }
                                default:
                                {
                                    // PrintWarning($"DEBUG | {player.displayName} have unknow skill");
                                    break;
                                }
                            }
                        }
                        else
                        {
                            // PrintWarning($"DEBUG | No additional player!");
                        }
                    }
                    else
                    {
                        // PrintWarning($"DEBUG | {player.displayName} try to use skill, but he dont have any skills!");
                    }
                }
            }
            catch (NullReferenceException)
            {
                
            }
        }

        #endregion

        #region Points Add

        private void OnDispenserGather(ResourceDispenser dispenser, BaseEntity entity, Item item)
        {
            // Если это не игрок, или если это НПС - не делаем ничего
            if (entity is BasePlayer && entity.GetComponent<NPCPlayer>() == null)
            {
                BasePlayer player = entity as BasePlayer;
                
                if (playerSkills.ContainsKey(player.userID))
                {
                    // Добавляем игроку очки за разбитую бочку
                    playerSkills[player.userID].AddPoints(player, CONF_Dispenser);
                }
                else
                {
                    // PrintWarning($"DEBUG | {player.displayName} [{player.userID}] not in Player Skills!");
                    return;
                }
            }
            return;
        }
        
        private void OnEntityDeath(BaseCombatEntity entity, HitInfo info)
        {
            if (info != null && info.Initiator is BasePlayer && info.InitiatorPlayer.GetComponent<NPCPlayer>() != null)
            {
                BasePlayer attacker = info.InitiatorPlayer;

                if (!playerSkills.ContainsKey(attacker.userID))
                    return;

                PlayerSkills playerSkill = playerSkills[attacker.userID];

                if (entity is BasePlayer && entity.GetComponent<NPCPlayer>() == null)
                {
                    playerSkill.AddPoints(attacker, CONF_PlayerKill);
                    return;
                }

                if (entity.PrefabName.Contains("agent"))
                {
                    playerSkill.AddPoints(attacker, CONF_AnimalKill);
                    return;
                }

                if (entity.PrefabName.Contains("barrel"))
                {
                    playerSkill.AddPoints(attacker, CONF_BarDestroy);
                    return;
                }
            }
        }
        
        private void OnCollectiblePickup(Item item, BasePlayer player)
        {
            if (!playerSkills.ContainsKey(player.userID))
                return;

            PlayerSkills playerSkill = playerSkills[player.userID];
            playerSkill.AddPoints(player, CONF_GatherUp);
        }
        
        private void OnLootEntity(BasePlayer player, BaseEntity entity)
        {
            if (!(entity is LootContainer) || entity.OwnerID != 0)
                return;
            
            if (!playerSkills.ContainsKey(player.userID))
                return;

            PlayerSkills playerSkill = playerSkills[player.userID];
            playerSkill.AddPoints(player, CONF_LootEntry);
            entity.OwnerID = player.userID;
        }

        #endregion

        #endregion

        #region Commands

        [ConsoleCommand("UI_SkillHandler")]
        private void consoleCommandHandler(ConsoleSystem.Arg args)
        {
            if (args.Player() == null || !args.HasArgs(1))
                return;

            BasePlayer player = args.Player();

            switch (args.Args[0].ToLower())
            {
                case "switch":
                {
                    if (args.Args.Length != 2)
                    {
                        // PrintWarning($"DEBUG | {player.displayName} called Handler, but no args to switch!");
                        return;
                    }

                    string newSkill = args.Args[1];
                    if (!publicSkills.ContainsKey(newSkill))
                    {
                        // PrintWarning($"DEBUG | {player.displayName} called switch, but no skill with this name to switch!");
                        return;
                    }

                    CuiHelper.DestroyUi(player, MenuLayer);
                    playerSkills[player.userID].Switch(player, newSkill);
                    UI_ChooseSkill(player);
                    UI_CurrentProgress(player);
                    break;
                }
            }
        }

        [ChatCommand("skill")]
        private void cmdChatSkill(BasePlayer player) => UI_ChooseSkill(player);

        //[ChatCommand("testik")]
        private void cmdTest(BasePlayer player)
        {
            playerSkills[player.userID].AddPoints(player, 2);
        }

        #endregion

        #region GUI

        private void UI_CurrentProgress(BasePlayer player, bool avatarUpdate = true, bool levelUpdate = true, bool progressUpdate = true)
        {
            CuiElementContainer container = new CuiElementContainer();
            
            if (progressUpdate)
            {
                PlayerSkills playerSkill = playerSkills[player.userID];
                int levelNumber = playerSkill.skillLevels[playerSkill.ActiveSkill].Keys.ToList().IndexOf(playerSkill.ActiveLevel) + 1;
                var progress = playerSkill.skillLevels[playerSkill.ActiveSkill][playerSkill.ProgressLevel];
                
                CuiHelper.DestroyUi(player, CurrentLayer + ".progressUpdate"); 
                container.Add(new CuiElement
                {
                    FadeOut = 0.2f,
                    Name = CurrentLayer + ".progressUpdate",
                    Parent = CurrentLayer,
                    Components =
                    {
                        new CuiImageComponent { FadeIn = 0.2f, Color = "0.48 0.41 0.93 1.00" },
                        new CuiRectTransformComponent { AnchorMin = "0.143 0.15", AnchorMax = $"{Math.Min(0.15 + 0.857 * ((float) progress.CurrentPoints / progress.TotalPoints), 1)} 0.849", OffsetMax = "0 0"}
                    }
                });
                
                CuiHelper.DestroyUi(player, CurrentLayer + ".levelUpdate");
                
                container.Add(new CuiElement
                {
                    Name = CurrentLayer + ".levelUpdate",
                    Parent = CurrentLayer,
                    Components =
                    {
                        new CuiTextComponent { Text = $"УРОВЕНЬ: {levelNumber}", FontSize = 20, Font = "robotocondensed-bold.ttf", Align = TextAnchor.MiddleLeft},
                        new CuiRectTransformComponent { AnchorMin = "0.21 0", AnchorMax = "1 1", OffsetMax = "0 0"}
                    }
                });
            }
            
            if (avatarUpdate)
            {
                CuiHelper.DestroyUi(player, CurrentLayer + ".avatarUpdate");
                container.Add(new CuiElement
                {
                    Name = CurrentLayer + ".avatarUpdate",
                    Parent = CurrentLayer,
                    Components =
                    {
                        new CuiRawImageComponent { Png = (string) ImageLibrary.Call("GetImage", playerSkills[player.userID].ActiveSkill) },
                        new CuiRectTransformComponent { AnchorMin = "0 0", AnchorMax = "0 0", OffsetMin = "3.33333 3.33333", OffsetMax = "23.3333 23.3333"}
                    }
                });
            }
            
            CuiHelper.AddUi(player, container);
        }

        private void UI_ChooseSkill(BasePlayer player)
        {
            CuiHelper.DestroyUi(player, MenuLayer);
            CuiElementContainer container = new CuiElementContainer();

            container.Add(new CuiPanel
            {
                // Отрисовываем панель для ГУИ
                CursorEnabled = true,
                RectTransform = { AnchorMin = "0.09283856 0.2547454", AnchorMax = "0.09283856 0.2547454", OffsetMax = "1042 352" },
                Image = { Color = "0 0 0 0" }
            }, "Hud", MenuLayer);
            
            container.Add(new CuiButton
            {
                // Отрисовываем кнопку для закрытия на заднем плане
                RectTransform = { AnchorMin = "-100 -100", AnchorMax = "100 100", OffsetMax = "0 0" },
                Button = { Color = "0 0 0 0", Close = MenuLayer },
                Text = { Text = "" }
            }, MenuLayer);

            container.Add(new CuiElement
            {
                // Отрисовываем полноценный задник
                Parent = MenuLayer,
                Components =
                {
                    new CuiImageComponent { Color = "0 0 0 0.35" },
                    new CuiRectTransformComponent { AnchorMin = "0 0", AnchorMax = "1 1", OffsetMax = "0 0" },
                }
            });

            for (int i = 0; i < publicSkills.Count; i++)
            {
                if (!playerSkills.ContainsKey(player.userID))
                    return;

                var currentSkill = publicSkills.ElementAt(i);
                PlayerSkills playerSkill = playerSkills[player.userID];
                
                container.Add(new CuiElement
                {
                    // Отрисовываем задник для интерфейса
                    Parent = MenuLayer,
                    Name = MenuLayer + $".{currentSkill.Key}.Handler",
                    Components =
                    {
                        new CuiImageComponent { Color = "0 0 0 0.5" },
                        new CuiRectTransformComponent { AnchorMin = $"{0.007197953 + i * 0.165352} 0.022438414", AnchorMax = $"{0.1621337 + i * 0.165352} 0.9775616", OffsetMax = "0 0" }
                    }
                });
                
                container.Add(new CuiElement
                {
                    // Отрисовываем изображение для скилла
                    Parent = MenuLayer + $".{currentSkill.Key}.Handler",
                    Components =
                    {
                        new CuiRawImageComponent { Png = (string) ImageLibrary.Call("GetImage", currentSkill.Key) },
                        new CuiRectTransformComponent { AnchorMin = "0.2168479 0.6943213", AnchorMax = "0.7831521 0.9544452", OffsetMax = "0 0" }
                    }
                });
                
                
                container.Add(new CuiElement
                {
                    // Отрисовываем название для скилла
                    Parent = MenuLayer + $".{currentSkill.Key}.Handler",
                    Components =
                    {
                        new CuiTextComponent { Text = $"<color=>{currentSkill.Value.Name}</color>", Font = "robotocondensed-bold.ttf", FontSize = 16, Align = TextAnchor.MiddleCenter},
                        new CuiRectTransformComponent { AnchorMin = "0 0.6212121", AnchorMax = "1 0.6885524", OffsetMax = "0 0" }
                    }
                });
                
                container.Add(new CuiElement
                {
                    // Отрисовываем полосу для уровня для скиллаа
                    Name = MenuLayer + $".{currentSkill.Key}.Handler.LevelHandler",
                    Parent = MenuLayer + $".{currentSkill.Key}.Handler",
                    Components =
                    {
                        new CuiImageComponent { Color = "0 0 0 0.6" },
                        new CuiRectTransformComponent { AnchorMin = $"{0.05789989} 0.5577442", AnchorMax = $"{0.9214915} 0.6112121", OffsetMax = "0 0" }
                    }
                });
                

                int levelNumber = currentSkill.Value.skillAction.Keys.ToList().IndexOf(playerSkill.GetCurrentLevel(currentSkill.Key));
                var progress = playerSkill.skillLevels[currentSkill.Key][playerSkill.GetProgressLevel(currentSkill.Key)];
                float levelLine = (float) progress.CurrentPoints / progress.TotalPoints;
                
                container.Add(new CuiElement
                {
                    // Отрисовываем полосу для уровня для скиллаа
                    Parent = MenuLayer + $".{currentSkill.Key}.Handler.LevelHandler",
                    Components =
                    {
                        new CuiImageComponent { Color = "0.48 0.41 0.93 1.00" },
                        new CuiRectTransformComponent { AnchorMin = $"{0} 0", AnchorMax = $"{Math.Min(levelLine, 1)} 1", OffsetMax = "0 0" }
                    }
                });
                
                container.Add(new CuiElement
                {
                    // Отрисовываем полосу для уровня для скиллаа
                    Parent = MenuLayer + $".{currentSkill.Key}.Handler.LevelHandler",
                    Components =
                    {
                        new CuiTextComponent { Text = $"УРОВЕНЬ: {levelNumber + 1}", FontSize = 12, Font = "robotocondensed-bold.ttf", Align = TextAnchor.MiddleCenter },
                        new CuiRectTransformComponent { AnchorMin = $"{0} 0", AnchorMax = $"1 1", OffsetMax = "0 0" }
                    }
                });
                
                container.Add(new CuiElement
                {
                    // Отрисовываем полосу для уровня для скиллаа
                    Parent = MenuLayer + $".{currentSkill.Key}.Handler",
                    Components =
                    {
                        new CuiTextComponent { Text = $"{currentSkill.Value.Description.Replace("{0}", CONF_KritMultiplier.ToString())}", FontSize = 12, Font = "robotocondensed-regular.ttf", Align = TextAnchor.UpperCenter },
                        new CuiRectTransformComponent { AnchorMin = $"0.05 0.30", AnchorMax = $"0.95 0.53", OffsetMax = "0 0" },
						new CuiOutlineComponent { Color = "0 0 0 0.9", Distance = "0.6 0.6" }
                    }
                });

                string text = playerSkill.ActiveSkill == currentSkill.Key ? "<color=red>Используется</color>" : "<color=white>Использовать</color>";
                string command = playerSkill.ActiveSkill == currentSkill.Key ? "" : $"UI_SkillHandler switch {currentSkill.Key}";
                
                container.Add(new CuiButton
                {
                    RectTransform = { AnchorMin = "0.1 0.03", AnchorMax = "0.93 0.12", OffsetMax = "0 0" },
                    Text = { Text = text, FontSize = 16, Font = "robotocondensed-bold.ttf", Align = TextAnchor.MiddleCenter },
                    Button = { Command = command, Color = "0.42 0.36 0.96 1" }
                }, MenuLayer + $".{currentSkill.Key}.Handler");

                for (int skillIndex = 0; skillIndex < currentSkill.Value.skillAction.Count; skillIndex++)
                {
                    var currentProgress = currentSkill.Value.skillAction.ElementAt(skillIndex);
                    
                    container.Add(new CuiElement
                    {
                        Parent = MenuLayer + $".{currentSkill.Key}.Handler",
                        Components =
                        {
                            new CuiTextComponent { Text = $"<color=#7B68EE>Ур.{skillIndex+1}:   {currentSkill.Value.ActionName} +{currentProgress.Key}% </color>", FontSize = 13, Font = "robotocondensed-regular.ttf", Align = TextAnchor.MiddleLeft },
                            new CuiRectTransformComponent { AnchorMin = $"0.15 {0.145 + skillIndex * 0.04}", AnchorMax = $"1 {0.195 + skillIndex * 0.04}", OffsetMax = "0 0" },
							new CuiOutlineComponent { Color = "0 0 0 0.9", Distance = "0.6 0.6" }
                        }
                    });
                }
            }

            CuiHelper.AddUi(player, container);
        }

        #endregion

        #region Utils
        
        private static DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0);
        private static double LogTime() => DateTime.UtcNow.Subtract(epoch).TotalSeconds;

        #endregion
    }
}

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