FuelStream

NoEscape 2.1.34

Sep 2nd, 2021
1,642
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 76.15 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.34")]
  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 (!blockOnDamage)
  504.                 Unsubscribe ("OnEntityTakeDamage");
  505.  
  506.             if (!blockTypes.Contains ("repair"))
  507.                 Unsubscribe ("OnStructureRepair");
  508.  
  509.             if (!blockTypes.Contains ("upgrade"))
  510.                 Unsubscribe ("OnStructureUpgrade");
  511.  
  512.             if (!blockTypes.Contains ("mailbox"))
  513.                 Unsubscribe ("CanUseMailbox");
  514.  
  515.             if (!blockTypes.Contains ("vend"))
  516.                 Unsubscribe ("CanUseVending");
  517.  
  518.             if (!blockTypes.Contains ("build"))
  519.                 Unsubscribe ("CanBuild");
  520.  
  521.             if (!blockTypes.Contains ("assignbed"))
  522.                 Unsubscribe ("CanAssignBed");
  523.  
  524.             if (!blockTypes.Contains ("craft"))
  525.                 Unsubscribe ("CanCraft");
  526.                
  527.             if (!blockTypes.Contains ("backpack"))
  528.                 Unsubscribe ("CanOpenBackpack");
  529.                
  530.             if(!useZoneManager)
  531.             {
  532.                 Unsubscribe ("OnEnterZone");
  533.                 Unsubscribe ("OnExitZone");
  534.             }
  535.            
  536.             if(!useRaidableBases)
  537.             {
  538.                 Unsubscribe ("OnPlayerEnteredRaidableBase");
  539.                 Unsubscribe ("OnPlayerExitedRaidableBase");
  540.             }
  541.         }
  542.  
  543.         #endregion
  544.  
  545.         #region Classes
  546.  
  547.         public class RaidZone
  548.         {
  549.             public string zoneid;
  550.             public Vector3 position;
  551.             public Timer timer;
  552.  
  553.             public RaidZone (string zoneid, Vector3 position)
  554.             {
  555.                 this.zoneid = zoneid;
  556.                 this.position = position;
  557.             }
  558.  
  559.             public float Distance (RaidZone zone)
  560.             {
  561.                 return Vector3.Distance (position, zone.position);
  562.             }
  563.  
  564.             public float Distance (Vector3 pos)
  565.             {
  566.                 return Vector3.Distance (position, pos);
  567.             }
  568.  
  569.             public RaidZone ResetTimer ()
  570.             {
  571.                 if (timer is Timer && !timer.Destroyed)
  572.                     timer.Destroy ();
  573.  
  574.                 return this;
  575.             }
  576.         }
  577.  
  578.         public abstract class BlockBehavior : MonoBehaviour
  579.         {
  580.             protected BasePlayer player;
  581.             public DateTime lastBlock = DateTime.MinValue;
  582.             public DateTime lastNotification = DateTime.MinValue;
  583.             internal DateTime lastUINotification = DateTime.MinValue;
  584.             internal Timer timer;
  585.             internal Action notifyCallback;
  586.             internal string iconUID;
  587.             internal bool moved;
  588.  
  589.             public void CopyFrom (BlockBehavior behavior)
  590.             {
  591.                 lastBlock = behavior.lastBlock;
  592.                 lastNotification = behavior.lastNotification;
  593.                 lastUINotification = behavior.lastUINotification;
  594.                 timer = behavior.timer;
  595.                 notifyCallback = behavior.notifyCallback;
  596.                 iconUID = behavior.iconUID;
  597.                 NotificationWindow = behavior.NotificationWindow;
  598.             }
  599.  
  600.             internal abstract float Duration { get; }
  601.  
  602.             internal abstract CuiRectTransformComponent NotificationWindow { get; set; }
  603.  
  604.             internal abstract string notifyMessage { get; }
  605.  
  606.             internal string BlockName {
  607.                 get {
  608.                     return GetType ().Name;
  609.                 }
  610.             }
  611.  
  612.             public bool Active {
  613.                 get {
  614.                     if (lastBlock > DateTime.MinValue) {
  615.                         TimeSpan ts = DateTime.Now - lastBlock;
  616.                         if (ts.TotalSeconds < Duration) {
  617.                             return true;
  618.                         }
  619.                     }
  620.  
  621.                     GameObject.Destroy (this);
  622.  
  623.                     return false;
  624.                 }
  625.             }
  626.  
  627.             void Awake ()
  628.             {
  629.                 player = GetComponent<BasePlayer> ();
  630.                 if (plugin.blockBehaviors.ContainsKey (player.userID)) {
  631.                     plugin.blockBehaviors.Remove (player.userID);
  632.                 }
  633.                 plugin.blockBehaviors.Add (player.userID, this);
  634.             }
  635.  
  636.             void Destroy ()
  637.             {
  638.                 if (!moved) {
  639.                     Stop ();
  640.                 }
  641.                 CancelInvoke ("Update");
  642.             }
  643.  
  644.             void Update ()
  645.             {
  646.                 if (!plugin.sendUINotification)
  647.                     return;
  648.                 bool send = false;
  649.                 if (lastUINotification == DateTime.MinValue) {
  650.                     lastUINotification = DateTime.Now;
  651.                     send = true;
  652.                 } else {
  653.                     TimeSpan ts = DateTime.Now - lastUINotification;
  654.                     if (ts.TotalSeconds > 2) {
  655.                         send = true;
  656.                     } else {
  657.                         send = false;
  658.                     }
  659.                 }
  660.  
  661.                 if (player is BasePlayer && player.IsConnected) {
  662.                     if (!Active) {
  663.                         CuiHelper.DestroyUi (player, "BlockMsg" + BlockName);
  664.                     }
  665.  
  666.                     if (send && Active) {
  667.                         lastUINotification = DateTime.Now;
  668.                         SendGUI ();
  669.                     }
  670.                 }
  671.             }
  672.  
  673.             public void Stop ()
  674.             {
  675.                 if (notifyCallback is Action)
  676.                     notifyCallback.Invoke ();
  677.  
  678.                 if (timer is Timer && !timer.Destroyed)
  679.                     timer.Destroy ();
  680.  
  681.                 if (plugin.sendUINotification && player is BasePlayer && player.IsConnected)
  682.                     CuiHelper.DestroyUi (player, "BlockMsg" + BlockName);
  683.  
  684.                 plugin.blockBehaviors.Remove (player.userID);
  685.  
  686.                 GameObject.Destroy (this);
  687.             }
  688.  
  689.             public void Notify (Action callback)
  690.             {
  691.                 if (plugin.sendUINotification)
  692.                     SendGUI ();
  693.  
  694.                 notifyCallback = callback;
  695.                 if (timer is Timer && !timer.Destroyed)
  696.                     timer.Destroy ();
  697.  
  698.                 timer = plugin.timer.In (Duration, callback);
  699.             }
  700.  
  701.             private string FormatTime (TimeSpan ts)
  702.             {
  703.                 if (ts.Days > 0)
  704.                     return string.Format ("{0}D, {1}H", ts.Days, ts.Hours);
  705.  
  706.                 if (ts.Hours > 0)
  707.                     return string.Format ("{0}H {1}M", ts.Hours, ts.Minutes);
  708.  
  709.                 return string.Format ("{0}M {1}S", ts.Minutes, ts.Seconds);
  710.             }
  711.  
  712.             void SendGUI ()
  713.             {
  714.                 TimeSpan ts = lastBlock.AddSeconds (Duration) - DateTime.Now;
  715.  
  716.                 string countDown = FormatTime (ts);
  717.                 CuiHelper.DestroyUi (player, "BlockMsg" + BlockName);
  718.                 var elements = new CuiElementContainer ();
  719.                 var BlockMsg = elements.Add (new CuiPanel {
  720.                     Image =
  721.                         {
  722.                             Color = "0.95 0 0.02 0.67"
  723.                         },
  724.                     RectTransform =
  725.                         {
  726.                             AnchorMax = NotificationWindow.AnchorMax,
  727.                             AnchorMin = NotificationWindow.AnchorMin
  728.                         }
  729.                 }, "Hud", "BlockMsg" + BlockName);
  730.                 elements.Add (new CuiElement {
  731.                     Parent = BlockMsg,
  732.                     Components =
  733.                         {
  734.                             new CuiRawImageComponent
  735.                             {
  736.                                 Sprite = "assets/icons/explosion.png",
  737.                                 Color = "0.95 0 0.02 0.67"
  738.                             },
  739.                             new CuiRectTransformComponent
  740.                             {
  741.                                 AnchorMin = "0 0",
  742.                                 AnchorMax = "0.13 1"
  743.                             }
  744.                         }
  745.                 });
  746.                 elements.Add (new CuiLabel {
  747.                     RectTransform =
  748.                         {
  749.                             AnchorMin = "0.15 0",
  750.                             AnchorMax = "0.82 1"
  751.                         },
  752.                     Text =
  753.                         {
  754.                             Text = notifyMessage,
  755.                             FontSize = 11,
  756.                             Align = TextAnchor.MiddleLeft,
  757.                         }
  758.                 }, BlockMsg);
  759.                 elements.Add (new CuiElement {
  760.                     Name = "TimerPanel",
  761.                     Parent = BlockMsg,
  762.                     Components =
  763.                         {
  764.                             new CuiImageComponent
  765.                             {
  766.                                 Color = "0 0 0 0.64",
  767.                                 ImageType = UnityEngine.UI.Image.Type.Filled
  768.                             },
  769.                             new CuiRectTransformComponent
  770.                             {
  771.                                 AnchorMin = "0.73 0",
  772.                                 AnchorMax = "1 1"
  773.                             }
  774.                         }
  775.                 });
  776.                 elements.Add (new CuiLabel {
  777.                     RectTransform =
  778.                         {
  779.                             AnchorMin = "0 0",
  780.                             AnchorMax = "1 1"
  781.                         },
  782.                     Text =
  783.                         {
  784.                             Text = countDown,
  785.                             FontSize = 12,
  786.                             Align = TextAnchor.MiddleCenter,
  787.                         }
  788.                 }, "TimerPanel");
  789.                 CuiHelper.AddUi (player, elements);
  790.             }
  791.  
  792.  
  793.         }
  794.  
  795.         public class CombatBlock : BlockBehavior
  796.         {
  797.             internal override float Duration {
  798.                 get {
  799.                     return combatDuration;
  800.                 }
  801.             }
  802.  
  803.             internal override string notifyMessage {
  804.                 get { return GetMsg ("Combat Block UI Message", player); }
  805.             }
  806.  
  807.             CuiRectTransformComponent _notificationWindow = null;
  808.  
  809.             internal override CuiRectTransformComponent NotificationWindow {
  810.                 get {
  811.                     if (_notificationWindow != null) {
  812.                         return _notificationWindow;
  813.                     }
  814.                     return _notificationWindow = new CuiRectTransformComponent () {
  815.                         AnchorMin = "0.44 0.15",
  816.                         AnchorMax = "0.56 0.18"
  817.                     };
  818.                 }
  819.                 set {
  820.                     _notificationWindow = value;
  821.                 }
  822.             }
  823.         }
  824.  
  825.         public class RaidBlock : BlockBehavior
  826.         {
  827.             internal override float Duration {
  828.                 get {
  829.                     return raidDuration;
  830.                 }
  831.             }
  832.  
  833.             internal override string notifyMessage {
  834.                 get { return GetMsg ("Raid Block UI Message", player); }
  835.             }
  836.  
  837.             private CuiRectTransformComponent _notificationWindow = null;
  838.  
  839.             internal override CuiRectTransformComponent NotificationWindow {
  840.                 get {
  841.                     if (_notificationWindow != null) {
  842.                         return _notificationWindow;
  843.                     }
  844.                     return _notificationWindow = new CuiRectTransformComponent () {
  845.                         AnchorMin = "0.87 0.39",
  846.                         AnchorMax = "0.99 0.42"
  847.                     };
  848.                 }
  849.                 set {
  850.                     _notificationWindow = value;
  851.                 }
  852.             }
  853.         }
  854.  
  855.         #endregion
  856.  
  857.         #region Oxide Hooks
  858.  
  859.         void OnEntityTakeDamage (BaseCombatEntity entity, HitInfo hitInfo)
  860.         {
  861.             if (!blockOnDamage || !raidBlock)
  862.                 return;
  863.             if (hitInfo == null || hitInfo.Initiator == null || !IsEntityBlocked (entity) || hitInfo.Initiator.transform == null)
  864.                 return;
  865.             if (!IsRaidDamage (hitInfo.damageTypes))
  866.                 return;
  867.             if (IsExcludedWeapon (hitInfo?.WeaponPrefab?.ShortPrefabName))
  868.                 return;
  869.  
  870.             if (GetHealthPercent (entity, hitInfo.damageTypes.Total ()) > blockOnDamageMinCondition) {
  871.                 return;
  872.             }
  873.  
  874.             StructureAttack (entity, hitInfo.Initiator, hitInfo?.WeaponPrefab?.ShortPrefabName, hitInfo.HitPositionWorld);
  875.         }
  876.  
  877.         void OnPlayerConnected (BasePlayer player)
  878.         {
  879.             BlockBehavior behavior;
  880.             if (blockBehaviors.TryGetValue (player.userID, out behavior)) {
  881.                 if (behavior is RaidBlock) {
  882.                     var raidBlockComponent = player.gameObject.AddComponent<RaidBlock> ();
  883.                     raidBlockComponent.CopyFrom (behavior);
  884.                 } else if (behavior is CombatBlock) {
  885.                     var combatBlockComponent = player.gameObject.AddComponent<CombatBlock> ();
  886.                     combatBlockComponent.CopyFrom (behavior);
  887.                 }
  888.  
  889.                 behavior.moved = true;
  890.                 GameObject.Destroy (behavior);
  891.             }
  892.         }
  893.  
  894.         void OnPlayerAttack (BasePlayer attacker, HitInfo hitInfo)
  895.         {
  896.             if (!combatBlock || !(hitInfo.HitEntity is BasePlayer))
  897.                 return;
  898.             if (!combatOnHitNPC && hitInfo.HitEntity.IsNpc)
  899.                 return;
  900.             if (!combatOnTakeDamageNPC && attacker.IsNpc) {
  901.                 return;
  902.             }
  903.             if (!IsCombatDamage (hitInfo.damageTypes))
  904.                 return;
  905.  
  906.             float totalDamage = hitInfo.damageTypes.Total ();
  907.             BasePlayer target = hitInfo.HitEntity as BasePlayer;
  908.  
  909.             if (combatOnTakeDamage) {
  910.                 if (GetHealthPercent (target, hitInfo.damageTypes.Total ()) > combatOnTakeDamageMinCondition) {
  911.                     return;
  912.                 }
  913.  
  914.                 if (totalDamage < combatOnTakeDamageMinDamage) {
  915.                     return;
  916.                 }
  917.  
  918.  
  919.                 StartCombatBlocking (target);
  920.             }
  921.  
  922.             if (combatOnHitPlayer) {
  923.                 if (GetHealthPercent (attacker, hitInfo.damageTypes.Total ()) > combatOnHitPlayerMinCondition) {
  924.                     return;
  925.                 }
  926.  
  927.                 if (totalDamage < combatOnHitPlayerMinDamage) {
  928.                     return;
  929.                 }
  930.  
  931.                 StartCombatBlocking (attacker);
  932.             }
  933.         }
  934.  
  935.         void OnEntityDeath (BaseCombatEntity entity, HitInfo hitInfo)
  936.         {
  937.             if (blockOnDestroy && raidBlock) {
  938.                 if (hitInfo == null || hitInfo.Initiator == null || !IsDeathDamage (hitInfo.damageTypes) || !IsEntityBlocked (entity))
  939.                     return;
  940.  
  941.                 StructureAttack (entity, hitInfo.Initiator, hitInfo?.WeaponPrefab?.ShortPrefabName, hitInfo.HitPositionWorld);
  942.             }
  943.  
  944.             if (entity.ToPlayer () == null)
  945.                 return;
  946.  
  947.             var player = entity.ToPlayer ();
  948.             RaidBlock raidBlocker;
  949.             if (raidBlock && raidUnblockOnDeath && TryGetBlocker (player, out raidBlocker)) {
  950.                 timer.In (0.3f, delegate () {
  951.                     raidBlocker.Stop ();
  952.                 });
  953.             }
  954.  
  955.             CombatBlock combatBlocker;
  956.             if (combatBlock && combatUnblockOnDeath && TryGetBlocker (player, out combatBlocker)) {
  957.                 timer.In (0.3f, delegate () {
  958.                     combatBlocker.Stop ();
  959.                 });
  960.             }
  961.         }
  962.  
  963.         void OnPlayerSleepEnded (BasePlayer player)
  964.         {
  965.             if (player == null) return;
  966.             RaidBlock raidBlocker;
  967.             if (raidBlock && raidUnblockOnWakeup && TryGetBlocker (player, out raidBlocker)) {
  968.                 timer.In (0.3f, delegate () {
  969.                     raidBlocker.Stop ();
  970.                 });
  971.             }
  972.  
  973.             CombatBlock combatBlocker;
  974.             if (combatBlock && combatUnblockOnWakeup && TryGetBlocker (player, out combatBlocker)) {
  975.                 timer.In (0.3f, delegate () {
  976.                     combatBlocker.Stop ();
  977.                 });
  978.             }
  979.         }
  980.  
  981.         void OnPlayerRespawned (BasePlayer player)
  982.         {
  983.             if (player == null) return;
  984.             RaidBlock raidBlocker;
  985.             if (raidBlock && raidUnblockOnRespawn && TryGetBlocker (player, out raidBlocker)) {
  986.                 timer.In (0.3f, delegate () {
  987.                     raidBlocker.Stop ();
  988.                 });
  989.             }
  990.  
  991.             CombatBlock combatBlocker;
  992.             if (combatBlock && combatUnblockOnRespawn && TryGetBlocker (player, out combatBlocker)) {
  993.                 timer.In (0.3f, delegate () {
  994.                     combatBlocker.Stop ();
  995.                 });
  996.             }
  997.         }
  998.  
  999.         object CanLootEntity(BasePlayer player, StorageContainer container)
  1000.         {
  1001.             if(container?.GetEntity() is Recycler)
  1002.             {
  1003.                 object reply = CanDo("recycle", player);
  1004.  
  1005.                 if (reply != null && IsBlocked(player))
  1006.                 {
  1007.                     player.ChatMessage((string)reply);
  1008.                     return true;
  1009.                 }
  1010.             }
  1011.  
  1012.             return null;
  1013.         }
  1014.  
  1015.         #endregion
  1016.  
  1017.         #region Block Handling
  1018.  
  1019.         void StructureAttack (BaseEntity targetEntity, BaseEntity sourceEntity, string weapon, Vector3 hitPosition)
  1020.         {
  1021.             BasePlayer source = null;
  1022.  
  1023.             if (sourceEntity.ToPlayer () is BasePlayer)
  1024.                 source = sourceEntity.ToPlayer ();
  1025.             else {
  1026.                 ulong ownerID = sourceEntity.OwnerID;
  1027.                 if (ownerID.IsSteamId ())
  1028.                     source = BasePlayer.FindByID (ownerID);
  1029.                 else
  1030.                     return;
  1031.             }
  1032.  
  1033.             if (source == null)
  1034.                 return;
  1035.  
  1036.             List<string> sourceMembers = null;
  1037.  
  1038.             if (targetEntity.OwnerID.IsSteamId () || (blockUnowned && !targetEntity.OwnerID.IsSteamId ())) {
  1039.                 if (clanCheck || friendCheck)
  1040.                     sourceMembers = getFriends (source.UserIDString);
  1041.  
  1042.                 if (blockAll) {
  1043.                     BlockAll (source, targetEntity, sourceMembers);
  1044.                 } else {
  1045.                     if (ownerBlock)
  1046.                         OwnerBlock (source, sourceEntity, targetEntity.OwnerID, targetEntity.transform.position, sourceMembers);
  1047.  
  1048.                     if (raiderBlock)
  1049.                         RaiderBlock (source, targetEntity.OwnerID, targetEntity.transform.position, sourceMembers);
  1050.                 }
  1051.             }
  1052.         }
  1053.  
  1054.         float GetHealthPercent (BaseEntity entity, float damage = 0f)
  1055.         {
  1056.             return (entity.Health () - damage) * 100f / entity.MaxHealth ();
  1057.         }
  1058.  
  1059.         void BlockAll (BasePlayer source, BaseEntity targetEntity, List<string> sourceMembers = null)
  1060.         {
  1061.             if (ShouldBlockEscape (targetEntity.OwnerID, source.userID, sourceMembers)) {
  1062.                 StartRaidBlocking (source, targetEntity.transform.position);
  1063.             }
  1064.  
  1065.             var checkSourceMembers = false;
  1066.             if (targetEntity.OwnerID == source.userID || (sourceMembers is List<string> && sourceMembers.Contains (targetEntity.OwnerID.ToString ()))) {
  1067.                 checkSourceMembers = true;
  1068.             }
  1069.  
  1070.             var nearbyTargets = Pool.GetList<BasePlayer> ();
  1071.             Vis.Entities (targetEntity.transform.position, raidDistance, nearbyTargets, blockLayer);
  1072.             if (nearbyTargets.Count > 0) {
  1073.                 RaidBlock blocker;
  1074.                 foreach (BasePlayer nearbyTarget in nearbyTargets) {
  1075.                     if (nearbyTarget.IsNpc) continue;
  1076.                     if (nearbyTarget.userID == source.userID) continue;
  1077.                     if (TryGetBlocker (nearbyTarget, out blocker) && blocker.Active) {
  1078.                         StartRaidBlocking (nearbyTarget, targetEntity.transform.position);
  1079.                     } else if (ShouldBlockEscape (nearbyTarget.userID, source.userID, checkSourceMembers ? sourceMembers : null)) {
  1080.                         StartRaidBlocking (nearbyTarget, targetEntity.transform.position);
  1081.                     }
  1082.                 }
  1083.             }
  1084.  
  1085.             Pool.FreeList (ref nearbyTargets);
  1086.         }
  1087.  
  1088.         void OwnerBlock (BasePlayer source, BaseEntity sourceEntity, ulong target, Vector3 position, List<string> sourceMembers = null)
  1089.         {
  1090.             if (!ShouldBlockEscape (target, source.userID, sourceMembers))
  1091.                 return;
  1092.  
  1093.             var targetMembers = new List<string> ();
  1094.  
  1095.             if (clanShare || friendShare)
  1096.                 targetMembers = getFriends (target.ToString ());
  1097.  
  1098.             var nearbyTargets = Pool.GetList<BasePlayer> ();
  1099.             Vis.Entities (position, raidDistance, nearbyTargets, blockLayer);
  1100.             if (cupboardShare)
  1101.                 sourceMembers = CupboardShare (target.ToString (), position, sourceEntity, sourceMembers);
  1102.  
  1103.             if (nearbyTargets.Count > 0) {
  1104.                 foreach (BasePlayer nearbyTarget in nearbyTargets) {
  1105.                     if (nearbyTarget.IsNpc) continue;
  1106.                     if (nearbyTarget.userID == target || (targetMembers != null && targetMembers.Contains (nearbyTarget.UserIDString)))
  1107.                         StartRaidBlocking (nearbyTarget, position);
  1108.                 }
  1109.             }
  1110.  
  1111.             Pool.FreeList (ref nearbyTargets);
  1112.         }
  1113.  
  1114.         List<string> CupboardShare (string owner, Vector3 position, BaseEntity sourceEntity, List<string> sourceMembers = null)
  1115.         {
  1116.             var nearbyCupboards = Pool.GetList<BuildingPrivlidge> ();
  1117.             Vis.Entities (position, raidDistance, nearbyCupboards, cupboardMask);
  1118.             if (sourceMembers == null)
  1119.                 sourceMembers = new List<string> ();
  1120.  
  1121.             List<string> cupboardMembers = new List<string> ();
  1122.  
  1123.             var sourcePlayer = sourceEntity as BasePlayer;
  1124.  
  1125.             if (sourcePlayer != null) {
  1126.                 foreach (var cup in nearbyCupboards) {
  1127.                     if (cup.IsAuthed (sourcePlayer)) {
  1128.                         bool ownerOrFriend = false;
  1129.  
  1130.                         if (owner == cup.OwnerID.ToString ())
  1131.                             ownerOrFriend = true;
  1132.  
  1133.                         foreach (var member in sourceMembers) {
  1134.                             if (member == cup.OwnerID.ToString ())
  1135.                                 ownerOrFriend = true;
  1136.                         }
  1137.  
  1138.                         if (ownerOrFriend)
  1139.                             foreach (var proto in cup.authorizedPlayers)
  1140.                                 if (!sourceMembers.Contains (proto.userid.ToString ()))
  1141.                                     cupboardMembers.Add (proto.userid.ToString ());
  1142.                     }
  1143.                 }
  1144.             }
  1145.  
  1146.             sourceMembers.AddRange (cupboardMembers);
  1147.             Pool.FreeList (ref nearbyCupboards);
  1148.  
  1149.             return sourceMembers;
  1150.         }
  1151.  
  1152.         void RaiderBlock (BasePlayer source, ulong target, Vector3 position, List<string> sourceMembers = null)
  1153.         {
  1154.             if (!ShouldBlockEscape (target, source.userID, sourceMembers))
  1155.                 return;
  1156.  
  1157.             var targetMembers = new List<string> ();
  1158.  
  1159.             if ((clanShare || friendShare) && sourceMembers == null)
  1160.                 sourceMembers = getFriends (source.UserIDString);
  1161.  
  1162.             var nearbyTargets = Pool.GetList<BasePlayer> ();
  1163.             Vis.Entities (position, raidDistance, nearbyTargets, blockLayer);
  1164.             if (nearbyTargets.Count > 0) {
  1165.                 foreach (BasePlayer nearbyTarget in nearbyTargets) {
  1166.                     if (nearbyTarget.IsNpc) continue;
  1167.                     if (nearbyTarget == source || (sourceMembers != null && sourceMembers.Contains (nearbyTarget.UserIDString)))
  1168.                         StartRaidBlocking (nearbyTarget, position);
  1169.                 }
  1170.             }
  1171.  
  1172.             Pool.FreeList (ref nearbyTargets);
  1173.         }
  1174.  
  1175.         #endregion
  1176.  
  1177.         #region API
  1178.  
  1179.         bool IsBlocked (string target)
  1180.         {
  1181.             var player = BasePlayer.Find (target);
  1182.             if (player is BasePlayer) {
  1183.                 return IsBlocked (player);
  1184.             }
  1185.  
  1186.             return false;
  1187.         }
  1188.  
  1189.         bool IsBlocked (BasePlayer target)
  1190.         {
  1191.             if (IsBlocked<RaidBlock> (target) || IsBlocked<CombatBlock> (target))
  1192.                 return true;
  1193.  
  1194.             return false;
  1195.         }
  1196.  
  1197.         public bool IsBlocked<T> (BasePlayer target) where T : BlockBehavior
  1198.         {
  1199.             T behavior;
  1200.             if (TryGetBlocker<T> (target, out behavior) && behavior.Active)
  1201.                 return true;
  1202.  
  1203.             return false;
  1204.         }
  1205.  
  1206.         bool IsRaidBlocked (BasePlayer target)
  1207.         {
  1208.             return IsBlocked<RaidBlock> (target);
  1209.         }
  1210.  
  1211.         bool IsCombatBlocked (BasePlayer target)
  1212.         {
  1213.             return IsBlocked<CombatBlock> (target);
  1214.         }
  1215.  
  1216.         bool IsEscapeBlocked (string target)
  1217.         {
  1218.             var player = BasePlayer.Find (target);
  1219.             if (player is BasePlayer) {
  1220.                 return IsBlocked (player);
  1221.             }
  1222.  
  1223.             return false;
  1224.         }
  1225.  
  1226.         bool IsRaidBlocked (string target)
  1227.         {
  1228.             var player = BasePlayer.Find (target);
  1229.             if (player is BasePlayer) {
  1230.                 return IsBlocked<RaidBlock> (player);
  1231.             }
  1232.  
  1233.             return false;
  1234.         }
  1235.  
  1236.         bool IsCombatBlocked (string target)
  1237.         {
  1238.             var player = BasePlayer.Find (target);
  1239.             if (player is BasePlayer) {
  1240.                 return IsBlocked<CombatBlock> (player);
  1241.             }
  1242.  
  1243.             return false;
  1244.         }
  1245.  
  1246.         bool ShouldBlockEscape (ulong target, ulong source, List<string> sourceMembers = null)
  1247.         {
  1248.             if (target == source) {
  1249.                 if ((ownerBlock || raiderBlock || blockAll) && (!ownerCheck))
  1250.                     return true;
  1251.  
  1252.                 return false;
  1253.             }
  1254.  
  1255.             if (sourceMembers is List<string> && sourceMembers.Contains (target.ToString ()))
  1256.                 return false;
  1257.  
  1258.             return true;
  1259.         }
  1260.  
  1261.         //[ChatCommand ("bblocked")]
  1262.         //void cmdBBlocked (BasePlayer player, string command, string [] args)
  1263.         //{
  1264.         //    StartCombatBlocking (player);
  1265.         //    StartRaidBlocking (player);
  1266.         //}
  1267.  
  1268.         //[ChatCommand ("bunblocked")]
  1269.         //void cmdBUnblocked (BasePlayer player, string command, string [] args)
  1270.         //{
  1271.         //    StopCombatBlocking (player);
  1272.         //    StopRaidBlocking (player);
  1273.         //}
  1274.  
  1275.         void StartRaidBlocking (BasePlayer target, bool createZone = true)
  1276.         {
  1277.             StartRaidBlocking (target, target.transform.position, createZone);
  1278.         }
  1279.  
  1280.         void StartRaidBlocking (BasePlayer target, Vector3 position, bool createZone = true)
  1281.         {
  1282.             if (HasPerm (target.UserIDString, "disable")) {
  1283.                 return;
  1284.             }
  1285.  
  1286.             if (target.gameObject == null) {
  1287.                 return;
  1288.             }
  1289.  
  1290.             if (Interface.Call ("CanRaidBlock", target, position, createZone) != null) {
  1291.                 return;
  1292.             }
  1293.  
  1294.             if (target.gameObject == null)
  1295.                 return;
  1296.             var raidBlocker = target.gameObject.GetComponent<RaidBlock> ();
  1297.             if (raidBlocker == null) {
  1298.                 raidBlocker = target.gameObject.AddComponent<RaidBlock> ();
  1299.             }
  1300.  
  1301.             Interface.CallHook ("OnRaidBlock", target, position);
  1302.  
  1303.             raidBlocker.lastBlock = DateTime.Now;
  1304.  
  1305.             if (raidBlockNotify)
  1306.                 SendBlockMessage (target, raidBlocker, "Raid Block Notifier", "Raid Block Complete");
  1307.  
  1308.             if (useZoneManager && createZone && (zoneEnter || zoneLeave))
  1309.                 CreateRaidZone (position);
  1310.         }
  1311.  
  1312.         void StartCombatBlocking (BasePlayer target)
  1313.         {
  1314.             if (HasPerm (target.UserIDString, "disable")) {
  1315.                 return;
  1316.             }
  1317.  
  1318.             if (target.gameObject == null) {
  1319.                 return;
  1320.             }
  1321.  
  1322.             if (Interface.Call ("CanCombatBlock", target) != null) {
  1323.                 return;
  1324.             }
  1325.  
  1326.             var combatBlocker = target.gameObject.GetComponent<CombatBlock> ();
  1327.             if (combatBlocker == null) {
  1328.                 combatBlocker = target.gameObject.AddComponent<CombatBlock> ();
  1329.             }
  1330.  
  1331.             Interface.CallHook ("OnCombatBlock", target);
  1332.  
  1333.             combatBlocker.lastBlock = DateTime.Now;
  1334.  
  1335.             if (combatBlockNotify)
  1336.                 SendBlockMessage (target, combatBlocker, "Combat Block Notifier", "Combat Block Complete");
  1337.         }
  1338.  
  1339.         void StopBlocking (BasePlayer target)
  1340.         {
  1341.             if (IsRaidBlocked (target))
  1342.                 StopBlocking<RaidBlock> (target);
  1343.             if (IsCombatBlocked (target))
  1344.                 StopBlocking<CombatBlock> (target);
  1345.         }
  1346.  
  1347.         public void StopBlocking<T> (BasePlayer target) where T : BlockBehavior
  1348.         {
  1349.             if (target.gameObject == null)
  1350.                 return;
  1351.             var block = target.gameObject.GetComponent<T> ();
  1352.             if (block is BlockBehavior)
  1353.                 block.Stop ();
  1354.  
  1355.             if (block is RaidBlock) {
  1356.                 Interface.CallHook ("OnRaidBlockStopped", target);
  1357.             } else if (block is CombatBlock) {
  1358.                 Interface.CallHook ("OnCombatBlockStopped", target);
  1359.             }
  1360.         }
  1361.  
  1362.         void ClearRaidBlockingS (string target)
  1363.         {
  1364.             StopRaidBlocking (target);
  1365.         }
  1366.  
  1367.         void StopRaidBlocking (BasePlayer player)
  1368.         {
  1369.             if (player is BasePlayer && IsRaidBlocked (player))
  1370.                 StopBlocking<RaidBlock> (player);
  1371.         }
  1372.  
  1373.         void StopRaidBlocking (string target)
  1374.         {
  1375.             var player = BasePlayer.Find (target);
  1376.             StopRaidBlocking (player);
  1377.         }
  1378.  
  1379.         void StopCombatBlocking (BasePlayer player)
  1380.         {
  1381.             if (player is BasePlayer && IsRaidBlocked (player))
  1382.                 StopBlocking<CombatBlock> (player);
  1383.         }
  1384.  
  1385.         void StopCombatBlocking (string target)
  1386.         {
  1387.             var player = BasePlayer.Find (target);
  1388.             StopCombatBlocking (player);
  1389.         }
  1390.  
  1391.         void ClearCombatBlocking (string target)
  1392.         {
  1393.             StopCombatBlocking (target);
  1394.         }
  1395.  
  1396.         #endregion
  1397.  
  1398.         #region Zone Handling
  1399.  
  1400.         void EraseZone (string zoneid)
  1401.         {
  1402.             ZoneManager.CallHook ("EraseZone", zoneid);
  1403.             zones.Remove (zoneid);
  1404.         }
  1405.  
  1406.         void ResetZoneTimer (RaidZone zone)
  1407.         {
  1408.             zone.ResetTimer ().timer = timer.In (raidDuration, delegate () {
  1409.                 EraseZone (zone.zoneid);
  1410.             });
  1411.         }
  1412.  
  1413.         void CreateRaidZone (Vector3 position)
  1414.         {
  1415.             var zoneid = position.ToString ();
  1416.  
  1417.             RaidZone zone;
  1418.             if (zones.TryGetValue (zoneid, out zone)) {
  1419.                 ResetZoneTimer (zone);
  1420.                 return;
  1421.             }
  1422.  
  1423.             foreach (var nearbyZone in zones) {
  1424.                 if (nearbyZone.Value.Distance (position) < (raidDistance / 2)) {
  1425.                     ResetZoneTimer (nearbyZone.Value);
  1426.                     return;
  1427.                 }
  1428.             }
  1429.  
  1430.             ZoneManager.CallHook ("CreateOrUpdateZone", zoneid, new string []
  1431.                 {
  1432.                     "radius",
  1433.                     raidDistance.ToString()
  1434.                 }, position);
  1435.  
  1436.             zones.Add (zoneid, zone = new RaidZone (zoneid, position));
  1437.  
  1438.             ResetZoneTimer (zone);
  1439.         }
  1440.  
  1441.         [HookMethod ("OnEnterZone")]
  1442.         void OnEnterZone (string zoneid, BasePlayer player)
  1443.         {
  1444.             if (!zoneEnter)
  1445.                 return;
  1446.             if (!zones.ContainsKey (zoneid))
  1447.                 return;
  1448.  
  1449.             StartRaidBlocking (player, player.transform.position, false);
  1450.         }
  1451.  
  1452.         [HookMethod ("OnExitZone")]
  1453.         void OnExitZone (string zoneid, BasePlayer player)
  1454.         {
  1455.             if (!zoneLeave)
  1456.                 return;
  1457.             if (!zones.ContainsKey (zoneid))
  1458.                 return;
  1459.  
  1460.             if (IsRaidBlocked (player)) {
  1461.                 StopBlocking<RaidBlock> (player);
  1462.             }
  1463.         }
  1464.        
  1465.         [HookMethod ("OnPlayerEnteredRaidableBase")]
  1466.         void OnPlayerEnteredRaidableBase(BasePlayer player, Vector3 raidPos, bool allowPVP)
  1467.         {
  1468.             if (!raidableZoneEnter)
  1469.                 return;
  1470.                
  1471.             StartRaidBlocking (player, false);
  1472.         }
  1473.        
  1474.         [HookMethod ("OnPlayerExitedRaidableBase")]
  1475.         void OnPlayerExitedRaidableBase(BasePlayer player, Vector3 raidPos, bool allowPVP)
  1476.         {
  1477.             if (!raidableZoneLeave)
  1478.                 return;
  1479.                
  1480.             if (IsRaidBlocked (player)) {
  1481.                 StopBlocking<RaidBlock> (player);
  1482.             }
  1483.         }
  1484.  
  1485.         #endregion
  1486.  
  1487.         #region Friend/Clan Integration
  1488.  
  1489.         public List<string> getFriends (string player)
  1490.         {
  1491.             var players = new List<string> ();
  1492.             if (player == null)
  1493.                 return players;
  1494.  
  1495.             if (friendShare || friendCheck) {
  1496.                 var friendList = getFriendList (player);
  1497.                 if (friendList != null)
  1498.                     players.AddRange (friendList);
  1499.             }
  1500.  
  1501.             if (clanShare || clanCheck) {
  1502.                 var members = getClanMembers (player);
  1503.                 if (members != null)
  1504.                     players.AddRange (members);
  1505.             }
  1506.             return players;
  1507.         }
  1508.  
  1509.         public List<string> getFriendList (string player)
  1510.         {
  1511.             object friends_obj = null;
  1512.             DateTime lastFriendCheckPlayer;
  1513.             var players = new List<string> ();
  1514.  
  1515.             if (lastFriendCheck.TryGetValue (player, out lastFriendCheckPlayer)) {
  1516.                 if ((DateTime.Now - lastFriendCheckPlayer).TotalMinutes <= cacheTimer && friendCache.TryGetValue (player, out players)) {
  1517.                     return players;
  1518.                 } else {
  1519.                     friends_obj = Friends?.CallHook ("IsFriendOfS", player);
  1520.                     lastFriendCheck [player] = DateTime.Now;
  1521.                 }
  1522.             } else {
  1523.                 friends_obj = Friends?.CallHook ("IsFriendOfS", player);
  1524.                 lastFriendCheck.Add (player, DateTime.Now);
  1525.             }
  1526.  
  1527.             if (friends_obj == null)
  1528.                 return players;
  1529.  
  1530.             string [] friends = friends_obj as string [];
  1531.  
  1532.             foreach (string fid in friends)
  1533.                 players.Add (fid);
  1534.  
  1535.             if (friendCache.ContainsKey (player))
  1536.                 friendCache [player] = players;
  1537.             else
  1538.                 friendCache.Add (player, players);
  1539.  
  1540.             return players;
  1541.         }
  1542.  
  1543.         public List<string> getClanMembers (string player)
  1544.         {
  1545.             string tag = null;
  1546.             DateTime lastClanCheckPlayer;
  1547.             string lastClanCached;
  1548.             if (lastClanCheck.TryGetValue (player, out lastClanCheckPlayer) && clanCache.TryGetValue (player, out lastClanCached)) {
  1549.                 if ((DateTime.Now - lastClanCheckPlayer).TotalMinutes <= cacheTimer)
  1550.                     tag = lastClanCached;
  1551.                 else {
  1552.                     tag = Clans.Call<string> ("GetClanOf", player);
  1553.                     clanCache [player] = tag;
  1554.                     lastClanCheck [player] = DateTime.Now;
  1555.                 }
  1556.             } else {
  1557.                 tag = Clans.Call<string> ("GetClanOf", player);
  1558.                 if (lastClanCheck.ContainsKey (player))
  1559.                     lastClanCheck.Remove (player);
  1560.  
  1561.                 if (clanCache.ContainsKey (player))
  1562.                     clanCache.Remove (player);
  1563.  
  1564.                 clanCache.Add (player, tag);
  1565.                 lastClanCheck.Add (player, DateTime.Now);
  1566.             }
  1567.  
  1568.             if (tag == null)
  1569.                 return null;
  1570.  
  1571.             List<string> lastMemberCache;
  1572.             if (memberCache.TryGetValue (tag, out lastMemberCache))
  1573.                 return lastMemberCache;
  1574.  
  1575.             var clan = GetClan (tag);
  1576.  
  1577.             if (clan == null)
  1578.                 return null;
  1579.  
  1580.             return CacheClan (clan);
  1581.         }
  1582.  
  1583.         JObject GetClan (string tag)
  1584.         {
  1585.             if (string.IsNullOrEmpty (tag)) {
  1586.                 return null;
  1587.             }
  1588.             return Clans.Call<JObject> ("GetClan", tag);
  1589.         }
  1590.  
  1591.         List<string> CacheClan (JObject clan)
  1592.         {
  1593.             string tag = clan ["tag"].ToString ();
  1594.             List<string> players = new List<string> ();
  1595.             foreach (string memberid in clan ["members"]) {
  1596.                 if (clanCache.ContainsKey (memberid))
  1597.                     clanCache [memberid] = tag;
  1598.                 else
  1599.                     clanCache.Add (memberid, tag);
  1600.  
  1601.                 players.Add (memberid);
  1602.             }
  1603.  
  1604.             if (memberCache.ContainsKey (tag))
  1605.                 memberCache [tag] = players;
  1606.             else
  1607.                 memberCache.Add (tag, players);
  1608.  
  1609.             if (lastCheck.ContainsKey (tag))
  1610.                 lastCheck [tag] = DateTime.Now;
  1611.             else
  1612.                 lastCheck.Add (tag, DateTime.Now);
  1613.  
  1614.             return players;
  1615.         }
  1616.  
  1617.         [HookMethod ("OnClanCreate")]
  1618.         void OnClanCreate (string tag)
  1619.         {
  1620.             var clan = GetClan (tag);
  1621.             if (clan != null) {
  1622.                 CacheClan (clan);
  1623.             } else {
  1624.                 PrintWarning ("Unable to find clan after creation: " + tag);
  1625.             }
  1626.         }
  1627.  
  1628.         [HookMethod ("OnClanUpdate")]
  1629.         void OnClanUpdate (string tag)
  1630.         {
  1631.             var clan = GetClan (tag);
  1632.             if (clan != null) {
  1633.                 CacheClan (clan);
  1634.             } else {
  1635.                 PrintWarning ("Unable to find clan after update: " + tag);
  1636.             }
  1637.         }
  1638.  
  1639.         [HookMethod ("OnClanDestroy")]
  1640.         void OnClanDestroy (string tag)
  1641.         {
  1642.             if (lastCheck.ContainsKey (tag)) {
  1643.                 lastCheck.Remove (tag);
  1644.             }
  1645.  
  1646.             if (memberCache.ContainsKey (tag)) {
  1647.                 memberCache.Remove (tag);
  1648.             }
  1649.         }
  1650.  
  1651.         #endregion
  1652.  
  1653.         #region Permission Checking & External API Handling
  1654.  
  1655.         bool HasPerm (string userid, string perm)
  1656.         {
  1657.             return permission.UserHasPermission (userid, "noescape." + perm);
  1658.         }
  1659.  
  1660.         bool CanRaidCommand (BasePlayer player, string command)
  1661.         {
  1662.             return raidBlock && HasPerm (player.UserIDString, "raid." + command + "block") && IsRaidBlocked (player);
  1663.         }
  1664.  
  1665.         bool CanRaidCommand (string playerID, string command)
  1666.         {
  1667.             return raidBlock && HasPerm (playerID, "raid." + command + "block") && IsRaidBlocked (playerID);
  1668.         }
  1669.  
  1670.         bool CanCombatCommand (BasePlayer player, string command)
  1671.         {
  1672.             return combatBlock && HasPerm (player.UserIDString, "combat." + command + "block") && IsCombatBlocked (player);
  1673.         }
  1674.  
  1675.         bool CanCombatCommand (string playerID, string command)
  1676.         {
  1677.             return combatBlock && HasPerm (playerID, "combat." + command + "block") && IsCombatBlocked (playerID);
  1678.         }
  1679.  
  1680.         object CanDo (string command, BasePlayer player)
  1681.         {
  1682.             if (CanRaidCommand (player, command))
  1683.                 return GetMessage<RaidBlock> (player, "Raid Blocked Message", raidDuration);
  1684.             else if (CanCombatCommand (player, command))
  1685.                 return GetMessage<CombatBlock> (player, "Combat Blocked Message", combatDuration);
  1686.  
  1687.             return null;
  1688.         }
  1689.  
  1690.         object OnStructureRepair (BaseCombatEntity entity, BasePlayer player)
  1691.         {
  1692.             var result = CanDo ("repair", player);
  1693.             if (result is string) {
  1694.                 if (entity.health > entity.MaxHealth ()) {
  1695.                     return null;
  1696.                 }
  1697.                 SendReply (player, result.ToString ());
  1698.                 return true;
  1699.             }
  1700.  
  1701.             return null;
  1702.         }
  1703.  
  1704.         object OnStructureUpgrade (BuildingBlock block, BasePlayer player, BuildingGrade.Enum grade)
  1705.         {
  1706.             var result = CanDo ("upgrade", player);
  1707.             if (result is string) {
  1708.                 SendReply (player, result.ToString ());
  1709.                 return true;
  1710.             }
  1711.  
  1712.             return null;
  1713.         }
  1714.  
  1715.         object canRedeemKit (BasePlayer player)
  1716.         {
  1717.             return CanDo ("kit", player);
  1718.         }
  1719.  
  1720.         object CanUseMailbox (BasePlayer player, Mailbox mailbox)
  1721.         {
  1722.             var result = CanDo ("mailbox", player);
  1723.             if (result is string) {
  1724.                 SendReply (player, result.ToString ());
  1725.                 return true;
  1726.             }
  1727.  
  1728.             return null;
  1729.         }
  1730.  
  1731.         object CanUseVending (VendingMachine machine, BasePlayer player)
  1732.         {
  1733.             var result = CanDo ("vend", player);
  1734.             if (result is string) {
  1735.                 SendReply (player, result.ToString ());
  1736.                 return true;
  1737.             }
  1738.  
  1739.             return null;
  1740.         }
  1741.  
  1742.         object CanBuild (Planner plan, Construction prefab)
  1743.         {
  1744.             var player = plan.GetOwnerPlayer ();
  1745.             var result = CanDo ("build", player);
  1746.             if (result is string) {
  1747.                 if (isEntityException (prefab.fullName)) {
  1748.                     return null;
  1749.                 }
  1750.  
  1751.                 SendReply (player, result.ToString ());
  1752.                 return true;
  1753.             }
  1754.  
  1755.             return null;
  1756.         }
  1757.  
  1758.         object CanAssignBed (SleepingBag bag, BasePlayer player, ulong targetPlayerId)
  1759.         {
  1760.             var result = CanDo ("assignbed", player);
  1761.             if (result is string) {
  1762.                 SendReply (player, result.ToString ());
  1763.                 return true;
  1764.             }
  1765.  
  1766.             return null;
  1767.         }
  1768.        
  1769.         object CanOpenBackpack(BasePlayer player, ulong backpackOwnerID)
  1770.         {
  1771.             return CanDo ("backpack", player);
  1772.         }
  1773.  
  1774.         object CanBank (BasePlayer player)
  1775.         {
  1776.             return CanDo ("bank", player);
  1777.         }
  1778.  
  1779.         object CanTrade (BasePlayer player)
  1780.         {
  1781.             return CanDo ("trade", player);
  1782.         }
  1783.  
  1784.         object canRemove (BasePlayer player)
  1785.         {
  1786.             return CanDo ("remove", player);
  1787.         }
  1788.  
  1789.         object canShop (BasePlayer player)
  1790.         {
  1791.             return CanDo ("shop", player);
  1792.         }
  1793.  
  1794.         object CanShop (BasePlayer player)
  1795.         {
  1796.             return CanDo ("shop", player);
  1797.         }
  1798.  
  1799.         object CanTeleport (BasePlayer player)
  1800.         {
  1801.             return CanDo ("tp", player);
  1802.         }
  1803.  
  1804.         object canTeleport (BasePlayer player) // ALIAS FOR MagicTeleportation
  1805.         {
  1806.             return CanTeleport (player);
  1807.         }
  1808.  
  1809.         object CanGridTeleport (BasePlayer player) // ALIAS FOR GrTeleport
  1810.         {
  1811.             return CanTeleport (player);
  1812.         }
  1813.  
  1814.         object CanCraft (ItemCrafter itemCrafter, ItemBlueprint bp, int amount)
  1815.         {
  1816.             BasePlayer player = itemCrafter.containers [0].GetOwnerPlayer ();
  1817.  
  1818.             if (player != null) {
  1819.                 var result = CanDo ("craft", player);
  1820.                 if (result is string) {
  1821.                     SendReply (player, result.ToString ());
  1822.                     return false;
  1823.                 }
  1824.             }
  1825.  
  1826.             return null;
  1827.         }
  1828.  
  1829.         object CanRecycleCommand (BasePlayer player)
  1830.         {
  1831.             return CanDo ("recycle", player);
  1832.         }
  1833.  
  1834.         object CanBGrade (BasePlayer player, int grade, BuildingBlock buildingBlock, Planner planner)
  1835.         {
  1836.             if (CanRaidCommand (player, "bgrade") || CanCombatCommand (player, "bgrade"))
  1837.                 return -1;
  1838.             return null;
  1839.         }
  1840.  
  1841.         #endregion
  1842.  
  1843.         #region Messages
  1844.  
  1845.         void SendBlockMessage (BasePlayer target, BlockBehavior blocker, string langMessage, string completeMessage)
  1846.         {
  1847.             var send = false;
  1848.             if (blocker.lastNotification != DateTime.MinValue) {
  1849.                 TimeSpan diff = DateTime.Now - blocker.lastNotification;
  1850.                 if (diff.TotalSeconds >= (blocker.Duration / 2))
  1851.                     send = true;
  1852.             } else
  1853.                 send = true;
  1854.  
  1855.             if (send) {
  1856.                 string message = string.Empty;
  1857.  
  1858.                 if (sendChatNotification || sendGUIAnnouncementsNotification)
  1859.                     message = GetPrefix (target.UserIDString) + GetMsg (langMessage, target.UserIDString).Replace ("{time}", GetCooldownTime (blocker.Duration, target.UserIDString));
  1860.  
  1861.                 if (sendChatNotification)
  1862.                     SendReply (target, message);
  1863.  
  1864.                 if (sendGUIAnnouncementsNotification)
  1865.                     GUIAnnouncements?.Call ("CreateAnnouncement", message, GUIAnnouncementTintColor, GUIAnnouncementTextColor, target);
  1866.  
  1867.                 if (sendLustyMapNotification && LustyMapDuration > 0) {
  1868.                     blocker.iconUID = Guid.NewGuid ().ToString ("N");
  1869.                     var obj = LustyMap?.Call ("AddMarker", target.transform.position.x, target.transform.position.z, blocker.iconUID, LustyMapIcon);
  1870.                     if (obj is bool && (bool)obj == true) {
  1871.                         timer.In (LustyMapDuration, delegate () {
  1872.                             LustyMap?.Call ("RemoveMarker", blocker.iconUID);
  1873.                         });
  1874.                     }
  1875.                 }
  1876.  
  1877.                 blocker.lastNotification = DateTime.Now;
  1878.             }
  1879.  
  1880.             blocker.Notify (delegate () {
  1881.                 blocker.notifyCallback = null;
  1882.                 if (target?.IsConnected == true) {
  1883.                     string message = string.Empty;
  1884.  
  1885.                     if (sendChatNotification || sendGUIAnnouncementsNotification)
  1886.                         message = GetPrefix (target.UserIDString) + GetMsg (completeMessage, target.UserIDString);
  1887.  
  1888.                     if (sendChatNotification)
  1889.                         SendReply (target, message);
  1890.  
  1891.                     if (sendGUIAnnouncementsNotification)
  1892.                         GUIAnnouncements?.Call ("CreateAnnouncement", message, GUIAnnouncementTintColor, GUIAnnouncementTextColor, target);
  1893.  
  1894.                     if (sendLustyMapNotification && LustyMapDuration > 0)
  1895.                         LustyMap?.Call ("RemoveMarker", blocker.iconUID);
  1896.                 }
  1897.             });
  1898.         }
  1899.  
  1900.         string GetCooldownTime (float f, string userID)
  1901.         {
  1902.             if (f > 60)
  1903.                 return Math.Round (f / 60, 1) + " " + GetMsg ("Unit Minutes", userID);
  1904.  
  1905.             return f + " " + GetMsg ("Unit Seconds", userID);
  1906.         }
  1907.  
  1908.         public string GetMessage (BasePlayer player)
  1909.         {
  1910.             if (IsRaidBlocked (player))
  1911.                 return GetMessage<RaidBlock> (player, "Raid Blocked Message", raidDuration);
  1912.             else if (IsCombatBlocked (player))
  1913.                 return GetMessage<CombatBlock> (player, "Combat Blocked Message", combatDuration);
  1914.  
  1915.             return null;
  1916.         }
  1917.  
  1918.         public string GetPrefix (string player)
  1919.         {
  1920.             string prefix = GetMsg ("Prefix", player);
  1921.             if (!string.IsNullOrEmpty (prefix)) {
  1922.                 return prefix + ": ";
  1923.             }
  1924.  
  1925.             return string.Empty;
  1926.         }
  1927.  
  1928.         public string GetMessage<T> (BasePlayer player, string blockMsg, float duration) where T : BlockBehavior
  1929.         {
  1930.             T blocker;
  1931.             if (duration > 0 && TryGetBlocker<T> (player, out blocker)) {
  1932.                 var ts = DateTime.Now - blocker.lastBlock;
  1933.                 var unblocked = Math.Round ((duration / 60) - Convert.ToSingle (ts.TotalMinutes), 2);
  1934.  
  1935.                 if (ts.TotalMinutes <= duration) {
  1936.                     if (unblocked < 1) {
  1937.                         var timelefts = Math.Round (Convert.ToDouble (duration) - ts.TotalSeconds);
  1938.                         return GetPrefix (player.UserIDString) + GetMsg (blockMsg, player).Replace ("{time}", timelefts.ToString () + " " + GetMsg ("Unit Seconds", player));
  1939.                     }
  1940.  
  1941.                     return GetPrefix (player.UserIDString) + GetMsg (blockMsg, player).Replace ("{time}", unblocked.ToString () + " " + GetMsg ("Unit Minutes", player));
  1942.                 }
  1943.             }
  1944.  
  1945.             return null;
  1946.         }
  1947.  
  1948.         #endregion
  1949.  
  1950.         #region Utility Methods
  1951.  
  1952.         bool TryGetBlocker<T> (BasePlayer player, out T blocker) where T : BlockBehavior
  1953.         {
  1954.             blocker = null;
  1955.             if (player.gameObject == null)
  1956.                 return false;
  1957.             if ((blocker = player.gameObject.GetComponent<T> ()) != null)
  1958.                 return true;
  1959.  
  1960.             return false;
  1961.         }
  1962.  
  1963.         public bool isEntityException (string prefabName)
  1964.         {
  1965.             var result = false;
  1966.  
  1967.             foreach (string p in exceptionPrefabs) {
  1968.                 if (prefabName.IndexOf (p) != -1) {
  1969.                     result = true;
  1970.                     break;
  1971.                 }
  1972.             }
  1973.  
  1974.             return result;
  1975.         }
  1976.  
  1977.         public bool IsEntityBlocked (BaseCombatEntity entity)
  1978.         {
  1979.             if (entity is BuildingBlock) {
  1980.                 if (((BuildingBlock)entity).grade == BuildingGrade.Enum.Twigs)
  1981.                     return false;
  1982.  
  1983.                 return true;
  1984.             }
  1985.  
  1986.             var prefabName = entity.ShortPrefabName;
  1987.             var result = false;
  1988.             if (prefabBlockCache.TryGetValue (prefabName, out result))
  1989.                 return result;
  1990.  
  1991.             result = false;
  1992.  
  1993.             foreach (string p in blockedPrefabs) {
  1994.                 if (prefabName.IndexOf (p) != -1) {
  1995.                     result = true;
  1996.                     break;
  1997.                 }
  1998.             }
  1999.  
  2000.  
  2001.             prefabBlockCache.Add (prefabName, result);
  2002.             return result;
  2003.         }
  2004.  
  2005.         bool IsRaidDamage (DamageType dt)
  2006.         {
  2007.             return raidDamageTypes.Contains (dt.ToString ());
  2008.         }
  2009.  
  2010.         bool IsDeathDamage (DamageType dt)
  2011.         {
  2012.             return raidDeathTypes.Contains (dt.ToString ());
  2013.         }
  2014.  
  2015.         bool IsRaidDamage (DamageTypeList dtList)
  2016.         {
  2017.             for (int index = 0; index < dtList.types.Length; ++index) {
  2018.                 if (dtList.types [index] > 0 && IsRaidDamage ((DamageType)index)) {
  2019.                     return true;
  2020.                 }
  2021.             }
  2022.  
  2023.             return false;
  2024.         }
  2025.  
  2026.         bool IsDeathDamage (DamageTypeList dtList)
  2027.         {
  2028.             for (int index = 0; index < dtList.types.Length; ++index) {
  2029.                 if (dtList.types [index] > 0 && IsDeathDamage ((DamageType)index)) {
  2030.                     return true;
  2031.                 }
  2032.             }
  2033.  
  2034.             return false;
  2035.         }
  2036.  
  2037.         bool IsExcludedWeapon (string name)
  2038.         {
  2039.             if (string.IsNullOrEmpty (name)) {
  2040.                 return false;
  2041.             }
  2042.  
  2043.             bool cachedValue;
  2044.  
  2045.             if (_cachedExcludedWeapons.TryGetValue (name, out cachedValue)) {
  2046.                 return cachedValue;
  2047.             }
  2048.  
  2049.             foreach (var weaponName in exceptionWeapons) {
  2050.                 if (name.Contains (weaponName)) {
  2051.                     _cachedExcludedWeapons.Add (name, true);
  2052.                     return true;
  2053.                 }
  2054.             }
  2055.  
  2056.             _cachedExcludedWeapons.Add (name, false);
  2057.             return false;
  2058.         }
  2059.  
  2060.         bool IsCombatDamage (DamageType dt)
  2061.         {
  2062.             return combatDamageTypes.Contains (dt.ToString ());
  2063.         }
  2064.  
  2065.         bool IsCombatDamage (DamageTypeList dtList)
  2066.         {
  2067.             for (int index = 0; index < dtList.types.Length; ++index) {
  2068.                 if (dtList.types [index] > 0 && IsCombatDamage ((DamageType)index)) {
  2069.                     return true;
  2070.                 }
  2071.             }
  2072.  
  2073.             return false;
  2074.         }
  2075.  
  2076.         T GetConfig<T> (string name, string name2, string name3, T defaultValue)
  2077.         {
  2078.             try {
  2079.                 var val = Config [name, name2, name3];
  2080.  
  2081.                 return ParseValue<T> (val, defaultValue);
  2082.             } catch (Exception ex) {
  2083.                 //PrintWarning ("Invalid config value: " + name + "/" + name2 + "/" + name3 + " (" + ex.Message + ")");
  2084.                 Config [name, name2, name3] = defaultValue;
  2085.                 Config.Save ();
  2086.                 return defaultValue;
  2087.             }
  2088.         }
  2089.  
  2090.         T GetConfig<T> (string name, string name2, T defaultValue)
  2091.         {
  2092.             try {
  2093.                 var val = Config [name, name2];
  2094.  
  2095.                 return ParseValue<T> (val, defaultValue);
  2096.             } catch (Exception ex) {
  2097.                 //PrintWarning ("Invalid config value: " + name + "/" + name2 + " (" + ex.Message + ")");
  2098.                 Config [name, name2] = defaultValue;
  2099.                 Config.Save ();
  2100.                 return defaultValue;
  2101.             }
  2102.         }
  2103.  
  2104.         T GetConfig<T> (string name, T defaultValue)
  2105.         {
  2106.             try {
  2107.                 var val = Config [name];
  2108.  
  2109.                 return ParseValue<T> (val, defaultValue);
  2110.             } catch (Exception ex) {
  2111.                 //PrintWarning ("Invalid config value: " + name + " (" + ex.Message + ")");
  2112.                 Config [name] = defaultValue;
  2113.                 Config.Save ();
  2114.                 return defaultValue;
  2115.             }
  2116.         }
  2117.  
  2118.         T ParseValue<T> (object val, T defaultValue)
  2119.         {
  2120.             if (val == null)
  2121.                 return defaultValue;
  2122.  
  2123.             if (val is List<object>) {
  2124.                 var t = typeof (T).GetGenericArguments () [0];
  2125.                 if (t == typeof (String)) {
  2126.                     var cval = new List<string> ();
  2127.                     foreach (var v in val as List<object>)
  2128.                         cval.Add ((string)v);
  2129.                     val = cval;
  2130.                 } else if (t == typeof (int)) {
  2131.                     var cval = new List<int> ();
  2132.                     foreach (var v in val as List<object>)
  2133.                         cval.Add (Convert.ToInt32 (v));
  2134.                     val = cval;
  2135.                 }
  2136.             } else if (val is Dictionary<string, object>) {
  2137.                 var t = typeof (T).GetGenericArguments () [1];
  2138.                 if (t == typeof (int)) {
  2139.                     var cval = new Dictionary<string, int> ();
  2140.                     foreach (var v in val as Dictionary<string, object>)
  2141.                         cval.Add (Convert.ToString (v.Key), Convert.ToInt32 (v.Value));
  2142.                     val = cval;
  2143.                 }
  2144.             }
  2145.  
  2146.             return (T)Convert.ChangeType (val, typeof (T));
  2147.         }
  2148.  
  2149.         static string GetMsg (string key, object user = null)
  2150.         {
  2151.             if (user is BasePlayer) {
  2152.                 user = ((BasePlayer)user).UserIDString;
  2153.             }
  2154.             return plugin.lang.GetMessage (key, plugin, user == null ? null : user.ToString ());
  2155.         }
  2156.  
  2157.         #endregion
  2158.     }
  2159. }
Advertisement
Add Comment
Please, Sign In to add comment