FuelStream

NoEscape 2.1.4 | Fix for Melee & Explosives

Sep 4th, 2021
1,368
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 76.97 KB | None | 0 0
  1. using System;
  2. using System.Linq;
  3. using System.Collections.Generic;
  4. using System.Text.RegularExpressions;
  5.  
  6. using Oxide.Core;
  7. using Oxide.Core.Plugins;
  8. using Oxide.Game.Rust.Cui;
  9.  
  10. using Newtonsoft.Json.Linq;
  11.  
  12. using UnityEngine;
  13. using Facepunch;
  14. using Rust;
  15.  
  16. namespace Oxide.Plugins
  17. {
  18.     [Info ("No Escape", "Calytic (edit by Steenamaroo)", "2.1.4")]
  19.     [Description ("Prevent commands/actions while raid and/or combat is occuring")]
  20.     class NoEscape : RustPlugin
  21.     {
  22.         #region Setup & Configuration
  23.  
  24.         List<string> blockTypes = new List<string> ()
  25.         {
  26.             "remove",
  27.             "tp",
  28.             "bank",
  29.             "trade",
  30.             "recycle",
  31.             "shop",
  32.             "bgrade",
  33.             "build",
  34.             "repair",
  35.             "upgrade",
  36.             "vend",
  37.             "kit",
  38.             "assignbed",
  39.             "craft",
  40.             "mailbox",
  41.             "backpack"
  42.         };
  43.  
  44.         // COMBAT SETTINGS
  45.         bool combatBlock;
  46.         static float combatDuration;
  47.         bool combatOnHitPlayer;
  48.         float combatOnHitPlayerMinCondition;
  49.         float combatOnHitPlayerMinDamage;
  50.  
  51.         bool combatOnTakeDamage;
  52.         float combatOnTakeDamageMinCondition;
  53.         float combatOnTakeDamageMinDamage;
  54.  
  55.         bool combatOnHitNPC;
  56.         bool combatOnTakeDamageNPC;
  57.  
  58.         // RAID BLOCK SETTINGS
  59.         bool raidBlock;
  60.         static float raidDuration;
  61.         float raidDistance;
  62.         bool blockOnDamage;
  63.         float blockOnDamageMinCondition;
  64.         bool blockOnDestroy;
  65.  
  66.         // RAID-ONLY SETTINGS
  67.         bool ownerCheck;
  68.         bool blockUnowned;
  69.         bool blockAll;
  70.         // IGNORES ALL OTHER CHECKS
  71.         bool ownerBlock;
  72.         bool cupboardShare;
  73.         bool friendShare;
  74.         bool clanShare;
  75.         bool clanCheck;
  76.         bool friendCheck;
  77.         bool raiderBlock;
  78.         List<string> raidDamageTypes;
  79.         List<string> raidDeathTypes;
  80.         List<string> combatDamageTypes;
  81.  
  82.         // RAID UNBLOCK SETTINGS
  83.         bool raidUnblockOnDeath;
  84.         bool raidUnblockOnWakeup;
  85.         bool raidUnblockOnRespawn;
  86.  
  87.         // COMBAT UNBLOCK SETTINGS
  88.         bool combatUnblockOnDeath;
  89.         bool combatUnblockOnWakeup;
  90.         bool combatUnblockOnRespawn;
  91.  
  92.         float cacheTimer;
  93.  
  94.         // MESSAGES
  95.         bool raidBlockNotify;
  96.         bool combatBlockNotify;
  97.  
  98.         bool useZoneManager;
  99.         bool zoneEnter;
  100.         bool zoneLeave;
  101.        
  102.         bool useRaidableBases;
  103.         bool raidableZoneEnter;
  104.         bool raidableZoneLeave;
  105.  
  106.         bool sendUINotification;
  107.         bool sendChatNotification;
  108.         bool sendGUIAnnouncementsNotification;
  109.         bool sendLustyMapNotification;
  110.  
  111.         string GUIAnnouncementTintColor = "Red";
  112.         string GUIAnnouncementTextColor = "White";
  113.  
  114.         string LustyMapIcon = "special";
  115.         float LustyMapDuration = 150f;
  116.  
  117.         Dictionary<string, RaidZone> zones = new Dictionary<string, RaidZone> ();
  118.         Dictionary<string, List<string>> memberCache = new Dictionary<string, List<string>> ();
  119.         Dictionary<string, string> clanCache = new Dictionary<string, string> ();
  120.         Dictionary<string, List<string>> friendCache = new Dictionary<string, List<string>> ();
  121.         Dictionary<string, DateTime> lastClanCheck = new Dictionary<string, DateTime> ();
  122.         Dictionary<string, DateTime> lastCheck = new Dictionary<string, DateTime> ();
  123.         Dictionary<string, DateTime> lastFriendCheck = new Dictionary<string, DateTime> ();
  124.         Dictionary<string, bool> prefabBlockCache = new Dictionary<string, bool> ();
  125.         internal Dictionary<ulong, BlockBehavior> blockBehaviors = new Dictionary<ulong, BlockBehavior> ();
  126.  
  127.         public static NoEscape plugin;
  128.  
  129.         [PluginReference]
  130.         Plugin Clans, Friends, ZoneManager, GUIAnnouncements, LustyMap;
  131.  
  132.         readonly int cupboardMask = LayerMask.GetMask ("Deployed");
  133.         readonly int blockLayer = LayerMask.GetMask ("Player (Server)");
  134.         Dictionary<string, bool> _cachedExcludedWeapons = new Dictionary<string, bool> ();
  135.  
  136.         List<string> blockedPrefabs = new List<string> ()
  137.         {
  138.             "door",
  139.             "window.bars",
  140.             "floor.ladder.hatch",
  141.             "floor.frame",
  142.             "wall.frame",
  143.             "shutter",
  144.             "external"
  145.         };
  146.  
  147.         List<string> exceptionPrefabs = new List<string> ()
  148.         {
  149.             "ladder.wooden"
  150.         };
  151.  
  152.         List<string> exceptionWeapons = new List<string> ()
  153.         {
  154.             "torch"
  155.         };
  156.  
  157.         private List<string> GetDefaultRaidDamageTypes ()
  158.         {
  159.             return new List<DamageType> ()
  160.             {
  161.                 DamageType.Bullet,
  162.                 DamageType.Blunt,
  163.                 DamageType.Stab,
  164.                 DamageType.Slash,
  165.                 DamageType.Explosion,
  166.                 DamageType.Heat
  167.             }.Select (x => x.ToString ()).ToList<string> ();
  168.         }
  169.  
  170.         private List<string> GetDefaultCombatDamageTypes ()
  171.         {
  172.             return new List<DamageType> ()
  173.             {
  174.                 DamageType.Bullet,
  175.                 DamageType.Arrow,
  176.                 DamageType.Blunt,
  177.                 DamageType.Stab,
  178.                 DamageType.Slash,
  179.                 DamageType.Explosion,
  180.                 DamageType.Heat,
  181.                 DamageType.ElectricShock
  182.             }.Select (x => x.ToString ()).ToList<string> ();
  183.         }
  184.  
  185.         Dictionary<string, object> blockWhenRaidDamageDefault = new Dictionary<string, object> () {
  186.             {"enabled", true},
  187.             {"minCondition", 100f},
  188.         };
  189.  
  190.         Dictionary<string, object> blockWhenCombatDamageDefault = new Dictionary<string, object> () {
  191.             {"enabled", false},
  192.             {"minCondition", 100f},
  193.             {"minDamage", 1f},
  194.         };
  195.  
  196.         static Regex _htmlRegex = new Regex ("<.*?>", RegexOptions.Compiled);
  197.  
  198.         protected override void LoadDefaultConfig ()
  199.         {
  200.             Config ["VERSION"] = Version.ToString ();
  201.  
  202.             // RAID SETTINGS
  203.             Config ["Raid", "Block", "enabled"] = true;
  204.             Config ["Raid", "Block", "duration"] = 300f; // 5 minutes
  205.             Config ["Raid", "Block", "distance"] = 100f;
  206.             Config ["Raid", "Block", "notify"] = true;
  207.             Config ["Raid", "Block", "damageTypes"] = GetDefaultRaidDamageTypes ();
  208.             Config ["Raid", "Block", "deathTypes"] = GetDefaultRaidDamageTypes();
  209.             Config ["Raid", "Block", "includePrefabs"] = blockedPrefabs;
  210.             Config ["Raid", "Block", "excludePrefabs"] = exceptionPrefabs;
  211.             Config ["Raid", "Block", "excludeWeapons"] = exceptionWeapons;
  212.  
  213.             Config ["Raid", "BlockWhen", "damage"] = blockWhenRaidDamageDefault;
  214.  
  215.             Config ["Raid", "BlockWhen", "destroy"] = true;
  216.             Config ["Raid", "BlockWhen", "unowned"] = false;
  217.  
  218.             Config ["Raid", "BlockWho", "everyone"] = true;
  219.             Config ["Raid", "BlockWho", "owner"] = false;
  220.             Config ["Raid", "BlockWho", "cupboardAuthorized"] = false;
  221.             Config ["Raid", "BlockWho", "clan"] = false;
  222.             Config ["Raid", "BlockWho", "friends"] = false;
  223.             Config ["Raid", "BlockWho", "raider"] = false;
  224.  
  225.             Config ["Raid", "BlockExcept", "owner"] = true;
  226.             Config ["Raid", "BlockExcept", "friends"] = false;
  227.             Config ["Raid", "BlockExcept", "clan"] = false;
  228.  
  229.             Config ["Raid", "Zone", "enabled"] = false;
  230.             Config ["Raid", "Zone", "enter"] = true;
  231.             Config ["Raid", "Zone", "leave"] = false;
  232.  
  233.             Config ["Raid", "Map", "enabled"] = false;
  234.             Config ["Raid", "Map", "icon"] = "special";
  235.             Config ["Raid", "Map", "duration"] = 150f;
  236.  
  237.             Config ["Raid", "UnblockWhen", "death"] = true;
  238.             Config ["Raid", "UnblockWhen", "wakeup"] = false;
  239.             Config ["Raid", "UnblockWhen", "respawn"] = true;
  240.  
  241.             // COMBAT SETTINGS
  242.             Config ["Combat", "Block", "enabled"] = false;
  243.             Config ["Combat", "Block", "duration"] = 180f; // 3 minutes
  244.             Config ["Combat", "Block", "notify"] = true;
  245.             Config ["Combat", "Block", "damageTypes"] = GetDefaultCombatDamageTypes ();
  246.  
  247.             Config ["Combat", "BlockWhen", "giveDamage"] = blockWhenCombatDamageDefault;
  248.             Config ["Combat", "BlockWhen", "takeDamage"] = blockWhenCombatDamageDefault;
  249.  
  250.             Config ["Combat", "BlockWhen", "npcGiveDamage"] = false;
  251.             Config ["Combat", "BlockWhen", "npcTakeDamage"] = false;
  252.  
  253.             Config ["Combat", "UnblockWhen", "death"] = true;
  254.             Config ["Combat", "UnblockWhen", "wakeup"] = false;
  255.             Config ["Combat", "UnblockWhen", "respawn"] = true;
  256.  
  257.             Config ["Settings", "cacheMinutes"] = 1f;
  258.             Config ["Settings", "Block", "Types"] = blockTypes;
  259.  
  260.             Config ["Notifications", "UI"] = true;
  261.             Config ["Notifications", "Chat"] = true;
  262.             Config ["Notifications", "GUIAnnouncements", "enabled"] = false;
  263.             Config ["Notifications", "GUIAnnouncements", "backgroundColor"] = "Red";
  264.             Config ["Notifications", "GUIAnnouncements", "textColor"] = "White";
  265.  
  266.             Config ["VERSION"] = Version.ToString ();
  267.         }
  268.  
  269.         void Loaded ()
  270.         {
  271.             LoadMessages ();
  272.         }
  273.  
  274.         void Unload ()
  275.         {
  276.             if (useZoneManager)
  277.                 foreach (var zone in zones.ToList ())
  278.                     EraseZone (zone.Value.zoneid);
  279.  
  280.             var objects = GameObject.FindObjectsOfType (typeof (RaidBlock));
  281.             if (objects != null)
  282.                 foreach (var gameObj in objects)
  283.                     if (!((RaidBlock)gameObj).Active)
  284.                         GameObject.Destroy (gameObj);
  285.  
  286.             objects = GameObject.FindObjectsOfType (typeof (CombatBlock));
  287.             if (objects != null)
  288.                 foreach (var gameObj in objects)
  289.                     if (!((CombatBlock)gameObj).Active)
  290.                         GameObject.Destroy (gameObj);
  291.         }
  292.  
  293.         void LoadMessages ()
  294.         {
  295.             lang.RegisterMessages (new Dictionary<string, string>
  296.                 {
  297.                     { "Raid Blocked Message", "You may not do that while raid blocked ({time})" },
  298.                     { "Combat Blocked Message", "You may do that while a in combat ({time})" },
  299.                     { "Raid Block Complete", "You are no longer raid blocked." },
  300.                     { "Combat Block Complete", "You are no longer combat blocked." },
  301.                     { "Raid Block Notifier", "You are raid blocked for {time}" },
  302.                     { "Combat Block Notifier", "You are combat blocked for {time}" },
  303.                     { "Combat Block UI Message", "COMBAT BLOCK" },
  304.                     { "Raid Block UI Message", "RAID BLOCK" },
  305.                     { "Unit Seconds", "second(s)" },
  306.                     { "Unit Minutes", "minute(s)" },
  307.                     { "Prefix", string.Empty }
  308.                 }, this);
  309.         }
  310.  
  311.         void CheckConfig ()
  312.         {
  313.             if (Config ["VERSION"] == null) {
  314.                 // FOR COMPATIBILITY WITH INITIAL VERSIONS WITHOUT VERSIONED CONFIG
  315.                 ReloadConfig ();
  316.             } else if (GetConfig ("VERSION", string.Empty) != Version.ToString ()) {
  317.                 // ADDS NEW, IF ANY, CONFIGURATION OPTIONS
  318.                 ReloadConfig ();
  319.             }
  320.         }
  321.  
  322.         protected void ReloadConfig ()
  323.         {
  324.             Config ["VERSION"] = Version.ToString ();
  325.  
  326.             // NEW CONFIGURATION OPTIONS HERE
  327.             // END NEW CONFIGURATION OPTIONS
  328.  
  329.             PrintToConsole ("Upgrading configuration file");
  330.             SaveConfig ();
  331.         }
  332.  
  333.         void OnServerInitialized ()
  334.         {
  335.             NoEscape.plugin = this;
  336.  
  337.             permission.RegisterPermission ("noescape.disable", this);
  338.  
  339.             blockTypes = GetConfig ("Settings", "Block", "Types", blockTypes);
  340.  
  341.             foreach (string command in blockTypes) {
  342.                 permission.RegisterPermission ("noescape.raid." + command + "block", this);
  343.                 permission.RegisterPermission ("noescape.combat." + command + "block", this);
  344.             }
  345.  
  346.             CheckConfig ();
  347.  
  348.             // RAID SETTINGS
  349.             raidBlock = GetConfig ("Raid", "Block", "enabled", true);
  350.             raidDuration = GetConfig ("Raid", "Block", "duration", 300f);
  351.             raidDistance = GetConfig ("Raid", "Block", "distance", 100f);
  352.             raidBlockNotify = GetConfig ("Raid", "Block", "notify", true);
  353.             raidDamageTypes = GetConfig ("Raid", "Block", "damageTypes", GetDefaultRaidDamageTypes ());
  354.             raidDeathTypes = GetConfig("Raid", "Block", "deathTypes", GetDefaultRaidDamageTypes());
  355.             blockedPrefabs = GetConfig ("Raid", "Block", "includePrefabs", blockedPrefabs);
  356.             exceptionPrefabs = GetConfig ("Raid", "Block", "excludePrefabs", exceptionPrefabs);
  357.             exceptionWeapons = GetConfig ("Raid", "Block", "excludeWeapons", exceptionWeapons);
  358.  
  359.             Dictionary<string, object> blockOnRaidDamageDetails = GetConfig ("Raid", "BlockWhen", "damage", blockWhenRaidDamageDefault);
  360.             if (blockOnRaidDamageDetails.ContainsKey ("enabled")) {
  361.                 blockOnDamage = (bool)blockOnRaidDamageDetails ["enabled"];
  362.             } else {
  363.                 blockOnDamage = true;
  364.             }
  365.  
  366.             if (blockOnRaidDamageDetails.ContainsKey ("minCondition")) {
  367.                 blockOnDamageMinCondition = Convert.ToSingle (blockOnRaidDamageDetails ["minCondition"]);
  368.             } else {
  369.                 blockOnDamageMinCondition = 100f;
  370.             }
  371.  
  372.             blockOnDestroy = GetConfig ("Raid", "BlockWhen", "destroy", true);
  373.             blockUnowned = GetConfig ("Raid", "BlockWhen", "unowned", false);
  374.  
  375.             blockAll = GetConfig ("Raid", "BlockWho", "everyone", true);
  376.             ownerBlock = GetConfig ("Raid", "BlockWho", "owner", false);
  377.             friendShare = GetConfig ("Raid", "BlockWho", "friends", false);
  378.             clanShare = GetConfig ("Raid", "BlockWho", "clan", false);
  379.             cupboardShare = GetConfig ("Raid", "BlockWho", "cupboardAuthorized", false);
  380.             raiderBlock = GetConfig ("Raid", "BlockWho", "raider", false);
  381.  
  382.             ownerCheck = GetConfig ("Raid", "BlockExcept", "owner", true);
  383.             friendCheck = GetConfig ("Raid", "BlockExcept", "friends", false);
  384.             clanCheck = GetConfig ("Raid", "BlockExcept", "clan", false);
  385.  
  386.             useZoneManager = GetConfig ("Raid", "Zone", "enabled", false);
  387.             zoneEnter = GetConfig ("Raid", "Zone", "enter", true);
  388.             zoneLeave = GetConfig ("Raid", "Zone", "leave", false);
  389.            
  390.             useRaidableBases = GetConfig ("Raid", "RaidableBases", "enabled", false);
  391.             raidableZoneEnter = GetConfig ("Raid", "RaidableBases", "enter", true);
  392.             raidableZoneLeave = GetConfig ("Raid", "RaidableBases", "leave", false);
  393.  
  394.             sendLustyMapNotification = GetConfig ("Raid", "Map", "enabled", false);
  395.             LustyMapIcon = GetConfig ("Raid", "Map", "icon", "special");
  396.             LustyMapDuration = GetConfig ("Raid", "Map", "duration", 150f);
  397.  
  398.             raidUnblockOnDeath = GetConfig ("Raid", "UnblockWhen", "death", true);
  399.             raidUnblockOnWakeup = GetConfig ("Raid", "UnblockWhen", "wakeup", false);
  400.             raidUnblockOnRespawn = GetConfig ("Raid", "UnblockWhen", "respawn", true);
  401.  
  402.             // COMBAT SETTINGS
  403.             combatBlock = GetConfig ("Combat", "Block", "enabled", false);
  404.             combatDuration = GetConfig ("Combat", "Block", "duration", 180f);
  405.             combatBlockNotify = GetConfig ("Combat", "Block", "notify", true);
  406.             combatDamageTypes = GetConfig ("Combat", "Block", "damageTypes", GetDefaultCombatDamageTypes ());
  407.  
  408.             //combatOnHitPlayer = GetConfig ("Combat", "BlockWhen", "giveDamage", true);
  409.             Dictionary<string, object> blockOnCombatGiveDamageDetails = GetConfig ("Combat", "BlockWhen", "giveDamage", blockWhenCombatDamageDefault);
  410.             if (blockOnCombatGiveDamageDetails.ContainsKey ("enabled")) {
  411.                 combatOnHitPlayer = (bool)blockOnCombatGiveDamageDetails ["enabled"];
  412.             } else {
  413.                 combatOnHitPlayer = false;
  414.             }
  415.  
  416.             if (blockOnCombatGiveDamageDetails.ContainsKey ("minCondition")) {
  417.                 combatOnHitPlayerMinCondition = Convert.ToSingle (blockOnCombatGiveDamageDetails ["minCondition"]);
  418.             } else {
  419.                 combatOnHitPlayerMinCondition = 100f;
  420.             }
  421.  
  422.             //combatOnTakeDamage = GetConfig ("Combat", "BlockWhen", "takeDamage", true);
  423.             Dictionary<string, object> blockOnCombatTakeDamageDetails = GetConfig ("Combat", "BlockWhen", "takeDamage", blockWhenCombatDamageDefault);
  424.             if (blockOnCombatTakeDamageDetails.ContainsKey ("enabled")) {
  425.                 combatOnTakeDamage = (bool)blockOnCombatTakeDamageDetails ["enabled"];
  426.             } else {
  427.                 combatOnTakeDamage = false;
  428.             }
  429.  
  430.             if (blockOnCombatTakeDamageDetails.ContainsKey ("minCondition")) {
  431.                 combatOnTakeDamageMinCondition = Convert.ToSingle (blockOnCombatTakeDamageDetails ["minCondition"]);
  432.             } else {
  433.                 combatOnTakeDamageMinCondition = 100f;
  434.             }
  435.  
  436.             if (blockOnCombatTakeDamageDetails.ContainsKey ("minDamage")) {
  437.                 combatOnTakeDamageMinDamage = Convert.ToSingle (blockOnCombatTakeDamageDetails ["minDamage"]);
  438.             } else {
  439.                 combatOnTakeDamageMinDamage = 1f;
  440.             }
  441.  
  442.             combatOnHitNPC = GetConfig ("Combat", "BlockWhen", "npcGiveDamage", false);
  443.             combatOnTakeDamageNPC = GetConfig ("Combat", "BlockWhen", "npcTakeDamage", false);
  444.  
  445.             combatUnblockOnDeath = GetConfig ("Combat", "UnblockWhen", "death", true);
  446.             combatUnblockOnWakeup = GetConfig ("Combat", "UnblockWhen", "wakeup", false);
  447.             combatUnblockOnRespawn = GetConfig ("Combat", "UnblockWhen", "respawn", true);
  448.  
  449.             cacheTimer = GetConfig ("Settings", "cacheMinutes", 1f);
  450.  
  451.             sendUINotification = GetConfig ("Notifications", "UI", true);
  452.             sendChatNotification = GetConfig ("Notifications", "Chat", true);
  453.  
  454.             sendGUIAnnouncementsNotification = GetConfig ("Notifications", "GUIAnnouncements", "enabled", false);
  455.             GUIAnnouncementTintColor = GetConfig ("Notifications", "GUIAnnouncements", "backgroundColor", "Red");
  456.             GUIAnnouncementTextColor = GetConfig ("Notifications", "GUIAnnouncements", "textColor", "White");
  457.  
  458.             if ((clanShare || clanCheck) && !Clans) {
  459.                 clanShare = false;
  460.                 clanCheck = false;
  461.                 PrintWarning ("Clans not found! All clan options disabled. Cannot use clan options without this plugin. http://oxidemod.org/plugins/clans.2087");
  462.             }
  463.  
  464.             if (friendShare && !Friends) {
  465.                 friendShare = false;
  466.                 friendCheck = false;
  467.                 PrintWarning ("Friends not found! All friend options disabled. Cannot use friend options without this plugin. http://oxidemod.org/plugins/friends-api.686");
  468.             }
  469.  
  470.             if (useZoneManager && !ZoneManager) {
  471.                 useZoneManager = false;
  472.                 PrintWarning ("ZoneManager not found! All zone options disabled. Cannot use zone options without this plugin. http://oxidemod.org/plugins/zones-manager.739");
  473.             }
  474.  
  475.             if (sendGUIAnnouncementsNotification && !GUIAnnouncements) {
  476.                 sendGUIAnnouncementsNotification = false;
  477.                 PrintWarning ("GUIAnnouncements not found! GUI announcement option disabled. Cannot use gui announcement integration without this plugin. http://oxidemod.org/plugins/gui-announcements.1222");
  478.             }
  479.  
  480.             if (sendLustyMapNotification && !LustyMap) {
  481.                 sendLustyMapNotification = false;
  482.                 PrintWarning ("LustyMap not found! LustyMap notification option disabled. Cannot use LustyMap integration without this plugin. http://oxidemod.org/plugins/lustymap.1333");
  483.             }
  484.  
  485.             if (sendLustyMapNotification && LustyMap && LustyMapDuration <= 0) {
  486.                 PrintWarning ("LustyMap icon duration is zero, no icon will be displayed");
  487.             }
  488.  
  489.             UnsubscribeHooks ();
  490.         }
  491.  
  492.         void UnsubscribeHooks ()
  493.         {
  494.             if (!blockOnDestroy && !raidUnblockOnDeath && !combatUnblockOnDeath)
  495.                 Unsubscribe ("OnEntityDeath");
  496.  
  497.             if (!raidUnblockOnWakeup && !combatUnblockOnWakeup)
  498.                 Unsubscribe ("OnPlayerSleepEnded");
  499.  
  500.             if (!combatOnTakeDamage && !combatOnHitPlayer)
  501.                 Unsubscribe ("OnPlayerAttack");
  502.  
  503.             if (!blockTypes.Contains ("repair"))
  504.                 Unsubscribe ("OnStructureRepair");
  505.  
  506.             if (!blockTypes.Contains ("upgrade"))
  507.                 Unsubscribe ("OnStructureUpgrade");
  508.  
  509.             if (!blockTypes.Contains ("mailbox"))
  510.                 Unsubscribe ("CanUseMailbox");
  511.  
  512.             if (!blockTypes.Contains ("vend"))
  513.                 Unsubscribe ("CanUseVending");
  514.  
  515.             if (!blockTypes.Contains ("build"))
  516.                 Unsubscribe ("CanBuild");
  517.  
  518.             if (!blockTypes.Contains ("assignbed"))
  519.                 Unsubscribe ("CanAssignBed");
  520.  
  521.             if (!blockTypes.Contains ("craft"))
  522.                 Unsubscribe ("CanCraft");
  523.                
  524.             if (!blockTypes.Contains ("backpack"))
  525.                 Unsubscribe ("CanOpenBackpack");
  526.                
  527.             if(!useZoneManager)
  528.             {
  529.                 Unsubscribe ("OnEnterZone");
  530.                 Unsubscribe ("OnExitZone");
  531.             }
  532.            
  533.             if(!useRaidableBases)
  534.             {
  535.                 Unsubscribe ("OnPlayerEnteredRaidableBase");
  536.                 Unsubscribe ("OnPlayerExitedRaidableBase");
  537.             }
  538.         }
  539.  
  540.         #endregion
  541.  
  542.         #region Classes
  543.  
  544.         public class RaidZone
  545.         {
  546.             public string zoneid;
  547.             public Vector3 position;
  548.             public Timer timer;
  549.  
  550.             public RaidZone (string zoneid, Vector3 position)
  551.             {
  552.                 this.zoneid = zoneid;
  553.                 this.position = position;
  554.             }
  555.  
  556.             public float Distance (RaidZone zone)
  557.             {
  558.                 return Vector3.Distance (position, zone.position);
  559.             }
  560.  
  561.             public float Distance (Vector3 pos)
  562.             {
  563.                 return Vector3.Distance (position, pos);
  564.             }
  565.  
  566.             public RaidZone ResetTimer ()
  567.             {
  568.                 if (timer is Timer && !timer.Destroyed)
  569.                     timer.Destroy ();
  570.  
  571.                 return this;
  572.             }
  573.         }
  574.  
  575.         public abstract class BlockBehavior : MonoBehaviour
  576.         {
  577.             protected BasePlayer player;
  578.             public DateTime lastBlock = DateTime.MinValue;
  579.             public DateTime lastNotification = DateTime.MinValue;
  580.             internal DateTime lastUINotification = DateTime.MinValue;
  581.             internal Timer timer;
  582.             internal Action notifyCallback;
  583.             internal string iconUID;
  584.             internal bool moved;
  585.  
  586.             public void CopyFrom (BlockBehavior behavior)
  587.             {
  588.                 lastBlock = behavior.lastBlock;
  589.                 lastNotification = behavior.lastNotification;
  590.                 lastUINotification = behavior.lastUINotification;
  591.                 timer = behavior.timer;
  592.                 notifyCallback = behavior.notifyCallback;
  593.                 iconUID = behavior.iconUID;
  594.                 NotificationWindow = behavior.NotificationWindow;
  595.             }
  596.  
  597.             internal abstract float Duration { get; }
  598.  
  599.             internal abstract CuiRectTransformComponent NotificationWindow { get; set; }
  600.  
  601.             internal abstract string notifyMessage { get; }
  602.  
  603.             internal string BlockName {
  604.                 get {
  605.                     return GetType ().Name;
  606.                 }
  607.             }
  608.  
  609.             public bool Active {
  610.                 get {
  611.                     if (lastBlock > DateTime.MinValue) {
  612.                         TimeSpan ts = DateTime.Now - lastBlock;
  613.                         if (ts.TotalSeconds < Duration) {
  614.                             return true;
  615.                         }
  616.                     }
  617.  
  618.                     GameObject.Destroy (this);
  619.  
  620.                     return false;
  621.                 }
  622.             }
  623.  
  624.             void Awake ()
  625.             {
  626.                 player = GetComponent<BasePlayer> ();
  627.                 if (plugin.blockBehaviors.ContainsKey (player.userID)) {
  628.                     plugin.blockBehaviors.Remove (player.userID);
  629.                 }
  630.                 plugin.blockBehaviors.Add (player.userID, this);
  631.             }
  632.  
  633.             void Destroy ()
  634.             {
  635.                 if (!moved) {
  636.                     Stop ();
  637.                 }
  638.                 CancelInvoke ("Update");
  639.             }
  640.  
  641.             void Update ()
  642.             {
  643.                 if (!plugin.sendUINotification)
  644.                     return;
  645.                 bool send = false;
  646.                 if (lastUINotification == DateTime.MinValue) {
  647.                     lastUINotification = DateTime.Now;
  648.                     send = true;
  649.                 } else {
  650.                     TimeSpan ts = DateTime.Now - lastUINotification;
  651.                     if (ts.TotalSeconds > 2) {
  652.                         send = true;
  653.                     } else {
  654.                         send = false;
  655.                     }
  656.                 }
  657.  
  658.                 if (player is BasePlayer && player.IsConnected) {
  659.                     if (!Active) {
  660.                         CuiHelper.DestroyUi (player, "BlockMsg" + BlockName);
  661.                     }
  662.  
  663.                     if (send && Active) {
  664.                         lastUINotification = DateTime.Now;
  665.                         SendGUI ();
  666.                     }
  667.                 }
  668.             }
  669.  
  670.             public void Stop ()
  671.             {
  672.                 if (notifyCallback is Action)
  673.                     notifyCallback.Invoke ();
  674.  
  675.                 if (timer is Timer && !timer.Destroyed)
  676.                     timer.Destroy ();
  677.  
  678.                 if (plugin.sendUINotification && player is BasePlayer && player.IsConnected)
  679.                     CuiHelper.DestroyUi (player, "BlockMsg" + BlockName);
  680.  
  681.                 plugin.blockBehaviors.Remove (player.userID);
  682.  
  683.                 GameObject.Destroy (this);
  684.             }
  685.  
  686.             public void Notify (Action callback)
  687.             {
  688.                 if (plugin.sendUINotification)
  689.                     SendGUI ();
  690.  
  691.                 notifyCallback = callback;
  692.                 if (timer is Timer && !timer.Destroyed)
  693.                     timer.Destroy ();
  694.  
  695.                 timer = plugin.timer.In (Duration, callback);
  696.             }
  697.  
  698.             private string FormatTime (TimeSpan ts)
  699.             {
  700.                 if (ts.Days > 0)
  701.                     return string.Format ("{0}D, {1}H", ts.Days, ts.Hours);
  702.  
  703.                 if (ts.Hours > 0)
  704.                     return string.Format ("{0}H {1}M", ts.Hours, ts.Minutes);
  705.  
  706.                 return string.Format ("{0}M {1}S", ts.Minutes, ts.Seconds);
  707.             }
  708.  
  709.             void SendGUI ()
  710.             {
  711.                 TimeSpan ts = lastBlock.AddSeconds (Duration) - DateTime.Now;
  712.  
  713.                 string countDown = FormatTime (ts);
  714.                 CuiHelper.DestroyUi (player, "BlockMsg" + BlockName);
  715.                 var elements = new CuiElementContainer ();
  716.                 var BlockMsg = elements.Add (new CuiPanel {
  717.                     Image =
  718.                         {
  719.                             Color = "0.95 0 0.02 0.67"
  720.                         },
  721.                     RectTransform =
  722.                         {
  723.                             AnchorMax = NotificationWindow.AnchorMax,
  724.                             AnchorMin = NotificationWindow.AnchorMin
  725.                         }
  726.                 }, "Hud", "BlockMsg" + BlockName);
  727.                 elements.Add (new CuiElement {
  728.                     Parent = BlockMsg,
  729.                     Components =
  730.                         {
  731.                             new CuiRawImageComponent
  732.                             {
  733.                                 Sprite = "assets/icons/explosion.png",
  734.                                 Color = "0.95 0 0.02 0.67"
  735.                             },
  736.                             new CuiRectTransformComponent
  737.                             {
  738.                                 AnchorMin = "0 0",
  739.                                 AnchorMax = "0.13 1"
  740.                             }
  741.                         }
  742.                 });
  743.                 elements.Add (new CuiLabel {
  744.                     RectTransform =
  745.                         {
  746.                             AnchorMin = "0.15 0",
  747.                             AnchorMax = "0.82 1"
  748.                         },
  749.                     Text =
  750.                         {
  751.                             Text = notifyMessage,
  752.                             FontSize = 11,
  753.                             Align = TextAnchor.MiddleLeft,
  754.                         }
  755.                 }, BlockMsg);
  756.                 elements.Add (new CuiElement {
  757.                     Name = "TimerPanel",
  758.                     Parent = BlockMsg,
  759.                     Components =
  760.                         {
  761.                             new CuiImageComponent
  762.                             {
  763.                                 Color = "0 0 0 0.64",
  764.                                 ImageType = UnityEngine.UI.Image.Type.Filled
  765.                             },
  766.                             new CuiRectTransformComponent
  767.                             {
  768.                                 AnchorMin = "0.73 0",
  769.                                 AnchorMax = "1 1"
  770.                             }
  771.                         }
  772.                 });
  773.                 elements.Add (new CuiLabel {
  774.                     RectTransform =
  775.                         {
  776.                             AnchorMin = "0 0",
  777.                             AnchorMax = "1 1"
  778.                         },
  779.                     Text =
  780.                         {
  781.                             Text = countDown,
  782.                             FontSize = 12,
  783.                             Align = TextAnchor.MiddleCenter,
  784.                         }
  785.                 }, "TimerPanel");
  786.                 CuiHelper.AddUi (player, elements);
  787.             }
  788.  
  789.  
  790.         }
  791.  
  792.         public class CombatBlock : BlockBehavior
  793.         {
  794.             internal override float Duration {
  795.                 get {
  796.                     return combatDuration;
  797.                 }
  798.             }
  799.  
  800.             internal override string notifyMessage {
  801.                 get { return GetMsg ("Combat Block UI Message", player); }
  802.             }
  803.  
  804.             CuiRectTransformComponent _notificationWindow = null;
  805.  
  806.             internal override CuiRectTransformComponent NotificationWindow {
  807.                 get {
  808.                     if (_notificationWindow != null) {
  809.                         return _notificationWindow;
  810.                     }
  811.                     return _notificationWindow = new CuiRectTransformComponent () {
  812.                         AnchorMin = "0.44 0.15",
  813.                         AnchorMax = "0.56 0.18"
  814.                     };
  815.                 }
  816.                 set {
  817.                     _notificationWindow = value;
  818.                 }
  819.             }
  820.         }
  821.  
  822.         public class RaidBlock : BlockBehavior
  823.         {
  824.             internal override float Duration {
  825.                 get {
  826.                     return raidDuration;
  827.                 }
  828.             }
  829.  
  830.             internal override string notifyMessage {
  831.                 get { return GetMsg ("Raid Block UI Message", player); }
  832.             }
  833.  
  834.             private CuiRectTransformComponent _notificationWindow = null;
  835.  
  836.             internal override CuiRectTransformComponent NotificationWindow {
  837.                 get {
  838.                     if (_notificationWindow != null) {
  839.                         return _notificationWindow;
  840.                     }
  841.                     return _notificationWindow = new CuiRectTransformComponent () {
  842.                         AnchorMin = "0.87 0.39",
  843.                         AnchorMax = "0.99 0.42"
  844.                     };
  845.                 }
  846.                 set {
  847.                     _notificationWindow = value;
  848.                 }
  849.             }
  850.         }
  851.  
  852.         #endregion
  853.  
  854.         #region Oxide Hooks
  855.  
  856.         void OnEntityTakeDamage (BaseCombatEntity entity, HitInfo hitInfo)
  857.         {
  858.             BasePlayer attacker = hitInfo?.InitiatorPlayer;
  859.             BasePlayer victim = entity as BasePlayer;
  860.  
  861.             if (victim == attacker)
  862.                 return;
  863.  
  864.             if (victim != null && attacker != null && hitInfo.Weapon == null)
  865.             {
  866.                 hitInfo.HitEntity = victim;
  867.                 OnPlayerAttack(attacker, hitInfo);
  868.                 return;
  869.             }
  870.  
  871.             if (!blockOnDamage || !raidBlock)
  872.                 return;
  873.             if (hitInfo == null || hitInfo.Initiator == null || !IsEntityBlocked (entity) || hitInfo.Initiator.transform == null)
  874.                 return;
  875.             if (!IsRaidDamage (hitInfo.damageTypes))
  876.                 return;
  877.             if (IsExcludedWeapon (hitInfo?.WeaponPrefab?.ShortPrefabName))
  878.                 return;
  879.             if (GetHealthPercent (entity, hitInfo.damageTypes.Total ()) > blockOnDamageMinCondition) {
  880.                 return;
  881.             }
  882.  
  883.             StructureAttack (entity, hitInfo.Initiator, hitInfo?.WeaponPrefab?.ShortPrefabName, hitInfo.HitPositionWorld);
  884.         }
  885.          
  886.         void OnPlayerConnected (BasePlayer player)
  887.         {
  888.             BlockBehavior behavior;
  889.             if (blockBehaviors.TryGetValue (player.userID, out behavior)) {
  890.                 if (behavior is RaidBlock) {
  891.                     var raidBlockComponent = player.gameObject.AddComponent<RaidBlock> ();
  892.                     raidBlockComponent.CopyFrom (behavior);
  893.                 } else if (behavior is CombatBlock) {
  894.                     var combatBlockComponent = player.gameObject.AddComponent<CombatBlock> ();
  895.                     combatBlockComponent.CopyFrom (behavior);
  896.                 }
  897.  
  898.                 behavior.moved = true;
  899.                 GameObject.Destroy (behavior);
  900.             }
  901.         }
  902.  
  903.         void OnPlayerAttack (BasePlayer attacker, HitInfo hitInfo)
  904.         {
  905.             if (!combatBlock || !(hitInfo.HitEntity is BasePlayer))
  906.                 return;
  907.  
  908.             if (!combatOnHitNPC && hitInfo.HitEntity != null && hitInfo.HitEntity.IsNpc)
  909.                 return;
  910.  
  911.             if (!combatOnTakeDamageNPC && attacker.IsNpc)
  912.                 return;
  913.  
  914.  
  915.             if (!IsCombatDamage(hitInfo.damageTypes))
  916.                 return;
  917.  
  918.             float totalDamage = Mathf.Max(1,hitInfo.damageTypes.Total ());
  919.             BasePlayer target = hitInfo.HitEntity as BasePlayer;
  920.  
  921.             if (combatOnTakeDamage)
  922.             {
  923.  
  924.                 if (GetHealthPercent (target, hitInfo.damageTypes.Total ()) > combatOnTakeDamageMinCondition)
  925.                     return;
  926.  
  927.                 if (totalDamage < combatOnTakeDamageMinDamage)
  928.                     return;
  929.  
  930.                 StartCombatBlocking (target);
  931.             }
  932.  
  933.             if (combatOnHitPlayer)
  934.             {
  935.                 if (GetHealthPercent (attacker, hitInfo.damageTypes.Total ()) > combatOnHitPlayerMinCondition)
  936.                     return;
  937.  
  938.                 if (totalDamage < combatOnHitPlayerMinDamage)
  939.                     return;
  940.  
  941.                 StartCombatBlocking (attacker);
  942.             }
  943.         }
  944.  
  945.         void OnEntityDeath (BaseCombatEntity entity, HitInfo hitInfo)
  946.         {
  947.             if (blockOnDestroy && raidBlock) {
  948.                 if (hitInfo == null || hitInfo.Initiator == null || !IsDeathDamage (hitInfo.damageTypes) || !IsEntityBlocked (entity))
  949.                     return;
  950.  
  951.                 StructureAttack (entity, hitInfo.Initiator, hitInfo?.WeaponPrefab?.ShortPrefabName, hitInfo.HitPositionWorld);
  952.             }
  953.  
  954.             if (entity.ToPlayer () == null)
  955.                 return;
  956.  
  957.             var player = entity.ToPlayer ();
  958.             RaidBlock raidBlocker;
  959.             if (raidBlock && raidUnblockOnDeath && TryGetBlocker (player, out raidBlocker)) {
  960.                 timer.In (0.3f, delegate () {
  961.                     raidBlocker.Stop ();
  962.                 });
  963.             }
  964.  
  965.             CombatBlock combatBlocker;
  966.             if (combatBlock && combatUnblockOnDeath && TryGetBlocker (player, out combatBlocker)) {
  967.                 timer.In (0.3f, delegate () {
  968.                     combatBlocker.Stop ();
  969.                 });
  970.             }
  971.         }
  972.  
  973.         void OnPlayerSleepEnded (BasePlayer player)
  974.         {
  975.             if (player == null) return;
  976.             RaidBlock raidBlocker;
  977.             if (raidBlock && raidUnblockOnWakeup && TryGetBlocker (player, out raidBlocker)) {
  978.                 timer.In (0.3f, delegate () {
  979.                     raidBlocker.Stop ();
  980.                 });
  981.             }
  982.  
  983.             CombatBlock combatBlocker;
  984.             if (combatBlock && combatUnblockOnWakeup && TryGetBlocker (player, out combatBlocker)) {
  985.                 timer.In (0.3f, delegate () {
  986.                     combatBlocker.Stop ();
  987.                 });
  988.             }
  989.         }
  990.  
  991.         void OnPlayerRespawned (BasePlayer player)
  992.         {
  993.             if (player == null) return;
  994.             RaidBlock raidBlocker;
  995.             if (raidBlock && raidUnblockOnRespawn && TryGetBlocker (player, out raidBlocker)) {
  996.                 timer.In (0.3f, delegate () {
  997.                     raidBlocker.Stop ();
  998.                 });
  999.             }
  1000.  
  1001.             CombatBlock combatBlocker;
  1002.             if (combatBlock && combatUnblockOnRespawn && TryGetBlocker (player, out combatBlocker)) {
  1003.                 timer.In (0.3f, delegate () {
  1004.                     combatBlocker.Stop ();
  1005.                 });
  1006.             }
  1007.         }
  1008.  
  1009.         object CanLootEntity(BasePlayer player, StorageContainer container)
  1010.         {
  1011.             if(container?.GetEntity() is Recycler)
  1012.             {
  1013.                 object reply = CanDo("recycle", player);
  1014.  
  1015.                 if (reply != null && IsBlocked(player))
  1016.                 {
  1017.                     player.ChatMessage((string)reply);
  1018.                     return true;
  1019.                 }
  1020.             }
  1021.  
  1022.             return null;
  1023.         }
  1024.  
  1025.         #endregion
  1026.  
  1027.         #region Block Handling
  1028.  
  1029.         void StructureAttack (BaseEntity targetEntity, BaseEntity sourceEntity, string weapon, Vector3 hitPosition)
  1030.         {
  1031.             BasePlayer source = null;
  1032.  
  1033.             if (sourceEntity.ToPlayer () is BasePlayer)
  1034.                 source = sourceEntity.ToPlayer ();
  1035.             else {
  1036.                 ulong ownerID = sourceEntity.OwnerID;
  1037.                 if (ownerID.IsSteamId ())
  1038.                     source = BasePlayer.FindByID (ownerID);
  1039.                 else
  1040.                     return;
  1041.             }
  1042.  
  1043.             if (source == null)
  1044.                 return;
  1045.  
  1046.             List<string> sourceMembers = null;
  1047.  
  1048.             if (targetEntity.OwnerID.IsSteamId () || (blockUnowned && !targetEntity.OwnerID.IsSteamId ())) {
  1049.                 if (clanCheck || friendCheck)
  1050.                     sourceMembers = getFriends (source.UserIDString);
  1051.  
  1052.                 if (blockAll) {
  1053.                     BlockAll (source, targetEntity, sourceMembers);
  1054.                 } else {
  1055.                     if (ownerBlock)
  1056.                         OwnerBlock (source, sourceEntity, targetEntity.OwnerID, targetEntity.transform.position, sourceMembers);
  1057.  
  1058.                     if (raiderBlock)
  1059.                         RaiderBlock (source, targetEntity.OwnerID, targetEntity.transform.position, sourceMembers);
  1060.                 }
  1061.             }
  1062.         }
  1063.  
  1064.         float GetHealthPercent (BaseEntity entity, float damage = 0f)
  1065.         {
  1066.             if (entity == null)
  1067.                 return 0f;
  1068.             return (entity.Health () - damage) * 100f / entity.MaxHealth ();
  1069.         }
  1070.  
  1071.         void BlockAll (BasePlayer source, BaseEntity targetEntity, List<string> sourceMembers = null)
  1072.         {
  1073.             if (ShouldBlockEscape (targetEntity.OwnerID, source.userID, sourceMembers)) {
  1074.                 StartRaidBlocking (source, targetEntity.transform.position);
  1075.             }
  1076.  
  1077.             var checkSourceMembers = false;
  1078.             if (targetEntity.OwnerID == source.userID || (sourceMembers is List<string> && sourceMembers.Contains (targetEntity.OwnerID.ToString ()))) {
  1079.                 checkSourceMembers = true;
  1080.             }
  1081.  
  1082.             var nearbyTargets = Pool.GetList<BasePlayer> ();
  1083.             Vis.Entities (targetEntity.transform.position, raidDistance, nearbyTargets, blockLayer);
  1084.             if (nearbyTargets.Count > 0) {
  1085.                 RaidBlock blocker;
  1086.                 foreach (BasePlayer nearbyTarget in nearbyTargets) {
  1087.                     if (nearbyTarget.IsNpc) continue;
  1088.                     if (nearbyTarget.userID == source.userID) continue;
  1089.                     if (TryGetBlocker (nearbyTarget, out blocker) && blocker.Active) {
  1090.                         StartRaidBlocking (nearbyTarget, targetEntity.transform.position);
  1091.                     } else if (ShouldBlockEscape (nearbyTarget.userID, source.userID, checkSourceMembers ? sourceMembers : null)) {
  1092.                         StartRaidBlocking (nearbyTarget, targetEntity.transform.position);
  1093.                     }
  1094.                 }
  1095.             }
  1096.  
  1097.             Pool.FreeList (ref nearbyTargets);
  1098.         }
  1099.  
  1100.         void OwnerBlock (BasePlayer source, BaseEntity sourceEntity, ulong target, Vector3 position, List<string> sourceMembers = null)
  1101.         {
  1102.             if (!ShouldBlockEscape (target, source.userID, sourceMembers))
  1103.                 return;
  1104.  
  1105.             var targetMembers = new List<string> ();
  1106.  
  1107.             if (clanShare || friendShare)
  1108.                 targetMembers = getFriends (target.ToString ());
  1109.  
  1110.             var nearbyTargets = Pool.GetList<BasePlayer> ();
  1111.             Vis.Entities (position, raidDistance, nearbyTargets, blockLayer);
  1112.             if (cupboardShare)
  1113.                 sourceMembers = CupboardShare (target.ToString (), position, sourceEntity, sourceMembers);
  1114.  
  1115.             if (nearbyTargets.Count > 0) {
  1116.                 foreach (BasePlayer nearbyTarget in nearbyTargets) {
  1117.                     if (nearbyTarget.IsNpc) continue;
  1118.                     if (nearbyTarget.userID == target || (targetMembers != null && targetMembers.Contains (nearbyTarget.UserIDString)))
  1119.                         StartRaidBlocking (nearbyTarget, position);
  1120.                 }
  1121.             }
  1122.  
  1123.             Pool.FreeList (ref nearbyTargets);
  1124.         }
  1125.  
  1126.         List<string> CupboardShare (string owner, Vector3 position, BaseEntity sourceEntity, List<string> sourceMembers = null)
  1127.         {
  1128.             var nearbyCupboards = Pool.GetList<BuildingPrivlidge> ();
  1129.             Vis.Entities (position, raidDistance, nearbyCupboards, cupboardMask);
  1130.             if (sourceMembers == null)
  1131.                 sourceMembers = new List<string> ();
  1132.  
  1133.             List<string> cupboardMembers = new List<string> ();
  1134.  
  1135.             var sourcePlayer = sourceEntity as BasePlayer;
  1136.  
  1137.             if (sourcePlayer != null) {
  1138.                 foreach (var cup in nearbyCupboards) {
  1139.                     if (cup.IsAuthed (sourcePlayer)) {
  1140.                         bool ownerOrFriend = false;
  1141.  
  1142.                         if (owner == cup.OwnerID.ToString ())
  1143.                             ownerOrFriend = true;
  1144.  
  1145.                         foreach (var member in sourceMembers) {
  1146.                             if (member == cup.OwnerID.ToString ())
  1147.                                 ownerOrFriend = true;
  1148.                         }
  1149.  
  1150.                         if (ownerOrFriend)
  1151.                             foreach (var proto in cup.authorizedPlayers)
  1152.                                 if (!sourceMembers.Contains (proto.userid.ToString ()))
  1153.                                     cupboardMembers.Add (proto.userid.ToString ());
  1154.                     }
  1155.                 }
  1156.             }
  1157.  
  1158.             sourceMembers.AddRange (cupboardMembers);
  1159.             Pool.FreeList (ref nearbyCupboards);
  1160.  
  1161.             return sourceMembers;
  1162.         }
  1163.  
  1164.         void RaiderBlock (BasePlayer source, ulong target, Vector3 position, List<string> sourceMembers = null)
  1165.         {
  1166.             if (!ShouldBlockEscape (target, source.userID, sourceMembers))
  1167.                 return;
  1168.  
  1169.             var targetMembers = new List<string> ();
  1170.  
  1171.             if ((clanShare || friendShare) && sourceMembers == null)
  1172.                 sourceMembers = getFriends (source.UserIDString);
  1173.  
  1174.             var nearbyTargets = Pool.GetList<BasePlayer> ();
  1175.             Vis.Entities (position, raidDistance, nearbyTargets, blockLayer);
  1176.             if (nearbyTargets.Count > 0) {
  1177.                 foreach (BasePlayer nearbyTarget in nearbyTargets) {
  1178.                     if (nearbyTarget.IsNpc) continue;
  1179.                     if (nearbyTarget == source || (sourceMembers != null && sourceMembers.Contains (nearbyTarget.UserIDString)))
  1180.                         StartRaidBlocking (nearbyTarget, position);
  1181.                 }
  1182.             }
  1183.  
  1184.             Pool.FreeList (ref nearbyTargets);
  1185.         }
  1186.  
  1187.         #endregion
  1188.  
  1189.         #region API
  1190.  
  1191.         bool IsBlocked (string target)
  1192.         {
  1193.             var player = BasePlayer.Find (target);
  1194.             if (player is BasePlayer) {
  1195.                 return IsBlocked (player);
  1196.             }
  1197.  
  1198.             return false;
  1199.         }
  1200.  
  1201.         bool IsBlocked (BasePlayer target)
  1202.         {
  1203.             if (IsBlocked<RaidBlock> (target) || IsBlocked<CombatBlock> (target))
  1204.                 return true;
  1205.  
  1206.             return false;
  1207.         }
  1208.  
  1209.         public bool IsBlocked<T> (BasePlayer target) where T : BlockBehavior
  1210.         {
  1211.             T behavior;
  1212.             if (TryGetBlocker<T> (target, out behavior) && behavior.Active)
  1213.                 return true;
  1214.  
  1215.             return false;
  1216.         }
  1217.  
  1218.         bool IsRaidBlocked (BasePlayer target)
  1219.         {
  1220.             return IsBlocked<RaidBlock> (target);
  1221.         }
  1222.  
  1223.         bool IsCombatBlocked (BasePlayer target)
  1224.         {
  1225.             return IsBlocked<CombatBlock> (target);
  1226.         }
  1227.  
  1228.         bool IsEscapeBlocked (string target)
  1229.         {
  1230.             var player = BasePlayer.Find (target);
  1231.             if (player is BasePlayer) {
  1232.                 return IsBlocked (player);
  1233.             }
  1234.  
  1235.             return false;
  1236.         }
  1237.  
  1238.         bool IsRaidBlocked (string target)
  1239.         {
  1240.             var player = BasePlayer.Find (target);
  1241.             if (player is BasePlayer) {
  1242.                 return IsBlocked<RaidBlock> (player);
  1243.             }
  1244.  
  1245.             return false;
  1246.         }
  1247.  
  1248.         bool IsCombatBlocked (string target)
  1249.         {
  1250.             var player = BasePlayer.Find (target);
  1251.             if (player is BasePlayer) {
  1252.                 return IsBlocked<CombatBlock> (player);
  1253.             }
  1254.  
  1255.             return false;
  1256.         }
  1257.  
  1258.         bool ShouldBlockEscape (ulong target, ulong source, List<string> sourceMembers = null)
  1259.         {
  1260.             if (target == source) {
  1261.                 if ((ownerBlock || raiderBlock || blockAll) && (!ownerCheck))
  1262.                     return true;
  1263.  
  1264.                 return false;
  1265.             }
  1266.  
  1267.             if (sourceMembers is List<string> && sourceMembers.Contains (target.ToString ()))
  1268.                 return false;
  1269.  
  1270.             return true;
  1271.         }
  1272.  
  1273.         //[ChatCommand ("bblocked")]
  1274.         //void cmdBBlocked (BasePlayer player, string command, string [] args)
  1275.         //{
  1276.         //    StartCombatBlocking (player);
  1277.         //    StartRaidBlocking (player);
  1278.         //}
  1279.  
  1280.         //[ChatCommand ("bunblocked")]
  1281.         //void cmdBUnblocked (BasePlayer player, string command, string [] args)
  1282.         //{
  1283.         //    StopCombatBlocking (player);
  1284.         //    StopRaidBlocking (player);
  1285.         //}
  1286.  
  1287.         void StartRaidBlocking (BasePlayer target, bool createZone = true)
  1288.         {
  1289.             StartRaidBlocking (target, target.transform.position, createZone);
  1290.         }
  1291.  
  1292.         void StartRaidBlocking (BasePlayer target, Vector3 position, bool createZone = true)
  1293.         {
  1294.             if (HasPerm (target.UserIDString, "disable")) {
  1295.                 return;
  1296.             }
  1297.  
  1298.             if (target.gameObject == null) {
  1299.                 return;
  1300.             }
  1301.  
  1302.             if (Interface.Call ("CanRaidBlock", target, position, createZone) != null) {
  1303.                 return;
  1304.             }
  1305.  
  1306.             if (target.gameObject == null)
  1307.                 return;
  1308.  
  1309.             foreach (var comp in target.gameObject.GetComponents<Component>().ToList())
  1310.                 if (!(comp is CombatBlock) && comp.ToString().Contains("NoEscape"))
  1311.                     UnityEngine.Object.Destroy(comp);
  1312.  
  1313.             var raidBlocker = target.gameObject.GetComponent<RaidBlock> ();
  1314.             if (raidBlocker == null) {
  1315.                 raidBlocker = target.gameObject.AddComponent<RaidBlock> ();
  1316.             }
  1317.  
  1318.             Interface.CallHook ("OnRaidBlock", target, position);
  1319.              
  1320.             raidBlocker.lastBlock = DateTime.Now;
  1321.  
  1322.             if (raidBlockNotify)
  1323.                 SendBlockMessage (target, raidBlocker, "Raid Block Notifier", "Raid Block Complete");
  1324.  
  1325.             if (useZoneManager && createZone && (zoneEnter || zoneLeave))
  1326.                 CreateRaidZone (position);
  1327.         }
  1328.  
  1329.         void StartCombatBlocking (BasePlayer target)
  1330.         {
  1331.             if (HasPerm (target.UserIDString, "disable")) {
  1332.                 return;
  1333.             }
  1334.             if (target.gameObject == null) {
  1335.                 return;
  1336.             }
  1337.  
  1338.             if (Interface.Call ("CanCombatBlock", target) != null) {
  1339.                 return;
  1340.             }
  1341.  
  1342.             foreach (var comp in target.gameObject.GetComponents<Component>().ToList())
  1343.                 if (!(comp is CombatBlock) && comp.ToString().Contains("NoEscape"))
  1344.                     UnityEngine.Object.Destroy(comp);
  1345.  
  1346.             var combatBlocker = target.gameObject.GetComponent<CombatBlock> ();
  1347.             if (combatBlocker == null) {
  1348.                 combatBlocker = target.gameObject.AddComponent<CombatBlock> ();
  1349.             }
  1350.             Interface.CallHook ("OnCombatBlock", target);
  1351.             combatBlocker.lastBlock = DateTime.Now;
  1352.  
  1353.             if (combatBlockNotify)
  1354.                 SendBlockMessage(target, combatBlocker, "Combat Block Notifier", "Combat Block Complete");
  1355.         }
  1356.          
  1357.         void StopBlocking (BasePlayer target)
  1358.         {
  1359.             if (IsRaidBlocked (target))
  1360.                 StopBlocking<RaidBlock> (target);
  1361.             if (IsCombatBlocked (target))
  1362.                 StopBlocking<CombatBlock> (target);
  1363.         }
  1364.          
  1365.         public void StopBlocking<T> (BasePlayer target) where T : BlockBehavior
  1366.         {
  1367.             if (target.gameObject == null)
  1368.                 return;
  1369.             var block = target.gameObject.GetComponent<T> ();
  1370.             if (block is BlockBehavior)
  1371.                 block.Stop ();
  1372.  
  1373.             if (block is RaidBlock) {
  1374.                 Interface.CallHook ("OnRaidBlockStopped", target);
  1375.             } else if (block is CombatBlock) {
  1376.                 Interface.CallHook ("OnCombatBlockStopped", target);
  1377.             }
  1378.         }
  1379.  
  1380.         void ClearRaidBlockingS (string target)
  1381.         {
  1382.             StopRaidBlocking (target);
  1383.         }
  1384.  
  1385.         void StopRaidBlocking (BasePlayer player)
  1386.         {
  1387.             if (player is BasePlayer && IsRaidBlocked (player))
  1388.                 StopBlocking<RaidBlock> (player);
  1389.         }
  1390.  
  1391.         void StopRaidBlocking (string target)
  1392.         {
  1393.             var player = BasePlayer.Find (target);
  1394.             StopRaidBlocking (player);
  1395.         }
  1396.  
  1397.         void StopCombatBlocking (BasePlayer player)
  1398.         {
  1399.             if (player is BasePlayer && IsRaidBlocked (player))
  1400.                 StopBlocking<CombatBlock> (player);
  1401.         }
  1402.  
  1403.         void StopCombatBlocking (string target)
  1404.         {
  1405.             var player = BasePlayer.Find (target);
  1406.             StopCombatBlocking (player);
  1407.         }
  1408.  
  1409.         void ClearCombatBlocking (string target)
  1410.         {
  1411.             StopCombatBlocking (target);
  1412.         }
  1413.  
  1414.         #endregion
  1415.  
  1416.         #region Zone Handling
  1417.  
  1418.         void EraseZone (string zoneid)
  1419.         {
  1420.             ZoneManager.CallHook ("EraseZone", zoneid);
  1421.             zones.Remove (zoneid);
  1422.         }
  1423.  
  1424.         void ResetZoneTimer (RaidZone zone)
  1425.         {
  1426.             zone.ResetTimer ().timer = timer.In (raidDuration, delegate () {
  1427.                 EraseZone (zone.zoneid);
  1428.             });
  1429.         }
  1430.  
  1431.         void CreateRaidZone (Vector3 position)
  1432.         {
  1433.             var zoneid = position.ToString ();
  1434.  
  1435.             RaidZone zone;
  1436.             if (zones.TryGetValue (zoneid, out zone)) {
  1437.                 ResetZoneTimer (zone);
  1438.                 return;
  1439.             }
  1440.  
  1441.             foreach (var nearbyZone in zones) {
  1442.                 if (nearbyZone.Value.Distance (position) < (raidDistance / 2)) {
  1443.                     ResetZoneTimer (nearbyZone.Value);
  1444.                     return;
  1445.                 }
  1446.             }
  1447.  
  1448.             ZoneManager.CallHook ("CreateOrUpdateZone", zoneid, new string []
  1449.                 {
  1450.                     "radius",
  1451.                     raidDistance.ToString()
  1452.                 }, position);
  1453.  
  1454.             zones.Add (zoneid, zone = new RaidZone (zoneid, position));
  1455.  
  1456.             ResetZoneTimer (zone);
  1457.         }
  1458.  
  1459.         [HookMethod ("OnEnterZone")]
  1460.         void OnEnterZone (string zoneid, BasePlayer player)
  1461.         {
  1462.             if (!zoneEnter)
  1463.                 return;
  1464.             if (!zones.ContainsKey (zoneid))
  1465.                 return;
  1466.  
  1467.             StartRaidBlocking (player, player.transform.position, false);
  1468.         }
  1469.  
  1470.         [HookMethod ("OnExitZone")]
  1471.         void OnExitZone (string zoneid, BasePlayer player)
  1472.         {
  1473.             if (!zoneLeave)
  1474.                 return;
  1475.             if (!zones.ContainsKey (zoneid))
  1476.                 return;
  1477.  
  1478.             if (IsRaidBlocked (player)) {
  1479.                 StopBlocking<RaidBlock> (player);
  1480.             }
  1481.         }
  1482.        
  1483.         [HookMethod ("OnPlayerEnteredRaidableBase")]
  1484.         void OnPlayerEnteredRaidableBase(BasePlayer player, Vector3 raidPos, bool allowPVP)
  1485.         {
  1486.             if (!raidableZoneEnter)
  1487.                 return;
  1488.                
  1489.             StartRaidBlocking (player, false);
  1490.         }
  1491.        
  1492.         [HookMethod ("OnPlayerExitedRaidableBase")]
  1493.         void OnPlayerExitedRaidableBase(BasePlayer player, Vector3 raidPos, bool allowPVP)
  1494.         {
  1495.             if (!raidableZoneLeave)
  1496.                 return;
  1497.                
  1498.             if (IsRaidBlocked (player)) {
  1499.                 StopBlocking<RaidBlock> (player);
  1500.             }
  1501.         }
  1502.  
  1503.         #endregion
  1504.  
  1505.         #region Friend/Clan Integration
  1506.  
  1507.         public List<string> getFriends (string player)
  1508.         {
  1509.             var players = new List<string> ();
  1510.             if (player == null)
  1511.                 return players;
  1512.  
  1513.             if (friendShare || friendCheck) {
  1514.                 var friendList = getFriendList (player);
  1515.                 if (friendList != null)
  1516.                     players.AddRange (friendList);
  1517.             }
  1518.  
  1519.             if (clanShare || clanCheck) {
  1520.                 var members = getClanMembers (player);
  1521.                 if (members != null)
  1522.                     players.AddRange (members);
  1523.             }
  1524.             return players;
  1525.         }
  1526.  
  1527.         public List<string> getFriendList (string player)
  1528.         {
  1529.             object friends_obj = null;
  1530.             DateTime lastFriendCheckPlayer;
  1531.             var players = new List<string> ();
  1532.  
  1533.             if (lastFriendCheck.TryGetValue (player, out lastFriendCheckPlayer)) {
  1534.                 if ((DateTime.Now - lastFriendCheckPlayer).TotalMinutes <= cacheTimer && friendCache.TryGetValue (player, out players)) {
  1535.                     return players;
  1536.                 } else {
  1537.                     friends_obj = Friends?.CallHook ("IsFriendOfS", player);
  1538.                     lastFriendCheck [player] = DateTime.Now;
  1539.                 }
  1540.             } else {
  1541.                 friends_obj = Friends?.CallHook ("IsFriendOfS", player);
  1542.                 lastFriendCheck.Add (player, DateTime.Now);
  1543.             }
  1544.  
  1545.             if (friends_obj == null)
  1546.                 return players;
  1547.  
  1548.             string [] friends = friends_obj as string [];
  1549.  
  1550.             foreach (string fid in friends)
  1551.                 players.Add (fid);
  1552.  
  1553.             if (friendCache.ContainsKey (player))
  1554.                 friendCache [player] = players;
  1555.             else
  1556.                 friendCache.Add (player, players);
  1557.  
  1558.             return players;
  1559.         }
  1560.  
  1561.         public List<string> getClanMembers (string player)
  1562.         {
  1563.             string tag = null;
  1564.             DateTime lastClanCheckPlayer;
  1565.             string lastClanCached;
  1566.             if (lastClanCheck.TryGetValue (player, out lastClanCheckPlayer) && clanCache.TryGetValue (player, out lastClanCached)) {
  1567.                 if ((DateTime.Now - lastClanCheckPlayer).TotalMinutes <= cacheTimer)
  1568.                     tag = lastClanCached;
  1569.                 else {
  1570.                     tag = Clans.Call<string> ("GetClanOf", player);
  1571.                     clanCache [player] = tag;
  1572.                     lastClanCheck [player] = DateTime.Now;
  1573.                 }
  1574.             } else {
  1575.                 tag = Clans.Call<string> ("GetClanOf", player);
  1576.                 if (lastClanCheck.ContainsKey (player))
  1577.                     lastClanCheck.Remove (player);
  1578.  
  1579.                 if (clanCache.ContainsKey (player))
  1580.                     clanCache.Remove (player);
  1581.  
  1582.                 clanCache.Add (player, tag);
  1583.                 lastClanCheck.Add (player, DateTime.Now);
  1584.             }
  1585.  
  1586.             if (tag == null)
  1587.                 return null;
  1588.  
  1589.             List<string> lastMemberCache;
  1590.             if (memberCache.TryGetValue (tag, out lastMemberCache))
  1591.                 return lastMemberCache;
  1592.  
  1593.             var clan = GetClan (tag);
  1594.  
  1595.             if (clan == null)
  1596.                 return null;
  1597.  
  1598.             return CacheClan (clan);
  1599.         }
  1600.  
  1601.         JObject GetClan (string tag)
  1602.         {
  1603.             if (string.IsNullOrEmpty (tag)) {
  1604.                 return null;
  1605.             }
  1606.             return Clans.Call<JObject> ("GetClan", tag);
  1607.         }
  1608.  
  1609.         List<string> CacheClan (JObject clan)
  1610.         {
  1611.             string tag = clan ["tag"].ToString ();
  1612.             List<string> players = new List<string> ();
  1613.             foreach (string memberid in clan ["members"]) {
  1614.                 if (clanCache.ContainsKey (memberid))
  1615.                     clanCache [memberid] = tag;
  1616.                 else
  1617.                     clanCache.Add (memberid, tag);
  1618.  
  1619.                 players.Add (memberid);
  1620.             }
  1621.  
  1622.             if (memberCache.ContainsKey (tag))
  1623.                 memberCache [tag] = players;
  1624.             else
  1625.                 memberCache.Add (tag, players);
  1626.  
  1627.             if (lastCheck.ContainsKey (tag))
  1628.                 lastCheck [tag] = DateTime.Now;
  1629.             else
  1630.                 lastCheck.Add (tag, DateTime.Now);
  1631.  
  1632.             return players;
  1633.         }
  1634.  
  1635.         [HookMethod ("OnClanCreate")]
  1636.         void OnClanCreate (string tag)
  1637.         {
  1638.             var clan = GetClan (tag);
  1639.             if (clan != null) {
  1640.                 CacheClan (clan);
  1641.             } else {
  1642.                 PrintWarning ("Unable to find clan after creation: " + tag);
  1643.             }
  1644.         }
  1645.  
  1646.         [HookMethod ("OnClanUpdate")]
  1647.         void OnClanUpdate (string tag)
  1648.         {
  1649.             var clan = GetClan (tag);
  1650.             if (clan != null) {
  1651.                 CacheClan (clan);
  1652.             } else {
  1653.                 PrintWarning ("Unable to find clan after update: " + tag);
  1654.             }
  1655.         }
  1656.  
  1657.         [HookMethod ("OnClanDestroy")]
  1658.         void OnClanDestroy (string tag)
  1659.         {
  1660.             if (lastCheck.ContainsKey (tag)) {
  1661.                 lastCheck.Remove (tag);
  1662.             }
  1663.  
  1664.             if (memberCache.ContainsKey (tag)) {
  1665.                 memberCache.Remove (tag);
  1666.             }
  1667.         }
  1668.  
  1669.         #endregion
  1670.  
  1671.         #region Permission Checking & External API Handling
  1672.  
  1673.         bool HasPerm (string userid, string perm)
  1674.         {
  1675.             return permission.UserHasPermission (userid, "noescape." + perm);
  1676.         }
  1677.  
  1678.         bool CanRaidCommand (BasePlayer player, string command)
  1679.         {
  1680.             return raidBlock && HasPerm (player.UserIDString, "raid." + command + "block") && IsRaidBlocked (player);
  1681.         }
  1682.  
  1683.         bool CanRaidCommand (string playerID, string command)
  1684.         {
  1685.             return raidBlock && HasPerm (playerID, "raid." + command + "block") && IsRaidBlocked (playerID);
  1686.         }
  1687.  
  1688.         bool CanCombatCommand (BasePlayer player, string command)
  1689.         {
  1690.             return combatBlock && HasPerm (player.UserIDString, "combat." + command + "block") && IsCombatBlocked (player);
  1691.         }
  1692.  
  1693.         bool CanCombatCommand (string playerID, string command)
  1694.         {
  1695.             return combatBlock && HasPerm (playerID, "combat." + command + "block") && IsCombatBlocked (playerID);
  1696.         }
  1697.  
  1698.         object CanDo (string command, BasePlayer player)
  1699.         {
  1700.             if (CanRaidCommand (player, command))
  1701.                 return GetMessage<RaidBlock> (player, "Raid Blocked Message", raidDuration);
  1702.             else if (CanCombatCommand (player, command))
  1703.                 return GetMessage<CombatBlock> (player, "Combat Blocked Message", combatDuration);
  1704.  
  1705.             return null;
  1706.         }
  1707.  
  1708.         object OnStructureRepair (BaseCombatEntity entity, BasePlayer player)
  1709.         {
  1710.             var result = CanDo ("repair", player);
  1711.             if (result is string) {
  1712.                 if (entity.health > entity.MaxHealth ()) {
  1713.                     return null;
  1714.                 }
  1715.                 SendReply (player, result.ToString ());
  1716.                 return true;
  1717.             }
  1718.  
  1719.             return null;
  1720.         }
  1721.  
  1722.         object OnStructureUpgrade (BuildingBlock block, BasePlayer player, BuildingGrade.Enum grade)
  1723.         {
  1724.             var result = CanDo ("upgrade", player);
  1725.             if (result is string) {
  1726.                 SendReply (player, result.ToString ());
  1727.                 return true;
  1728.             }
  1729.  
  1730.             return null;
  1731.         }
  1732.  
  1733.         object canRedeemKit (BasePlayer player)
  1734.         {
  1735.             return CanDo ("kit", player);
  1736.         }
  1737.  
  1738.         object CanUseMailbox (BasePlayer player, Mailbox mailbox)
  1739.         {
  1740.             var result = CanDo ("mailbox", player);
  1741.             if (result is string) {
  1742.                 SendReply (player, result.ToString ());
  1743.                 return true;
  1744.             }
  1745.  
  1746.             return null;
  1747.         }
  1748.  
  1749.         object CanUseVending (VendingMachine machine, BasePlayer player)
  1750.         {
  1751.             var result = CanDo ("vend", player);
  1752.             if (result is string) {
  1753.                 SendReply (player, result.ToString ());
  1754.                 return true;
  1755.             }
  1756.  
  1757.             return null;
  1758.         }
  1759.  
  1760.         object CanBuild (Planner plan, Construction prefab)
  1761.         {
  1762.             var player = plan.GetOwnerPlayer ();
  1763.             var result = CanDo ("build", player);
  1764.             if (result is string) {
  1765.                 if (isEntityException (prefab.fullName)) {
  1766.                     return null;
  1767.                 }
  1768.  
  1769.                 SendReply (player, result.ToString ());
  1770.                 return true;
  1771.             }
  1772.  
  1773.             return null;
  1774.         }
  1775.  
  1776.         object CanAssignBed (SleepingBag bag, BasePlayer player, ulong targetPlayerId)
  1777.         {
  1778.             var result = CanDo ("assignbed", player);
  1779.             if (result is string) {
  1780.                 SendReply (player, result.ToString ());
  1781.                 return true;
  1782.             }
  1783.  
  1784.             return null;
  1785.         }
  1786.        
  1787.         object CanOpenBackpack(BasePlayer player, ulong backpackOwnerID)
  1788.         {
  1789.             return CanDo ("backpack", player);
  1790.         }
  1791.  
  1792.         object CanBank (BasePlayer player)
  1793.         {
  1794.             return CanDo ("bank", player);
  1795.         }
  1796.  
  1797.         object CanTrade (BasePlayer player)
  1798.         {
  1799.             return CanDo ("trade", player);
  1800.         }
  1801.  
  1802.         object canRemove (BasePlayer player)
  1803.         {
  1804.             return CanDo ("remove", player);
  1805.         }
  1806.  
  1807.         object canShop (BasePlayer player)
  1808.         {
  1809.             return CanDo ("shop", player);
  1810.         }
  1811.  
  1812.         object CanShop (BasePlayer player)
  1813.         {
  1814.             return CanDo ("shop", player);
  1815.         }
  1816.  
  1817.         object CanTeleport (BasePlayer player)
  1818.         {
  1819.             return CanDo ("tp", player);
  1820.         }
  1821.  
  1822.         object canTeleport (BasePlayer player) // ALIAS FOR MagicTeleportation
  1823.         {
  1824.             return CanTeleport (player);
  1825.         }
  1826.  
  1827.         object CanGridTeleport (BasePlayer player) // ALIAS FOR GrTeleport
  1828.         {
  1829.             return CanTeleport (player);
  1830.         }
  1831.  
  1832.         object CanCraft (ItemCrafter itemCrafter, ItemBlueprint bp, int amount)
  1833.         {
  1834.             BasePlayer player = itemCrafter.containers [0].GetOwnerPlayer ();
  1835.  
  1836.             if (player != null) {
  1837.                 var result = CanDo ("craft", player);
  1838.                 if (result is string) {
  1839.                     SendReply (player, result.ToString ());
  1840.                     return false;
  1841.                 }
  1842.             }
  1843.  
  1844.             return null;
  1845.         }
  1846.  
  1847.         object CanRecycleCommand (BasePlayer player)
  1848.         {
  1849.             return CanDo ("recycle", player);
  1850.         }
  1851.  
  1852.         object CanBGrade (BasePlayer player, int grade, BuildingBlock buildingBlock, Planner planner)
  1853.         {
  1854.             if (CanRaidCommand (player, "bgrade") || CanCombatCommand (player, "bgrade"))
  1855.                 return -1;
  1856.             return null;
  1857.         }
  1858.  
  1859.         #endregion
  1860.  
  1861.         #region Messages
  1862.  
  1863.         void SendBlockMessage (BasePlayer target, BlockBehavior blocker, string langMessage, string completeMessage)
  1864.         {
  1865.             var send = false;
  1866.             if (blocker.lastNotification != DateTime.MinValue) {
  1867.                 TimeSpan diff = DateTime.Now - blocker.lastNotification;
  1868.                 if (diff.TotalSeconds >= (blocker.Duration / 2))
  1869.                     send = true;
  1870.             } else
  1871.                 send = true;
  1872.  
  1873.             if (send) {
  1874.                 string message = string.Empty;
  1875.  
  1876.                 if (sendChatNotification || sendGUIAnnouncementsNotification)
  1877.                     message = GetPrefix (target.UserIDString) + GetMsg (langMessage, target.UserIDString).Replace ("{time}", GetCooldownTime (blocker.Duration, target.UserIDString));
  1878.  
  1879.                 if (sendChatNotification)
  1880.                     SendReply (target, message);
  1881.  
  1882.                 if (sendGUIAnnouncementsNotification)
  1883.                     GUIAnnouncements?.Call ("CreateAnnouncement", message, GUIAnnouncementTintColor, GUIAnnouncementTextColor, target);
  1884.  
  1885.                 if (sendLustyMapNotification && LustyMapDuration > 0) {
  1886.                     blocker.iconUID = Guid.NewGuid ().ToString ("N");
  1887.                     var obj = LustyMap?.Call ("AddMarker", target.transform.position.x, target.transform.position.z, blocker.iconUID, LustyMapIcon);
  1888.                     if (obj is bool && (bool)obj == true) {
  1889.                         timer.In (LustyMapDuration, delegate () {
  1890.                             LustyMap?.Call ("RemoveMarker", blocker.iconUID);
  1891.                         });
  1892.                     }
  1893.                 }
  1894.  
  1895.                 blocker.lastNotification = DateTime.Now;
  1896.             }
  1897.  
  1898.             blocker.Notify (delegate () {
  1899.                 blocker.notifyCallback = null;
  1900.                 if (target?.IsConnected == true) {
  1901.                     string message = string.Empty;
  1902.  
  1903.                     if (sendChatNotification || sendGUIAnnouncementsNotification)
  1904.                         message = GetPrefix (target.UserIDString) + GetMsg (completeMessage, target.UserIDString);
  1905.  
  1906.                     if (sendChatNotification)
  1907.                         SendReply (target, message);
  1908.  
  1909.                     if (sendGUIAnnouncementsNotification)
  1910.                         GUIAnnouncements?.Call ("CreateAnnouncement", message, GUIAnnouncementTintColor, GUIAnnouncementTextColor, target);
  1911.  
  1912.                     if (sendLustyMapNotification && LustyMapDuration > 0)
  1913.                         LustyMap?.Call ("RemoveMarker", blocker.iconUID);
  1914.                 }
  1915.             });
  1916.         }
  1917.  
  1918.         string GetCooldownTime (float f, string userID)
  1919.         {
  1920.             if (f > 60)
  1921.                 return Math.Round (f / 60, 1) + " " + GetMsg ("Unit Minutes", userID);
  1922.  
  1923.             return f + " " + GetMsg ("Unit Seconds", userID);
  1924.         }
  1925.  
  1926.         public string GetMessage (BasePlayer player)
  1927.         {
  1928.             if (IsRaidBlocked (player))
  1929.                 return GetMessage<RaidBlock> (player, "Raid Blocked Message", raidDuration);
  1930.             else if (IsCombatBlocked (player))
  1931.                 return GetMessage<CombatBlock> (player, "Combat Blocked Message", combatDuration);
  1932.  
  1933.             return null;
  1934.         }
  1935.  
  1936.         public string GetPrefix (string player)
  1937.         {
  1938.             string prefix = GetMsg ("Prefix", player);
  1939.             if (!string.IsNullOrEmpty (prefix)) {
  1940.                 return prefix + ": ";
  1941.             }
  1942.  
  1943.             return string.Empty;
  1944.         }
  1945.  
  1946.         public string GetMessage<T> (BasePlayer player, string blockMsg, float duration) where T : BlockBehavior
  1947.         {
  1948.             T blocker;
  1949.             if (duration > 0 && TryGetBlocker<T> (player, out blocker)) {
  1950.                 var ts = DateTime.Now - blocker.lastBlock;
  1951.                 var unblocked = Math.Round ((duration / 60) - Convert.ToSingle (ts.TotalMinutes), 2);
  1952.  
  1953.                 if (ts.TotalMinutes <= duration) {
  1954.                     if (unblocked < 1) {
  1955.                         var timelefts = Math.Round (Convert.ToDouble (duration) - ts.TotalSeconds);
  1956.                         return GetPrefix (player.UserIDString) + GetMsg (blockMsg, player).Replace ("{time}", timelefts.ToString () + " " + GetMsg ("Unit Seconds", player));
  1957.                     }
  1958.  
  1959.                     return GetPrefix (player.UserIDString) + GetMsg (blockMsg, player).Replace ("{time}", unblocked.ToString () + " " + GetMsg ("Unit Minutes", player));
  1960.                 }
  1961.             }
  1962.  
  1963.             return null;
  1964.         }
  1965.  
  1966.         #endregion
  1967.  
  1968.         #region Utility Methods
  1969.  
  1970.         bool TryGetBlocker<T> (BasePlayer player, out T blocker) where T : BlockBehavior
  1971.         {
  1972.             blocker = null;
  1973.             if (player.gameObject == null)
  1974.                 return false;
  1975.             if ((blocker = player.gameObject.GetComponent<T> ()) != null)
  1976.                 return true;
  1977.  
  1978.             return false;
  1979.         }
  1980.  
  1981.         public bool isEntityException (string prefabName)
  1982.         {
  1983.             var result = false;
  1984.  
  1985.             foreach (string p in exceptionPrefabs) {
  1986.                 if (prefabName.IndexOf (p) != -1) {
  1987.                     result = true;
  1988.                     break;
  1989.                 }
  1990.             }
  1991.  
  1992.             return result;
  1993.         }
  1994.  
  1995.         public bool IsEntityBlocked (BaseCombatEntity entity)
  1996.         {
  1997.             if (entity is BuildingBlock) {
  1998.                 if (((BuildingBlock)entity).grade == BuildingGrade.Enum.Twigs)
  1999.                     return false;
  2000.  
  2001.                 return true;
  2002.             }
  2003.  
  2004.             var prefabName = entity.ShortPrefabName;
  2005.             var result = false;
  2006.             if (prefabBlockCache.TryGetValue (prefabName, out result))
  2007.                 return result;
  2008.  
  2009.             result = false;
  2010.  
  2011.             foreach (string p in blockedPrefabs) {
  2012.                 if (prefabName.IndexOf (p) != -1) {
  2013.                     result = true;
  2014.                     break;
  2015.                 }
  2016.             }
  2017.  
  2018.  
  2019.             prefabBlockCache.Add (prefabName, result);
  2020.             return result;
  2021.         }
  2022.  
  2023.         bool IsRaidDamage (DamageType dt)
  2024.         {
  2025.             return raidDamageTypes.Contains (dt.ToString ());
  2026.         }
  2027.  
  2028.         bool IsDeathDamage (DamageType dt)
  2029.         {
  2030.             return raidDeathTypes.Contains (dt.ToString ());
  2031.         }
  2032.  
  2033.         bool IsRaidDamage (DamageTypeList dtList)
  2034.         {
  2035.             for (int index = 0; index < dtList.types.Length; ++index) {
  2036.                 if (dtList.types [index] > 0 && IsRaidDamage ((DamageType)index)) {
  2037.                     return true;
  2038.                 }
  2039.             }
  2040.  
  2041.             return false;
  2042.         }
  2043.  
  2044.         bool IsDeathDamage (DamageTypeList dtList)
  2045.         {
  2046.             for (int index = 0; index < dtList.types.Length; ++index) {
  2047.                 if (dtList.types [index] > 0 && IsDeathDamage ((DamageType)index)) {
  2048.                     return true;
  2049.                 }
  2050.             }
  2051.  
  2052.             return false;
  2053.         }
  2054.  
  2055.         bool IsExcludedWeapon (string name)
  2056.         {
  2057.             if (string.IsNullOrEmpty (name)) {
  2058.                 return false;
  2059.             }
  2060.  
  2061.             bool cachedValue;
  2062.  
  2063.             if (_cachedExcludedWeapons.TryGetValue (name, out cachedValue)) {
  2064.                 return cachedValue;
  2065.             }
  2066.  
  2067.             foreach (var weaponName in exceptionWeapons) {
  2068.                 if (name.Contains (weaponName)) {
  2069.                     _cachedExcludedWeapons.Add (name, true);
  2070.                     return true;
  2071.                 }
  2072.             }
  2073.  
  2074.             _cachedExcludedWeapons.Add (name, false);
  2075.             return false;
  2076.         }
  2077.  
  2078.         bool IsCombatDamage (DamageType dt)
  2079.         {
  2080.             return combatDamageTypes.Contains (dt.ToString ());
  2081.         }
  2082.  
  2083.         bool IsCombatDamage (DamageTypeList dtList)
  2084.         {
  2085.             for (int index = 0; index < dtList.types.Length; ++index) {
  2086.                 if (IsCombatDamage ((DamageType)index)) {
  2087.                     return true;
  2088.                 }
  2089.             }
  2090.  
  2091.             return false;
  2092.         }
  2093.  
  2094.         T GetConfig<T> (string name, string name2, string name3, T defaultValue)
  2095.         {
  2096.             try {
  2097.                 var val = Config [name, name2, name3];
  2098.  
  2099.                 return ParseValue<T> (val, defaultValue);
  2100.             } catch (Exception ex) {
  2101.                 //PrintWarning ("Invalid config value: " + name + "/" + name2 + "/" + name3 + " (" + ex.Message + ")");
  2102.                 Config [name, name2, name3] = defaultValue;
  2103.                 Config.Save ();
  2104.                 return defaultValue;
  2105.             }
  2106.         }
  2107.  
  2108.         T GetConfig<T> (string name, string name2, T defaultValue)
  2109.         {
  2110.             try {
  2111.                 var val = Config [name, name2];
  2112.  
  2113.                 return ParseValue<T> (val, defaultValue);
  2114.             } catch (Exception ex) {
  2115.                 //PrintWarning ("Invalid config value: " + name + "/" + name2 + " (" + ex.Message + ")");
  2116.                 Config [name, name2] = defaultValue;
  2117.                 Config.Save ();
  2118.                 return defaultValue;
  2119.             }
  2120.         }
  2121.  
  2122.         T GetConfig<T> (string name, T defaultValue)
  2123.         {
  2124.             try {
  2125.                 var val = Config [name];
  2126.  
  2127.                 return ParseValue<T> (val, defaultValue);
  2128.             } catch (Exception ex) {
  2129.                 //PrintWarning ("Invalid config value: " + name + " (" + ex.Message + ")");
  2130.                 Config [name] = defaultValue;
  2131.                 Config.Save ();
  2132.                 return defaultValue;
  2133.             }
  2134.         }
  2135.  
  2136.         T ParseValue<T> (object val, T defaultValue)
  2137.         {
  2138.             if (val == null)
  2139.                 return defaultValue;
  2140.  
  2141.             if (val is List<object>) {
  2142.                 var t = typeof (T).GetGenericArguments () [0];
  2143.                 if (t == typeof (String)) {
  2144.                     var cval = new List<string> ();
  2145.                     foreach (var v in val as List<object>)
  2146.                         cval.Add ((string)v);
  2147.                     val = cval;
  2148.                 } else if (t == typeof (int)) {
  2149.                     var cval = new List<int> ();
  2150.                     foreach (var v in val as List<object>)
  2151.                         cval.Add (Convert.ToInt32 (v));
  2152.                     val = cval;
  2153.                 }
  2154.             } else if (val is Dictionary<string, object>) {
  2155.                 var t = typeof (T).GetGenericArguments () [1];
  2156.                 if (t == typeof (int)) {
  2157.                     var cval = new Dictionary<string, int> ();
  2158.                     foreach (var v in val as Dictionary<string, object>)
  2159.                         cval.Add (Convert.ToString (v.Key), Convert.ToInt32 (v.Value));
  2160.                     val = cval;
  2161.                 }
  2162.             }
  2163.  
  2164.             return (T)Convert.ChangeType (val, typeof (T));
  2165.         }
  2166.  
  2167.         static string GetMsg (string key, object user = null)
  2168.         {
  2169.             if (user is BasePlayer) {
  2170.                 user = ((BasePlayer)user).UserIDString;
  2171.             }
  2172.             return plugin.lang.GetMessage (key, plugin, user == null ? null : user.ToString ());
  2173.         }
  2174.  
  2175.         #endregion
  2176.     }
  2177. }
Advertisement
Add Comment
Please, Sign In to add comment