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

FREE RaidProtection : 2.1.8 2.1.8

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

namespace Oxide.Plugins
{
	[Info("Raid Protection", "mr01sam", "2.1.8")]
	[Description("Configurable raid protection at the cost of a resource")]
	public class RaidProtection : CovalencePlugin
	{
		/*
		 * CURRENT CHANGELOG
		 * - Removed raidprotection.ui permission which causes spam
		 * - Fixed miscalculations with damage costs
		 * - Cupboard balances are now saved upon plugin unload as well as server save
		 * - Tesla coils can no longer be protected from their own shock damage
		 * - Loot container entities, like barrels and supply drops, are no longer protected
		 */

		[PluginReference]
		private readonly Plugin Economics;

		[PluginReference]
		private readonly Plugin ServerRewards;

		[PluginReference]
		private readonly Plugin ScrapRaidProtection;

		[PluginReference]
		private readonly Plugin ImageLibrary;

		public static RaidProtection PLUGIN;

		public readonly int COLLECTION_INTERVAL = 30;

		public readonly string PermissionLevel = "raidprotection.level.";
		public const string PermissionAdmin = "raidprotection.admin";

		private readonly HashSet<ulong> onCooldown = new HashSet<ulong>();

		private readonly EconomyPanel economyPanel = new EconomyPanel();

		private readonly string[] trackedBuildingBlocks = new string[] { "foundation", "foundation.triangle", "floor", "floor.triangle" };

		private bool UseMaterialPrices;
		private ItemDefinition CurrencyItemDef;

		#region Oxide Hooks

		private void Init()
		{
			Unsubscribe(nameof(Unload));
			Unsubscribe(nameof(OnServerSave));
			Unsubscribe(nameof(OnPlayerSleepEnded));
			Unsubscribe(nameof(OnUserConnected));
			Unsubscribe(nameof(OnUserDisconnected));
			Unsubscribe(nameof(OnEntitySpawned));
			Unsubscribe(nameof(OnEntityKill));
			Unsubscribe(nameof(OnEntityDeath));
			Unsubscribe(nameof(OnCupboardAuthorize));
			Unsubscribe(nameof(OnCupboardDeauthorize));
			Unsubscribe(nameof(OnCupboardClearList));
			Unsubscribe(nameof(OnUserPermissionGranted));
			Unsubscribe(nameof(OnUserPermissionRevoked));
			Unsubscribe(nameof(OnUserGroupAdded));
			Unsubscribe(nameof(OnUserGroupRemoved));
			Unsubscribe(nameof(OnGroupPermissionGranted));
			Unsubscribe(nameof(OnGroupPermissionRevoked));
			Unsubscribe(nameof(OnLootEntity));
			Unsubscribe(nameof(OnLootEntityEnd));
			Unsubscribe(nameof(OnEntityTakeDamage));
			Unsubscribe(nameof(OnEntityBuilt));
			Unsubscribe(nameof(OnEntityKill));
			Unsubscribe(nameof(OnStructureUpgrade));
			ProtectionLevel.Load();
			PLUGIN = this;
		}

		private void OnServerInitialized()
		{
			if (ScrapRaidProtection)
			{
				PrintError($"You have both Raid Protection and Scrap Raid Protection installed.Raid Protection is a new version of Scrap Raid Protection and it is recommened that you remove Scrap Raid Protection.");
			}
			if (config.Settings.UseEconomics && !Economics)
			{
				PrintWarning($"You do not have the Economics plugin installed, setting 'Use economics balance' to false");
				config.Settings.UseEconomics = false;
			}
			if (config.Settings.UseRP && !ServerRewards)
			{
				PrintWarning($"You do not have the Server Rewards plugin installed, setting 'Use rewards points' to false");
				config.Settings.UseRP = false;
			}
			if (config.Settings.UseRP && config.Settings.UseEconomics)
			{
				PrintWarning($"You have both 'Use reward points' and 'Use economics balance' set to true.Only one can be used.Setting 'Use economics balance' to false");
				config.Settings.UseEconomics = false;
			}

			InitProtectionLevels();
			LoadImages();
			LoadAllTcs();
			ResetUI();

			Subscribe(nameof(Unload));
			Subscribe(nameof(OnServerSave));
			Subscribe(nameof(OnPlayerSleepEnded));
			Subscribe(nameof(OnUserConnected));
			Subscribe(nameof(OnUserDisconnected));
			Subscribe(nameof(OnEntitySpawned));
			Subscribe(nameof(OnEntityKill));
			Subscribe(nameof(OnEntityDeath));
			Subscribe(nameof(OnCupboardAuthorize));
			Subscribe(nameof(OnCupboardDeauthorize));
			Subscribe(nameof(OnCupboardClearList));
			Subscribe(nameof(OnUserPermissionGranted));
			Subscribe(nameof(OnUserPermissionRevoked));
			Subscribe(nameof(OnUserGroupAdded));
			Subscribe(nameof(OnUserGroupRemoved));
			Subscribe(nameof(OnGroupPermissionGranted));
			Subscribe(nameof(OnGroupPermissionRevoked));
			Subscribe(nameof(OnLootEntity));
			Subscribe(nameof(OnLootEntityEnd));
			Subscribe(nameof(OnEntityTakeDamage));
			Subscribe(nameof(OnEntityBuilt));
			Subscribe(nameof(OnEntityKill));
			Subscribe(nameof(OnStructureUpgrade));
		}

		private void OnServerSave()
		{
			SaveTcBalances();
		}

		private void Unload()
		{
			SaveTcBalances();
			ProtectedCupboard.Unload();
			ProtectionLevel.Unload();
			PLUGIN = null;
		}

		private void OnUserConnected( IPlayer player )
		{
			HandleUserConnected(player);
		}

		private void OnUserDisconnected( IPlayer player )
		{
			HandleUserDisconnected(player);
		}

		void OnPlayerSleepEnded( BasePlayer player )
		{
			if (config.Indicator.Persistent)
			{
				IndicatorLoop(player);
			}
		}

		private void OnEntitySpawned( BuildingPrivlidge priv )
		{
			timer.In(0.1f, () =>
			{
				if (priv.IsValid())
				{
					ProtectedCupboard.InitCupboard(priv);
				}
			});
		}

		private void OnEntityKill( BuildingPrivlidge priv )
		{
			ProtectedCupboard.RemoveCupboard(priv);
		}

		private void OnEntityDeath( BuildingPrivlidge priv, HitInfo hitInfo ) => OnEntityKill(priv);

		private object OnCupboardAuthorize( BuildingPrivlidge priv, BasePlayer player )
		{
			timer.In(0.1f, () =>
			{
				if (priv.IsValid())
				{
					ProtectedCupboard tc = ProtectedCupboard.InitCupboard(priv);
					if ((tc != null) && (!permission.UserHasPermission(player.userID.ToString(), PermissionAdmin)))
					{
						tc.AllOwnerIds.Add(player.userID);
						tc.OnlineOwners.Add(player);
						tc.UpdateHighestProtectionLevel();
						tc.UpdateTotalBuildingCost();
						tc.UpdateProtectionCostPerHour();
						tc.UpdateStatus();
					}
				}
			});
			return null;
		}

		private object OnCupboardDeauthorize( BuildingPrivlidge priv, BasePlayer player )
		{
			timer.In(0.1f, () =>
			{
				if (priv.IsValid())
				{
					ProtectedCupboard tc = ProtectedCupboard.InitCupboard(priv);
					if ((tc != null) && (!permission.UserHasPermission(player.userID.ToString(), PermissionAdmin)))
					{
						tc.AllOwnerIds.Remove(player.userID);
						tc.OnlineOwners.Remove(player);
						tc.UpdateHighestProtectionLevel();
						tc.UpdateTotalBuildingCost();
						tc.UpdateProtectionCostPerHour();
						tc.UpdateStatus();
					}
				}
			});
			return null;
		}

		private object OnCupboardClearList( BuildingPrivlidge priv, BasePlayer player )
		{
			timer.In(0.1f, () =>
			{
				if (priv.IsValid())
				{
					ProtectedCupboard tc = ProtectedCupboard.InitCupboard(priv);
					if (tc != null)
					{
						tc.AllOwnerIds = new HashSet<ulong>();
						tc.UpdateHighestProtectionLevel();
						tc.UpdateTotalBuildingCost();
						tc.UpdateProtectionCostPerHour();
						tc.UpdateStatus();
					}
				}
			});
			return null;
		}

		private void OnUserPermissionGranted( string id, string permName )
		{
			HandleUserPermissionChanged(id, permName);
		}

		private void OnUserPermissionRevoked( string id, string permName )
		{
			HandleUserPermissionChanged(id, permName);
		}

		void OnUserGroupAdded( string id, string groupName )
		{
			if (groupName != null)
				HandleUserPermissionChanged(id, PermissionLevel);
		}

		void OnUserGroupRemoved( string id, string groupName )
		{
			if (groupName != null)
				HandleUserPermissionChanged(id, PermissionLevel);
		}

		private void OnGroupPermissionGranted( string group, string permName )
		{
			HandleGroupPermissionChanged(group, permName);
		}

		private void OnGroupPermissionRevoked( string group, string permName )
		{
			HandleGroupPermissionChanged(group, permName);
		}

		void OnLootEntity( BasePlayer player, BuildingPrivlidge priv )
		{
			if (player != null && priv != null)
			{
				ProtectedCupboard tc = ProtectedCupboard.InitCupboard(priv);
				if (tc != null)
				{
					tc.PlayersViewing.Add(player);
					OpenUi(player, priv);
				}
			}
		}

		private void OnLootEntityEnd( BasePlayer player, BuildingPrivlidge priv )
		{
			ProtectedCupboard tc = ProtectedCupboard.InitCupboard(priv);
			if (tc != null)
			{
				tc.PlayersViewing.Remove(player);
			}
			CloseUi(player);
		}

		object OnLootNetworkUpdate( PlayerLoot loot )
		{
			if (loot.entitySource != null && loot.entitySource is BuildingPrivlidge && !config.Settings.UseEconomics && !config.Settings.UseRP)
			{
				ProtectedCupboard tc = ProtectedCupboard.InitCupboard((BuildingPrivlidge)loot.entitySource);
				if (tc != null)
				{
					bool before = tc.IsActive;
					tc.UpdateStoredBalance(tc.ProtectionCostPerInterval);
					tc.InitialPurchaseProtection();
					BasePlayer player = loot._baseEntity;
					if (player != null && tc.Priv != null)
					{
						OpenUi(player, tc.Priv);
					}
					if (tc.IsActive != before)
					{
						ShowIndicatorForOwners(tc);
					}
				}
			}
			return null;
		}

		private object OnEntityTakeDamage( DecayEntity entity, HitInfo info )
		{
			return config.Protection.ProtectBuildings ? ProtectFromDamage(entity, info) : null;
		}

		private object OnEntityTakeDamage( LootContainer entity, HitInfo info )
		{
			return null;
		}

		private object OnEntityTakeDamage( BaseMountable entity, HitInfo info )
		{
			return config.Protection.ProtectVehicles ? ProtectFromDamage(entity, info) : null;
		}

		private object OnEntityTakeDamage( BasePlayer entity, HitInfo info )
		{
			return config.Protection.ProtectPlayers ? ProtectFromDamage(entity, info) : null;
		}

		private object OnEntityTakeDamage( NPCPlayer entity, HitInfo info )
		{
			return null;
		}

		private object OnEntityTakeDamage( IOEntity entity, HitInfo info )
		{
			return config.Protection.ProtectTraps ? ProtectFromDamage(entity, info) : null;
		}

		private object OnEntityTakeDamage( BaseResourceExtractor entity, HitInfo info )
		{
			return config.Protection.ProtectBuildings ? ProtectFromDamage(entity, info) : null;
		}

		private void OnEntityBuilt( Planner plan, GameObject go )
		{
			if (plan == null || go?.name == "assets/prefabs/deployable/tool cupboard/cupboard.tool.deployed.prefab") return;
			DebugTimeStart("OnEntityBuilt");
			BuildingPrivlidge priv = plan.GetBuildingPrivilege();
			if (priv != null)
			{
				ProtectedCupboard tc = ProtectedCupboard.InitCupboard(priv);
				if (tc != null)
				{
					tc.UpdateTotalBuildingCost();
					tc.UpdateProtectionCostPerHour();
				}
			}
			DebugTimeEnd("OnEntityBuilt");
		}

		private void OnEntityKill( BuildingBlock block )
		{
			BuildingPrivlidge priv = block.GetBuildingPrivilege();
			if (priv != null)
			{
				ProtectedCupboard tc = ProtectedCupboard.InitCupboard(priv);
				timer.In(0.1f, () =>
				{
					if (tc != null)
					{
						tc.UpdateTotalBuildingCost();
						tc.UpdateProtectionCostPerHour();
					}
				});
			}
		}

		private void OnEntityDeath( BuildingBlock block, HitInfo hitInfo ) => OnEntityKill(block);

		private object OnStructureUpgrade( BuildingBlock block, BasePlayer player, BuildingGrade.Enum grade )
		{
			BuildingPrivlidge priv = block.GetBuildingPrivilege();
			if (priv != null)
			{
				ProtectedCupboard tc = ProtectedCupboard.InitCupboard(priv);
				if (tc != null)
				{
					tc.UpdateTotalBuildingCost();
					tc.UpdateProtectionCostPerHour();
				}
			}
			return null;
		}

		#endregion Oxide Hooks

		#region Helper Functions

		private object ProtectFromDamage( BaseCombatEntity entity, HitInfo info )
		{
			if (entity?.net == null) return null;
			if (info == null) return null;

			BuildingPrivlidge priv = entity.GetBuildingPrivilege();
			if (priv == null) { return null; };

			Rust.DamageType majorityDamage = info.damageTypes.GetMajorityDamageType();
			if (majorityDamage == Rust.DamageType.Decay || majorityDamage == Rust.DamageType.ElectricShock) { return null; };

			ProtectedCupboard tc = ProtectedCupboard.InitCupboard(priv);
			if (tc == null) { return null; };

			DebugTimeStart("ProtectFromDamage");
			if (tc.Status == ProtectionStatus.Protected)
			{

				if (tc.ProtectionPercentage >= 100)
				{
					ApplyDamageCost(tc, info, majorityDamage);
					if (info.Initiator is BasePlayer && info.InitiatorPlayer != null)
					{
						ShowIndicator(info.InitiatorPlayer, priv, true);
					}
					DebugTimeEnd("ProtectFromDamage");
					return true;
				}
				else
				{
					ApplyDamageCost(tc, info, majorityDamage, (tc.ProtectionPercentage / 100));
					info.damageTypes.ScaleAll((float)(1 - (tc.ProtectionPercentage / 100)));
					if (info.Initiator is BasePlayer && info.InitiatorPlayer != null)
					{
						ShowIndicator(info.InitiatorPlayer, priv, true);
					}
				}
			}
			else
			{
				tc.MostRecentAttack = DateTime.Now;
			}
			DebugTimeEnd("ProtectFromDamage");
			return null;
		}

		private void ApplyDamageCost( ProtectedCupboard tc, HitInfo info, Rust.DamageType majorityDamage, float ratio = 1f )
		{
			if (tc.CostPerDamage > 0 && majorityDamage != Rust.DamageType.Heat)
			{
				float costFromDamage = info.damageTypes.Total() * tc.CostPerDamage * (ratio);
				tc.UpdateCostDebt(costFromDamage);
				tc.UpdateStoredBalance(costFromDamage);
				tc.UpdateStatus();
				PLUGIN.Debug($"TC with ID={tc.Priv.net.ID} consumed ${costFromDamage} from damage");
			}
		}

		private void InitProtectionLevels()
		{
			try
			{
				foreach (int i in config.Protection.ProtectionLevels.Keys)
				{
					permission.RegisterPermission(PermissionLevel + i.ToString(), this);
					Puts($"Registered permission {PermissionLevel + i.ToString()}");
				}
			}
			catch
			{
				PrintError("Failed to load protection levels from config file, make sure they are properly formatted.");
			}
		}

		private string FormatCurrency( double amount )
		{
			if (config.Settings.UseRP)
			{
				return $"{amount} RP";
			}
			if (config.Settings.UseEconomics)
			{
				return $"{amount:C}";
			}
			return $"{amount} {CurrencyItemDef.displayName.translated}";

		}

		private string GetStatusMessage( BasePlayer player, ProtectedCupboard tc )
		{
			if (!tc.HasPermission || !tc.HasAnyProtection)
			{
				return Lang("StatusNoPermission", player.UserIDString);
			}
			if (!tc.CanAffordProtection && tc.IsActive)
			{
				return Lang("StatusNoBalance", player.UserIDString);
			}
			if (!tc.CanAffordProtection && !tc.IsActive)
			{
				return Lang("StatusUnprotected", player.UserIDString, FormatCurrency((int)Math.Ceiling(tc.ProtectionCostPerInterval)));
			}
			switch (tc.Status)
			{
				case ProtectionStatus.Protected:
					return Lang("StatusProtected", player.UserIDString, tc.ProtectionPercentage, GetTimeRemaining(player, tc));

				case ProtectionStatus.PendingOfflineOnly:
					return Lang("StatusPendingOffline", player.UserIDString, tc.HighestProtectionLevel.OfflineProtectionPercentage);

				case ProtectionStatus.PendingRecentlyDamage:
					return Lang("StatusPendingDamage", player.UserIDString, tc.ProtectionPercentage);

				default:
					return Lang("StatusUnprotected", player.UserIDString, FormatCurrency((int)Math.Ceiling(tc.ProtectionCostPerInterval)));
			}
		}

		private string GetTimeRemaining( BasePlayer player, ProtectedCupboard tc )
		{
			return GetTimeRemaining(player.UserIDString, tc);
		}

		private string GetTimeRemaining( string UserIDString, ProtectedCupboard tc )
		{
			float hours = tc.HoursRemaining;
			if (hours <= 0 || tc.HoursRemaining <= 0)
			{
				return "∞";
			}
			if (hours >= 24)
			{
				return Math.Round(hours / 24, 1).ToString() + $" {Lang("Days", UserIDString)}";
			}
			if (hours >= 1)
			{
				return Math.Round(hours, 1).ToString() + $" {Lang("Hours", UserIDString)}";
			}
			else
			{
				return Math.Round((hours * 60), 1).ToString() + $" {Lang("Minutes", UserIDString)}";
			}
		}

		private void LoadImages()
		{
			if (ImageLibrary != null && ImageLibrary.IsLoaded)
			{
				ImageLibrary.Call<bool>("AddImage", config.Indicator.ImageUrl, "SrpIndicatorIcon", 0UL);
			}
		}

		private void LoadAllTcs()
		{
			timer.In(1f, () =>
			{
				ProtectedCupboard.toolcupboards = new Dictionary<uint, ProtectedCupboard>();
				List<BuildingPrivlidge> allCupboards = GameObject.FindObjectsOfType<BuildingPrivlidge>().ToList();
				int i = 0;
				foreach (BuildingPrivlidge priv in allCupboards)
				{
					if (ProtectedCupboard.InitCupboard(priv) != null)
					{
						i++;
					}
				}
				Puts($"Initialized {i} cupboards");
				StartCollecting();
				StartIndicatorLoops();
				LoadTcBalances();
			});
		}

		private void StartCollecting()
		{
			int i = 0;
			PLUGIN.Debug($"Starting collection loop");
			PLUGIN.timer.Repeat(0.1f, ProtectedCupboard.toolcupboards.Count, () =>
			{
				if (ProtectedCupboard.toolcupboards != null && ProtectedCupboard.toolcupboards.Keys.Count > i)
				{
					ProtectedCupboard tc = ProtectedCupboard.toolcupboards[ProtectedCupboard.toolcupboards.Keys.ElementAt(i)];
					if (tc != null && tc.Priv != null)
					{
						tc.PurchaseProtection();
						i++;
					}
				}
			});
		}

		private void StartIndicatorLoops()
		{
			if (config.Indicator.Persistent)
			{
				PLUGIN.Debug($"Starting indicator loop");
				foreach (BasePlayer basePlayer in BasePlayer.activePlayerList)
				{
					IndicatorLoop(basePlayer);
				}
			}
		}

		private void SaveTcBalances()
		{
			if (config.Settings.UseEconomics || config.Settings.UseRP)
			{
				Dictionary<uint, float> balances = ProtectedCupboard.toolcupboards.Values.ToDictionary(x => x.Priv.net.ID, x => x.StoredBalance);
				Interface.Oxide.DataFileSystem.WriteObject("CupboardBalances", balances);
				Debug($"Saved {balances.Count} balances");
			}
		}

		private void LoadTcBalances()
		{
			if (config.Settings.UseEconomics || config.Settings.UseRP)
			{
				timer.In(0.5f, () =>
				{
					Dictionary<uint, float> balances = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<uint, float>>("CupboardBalances");
					int loaded = 0;
					foreach (uint key in balances.Keys)
					{
						if (ProtectedCupboard.toolcupboards.ContainsKey(key))
						{
							ProtectedCupboard tc = ProtectedCupboard.toolcupboards[key];
							tc.StoredBalance = balances[key];
							tc.PurchaseProtection();
							loaded++;
						}
					}
					Debug($"Loaded {loaded} balances");
				});

			}
		}

		private void ResetUI()
		{
			foreach (BasePlayer basePlayer in BasePlayer.activePlayerList)
			{
				if (basePlayer.IsValid())
				{
					CloseUi(basePlayer);
					CloseIndicator(basePlayer);
					if (onCooldown.Contains(basePlayer.userID))
						onCooldown.Remove(basePlayer.userID);
				}
			}
		}

		private double GetBalance( ulong userId )
		{
			if (config.Settings.UseRP)
			{
				int? points = (int?)ServerRewards.Call("CheckPoints", userId);
				return points ?? 0;
			}
			if (config.Settings.UseEconomics)
			{
				return (double)Economics.Call("Balance", userId);
			}
			return 0;
		}

		private void TakeBalance( ulong userId, double amount )
		{
			if (config.Settings.UseRP)
			{
				ServerRewards.Call("TakePoints", userId, (int)amount);
			}
			if (config.Settings.UseEconomics)
			{
				Economics.Call("Withdraw", userId, amount);
			}
		}

		private void GiveBalance( ulong userId, double amount )
		{
			if (config.Settings.UseRP)
			{
				ServerRewards.Call("AddPoints", userId, (int)amount);
			}
			if (config.Settings.UseEconomics)
			{
				Economics.Call("Deposit", userId, amount);
			}
		}

		private void HandleUserPermissionChanged( string id, string permName )
		{
			if (id == null || permName == null)
				return;
			if (permName.StartsWith(PermissionLevel))
			{
				List<BuildingPrivlidge> allPrivlidges = BaseNetworkable.serverEntities.OfType<BuildingPrivlidge>().ToList();
				BasePlayer player = BasePlayer.FindByID(ulong.Parse(id));
				if (player.IsValid())
				{
					foreach (BuildingPrivlidge priv in allPrivlidges)
					{
						if ((priv.IsAuthed(player)) && (!permission.UserHasPermission(player.userID.ToString(), PermissionAdmin)))
						{
							ProtectedCupboard tc = ProtectedCupboard.InitCupboard(priv);
							if (tc != null)
							{
								tc.UpdateHighestProtectionLevel();
								tc.UpdateTotalBuildingCost();
								tc.UpdateProtectionCostPerHour();
								tc.UpdateStatus();
							}
						}
					}
				}
			}
		}

		private void HandleGroupPermissionChanged( string group, string permName )
		{
			if (group == null || permName == null)
				return;
			if (permName.StartsWith(PermissionLevel))
			{
				string[] userIds = permission.GetUsersInGroup(group);
				foreach (string steamid in userIds)
				{
					BasePlayer basePlayer = BasePlayer.Find(steamid.Split(' ')[0]);
					if (basePlayer != null)
					{
						if (!permission.UserHasPermission(basePlayer.userID.ToString(), PermissionAdmin))
							HandleUserPermissionChanged(basePlayer.UserIDString, permName);
					}
				}
			}
		}

		private void HandleUserConnected( IPlayer player )
		{
			timer.In(0.1f, () =>
			{
				DebugTimeStart("HandleUserConnected");
				if (player != null)
				{
					foreach (ProtectedCupboard tc in ProtectedCupboard.toolcupboards.Values.Where(
						x => x?.Priv != null
						&& x.AllOwnerIds.Contains(ulong.Parse(player.Id))
						&& x.OnlineOwners.Count == 1
						&& !(x.HasOnlineProtection && x.HasOfflineProtection)
					))
					{
						if (tc.HasOnlineProtection && !tc.IsActive)
						{
							tc.PurchaseProtection();
						}
						else if (tc.HasOfflineProtection && tc.IsActive)
						{
							tc.StopProtection();
						}
					}
				}
				DebugTimeEnd("HandleUserConnected");
			});
		}

		private void HandleUserDisconnected( IPlayer player )
		{
			timer.In(0.1f, () =>
			{
				DebugTimeStart("HandleUserDisconnected");
				if (player != null)
				{
					foreach (ProtectedCupboard tc in ProtectedCupboard.toolcupboards.Values.Where(
						x => x?.Priv != null
						&& x.AllOwnerIds.Contains(ulong.Parse(player.Id))
						&& x.OnlineOwners.Count == 0
						&& !(x.HasOnlineProtection && x.HasOfflineProtection)
					))
					{
						if (tc.HasOnlineProtection && tc.IsActive)
						{
							tc.StopProtection();
						}
						else if (tc.HasOfflineProtection && !tc.IsActive)
						{
							timer.In(config.Protection.OfflineProtectionDelay, () =>
							{
								if (tc?.Priv != null && !tc.HasOwnersOnline)
								{
									tc.PurchaseProtection();
								}
							});
						}
					}
				}
				DebugTimeEnd("HandleUserDisconnected");
			});
		}

		private void IndicatorLoop( BasePlayer player )
		{
			if (config.Indicator.Persistent)
			{
				timer.In(2f, () =>
				{
					if (player != null && player.IsConnected && !player.IsSleeping())
					{
						BuildingPrivlidge priv = player.GetBuildingPrivilege();
						if (priv != null)
						{
							ProtectedCupboard tc = ProtectedCupboard.InitCupboard(priv);
							if (tc != null)
							{
								if (priv.IsAuthed(player) && tc.HasOnlineProtection)
								{
									ShowIndicator(player, priv, true, true, true);
								}
								else if (tc.Status == ProtectionStatus.Protected)
								{
									ShowIndicator(player, priv, true, true, true);
								}
								else
								{
									CloseIndicator(player);
								}
							}
						}
						else
						{
							CloseIndicator(player);
						}
						IndicatorLoop(player);
					}
				});
			}
		}

		#endregion Helper Functions

		#region Classes

		private enum ProtectionStatus
		{
			Unprotected = 0,
			PendingOfflineOnly = 1, /* Not currently protected, but will be when offline */
			PendingOnlineOnly = 2, /* Not currently protected, but will be when online */
			PendingRecentlyDamage = 3,
			Protected = 4
		}

		private class EconomyPanel
		{
			private const float MIN = 0f;
			private const float MAX = 9999f;

			private Dictionary<string, float> SetBalances = new Dictionary<string, float>();

			public void Increment( string userIdString, float amount )
			{
				if (!SetBalances.ContainsKey(userIdString))
				{
					SetBalances.Add(userIdString, MIN);
				}
				SetBalances[userIdString] = Math.Min(SetBalances[userIdString] + amount, MAX);
			}

			public void Decrement( string userIdString, float amount )
			{
				if (!SetBalances.ContainsKey(userIdString))
				{
					SetBalances.Add(userIdString, MIN);
				}
				SetBalances[userIdString] = Math.Max(SetBalances[userIdString] - amount, MIN);
			}

			public float Get( string userIdString )
			{
				if (!SetBalances.ContainsKey(userIdString))
				{
					SetBalances.Add(userIdString, MIN);
				}
				return SetBalances[userIdString];
			}

			public void Reset( string userIdString )
			{
				if (!SetBalances.ContainsKey(userIdString))
				{
					SetBalances.Add(userIdString, MIN);
				}
				SetBalances[userIdString] = MIN;
			}
		}

		private class ProtectionLevel
		{
			public static ProtectionLevel NONE { get; set; }

			[JsonProperty(PropertyName = "Online protection percentage (0-100)")]
			public float OnlineProtectionPercentage { get; set; }

			[JsonProperty(PropertyName = "Offline protection percentage (0-100)")]
			public float OfflineProtectionPercentage { get; set; }

			[JsonProperty(PropertyName = "Hourly building cost", NullValueHandling = NullValueHandling.Ignore)]
			public float? HourlyBuildingCost { get; set; } = null;

			[JsonProperty(PropertyName = "Hourly base cost", NullValueHandling = NullValueHandling.Ignore)]
			public float? HourlyBaseCost { get; set; } = null;

			[JsonProperty(PropertyName = "Structure damage cost", NullValueHandling = NullValueHandling.Ignore)]
			public float? CostPerDamage { get; set; } = null;

			public static int LevelOf( string useridstring )
			{
				List<int> keys = PLUGIN.config.Protection.ProtectionLevels.Keys.ToList();
				keys.Sort(( a, b ) => b.CompareTo(a));
				foreach (int i in keys)
				{
					if (PLUGIN.permission.UserHasPermission(useridstring, PLUGIN.PermissionLevel + i) || PLUGIN.permission.GetUserGroups(useridstring).Any(groupid => PLUGIN.permission.GroupHasPermission(groupid, PLUGIN.PermissionLevel + i)))
					{
						return (int)i;
					}
				}
				return -1;
			}

			public override string ToString()
			{
				return this == NONE ? "--" : PLUGIN.config.Protection.ProtectionLevels.Values.ToList().IndexOf(this).ToString();
			}

			public static void Load()
			{
				NONE = new ProtectionLevel { OnlineProtectionPercentage = 0f, OfflineProtectionPercentage = 0f };
			}

			public static void Unload()
			{
				NONE = null;
			}
		}

		private class ProtectedCupboard
		{
			public static Dictionary<uint, ProtectedCupboard> toolcupboards = new Dictionary<uint, ProtectedCupboard>();

			public static ProtectedCupboard InitCupboard( BuildingPrivlidge priv )
			{
				if (priv != null && toolcupboards != null && !toolcupboards.ContainsKey(priv.net.ID))
				{
					toolcupboards.Add(priv.net.ID, new ProtectedCupboard(priv));
					PLUGIN.Debug($"Added TC with ID={priv.net.ID}");
					PLUGIN.Debug($"There are {toolcupboards.Count} TCs added");
					return toolcupboards[priv.net.ID];
				}
				else if (priv != null && toolcupboards != null)
				{
					return toolcupboards[priv.net.ID];
				}
				return null;
			}

			public static void RemoveCupboard( BuildingPrivlidge priv )
			{
				if (priv != null && toolcupboards.ContainsKey(priv.net.ID))
				{
					toolcupboards.Remove(priv.net.ID);
					PLUGIN.Debug($"Removed TC with ID={priv.net.ID}");
					PLUGIN.Debug($"There are {toolcupboards.Count} TCs added");
				}
			}

			public BuildingPrivlidge Priv { get; set; }

			public float ProtectionCostPerHour { get; private set; }

			public float HoursRemaining
			{
				get { return StoredBalance / ProtectionCostPerHour; }
			}

			public float ProtectionCostPerInterval
			{
				get { return ProtectionCostPerHour / 3600 * PLUGIN.COLLECTION_INTERVAL; }
			}


			public int SurfaceBlockCount { get { return Priv == null ? 0 : Priv.GetBuilding().buildingBlocks.Where(x => x.ShortPrefabName.Contains("floor") || x.ShortPrefabName.Contains("foundation")).Count(); } }

			public DateTime MostRecentAttack { get; set; }

			public bool RecentlyDamaged
			{
				get { return MostRecentAttack == null ? false : (DateTime.Now - MostRecentAttack).TotalSeconds < PLUGIN.config.Protection.ProtectedDelayAfterTakingDamage; }
			}

			public float StoredBalance { get; set; }

			public float CostDebt { get; set; }

			public bool ContentsLocked { get; set; }

			public int ItemAmount { get { return Priv.inventory.GetAmount(PLUGIN.config.Settings.CurrencyItemId, false); } }

			public float HourlyBaseCost { get; set; }

			public float HourlyBuildingCost { get; set; }

			public float TotalBuildingCost { get; set; }

			public float CostPerDamage { get; set; }

			public bool CanAffordProtection
			{
				get { return StoredBalance >= ProtectionCostPerInterval; }
			}

			public HashSet<BasePlayer> PlayersViewing { get; set; }

			public HashSet<ulong> AllOwnerIds { get; set; }

			public HashSet<BasePlayer> OnlineOwners
			{
				get
				{
					return _debugging ? PLUGIN._onlinePlayers : (from id in AllOwnerIds select BasePlayer.FindByID(id)).Where(x => x != null && x.IsConnected).ToHashSet();
				}
			}

			public ProtectionLevel HighestProtectionLevel { get; set; }

			public bool ForcedProtectionLevel { get; set; }

			public bool IsActive { get; set; }

			public bool HasPermission { get { return HighestProtectionLevel != ProtectionLevel.NONE; } }

			public bool HasOnlineProtection { get { return HighestProtectionLevel.OnlineProtectionPercentage > 0; } }

			public bool HasOfflineProtection { get { return HighestProtectionLevel.OfflineProtectionPercentage > 0; } }

			public bool HasAnyProtection { get { return HasOnlineProtection || HasOfflineProtection; } }

			public bool HasOwnersOnline { get { return OnlineOwners.Count > 0; } }

			public ProtectionStatus Status { get; private set; }

			public float ProtectionPercentage
			{
				get
				{
					return HighestProtectionLevel == null ? 0 : OnlineOwners.Count == 0 ? HighestProtectionLevel.OfflineProtectionPercentage : HighestProtectionLevel.OnlineProtectionPercentage;
				}
			}

			public ProtectedCupboard( BuildingPrivlidge priv )
			{
				HashSet<ulong> AllOwnerIdsTemp = (from id in priv.authorizedPlayers select id.userid).ToHashSet();
				HashSet<ulong> AllOwnerIds = new HashSet<ulong>();

				if (AllOwnerIdsTemp.Count >= 1) {
					foreach(ulong OwnerId in AllOwnerIdsTemp) {
						if (PLUGIN.permission.UserHasPermission(OwnerId.ToString(), PermissionAdmin))
							continue;

						AllOwnerIds.Add(OwnerId);
					}
				} else {
					AllOwnerIds = AllOwnerIdsTemp;
				}

				this.Priv = priv;
				this.StoredBalance = (PLUGIN.config.Settings.UseEconomics || PLUGIN.config.Settings.UseRP) ? 0 : Priv.inventory.GetAmount(PLUGIN.config.Settings.CurrencyItemId, false);
				this.PlayersViewing = new HashSet<BasePlayer>();
				this.ContentsLocked = false;
				this.AllOwnerIds = AllOwnerIds;
				this.IsActive = false;
				this.ForcedProtectionLevel = false;
				UpdateHighestProtectionLevel();
				UpdateTotalBuildingCost();
				UpdateProtectionCostPerHour();
				UpdateStatus();
			}

			public void UpdateHighestProtectionLevel()
			{
				if (Priv != null)
				{
					if (ForcedProtectionLevel == false)
					{
						if (AllOwnerIds != null)
						{
							int level = AllOwnerIds.Count == 0 ? -1 : (from id in (from ownerid in AllOwnerIds select ownerid.ToString()) select ProtectionLevel.LevelOf(id)).Max();
							HighestProtectionLevel = level == -1 ? ProtectionLevel.NONE : PLUGIN.config.Protection.ProtectionLevels[level];
							HourlyBaseCost = HighestProtectionLevel.HourlyBaseCost ?? PLUGIN.config.Pricing.DefaultBasePrice;
							HourlyBuildingCost = HighestProtectionLevel.HourlyBuildingCost ?? PLUGIN.config.Pricing.DefaultBuildingCost;
							CostPerDamage = HighestProtectionLevel.CostPerDamage ?? PLUGIN.config.Pricing.DefaultCostPerDamage;
							PLUGIN.Debug($"TC with ID={Priv.net.ID} HighestProtectionLevel={HighestProtectionLevel.OnlineProtectionPercentage}:{HighestProtectionLevel.OfflineProtectionPercentage}");
							PLUGIN.RefreshUi(this);
						}
					}
				}
			}

			public void UpdateProtectionCostPerHour()
			{
				if (Priv != null)
				{
					if (HasAnyProtection)
					{
						ProtectionCostPerHour = HourlyBaseCost + TotalBuildingCost;
						PLUGIN.RefreshUi(this);
					}
					else
					{
						ProtectionCostPerHour = 0;
						PLUGIN.RefreshUi(this);
					}
				}
			}

			public void UpdateTotalBuildingCost()
			{
				PLUGIN.DebugTimeStart("UpdateTotalBuildingCost");
				if (Priv != null)
				{
					BuildingManager.Building building = Priv.GetBuilding();
					if (building != null) {
						if (PLUGIN.UseMaterialPrices)
						{
							TotalBuildingCost = 0;
							foreach (BuildingBlock block in building.buildingBlocks)
							{
								if (block.ShortPrefabName.Contains("foundation") || block.ShortPrefabName.Contains("floor"))
								{
									float mod = block.ShortPrefabName.Contains("triangle") ? 0.5f : 1f;
									int rank = (int)block.grade;
									if (rank >= 0)
									{
										TotalBuildingCost += PLUGIN.config.Pricing.MaterialMultipliers.Values.ElementAt(rank) * HourlyBuildingCost * mod;
									}
								}
							}
						}
						else
						{
							TotalBuildingCost = 0;
							foreach (BuildingBlock block in building.buildingBlocks)
							{
								if (block.ShortPrefabName.Contains("foundation") || block.ShortPrefabName.Contains("floor"))
								{
									float mod = block.ShortPrefabName.Contains("triangle") ? 0.5f : 1f;
									TotalBuildingCost += HourlyBuildingCost * mod;
								}
							}
						}
					}
				}
				PLUGIN.DebugTimeEnd("UpdateTotalBuildingCost");
			}

			public void InitialPurchaseProtection()
			{
				if (Priv != null)
				{
					if (HasPermission && ((HasOnlineProtection && HasOwnersOnline) || (HasOfflineProtection && !HasOwnersOnline)))
					{
						if (RecentlyDamaged)
						{
							UpdateStatus();
						}
						else if (Priv != null && CanAffordProtection && !IsActive)
						{
							IsActive = true;
							UpdateCostDebt(ProtectionCostPerInterval, 1);
							UpdateStoredBalance(ProtectionCostPerInterval);
							UpdateStatus();
							CollectionLoop();
						}
					}
				}
			}

			public void PurchaseProtection()
			{
				if (Priv != null)
				{
					if (HasPermission && ((HasOnlineProtection && HasOwnersOnline) || (HasOfflineProtection && !HasOwnersOnline)))
					{
						PLUGIN.DebugTimeStart("PurchaseProtection");
						if (RecentlyDamaged)
						{
							UpdateStatus();
							PLUGIN.DebugTimeEnd("PurchaseProtection");
						}
						else if (Priv != null && CanAffordProtection && !IsActive)
						{
							IsActive = true;
							UpdateCostDebt(ProtectionCostPerInterval);
							UpdateStoredBalance(ProtectionCostPerInterval);
							UpdateStatus();
							CollectionLoop();
						}
					}
				}
			}

			public void StopProtection()
			{
				if (Priv != null && IsActive)
				{
					IsActive = false;
					UpdateStatus();
					PLUGIN.Debug($"Stopping protection for TC with ID={Priv.net.ID}");
					PLUGIN.ShowIndicatorForOwners(this);
				}
			}

			private void CollectionLoop()
			{
				if (Priv != null && IsActive)
				{
					PLUGIN.timer.In(PLUGIN.COLLECTION_INTERVAL, () =>
					{
						if (Priv != null && CanAffordProtection && IsActive)
						{
							IsActive = false;
							PurchaseProtection();
						}
						else
						{
							StopProtection();
						}
					});
				}
			}

			public void UpdateCostDebt( float amount, int minAmount = 0 )
			{
				if (Priv != null && !PLUGIN.config.Settings.UseEconomics && !PLUGIN.config.Settings.UseRP)
				{
					ContentsLocked = true;
					CostDebt += Math.Max(minAmount, amount);
					while (CostDebt >= 1)
					{
						Priv.inventory.FindItemByItemID(PLUGIN.config.Settings.CurrencyItemId).UseItem(1);
						CostDebt -= 1;
					}
					ContentsLocked = false;
					PLUGIN.RefreshUi(this);
				}
			}


			public void UpdateStoredBalance( float amount )
			{
				if (Priv != null && !PLUGIN.config.Settings.UseEconomics && !PLUGIN.config.Settings.UseRP)
				{
					float remainder = (float)(StoredBalance - Math.Truncate(StoredBalance));
					StoredBalance = ItemAmount + remainder;
				}
				else
				{
					StoredBalance = Math.Max(StoredBalance - amount, 0);
				}
			}

			public void UpdateStatus()
			{
				if (Priv != null)
				{
					if (!HasPermission)
					{
						Status = ProtectionStatus.Unprotected;
					}
					else if (HasOnlineProtection && HasOwnersOnline && RecentlyDamaged && Status != ProtectionStatus.Protected && CanAffordProtection)
					{
						Status = ProtectionStatus.PendingRecentlyDamage;
						PLUGIN.Debug($"TC with ID={Priv.net.ID} recently took damage, protection starts soon");
						PLUGIN.timer.In(PLUGIN.config.Protection.ProtectedDelayAfterTakingDamage, () =>
						{
							PurchaseProtection();
							UpdateStatus();
							PLUGIN.ShowIndicatorForOwners(this);
						});
					}
					else if (HasOfflineProtection && !HasOwnersOnline && RecentlyDamaged && Status != ProtectionStatus.Protected && CanAffordProtection)
					{
						Status = ProtectionStatus.PendingRecentlyDamage;
						PLUGIN.Debug($"TC with ID={Priv.net.ID} recently took damage, protection starts soon");
						PLUGIN.timer.In(PLUGIN.config.Protection.ProtectedDelayAfterTakingDamage, () =>
						{
							PurchaseProtection();
							UpdateStatus();
							PLUGIN.ShowIndicatorForOwners(this);
						});
					}
					else if (HasOfflineProtection && !HasOnlineProtection && HasOwnersOnline)
					{
						Status = ProtectionStatus.PendingOfflineOnly;
					}
					else if (!HasOfflineProtection && HasOnlineProtection && !HasOwnersOnline)
					{
						Status = ProtectionStatus.PendingOnlineOnly;
					}
					else if (IsActive)
					{
						Status = ProtectionStatus.Protected;
					}
					else
					{
						Status = ProtectionStatus.Unprotected;
					}
					PLUGIN.RefreshUi(this);
					PLUGIN.Debug($"TC with ID={Priv.net.ID} Status={Status} StoredBalance={StoredBalance}");
				}
			}

			public static void Unload()
			{
				toolcupboards = null;
			}
		}

		#endregion Classes

		#region Configuration
		private Configuration config;

		private class Configuration
		{
			[JsonProperty(PropertyName = "General settings")]
			public GeneralConfig Settings = new GeneralConfig();

			[JsonProperty(PropertyName = "Protection settings")]
			public ProtectionConfig Protection = new ProtectionConfig();

			[JsonProperty(PropertyName = "Cost settings")]
			public PricingConfig Pricing = new PricingConfig();

			[JsonProperty(PropertyName = "Indicator settings")]
			public IndicatorConfig Indicator = new IndicatorConfig();

			public class GeneralConfig
			{
				[JsonProperty(PropertyName = "Currency item ID (if not using economics)")]
				public int CurrencyItemId = -932201673;

				[JsonProperty(PropertyName = "Use economics balance (requires economics plugin)")]
				public bool UseEconomics = false;

				[JsonProperty(PropertyName = "Use reward points (requires server rewards plugin)")]
				public bool UseRP = false;
			}

			public class ProtectionConfig
			{
				[JsonProperty(PropertyName = "Delay after taking damage (seconds)")]
				public int ProtectedDelayAfterTakingDamage { get; set; } = 10;

				[JsonProperty(PropertyName = "Delay for offline protection (seconds)")]
				public int OfflineProtectionDelay { get; set; } = 600;

				[JsonProperty(PropertyName = "Protect buildings and deployables (true/false)")]
				public bool ProtectBuildings { get; set; } = true;

				[JsonProperty(PropertyName = "Protect players (true/false)")]
				public bool ProtectPlayers { get; set; } = true;

				[JsonProperty(PropertyName = "Protect vehicles and horses (true/false)")]
				public bool ProtectVehicles { get; set; } = true;

				[JsonProperty(PropertyName = "Protect traps and electronics (true/false)")]
				public bool ProtectTraps { get; set; } = true;

				[JsonProperty(PropertyName = "Protection levels")]
				public Dictionary<int, ProtectionLevel> ProtectionLevels = new Dictionary<int, ProtectionLevel>
				{
					{
						0, new ProtectionLevel {
							OnlineProtectionPercentage = 100f,
							OfflineProtectionPercentage = 100f
						}
					}
				};
			}

			public class PricingConfig
			{
				[JsonProperty(PropertyName = "Material cost multipliers")]
				public Dictionary<string, float> MaterialMultipliers { get; set; } = new Dictionary<string, float> {
					{ "twig", 1.0f },
					{ "wood", 1.0f },
					{ "stone", 1.0f },
					{ "metal", 1.0f },
					{ "armored", 1.0f }
				};

				[JsonProperty(PropertyName = "Default hourly building cost")]
				public float DefaultBuildingCost { get; set; } = 1.0f;

				[JsonProperty(PropertyName = "Default hourly base cost")]
				public float DefaultBasePrice { get; set; } = 9f;

				[JsonProperty(PropertyName = "Default structure damage cost")]
				public float DefaultCostPerDamage { get; set; } = 0f;
			}

			public class IndicatorConfig
			{
				[JsonProperty(PropertyName = "Enabled")]
				public bool Enabled { get; set; } = true;

				[JsonProperty(PropertyName = "Persistent")]
				public bool Persistent { get; set; } = false;

				[JsonProperty(PropertyName = "Image url")]
				public string ImageUrl { get; set; } = "https://i.imgur.com/ue05FGg.png";
			}
		}

		protected override void LoadConfig()
		{
			LoadDefaultConfig();
			base.LoadConfig();

			try
			{
				config = Config.ReadObject<Configuration>();
				if (config == null) throw new Exception();
			}
			catch
			{
				PrintError("Your configuration file contains an error.Default configuration values will be used.It is recommended to backup your current configuration file and remove it to generate a fresh one.");
				LoadDefaultConfig();
			}
			CurrencyItemDef = ItemManager.FindItemDefinition(config.Settings.CurrencyItemId);
			UseMaterialPrices = config.Pricing.MaterialMultipliers.Values.Any(x => x != 1f);
		}

		protected override void SaveConfig() => Config.WriteObject(config);

		protected override void LoadDefaultConfig() => config = new Configuration();

		#endregion Configuration

		#region Localization

		private string Label( string message, string color )
		{
			return $"<color={color}>{message}: </color>";
		}

		private string Color( string message, string color )
		{
			return $"<color={color}>{message}</color>";
		}

		protected override void LoadDefaultMessages()
		{
			lang.RegisterMessages(new Dictionary<string, string>
			{
				["Title"] = "RAID PROTECTION",
				["Cost"] = "Cost",
				["Balance"] = "Balance",
				["Level"] = "Level",
				["Protected"] = "PROTECTED",
				["Unprotected"] = "UNPROTECTED",

				["StatusProtected"] = "Your base is {0}% protected for {1}",
				["StatusUnprotected"] = "Balance of {0} is required to receive protection",
				["StatusPendingDamage"] = "Recently damaged, protection starts soon",
				["StatusPendingOffline"] = "Resuming {0}% protection when owners are offline",
				["StatusNoPermission"] = "You do not have permission to receive protection",
				["StatusNoBalance"] = "Low remaining balance, protection ends soon",

				["Days"] = "days",
				["Hour"] = "hr",
				["Hours"] = "hrs",
				["Minutes"] = "min",
				["Usage"] = "Usage",
				["NoPriv"] = "There is no protected area at the current location",
				["NoPerm"] = "You do not have permission to use that command",
				["ForceLevel"] = "The protection level for this protected area will be forced to level {0}.It will remain at this level until reset with the {1} command.",
				["ResetLevel"] = "The protection level for this protected area will default to the highest protection level among authorized players.",
				["NoLevel"] = "No protection level defined in the config for level {0}",
				["Activate"] = "Activating protection for protected area",
				["Deactive"] = "Deactivating protection for protected area",

				["LabelStatus"] = "Status",
				["LabelLevel"] = "Level",
				["LabelProtection"] = "Protection",
				["LabelDelay"] = "Offline Protection Delay",
				["LabelBalance"] = "Balance",
				["LabelCost"] = "Cost Per Hour",
				["LabelCostPerDamage"] = "Cost Per Damage Taken",
				["LabelTime"] = "Hours Left",
				["LabelOnline"] = "Online Players",
				["LabelId"] = "Toolcupboard ID",

				["ValueStatusProtected"] = "{0}% Protected",
				["ValueStatusUnprotected"] = "Unprotected",
				["ValueProtection"] = "{0}% Online | {1}% Offline",
				["ValueCost"] = "{0} Base + {1} Building = {2} Total",

				["Deposit"] = "Deposit",
				["Wallet"] = "Wallet",
				["Wallet"] = "Wallet",

				["IndicatorProtected"] = "{0}% PROTECTED",
				["IndicatorUnprotected"] = "UNPROTECTED",
				["IndicatorWarning"] = "Damage dealt deducts from the protection balance",
			}, this);
		}

		private string Lang( string key, string id = null, params object[] args )
		{
			return string.Format(lang.GetMessage(key, this, id), args);
		}
		#endregion Localization

		#region UI

		private readonly string COLOR_TRANSPARENT = "0 0 0 0";
		private readonly string COLOR_GREEN = "0.749 0.9059 0.4783 1";
		private readonly string COLOR_RED = "1 0.529 0.180 1";

		private readonly string COLOR_GREEN_DARK = "0.5992 0.72472 0.38264 1";
		private readonly string COLOR_GREEN_DARK_LESS = "0.25 0.4 0.1 1";
		private readonly string COLOR_RED_DARK = "0.8 0.4232 0.144 1";
		private readonly string COLOR_RED_DARK_LESS = "0.8 0.25 0.144 1";

		private readonly string COLOR_YELLOW = "1 1 0.5 1";

		private void RefreshUi( ProtectedCupboard tc )
		{
			foreach (BasePlayer player in tc.PlayersViewing)
			{
				OpenUi(player, tc.Priv);
			}
		}
		private void OpenUi( BasePlayer player, BuildingPrivlidge priv )
		{
			ProtectedCupboard tc = ProtectedCupboard.InitCupboard(priv);
			if (tc != null)
			{

				/* Constant */
				string titleColor = "1 1 1 0.75";
				string textColor = "1 1 1 0.6";
				int titleFont = 11;
				int textFont = 10;
				CuiElementContainer container = new CuiElementContainer
			{
				new CuiElement
				{
					Name = "srpPanel",
					Parent = "Overlay",
					Components = {
					new CuiImageComponent {
						Color=COLOR_TRANSPARENT
					},
					new CuiRectTransformComponent {
						AnchorMin="0.650 0.022",
						AnchorMax="0.828 0.135"
					}
				}
				},
				new CuiElement
				{
					Name = "srpTitle",
					Parent = "srpPanel",
					Components = {
					new CuiImageComponent {
						Color="0.3786 0.3686 0.3686 0.5"
					},
					new CuiRectTransformComponent {
						AnchorMin="0 0.80",
						AnchorMax="1 1"
					}
				}
				},
				new CuiElement
				{
					Name = "srpTitleText",
					Parent = "srpTitle",
					Components = {
					new CuiTextComponent {
						Text = Lang("Title", player.UserIDString),
						Align = TextAnchor.MiddleLeft,
						Color = titleColor,
						FontSize = titleFont
					},
					new CuiRectTransformComponent {
						AnchorMin="0.03 0.0",
						AnchorMax="0.97 1.0"
					}
				}
				},
				new CuiElement
				{
					Name = "srpBody",
					Parent = "srpPanel",
					Components = {
					new CuiImageComponent {
						Color="0.3786 0.3686 0.3686 0.5"
					},
					new CuiRectTransformComponent {
						AnchorMin="0 0",
						AnchorMax="1 0.75"
					}
				}
				},
				new CuiElement
				{
					Name = "srpBodyText1",
					Parent = "srpBody",
					Components = {
					new CuiTextComponent {
						Text = $"{(tc.Status == ProtectionStatus.Protected ? Lang("Protected", player.UserIDString) : Lang("Unprotected", player.UserIDString))}",
						Align = TextAnchor.MiddleCenter,
						Color = (tc.Status == ProtectionStatus.Protected ? COLOR_GREEN : COLOR_RED),
						FontSize = titleFont
					},
					new CuiRectTransformComponent {
						AnchorMin="0.03 0.7",
						AnchorMax="0.97 0.9"
					}
				}
				},
				new CuiElement
				{
					Name = "srpBodyText2",
					Parent = "srpBody",
					Components
// ... [Code preview truncated due to length. Full source in attached file] ...

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