Advertisement
MONaH-Rasta

ZLevelsRemastered

Aug 5th, 2020
169
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 67.05 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Reflection;
  6. using Oxide.Core;
  7. using Oxide.Core.Database;
  8. using Oxide.Core.Plugins;
  9. using Oxide.Core.Libraries;
  10. using Oxide.Core.Libraries.Covalence;
  11. using Oxide.Game.Rust.Cui;
  12. using UnityEngine;
  13.  
  14. namespace Oxide.Plugins
  15. {
  16.     [Info("ZLevels Remastered", "Default", "2.9.10")]
  17.     [Description("Lets players level up as they harvest different resources and when crafting")]
  18.     class ZLevelsRemastered : RustPlugin
  19.     {
  20.         #region Variables
  21.  
  22.         [PluginReference]
  23.         Plugin EventManager;
  24.  
  25.         bool Changed = false;
  26.         bool initialized;
  27.         bool bonusOn = false;
  28.         static ZLevelsRemastered zLevels = null;
  29.  
  30.         Dictionary<string, ItemDefinition> CraftItems;
  31.         CraftData _craftData;
  32.         PlayerData playerPrefs = new PlayerData();
  33.         bool newSaveDetected = false;
  34.  
  35.         private long[] levelAnnounce =
  36.             {10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200};
  37.  
  38.         int MaxB = 10001;
  39.         int MinB = 10;
  40.  
  41.         #endregion Variables
  42.  
  43.         #region Config
  44.  
  45.         int gameProtocol;
  46.         int penaltyMinutes;
  47.         bool penaltyOnDeath;
  48.         bool wipeDataOnNewSave;
  49.         bool enablePermission;
  50.         bool enableNightBonus;
  51.         bool logEnabledBonusConsole;
  52.         bool broadcastEnabledBonus;
  53.         bool enableLevelupBroadcast;
  54.         string permissionName;
  55.         string permissionNameXP;
  56.         string pluginPrefix;
  57.         bool playerCuiDefaultEnabled;
  58.         bool playerPluginDefaultEnabled;
  59.         bool excludeWeaponsOnGather;
  60.         bool excludeJackhammerOnGather;
  61.         bool excludeChainsawOnGather;
  62.         bool enableDispenserGather;
  63.         bool enableCollectiblePickup;
  64.         bool enableCropGather;
  65.  
  66.         Dictionary<string, object> enabledCollectibleEntity;
  67.         Dictionary<string, object> defaultMultipliers;
  68.         Dictionary<string, object> resourceMultipliers;
  69.         Dictionary<string, object> resourceMultipliersAtNight;
  70.         Dictionary<string, object> resourceMultipliersCurrent;
  71.         Dictionary<string, object> levelCaps;
  72.         Dictionary<string, object> pointsPerHit;
  73.         Dictionary<string, object> pointsPerHitAtNight;
  74.         Dictionary<string, object> pointsPerHitCurrent;
  75.         Dictionary<string, object> craftingDetails;
  76.         Dictionary<string, object> percentLostOnDeath;
  77.         Dictionary<string, object> colors;
  78.  
  79.         Dictionary<string, int> skillIndex;
  80.         Dictionary<string, object> cuiColors;
  81.         bool cuiEnabled;
  82.         int cuiFontSizeLvl;
  83.         int cuiFontSizeBar;
  84.         int cuiFontSizePercent;
  85.         string cuiFontColor;
  86.         bool cuiTextShadow;
  87.         string cuiXpBarBackground;
  88.         string cuiBoundsBackground;
  89.         Dictionary<string, object> cuiPositioning;
  90.  
  91.         protected override void LoadDefaultConfig()
  92.         {
  93.             Config.Clear();
  94.             LoadVariables();
  95.         }
  96.  
  97.         object GetConfig(string menu, string datavalue, object defaultValue)
  98.         {
  99.             var data = Config[menu] as Dictionary<string, object>;
  100.             if (data == null)
  101.             {
  102.                 data = new Dictionary<string, object>();
  103.                 Config[menu] = data;
  104.                 Changed = true;
  105.             }
  106.             object value;
  107.             if (!data.TryGetValue(datavalue, out value))
  108.             {
  109.                 value = defaultValue;
  110.                 data[datavalue] = value;
  111.                 Changed = true;
  112.             }
  113.             return value;
  114.         }
  115.  
  116.         void LoadVariables()
  117.         {
  118.             gameProtocol = Convert.ToInt32(GetConfig("Generic", "gameProtocol", Rust.Protocol.network));
  119.             penaltyMinutes = Convert.ToInt32(GetConfig("Generic", "penaltyMinutes", 10));
  120.             penaltyOnDeath = Convert.ToBoolean(GetConfig("Generic", "penaltyOnDeath", true));
  121.             wipeDataOnNewSave = Convert.ToBoolean(GetConfig("Generic", "wipeDataOnNewSave", false));
  122.             enablePermission = Convert.ToBoolean(GetConfig("Generic", "enablePermission", false));
  123.             permissionName = Convert.ToString(GetConfig("Generic", "permissionName", "zlevelsremastered.use"));
  124.             permissionNameXP = Convert.ToString(GetConfig("Generic", "permissionNameXP", "zlevelsremastered.noxploss"));
  125.             pluginPrefix = Convert.ToString(GetConfig("Generic", "pluginPrefix", "<color=orange>ZLevels</color>:"));
  126.             enableLevelupBroadcast = Convert.ToBoolean(GetConfig("Generic", "enableLevelupBroadcast", false));
  127.             playerCuiDefaultEnabled = Convert.ToBoolean(GetConfig("Generic", "playerCuiDefaultEnabled", true));
  128.             playerPluginDefaultEnabled = Convert.ToBoolean(GetConfig("Generic", "playerPluginDefaultEnabled", true));
  129.             excludeWeaponsOnGather =  Convert.ToBoolean(GetConfig("Generic", "exludeWeaponsOnGather", false));
  130.             excludeJackhammerOnGather =  Convert.ToBoolean(GetConfig("Generic", "excludeJackhammerOnGather", true));
  131.             excludeChainsawOnGather =  Convert.ToBoolean(GetConfig("Generic", "excludeChainsawOnGather", true));
  132.  
  133.             enableDispenserGather =  Convert.ToBoolean(GetConfig("Functions", "enableDispenserGather", true));
  134.             enableCollectiblePickup = Convert.ToBoolean(GetConfig("Functions", "enableCollectiblePickup", true));
  135.             enableCropGather = Convert.ToBoolean(GetConfig("Functions", "enableCropGather", true));
  136.  
  137.             enabledCollectibleEntity = (Dictionary<string, object>)GetConfig("Functions", "CollectibleEntitys", new Dictionary<string, object>());
  138.  
  139.             defaultMultipliers = (Dictionary<string, object>)GetConfig("Settings", "DefaultResourceMultiplier", new Dictionary<string, object>{
  140.                 {Skills.WOODCUTTING, 1},
  141.                 {Skills.MINING, 1},
  142.                 {Skills.SKINNING, 1},
  143.                 {Skills.ACQUIRE, 1}
  144.             });
  145.  
  146.             resourceMultipliers = (Dictionary<string, object>)GetConfig("Settings", "ResourcePerLevelMultiplier", new Dictionary<string, object>{
  147.                 {Skills.WOODCUTTING, 2},
  148.                 {Skills.MINING, 2},
  149.                 {Skills.SKINNING, 2},
  150.                 {Skills.ACQUIRE, 2}
  151.             });
  152.             levelCaps = (Dictionary<string, object>)GetConfig("Settings", "LevelCaps", new Dictionary<string, object>{
  153.                 {Skills.WOODCUTTING, 200},
  154.                 {Skills.MINING, 200},
  155.                 {Skills.SKINNING, 200},
  156.                 {Skills.ACQUIRE, 200},
  157.                 {Skills.CRAFTING, -1}
  158.  
  159.             });
  160.             pointsPerHit = (Dictionary<string, object>)GetConfig("Settings", "PointsPerHit", new Dictionary<string, object>{
  161.                 {Skills.WOODCUTTING, 30},
  162.                 {Skills.MINING, 30},
  163.                 {Skills.SKINNING, 30},
  164.                 {Skills.ACQUIRE, 30}
  165.             });
  166.             craftingDetails = (Dictionary<string, object>)GetConfig("Settings", "CraftingDetails", new Dictionary<string, object>{
  167.                 { "TimeSpent", 1},
  168.                 { "XPPerTimeSpent", 3},
  169.                 { "PercentFasterPerLevel", 5 }
  170.             });
  171.             percentLostOnDeath = (Dictionary<string, object>)GetConfig("Settings", "PercentLostOnDeath", new Dictionary<string, object>{
  172.                 {Skills.WOODCUTTING, 50},
  173.                 {Skills.MINING, 50},
  174.                 {Skills.SKINNING, 50},
  175.                 {Skills.ACQUIRE, 50},
  176.                 {Skills.CRAFTING, 50}
  177.             });
  178.             colors = (Dictionary<string, object>)GetConfig("Settings", "SkillColors", new Dictionary<string, object>()
  179.             {
  180.                 {Skills.WOODCUTTING, "#FFDDAA"},
  181.                 {Skills.MINING, "#DDDDDD"},
  182.                 {Skills.SKINNING, "#FFDDDD"},
  183.                 {Skills.ACQUIRE, "#ADD8E6"},
  184.                 {Skills.CRAFTING, "#CCFF99"}
  185.             });
  186.             cuiColors = (Dictionary<string, object>)GetConfig("CUI", "XpBarColors", new Dictionary<string, object>()
  187.             {
  188.                 {Skills.WOODCUTTING, "0.8 0.4 0 0.5"},
  189.                 {Skills.MINING, "0.1 0.5 0.8 0.5"},
  190.                 {Skills.SKINNING, "0.8 0.1 0 0.5"},
  191.                 {Skills.ACQUIRE, "0 0.8 0 0.5"},
  192.                 {Skills.CRAFTING, "0.2 0.72 0.5 0.5"}
  193.             });
  194.             cuiEnabled = Convert.ToBoolean(GetConfig("CUI", "cuiEnabled", true));
  195.             cuiFontSizeLvl = Convert.ToInt32(GetConfig("CUI", "FontSizeLevel", 11));
  196.             cuiFontSizeBar = Convert.ToInt32(GetConfig("CUI", "FontSizeBar", 11));
  197.             cuiFontSizePercent = Convert.ToInt32(GetConfig("CUI", "FontSizePercent", 11));
  198.             cuiTextShadow = Convert.ToBoolean(GetConfig("CUI", "TextShadowEnabled", true));
  199.             cuiFontColor = Convert.ToString(GetConfig("CUI", "FontColor", "0.74 0.76 0.78 1"));
  200.             cuiXpBarBackground = Convert.ToString(GetConfig("CUI", "XpBarBackground", "0.2 0.2 0.2 0.2"));
  201.             cuiBoundsBackground = Convert.ToString(GetConfig("CUI", "BoundsBackground", "0.1 0.1 0.1 0.1"));
  202.             cuiPositioning = (Dictionary<string, object>)GetConfig("CUI", "Bounds", new Dictionary<string, object>()
  203.             {
  204.                 {"WidthLeft", "0.725"},
  205.                 {"WidthRight", "0.83"},
  206.                 {"HeightLower", "0.02"},
  207.                 {"HeightUpper", "0.1225"}
  208.             });
  209.  
  210.             pointsPerHitAtNight = (Dictionary<string, object>)GetConfig("NightBonus", "PointsPerHitAtNight", new Dictionary<string, object>{
  211.                 {Skills.WOODCUTTING, 60},
  212.                 {Skills.MINING, 60},
  213.                 {Skills.SKINNING, 60},
  214.                 {Skills.ACQUIRE, 60}
  215.             });
  216.             resourceMultipliersAtNight = (Dictionary<string, object>)GetConfig("NightBonus", "ResourcePerLevelMultiplierAtNight", new Dictionary<string, object>{
  217.                 {Skills.WOODCUTTING, 2},
  218.                 {Skills.MINING, 2},
  219.                 {Skills.SKINNING, 2},
  220.                 {Skills.ACQUIRE, 2}
  221.             });
  222.             enableNightBonus = Convert.ToBoolean(GetConfig("NightBonus", "enableNightBonus", false));
  223.             logEnabledBonusConsole = Convert.ToBoolean(GetConfig("NightBonus", "logEnabledBonusConsole", false));
  224.             broadcastEnabledBonus = Convert.ToBoolean(GetConfig("NightBonus", "broadcastEnabledBonus", true));
  225.  
  226.             if (!Changed) return;
  227.             SaveConfig();
  228.             Changed = false;
  229.         }
  230.  
  231.         protected override void LoadDefaultMessages()
  232.         {
  233.             lang.RegisterMessages(new Dictionary<string, string>
  234.             {
  235.                 {"StatsHeadline", "Level stats (/statinfo - To get more information about skills)"},
  236.                 {"StatsText",   "-{0}\nLevel: {1} (+{4}% bonus) \nXP: {2}/{3} [{5}].\n<color=red>-{6} XP loose on death.</color>"},
  237.                 {"LevelUpText", "{0} Level up\nLevel: {1} (+{4}% bonus) \nXP: {2}/{3}"},
  238.                 {"LevelUpTextBroadcast", "<color=#5af>{0}</color> has reached level <color=#5af>{1}</color> in <color={2}>{3}</color>"},
  239.                 {"PenaltyText", "<color=orange>You have lost XP for dying:{0}</color>"},
  240.                 {"NoPermission", "You don't have permission to use this command"},
  241.                 {"WCSkill", "Woodcutting"},
  242.                 {"MSkill", "Mining"},
  243.                 {"SSkill", "Skinning"},
  244.                 {"CSkill", "Crafting" },
  245.                 {"ASkill", "Acquire" },
  246.                 {"NightBonusOn", "Nightbonus for points per hit enabled"},
  247.                 {"NightBonusOff", "Nightbonus for points per hit disabled"},
  248.                 {"PluginPlayerOn", "The plugin functions are now enabled again"},
  249.                 {"PluginPlayerOff", "The plugin functions are now disabled for your character"},
  250.             },this);
  251.         }
  252.  
  253.         #endregion Config
  254.  
  255.         #region Main
  256.  
  257.         void Init()
  258.         {
  259.             LoadVariables();
  260.             LoadDefaultMessages();
  261.             initialized = false;
  262.             try {
  263.                 if ((int)levelCaps[Skills.CRAFTING] > 20)
  264.                 levelCaps[Skills.CRAFTING] = 20;
  265.             }
  266.             catch
  267.             {
  268.                 // ignored
  269.             }
  270.  
  271.             if (!permission.PermissionExists(permissionName)) permission.RegisterPermission(permissionName, this);
  272.             if (!permission.PermissionExists(permissionNameXP)) permission.RegisterPermission(permissionNameXP, this);
  273.             if ((_craftData = Interface.GetMod().DataFileSystem.ReadObject<CraftData>("ZLevelsCraftDetails")) == null || !_craftData.CraftList.Any())
  274.             {
  275.                 GenerateItems(true);
  276.                 _craftData = Interface.GetMod().DataFileSystem.ReadObject<CraftData>("ZLevelsCraftDetails");
  277.             }
  278.             var index = 0;
  279.             skillIndex = new Dictionary<string,int>();
  280.             foreach (var skill in Skills.ALL)
  281.                 if (IsSkillEnabled(skill))
  282.                     skillIndex.Add(skill, ++index);
  283.         }
  284.  
  285.         void Loaded() => zLevels = this;
  286.  
  287.         void OnServerSave()
  288.         {
  289.             if (initialized)
  290.                 SaveData();
  291.         }
  292.  
  293.         void Unload()
  294.         {
  295.             if (!initialized)
  296.                 return;
  297.             SaveData();
  298.             foreach (var player in BasePlayer.activePlayerList)
  299.                 DestroyGUI(player);
  300.         }
  301.  
  302.         void OnNewSave(string strFilename)
  303.         {
  304.             if (wipeDataOnNewSave)
  305.                 newSaveDetected = true;
  306.         }
  307.  
  308.         void SaveData() => Interface.Oxide.DataFileSystem.WriteObject(this.Name, playerPrefs);
  309.  
  310.         void OnServerInitialized()
  311.         {
  312.             CheckCollectible();
  313.             playerPrefs = Interface.GetMod().DataFileSystem.ReadObject<PlayerData>(this.Name) ?? new PlayerData();
  314.             if (newSaveDetected || (playerPrefs == null || playerPrefs.PlayerInfo == null || playerPrefs.PlayerInfo.Count == 0))
  315.             {
  316.                 playerPrefs = new PlayerData();
  317.                 SaveData();
  318.             }
  319.             pointsPerHitCurrent = pointsPerHit;
  320.             resourceMultipliersCurrent = resourceMultipliers;
  321.             if (enableNightBonus && TOD_Sky.Instance.IsNight)
  322.             {
  323.                 pointsPerHitCurrent = pointsPerHitAtNight;
  324.                 resourceMultipliersCurrent = resourceMultipliersAtNight;
  325.                 bonusOn = true;
  326.             }
  327.             initialized = true;
  328.             foreach (var player in BasePlayer.activePlayerList)
  329.             {
  330.                 if (player != null)
  331.                 {
  332.                     UpdatePlayer(player);
  333.                     if (cuiEnabled)
  334.                         CreateGUI(player);
  335.                 }
  336.             }
  337.             foreach (var player in BasePlayer.sleepingPlayerList)
  338.             {
  339.                 if (player != null)
  340.                     UpdatePlayer(player);
  341.             }
  342.             SaveData();
  343.             Puts("Stats can be reset by > zl.reset <");
  344.         }
  345.  
  346.         void CheckCollectible()
  347.         {
  348.             var collectList =  Resources.FindObjectsOfTypeAll<CollectibleEntity>().Select(c => c.ShortPrefabName).Distinct().ToList();
  349.             if (collectList == null || collectList.Count == 0)
  350.                 return;
  351.             if (enabledCollectibleEntity == null)
  352.                 enabledCollectibleEntity = new Dictionary<string, object>();
  353.             bool updated = false;
  354.             foreach (var collect in collectList)
  355.             {
  356.                 if (!enabledCollectibleEntity.ContainsKey(collect))
  357.                 {
  358.                     enabledCollectibleEntity.Add(collect, true);
  359.                     updated = true;
  360.                 }
  361.             }
  362.             if (updated)
  363.             {
  364.                 Config["Functions", "CollectibleEntitys"] = enabledCollectibleEntity;
  365.                 Config.Save();
  366.             }
  367.         }
  368.  
  369.         #endregion Main
  370.  
  371.         #region Classes
  372.  
  373.         class Skills
  374.         {
  375.             public static string CRAFTING = "C";
  376.             public static string WOODCUTTING = "WC";
  377.             public static string SKINNING = "S";
  378.             public static string MINING = "M";
  379.             public static string ACQUIRE = "A";
  380.             public static string[] ALL = { WOODCUTTING, MINING, SKINNING, ACQUIRE, CRAFTING };
  381.         }
  382.  
  383.         class CraftData
  384.         {
  385.             public Dictionary<string, CraftInfo> CraftList = new Dictionary<string, CraftInfo>();
  386.         }
  387.  
  388.         class CraftInfo
  389.         {
  390.             public int MaxBulkCraft;
  391.             public int MinBulkCraft;
  392.             public string shortName;
  393.             public bool Enabled;
  394.         }
  395.  
  396.         class PlayerData
  397.         {
  398.             public Dictionary<ulong, PlayerInfo> PlayerInfo = new Dictionary<ulong, PlayerInfo>();
  399.             public PlayerData(){}
  400.         }
  401.  
  402.         class PlayerInfo
  403.         {
  404.             public long WCL = 1;
  405.             public long WCP = 10;
  406.             public long ML = 1;
  407.             public long MP = 10;
  408.             public long SL = 1;
  409.             public long SP = 10;
  410.             public long AL = 1;
  411.             public long AP = 10;
  412.             public long CL = 1;
  413.             public long CP = 10;
  414.             public long LD;
  415.             public long LLD;
  416.             public long XPM = 100;
  417.             public bool CUI = true;
  418.             public bool ONOFF = true;
  419.         }
  420.  
  421.         #endregion Classes
  422.  
  423.         #region Serverhooks
  424.  
  425.         void OnPlayerConnected(BasePlayer player)
  426.         {
  427.             if (!initialized || player == null || !IsValid(player)) return;
  428.             UpdatePlayer(player);
  429.             CreateGUI(player);
  430.             /*
  431.             long multiplier = 100;
  432.             var playerPermissions = permission.GetUserPermissions(player.UserIDString);
  433.             if (playerPermissions.Any(x => x.ToLower().StartsWith("zlvlboost")))
  434.             {
  435.                 var perm = playerPermissions.First(x => x.ToLower().StartsWith("zlvlboost"));
  436.                 if (!long.TryParse(perm.ToLower().Replace("zlvlboost", ""), out multiplier))
  437.                     multiplier = 100;
  438.             }
  439.             editMultiplierForPlayer(multiplier, player.userID);
  440.             */
  441.         }
  442.  
  443.         void OnPlayerDisconnected(BasePlayer player)
  444.         {
  445.             if (initialized && player != null)
  446.                 UpdatePlayer(player);
  447.         }
  448.  
  449.         void UpdatePlayer(BasePlayer player)
  450.         {
  451.             PlayerInfo p = null;
  452.             if (!playerPrefs.PlayerInfo.TryGetValue(player.userID, out p))
  453.             {
  454.                 var info = new PlayerInfo();
  455.                 info.LD = ToEpochTime(DateTime.UtcNow);
  456.                 info.LLD = ToEpochTime(DateTime.UtcNow);
  457.                 info.CUI = playerCuiDefaultEnabled;
  458.                 info.ONOFF = playerPluginDefaultEnabled;
  459.                 playerPrefs.PlayerInfo.Add(player.userID, info);
  460.                 return;
  461.             }
  462.             else
  463.                 p.LLD = ToEpochTime(DateTime.UtcNow);
  464.         }
  465.  
  466.         void CheckPlayer(BasePlayer player)
  467.         {
  468.             PlayerInfo p = null;
  469.             if (!playerPrefs.PlayerInfo.TryGetValue(player.userID, out p))
  470.                 UpdatePlayer(player);
  471.         }
  472.  
  473.         void OnPlayerSleepEnded(BasePlayer player)
  474.         {
  475.             if (!initialized || player == null) return;
  476.             PlayerInfo p = null;
  477.             if (playerPrefs.PlayerInfo.TryGetValue(player.userID, out p))
  478.                 CreateGUI(player);
  479.             else
  480.             {
  481.                 UpdatePlayer(player);
  482.                 CreateGUI(player);
  483.             }
  484.         }
  485.  
  486.         void OnPlayerSleep(BasePlayer player)
  487.         {
  488.             if (!initialized || player == null) return;
  489.             PlayerInfo p = null;
  490.             if (playerPrefs.PlayerInfo.TryGetValue(player.userID, out p))
  491.                 DestroyGUI(player);
  492.         }
  493.  
  494.         void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info)
  495.         {
  496.             if (!initialized || entity == null || !(entity is BasePlayer) || !IsValid((BasePlayer) entity)) return;
  497.             NextTick(()=>{
  498.                 if (entity != null && entity.health <= 0f) DestroyGUI(entity as BasePlayer);
  499.             });
  500.         }
  501.  
  502.         void OnEntityDeath(BaseCombatEntity entity, HitInfo hitInfo)
  503.         {
  504.             if (!initialized || !penaltyOnDeath || entity == null || !(entity is BasePlayer) || !IsValid(entity as BasePlayer))
  505.                 return;
  506.             var player = entity as BasePlayer;
  507.             CheckPlayer(player);
  508.             if (!playerPrefs.PlayerInfo[player.userID].ONOFF)
  509.                 return;
  510.             if (Interface.CallHook("CanBePenalized", player) != null)
  511.                 return;
  512.             PlayerInfo p = null;
  513.             if (!hasRights(player.UserIDString) || !playerPrefs.PlayerInfo.TryGetValue(player.userID, out p))
  514.                 return;
  515.             if (EventManager?.Call("isPlaying", player) != null && (bool)EventManager?.Call("isPlaying", player))
  516.                 return;
  517.             if (hitInfo != null && hitInfo.damageTypes != null && hitInfo.damageTypes.Has(Rust.DamageType.Suicide))
  518.                 return;
  519.             if (permission.UserHasPermission(player.UserIDString, permissionNameXP))
  520.                 return;
  521.             var penaltyText = string.Empty;
  522.             var penaltyExist = false;
  523.             foreach (var skill in Skills.ALL)
  524.                 if (IsSkillEnabled(skill))
  525.                 {
  526.                     var penalty = GetPenalty(player, skill);
  527.                     if (penalty > 0)
  528.                     {
  529.                         penaltyText += "\n* -" + penalty + " " + msg(skill + "Skill") + " XP.";
  530.                         removePoints(player.userID, skill, penalty);
  531.                         penaltyExist = true;
  532.                     }
  533.                 }
  534.             if (penaltyExist)
  535.                 PrintToChat(player, string.Format(msg("PenaltyText", player.UserIDString), penaltyText));
  536.             playerPrefs.PlayerInfo[player.userID].LD = ToEpochTime(DateTime.UtcNow);
  537.         }
  538.  
  539.         void OnDispenserGather(ResourceDispenser dispenser, BaseEntity entity, Item item)
  540.         {
  541.             if (!initialized || !enableDispenserGather || entity == null || !(entity is BasePlayer) || item == null || dispenser == null)
  542.                 return;
  543.             var player = entity as BasePlayer;
  544.             CheckPlayer(player);
  545.             if (!playerPrefs.PlayerInfo[player.userID].ONOFF || excludeWeaponsOnGather && player.GetActiveItem()?.info?.category == ItemCategory.Weapon)
  546.                 return;
  547.             if (!hasRights(player.UserIDString))
  548.                 return;
  549.             if (excludeJackhammerOnGather && player.GetHeldEntity() is Jackhammer || excludeChainsawOnGather && player.GetHeldEntity() is Chainsaw)
  550.                 return;
  551.            if (IsSkillEnabled(Skills.WOODCUTTING) &&(int)dispenser.gatherType == 0) levelHandler(player, item, Skills.WOODCUTTING);
  552.             if (IsSkillEnabled(Skills.MINING) && (int)dispenser.gatherType == 1) levelHandler(player, item, Skills.MINING);
  553.             if (IsSkillEnabled(Skills.SKINNING) && (int)dispenser.gatherType == 2) levelHandler(player, item, Skills.SKINNING);
  554.         }
  555.  
  556.         void OnDispenserBonus(ResourceDispenser dispenser, BaseEntity entity, Item item) => OnDispenserGather(dispenser, entity, item);
  557.  
  558.         void OnCollectiblePickup(Item item, BasePlayer player, CollectibleEntity entity)
  559.         {
  560.             if (!initialized || !enableCollectiblePickup || item == null || player == null || !hasRights(player.UserIDString))
  561.                 return;
  562.             CheckPlayer(player);
  563.             if (!playerPrefs.PlayerInfo[player.userID].ONOFF)
  564.                 return;
  565.             if (enabledCollectibleEntity.ContainsKey(entity.ShortPrefabName) && (bool)enabledCollectibleEntity[entity.ShortPrefabName] == false)
  566.                 return;
  567.             var skillName = string.Empty;
  568.  
  569.             if (IsSkillDisabled(Skills.ACQUIRE))
  570.             {
  571.                 switch (item.info.shortname)
  572.                 {
  573.                     case "wood":
  574.                         skillName = Skills.WOODCUTTING;
  575.                         break;
  576.                     case "cloth":
  577.                     case "mushroom":
  578.                     case "corn":
  579.                     case "pumpkin":
  580.                     case "seed.hemp":
  581.                     case "seed.pumpkin":
  582.                     case "seed.corn":
  583.                         skillName = Skills.SKINNING;
  584.                         break;
  585.                     case "metal.ore":
  586.                     case "sulfur.ore":
  587.                     case "stones":
  588.                         skillName = Skills.MINING;
  589.                         break;
  590.                 }
  591.             }
  592.             else
  593.                 skillName = Skills.ACQUIRE;
  594.  
  595.             if (!string.IsNullOrEmpty(skillName))
  596.                 levelHandler(player, item, skillName);
  597.         }
  598.  
  599.         void OnTimeSunset()
  600.         {
  601.             if (!enableNightBonus || bonusOn) return;
  602.             bonusOn = true;
  603.             pointsPerHitCurrent = pointsPerHitAtNight;
  604.             resourceMultipliersCurrent = resourceMultipliersAtNight;
  605.             if (broadcastEnabledBonus)
  606.                 Server.Broadcast(pluginPrefix + " "+ msg("NightBonusOn"));
  607.             if (logEnabledBonusConsole)
  608.                 Puts("Nightbonus points enabled");
  609.         }
  610.  
  611.         void OnTimeSunrise()
  612.         {
  613.             if (!enableNightBonus || !bonusOn) return;
  614.             bonusOn = false;
  615.             pointsPerHitCurrent = pointsPerHit;
  616.             resourceMultipliersCurrent = resourceMultipliers;
  617.             if (broadcastEnabledBonus)
  618.                 Server.Broadcast(pluginPrefix + " "+ msg("NightBonusOff"));
  619.             if (logEnabledBonusConsole)
  620.                 Puts("Nightbonus points disabled");
  621.         }
  622.  
  623.         void OnGrowableGathered(GrowableEntity growable, Item item, BasePlayer player)
  624.         {
  625.             if (!initialized || !enableCropGather || item == null || player == null || !hasRights(player.UserIDString) || !playerPrefs.PlayerInfo[player.userID].ONOFF) return;
  626.             var skillName = string.Empty;
  627.             if (IsSkillDisabled(Skills.ACQUIRE))
  628.                 skillName = Skills.SKINNING;
  629.             else
  630.                 skillName = Skills.ACQUIRE;
  631.             levelHandler(player, item, skillName);
  632.         }
  633.  
  634.         object OnItemCraft(ItemCraftTask task, BasePlayer crafter)
  635.         {
  636.             if (!initialized || IsSkillDisabled(Skills.CRAFTING) || !hasRights(crafter.UserIDString) || !playerPrefs.PlayerInfo[crafter.userID].ONOFF) return null;
  637.             var Level = getLevel(crafter.userID, Skills.CRAFTING);
  638.             var craftingTime = task.blueprint.time;
  639.             var amountToReduce = task.blueprint.time * ((float)(Level * (int)craftingDetails["PercentFasterPerLevel"]) / 100);
  640.             craftingTime -= amountToReduce;
  641.             if (craftingTime < 0)
  642.                 craftingTime = 0;
  643.             if (craftingTime == 0)
  644.             {
  645.                 try
  646.                 {
  647.                     foreach (var entry in _craftData.CraftList)
  648.                     {
  649.                         var itemname = task.blueprint.targetItem.shortname;
  650.                         if (entry.Value.shortName == itemname && entry.Value.Enabled)
  651.                         {
  652.                             var amount = task.amount;
  653.                             if (amount >= entry.Value.MinBulkCraft && amount <= entry.Value.MaxBulkCraft)
  654.                             {
  655.                                 var item = GetItem(itemname);
  656.                                 var final_amount = task.blueprint.amountToCreate * amount;
  657.                                 var newItem = ItemManager.CreateByItemID(item.itemid, (int)final_amount);
  658.                                 crafter.inventory.GiveItem(newItem);
  659.  
  660.                                 /*var returnstring = "You have crafted <color=#66FF66>" + amount + "</color> <color=#66FFFF>" + item.displayName.english + "</color>\n[Batch Amount: <color=#66FF66>" + final_amount + "</color>]";
  661.                                 PrintToChat(crafter, returnstring);*/
  662.                                 return false;
  663.                             }
  664.                         }
  665.                     }
  666.                 }
  667.                 catch
  668.                 {
  669.                     GenerateItems();
  670.                 }
  671.             }
  672.  
  673.             if (!task.blueprint.name.Contains("(Clone)"))
  674.                 task.blueprint = UnityEngine.Object.Instantiate(task.blueprint);
  675.             task.blueprint.time = craftingTime;
  676.             return null;
  677.         }
  678.  
  679.         object OnItemCraftFinished(ItemCraftTask task, Item item)
  680.         {
  681.             if (!initialized || IsSkillDisabled(Skills.CRAFTING)) return null;
  682.             var crafter = task.owner;
  683.             if (crafter == null || !hasRights(crafter.UserIDString)) return null;
  684.             var xpPercentBefore = getExperiencePercent(crafter, Skills.CRAFTING);
  685.             if (task.blueprint == null)
  686.             {
  687.                 Puts("There is problem obtaining task.blueprint on 'OnItemCraftFinished' hook! This is usually caused by some incompatable plugins.");
  688.                 return null;
  689.             }
  690.             var experienceGain = Convert.ToInt32(Math.Floor((task.blueprint.time + 0.99f) / (int)craftingDetails["TimeSpent"]));//(int)task.blueprint.time / 10;
  691.             if (experienceGain == 0)
  692.                 return null;
  693.  
  694.             long Level = 0;
  695.             long Points = 0;
  696.             try
  697.             {
  698.                 Level = getLevel(crafter.userID, Skills.CRAFTING);
  699.                 Points = getPoints(crafter.userID, Skills.CRAFTING);
  700.             } catch {}
  701.             Points += experienceGain * (int)craftingDetails["XPPerTimeSpent"];
  702.             if (Points >= getLevelPoints(Level + 1))
  703.             {
  704.                 var maxLevel = (int)levelCaps[Skills.CRAFTING] > 0 && Level + 1 > (int)levelCaps[Skills.CRAFTING];
  705.                 if (!maxLevel)
  706.                 {
  707.                     Level = getPointsLevel(Points, Skills.CRAFTING);
  708.                     PrintToChat(crafter, string.Format("<color=" + colors[Skills.CRAFTING] + '>' + msg("LevelUpText", crafter.UserIDString) + "</color>", msg("CSkill", crafter.UserIDString), Level, Points, getLevelPoints(Level + 1), (getLevel(crafter.userID, Skills.CRAFTING) * Convert.ToDouble(craftingDetails["PercentFasterPerLevel"]))));
  709.                     if (enableLevelupBroadcast)
  710.                     {
  711.                         foreach (var target in BasePlayer.activePlayerList.Where(x => x.userID != crafter.userID))
  712.                         {
  713.                             if (hasRights(target.UserIDString) && playerPrefs.PlayerInfo[target.userID].ONOFF)
  714.                                 PrintToChat(target, string.Format(msg("LevelUpTextBroadcast", target.UserIDString), crafter.displayName, Level, colors[Skills.CRAFTING], msg("CSkill", crafter.UserIDString)));
  715.                         }
  716.                     }
  717.                 }
  718.             }
  719.             try
  720.             {
  721.                 if (item.info.shortname != "lantern_a" && item.info.shortname != "lantern_b")
  722.                     setPointsAndLevel(crafter.userID, Skills.CRAFTING, Points, Level);
  723.             } catch {}
  724.  
  725.             try
  726.             {
  727.                 var xpPercentAfter = getExperiencePercent(crafter, Skills.CRAFTING);
  728.                 if (!xpPercentAfter.Equals(xpPercentBefore))
  729.                     GUIUpdateSkill(crafter, Skills.CRAFTING);
  730.             } catch {}
  731.  
  732.             if (task.amount > 0) return null;
  733.             if (task.blueprint != null && task.blueprint.name.Contains("(Clone)"))
  734.             {
  735.                 var behaviours = task.blueprint.GetComponents<MonoBehaviour>();
  736.                 foreach (var behaviour in behaviours)
  737.                 {
  738.                     if (behaviour.name.Contains("(Clone)")) UnityEngine.Object.Destroy(behaviour);
  739.                 }
  740.             }
  741.             return null;
  742.         }
  743.  
  744.  
  745.         #endregion Serverhooks
  746.  
  747.        #region Commands
  748.  
  749.         [HookMethod("SendHelpText"), ChatCommand("stathelp")]
  750.         void SendHelpText(BasePlayer player)
  751.         {
  752.             var sb = new StringBuilder();
  753.             sb.AppendLine("<size=18><color=orange>ZLevels</color></size><size=14><color=#ce422b>REMASTERED</color></size>");
  754.             sb.AppendLine("/stats - Displays your stats.");
  755.             sb.AppendLine("/statsui - Enable/Disable stats UI.");
  756.             sb.AppendLine("/statsonoff - Enable/Disable whole leveling.");
  757.             sb.AppendLine("/statinfo - Displays information about skills.");
  758.             sb.AppendLine("/stathelp - Displays the help.");
  759.             //sb.AppendLine("/topskills - Display max levels reached so far.");
  760.             player.ChatMessage(sb.ToString());
  761.         }
  762.  
  763.         /*[ChatCommand("topskills")]
  764.         void StatsTopCommand(BasePlayer player, string command, string[] args)
  765.         {
  766.             if (!hasRights(player.UserIDString))
  767.             {
  768.                 player.ChatMessage(pluginPrefix + " "+ msg("NoPermission", player.UserIDString));
  769.                 return;
  770.             }
  771.             var sb = new StringBuilder();
  772.             sb.AppendLine("<size=18><color=orange>ZLevels</color></size><size=14><color=#ce422b>REMASTERED</color></size>");
  773.             sb.AppendLine("Data temporary not available");
  774.             player.ChatMessage(sb.ToString());
  775.             PrintToChat(player, "Max stats on server so far:");
  776.             foreach (var skill in Skills.ALL)
  777.                 if (!IsSkillDisabled(skill))
  778.                     printMaxSkillDetails(player, skill);
  779.         }*/
  780.  
  781.         [ConsoleCommand("zl.pointsperhit")]
  782.         void PointsPerHitCommand(ConsoleSystem.Arg arg)
  783.         {
  784.             if (arg.Connection != null && arg.Connection.authLevel < 2) return;
  785.             if (arg.Args == null || arg.Args.Length < 2)
  786.             {
  787.                 SendReply(arg, "Syntax: zl.pointsperhit skill number");
  788.                 SendReply(arg, "Possible skills are: WC, M, S, A, C, *(All skills)");
  789.                 var sb = new StringBuilder();
  790.                 sb.Append("Current points per hit:");
  791.                 foreach (var currSkill in Skills.ALL)
  792.                 {
  793.                     if (IsSkillDisabled(currSkill)) continue;
  794.                     sb.Append($" {currSkill} > {pointsPerHitCurrent[currSkill]} |");
  795.                 }
  796.                 SendReply(arg, sb.ToString().TrimEnd('|'));
  797.                 return;
  798.             }
  799.             int points = -1;
  800.             if (int.TryParse(arg.Args[1], out points))
  801.             {
  802.                 if (points < 1)
  803.                 {
  804.                     SendReply(arg, "Incorrect number. Must be greater than 1");
  805.                     return;
  806.                 }
  807.             }
  808.             else
  809.             {
  810.                 SendReply(arg, "Incorrect number. Must be greater than 1");
  811.                 return;
  812.             }
  813.  
  814.             var skill = arg.Args[0].ToUpper();
  815.             if (skill == Skills.WOODCUTTING || skill == Skills.MINING || skill == Skills.SKINNING || skill == Skills.ACQUIRE || skill == Skills.CRAFTING || skill == "*")
  816.             {
  817.                 if (skill == "*")
  818.                 {
  819.                     foreach (var currSkill in Skills.ALL)
  820.                     {
  821.                         if (IsSkillDisabled(currSkill)) continue;
  822.                         pointsPerHitCurrent[currSkill] = points;
  823.                     }
  824.                     var sb = new StringBuilder();
  825.                     sb.Append("New points per hit:");
  826.                     foreach (var currSkill in Skills.ALL)
  827.                     {
  828.                         if (IsSkillDisabled(currSkill)) continue;
  829.                         sb.Append($" {currSkill} > {pointsPerHitCurrent[currSkill]} |");
  830.                     }
  831.                     SendReply(arg, sb.ToString().TrimEnd('|'));
  832.                     return;
  833.                 }
  834.                 else
  835.                 {
  836.                     pointsPerHitCurrent[skill] = points;
  837.                     var sb = new StringBuilder();
  838.                     sb.Append("New points per hit:");
  839.                     foreach (var currSkill in Skills.ALL)
  840.                     {
  841.                         if (IsSkillDisabled(currSkill)) continue;
  842.                         sb.Append($" {currSkill} > {pointsPerHitCurrent[currSkill]} |");
  843.                     }
  844.                     SendReply(arg, sb.ToString().TrimEnd('|'));
  845.                     return;
  846.                 }
  847.             }
  848.             else
  849.                 SendReply(arg, "Incorrect skill. Possible skills are: WC, M, S, A, C, *(All skills).");
  850.         }
  851.  
  852.         [ConsoleCommand("zl.playerxpm")]
  853.         void PlayerXpmCommand(ConsoleSystem.Arg arg)
  854.         {
  855.             if (arg.Connection != null && arg.Connection.authLevel < 2) return;
  856.             if (arg.Args == null || arg.Args.Length < 1)
  857.             {
  858.                 SendReply(arg, "Syntax: zl.playerxpm name|steamid (to show current XP multiplier)");
  859.                 SendReply(arg, "Syntax: zl.playerxpm name|steamid number (to set current XP multiplier >= 100)");
  860.                 return;
  861.             }
  862.             IPlayer player = this.covalence.Players.FindPlayer(arg.Args[0]);
  863.             if (player == null)
  864.             {
  865.                 SendReply(arg, "Player not found!");
  866.                 return;
  867.             }
  868.             PlayerInfo playerData = null;
  869.             if (!playerPrefs.PlayerInfo.TryGetValue(Convert.ToUInt64(player.Id), out playerData))
  870.             {
  871.                 SendReply(arg, "PlayerData is NULL!");
  872.                 return;
  873.             }
  874.             if (arg.Args.Length < 2)
  875.             {
  876.                 SendReply(arg, $"Current XP multiplier for player '{player.Name}' is {playerData.XPM.ToString()}%");
  877.                 return;
  878.             }
  879.             int multiplier = -1;
  880.             if (int.TryParse(arg.Args[1], out multiplier))
  881.             {
  882.                 if (multiplier < 100)
  883.                 {
  884.                     SendReply(arg, "Incorrect number. Must be greater greater or equal 100");
  885.                     return;
  886.                 }
  887.             }
  888.             playerData.XPM = multiplier;
  889.             SendReply(arg, $"New XP multiplier for player '{player.Name}' is {playerData.XPM.ToString()}%");
  890.         }
  891.  
  892.         [ConsoleCommand("zl.info")]
  893.         void InfoCommand(ConsoleSystem.Arg arg)
  894.         {
  895.             if (arg.Connection != null && arg.Connection.authLevel < 2) return;
  896.             if (arg.Args == null || arg.Args.Length < 1)
  897.             {
  898.                 SendReply(arg, "Syntax: zl.info name|steamid");
  899.                 return;
  900.             }
  901.             IPlayer player = this.covalence.Players.FindPlayer(arg.Args[0]);
  902.             if (player == null)
  903.             {
  904.                 SendReply(arg, "Player not found!");
  905.                 return;
  906.             }
  907.             PlayerInfo playerData = null;
  908.             if (!playerPrefs.PlayerInfo.TryGetValue(Convert.ToUInt64(player.Id), out playerData))
  909.             {
  910.                 SendReply(arg, "PlayerData is NULL!");
  911.                 return;
  912.             }
  913.             TextTable textTable = new TextTable();
  914.             textTable.AddColumn("FieldInfo");
  915.             textTable.AddColumn("Level");
  916.             textTable.AddColumn("Points");
  917.             textTable.AddRow(new string[]   { "Woodcutting", playerData.WCL.ToString(), playerData.WCP.ToString() });
  918.             textTable.AddRow(new string[]   { "Mining", playerData.ML.ToString(), playerData.MP.ToString() });
  919.             textTable.AddRow(new string[]   { "Skinning", playerData.SL.ToString(), playerData.SP.ToString() });
  920.             textTable.AddRow(new string[]   { "Acquire", playerData.AL.ToString(), playerData.AP.ToString() });
  921.             textTable.AddRow(new string[]   { "Crafting", playerData.CL.ToString(), playerData.CP.ToString() });
  922.             textTable.AddRow(new string[]   { "XP Multiplier", playerData.XPM.ToString()+"%", string.Empty });
  923.             SendReply(arg, "\nStats for player: " + player.Name + "\n" +textTable.ToString());
  924.         }
  925.  
  926.         [ConsoleCommand("zl.reset")]
  927.         void ResetCommand(ConsoleSystem.Arg arg)
  928.         {
  929.             if (arg.Connection != null && arg.Connection.authLevel < 2) return;
  930.             if (arg.Args == null || arg.Args.Length != 1 || arg.Args[0] != "true")
  931.             {
  932.                 SendReply(arg, "Usage: zl.reset true | Resets all userdata to zero");
  933.                 return;
  934.             }
  935.             playerPrefs = new PlayerData();
  936.             Interface.Oxide.DataFileSystem.WriteObject(this.Name, playerPrefs);
  937.             foreach (var player in BasePlayer.activePlayerList)
  938.             {
  939.                 if (player != null)
  940.                 {
  941.                     CuiHelper.DestroyUi(player, "ZLevelsUI");
  942.                     UpdatePlayer(player);
  943.                     if (cuiEnabled)
  944.                         CreateGUI(player);
  945.                 }
  946.             }
  947.             SendReply(arg, "Userdata was successfully reset to zero");
  948.         }
  949.  
  950.         [ConsoleCommand("zl.lvl")]
  951.         void ZlvlCommand(ConsoleSystem.Arg arg)
  952.         {
  953.             if (arg.Connection != null && arg.Connection.authLevel < 2) return;
  954.  
  955.             if (arg.Args == null || arg.Args.Length < 3)
  956.             {
  957.                 var sb = new StringBuilder();
  958.                 sb.AppendLine("Syntax: zl.lvl name|steamid skill [OPERATOR]NUMBER");
  959.                 sb.AppendLine("Example: zl.lvl Player WC /2 -- Player gets his WC level divided by 2.");
  960.                 sb.AppendLine("Example: zl.lvl * * +3 -- Everyone currently playing in the server gets +3 for all skills.");
  961.                 sb.AppendLine("Example: zl.lvl ** * /2 -- Everyone (including offline players) gets their level divided by 2.");
  962.                 sb.AppendLine("Instead of names you can use wildcard(*): * - affects online players, ** - affects all players");
  963.                 sb.AppendLine("Possible operators: *(XP Modified %), +(Adds level), -(Removes level), /(Divides level)");
  964.                 SendReply(arg, "\n"+sb.ToString());
  965.                 return;
  966.             }
  967.             var playerName = arg.Args[0];
  968.             IPlayer p = this.covalence.Players.FindPlayer(arg.Args[0]);
  969.  
  970.             if (playerName != "*" && playerName != "**" && p == null)
  971.             {
  972.                 SendReply(arg, "Player not found!");
  973.                 return;
  974.             }
  975.             PlayerInfo playerData = null;
  976.             if (playerName != "*" && playerName != "**" && !playerPrefs.PlayerInfo.TryGetValue(Convert.ToUInt64(p.Id), out playerData))
  977.             {
  978.                 SendReply(arg, "PlayerData is NULL!");
  979.                 return;
  980.             }
  981.  
  982.             if (p != null || playerName == "*" || playerName == "**")
  983.             {
  984.                 var playerMode = 0; // Exact player
  985.                 if (playerName == "*")
  986.                     playerMode = 1; // Online players
  987.                 else if (playerName == "**")
  988.                     playerMode = 2; // All players
  989.                 var skill = arg.Args[1].ToUpper();
  990.                 if (skill == Skills.WOODCUTTING || skill == Skills.MINING || skill == Skills.SKINNING || skill == Skills.ACQUIRE ||
  991.                     skill == Skills.CRAFTING || skill == "*")
  992.                 {
  993.                     var allSkills = skill == "*";
  994.                     var mode = 0; // 0 = SET, 1 = ADD, 2 = SUBTRACT, 3 = multiplier, 4 = divide
  995.                     int value;
  996.                     var correct = false;
  997.                     if (arg.Args[2][0] == '+')
  998.                     {
  999.                         mode = 1;
  1000.                         correct = int.TryParse(arg.Args[2].Replace("+", ""), out value);
  1001.                     }
  1002.                     else if (arg.Args[2][0] == '-')
  1003.                     {
  1004.                         mode = 2;
  1005.                         correct = int.TryParse(arg.Args[2].Replace("-", ""), out value);
  1006.                     }
  1007.                     else if (arg.Args[2][0] == '*')
  1008.                     {
  1009.                         mode = 3;
  1010.                         correct = int.TryParse(arg.Args[2].Replace("*", ""), out value);
  1011.                     }
  1012.                     else if (arg.Args[2][0] == '/')
  1013.                     {
  1014.                         mode = 4;
  1015.                         correct = int.TryParse(arg.Args[2].Replace("/", ""), out value);
  1016.                     }
  1017.                     else
  1018.                     {
  1019.                         correct = int.TryParse(arg.Args[2], out value);
  1020.                     }
  1021.                     if (correct)
  1022.                     {
  1023.                         if (mode == 3) // Change XP Multiplier.
  1024.                         {
  1025.                             if (!allSkills)
  1026.                             {
  1027.                                 SendReply(arg, "XPMultiplier is changeable for all skills! Use * instead of " + skill + ".");
  1028.                                 return;
  1029.                             }
  1030.                             if (playerMode == 1)
  1031.                             {
  1032.                                 foreach (var currPlayer in BasePlayer.activePlayerList)
  1033.                                     editMultiplierForPlayer(value, currPlayer.userID);
  1034.                             }
  1035.                             else if (playerMode == 2)
  1036.                                 editMultiplierForPlayer(value);
  1037.                             else if (p != null)
  1038.                                 editMultiplierForPlayer(value, Convert.ToUInt64(p.Id));
  1039.  
  1040.                             SendReply(arg, "XP rates has changed to " + value + "% of normal XP for " + (playerMode == 1 ? "ALL ONLINE PLAYERS" : (playerMode == 2 ? "ALL PLAYERS" : p.Name)));
  1041.                             return;
  1042.                         }
  1043.  
  1044.                         if (playerMode == 1)
  1045.                         {
  1046.                             foreach (var connPlayer in this.covalence.Players.Connected)
  1047.                             {
  1048.                                 adminModifyPlayerStats(arg, skill, value, mode, connPlayer);
  1049.                             }
  1050.                         }
  1051.                         else if (playerMode == 2)
  1052.                         {
  1053.                             foreach (var allPlayer in this.covalence.Players.All)
  1054.                             {
  1055.                                 PlayerInfo checkData = null;
  1056.                                 if (playerPrefs.PlayerInfo.TryGetValue(Convert.ToUInt64(allPlayer.Id), out checkData))
  1057.                                 {
  1058.                                     adminModifyPlayerStats(arg, skill, value, mode, allPlayer);
  1059.                                 }
  1060.                             }
  1061.                         }
  1062.                         else
  1063.                         {
  1064.                             adminModifyPlayerStats(arg, skill, value, mode, p);
  1065.                         }
  1066.                     }
  1067.                 }
  1068.                 else
  1069.                     SendReply(arg, "Incorrect skill. Possible skills are: WC, M, S, A, C, *(All skills).");
  1070.             }
  1071.         }
  1072.  
  1073.         [ChatCommand("stats")]
  1074.         void StatsCommand(BasePlayer player, string command, string[] args)
  1075.         {
  1076.             if (!hasRights(player.UserIDString))
  1077.             {
  1078.                 player.ChatMessage(pluginPrefix + " " + msg("NoPermission", player.UserIDString));
  1079.                 return;
  1080.             }
  1081.             var text = "<size=18><color=orange>ZLevels</color></size><size=14><color=#ce422b>REMASTERED</color></size>\n";
  1082.             foreach (var skill in Skills.ALL)
  1083.                 text += getStatPrint(player, skill);
  1084.             var details = playerPrefs.PlayerInfo[player.userID].LD;
  1085.             var currentTime = DateTime.UtcNow;
  1086.             var lastDeath = ToDateTimeFromEpoch(details);
  1087.             var timeAlive = currentTime - lastDeath;
  1088.             text += "\nTime alive: " + ReadableTimeSpan(timeAlive);
  1089.             if (playerPrefs.PlayerInfo[player.userID].XPM.ToString() != "100")
  1090.                 text += "XP rates for you are " + playerPrefs.PlayerInfo[player.userID].XPM + "%";
  1091.             player.ChatMessage(text);
  1092.         }
  1093.  
  1094.         [ChatCommand("statinfo")]
  1095.         void StatInfoCommand(BasePlayer player, string command, string[] args)
  1096.         {
  1097.             if (!hasRights(player.UserIDString))
  1098.             {
  1099.                 player.ChatMessage(pluginPrefix + " " + msg("NoPermission", player.UserIDString));
  1100.                 return;
  1101.             }
  1102.             var messagesText = string.Empty;
  1103.             long xpMultiplier = playerPrefs.PlayerInfo[player.userID].XPM;
  1104.  
  1105.             messagesText += "<size=18><color=orange>ZLevels</color></size><size=14><color=#ce422b>REMASTERED</color></size>\n";
  1106.  
  1107.             messagesText += "<color=" + colors[Skills.MINING] + ">Mining</color>" + (IsSkillDisabled(Skills.MINING) ? "(DISABLED)" : "") + "\n";
  1108.             messagesText += "XP per hit: <color=" + colors[Skills.MINING] + ">" + ((int)pointsPerHitCurrent[Skills.MINING] * (xpMultiplier / 100f)) + "</color>\n";
  1109.             messagesText += "Bonus materials per level: <color=" + colors[Skills.MINING] + ">" + ((getGathMult(2, Skills.MINING) - 1) * 100).ToString("0.##") + "%</color>\n";
  1110.  
  1111.             messagesText += "<color=" + colors[Skills.WOODCUTTING] + ">Woodcutting</color>" + (IsSkillDisabled(Skills.WOODCUTTING) ? "(DISABLED)" : "") + "\n";
  1112.             messagesText += "XP per hit: <color=" + colors[Skills.WOODCUTTING] + ">" + ((int)pointsPerHitCurrent[Skills.WOODCUTTING] * (xpMultiplier / 100f)) + "</color>\n";
  1113.             messagesText += "Bonus materials per level: <color=" + colors[Skills.WOODCUTTING] + ">" + ((getGathMult(2, Skills.WOODCUTTING) - 1) * 100).ToString("0.##") + "%</color>\n";
  1114.  
  1115.             messagesText += "<color=" + colors[Skills.SKINNING] + '>' + "Skinning" + "</color>" + (IsSkillDisabled(Skills.SKINNING) ? "(DISABLED)" : "") + "\n";
  1116.             messagesText += "XP per hit: <color=" + colors[Skills.SKINNING] + ">" + ((int)pointsPerHitCurrent[Skills.SKINNING] * (xpMultiplier / 100f)) + "</color>\n";
  1117.             messagesText += "Bonus materials per level: <color=" + colors[Skills.SKINNING] + ">" + ((getGathMult(2, Skills.SKINNING) - 1) * 100).ToString("0.##") + "%</color>\n";
  1118.  
  1119.             if (IsSkillEnabled(Skills.ACQUIRE))
  1120.             {
  1121.                 messagesText += "<color=" + colors[Skills.ACQUIRE] + '>' + "Acquire" + "</color>" + (IsSkillDisabled(Skills.ACQUIRE) ? "(DISABLED)" : "") + "\n";
  1122.                 messagesText += "XP per hit: <color=" + colors[Skills.ACQUIRE] + ">" + ((int)pointsPerHitCurrent[Skills.ACQUIRE] * (xpMultiplier / 100f)) + "</color>\n";
  1123.                 messagesText += "Bonus materials per level: <color=" + colors[Skills.ACQUIRE] + ">" + ((getGathMult(2, Skills.ACQUIRE) - 1) * 100).ToString("0.##") + "%</color>\n";
  1124.             }
  1125.  
  1126.             messagesText += "<color=" + colors[Skills.CRAFTING] + '>' + "Crafting" + "</color>" + (IsSkillDisabled(Skills.CRAFTING) ? "(DISABLED)" : "") + "\n";
  1127.             messagesText += "XP gain: <color=" + colors[Skills.SKINNING] + ">You get " + craftingDetails["XPPerTimeSpent"] + " XP per " + craftingDetails["TimeSpent"] + "s spent crafting.</color>\n";
  1128.             messagesText += "Bonus: <color=" + colors[Skills.SKINNING] + ">Crafting time is decreased by " + craftingDetails["PercentFasterPerLevel"] + "% per every level.</color>\n";
  1129.  
  1130.             player.ChatMessage(messagesText);
  1131.         }
  1132.  
  1133.         [ChatCommand("statsui")]
  1134.         void StatsUICommand(BasePlayer player, string command, string[] args)
  1135.         {
  1136.             if (!hasRights(player.UserIDString)) return;
  1137.             if (playerPrefs.PlayerInfo[player.userID].CUI)
  1138.             {
  1139.                 DestroyGUI(player);
  1140.                 playerPrefs.PlayerInfo[player.userID].CUI = false;
  1141.             }
  1142.             else
  1143.             {
  1144.                 playerPrefs.PlayerInfo[player.userID].CUI = true;
  1145.                 CreateGUI(player);
  1146.             }
  1147.         }
  1148.  
  1149.         [ChatCommand("statsonoff")]
  1150.         void StatsOnOffCommand(BasePlayer player, string command, string[] args)
  1151.         {
  1152.             if (!hasRights(player.UserIDString)) return;
  1153.             if (playerPrefs.PlayerInfo[player.userID].ONOFF)
  1154.             {
  1155.                 DestroyGUI(player);
  1156.                 playerPrefs.PlayerInfo[player.userID].ONOFF = false;
  1157.                 player.ChatMessage(pluginPrefix + " " + msg("PluginPlayerOff"));
  1158.             }
  1159.             else
  1160.             {
  1161.                 playerPrefs.PlayerInfo[player.userID].ONOFF = true;
  1162.                 player.ChatMessage(pluginPrefix + " " + msg("PluginPlayerOn"));
  1163.                 if (playerPrefs.PlayerInfo[player.userID].CUI)
  1164.                     CreateGUI(player);
  1165.             }
  1166.         }
  1167.  
  1168.         #endregion Commands
  1169.  
  1170.         #region Functions
  1171.  
  1172.         bool hasRights(string UserIDString)
  1173.         {
  1174.             return !enablePermission || permission.UserHasPermission(UserIDString, permissionName);
  1175.         }
  1176.  
  1177.         void editMultiplierForPlayer(long multiplier, ulong userID = ulong.MinValue)
  1178.         {
  1179.             if (userID == ulong.MinValue)
  1180.             {
  1181.                 foreach (var p in playerPrefs.PlayerInfo.ToList())
  1182.                     playerPrefs.PlayerInfo[p.Key].XPM = multiplier;
  1183.                 return;
  1184.             }
  1185.             PlayerInfo playerData = null;
  1186.             if (playerPrefs.PlayerInfo.TryGetValue(userID, out playerData))
  1187.                     playerData.XPM = multiplier;
  1188.         }
  1189.  
  1190.         void adminModifyPlayerStats(ConsoleSystem.Arg arg, string skill, long level, int mode, IPlayer p)
  1191.         {
  1192.             if (skill == "*")
  1193.             {
  1194.                 var sb = new StringBuilder();
  1195.                 foreach (var currSkill in Skills.ALL)
  1196.                 {
  1197.                     if (IsSkillDisabled(currSkill)) continue;
  1198.                     var modifiedLevel = getLevel(Convert.ToUInt64(p.Id), currSkill);
  1199.                     if (mode == 0) // SET
  1200.                         modifiedLevel = level;
  1201.                     else if (mode == 1) // ADD
  1202.                         modifiedLevel += level;
  1203.                     else if (mode == 2) // SUBTRACT
  1204.                         modifiedLevel -= level;
  1205.                     else if (mode == 4) // DIVIDE
  1206.                         modifiedLevel /= level;
  1207.                     if (modifiedLevel < 1)
  1208.                         modifiedLevel = 1;
  1209.                     if (modifiedLevel > Convert.ToInt32(levelCaps[currSkill]) && Convert.ToInt32(levelCaps[currSkill]) != 0)
  1210.                     {
  1211.                         modifiedLevel = Convert.ToInt32(levelCaps[currSkill]);
  1212.                     }
  1213.                     setPointsAndLevel(Convert.ToUInt64(p.Id), currSkill, getLevelPoints(modifiedLevel), modifiedLevel);
  1214.                     var baseP = BasePlayer.FindByID(Convert.ToUInt64(p.Id));
  1215.                     if (baseP != null)
  1216.                         CreateGUI(baseP);
  1217.                     sb.Append($"({msg(currSkill + "Skill")} > {modifiedLevel}) ");
  1218.                 }
  1219.                 SendReply(arg, $"\nChanges for '{p.Name}': "+ sb.ToString().TrimEnd());
  1220.             }
  1221.             else
  1222.             {
  1223.                 var modifiedLevel = getLevel(Convert.ToUInt64(p.Id), skill);
  1224.                 if (mode == 0) // SET
  1225.                     modifiedLevel = level;
  1226.                 else if (mode == 1) // ADD
  1227.                     modifiedLevel += level;
  1228.                 else if (mode == 2) // SUBTRACT
  1229.                     modifiedLevel -= level;
  1230.                 else if (mode == 4) // DIVIDE
  1231.                     modifiedLevel /= level;
  1232.                 if (modifiedLevel < 1)
  1233.                     modifiedLevel = 1;
  1234.                 if (modifiedLevel > Convert.ToInt32(levelCaps[skill]) && Convert.ToInt32(levelCaps[skill]) != 0)
  1235.                 {
  1236.                     modifiedLevel = Convert.ToInt32(levelCaps[skill]);
  1237.                 }
  1238.                 setPointsAndLevel(Convert.ToUInt64(p.Id), skill, getLevelPoints(modifiedLevel), modifiedLevel);
  1239.                 var baseP = BasePlayer.FindByID(Convert.ToUInt64(p.Id));
  1240.                 if (baseP != null)
  1241.                     GUIUpdateSkill(baseP, skill);
  1242.                 SendReply(arg, msg(skill + "Skill") + " Lvl for [" + p.Name + "] set to: [" + modifiedLevel + "]");
  1243.             }
  1244.         }
  1245.  
  1246.         string getStatPrint(BasePlayer player, string skill)
  1247.         {
  1248.             if (IsSkillDisabled(skill))
  1249.                 return string.Empty;
  1250.  
  1251.             var skillMaxed = (int)levelCaps[skill] != 0 && getLevel(player.userID, skill) == (int)levelCaps[skill];
  1252.             var bonusText = string.Empty;
  1253.             if (skill == Skills.CRAFTING)
  1254.                 bonusText =
  1255.                     (getLevel(player.userID, skill) * (int)craftingDetails["PercentFasterPerLevel"]).ToString("0.##");
  1256.             else
  1257.                 bonusText = ((getGathMult(getLevel(player.userID, skill), skill) - 1) * 100).ToString("0.##");
  1258.  
  1259.             return string.Format("<color=" + colors[skill] + '>' + msg("StatsText", player.UserIDString) + "</color>\n",
  1260.                 msg(skill + "Skill", player.UserIDString),
  1261.                 getLevel(player.userID, skill) + (Convert.ToInt32(levelCaps[skill]) > 0 ? ("/" + levelCaps[skill]) : ""),
  1262.                 getPoints(player.userID, skill),
  1263.                 skillMaxed ? "∞" : getLevelPoints(getLevel(player.userID, skill) + 1).ToString(),
  1264.                 bonusText,
  1265.                 getExperiencePercent(player, skill),
  1266.                 getPenaltyPercent(player, skill) + "%");
  1267.         }
  1268.  
  1269.         void removePoints(ulong userID, string skill, long points)
  1270.         {
  1271.             var field = typeof(PlayerInfo).GetField(skill + "P");
  1272.             var skillpoints = (long)field.GetValue(playerPrefs.PlayerInfo[userID]);
  1273.             if (skillpoints - 10 > points)
  1274.                 skillpoints -= points;
  1275.             else
  1276.                 skillpoints = 10;
  1277.             field.SetValue(playerPrefs.PlayerInfo[userID], skillpoints);
  1278.  
  1279.             setLevel(userID, skill, getPointsLevel(skillpoints, skill));
  1280.         }
  1281.  
  1282.         void setLevel(ulong userID, string skill, long level)
  1283.         {
  1284.             var field = typeof(PlayerInfo).GetField(skill + "L");
  1285.             field.SetValue(playerPrefs.PlayerInfo[userID], level);
  1286.         }
  1287.  
  1288.         int GetPenalty(BasePlayer player, string skill)
  1289.         {
  1290.             var penalty = 0;
  1291.             var penaltyPercent = getPenaltyPercent(player, skill);
  1292.             var field = typeof(PlayerInfo).GetField(skill + "L");
  1293.             penalty = Convert.ToInt32(getPercentAmount((long)field.GetValue(playerPrefs.PlayerInfo[player.userID]), penaltyPercent));
  1294.             return penalty;
  1295.         }
  1296.  
  1297.         int getPenaltyPercent(BasePlayer player, string skill)
  1298.         {
  1299.             var penaltyPercent = 0;
  1300.             var details = playerPrefs.PlayerInfo[player.userID].LD;
  1301.             var currentTime = DateTime.UtcNow;
  1302.             var lastDeath = ToDateTimeFromEpoch(details);
  1303.             var timeAlive = currentTime - lastDeath;
  1304.             if (timeAlive.TotalMinutes >= penaltyMinutes)
  1305.             {
  1306.                 penaltyPercent = ((int)percentLostOnDeath[skill] - ((int)timeAlive.TotalHours * (int)percentLostOnDeath[skill] / 10));
  1307.                 if (penaltyPercent < 0)
  1308.                     penaltyPercent = 0;
  1309.             }
  1310.             return penaltyPercent;
  1311.         }
  1312.  
  1313.         void levelHandler(BasePlayer player, Item item, string skill)
  1314.         {
  1315.             var xpPercentBefore = getExperiencePercent(player, skill);
  1316.             var Level = getLevel(player.userID, skill);
  1317.             var Points = getPoints(player.userID, skill);
  1318.             item.amount = Mathf.CeilToInt((float)(item.amount * getGathMult(Level, skill)));
  1319.             var pointsToGet = (int)pointsPerHitCurrent[skill];
  1320.             var xpMultiplier = Convert.ToInt64(playerPrefs.PlayerInfo[player.userID].XPM);
  1321.             Points += Convert.ToInt64(pointsToGet * (xpMultiplier / 100f));
  1322.             getPointsLevel(Points, skill);
  1323.             try
  1324.             {
  1325.                 if (Points >= getLevelPoints(Level + 1))
  1326.                 {
  1327.                     var maxLevel = (int)levelCaps[skill] > 0 && Level + 1 > (int)levelCaps[skill];
  1328.                     if (!maxLevel)
  1329.                     {
  1330.                         Level = getPointsLevel(Points, skill);
  1331.                         PrintToChat(player, string.Format("<color=" + colors[skill] + '>' + msg("LevelUpText", player.UserIDString) + "</color>", msg(skill + "Skill", player.UserIDString), Level, Points, getLevelPoints(Level + 1), ((getGathMult(Level, skill) - 1) * 100).ToString("0.##")));
  1332.                         if (enableLevelupBroadcast)
  1333.                         {
  1334.                             if (!levelAnnounce.Contains(Level))
  1335.                                 return;
  1336.                             foreach (var target in BasePlayer.activePlayerList.Where(x => x.userID != player.userID))
  1337.                             {
  1338.                                 if (hasRights(target.UserIDString) && playerPrefs.PlayerInfo[target.userID].ONOFF)
  1339.                                     PrintToChat(target, string.Format(msg("LevelUpTextBroadcast", target.UserIDString), player.displayName, Level, colors[skill], msg(skill + "Skill", target.UserIDString)));
  1340.                             }
  1341.                         }
  1342.                     }
  1343.                 }
  1344.             } catch {}
  1345.             setPointsAndLevel(player.userID, skill, Points, Level);
  1346.             var xpPercentAfter = getExperiencePercent(player, skill);
  1347.             if (!xpPercentAfter.Equals(xpPercentBefore))
  1348.                 GUIUpdateSkill(player, skill);
  1349.         }
  1350.  
  1351.         string getExperiencePercent(BasePlayer player, string skill)
  1352.         {
  1353.             return getExperiencePercentInt(player, skill) + "%";
  1354.         }
  1355.  
  1356.         int getExperiencePercentInt(BasePlayer player, string skill)
  1357.         {
  1358.             var Level = getLevel(player.userID, skill);
  1359.             var startingPoints = getLevelPoints(Level);
  1360.             var nextLevelPoints = getLevelPoints(Level + 1) - startingPoints;
  1361.             var Points = getPoints(player.userID, skill) - startingPoints;
  1362.             var experienceProc = Convert.ToInt32((Points / (double)nextLevelPoints) * 100);
  1363.             if (experienceProc >= 100)
  1364.                 experienceProc = 99;
  1365.             else if (experienceProc == 0)
  1366.                 experienceProc = 1;
  1367.             return experienceProc;
  1368.         }
  1369.  
  1370.         void setPointsAndLevel(ulong userID, string skill, long points, long level)
  1371.         {
  1372.             var fieldL = typeof(PlayerInfo).GetField(skill + "L");
  1373.             fieldL.SetValue(playerPrefs.PlayerInfo[userID], level);
  1374.             var fieldP = typeof(PlayerInfo).GetField(skill + "P");
  1375.             fieldP.SetValue(playerPrefs.PlayerInfo[userID], points == 0 ? getLevelPoints(level) : points);
  1376.         }
  1377.  
  1378.         long getLevel(ulong userID, string skill)
  1379.         {
  1380.             var field = typeof(PlayerInfo).GetField(skill + "L");
  1381.             return (long)field.GetValue(playerPrefs.PlayerInfo[userID]);
  1382.         }
  1383.  
  1384.         long getPoints(ulong userID, string skill)
  1385.         {
  1386.             var field = typeof(PlayerInfo).GetField(skill + "P");
  1387.             return (long)field.GetValue(playerPrefs.PlayerInfo[userID]);
  1388.         }
  1389.  
  1390.         /*void printMaxSkillDetails(BasePlayer player, string skill)
  1391.         {
  1392.             var sql = Sql.Builder.Append("SELECT * FROM RPG_User ORDER BY " + skill + "Level DESC," + skill + "Points DESC LIMIT 1;");
  1393.             if (usingMySQL())
  1394.             {
  1395.                 _mySql.Query(sql, mySqlConnection, list =>
  1396.                 {
  1397.                     if (list.Count > 0)
  1398.                         printMaxSkillDetails(player, skill, list);
  1399.                 });
  1400.             }
  1401.             else
  1402.             {
  1403.                 _sqLite.Query(sql, sqLiteConnection, list =>
  1404.                 {
  1405.                     if (list.Count > 0)
  1406.                         printMaxSkillDetails(player, skill, list);
  1407.                 });
  1408.             }
  1409.         }
  1410.  
  1411.         void printMaxSkillDetails(BasePlayer player, string skill, List<Dictionary<string, object>> sqlData)
  1412.         {
  1413.             PrintToChat(player,
  1414.                             "<color=" + colors[skill] + ">" + messages[skill + "Skill"] + ": " +
  1415.                             sqlData[0][skill + "Level"] + " (XP: " + sqlData[0][skill + "Points"] + ")</color> <- " +
  1416.                             sqlData[0]["Name"]);
  1417.         }*/
  1418.  
  1419.         long getLevelPoints(long level) => 110 * level * level - 100 * level;
  1420.  
  1421.         long getPointsLevel(long points, string skill)
  1422.         {
  1423.             var a = 110;
  1424.             var b = 100;
  1425.             var c = -points;
  1426.             var x1 = (-b - Math.Sqrt(b * b - 4 * a * c)) / (2 * a);
  1427.             if ((int)levelCaps[skill] == 0 || (int)-x1 <= (int)levelCaps[skill])
  1428.                 return (int)-x1;
  1429.             return (int)levelCaps[skill];
  1430.         }
  1431.  
  1432.         double getGathMult(long skillLevel, string skill)
  1433.         {
  1434.             return Convert.ToDouble(defaultMultipliers[skill]) + Convert.ToDouble(resourceMultipliersCurrent[skill]) * 0.1 * (skillLevel - 1);
  1435.         }
  1436.  
  1437.         bool IsSkillDisabled(string skill)
  1438.         {
  1439.             if (skill == Skills.CRAFTING && ConVar.Craft.instant)
  1440.                 return true;
  1441.             return levelCaps[skill].ToString() == "-1";
  1442.         }
  1443.  
  1444.         bool IsSkillEnabled(string skill)
  1445.         {
  1446.             if (skill == Skills.CRAFTING && ConVar.Craft.instant)
  1447.                 return false;
  1448.             return levelCaps[skill].ToString() != "-1";
  1449.         }
  1450.  
  1451.         long getPointsNeededForNextLevel(long level)
  1452.         {
  1453.             return getLevelPoints(level + 1) - getLevelPoints(level);
  1454.         }
  1455.  
  1456.         long getPercentAmount(long level, int percent)
  1457.         {
  1458.             return (getPointsNeededForNextLevel(level) * percent) / 100;
  1459.         }
  1460.  
  1461.         #endregion Functions
  1462.  
  1463.         #region CUI
  1464.  
  1465.         void GUIUpdateSkill(BasePlayer player, string skill)
  1466.         {
  1467.             int maxRows = skillIndex.Count();
  1468.             int rowNumber = skillIndex[skill];
  1469.             long level = getLevel(player.userID, skill);
  1470.             //If the player has the max level we don't care about the percentage
  1471.             bool isMaxLevel = level == (int)levelCaps[skill];
  1472.             int percent = isMaxLevel ? 100 : getExperiencePercentInt(player, skill);
  1473.             var skillName = msg(skill + "Skill", player.UserIDString);
  1474.  
  1475.             var mainPanel = "ZL" + skillName;
  1476.             CuiHelper.DestroyUi(player, mainPanel);
  1477.  
  1478.             var value = 1 / (float)maxRows;
  1479.             var positionMin = 1 - (value * rowNumber);
  1480.             var positionMax = 2 - (1 - (value * (1 - rowNumber)));
  1481.  
  1482.             var container = new CuiElementContainer()
  1483.             {
  1484.                 {
  1485.                     new CuiPanel
  1486.                     {
  1487.                         Image = {Color = cuiBoundsBackground},
  1488.                         RectTransform = { AnchorMin = "0 " + positionMin.ToString("0.####"), AnchorMax = $"1 "+ positionMax.ToString("0.####") },
  1489.                     },
  1490.                     new CuiElement().Parent = "ZLevelsUI",
  1491.                     mainPanel
  1492.                 }
  1493.             };
  1494.  
  1495.             var innerXPBar1 = new CuiElement
  1496.             {
  1497.                 Name = CuiHelper.GetGuid(),
  1498.                 Parent = mainPanel,
  1499.                 Components =
  1500.                         {
  1501.                             new CuiImageComponent { Color = cuiXpBarBackground },
  1502.                             new CuiRectTransformComponent{ AnchorMin = "0.225 0.05", AnchorMax = "0.8 0.85" }
  1503.                         }
  1504.             };
  1505.             container.Add(innerXPBar1);
  1506.  
  1507.             var innerXPBarProgress1 = new CuiElement
  1508.             {
  1509.                 Name = CuiHelper.GetGuid(),
  1510.                 Parent = innerXPBar1.Name,
  1511.                 Components =
  1512.                         {
  1513.                             new CuiImageComponent() { Color = (string)cuiColors[skill] },
  1514.                             new CuiRectTransformComponent{ AnchorMin = "0 0", AnchorMax = (percent / 100.0) + " 0.95" }
  1515.                         }
  1516.             };
  1517.             container.Add(innerXPBarProgress1);
  1518.            
  1519.             if (cuiTextShadow)
  1520.             {
  1521.                 var innerXPBarTextShadow1 = new CuiElement
  1522.                 {
  1523.                     Name = CuiHelper.GetGuid(),
  1524.                     Parent = innerXPBar1.Name,
  1525.                     Components =
  1526.                             {
  1527.                                 new CuiTextComponent { Color = "0.1 0.1 0.1 0.75", Text = $"{skillName}", FontSize = cuiFontSizeBar, Align = TextAnchor.MiddleCenter},
  1528.                                 new CuiRectTransformComponent{ AnchorMin = "0.035 -0.1", AnchorMax = "1 1" }
  1529.                             }
  1530.                 };
  1531.                 container.Add(innerXPBarTextShadow1);
  1532.             }
  1533.  
  1534.             var innerXPBarText1 = new CuiElement
  1535.             {
  1536.                 Name = CuiHelper.GetGuid(),
  1537.                 Parent = innerXPBar1.Name,
  1538.                 Components =
  1539.                         {
  1540.                             new CuiTextComponent { Color = cuiFontColor, Text = $"{skillName}", FontSize = cuiFontSizeBar, Align = TextAnchor.MiddleCenter},
  1541.                             new CuiRectTransformComponent{ AnchorMin = "0.05 0", AnchorMax = "1 1" }
  1542.                         }
  1543.             };
  1544.             container.Add(innerXPBarText1);
  1545.            
  1546.             if (cuiTextShadow)
  1547.             {
  1548.                 var lvShader1 = new CuiElement
  1549.                 {
  1550.                     Name = CuiHelper.GetGuid(),
  1551.                     Parent = mainPanel,
  1552.                     Components =
  1553.                             {
  1554.                                 new CuiTextComponent { Text = "Lv." + level, FontSize = cuiFontSizeLvl , Align = TextAnchor.MiddleLeft, Color = "0.1 0.1 0.1 0.75" },
  1555.                                 new CuiRectTransformComponent{ AnchorMin = "0.035 -0.1", AnchorMax = $"0.5 1" }
  1556.                             }
  1557.                 };
  1558.                 container.Add(lvShader1);
  1559.             }
  1560.  
  1561.             var lvText1 = new CuiElement
  1562.             {
  1563.                 Name = CuiHelper.GetGuid(),
  1564.                 Parent = mainPanel,
  1565.                 Components =
  1566.                         {
  1567.                             new CuiTextComponent { Text = "Lv." + level, FontSize = cuiFontSizeLvl , Align = TextAnchor.MiddleLeft, Color = cuiFontColor },
  1568.                             new CuiRectTransformComponent{ AnchorMin = "0.025 0", AnchorMax = $"0.5 1" }
  1569.                         }
  1570.             };
  1571.             container.Add(lvText1);
  1572.  
  1573.             var percFinal = "MAX";
  1574.             if(!isMaxLevel) percFinal = $"{percent}%";
  1575.             if (cuiTextShadow)
  1576.             {
  1577.                 var percShader1 = new CuiElement
  1578.                 {
  1579.                     Name = CuiHelper.GetGuid(),
  1580.                     Parent = mainPanel,
  1581.                     Components =
  1582.                         {
  1583.                             new CuiTextComponent { Text = percFinal, FontSize = cuiFontSizePercent , Align = TextAnchor.MiddleRight, Color = "0.1 0.1 0.1 0.75" },
  1584.                             new CuiRectTransformComponent{ AnchorMin = "0.5 -0.1", AnchorMax = $"0.985 1" }
  1585.                         }
  1586.                 };
  1587.                     container.Add(percShader1);
  1588.             }
  1589.  
  1590.             var percText1 = new CuiElement
  1591.             {
  1592.                 Name = CuiHelper.GetGuid(),
  1593.                 Parent = mainPanel,
  1594.                 Components =
  1595.                     {
  1596.                         new CuiTextComponent { Text = percFinal, FontSize = cuiFontSizePercent , Align = TextAnchor.MiddleRight, Color = cuiFontColor },
  1597.                         new CuiRectTransformComponent{ AnchorMin = "0.5 0", AnchorMax = $"0.975 1" }
  1598.                     }
  1599.             };
  1600.             container.Add(percText1);
  1601.                
  1602.         CuiHelper.AddUi(player, container);
  1603.         }
  1604.  
  1605.         void DestroyGUI(BasePlayer player)
  1606.         {
  1607.             if (!cuiEnabled || !IsValid(player) || !playerPrefs.PlayerInfo[player.userID].ONOFF || !playerPrefs.PlayerInfo[player.userID].CUI)
  1608.                 return;
  1609.             CuiHelper.DestroyUi(player, "ZLevelsUI");
  1610.         }
  1611.  
  1612.         void CreateGUI(BasePlayer player)
  1613.         {
  1614.             if (!cuiEnabled || !IsValid(player) || !playerPrefs.PlayerInfo[player.userID].ONOFF || !playerPrefs.PlayerInfo[player.userID].CUI || !hasRights(player.UserIDString))
  1615.                 return;
  1616.             var panelName = "ZLevelsUI";
  1617.             CuiHelper.DestroyUi(player, panelName);
  1618.             var mainContainer = new CuiElementContainer()
  1619.             {
  1620.                 {
  1621.                     new CuiPanel
  1622.                     {
  1623.                         Image = {Color = "0 0 0 0"},
  1624.                         RectTransform = {AnchorMin = $"{(string)cuiPositioning["WidthLeft"]} {(string)cuiPositioning["HeightLower"]}", AnchorMax =$"{(string)cuiPositioning["WidthRight"]} {(string)cuiPositioning["HeightUpper"]}"},
  1625.                         CursorEnabled = false
  1626.                     },
  1627.                     new CuiElement().Parent = "Under",
  1628.                     panelName
  1629.                 }
  1630.             };
  1631.             CuiHelper.AddUi(player, mainContainer);
  1632.             foreach (var skill in Skills.ALL)
  1633.                 if (IsSkillEnabled(skill))
  1634.                     GUIUpdateSkill(player, skill);
  1635.         }
  1636.  
  1637.         #endregion CUI
  1638.  
  1639.         #region Helpers
  1640.  
  1641.         Boolean IsValid(BasePlayer player)
  1642.         {
  1643.             if (player is NPCPlayer || player.userID < 76561197960265728L)
  1644.                 return false;
  1645.             return true;
  1646.         }
  1647.  
  1648.         string ReadableTimeSpan(TimeSpan span)
  1649.         {
  1650.             var formatted = string.Format("{0}{1}{2}{3}{4}",
  1651.                 (span.Days / 7) > 0 ? string.Format("{0:0} weeks, ", span.Days / 7) : string.Empty,
  1652.                 span.Days % 7 > 0 ? string.Format("{0:0} days, ", span.Days % 7) : string.Empty,
  1653.                 span.Hours > 0 ? string.Format("{0:0} hours, ", span.Hours) : string.Empty,
  1654.                 span.Minutes > 0 ? string.Format("{0:0} minutes, ", span.Minutes) : string.Empty,
  1655.                 span.Seconds > 0 ? string.Format("{0:0} seconds, ", span.Seconds) : string.Empty);
  1656.  
  1657.             if (formatted.EndsWith(", ")) formatted = formatted.Substring(0, formatted.Length - 2);
  1658.             return formatted;
  1659.         }
  1660.  
  1661.         long ToEpochTime(DateTime dateTime)
  1662.         {
  1663.             var date = dateTime.ToUniversalTime();
  1664.             var ticks = date.Ticks - new DateTime(1970, 1, 1, 0, 0, 0, 0).Ticks;
  1665.             var ts = ticks / TimeSpan.TicksPerSecond;
  1666.             return ts;
  1667.         }
  1668.  
  1669.         DateTime ToDateTimeFromEpoch(long intDate)
  1670.         {
  1671.             var timeInTicks = intDate * TimeSpan.TicksPerSecond;
  1672.             return new DateTime(1970, 1, 1, 0, 0, 0, 0).AddTicks(timeInTicks);
  1673.         }
  1674.  
  1675.         string msg(string key, string id = null) => lang.GetMessage(key, this, id);
  1676.  
  1677.         ItemDefinition GetItem(string shortname)
  1678.         {
  1679.             if (string.IsNullOrEmpty(shortname) || CraftItems == null) return null;
  1680.             ItemDefinition item;
  1681.             if (CraftItems.TryGetValue(shortname, out item)) return item;
  1682.             return null;
  1683.         }
  1684.  
  1685.         void GenerateItems(bool reset = false)
  1686.         {
  1687.             if (!reset)
  1688.             {
  1689.                 var config_protocol = gameProtocol;
  1690.                 if (config_protocol != Rust.Protocol.network)
  1691.                 {
  1692.                     gameProtocol = Rust.Protocol.network;
  1693.                     Config["Generic","gameProtocol"] = gameProtocol;
  1694.                     Puts("Updating item list from protocol " + config_protocol + " to protocol " + gameProtocol + ".");
  1695.                     GenerateItems(true);
  1696.                     SaveConfig();
  1697.                     return;
  1698.                 }
  1699.             }
  1700.  
  1701.             if (reset)
  1702.             {
  1703.                 Interface.GetMod().DataFileSystem.WriteObject("ZLevelsCraftDetails.old", _craftData);
  1704.                 _craftData.CraftList.Clear();
  1705.                 Puts("Generating new item list...");
  1706.             }
  1707.  
  1708.             CraftItems = ItemManager.itemList.ToDictionary(i => i.shortname);
  1709.             int loaded = 0, enabled = 0;
  1710.             foreach (var definition in CraftItems)
  1711.             {
  1712.                 if (definition.Value.shortname.Length >= 1)
  1713.                 {
  1714.                     CraftInfo p;
  1715.                     if (_craftData.CraftList.TryGetValue(definition.Value.shortname, out p))
  1716.                     {
  1717.                         if (p.Enabled) { enabled++; }
  1718.                         loaded++;
  1719.                     }
  1720.                     else
  1721.                     {
  1722.                         var z = new CraftInfo
  1723.                         {
  1724.                             shortName = definition.Value.shortname,
  1725.                             MaxBulkCraft = MaxB,
  1726.                             MinBulkCraft = MinB,
  1727.                             Enabled = true
  1728.                         };
  1729.                         _craftData.CraftList.Add(definition.Value.shortname, z);
  1730.                         loaded++;
  1731.                     }
  1732.                 }
  1733.             }
  1734.             var inactive = loaded - enabled;
  1735.             Puts("Loaded " + loaded + " items. (Enabled: " + enabled + " | Inactive: " + inactive + ").");
  1736.             Interface.GetMod().DataFileSystem.WriteObject("ZLevelsCraftDetails", _craftData);
  1737.         }
  1738.  
  1739.         #endregion Helpers
  1740.  
  1741.     }
  1742. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement