C#:
// Reference: EasyAntiCheat.Server
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using ConVar;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using UnityEngine;
using WebSocketSharp;
using Pool = Facepunch.Pool;
using Random = UnityEngine.Random;
using Time = UnityEngine.Time;
namespace Oxide.Plugins {
[Info("Skills", "https://topplugin.ru/", "1.14.0")]
[Description("Adds a system of skills")]
public class Skills : RustPlugin {
#region Fields
[PluginReference]
private Plugin ImageLibrary, Notifications;
private const string Layer = "Com.Mevent.Main";
private static Skills _instance;
private readonly Dictionary<ulong, TimerPlayer> _timers = new Dictionary<ulong, TimerPlayer>();
private readonly List<uint> Containers = new List<uint>();
private CraftsController Controller;
private readonly Dictionary<SkillType, Skill> SkillByType = new Dictionary<SkillType, Skill>();
private class TimerPlayer {
public readonly Timer Timer;
public readonly float Chance;
public TimerPlayer(Timer timer, float chance) {
Timer = timer;
Chance = chance;
}
}
private enum SkillType {
Wood, Stones, Metal, Sulfur, Attack, Secure, Regeneration, Metabolism, ComponentsRates, StandUpChance, CraftSpeed, FastOven, Kits, None, Cloth, Butcher
}
#endregion
#region Config
private static Configuration _config;
private class Configuration {
[JsonProperty(PropertyName = "Команда | Command")]
public string Command = "skills";
[JsonProperty(PropertyName = "Автоматический вайп? | Automatic wipe?")]
public bool Wipe = true;
[JsonProperty(PropertyName = "Экономика | Economy")]
public EconomyPlugin Economy = new EconomyPlugin {
AddHook = "Deposit", BalanceHook = "Balance", RemoveHook = "Withdraw", Plug = "Economics"
}
;
[JsonProperty(PropertyName = "Оповещение о максимальном уровне | Maximum level alert")]
public INotify MaxLevel = new INotify {
Image = "warning", Url = "https://i.imgur.com/p3tKXJV.png", Delay = 0.9f
}
;
[JsonProperty(PropertyName = "Оповещение о нехватке баланса | Out of balance alert")]
public INotify NotMoney = new INotify {
Image = "warning", Url = "https://i.imgur.com/p3tKXJV.png", Delay = 0.9f
}
;
[JsonProperty(PropertyName = "Фон | Background")]
public IPanel Background = new IPanel {
AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = "0 0", OffsetMax = "0 0", Image = string.Empty, Color = new IColor("#0D1F4E", 95), isRaw = false, Sprite = "Assets/Content/UI/UI.Background.Tile.psd", Material = "Assets/Icons/IconMaterial.mat"
}
;
[JsonProperty(PropertyName = "Заглавие | Title")]
public IText Title = new IText {
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = "-150 300", OffsetMax = "150 360", Font = "robotocondensed-bold.ttf", Align = TextAnchor.MiddleCenter, FontSize = 38, Color = new IColor("#FFFFFF", 100)
}
;
[JsonProperty(PropertyName = "Назад | Back")]
public IText Back = new IText {
AnchorMin = "0 0.5", AnchorMax = "0 0.5", OffsetMin = "0 -40", OffsetMax = "65 40", Font = "robotocondensed-bold.ttf", Align = TextAnchor.MiddleCenter, FontSize = 60, Color = new IColor("#FFFFFF", 100)
}
;
[JsonProperty(PropertyName = "Вперёд | Next")]
public IText Next = new IText {
AnchorMin = "1 0.5", AnchorMax = "1 0.5", OffsetMin = "-65 -40", OffsetMax = "0 40", Font = "robotocondensed-bold.ttf", Align = TextAnchor.MiddleCenter, FontSize = 60, Color = new IColor("#FFFFFF", 100)
}
;
[JsonProperty(PropertyName = "Баланс | Balance")]
public IText BalanceText = new IText {
AnchorMin = "0.5 0", AnchorMax = "0.5 0", OffsetMin = "-150 0", OffsetMax = "150 75", Font = "robotocondensed-regular.ttf", Align = TextAnchor.MiddleCenter, FontSize = 24, Color = new IColor("#FFFFFF", 100)
}
;
[JsonProperty(PropertyName = "Включить иконку баланса | Enable Balance Icon")]
public bool EnableBalanceIcon;
[JsonProperty(PropertyName = "Иконка Баланса | Balance Icon")]
public BalanceIcon BalanceIcon = new BalanceIcon {
OffsetMinY = 20, OffsetMaxY = 55, Length = 35
}
;
[JsonProperty(PropertyName = "Закрыть | Close")]
public IText Close = new IText {
AnchorMin = "1 1", AnchorMax = "1 1", OffsetMin = "-35 -35", OffsetMax = "-5 -5", Font = "robotocondensed-bold.ttf", Align = TextAnchor.MiddleCenter, FontSize = 24, Color = new IColor("#FFFFFF", 100)
}
;
[JsonProperty(PropertyName = "Способность | Skill Panel")]
public SkillPanel SkillPanel = new SkillPanel {
Background = new SIPanel {
Image = string.Empty, Color = new IColor("#1D3676", 98), isRaw = false, Sprite = "Assets/Content/UI/UI.Background.Tile.psd", Material = "Assets/Icons/IconMaterial.mat", HeightCorrect = 5
}
, Image = new InterfacePosition {
AnchorMin = "0 0", AnchorMax = "0 0", OffsetMin = "10 10", OffsetMax = "160 160"
}
, Title = new IText {
AnchorMin = "0 0", AnchorMax = "1 0", OffsetMin = "165 135", OffsetMax = "-5 160", Align = TextAnchor.MiddleLeft, FontSize = 20, Font = "robotocondensed-bold.ttf", Color = new IColor("#FFFFFF", 100)
}
, Description = new IText {
AnchorMin = "0 0", AnchorMax = "1 0", OffsetMin = "165 30", OffsetMax = "-5 130", Align = TextAnchor.UpperLeft, FontSize = 14, Font = "robotocondensed-regular.ttf", Color = new IColor("#FFFFFF", 100)
}
, Button = new IButton {
AnchorMin = "1 0", AnchorMax = "1 0", OffsetMin = "-105 10", OffsetMax = "-10 30", AColor = new IColor("#B5FFC9", 100), DColor = new IColor("#B5FFC9", 25), TextUi = new IText {
AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = "0 0", OffsetMax = "0 0", Align = TextAnchor.MiddleCenter, FontSize = 14, Font = "robotocondensed-regular.ttf", Color = new IColor("#1D3676", 100)
}
}
, Cost = new IText {
AnchorMin = "1 0", AnchorMax = "1 0", OffsetMin = "-150 10", OffsetMax = "-110 30", Align = TextAnchor.MiddleRight, FontSize = 14, Font = "robotocondensed-regular.ttf", Color = new IColor("#FFFFFF", 100)
}
, AddCost = "$", EnableCostImage = false, AddCostImage = new IPanel {
AnchorMin = "1 0", AnchorMax = "1 0", OffsetMin = "-130 10", OffsetMax = "-110 30", Color = new IColor("#FFFFFF", 100), isRaw = true, Image = "https://i.imgur.com/5GdD0cU.png", Sprite = string.Empty, Material = string.Empty
}
, Stages = new IProgress {
AnchorMin = "0 0", AnchorMax = "0 0", OffsetMin = "160 10", OffsetMax = "160 10", Height = 20, Weidth = 10, Margin = 5, AColor = new IColor("#8C70D6", 100), DColor = new IColor("#8C70D6", 25)
}
, Count = 6, Height = 170, Width = 565, Margin = 20
}
;
[JsonProperty(PropertyName = "Способности | Skills", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<Skill> Skills = new List<Skill> {
new Skill {
Type = SkillType.Wood, Image = "https://gspics.org/images/2020/09/02/xz6Fy.png", Title = "Дровосек", Description = "Отвечает за добычу дерева\nИзучив способность, рейт добычи увеличивается на x1", Stages = new Dictionary<int, StageConf> {
[1]
= new StageConf(10, 133), [2] = new StageConf(25, 164), [3] = new StageConf(40, 200)
}
}
, new Skill {
Type = SkillType.Stones, Image = "https://gspics.org/images/2020/09/02/xz9mX.png", Title = "Камнедобыча", Description = "Отвечает за добычу камня\nИзучив способность, рейт добычи увеличивается на x1", Stages = new Dictionary<int, StageConf> {
[1]
= new StageConf(10, 133), [2] = new StageConf(25, 164), [3] = new StageConf(40, 200)
}
}
, new Skill {
Type = SkillType.Metal, Image = "https://gspics.org/images/2020/09/02/xznT3.png", Title = "Чернорабочий", Description = "Отвечает за добычу железной руды\nИзучив способность, рейт добычи увеличивается на x1", Stages = new Dictionary<int, StageConf> {
[1]
= new StageConf(10, 133), [2] = new StageConf(25, 164), [3] = new StageConf(40, 200)
}
}
, new Skill {
Type = SkillType.Sulfur, Image = "https://gspics.org/images/2020/09/02/xz4te.png", Title = "Серодобытчик", Description = "Отвечает за добычу серной руды\nИзучив способность, рейт добычи увеличивается на x1", Stages = new Dictionary<int, StageConf> {
[1]
= new StageConf(10, 133), [2] = new StageConf(25, 164), [3] = new StageConf(40, 200)
}
}
, new Skill {
Type = SkillType.Attack, Image = "https://gspics.org/images/2020/09/02/xzXza.png", Title = "Нападение", Description = "Изменяет величину урона любого оружия\nИзучив способность, Вы увеличите свой урон на 15%", Stages = new Dictionary<int, StageConf> {
[1]
= new StageConf(20, 5), [2] = new StageConf(35, 10), [3] = new StageConf(50, 15)
}
}
, new Skill {
Type = SkillType.Secure, Image = "https://gspics.org/images/2020/09/02/xzAfi.png", Title = "Защита", Description = "Изменяет величину урона любого оружия\nИзучив способность, Вы увеличите свою защиту на 15%", Stages = new Dictionary<int, StageConf> {
[1]
= new StageConf(20, 5), [2] = new StageConf(35, 10), [3] = new StageConf(50, 15)
}
}
, new Skill {
Type = SkillType.Regeneration, Image = "https://gspics.org/images/2020/09/02/xzGrO.png", Title = "Регенерация", Description = "Скоростная регенерация здоровья\nИзучив способность, Вы учеличите скорость регенерации на 90%", Stages = new Dictionary<int, StageConf> {
[1]
= new StageConf(10, 50), [2] = new StageConf(15, 70), [3] = new StageConf(20, 90)
}
}
, new Skill {
Type = SkillType.Metabolism, Image = "https://gspics.org/images/2020/09/02/xzWdI.png", Title = "Метаболизм", Description = "Изменяет восстановление жажды и голода\nИзучив способность, Вы получите восполнение каллорий и гидратации", Stages = new Dictionary<int, StageConf> {
[1]
= new StageConf(10, 0.5f), [2] = new StageConf(15, 1), [3] = new StageConf(20, 2)
}
}
, new Skill {
Type = SkillType.ComponentsRates, Image = "https://gspics.org/images/2020/09/02/xz15L.png", Title = "Рейты на компоненты", Description = "Изменяет рейты добываемых компонентов\nИзучив способность, найденные компоненты будут x4", Stages = new Dictionary<int, StageConf> {
[1]
= new StageConf(10, 2), [2] = new StageConf(15, 3), [3] = new StageConf(20, 4)
}
}
, new Skill {
Type = SkillType.StandUpChance, Image = "https://gspics.org/images/2020/09/02/xzTDD.png", Title = "Увеличение шанса встать", Description = "Увеличивает шанс подняться, когда вы ранены\nИзучив способность, шанс увеличивается с стандартных 20% до 50%", Stages = new Dictionary<int, StageConf> {
[1]
= new StageConf(10, 30), [2] = new StageConf(15, 40), [3] = new StageConf(20, 50)
}
}
, new Skill {
Type = SkillType.CraftSpeed, Image = "https://i.imgur.com/fAti1Cj.png", Title = "Скорость крафта", Description = "Ускоряет крафт.\nИзучив способность, вы сможете крафтить почти моментально", Stages = new Dictionary<int, StageConf> {
[1]
= new StageConf(10, 30), [2] = new StageConf(15, 40), [3] = new StageConf(20, 50)
}
}
, new Skill {
Type = SkillType.Kits, Image = "https://i.imgur.com/Log7sQR.png", Title = "Ускорение наборов", Description = "Ускоряет задержку между получением наборов", Stages = new Dictionary<int, StageConf> {
[1]
= new StageConf(10, 30), [2] = new StageConf(15, 40), [3] = new StageConf(20, 50)
}
}
, new Skill {
Type = SkillType.FastOven, Image = "https://i.imgur.com/IifHk5l.png", Title = "Ускорение печей", Description = "Ускорение плавки в печах", Stages = new Dictionary<int, StageConf> {
[1]
= new StageConf(10, 133), [2] = new StageConf(25, 164), [3] = new StageConf(40, 200)
}
}
, new Skill {
ID = 0, Type = SkillType.None, Image = "https://i.imgur.com/RqdcAm0.png", Title = "Сортировка", Description = "На каждом этапе открываются новые виды сортировки", Stages = new Dictionary<int, StageConf> {
[1]
= new StageConf(25, 0, new List<string> {
"grantperm %steamid% furnacesplitter.use"
}
), [2] = new StageConf(40, 0, new List<string> {
"grantperm %steamid% activesort.use"
}
)
}
}
, new Skill {
ID = 1, Type = SkillType.None, Image = "https://i.imgur.com/S4xulmj.png", Title = "Телепортация", Description = "Вы телепортируетесь быстрее с каждым этапом", Stages = new Dictionary<int, StageConf> {
[1]
= new StageConf(30, 0, new List<string> {
"grantperm %steamid% nteleportation.vip"
}
), [2] = new StageConf(50, 0, new List<string> {
"grantperm %steamid% nteleportation.premium"
}
), [2] = new StageConf(80, 0, new List<string> {
"grantperm %steamid% nteleportation.deluxe"
}
)
}
}
, new Skill {
Type = SkillType.Cloth, Image = "https://i.imgur.com/5fixMch.png", Title = "Сборщик конопли", Description = "Отвечает за сбор ткани\nИзучив способность, рейт добычи увеличивается на x1", Stages = new Dictionary<int, StageConf> {
[1]
= new StageConf(10, 133), [2] = new StageConf(25, 164), [3] = new StageConf(40, 200)
}
}
, new Skill {
Type = SkillType.Butcher, Image = "https://i.imgur.com/4WlHK7u.png", Title = "Butcher", Description = "Отвечает за добычу животных\nИзучив способность, рейт добычи увеличивается на x1", Stages = new Dictionary<int, StageConf> {
[1]
= new StageConf(10, 133), [2] = new StageConf(25, 164), [3] = new StageConf(40, 200)
}
}
}
;
[JsonProperty(PropertyName = "Животные | Animals", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<string> Animals = new List<string> {
"chicken.corpse", "boar.corpse", "bear.corpse", "wolf.corpse", "stag.corpse"
}
;
[JsonProperty(PropertyName = "Чёрный список печей | Ovens Black List", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<string> OvensBlackList = new List<string> {
"entity shortnameprefab 1", "entity shortnameprefab 2"
}
;
}
private class INotify {
[JsonProperty(PropertyName = "Ключ изображения | Image Key")]
public string Image;
[JsonProperty(PropertyName = "Ссылка на изображение | Image Url")]
public string Url;
[JsonProperty(PropertyName = "Время показа | Show Time")]
public float Delay;
}
private class EconomyPlugin {
[JsonProperty(PropertyName = "Функция пополнения баланса | Balance add hook")]
public string AddHook;
[JsonProperty(PropertyName = "Функция снятия баланса | Balance remove hook")]
public string RemoveHook;
[JsonProperty(PropertyName = "Функция показа баланса | Balance show hook")]
public string BalanceHook;
[JsonProperty(PropertyName = "Название плагина | Plugin name")]
public string Plug;
public int ShowBalance(BasePlayer player) {
var plugin = _instance?.plugins.Find(Plug);
if (plugin == null) return 0;
switch (Plug) {
case "IQEconomic" : return Convert.ToInt32(plugin.Call(BalanceHook, player.userID));
default : return Convert.ToInt32(plugin.Call(BalanceHook, player.UserIDString));
}
}
public void AddBalance(BasePlayer player, int amount) {
var plugin = _instance?.plugins.Find(Plug);
if (plugin == null) return;
switch (Plug) {
case "Economics" : plugin.Call(AddHook, player.UserIDString, (double) amount);
break;
case "IQEconomic" : plugin.Call(AddHook, player.userID, amount);
break;
default : plugin.Call(AddHook, player.UserIDString, amount);
break;
}
}
public bool RemoveBalance(BasePlayer player, int amount) {
if (ShowBalance(player) < amount) return false;
var plugin = _instance?.plugins.Find(Plug);
if (plugin == null) return false;
switch (Plug) {
case "Economics" : plugin.Call(RemoveHook, player.UserIDString, (double) amount);
break;
case "IQEconomic" : plugin.Call(RemoveHook, player.userID, amount);
break;
default : plugin.Call(RemoveHook, player.UserIDString, amount);
break;
}
return true;
}
}
private class Skill {
[JsonProperty(PropertyName = "Тип | Type")]
[JsonConverter(typeof(StringEnumConverter))]
public SkillType Type;
[JsonProperty(PropertyName = "ID (для/for None)")]
public int ID;
[JsonProperty(PropertyName = "Изображение | Image")]
public string Image;
[JsonProperty(PropertyName = "Название | Title")]
public string Title;
[JsonProperty(PropertyName = "Описание | Description")]
public string Description;
[JsonProperty(PropertyName = "Уровни | Levels", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<int, StageConf> Stages;
}
private class StageConf {
[JsonProperty(PropertyName = "Стоимость | Cost")]
public float Cost;
[JsonProperty(PropertyName = "Значение [метаболизм - значение, шанс встать - шанс, для всех остальных процент %] | VALUE")]
public float Value;
[JsonProperty(PropertyName = "Команды | Commands", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<string> Commands;
public StageConf(float cost, float value) {
Cost = cost;
Value = value;
Commands = new List<string>();
}
[JsonConstructor]
public StageConf(float cost, float value, List<string> commands) {
Cost = cost;
Value = value;
Commands = commands;
}
public void GetCommands(BasePlayer player) {
Commands?.ForEach(command => {
command = command.Replace("\n", "|").Replace("%steamid%", player.UserIDString, StringComparison.OrdinalIgnoreCase).Replace("%username%", player.displayName, StringComparison.OrdinalIgnoreCase);
foreach (var check in command.Split('|')) _instance?.Server.Command(check);
}
);
}
}
private class BalanceIcon {
[JsonProperty(PropertyName = "Offset Min Y")]
public float OffsetMinY;
[JsonProperty(PropertyName = "Offset Max Y")]
public float OffsetMaxY;
[JsonProperty(PropertyName = "Длина | Length")]
public float Length;
}
private class SkillPanel {
[JsonProperty(PropertyName = "Фон | Background")]
public SIPanel Background;
[JsonProperty(PropertyName = "Изображение | Image")]
public InterfacePosition Image;
[JsonProperty(PropertyName = "Заглавие | Title")]
public IText Title;
[JsonProperty(PropertyName = "Описание | Description")]
public IText Description;
[JsonProperty(PropertyName = "Кнопка | Button")]
public IButton Button;
[JsonProperty(PropertyName = "Стоимость | Cost")]
public IText Cost;
[JsonProperty(PropertyName = "Приписка к стоимости | Add to cost")]
public string AddCost;
[JsonProperty(PropertyName = "Включить пририску к стоимости (изображение) | Enable Add to cost (image)")]
public bool EnableCostImage;
[JsonProperty(PropertyName = "Приписка к стоимости (изображение) | Add to cost (image)")]
public IPanel AddCostImage;
[JsonProperty(PropertyName = "Уровни | Levels")]
public IProgress Stages;
[JsonProperty(PropertyName = "Количество на страницу | Count On Page")]
public int Count;
[JsonProperty(PropertyName = "Высота | Height")]
public float Height;
[JsonProperty(PropertyName = "Ширина | Width")]
public float Width;
[JsonProperty(PropertyName = "Отступ | Margin")]
public float Margin;
public void Get(ref CuiElementContainer container, string layer, int page, string parent, int index, BasePlayer player, Skill skill, float oMinX, float oMinY, float oMaxX, float oMaxY) {
Background?.Get(ref container, parent, parent + $".Skill.{index}", oMinX, oMinY, oMaxX, oMaxY);
container.Add(new CuiElement {
Parent = parent + $".Skill.{index}", Components = {
new CuiRawImageComponent {
Png = _instance?.ImageLibrary?.Call<string>("GetImage", skill.Image)
}
, new CuiRectTransformComponent {
AnchorMin = Image.AnchorMin, AnchorMax = Image.AnchorMax, OffsetMin = Image.OffsetMin, OffsetMax = Image.OffsetMax
}
}
}
);
Title?.Get(ref container, parent + $".Skill.{index}", null, skill.Title);
Description?.Get(ref container, parent + $".Skill.{index}", null, skill.Description);
var cost = _instance?.GetNextPrice(player.userID, skill) ?? -1;
Button?.Get(ref container, player, parent + $".Skill.{index}", null, $"UI_Skills upgrade {skill.Type} {page} {layer}", "", cost > 0);
if (cost > 0) Cost?.Get(ref container, parent + $".Skill.{index}", null, $"{cost}{AddCost}");
#region Stages
container.Add(new CuiPanel {
RectTransform = {
AnchorMin = Stages.AnchorMin, AnchorMax = Stages.AnchorMax, OffsetMin = Stages.OffsetMin, OffsetMax = Stages.OffsetMax
}
, Image = {
Color = "0 0 0 0"
}
}
, parent + $".Skill.{index}", parent + $".Skill.{index}.Stages");
var skillData = _instance?.GetPlayerData(player.userID)?.Skills ?.FirstOrDefault(x => x.Type == skill.Type);
var xSwitch = 0f;
foreach (var i in skill.Stages.Keys) {
var color = skillData != null && i <= skillData.Stage ? Stages.AColor : Stages.DColor;
container.Add(new CuiPanel {
RectTransform = {
AnchorMin = "0 0", AnchorMax = "0 0", OffsetMin = $"{xSwitch} 0", OffsetMax = $"{xSwitch + Stages.Weidth} {Stages.Height}"
}
, Image = {
Color = color.Get()
}
}
, parent + $".Skill.{index}.Stages", parent + $".Skill.{index}.Stages.{i}");
xSwitch += Stages.Weidth + Stages.Margin;
}
#endregion
}
}
private class IProgress : InterfacePosition {
[JsonProperty(PropertyName = "Высота | Height")]
public float Height;
[JsonProperty(PropertyName = "Ширина | Weidth")]
public float Weidth;
[JsonProperty(PropertyName = "Отступ | Margin")]
public float Margin;
[JsonProperty(PropertyName = "Активный цвет | Active Color")]
public IColor AColor;
[JsonProperty(PropertyName = "Не активный цвет | No Active Color")]
public IColor DColor;
}
private class IButton : InterfacePosition {
[JsonProperty(PropertyName = "Цвет | Color")]
public IColor AColor;
[JsonProperty(PropertyName = "Не активный цвет | No Active Color")]
public IColor DColor;
[JsonProperty(PropertyName = "Настройка текста | Text Setting")]
public IText TextUi;
public void Get(ref CuiElementContainer container, BasePlayer player, string parent, string name = null, string cmd = "", string close = "", bool color = true) {
if (name.IsNullOrEmpty()) name = CuiHelper.GetGuid();
container.Add(new CuiPanel {
RectTransform = {
AnchorMin = AnchorMin, AnchorMax = AnchorMax, OffsetMin = OffsetMin, OffsetMax = OffsetMax
}
, Image = {
Color = color ? AColor.Get() : DColor.Get()
}
}
, parent, name);
TextUi?.Get(ref container, name, null, _instance.Msg(Upgrade, player.UserIDString));
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "0 0", AnchorMax = "1 1"
}
, Text = {
Text = ""
}
, Button = {
Command = cmd, Close = close, Color = "0 0 0 0"
}
}
, name);
}
}
private class SIPanel {
[JsonProperty(PropertyName = "Изображение | Image")]
public string Image;
[JsonProperty(PropertyName = "Цвет | Color")]
public IColor Color;
[JsonProperty(PropertyName = "Сохранять цвет изображения? | Save Image Color")]
public bool isRaw;
[JsonProperty(PropertyName = "Sprite")]
public string Sprite;
[JsonProperty(PropertyName = "Material")]
public string Material;
[JsonProperty(PropertyName = "Отклонение по высоте | Height deviation")]
public float HeightCorrect;
public void Get(ref CuiElementContainer container, string parent = "Hud", string name = null, float oMinX = 0, float oMinY = 0, float oMaxX = 0, float oMaxY = 0) {
if (string.IsNullOrEmpty(name)) name = CuiHelper.GetGuid();
if (isRaw) container.Add(new CuiElement {
Name = name, Parent = parent, Components = {
new CuiRawImageComponent {
Png = !string.IsNullOrEmpty(Image) ? _instance.ImageLibrary.Call<string>("GetImage", Image) : null, Color = Color.Get(), Material = Material, Sprite = !Sprite.IsNullOrEmpty() ? Sprite : "Assets/Icons/rust.png"
}
, new CuiRectTransformComponent {
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = $"{oMinX} {oMinY + HeightCorrect}", OffsetMax = $"{oMaxX} {oMaxY + HeightCorrect}"
}
}
}
);
else container.Add(new CuiPanel {
RectTransform = {
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = $"{oMinX} {oMinY + HeightCorrect}", OffsetMax = $"{oMaxX} {oMaxY + HeightCorrect}"
}
, Image = {
Png = !string.IsNullOrEmpty(Image) ? _instance.ImageLibrary.Call<string>("GetImage", Image) : null, Color = Color.Get(), Sprite = !Sprite.IsNullOrEmpty() ? Sprite : "Assets/Content/UI/UI.Background.Tile.psd", Material = !Material.IsNullOrEmpty() ? Material : "Assets/Icons/IconMaterial.mat"
}
}
, parent, name);
}
}
private class InterfacePosition {
public string AnchorMin;
public string AnchorMax;
public string OffsetMin;
public string OffsetMax;
}
private class IColor {
[JsonProperty(PropertyName = "HEX")]
public string HEX;
[JsonProperty(PropertyName = "Непрозрачность | Opacity (0 - 100)")]
public float Alpha;
public string Get() {
if (string.IsNullOrEmpty(HEX)) HEX = "#FFFFFF";
var str = HEX.Trim('#');
if (str.Length != 6) throw new Exception(HEX);
var r = byte.Parse(str.Substring(0, 2), NumberStyles.HexNumber);
var g = byte.Parse(str.Substring(2, 2), NumberStyles.HexNumber);
var b = byte.Parse(str.Substring(4, 2), NumberStyles.HexNumber);
return $"{(double) r / 255} {(double) g / 255} {(double) b / 255} {Alpha / 100}";
}
public IColor(string hex, float alpha) {
HEX = hex;
Alpha = alpha;
}
}
private class IPanel : InterfacePosition {
[JsonProperty(PropertyName = "Изображение | Image")]
public string Image;
[JsonProperty(PropertyName = "Цвет | Color")]
public IColor Color;
[JsonProperty(PropertyName = "Сохранять цвет изображения? | Save Image Color")]
public bool isRaw;
[JsonProperty(PropertyName = "Sprite")]
public string Sprite;
[JsonProperty(PropertyName = "Material")]
public string Material;
public void Get(ref CuiElementContainer container, string parent = "Hud", string name = null, bool cursor = false) {
if (string.IsNullOrEmpty(name)) name = CuiHelper.GetGuid();
if (isRaw) {
var element = new CuiElement {
Name = name, Parent = parent, Components = {
new CuiRawImageComponent {
Png = !string.IsNullOrEmpty(Image) ? _instance.ImageLibrary.Call<string>("GetImage", Image) : null, Color = Color.Get(), Material = Material, Sprite = !Sprite.IsNullOrEmpty() ? Sprite : "Assets/Icons/rust.png"
}
, new CuiRectTransformComponent {
AnchorMin = AnchorMin, AnchorMax = AnchorMax, OffsetMin = OffsetMin, OffsetMax = OffsetMax
}
}
}
;
if (cursor) element.Components.Add(new CuiNeedsCursorComponent());
container.Add(element);
}
else {
container.Add(new CuiPanel {
RectTransform = {
AnchorMin = AnchorMin, AnchorMax = AnchorMax, OffsetMin = OffsetMin, OffsetMax = OffsetMax
}
, Image = {
Png = !string.IsNullOrEmpty(Image) ? _instance.ImageLibrary.Call<string>("GetImage", Image) : null, Color = Color.Get(), Sprite = !Sprite.IsNullOrEmpty() ? Sprite : "Assets/Content/UI/UI.Background.Tile.psd", Material = !Material.IsNullOrEmpty() ? Material : "Assets/Icons/IconMaterial.mat"
}
, CursorEnabled = cursor
}
, parent, name);
}
}
}
private class IText : InterfacePosition {
[JsonProperty(PropertyName = "Font Size")]
public int FontSize;
[JsonProperty(PropertyName = "Font")]
public string Font;
[JsonProperty(PropertyName = "Align")]
[JsonConverter(typeof(StringEnumConverter))]
public TextAnchor Align;
[JsonProperty(PropertyName = "Text Color")]
public IColor Color;
public void Get(ref CuiElementContainer container, string parent = "Hud", string name = null, string text = "", bool enableIcon = false) {
if (string.IsNullOrEmpty(name)) name = CuiHelper.GetGuid();
container.Add(new CuiLabel {
RectTransform = {
AnchorMin = AnchorMin, AnchorMax = AnchorMax, OffsetMin = OffsetMin, OffsetMax = OffsetMax
}
, Text = {
Text = $"{text}", Align = Align, FontSize = FontSize, Color = Color.Get(), Font = Font
}
}
, parent, name);
if (enableIcon) {
var length = text.Length * FontSize * 0.225f;
container.Add(new CuiElement {
Parent = parent, Components = {
new CuiRawImageComponent {
Png = _instance.ImageLibrary.Call<string>("GetImage", _config.SkillPanel.AddCostImage.Image)
}
, new CuiRectTransformComponent {
AnchorMin = AnchorMin, AnchorMax = AnchorMax, OffsetMin = $"{length} {_config.BalanceIcon.OffsetMinY}", OffsetMax = $"{length + _config.BalanceIcon.Length} {_config.BalanceIcon.OffsetMaxY}"
}
}
}
);
}
}
}
protected override void LoadConfig() {
base.LoadConfig();
try {
_config = Config.ReadObject<Configuration>();
if (_config == null) throw new Exception();
SaveConfig();
}
catch {
PrintError("Your configuration file contains an error.Using default configuration values.");
LoadDefaultConfig();
}
}
protected override void SaveConfig() {
Config.WriteObject(_config);
}
protected override void LoadDefaultConfig() {
_config = new Configuration();
}
#endregion
#region Data
private static PluginData _data;
private void SaveData() {
Interface.Oxide.DataFileSystem.WriteObject(Name, _data);
}
private void LoadData() {
try {
_data = Interface.Oxide.DataFileSystem.ReadObject<PluginData>(Name);
}
catch (Exception e) {
PrintError(e.ToString());
}
if (_data == null) _data = new PluginData();
}
private class PluginData {
[JsonProperty(PropertyName = "Players", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<ulong, PlayerData> Players = new Dictionary<ulong, PlayerData>();
}
private class PlayerData {
[JsonProperty(PropertyName = "Skills", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<SkillData> Skills = new List<SkillData>();
public SkillData GetSkill(SkillType type, int id = 0) {
if (type == SkillType.None) foreach (var skillData in Skills.FindAll(x => x.Type == SkillType.None && x.ID == id)) {
if (skillData.Skill == null) skillData.Skill = _config.Skills.Find(x => x.Type == SkillType.None && x.ID == id);
return skillData;
}
else foreach (var data in Skills) {
var skill = _instance.FindByType(data.Type);
if (skill == null || skill.Type != type) continue;
data.Skill = skill;
return data;
}
return null;
}
}
private class SkillData {
[JsonProperty(PropertyName = "Type")]
[JsonConverter(typeof(StringEnumConverter))]
public SkillType Type;
[JsonProperty(PropertyName = "ID")]
public int ID;
[JsonProperty(PropertyName = "Stage")]
public int Stage;
[JsonIgnore]
public Skill Skill;
}
private PlayerData GetPlayerData(BasePlayer player) {
return GetPlayerData(player.userID);
}
private PlayerData GetPlayerData(ulong user) {
if (!user.IsSteamId()) return null;
if (!_data.Players.ContainsKey(user)) _data.Players.Add(user, new PlayerData());
return _data.Players[user];
}
private float GetNextPrice(ulong user, Skill skill) {
var result = -1;
var data = GetPlayerData(user);
if (data == null) return result;
var skillData = data.GetSkill(skill.Type, skill.ID);
if (skillData == null) return skill.Stages[1].Cost;
var nextStage = skillData.Stage + 1;
if (!skill.Stages.ContainsKey(nextStage)) return result;
return skill.Stages[nextStage].Cost;
}
#endregion
#region Hooks
private void Init() {
_instance = this;
LoadData();
Controller = new GameObject("Craft Controller").AddComponent<CraftsController>();
}
private void OnServerInitialized() {
if (!ImageLibrary) {
PrintWarning("IMAGE LIBRARY IS NOT INSTALLED.");
}
else {
if (!_config.Background.Image.IsNullOrEmpty()) ImageLibrary.Call("AddImage", _config.Background.Image, _config.Background.Image);
if (!_config.SkillPanel.Background.Image.IsNullOrEmpty()) ImageLibrary.Call("AddImage", _config.SkillPanel.Background.Image, _config.SkillPanel.Background.Image);
if (!_config.SkillPanel.AddCostImage.Image.IsNullOrEmpty()) ImageLibrary.Call("AddImage", _config.SkillPanel.AddCostImage.Image, _config.SkillPanel.AddCostImage.Image);
Notifications?.Call("AddImage", _config.MaxLevel.Image, _config.MaxLevel.Url);
Notifications?.Call("AddImage", _config.NotMoney.Image, _config.NotMoney.Url);
_config.Skills.ForEach(skill => {
if (!skill.Image.IsNullOrEmpty()) ImageLibrary.Call("AddImage", skill.Image, skill.Image);
}
);
}
_config.Skills.ForEach(skill => {
if (skill.Type == SkillType.None) return;
skill.ID = 0;
if (SkillByType.ContainsKey(skill.Type)) {
PrintError($"DUBLICATE SKILL TYPE: {skill.Type}");
return;
}
SkillByType.Add(skill.Type, skill);
}
);
CheckOnDuplicates();
foreach (var check in _data.Players) check.Value.Skills.ForEach(skill => skill.Skill = FindByType(skill.Type));
AddCovalenceCommand(_config.Command, nameof(CmdOpenUi));
AddCovalenceCommand(new[] {
"giveallskills", "giveskill"
}
, nameof(AdminCommands));
}
private void OnServerSave() {
timer.In(Random.Range(2f, 7f), SaveData);
}
private void Unload() {
foreach (var player in BasePlayer.activePlayerList) CuiHelper.DestroyUi(player, Layer);
SaveData();
if (Controller != null) Controller.Kill();
_instance = null;
_config = null;
_data = null;
}
private void OnNewSave(string filename) {
if (!_config.Wipe) return;
_data.Players.Clear();
SaveData();
}
#region Gather
private void OnCollectiblePickup(Item item, BasePlayer player) {
OnGather(player, item);
}
private void OnGrowableGathered(GrowableEntity plant, Item item, BasePlayer player) {
OnGather(player, item);
}
private void OnDispenserBonus(ResourceDispenser dispenser, BasePlayer player, Item item) {
OnGather(player, item, dispenser);
}
private void OnDispenserGather(ResourceDispenser dispenser, BasePlayer player, Item item) {
OnGather(player, item, dispenser);
}
#endregion
#region Damage
private void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info) {
if (entity == null || info == null) return;
var amount = 1f;
var attacker = info.InitiatorPlayer;
if (attacker != null) {
var data = GetPlayerData(attacker);
var dataSkill = data?.GetSkill(SkillType.Attack);
var skill = dataSkill?.Skill;
if (skill != null) {
amount = 1f + skill.Stages[dataSkill.Stage].Value / 100f;
info.damageTypes.ScaleAll(amount);
}
}
var target = entity as BasePlayer;
if (target != null) {
var data = GetPlayerData(target);
var dataSkill = data?.GetSkill(SkillType.Secure);
var skill = dataSkill?.Skill;
if (skill != null) {
amount -= skill.Stages[dataSkill.Stage].Value / 100f;
info.damageTypes.ScaleAll(amount);
}
}
}
#endregion
#region Regeneration
private void OnRunPlayerMetabolism(PlayerMetabolism metabolism, BasePlayer player, float delta) {
if (metabolism == null || player == null) return;
var data = GetPlayerData(player);
if (data == null) return;
if (metabolism.pending_health.value > 0.0) {
var regen = data.GetSkill(SkillType.Regeneration);
var skill = regen?.Skill;
if (skill != null) {
var num12 = Mathf.Min(1f * delta, metabolism.pending_health.value);
var value = num12 * (skill.Stages[regen.Stage].Value / 100f);
player.Heal(value);
if (player.healthFraction == 1.0) metabolism.pending_health.value = 0.0f;
else metabolism.pending_health.Subtract(value);
}
}
var met = data.GetSkill(SkillType.Metabolism);
if (met != null) {
var skill = met.Skill;
if (skill != null) {
var value = skill.Stages[met.Stage].Value;
player.metabolism.hydration.Add(value);
player.metabolism.calories.Add(value);
}
}
}
#endregion
#region Loot
private void OnLootEntity(BasePlayer player, LootContainer container) {
if (player == null || container == null || container.net == null || container.inventory == null) return;
var id = container.net.ID;
if (Containers.Contains(id)) return;
var skillData = GetPlayerData(player)?.GetSkill(SkillType.ComponentsRates);
var skill = skillData?.Skill;
if (skill == null || !skill.Stages.ContainsKey(skillData.Stage)) return;
var value = skill.Stages[skillData.Stage].Value;
container.inventory.itemList.ForEach(item => {
if (item != null && item.info.category == ItemCategory.Component) item.amount = (int) (value * item.amount);
}
);
Containers.Add(id);
}
private void OnContainerDropItems(ItemContainer container) {
if (container == null) return;
var entity = container.entityOwner as LootContainer;
if (entity == null || !entity.name.Contains("barrel")) return;
var player = entity.lastAttacker as BasePlayer;
if (player == null) return;
var skillData = GetPlayerData(player)?.GetSkill(SkillType.ComponentsRates);
var skill = skillData?.Skill;
// ... [Code preview truncated due to length. Full source in attached file] ...