Guest User

uk loc

a guest
Oct 3rd, 2022
102
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 335.04 KB | None | 0 0
  1. //#define DEBUG
  2. using Facepunch;
  3. using Network;
  4. using Newtonsoft.Json.Converters;
  5. using Newtonsoft.Json.Linq;
  6. using Newtonsoft.Json;
  7. using Oxide.Core.Configuration;
  8. using Oxide.Core.Libraries.Covalence;
  9. using Oxide.Core.Plugins;
  10. using Oxide.Core;
  11. using Oxide.Game.Rust;
  12. using Rust;
  13. using System.Collections.Generic;
  14. using System.Collections;
  15. using System.Globalization;
  16. using System.Linq;
  17. using System.Reflection;
  18. using System;
  19. using UnityEngine;
  20. using System.IO;
  21.  
  22. // scrap payments to bypass cooldown
  23. // costs to buy teleport
  24.  
  25. /*
  26. Fixed home limit daily reset check
  27. Fixed ErrorTPR showing a blank target message
  28. Added TPTargetInsideEntity message to language API
  29. Updated /radiushome to reply with any error message
  30. Removed bounds check in CheckFoundation
  31. */
  32.  
  33. namespace Oxide.Plugins
  34. {
  35. [Info("NTeleportation", "nivex", "1.7.0")]
  36. [Description("Multiple teleportation systems for admin and players")]
  37. class NTeleportation : RustPlugin
  38. {
  39. [PluginReference]
  40. private Plugin Clans, Economics, ServerRewards, Friends, CompoundTeleport, ZoneManager, NoEscape, Vanish, PopupNotifications;
  41.  
  42. private Dictionary<string, BasePlayer> _ids = new Dictionary<string, BasePlayer>();
  43. private Dictionary<BasePlayer, string> _players = new Dictionary<BasePlayer, string>();
  44.  
  45. private bool newSave;
  46. private string banditPrefab;
  47. private string outpostPrefab;
  48. private const string NewLine = "\n";
  49. private const string PermAdmin = "nteleportation.admin";
  50. private const string PermRestrictions = "nteleportation.norestrictions";
  51. private const string ConfigDefaultPermVip = "nteleportation.vip";
  52. private const string PermHome = "nteleportation.home";
  53. private const string PermWipeHomes = "nteleportation.wipehomes";
  54. private const string PermCraftHome = "nteleportation.crafthome";
  55. private const string PermDeleteHome = "nteleportation.deletehome";
  56. private const string PermHomeHomes = "nteleportation.homehomes";
  57. private const string PermImportHomes = "nteleportation.importhomes";
  58. private const string PermRadiusHome = "nteleportation.radiushome";
  59. private const string PermCraftTpR = "nteleportation.crafttpr";
  60. private const string PermTpR = "nteleportation.tpr";
  61. private const string PermTp = "nteleportation.tp";
  62. private const string PermTpT = "nteleportation.tpt";
  63. private const string PermTpB = "nteleportation.tpb";
  64. private const string PermTpN = "nteleportation.tpn";
  65. private const string PermTpL = "nteleportation.tpl";
  66. private const string PermTpConsole = "nteleportation.tpconsole";
  67. private const string PermTpHome = "nteleportation.tphome";
  68. private const string PermTpRemove = "nteleportation.tpremove";
  69. private const string PermTpSave = "nteleportation.tpsave";
  70. private const string PermExempt = "nteleportation.exemptfrominterruptcountdown";
  71. private const string PermFoundationCheck = "nteleportation.bypassfoundationcheck";
  72. private const string PermTpMarker = "nteleportation.tpmarker";
  73. private DynamicConfigFile dataConvert;
  74. private DynamicConfigFile dataDisabled;
  75. private DynamicConfigFile dataAdmin;
  76. private DynamicConfigFile dataHome;
  77. private DynamicConfigFile dataTPR;
  78. private DynamicConfigFile dataTPT;
  79. private Dictionary<ulong, AdminData> _Admin;
  80. private Dictionary<ulong, HomeData> _Home;
  81. private Dictionary<ulong, TeleportData> _TPR;
  82. private List<string> TPTToggle;
  83. private bool changedAdmin;
  84. private bool changedHome;
  85. private bool changedTPR;
  86. private bool changedTPT;
  87. private float boundary;
  88. private readonly Dictionary<ulong, float> TeleportCooldowns = new Dictionary<ulong, float>();
  89. private readonly Dictionary<ulong, TeleportTimer> TeleportTimers = new Dictionary<ulong, TeleportTimer>();
  90. private readonly Dictionary<ulong, Timer> PendingRequests = new Dictionary<ulong, Timer>();
  91. private readonly Dictionary<ulong, BasePlayer> PlayersRequests = new Dictionary<ulong, BasePlayer>();
  92. private readonly Dictionary<int, string> ReverseBlockedItems = new Dictionary<int, string>();
  93. private readonly Dictionary<ulong, Vector3> teleporting = new Dictionary<ulong, Vector3>();
  94. private SortedDictionary<string, Vector3> caves = new SortedDictionary<string, Vector3>();
  95. private SortedDictionary<string, MonInfo> monuments = new SortedDictionary<string, MonInfo>();
  96. private bool outpostEnabled;
  97. private bool banditEnabled;
  98.  
  99. class MonInfo
  100. {
  101. public Vector3 Position;
  102. public float Radius;
  103. }
  104.  
  105. #region Configuration
  106.  
  107. private static Configuration config;
  108.  
  109. public class InterruptSettings
  110. {
  111. [JsonProperty(PropertyName = "Interrupt Teleport At Specific Monuments", ObjectCreationHandling = ObjectCreationHandling.Replace)]
  112. public List<string> Monuments { get; set; } = new List<string>();
  113.  
  114. [JsonProperty(PropertyName = "Above Water")]
  115. public bool AboveWater { get; set; } = true;
  116.  
  117. [JsonProperty(PropertyName = "Balloon")]
  118. public bool Balloon { get; set; } = true;
  119.  
  120. [JsonProperty(PropertyName = "Boats")]
  121. public bool Boats { get; set; }
  122.  
  123. [JsonProperty(PropertyName = "Cargo Ship")]
  124. public bool Cargo { get; set; } = true;
  125.  
  126. [JsonProperty(PropertyName = "Cold")]
  127. public bool Cold { get; set; } = false;
  128.  
  129. [JsonProperty(PropertyName = "Excavator")]
  130. public bool Excavator { get; set; } = false;
  131.  
  132. [JsonProperty(PropertyName = "Hot")]
  133. public bool Hot { get; set; } = false;
  134.  
  135. [JsonProperty(PropertyName = "Hostile")]
  136. public bool Hostile { get; set; } = false;
  137.  
  138. [JsonProperty(PropertyName = "Hurt")]
  139. public bool Hurt { get; set; } = true;
  140.  
  141. [JsonProperty(PropertyName = "Junkpiles")]
  142. public bool Junkpiles { get; set; }
  143.  
  144. [JsonProperty(PropertyName = "Lift")]
  145. public bool Lift { get; set; } = true;
  146.  
  147. [JsonProperty(PropertyName = "Monument")]
  148. public bool Monument { get; set; } = false;
  149.  
  150. [JsonProperty(PropertyName = "Ignore Monument Marker Prefab")]
  151. public bool BypassMonumentMarker { get; set; } = false;
  152.  
  153. [JsonProperty(PropertyName = "Mounted")]
  154. public bool Mounted { get; set; } = true;
  155.  
  156. [JsonProperty(PropertyName = "Oil Rig")]
  157. public bool Oilrig { get; set; } = false;
  158.  
  159. [JsonProperty(PropertyName = "Safe Zone")]
  160. public bool Safe { get; set; } = true;
  161.  
  162. [JsonProperty(PropertyName = "Swimming")]
  163. public bool Swimming { get; set; } = false;
  164. }
  165.  
  166. public class PluginSettings
  167. {
  168. [JsonProperty(PropertyName = "Interrupt TP")]
  169. public InterruptSettings Interrupt { get; set; } = new InterruptSettings();
  170.  
  171. [JsonProperty(PropertyName = "Block Teleport (NoEscape)")]
  172. public bool BlockNoEscape { get; set; } = false;
  173.  
  174. [JsonProperty(PropertyName = "Block Teleport (ZoneManager)")]
  175. public bool BlockZoneFlag { get; set; } = false;
  176.  
  177. [JsonProperty(PropertyName = "Chat Name")]
  178. public string ChatName { get; set; } = "<color=red>Teleportation</color> \n\n";
  179.  
  180. [JsonProperty(PropertyName = "Chat Steam64ID")]
  181. public ulong ChatID { get; set; } = 76561199056025689;
  182.  
  183. [JsonProperty(PropertyName = "Check Boundaries On Teleport X Y Z")]
  184. public bool CheckBoundaries { get; set; } = true;
  185.  
  186. [JsonProperty(PropertyName = "Data File Directory (Blank = Default)")]
  187. public string DataFileFolder { get; set; } = string.Empty;
  188.  
  189. [JsonProperty(PropertyName = "Draw Sphere On Set Home")]
  190. public bool DrawHomeSphere { get; set; } = true;
  191.  
  192. [JsonProperty(PropertyName = "Homes Enabled")]
  193. public bool HomesEnabled { get; set; } = true;
  194.  
  195. [JsonProperty(PropertyName = "TPR Enabled")]
  196. public bool TPREnabled { get; set; } = true;
  197.  
  198. [JsonProperty(PropertyName = "Strict Foundation Check")]
  199. public bool StrictFoundationCheck { get; set; } = false;
  200.  
  201. [JsonProperty(PropertyName = "Cave Distance Small")]
  202. public float CaveDistanceSmall { get; set; } = 50f;
  203.  
  204. [JsonProperty(PropertyName = "Cave Distance Medium")]
  205. public float CaveDistanceMedium { get; set; } = 70f;
  206.  
  207. [JsonProperty(PropertyName = "Cave Distance Large")]
  208. public float CaveDistanceLarge { get; set; } = 110f;
  209.  
  210. [JsonProperty(PropertyName = "Default Monument Size")]
  211. public float DefaultMonumentSize { get; set; } = 50f;
  212.  
  213. [JsonProperty(PropertyName = "Minimum Temp")]
  214. public float MinimumTemp { get; set; } = 0f;
  215.  
  216. [JsonProperty(PropertyName = "Maximum Temp")]
  217. public float MaximumTemp { get; set; } = 40f;
  218.  
  219. [JsonProperty(PropertyName = "Blocked Items", ObjectCreationHandling = ObjectCreationHandling.Replace)]
  220. public Dictionary<string, string> BlockedItems { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
  221.  
  222. [JsonProperty(PropertyName = "Bypass CMD")]
  223. public string BypassCMD { get; set; } = "pay";
  224.  
  225. [JsonProperty(PropertyName = "Use Monument Topology Check")]
  226. public bool MonumentTopologyCheck { get; set; }
  227.  
  228. [JsonProperty(PropertyName = "Use Cave Topology Check")]
  229. public bool CaveTopologyCheck { get; set; } = false;
  230.  
  231. [JsonProperty(PropertyName = "Use Economics")]
  232. public bool UseEconomics { get; set; } = false;
  233.  
  234. [JsonProperty(PropertyName = "Use Server Rewards")]
  235. public bool UseServerRewards { get; set; } = false;
  236.  
  237. [JsonProperty(PropertyName = "Wipe On Upgrade Or Change")]
  238. public bool WipeOnUpgradeOrChange { get; set; } = true;
  239.  
  240. [JsonProperty(PropertyName = "Auto Generate Outpost Location")]
  241. public bool AutoGenOutpost { get; set; } = true;
  242.  
  243. [JsonProperty(PropertyName = "Auto Generate Bandit Location")]
  244. public bool AutoGenBandit { get; set; } = true;
  245.  
  246. [JsonProperty(PropertyName = "Show Time As Seconds Instead")]
  247. public bool UseSeconds { get; set; } = false;
  248.  
  249. [JsonProperty(PropertyName = "Chat Command Color")]
  250. public string ChatCommandColor = "#FFFF00";
  251.  
  252. [JsonProperty(PropertyName = "Chat Command Argument Color")]
  253. public string ChatCommandArgumentColor = "#FFA500";
  254.  
  255. [JsonProperty("Enable Popup Support")]
  256. public bool UsePopup = false;
  257.  
  258. [JsonProperty("Block All Teleporting From Inside Authorized Base")]
  259. public bool BlockAuthorizedTeleporting = false;
  260.  
  261. [JsonProperty("TPB Available After X Seconds")]
  262. public float TPBTime = 0f;
  263.  
  264. [JsonProperty("Global Teleport Cooldown")]
  265. public float Global = 0f;
  266.  
  267. [JsonProperty("Global VIP Teleport Cooldown")]
  268. public float GlobalVIP = 0f;
  269.  
  270. [JsonProperty("Play Sounds After Teleport")]
  271. public bool PlaySounds = false;
  272.  
  273. [JsonProperty("Sounds To Play After Teleport", ObjectCreationHandling = ObjectCreationHandling.Replace)]
  274. public List<string> PrefabSounds = new List<string>
  275. {
  276. "assets/prefabs/misc/xmas/presents/effects/unwrap.prefab",
  277. "assets/bundled/prefabs/fx/player/howl.prefab",
  278. "assets/content/vehicles/minicopter/debris_effect.prefab",
  279. "assets/prefabs/npc/patrol helicopter/damage_effect_debris.prefab",
  280. "assets/prefabs/npc/patrol helicopter/effects/rocket_fire.prefab"
  281. };
  282. }
  283.  
  284. public class AdminSettings
  285. {
  286. [JsonProperty(PropertyName = "Announce Teleport To Target")]
  287. public bool AnnounceTeleportToTarget { get; set; } = false;
  288.  
  289. [JsonProperty(PropertyName = "Usable By Admins")]
  290. public bool UseableByAdmins { get; set; } = true;
  291.  
  292. [JsonProperty(PropertyName = "Usable By Moderators")]
  293. public bool UseableByModerators { get; set; } = true;
  294.  
  295. [JsonProperty(PropertyName = "Location Radius")]
  296. public int LocationRadius { get; set; } = 25;
  297.  
  298. [JsonProperty(PropertyName = "Teleport Near Default Distance")]
  299. public int TeleportNearDefaultDistance { get; set; } = 30;
  300. }
  301.  
  302. public class HomesSettings
  303. {
  304. [JsonProperty(PropertyName = "Homes Limit")]
  305. public int HomesLimit { get; set; } = 2;
  306.  
  307. [JsonProperty(PropertyName = "VIP Homes Limits", ObjectCreationHandling = ObjectCreationHandling.Replace)]
  308. public Dictionary<string, int> VIPHomesLimits { get; set; } = new Dictionary<string, int> { { ConfigDefaultPermVip, 5 } };
  309.  
  310. [JsonProperty(PropertyName = "Allow Sethome At Specific Monuments", ObjectCreationHandling = ObjectCreationHandling.Replace)]
  311. public List<string> AllowedMonuments { get; set; } = new List<string> { "HQM Quarry", "Stone Quarry", "Sulfur Quarry", "Ice Lake" };
  312.  
  313. [JsonProperty(PropertyName = "Allow Sethome At All Monuments")]
  314. public bool AllowAtAllMonuments { get; set; } = false;
  315.  
  316. [JsonProperty(PropertyName = "Allow TPB")]
  317. public bool AllowTPB { get; set; } = true;
  318.  
  319. [JsonProperty(PropertyName = "Cooldown")]
  320. public int Cooldown { get; set; } = 600;
  321.  
  322. [JsonProperty(PropertyName = "Countdown")]
  323. public int Countdown { get; set; } = 15;
  324.  
  325. [JsonProperty(PropertyName = "Daily Limit")]
  326. public int DailyLimit { get; set; } = 5;
  327.  
  328. [JsonProperty(PropertyName = "VIP Daily Limits", ObjectCreationHandling = ObjectCreationHandling.Replace)]
  329. public Dictionary<string, int> VIPDailyLimits { get; set; } = new Dictionary<string, int> { { ConfigDefaultPermVip, 5 } };
  330.  
  331. [JsonProperty(PropertyName = "VIP Cooldowns", ObjectCreationHandling = ObjectCreationHandling.Replace)]
  332. public Dictionary<string, int> VIPCooldowns { get; set; } = new Dictionary<string, int> { { ConfigDefaultPermVip, 5 } };
  333.  
  334. [JsonProperty(PropertyName = "VIP Countdowns", ObjectCreationHandling = ObjectCreationHandling.Replace)]
  335. public Dictionary<string, int> VIPCountdowns { get; set; } = new Dictionary<string, int> { { ConfigDefaultPermVip, 5 } };
  336.  
  337. [JsonProperty(PropertyName = "Location Radius")]
  338. public int LocationRadius { get; set; } = 25;
  339.  
  340. [JsonProperty(PropertyName = "Force On Top Of Foundation")]
  341. public bool ForceOnTopOfFoundation { get; set; } = true;
  342.  
  343. [JsonProperty(PropertyName = "Check Foundation For Owner")]
  344. public bool CheckFoundationForOwner { get; set; } = true;
  345.  
  346. [JsonProperty(PropertyName = "Use Friends")]
  347. public bool UseFriends { get; set; } = true;
  348.  
  349. [JsonProperty(PropertyName = "Use Clans")]
  350. public bool UseClans { get; set; } = true;
  351.  
  352. [JsonProperty(PropertyName = "Use Teams")]
  353. public bool UseTeams { get; set; } = true;
  354.  
  355. [JsonProperty(PropertyName = "Usable Out Of Building Blocked")]
  356. public bool UsableOutOfBuildingBlocked { get; set; } = false;
  357.  
  358. [JsonProperty(PropertyName = "Usable Into Building Blocked")]
  359. public bool UsableIntoBuildingBlocked { get; set; } = false;
  360.  
  361. [JsonProperty(PropertyName = "Usable From Safe Zone Only")]
  362. public bool UsableFromSafeZoneOnly { get; set; } = false;
  363.  
  364. [JsonProperty(PropertyName = "Allow Cupboard Owner When Building Blocked")]
  365. public bool CupOwnerAllowOnBuildingBlocked { get; set; } = true;
  366.  
  367. [JsonProperty(PropertyName = "Allow Iceberg")]
  368. public bool AllowIceberg { get; set; } = false;
  369.  
  370. [JsonProperty(PropertyName = "Allow Cave")]
  371. public bool AllowCave { get; set; }
  372.  
  373. [JsonProperty(PropertyName = "Allow Crafting")]
  374. public bool AllowCraft { get; set; } = false;
  375.  
  376. [JsonProperty(PropertyName = "Allow Above Foundation")]
  377. public bool AllowAboveFoundation { get; set; } = true;
  378.  
  379. [JsonProperty(PropertyName = "Check If Home Is Valid On Listhomes")]
  380. public bool CheckValidOnList { get; set; } = false;
  381.  
  382. [JsonProperty(PropertyName = "Pay")]
  383. public int Pay { get; set; } = 0;
  384.  
  385. [JsonProperty(PropertyName = "Bypass")]
  386. public int Bypass { get; set; } = 0;
  387. }
  388.  
  389. public class TPTSettings
  390. {
  391. [JsonProperty(PropertyName = "Use Friends")]
  392. public bool UseFriends { get; set; }
  393.  
  394. [JsonProperty(PropertyName = "Use Clans")]
  395. public bool UseClans { get; set; }
  396.  
  397. [JsonProperty(PropertyName = "Use Teams")]
  398. public bool UseTeams { get; set; }
  399.  
  400. [JsonProperty(PropertyName = "Allow Cave")]
  401. public bool AllowCave { get; set; }
  402. }
  403.  
  404. public class TPRSettings
  405. {
  406. [JsonProperty(PropertyName = "Require Player To Be Friend, Clan Mate, Or Team Mate")]
  407. public bool UseClans_Friends_Teams { get; set; }
  408.  
  409. [JsonProperty(PropertyName = "Allow Cave")]
  410. public bool AllowCave { get; set; }
  411.  
  412. [JsonProperty(PropertyName = "Allow TPB")]
  413. public bool AllowTPB { get; set; } = true;
  414.  
  415. [JsonProperty(PropertyName = "Cooldown")]
  416. public int Cooldown { get; set; } = 600;
  417.  
  418. [JsonProperty(PropertyName = "Countdown")]
  419. public int Countdown { get; set; } = 15;
  420.  
  421. [JsonProperty(PropertyName = "Daily Limit")]
  422. public int DailyLimit { get; set; } = 5;
  423.  
  424. [JsonProperty(PropertyName = "VIP Daily Limits", ObjectCreationHandling = ObjectCreationHandling.Replace)]
  425. public Dictionary<string, int> VIPDailyLimits { get; set; } = new Dictionary<string, int> { { ConfigDefaultPermVip, 5 } };
  426.  
  427. [JsonProperty(PropertyName = "VIP Cooldowns", ObjectCreationHandling = ObjectCreationHandling.Replace)]
  428. public Dictionary<string, int> VIPCooldowns { get; set; } = new Dictionary<string, int> { { ConfigDefaultPermVip, 5 } };
  429.  
  430. [JsonProperty(PropertyName = "VIP Countdowns", ObjectCreationHandling = ObjectCreationHandling.Replace)]
  431. public Dictionary<string, int> VIPCountdowns { get; set; } = new Dictionary<string, int> { { ConfigDefaultPermVip, 5 } };
  432.  
  433. [JsonProperty(PropertyName = "Request Duration")]
  434. public int RequestDuration { get; set; } = 30;
  435.  
  436. [JsonProperty(PropertyName = "Block TPA On Ceiling")]
  437. public bool BlockTPAOnCeiling { get; set; } = true;
  438.  
  439. [JsonProperty(PropertyName = "Usable Out Of Building Blocked")]
  440. public bool UsableOutOfBuildingBlocked { get; set; } = false;
  441.  
  442. [JsonProperty(PropertyName = "Usable Into Building Blocked")]
  443. public bool UsableIntoBuildingBlocked { get; set; } = false;
  444.  
  445. [JsonProperty(PropertyName = "Allow Cupboard Owner When Building Blocked")]
  446. public bool CupOwnerAllowOnBuildingBlocked { get; set; } = true;
  447.  
  448. [JsonProperty(PropertyName = "Allow Crafting")]
  449. public bool AllowCraft { get; set; } = false;
  450.  
  451. [JsonProperty(PropertyName = "Pay")]
  452. public int Pay { get; set; } = 0;
  453.  
  454. [JsonProperty(PropertyName = "Bypass")]
  455. public int Bypass { get; set; } = 0;
  456. }
  457.  
  458. public class TownSettings
  459. {
  460. [JsonProperty(PropertyName = "Command Enabled")]
  461. public bool Enabled { get; set; } = true;
  462.  
  463. [JsonProperty(PropertyName = "Allow TPB")]
  464. public bool AllowTPB { get; set; } = true;
  465.  
  466. [JsonProperty(PropertyName = "Allow Cave")]
  467. public bool AllowCave { get; set; }
  468.  
  469. [JsonProperty(PropertyName = "Cooldown")]
  470. public int Cooldown { get; set; } = 600;
  471.  
  472. [JsonProperty(PropertyName = "Countdown")]
  473. public int Countdown { get; set; } = 15;
  474.  
  475. [JsonProperty(PropertyName = "Daily Limit")]
  476. public int DailyLimit { get; set; } = 5;
  477.  
  478. [JsonProperty(PropertyName = "VIP Daily Limits", ObjectCreationHandling = ObjectCreationHandling.Replace)]
  479. public Dictionary<string, int> VIPDailyLimits { get; set; } = new Dictionary<string, int> { { ConfigDefaultPermVip, 5 } };
  480.  
  481. [JsonProperty(PropertyName = "VIP Cooldowns", ObjectCreationHandling = ObjectCreationHandling.Replace)]
  482. public Dictionary<string, int> VIPCooldowns { get; set; } = new Dictionary<string, int> { { ConfigDefaultPermVip, 5 } };
  483.  
  484. [JsonProperty(PropertyName = "VIP Countdowns", ObjectCreationHandling = ObjectCreationHandling.Replace)]
  485. public Dictionary<string, int> VIPCountdowns { get; set; } = new Dictionary<string, int> { { ConfigDefaultPermVip, 5 } };
  486.  
  487. [JsonProperty(PropertyName = "Location")]
  488. public Vector3 Location { get; set; } = Vector3.zero;
  489.  
  490. [JsonProperty(PropertyName = "Locations", ObjectCreationHandling = ObjectCreationHandling.Replace)]
  491. public List<Vector3> Locations { get; set; } = new List<Vector3>();
  492.  
  493. [JsonProperty(PropertyName = "Teleport To Random Location")]
  494. public bool Random { get; set; } = true;
  495.  
  496. [JsonProperty(PropertyName = "Usable Out Of Building Blocked")]
  497. public bool UsableOutOfBuildingBlocked { get; set; } = false;
  498.  
  499. [JsonProperty(PropertyName = "Allow Crafting")]
  500. public bool AllowCraft { get; set; } = false;
  501.  
  502. [JsonProperty(PropertyName = "Pay")]
  503. public int Pay { get; set; } = 0;
  504.  
  505. [JsonProperty(PropertyName = "Bypass")]
  506. public int Bypass { get; set; } = 0;
  507.  
  508. public bool CanCraft(BasePlayer player, string command)
  509. {
  510. return AllowCraft || player.IPlayer.HasPermission($"nteleportation.craft{command}");
  511. }
  512.  
  513. [JsonIgnore]
  514. public StoredData Teleports = new StoredData();
  515.  
  516. [JsonIgnore]
  517. public string Command { get; set; }
  518. }
  519.  
  520. private class Configuration
  521. {
  522. [JsonProperty(PropertyName = "Settings")]
  523. public PluginSettings Settings = new PluginSettings();
  524.  
  525. [JsonProperty(PropertyName = "Admin")]
  526. public AdminSettings Admin = new AdminSettings();
  527.  
  528. [JsonProperty(PropertyName = "Home")]
  529. public HomesSettings Home = new HomesSettings();
  530.  
  531. [JsonProperty(PropertyName = "TPT")]
  532. public TPTSettings TPT = new TPTSettings();
  533.  
  534. [JsonProperty(PropertyName = "TPR")]
  535. public TPRSettings TPR = new TPRSettings();
  536.  
  537. [JsonProperty(PropertyName = "Dynamic Commands", ObjectCreationHandling = ObjectCreationHandling.Replace)]
  538. public Dictionary<string, TownSettings> DynamicCommands { get; set; } = DefaultCommands;
  539. }
  540.  
  541. private static Dictionary<string, TownSettings> DefaultCommands = new Dictionary<string, TownSettings>
  542. {
  543. ["Town"] = new TownSettings() { Random = false },
  544. ["Island"] = new TownSettings() { AllowTPB = false },
  545. ["Outpost"] = new TownSettings(),
  546. ["Bandit"] = new TownSettings(),
  547. };
  548.  
  549. public void InitializeDynamicCommands()
  550. {
  551. banditPrefab = StringPool.Get(2074025910);
  552. outpostPrefab = StringPool.Get(1879405026);
  553.  
  554. foreach (var entry in config.DynamicCommands)
  555. {
  556. if (!entry.Value.Enabled)
  557. {
  558. continue;
  559. }
  560. else if (entry.Key.Equals("bandit", StringComparison.OrdinalIgnoreCase))
  561. {
  562. if (CompoundTeleport == null || Convert.ToBoolean(CompoundTeleport?.Call("umodversion")))
  563. {
  564. banditEnabled = true;
  565. }
  566. else continue;
  567. }
  568. else if (entry.Key.Equals("outpost", StringComparison.OrdinalIgnoreCase))
  569. {
  570. if (CompoundTeleport == null || Convert.ToBoolean(CompoundTeleport?.Call("umodversion")))
  571. {
  572. outpostEnabled = true;
  573. }
  574. else continue;
  575. }
  576.  
  577. entry.Value.Command = entry.Key;
  578. RegisterCommand(entry.Key, nameof(CommandCustom));
  579. }
  580.  
  581. RegisterCommand("ntp", nameof(CommandDynamic), PermAdmin);
  582. }
  583.  
  584. protected override void LoadConfig()
  585. {
  586. base.LoadConfig();
  587. try
  588. {
  589. Config.Settings.Converters = new JsonConverter[] { new UnityVector3Converter() };
  590. config = Config.ReadObject<Configuration>();
  591. if (config == null) LoadDefaultConfig();
  592. SaveConfig();
  593. }
  594. catch (JsonException ex)
  595. {
  596. Debug.LogException(ex);
  597. LoadDefaultConfig();
  598. }
  599. }
  600.  
  601. protected override void SaveConfig()
  602. {
  603. Config.WriteObject(config);
  604. }
  605.  
  606. protected override void LoadDefaultConfig()
  607. {
  608. config = new Configuration();
  609. Puts("Loaded default configuration.");
  610. }
  611.  
  612. #endregion
  613.  
  614. class DisabledData
  615. {
  616. [JsonProperty("List of disabled commands")]
  617. public List<string> DisabledCommands = new List<string>();
  618.  
  619. public DisabledData() { }
  620. }
  621.  
  622. DisabledData DisabledCommandData = new DisabledData();
  623.  
  624. class AdminData
  625. {
  626. [JsonProperty("pl")]
  627. public Vector3 PreviousLocation { get; set; }
  628.  
  629. [JsonProperty("l")]
  630. public Dictionary<string, Vector3> Locations { get; set; } = new Dictionary<string, Vector3>(StringComparer.OrdinalIgnoreCase);
  631. }
  632.  
  633. class HomeData
  634. {
  635. [JsonProperty("l")]
  636. public Dictionary<string, Vector3> Locations { get; set; } = new Dictionary<string, Vector3>(StringComparer.OrdinalIgnoreCase);
  637.  
  638. [JsonProperty("t")]
  639. public TeleportData Teleports { get; set; } = new TeleportData();
  640. }
  641.  
  642. public class TeleportData
  643. {
  644. [JsonProperty("a")]
  645. public int Amount { get; set; }
  646.  
  647. [JsonProperty("d")]
  648. public string Date { get; set; }
  649.  
  650. [JsonProperty("t")]
  651. public int Timestamp { get; set; }
  652. }
  653.  
  654. class TeleportTimer
  655. {
  656. public Timer Timer { get; set; }
  657. public BasePlayer OriginPlayer { get; set; }
  658. public BasePlayer TargetPlayer { get; set; }
  659. }
  660.  
  661. private enum checkmode
  662. {
  663. home, tpr, tpa, town
  664. };
  665.  
  666. protected override void LoadDefaultMessages()
  667. {
  668. var en = new Dictionary<string, string>
  669. {
  670. {"ErrorTPR", "Teleporting to {0} is blocked ({1})"},
  671. {"AdminTP", "You teleported to {0}!"},
  672. {"AdminTPTarget", "{0} teleported to you!"},
  673. {"AdminTPPlayers", "You teleported {0} to {1}!"},
  674. {"AdminTPPlayer", "{0} teleported you to {1}!"},
  675. {"AdminTPPlayerTarget", "{0} teleported {1} to you!"},
  676. {"AdminTPCoordinates", "You teleported to {0}!"},
  677. {"AdminTPTargetCoordinates", "You teleported {0} to {1}!"},
  678. {"AdminTPOutOfBounds", "You tried to teleport to a set of coordinates outside the map boundaries!"},
  679. {"AdminTPBoundaries", "X and Z values need to be between -{0} and {0} while the Y value needs to be between -100 and 2000!"},
  680. {"AdminTPLocation", "You teleported to {0}!"},
  681. {"AdminTPLocationSave", "You have saved the current location!"},
  682. {"AdminTPLocationRemove", "You have removed the location {0}!"},
  683. {"AdminLocationList", "The following locations are available:"},
  684. {"AdminLocationListEmpty", "You haven't saved any locations!"},
  685. {"AdminTPBack", "You've teleported back to your previous location!"},
  686. {"AdminTPBackSave", "Your previous location has been saved, use /tpb to teleport back!"},
  687. {"AdminTPTargetCoordinatesTarget", "{0} teleported you to {1}!"},
  688. {"AdminTPConsoleTP", "You were teleported to {0}"},
  689. {"AdminTPConsoleTPPlayer", "You were teleported to {0}"},
  690. {"AdminTPConsoleTPPlayerTarget", "{0} was teleported to you!"},
  691. {"HomeTP", "You teleported to your home '{0}'!"},
  692. {"HomeAdminTP", "You teleported to {0}'s home '{1}'!"},
  693. {"HomeSave", "You have saved the current location as your home!"},
  694. {"HomeNoFoundation", "You can only use a home location on a foundation!"},
  695. {"HomeFoundationNotOwned", "You can't use home on someone else's house."},
  696. {"HomeFoundationUnderneathFoundation", "You can't use home on a foundation that is underneath another foundation."},
  697. {"HomeFoundationNotFriendsOwned", "You or a friend need to own the house to use home!"},
  698. {"HomeRemovedInvalid", "Your home '{0}' was removed because not on a foundation or not owned!"},
  699. {"HighWallCollision", "High Wall Collision!"},
  700. {"HomeRemovedInsideBlock", "Your home '{0}' was removed because inside a foundation!"},
  701. {"HomeRemove", "You have removed your home {0}!"},
  702. {"HomeDelete", "You have removed {0}'s home '{1}'!"},
  703. {"HomeList", "The following homes are available:"},
  704. {"HomeListEmpty", "You haven't saved any homes!"},
  705. {"HomeMaxLocations", "Unable to set your home here, you have reached the maximum of {0} homes!"},
  706. {"HomeQuota", "You have set {0} of the maximum {1} homes!"},
  707. {"HomeTPStarted", "Teleporting to your home {0} in {1} seconds!"},
  708. {"PayToTown", "Standard payment of {0} applies to all {1} teleports!"},
  709. {"PayToTPR", "Standard payment of {0} applies to all tprs!"},
  710. {"HomeTPCooldown", "Your teleport is currently on cooldown. You'll have to wait {0} for your next teleport."},
  711. {"HomeTPCooldownBypass", "Your teleport was currently on cooldown. You chose to bypass that by paying {0} from your balance."},
  712. {"HomeTPCooldownBypassF", "Your teleport is currently on cooldown. You do not have sufficient funds - {0} - to bypass."},
  713. {"HomeTPCooldownBypassP", "You may choose to pay {0} to bypass this cooldown." },
  714. {"HomeTPCooldownBypassP2", "Type /home NAME {0}." },
  715. {"HomeTPLimitReached", "You have reached the daily limit of {0} teleports today!"},
  716. {"HomeTPAmount", "You have {0} home teleports left today!"},
  717. {"HomesListWiped", "You have wiped all the saved home locations!"},
  718. {"HomeTPBuildingBlocked", "You can't set your home if you are not allowed to build in this zone!"},
  719. {"HomeTPSwimming", "You can't set your home while swimming!"},
  720. {"HomeTPCrafting", "You can't set your home while crafting!"},
  721. {"Request", "You've requested a teleport to {0}!"},
  722. {"RequestTarget", "{0} requested to be teleported to you! Use '/tpa' to accept!"},
  723. {"RequestTargetOff", "Your request has been cancelled as the target is offline now." },
  724. {"TPR_NoClan_NoFriend_NoTeam", "This command is only available to friends or teammates or clanmates!"},
  725. {"PendingRequest", "You already have a request pending, cancel that request or wait until it gets accepted or times out!"},
  726. {"PendingRequestTarget", "The player you wish to teleport to already has a pending request, try again later!"},
  727. {"NoPendingRequest", "You have no pending teleport request!"},
  728. {"AcceptOnRoof", "You can't accept a teleport while you're on a ceiling, get to ground level!"},
  729. {"Accept", "{0} has accepted your teleport request! Teleporting in {1} seconds!"},
  730. {"AcceptTarget", "You've accepted the teleport request of {0}!"},
  731. {"AcceptToggleOff", "You've disabled automatic /tpa!"},
  732. {"AcceptToggleOn", "You've enabled automatic /tpa!"},
  733. {"NotAllowed", "You are not allowed to use this command!"},
  734. {"Success", "You teleported to {0}!"},
  735. {"SuccessTarget", "{0} teleported to you!"},
  736. {"Cancelled", "Your teleport request to {0} was cancelled!"},
  737. {"CancelledTarget", "{0} teleport request was cancelled!"},
  738. {"TPCancelled", "Your teleport was cancelled!"},
  739. {"TPCancelledTarget", "{0} cancelled teleport!"},
  740. {"TPYouCancelledTarget", "You cancelled {0} teleport!"},
  741. {"TimedOut", "{0} did not answer your request in time!"},
  742. {"TimedOutTarget", "You did not answer {0}'s teleport request in time!"},
  743. {"TargetDisconnected", "{0} has disconnected, your teleport was cancelled!"},
  744. {"TPRCooldown", "Your teleport requests are currently on cooldown. You'll have to wait {0} to send your next teleport request."},
  745. {"TPRCooldownBypass", "Your teleport request was on cooldown. You chose to bypass that by paying {0} from your balance."},
  746. {"TPRCooldownBypassF", "Your teleport is currently on cooldown. You do not have sufficient funds - {0} - to bypass."},
  747. {"TPRCooldownBypassP", "You may choose to pay {0} to bypass this cooldown." },
  748. {"TPMoney", "{0} deducted from your account!"},
  749. {"TPNoMoney", "You do not have {0} in any account!"},
  750. {"TPRCooldownBypassP2", "Type /tpr {0}." },
  751. {"TPRCooldownBypassP2a", "Type /tpr NAME {0}." },
  752. {"TPRLimitReached", "You have reached the daily limit of {0} teleport requests today!"},
  753. {"TPRAmount", "You have {0} teleport requests left today!"},
  754. {"TPRTarget", "Your target is currently not available!"},
  755. {"TPDead", "You can't teleport while being dead!"},
  756. {"TPWounded", "You can't teleport while wounded!"},
  757. {"TPTooCold", "You're too cold to teleport!"},
  758. {"TPTooHot", "You're too hot to teleport!"},
  759. {"TPBoat", "You can't teleport while on a boat!"},
  760. {"TPHostile", "Can't teleport to outpost or bandit when hostile!"},
  761. {"TPJunkpile", "You can't teleport from a junkpile!"},
  762. {"HostileTimer", "Teleport available in {0} minutes."},
  763. {"TPMounted", "You can't teleport while seated!"},
  764. //{"TPInsideTerrainFrom", "You can't teleport while inside terrain!"},
  765. //{"TPInsideTerrainTo", "You can't teleport into a location that is inside terrain!"},
  766. {"TPBuildingBlocked", "You can't teleport while in a building blocked zone!"},
  767. {"TPAboveWater", "You can't teleport while above water!"},
  768. {"TPTargetBuildingBlocked", "You can't teleport in a building blocked zone!"},
  769. {"TPTargetInsideBlock", "You can't teleport into a foundation!"},
  770. {"TPTargetInsideEntity", "You can't teleport into another entity!"},
  771. {"TPTargetInsideRock", "You can't teleport into a rock!"},
  772. {"TPSwimming", "You can't teleport while swimming!"},
  773. {"TPCargoShip", "You can't teleport from the cargo ship!"},
  774. {"TPOilRig", "You can't teleport from the oil rig!"},
  775. {"TPExcavator", "You can't teleport from the excavator!"},
  776. {"TPHotAirBalloon", "You can't teleport to or from a hot air balloon!"},
  777. {"TPLift", "You can't teleport while in an elevator or bucket lift!"},
  778. {"TPBucketLift", "You can't teleport while in a bucket lift!"},
  779. {"TPRegLift", "You can't teleport while in an elevator!"},
  780. {"TPSafeZone", "You can't teleport from a safezone!"},
  781. {"TPFlagZone", "You can't teleport from this zone!"},
  782. {"TPNoEscapeBlocked", "You can't teleport while blocked!"},
  783. {"TPCrafting", "You can't teleport while crafting!"},
  784. {"TPBlockedItem", "You can't teleport while carrying: {0}!"},
  785. {"TPHomeSafeZoneOnly", "You can only teleport home from within a safe zone!" },
  786. {"TooCloseToMon", "You can't teleport so close to the {0}!"},
  787. {"TooCloseToCave", "You can't teleport so close to a cave!"},
  788. {"HomeTooCloseToCave", "You can't set home so close to a cave!"},
  789. {"HomeTooCloseToMon", "You can't set home so close to a monument!"},
  790. {"CannotTeleportFromHome", "You must leave your base to be able to teleport!"},
  791. {"WaitGlobalCooldown", "You must wait {0} on your global teleport cooldown!" },
  792. {"DM_TownTP", "You teleported to {0}!"},
  793. {"DM_TownTPNoLocation", "<color=yellow>{0}</color> location is currently not set!"},
  794. {"DM_TownTPDisabled", "<color=yellow>{0}</color> is currently disabled in config file!"},
  795. {"DM_TownTPLocation", "You have set the <color=yellow>{0}</color> location to {1}!"},
  796. {"DM_TownTPCreated", "You have created the command: <color=yellow>{0}</color>"},
  797. {"DM_TownTPRemoved", "You have removed the command: <color=yellow>{0}</color>"},
  798. {"DM_TownTPDoesNotExist", "Command does not exist: <color=yellow>{0}</color>"},
  799. {"DM_TownTPExists", "Command <color=yellow>{0}</color> already exists!"},
  800. {"DM_TownTPLocationsCleared", "You have cleared all locations for {0}!"},
  801. {"DM_TownTPStarted", "Teleporting to {0} in {1} seconds!"},
  802. {"DM_TownTPCooldown", "Your teleport is currently on cooldown. You'll have to wait {0} for your next teleport."},
  803. {"DM_TownTPCooldownBypass", "Your teleport request was on cooldown. You chose to bypass that by paying {0} from your balance."},
  804. {"DM_TownTPCooldownBypassF", "Your teleport is currently on cooldown. You do not have sufficient funds ({0}) to bypass."},
  805. {"DM_TownTPCooldownBypassP", "You may choose to pay {0} to bypass this cooldown." },
  806. {"DM_TownTPCooldownBypassP2", "Type <color=yellow>/{0} {1}</color>" },
  807. {"DM_TownTPLimitReached", "You have reached the daily limit of {0} teleports today! You'll have to wait {1} for your next teleport."},
  808. {"DM_TownTPAmount", "You have {0} <color=yellow>{1}</color> teleports left today!"},
  809.  
  810. { "Days", "Days" },
  811. { "Hours", "Hours" },
  812. { "Minutes", "Minutes" },
  813. { "Seconds", "Seconds" },
  814.  
  815. {"Interrupted", "Your teleport was interrupted!"},
  816. {"InterruptedTarget", "{0}'s teleport was interrupted!"},
  817. {"Unlimited", "Unlimited"},
  818. {
  819. "TPInfoGeneral", string.Join(NewLine, new[]
  820. {
  821. "Please specify the module you want to view the info of.",
  822. "The available modules are: ",
  823. })
  824. },
  825. {
  826. "TPHelpGeneral", string.Join(NewLine, new[]
  827. {
  828. "/tpinfo - Shows limits and cooldowns.",
  829. "Please specify the module you want to view the help of.",
  830. "The available modules are: ",
  831. })
  832. },
  833. {
  834. "TPHelpadmintp", string.Join(NewLine, new[]
  835. {
  836. "As an admin you have access to the following commands:",
  837. "/tp \"targetplayer\" - Teleports yourself to the target player.",
  838. "/tp \"player\" \"targetplayer\" - Teleports the player to the target player.",
  839. "/tp x y z - Teleports you to the set of coordinates.",
  840. "/tpl - Shows a list of saved locations.",
  841. "/tpl \"location name\" - Teleports you to a saved location.",
  842. "/tpsave \"location name\" - Saves your current position as the location name.",
  843. "/tpremove \"location name\" - Removes the location from your saved list.",
  844. "/tpb - Teleports you back to the place where you were before teleporting.",
  845. "/home radius \"radius\" - Find all homes in radius.",
  846. "/home delete \"player name|id\" \"home name\" - Remove a home from a player.",
  847. "/home tp \"player name|id\" \"name\" - Teleports you to the home location with the name 'name' from the player.",
  848. "/home homes \"player name|id\" - Shows you a list of all homes from the player."
  849. })
  850. },
  851. {
  852. "TPHelphome", string.Join(NewLine, new[]
  853. {
  854. "With the following commands you can set your home location to teleport back to:",
  855. "/home add \"name\" - Saves your current position as the location name.",
  856. "/home list - Shows you a list of all the locations you have saved.",
  857. "/home remove \"name\" - Removes the location of your saved homes.",
  858. "/home \"name\" - Teleports you to the home location."
  859. })
  860. },
  861. {
  862. "TPHelptpr", string.Join(NewLine, new[]
  863. {
  864. "With these commands you can request to be teleported to a player or accept someone else's request:",
  865. "/tpr \"player name\" - Sends a teleport request to the player.",
  866. "/tpa - Accepts an incoming teleport request.",
  867. "/tpat - Toggle automatic /tpa on incoming teleport requests.",
  868. "/tpc - Cancel teleport or request."
  869. })
  870. },
  871. {
  872. "TPSettingsGeneral", string.Join(NewLine, new[]
  873. {
  874. "Please specify the module you want to view the settings of. ",
  875. "The available modules are:",
  876. })
  877. },
  878. {
  879. "TPSettingshome", string.Join(NewLine, new[]
  880. {
  881. "Home System has the current settings enabled:",
  882. "Time between teleports: {0}",
  883. "Daily amount of teleports: {1}",
  884. "Amount of saved Home locations: {2}"
  885. })
  886. },
  887. {
  888. "TPSettingsbandit", string.Join(NewLine, new[]
  889. {
  890. "Bandit System has the current settings enabled:",
  891. "Time between teleports: {0}",
  892. "Daily amount of teleports: {1}"
  893. })
  894. },
  895. {
  896. "TPSettingsoutpost", string.Join(NewLine, new[]
  897. {
  898. "Outpost System has the current settings enabled:",
  899. "Time between teleports: {0}",
  900. "Daily amount of teleports: {1}"
  901. })
  902. },
  903. {
  904. "TPSettingstpr", string.Join(NewLine, new[]
  905. {
  906. "TPR System has the current settings enabled:",
  907. "Time between teleports: {0}",
  908. "Daily amount of teleports: {1}"
  909. })
  910. },
  911. {
  912. "TPSettingstown", string.Join(NewLine, new[]
  913. {
  914. "Town System has the current settings enabled:",
  915. "Time between teleports: {0}",
  916. "Daily amount of teleports: {1}"
  917. })
  918. },
  919. {
  920. "TPSettingsdynamic", string.Join(NewLine, new[]
  921. {
  922. "{0} System has the current settings enabled:",
  923. "Time between teleports: {1}",
  924. "Daily amount of teleports: {2}"
  925. })
  926. },
  927. {"PlayerNotFound", "The specified player couldn't be found please try again!"},
  928. {"MultiplePlayers", "Found multiple players: {0}"},
  929. {"CantTeleportToSelf", "You can't teleport to yourself!"},
  930. {"CantTeleportPlayerToSelf", "You can't teleport a player to himself!"},
  931. {"TeleportPendingTPC", "You can't initiate another teleport while you have a teleport pending! Use /tpc to cancel this."},
  932. {"TeleportPendingTarget", "You can't request a teleport to someone who's about to teleport!"},
  933. {"LocationExists", "A location with this name already exists at {0}!"},
  934. {"LocationExistsNearby", "A location with the name {0} already exists near this position!"},
  935. {"LocationNotFound", "Couldn't find a location with that name!"},
  936. {"NoPreviousLocationSaved", "No previous location saved!"},
  937. {"HomeExists", "You have already saved a home location by this name!"},
  938. {"HomeExistsNearby", "A home location with the name {0} already exists near this position!"},
  939. {"HomeNotFound", "Couldn't find your home with that name!"},
  940. {"InvalidCoordinates", "The coordinates you've entered are invalid!"},
  941. {"InvalidHelpModule", "Invalid module supplied!"},
  942. {"InvalidCharacter", "You have used an invalid character, please limit yourself to the letters a to z and numbers."},
  943. {
  944. "SyntaxCommandTP", string.Join(NewLine, new[]
  945. {
  946. "A Syntax Error Occurred!",
  947. "You can only use the /tp command as follows:",
  948. "/tp \"targetplayer\" - Teleports yourself to the target player.",
  949. "/tp \"player\" \"targetplayer\" - Teleports the player to the target player.",
  950. "/tp x y z - Teleports you to the set of coordinates.",
  951. "/tp \"player\" x y z - Teleports the player to the set of coordinates."
  952. })
  953. },
  954. {
  955. "SyntaxCommandTPL", string.Join(NewLine, new[]
  956. {
  957. "A Syntax Error Occurred!",
  958. "You can only use the /tpl command as follows:",
  959. "/tpl - Shows a list of saved locations.",
  960. "/tpl \"location name\" - Teleports you to a saved location."
  961. })
  962. },
  963. {
  964. "SyntaxCommandTPSave", string.Join(NewLine, new[]
  965. {
  966. "A Syntax Error Occurred!",
  967. "You can only use the /tpsave command as follows:",
  968. "/tpsave \"location name\" - Saves your current position as 'location name'."
  969. })
  970. },
  971. {
  972. "SyntaxCommandTPRemove", string.Join(NewLine, new[]
  973. {
  974. "A Syntax Error Occurred!",
  975. "You can only use the /tpremove command as follows:",
  976. "/tpremove \"location name\" - Removes the location with the name 'location name'."
  977. })
  978. },
  979. {
  980. "SyntaxCommandTPN", string.Join(NewLine, new[]
  981. {
  982. "A Syntax Error Occurred!",
  983. "You can only use the /tpn command as follows:",
  984. "/tpn \"targetplayer\" - Teleports yourself the default distance behind the target player.",
  985. "/tpn \"targetplayer\" \"distance\" - Teleports you the specified distance behind the target player."
  986. })
  987. },
  988. {
  989. "SyntaxCommandSetHome", string.Join(NewLine, new[]
  990. {
  991. "A Syntax Error Occurred!",
  992. "You can only use the /home add command as follows:",
  993. "/home add \"name\" - Saves the current location as your home with the name 'name'."
  994. })
  995. },
  996. {
  997. "SyntaxCommandRemoveHome", string.Join(NewLine, new[]
  998. {
  999. "A Syntax Error Occurred!",
  1000. "You can only use the /home remove command as follows:",
  1001. "/home remove \"name\" - Removes the home location with the name 'name'."
  1002. })
  1003. },
  1004. {
  1005. "SyntaxCommandHome", string.Join(NewLine, new[]
  1006. {
  1007. "A Syntax Error Occurred!",
  1008. "You can only use the /home command as follows:",
  1009. "/home \"name\" - Teleports yourself to your home with the name 'name'.",
  1010. "/home \"name\" pay - Teleports yourself to your home with the name 'name', avoiding cooldown by paying for it.",
  1011. "/home add \"name\" - Saves the current location as your home with the name 'name'.",
  1012. "/home list - Shows you a list of all your saved home locations.",
  1013. "/home remove \"name\" - Removes the home location with the name 'name'."
  1014. })
  1015. },
  1016. {
  1017. "SyntaxCommandHomeAdmin", string.Join(NewLine, new[]
  1018. {
  1019. "/home radius \"radius\" - Shows you a list of all homes in radius(10).",
  1020. "/home delete \"player name|id\" \"name\" - Removes the home location with the name 'name' from the player.",
  1021. "/home tp \"player name|id\" \"name\" - Teleports you to the home location with the name 'name' from the player.",
  1022. "/home homes \"player name|id\" - Shows you a list of all homes from the player."
  1023. })
  1024. },
  1025. {
  1026. "SyntaxCommandTown", string.Join(NewLine, new[]
  1027. {
  1028. "A Syntax Error Occurred!",
  1029. "You can only use the /town command as follows:",
  1030. "/town - Teleports yourself to town.",
  1031. "/town pay - Teleports yourself to town, paying the penalty."
  1032. })
  1033. },
  1034. {
  1035. "SyntaxCommandTownAdmin", string.Join(NewLine, new[]
  1036. {
  1037. "/town set - Saves the current location as town.",
  1038. })
  1039. },
  1040. {
  1041. "SyntaxCommandOutpost", string.Join(NewLine, new[]
  1042. {
  1043. "A Syntax Error Occurred!",
  1044. "You can only use the /outpost command as follows:",
  1045. "/outpost - Teleports yourself to the Outpost.",
  1046. "/outpost pay - Teleports yourself to the Outpost, paying the penalty."
  1047. })
  1048. },
  1049. {
  1050. "SyntaxCommandOutpostAdmin", string.Join(NewLine, new[]
  1051. {
  1052. "/outpost set - Saves the current location as Outpost.",
  1053. })
  1054. },
  1055. {
  1056. "SyntaxCommandBandit", string.Join(NewLine, new[]
  1057. {
  1058. "A Syntax Error Occurred!",
  1059. "You can only use the /bandit command as follows:",
  1060. "/bandit - Teleports yourself to the Bandit Town.",
  1061. "/bandit pay - Teleports yourself to the Bandit Town, paying the penalty."
  1062. })
  1063. },
  1064. {
  1065. "SyntaxCommandBanditAdmin", string.Join(NewLine, new[]
  1066. {
  1067. "/bandit set - Saves the current location as Bandit Town.",
  1068. })
  1069. },
  1070. {
  1071. "SyntaxCommandHomeDelete", string.Join(NewLine, new[]
  1072. {
  1073. "A Syntax Error Occurred!",
  1074. "You can only use the /home delete command as follows:",
  1075. "/home delete \"player name|id\" \"name\" - Removes the home location with the name 'name' from the player."
  1076. })
  1077. },
  1078. {
  1079. "SyntaxCommandHomeAdminTP", string.Join(NewLine, new[]
  1080. {
  1081. "A Syntax Error Occurred!",
  1082. "You can only use the /home tp command as follows:",
  1083. "/home tp \"player name|id\" \"name\" - Teleports you to the home location with the name 'name' from the player."
  1084. })
  1085. },
  1086. {
  1087. "SyntaxCommandHomeHomes", string.Join(NewLine, new[]
  1088. {
  1089. "A Syntax Error Occurred!",
  1090. "You can only use the /home homes command as follows:",
  1091. "/home homes \"player name|id\" - Shows you a list of all homes from the player."
  1092. })
  1093. },
  1094. {
  1095. "SyntaxCommandListHomes", string.Join(NewLine, new[]
  1096. {
  1097. "A Syntax Error Occurred!",
  1098. "You can only use the /home list command as follows:",
  1099. "/home list - Shows you a list of all your saved home locations."
  1100. })
  1101. },
  1102. {
  1103. "SyntaxCommandTPR", string.Join(NewLine, new[]
  1104. {
  1105. "A Syntax Error Occurred!",
  1106. "You can only use the /tpr command as follows:",
  1107. "/tpr \"player name\" - Sends out a teleport request to 'player name'."
  1108. })
  1109. },
  1110. {
  1111. "SyntaxCommandTPA", string.Join(NewLine, new[]
  1112. {
  1113. "A Syntax Error Occurred!",
  1114. "You can only use the /tpa command as follows:",
  1115. "/tpa - Accepts an incoming teleport request."
  1116. })
  1117. },
  1118. {
  1119. "SyntaxCommandTPC", string.Join(NewLine, new[]
  1120. {
  1121. "A Syntax Error Occurred!",
  1122. "You can only use the /tpc command as follows:",
  1123. "/tpc - Cancels an teleport request."
  1124. })
  1125. },
  1126. {
  1127. "SyntaxConsoleCommandToPos", string.Join(NewLine, new[]
  1128. {
  1129. "A Syntax Error Occurred!",
  1130. "You can only use the teleport.topos console command as follows:",
  1131. " > teleport.topos \"player\" x y z"
  1132. })
  1133. },
  1134. {
  1135. "SyntaxConsoleCommandToPlayer", string.Join(NewLine, new[]
  1136. {
  1137. "A Syntax Error Occurred!",
  1138. "You can only use the teleport.toplayer console command as follows:",
  1139. " > teleport.toplayer \"player\" \"target player\""
  1140. })
  1141. },
  1142. {"LogTeleport", "{0} teleported to {1}."},
  1143. {"LogTeleportPlayer", "{0} teleported {1} to {2}."},
  1144. {"LogTeleportBack", "{0} teleported back to previous location."}
  1145. };
  1146.  
  1147. foreach (var key in config.DynamicCommands.Keys)
  1148. {
  1149. en[key] = key;
  1150. }
  1151.  
  1152. lang.RegisterMessages(en, this, "en");
  1153.  
  1154. var ru = new Dictionary<string, string>
  1155. {
  1156. {"ErrorTPR", "Телепорт к {0} блокирован ({1})"},
  1157. {"AdminTP", "Вы телепортированы к {0}!"},
  1158. {"AdminTPTarget", "{0} телепортировал вас!"},
  1159. {"AdminTPPlayers", "Вы телепортировали {0} к {1}!"},
  1160. {"AdminTPPlayer", "{0} телепортировал вас к {1}!"},
  1161. {"AdminTPPlayerTarget", "{0} телепортировал {1} к вам!"},
  1162. {"AdminTPCoordinates", "Вы телепортированы к {0}!"},
  1163. {"AdminTPTargetCoordinates", "Вы телепортировали {0} к {1}!"},
  1164. {"AdminTPOutOfBounds", "Вы пытались телепортироваться к координатам вне границ карты!"},
  1165. {"AdminTPBoundaries", "Значения X и Z должны быть между -{0} и {0}, а значение Y между -100 и 2000!"},
  1166. {"AdminTPLocation", "Вы телепортированы к {0}!"},
  1167. {"AdminTPLocationSave", "Вы сохранили текущее местоположение!"},
  1168. {"AdminTPLocationRemove", "Вы удалили местоположение {0}!"},
  1169. {"AdminLocationList", "Доступны следующие местоположения:"},
  1170. {"AdminLocationListEmpty", "Вы не сохранили никаких местоположений!"},
  1171. {"AdminTPBack", "Вы телепортированы назад, в ваше предыдущее местоположение!"},
  1172. {"AdminTPBackSave", "Ваше предыдущее местоположение сохранено, используйте <color=yellow>/tpb</color>, чтобы телепортироваться назад!"},
  1173. {"AdminTPTargetCoordinatesTarget", "{0} телепортировал вас к {1}!"},
  1174. {"AdminTPConsoleTP", "Вы были телепортированы к {0}"},
  1175. {"AdminTPConsoleTPPlayer", "Вы были телепортированы к {0}"},
  1176. {"AdminTPConsoleTPPlayerTarget", "{0} был телепортирован к вам!"},
  1177. {"HomeTP", "Вы телепортированы в ваш дом '{0}'!"},
  1178. {"HomeAdminTP", "Вы телепортированы к дому '{1}' принадлежащему {0}!"},
  1179. {"HomeSave", "Вы сохранили текущее местоположение как ваш дом!"},
  1180. {"HomeNoFoundation", "Использовать местоположение в качестве дома разрешено только на фундаменте!"},
  1181. {"HomeFoundationNotOwned", "Вы не можете использовать команду home в чужом доме."},
  1182. {"HomeFoundationUnderneathFoundation", "Вы не можете использовать команду home на фундаменте, который находится под другим фундаментом."},
  1183. {"HomeFoundationNotFriendsOwned", "Вы, или ваш друг, должны быть владельцем дома, чтобы использовать команду home!"},
  1184. {"HomeRemovedInvalid", "Ваш дом '{0}' был удалён потому, что не на фундаменте, или у фундамента новый владелец!"},
  1185. {"HighWallCollision", "Столкновение Высоких Стен!"},
  1186. {"HomeRemovedInsideBlock", "Ваш дом '{0}' был удалён потому, что внутри фундамента!"},
  1187. {"HomeRemove", "Вы удалили свой дом {0}!"},
  1188. {"HomeDelete", "Вы удалили дом '{1}' принадлежащий {0}!"},
  1189. {"HomeList", "Доступны следующие дома:"},
  1190. {"HomeListEmpty", "Вы не сохранили ни одного дома!"},
  1191. {"HomeMaxLocations", "Невозможно установить здесь ваш дом, вы достигли лимита в {0} домов!"},
  1192. {"HomeQuota", "Вы установили {0} из {1} максимально возможных домов!"},
  1193. {"HomeTPStarted", "Телепортация в ваш дом {0} через {1} секунд!"},
  1194. {"PayToTown", "Стандартный платеж {0} распространяется на все телепорты в город!"},
  1195. {"PayToTPR", "Стандартный платеж {0} распространяется на все tpr'ы!"},
  1196. {"HomeTPCooldown", "Ваш телепорт перезаряжается. Вам необходимо подождать {0} до следующей телепортации."},
  1197. {"HomeTPCooldownBypass", "Ваш телепорт был на перезарядке. Вы выбрали избежать ожидания, оплатив {0} с вашего баланса."},
  1198. {"HomeTPCooldownBypassF", "Ваш телепорт перезаряжается. У вас недостаточно средств - {0} - чтобы избежать ожидания."},
  1199. {"HomeTPCooldownBypassP", "Вы можете выбрать оплатить {0} чтобы избежать ожидания перезарядки." },
  1200. {"HomeTPCooldownBypassP2", "Напишите <color=yellow>/home \"название дома\" {0}</color>." },
  1201. {"HomeTPLimitReached", "Вы исчерпали ежедневный лимит {0} телепортаций сегодня!"},
  1202. {"HomeTPAmount", "У вас осталось {0} телепортаций домой сегодня!"},
  1203. {"HomesListWiped", "Вы очистили все местоположения, сохранённые как дом!"},
  1204. {"HomeTPBuildingBlocked", "Вы не можете сохранить местоположение в качестве дома, если у вас нет прав на строительство в этой зоне!"},
  1205. {"HomeTPSwimming", "Вы не можете устанавливать местоположение а качестве дома пока плывёте!"},
  1206. {"HomeTPCrafting", "Вы не можете устанавливать местоположение а качестве дома в процессе крафта!"},
  1207. {"Request", "Вы запросили телепортацию к {0}!"},
  1208. {"RequestTarget", "{0} запросил телепортацию к вам! Используйте <color=yellow>/tpa</color>, чтобы принять!"},
  1209. {"RequestTargetOff", "Ваш запрос был отменен, так как цель сейчас не в сети." },
  1210. {"TPR_NoClan_NoFriend_NoTeam", "Эта команда доступна только друзьям, участникам команды или клана!"},
  1211. {"PendingRequest", "У вас уже есть активный запрос, отмените его, ожидайте подтверждения, либо отмены по таймауту!"},
  1212. {"PendingRequestTarget", "У игрока, к которому вы хотите телепортироваться уже есть активный запрос, попробуйте позже!"},
  1213. {"NoPendingRequest", "У вас нет активных запросов на телепортацию!"},
  1214. {"AcceptOnRoof", "Вы не можете принять запрос на телепортацию стоя на потолке, спуститесь на уровень фундамента!"},
  1215. {"Accept", "{0} принял ваш запрос! Телепортация через {1} секунд!"},
  1216. {"AcceptTarget", "Вы приняли запрос на телепортацию {0}!"},
  1217. {"AcceptToggleOff", "Вы отключили автоматическое /tpa!"},
  1218. {"AcceptToggleOn", "Вы включили автоматическое /tpa!"},
  1219. {"NotAllowed", "Вам не разрешено использовать эту команду!"},
  1220. {"Success", "Вы телепортированы к {0}!"},
  1221. {"SuccessTarget", "{0} телепортирован к вам!"},
  1222. {"Cancelled", "Ваш запрос на телепортацию к {0} был отменён!"},
  1223. {"CancelledTarget", "Запрос на телепортацию {0} был отменён!"},
  1224. {"TPCancelled", "Ваша телепортация отменена!"},
  1225. {"TPCancelledTarget", "{0} отменил телепортацию!"},
  1226. {"TPYouCancelledTarget", "Вы отменили телепортацию {0}!"},
  1227. {"TimedOut", "{0} не ответил на ваш запрос во время!"},
  1228. {"TimedOutTarget", "Вы не ответили вовремя на запрос телепортации от {0}!"},
  1229. {"TargetDisconnected", "{0} отключился, ваша телепортация отменена!"},
  1230. {"TPRCooldown", "Ваши запросы на телепортацию в данный момент на перезарядке. Вам необходимо подождать {0} прежде чем отправить следующий запрос."},
  1231. {"TPRCooldownBypass", "Ваши запросы на телепортацию были на перезарядке. Вы выбрали избежать ожидания, оплатив {0} с вашего баланса."},
  1232. {"TPRCooldownBypassF", "Ваши запросы на телепортацию в данный момент на перезарядке. У вас недостаточно средств - {0} - чтобы избежать ожидания."},
  1233. {"TPRCooldownBypassP", "Вы можете выбрать оплатить {0} чтобы избежать ожидания перезарядки." },
  1234. {"TPMoney", "{0} списано с вашего аккаунта!"},
  1235. {"TPNoMoney", "У вас нет {0} ни на одном аккаунте!"},
  1236. {"TPRCooldownBypassP2", "Напишите <color=yellow>/tpr {0}</color>." },
  1237. {"TPRCooldownBypassP2a", "Напишите <color=yellow>/tpr \"имя игрока\" {0}</color>." },
  1238. {"TPRLimitReached", "Вы исчерпали ежедневный лимит {0} запросов на телепортацию сегодня!"},
  1239. {"TPRAmount", "У вас осталось {0} запросов на телепортацию на сегодня!"},
  1240. {"TPRTarget", "Ваша цель в данный момент не доступна!"},
  1241. {"TPDead", "Вы не можете телепортироваться, пока мертвы!"},
  1242. {"TPWounded", "Вы не можете телепортироваться, будучи раненым!"},
  1243. {"TPTooCold", "Вам слишком холодно для телепортации!"},
  1244. {"TPTooHot", "Вам слишком жарко для телепортации!"},
  1245. {"TPBoat", "Вы не можете телепортироваться находясь на лодке!"},
  1246. {"TPHostile", "Вы не можете телепортироваться в Город NPC или Лагерь бандитов пока враждебны!"},
  1247. {"TPJunkpile", "Вы не можете телепортироваться с кучи мусора"},
  1248. {"HostileTimer", "Телепорт станет доступен через {0} минут."},
  1249. {"TPMounted", "Вы не можете телепортироваться, когда сидите!"},
  1250. {"TPBuildingBlocked", "Вы не можете телепортироваться, находясь в зоне блокировки строительства!"},
  1251. //{"TPInsideTerrainFrom", "Вы не можете телепортироваться, находясь внутри местности!"},
  1252. //{"TPInsideTerrainTo", "Вы не можете телепортироваться в место, которое находится внутри местности!"},
  1253. {"TPAboveWater", "Вы не можете телепортироваться находясь над водой!"},
  1254. {"TPTargetBuildingBlocked", "Вы не можете телепортироваться в зону, где блокировано строительство!"},
  1255. {"TPTargetInsideBlock", "Вы не можете телепортироваться в фундамент!"},
  1256. {"TPTargetInsideRock", "Вы не можете телепортироваться в скалу!"},
  1257. {"TPSwimming", "Вы не можете телепортироваться, пока плывёте!"},
  1258. {"TPCargoShip", "Вы не можете телепортироваться с грузового корабля!"},
  1259. {"TPOilRig", "Вы не можете телепортироваться с нефтяной вышки!"},
  1260. {"TPExcavator", "Вы не можете телепортироваться с экскаватора!"},
  1261. {"TPHotAirBalloon", "Вы не можете телепортироваться с, или на воздушный шар!"},
  1262. {"TPLift", "Вы не можете телепортироваться находясь в лифте или подъемнике!"},
  1263. {"TPBucketLift", "Вы не можете телепортироваться находясь в ковшевом подъемнике!"},
  1264. {"TPRegLift", "Вы не можете телепортироваться находясь в лифте!"},
  1265. {"TPSafeZone", "Вы не можете телепортироваться из безопасной зоны!"},
  1266. {"TPFlagZone", "Вы не можете телепортироваться из этой зоны!"},
  1267. {"TPNoEscapeBlocked", "Вы не можете телепортироваться пока активна блокировка!"},
  1268. {"TPCrafting", "Вы не можете телепортироваться в процессе крафта!"},
  1269. {"TPBlockedItem", "Вы не можете телепортироваться пока несёте: {0}!"},
  1270. {"TooCloseToMon", "Вы не можете телепортироваться так близко к {0}!"},
  1271. {"TPHomeSafeZoneOnly", "Вы можете телепортироваться домой только из безопасной зоны!" },
  1272. {"TooCloseToCave", "Вы не можете телепортироваться так близко к пещере!"},
  1273. {"HomeTooCloseToCave", "Вы не можете сохранить местоположение в качестве дома так близко к пещере!"},
  1274. {"HomeTooCloseToMon", "Вы не можете сохранить местоположение в качестве дома так близко к монументу!"},
  1275. {"CannotTeleportFromHome", "Вы должны выйти из вашей базы, прежде чем телепортироваться!"},
  1276. {"WaitGlobalCooldown", "Вы должны подождать {0}, пока ваш глобальный телепорт перезаряжается!" },
  1277.  
  1278. {"DM_TownTP", "Вы телепортированы в {0}!"},
  1279. {"DM_TownTPNoLocation", "Местоположение <color=yellow>{0}</color> в данный момент не установлено!"},
  1280. {"DM_TownTPDisabled", "<color=yellow>{0}</color> в данный момент отключен в файле настройек!"},
  1281. {"DM_TownTPLocation", "Вы установили местоположение <color=yellow>{0}</color> в {1}!"},
  1282. {"DM_TownTPCreated", "Вы создали команду: <color=yellow>{0}</color>"},
  1283. {"DM_TownTPRemoved", "Вы удалили команду: <color=yellow>{0}</color>"},
  1284. {"DM_TownTPDoesNotExist", "Команда не существует: <color=yellow>{0}</color>"},
  1285. {"DM_TownTPExists", "Команда <color=yellow>{0}</color> уже сущуствует!"},
  1286. {"DM_TownTPLocationsCleared", "You have cleared all locations for {0}!"},
  1287. {"DM_TownTPStarted", "Телепортация в {0} через {1} секунд!"},
  1288. {"DM_TownTPCooldown", "Ваш телепорт перезаряжается. Вам необходимо подождать {0} до следующей телепортации."},
  1289. {"DM_TownTPCooldownBypass", "Ваш телепорт был на перезарядке. Вы выбрали избежать ожидания, оплатив {0} с вашего баланса."},
  1290. {"DM_TownTPCooldownBypassF", "Ваш телепорт перезаряжается. У вас недостаточно средств ({0}) чтобы избежать ожидания."},
  1291. {"DM_TownTPCooldownBypassP", "Вы можете выбрать оплатить {0} чтобы избежать ожидания перезарядки." },
  1292. {"DM_TownTPCooldownBypassP2", "Введите <color=yellow>/{0} {1}</color>" },
  1293. {"DM_TownTPLimitReached", "Вы исчерпали ежедневный лимит {0} телепортаций сегодня! Вам необходимо подождать {1} до следующей телепортации."},
  1294. {"DM_TownTPAmount", "У вас осталось {0} телепортаций <color=yellow>{1}</color> сегодня!"},
  1295.  
  1296. {"Days", "дней" },
  1297. {"Hours", "часов" },
  1298. {"Minutes", "минут" },
  1299. {"Seconds", "секунд" },
  1300.  
  1301. {"Interrupted", "Ваша телепортация была прервана!"},
  1302. {"InterruptedTarget", "Телепортация {0} была прервана!"},
  1303. {"Unlimited", "Не ограничено"},
  1304. {
  1305. "TPInfoGeneral", string.Join(NewLine, new[]
  1306. {
  1307. "Пожалуйста, укажите модуль, о котором вы хотите просмотреть информацию.",
  1308. "Доступные модули: ",
  1309. })
  1310. },
  1311. {
  1312. "TPHelpGeneral", string.Join(NewLine, new[]
  1313. {
  1314. "<color=yellow>/tpinfo</color> - Отображает лимиты и перезарядки.",
  1315. "Пожалуйста, укажите модуль, по которому вы хотите получить помощь.",
  1316. "Доступные модули: ",
  1317. })
  1318. },
  1319. {
  1320. "TPHelpadmintp", string.Join(NewLine, new[]
  1321. {
  1322. "Как админ, вы имеете доступ к следующим командам:",
  1323. "<color=yellow>/tp \"имя игрока\"</color> - Телепортирует вас к указанному игроку.",
  1324. "<color=yellow>/tp \"имя игрока\" \"имя игрока 2\"</color> - Телепортирует игрока с именем 'имя игрока' к игроку 'имя игрока 2'.",
  1325. "<color=yellow>/tp x y z</color> - Телепортирует вас к указанным координатам.",
  1326. "<color=yellow>/tpl</color> - Отображает список сохранённых местоположений.",
  1327. "<color=yellow>/tpl \"название местоположения\"</color> - Телепортирует вас в сохранённое местоположение.",
  1328. "<color=yellow>/tpsave \"название местоположения\"</color> - Сохраняет ваше текущее местоположение с указанным названием.",
  1329. "<color=yellow>/tpremove \"название местоположения\"</color> - Удаляет местоположение из списка сохранённых.",
  1330. "<color=yellow>/tpb</color> - Телепортирует вас назад на место, где вы были перед телепортацией.",
  1331. "<color=yellow>/home radius \"радиус\"</color> - Найти все дома в радиусе.",
  1332. "<color=yellow>/home delete \"имя игрока или ID\" \"название дома\"</color> - Удаляет дом с указанным именем принадлежащий указанному игроку.",
  1333. "<color=yellow>/home tp \"имя игрока или ID\" \"название дома\"</color> - Телепортирует вас в дом игрока с указанным названием принадлежащий указанному игроку.",
  1334. "<color=yellow>/home homes \"имя игрока или ID\"</color> - Отображает вам список всех домов, принадлежащих указанному игроку."
  1335. })
  1336. },
  1337. {
  1338. "TPHelphome", string.Join(NewLine, new[]
  1339. {
  1340. "Используя следующие команды, вы можете установить местоположение вашего дома, чтобы затем в него телепортироваться:",
  1341. "<color=yellow>/home add \"название дома\"</color> - Сохраняет ваше текущее местоположение как ваш дом с указанным названием.",
  1342. "<color=yellow>/home list</color> - Отображает список всех местоположений, сохранённых вами как дом.",
  1343. "<color=yellow>/home remove \"название дома\"</color> - Удаляет расположение сохранённого дома с указанным названием.",
  1344. "<color=yellow>/home \"название дома\"</color> - Телепортирует вас в местоположение дома с указанным названием."
  1345. })
  1346. },
  1347. {
  1348. "TPHelptpr", string.Join(NewLine, new[]
  1349. {
  1350. "Используя эти команды, вы можете отправить запрос на телепортацию к игроку, или принять чей-то запрос:",
  1351. "<color=yellow>/tpr \"имя игрока\"</color> - Отправляет запрос на телепортацию игроку с указанным именем.",
  1352. "<color=yellow>/tpa</color> - Принять входящий запрос на телепортацию.",
  1353. "<color=yellow>/tpat</color> - Вкл./Выкл. автоматическое принятие входящих запросов на телепортацию к вам /tpa.",
  1354. "<color=yellow>/tpc</color> - Отменить запрос на телепортацию."
  1355. })
  1356. },
  1357. {
  1358. "TPSettingsGeneral", string.Join(NewLine, new[]
  1359. {
  1360. "Пожалуйста, укажите модуль, настройки которого вы хотите просмотреть. ",
  1361. "Доступные модули:",
  1362. })
  1363. },
  1364. {
  1365. "TPSettingshome", string.Join(NewLine, new[]
  1366. {
  1367. "Система домов в данный момент имеет следующие включённые параметры:",
  1368. "Время между телепортами: {0}",
  1369. "Ежедневный лимит телепортаций: {1}",
  1370. "Количество сохранённых домов: {2}"
  1371. })
  1372. },
  1373. {
  1374. "TPSettingsbandit", string.Join(NewLine, new[]
  1375. {
  1376. "Система Лагерь бандитов в данный момент имеет следующие включённые параметры:",
  1377. "Время между телепортами: {0}",
  1378. "Ежедневный лимит телепортаций: {1}"
  1379. })
  1380. },
  1381. {
  1382. "TPSettingsoutpost", string.Join(NewLine, new[]
  1383. {
  1384. "Система Город NPC в данный момент имеет следующие включённые параметры:",
  1385. "Время между телепортами: {0}",
  1386. "Ежедневный лимит телепортаций: {1}"
  1387. })
  1388. },
  1389. {
  1390. "TPSettingstpr", string.Join(NewLine, new[]
  1391. {
  1392. "Система TPR в данный момент имеет следующие включённые параметры:",
  1393. "Время между телепортами: {0}",
  1394. "Ежедневный лимит телепортаций: {1}"
  1395. })
  1396. },
  1397. {
  1398. "TPSettingstown", string.Join(NewLine, new[]
  1399. {
  1400. "В Системе Городов включены следующие параметры:",
  1401. "Время между телепортами: {0}",
  1402. "Ежедневный лимит телепортаций: {1}"
  1403. })
  1404. },
  1405. {
  1406. "TPSettingsdynamic", string.Join(NewLine, new[]
  1407. {
  1408. "В Системе {0} включены следующие параметры:",
  1409. "Время между телепортами: {1}",
  1410. "Ежедневный лимит телепортаций: {2}"
  1411. })
  1412. },
  1413. {"PlayerNotFound", "Указанный игрок не обнаружен, пожалуйста попробуйте ещё раз!"},
  1414. {"MultiplePlayers", "Найдено несколько игроков: {0}"},
  1415. {"CantTeleportToSelf", "Вы не можете телепортироваться к самому себе!"},
  1416. {"CantTeleportPlayerToSelf", "Вы не можете телепортровать игрока к самому себе!"},
  1417. {"TeleportPendingTPC", "Вы не можете инициировать телепортацию, пока у вас есть активный запрос! Используйте <color=yellow>/tpc</color> чтобы отменить его."},
  1418. {"TeleportPendingTarget", "Вы не можете отправить запрос к тому, кто в процессе телепортации!"},
  1419. {"LocationExists", "Местоположение с таким названием уже существует в {0}!"},
  1420. {"LocationExistsNearby", "Местоположение с названием {0} уже существует рядом с текущей позицией!"},
  1421. {"LocationNotFound", "Не найдено местоположение с таким названием!"},
  1422. {"NoPreviousLocationSaved", "Предыдущее местоположение не сохранено!"},
  1423. {"HomeExists", "Вы уже сохранили дом с таким названием!"},
  1424. {"HomeExistsNearby", "Дом с названием {0} уже существует рядом с текущей позицией!"},
  1425. {"HomeNotFound", "Дом с таким названием не найден!"},
  1426. {"InvalidCoordinates", "Вы указали неверные координаты!"},
  1427. {"InvalidHelpModule", "Указан неверный модуль!"},
  1428. {"InvalidCharacter", "Вы использовали недопустимый символ, ограничьтесь буквами от a до z и цифрами."},
  1429. {
  1430. "SyntaxCommandTP", string.Join(NewLine, new[]
  1431. {
  1432. "Произошла синтаксическая ошибка!",
  1433. "Использование команды <color=yellow>/tp</color> возможно только следующим образом:",
  1434. "<color=yellow>/tp \"имя игрока\"</color> - Телепортирует вас к указанному игроку.",
  1435. "<color=yellow>/tp \"имя игрока\" \"имя игрока 2\"</color> - Телепортирует игрока с именем 'имя игрока' к игроку 'имя игрока 2'.",
  1436. "<color=yellow>/tp x y z</color> - Телепортирует вас к указанным координатам.",
  1437. "<color=yellow>/tp \"имя игрока\" x y z</color> - Телепортирует игрока с именем 'имя игрока' к указанным координатам."
  1438. })
  1439. },
  1440. {
  1441. "SyntaxCommandTPL", string.Join(NewLine, new[]
  1442. {
  1443. "Произошла синтаксическая ошибка!",
  1444. "Использование команды <color=yellow>/tpl</color> возможно только следующим образом:",
  1445. "<color=yellow>/tpl</color> - Отображает список сохранённых местоположений.",
  1446. "<color=yellow>/tpl \"название местоположения\"</color> - Телепортирует вас в место с указанным названием."
  1447. })
  1448. },
  1449. {
  1450. "SyntaxCommandTPSave", string.Join(NewLine, new[]
  1451. {
  1452. "Произошла синтаксическая ошибка!",
  1453. "Использование команды <color=yellow>/tpsave</color> возможно только следующим образом:",
  1454. "<color=yellow>/tpsave \"название местоположения\"</color> - Сохраняет ваше текущее местоположение с указанным названием."
  1455. })
  1456. },
  1457. {
  1458. "SyntaxCommandTPRemove", string.Join(NewLine, new[]
  1459. {
  1460. "Произошла синтаксическая ошибка!",
  1461. "Использование команды <color=yellow>/tpremove</color> возможно только следующим образом:",
  1462. "<color=yellow>/tpremove \"название местоположения\"</color> - Удаляет местоположение с указанным названием."
  1463. })
  1464. },
  1465. {
  1466. "SyntaxCommandTPN", string.Join(NewLine, new[]
  1467. {
  1468. "Произошла синтаксическая ошибка!",
  1469. "Использование команды <color=yellow>/tpn</color> возможно только следующим образом:",
  1470. "<color=yellow>/tpn \"имя игрока\"</color> - Телепортирует вас на расстояние по умолчанию позади игрока с указанным именем.",
  1471. "<color=yellow>/tpn \"имя игрока\" \"расстояние\"</color> - Телепортирует вас на указанное расстояние позади игрока с указанным именем."
  1472. })
  1473. },
  1474. {
  1475. "SyntaxCommandSetHome", string.Join(NewLine, new[]
  1476. {
  1477. "Произошла синтаксическая ошибка!",
  1478. "Использование команды <color=yellow>/home add</color> возможно только следующим образом:",
  1479. "<color=yellow>/home add \"название\"</color> - Сохраняет ваше текущее местоположение как ваш дом с указанным названием."
  1480. })
  1481. },
  1482. {
  1483. "SyntaxCommandRemoveHome", string.Join(NewLine, new[]
  1484. {
  1485. "Произошла синтаксическая ошибка!",
  1486. "Использование команды <color=yellow>/home remove</color> возможно только следующим образом:",
  1487. "<color=yellow>/home remove \"название\"</color> - Удаляет местоположение дома с указанным названием."
  1488. })
  1489. },
  1490. {
  1491. "SyntaxCommandHome", string.Join(NewLine, new[]
  1492. {
  1493. "Произошла синтаксическая ошибка!",
  1494. "Использование команды <color=yellow>/home</color> возможно только следующим образом:",
  1495. "<color=yellow>/home \"название\"</color> - Телепортирует вас в ваш дом с указанным названием.",
  1496. "<color=yellow>/home \"название\" pay</color> - Телепортирует вас в ваш дом с указанным названием, избегая перезарядки, заплатив за это.",
  1497. "<color=yellow>/home add \"название\"</color> - Сохраняет ваше текущее местоположение как ваш дом с указанным названием.",
  1498. "<color=yellow>/home list</color> - Отображает список всех местоположений, сохранённых вами как дом.",
  1499. "<color=yellow>/home remove \"название\"</color> - Удаляет местоположение дома с указанным названием."
  1500. })
  1501. },
  1502. {
  1503. "SyntaxCommandHomeAdmin", string.Join(NewLine, new[]
  1504. {
  1505. "<color=yellow>/home radius \"радиус\"</color> - Отображает список всех домов в радиусе(10).",
  1506. "<color=yellow>/home delete \"имя игрока или ID\" \"название\"</color> - Удаляет дом с указанным названием, принадлежащий указанному игроку.",
  1507. "<color=yellow>/home tp \"имя игрока или ID\" \"название\"</color> - Телепортирует вас в дом с указанным названием, принадлежащий указанному игроку.",
  1508. "<color=yellow>/home homes \"имя игрока или ID\"</color> - Отображает вам список всех домов, принадлежащих указанному игроку."
  1509. })
  1510. },
  1511. {
  1512. "SyntaxCommandTown", string.Join(NewLine, new[]
  1513. {
  1514. "Произошла синтаксическая ошибка!",
  1515. "Использование команды <color=yellow>/town</color> возможно только следующим образом:",
  1516. "<color=yellow>/town</color> - Телепортирует вас в Город.",
  1517. "<color=yellow>/town pay</color> - Телепортирует вас в Город с оплатой штрафа."
  1518. })
  1519. },
  1520. {
  1521. "SyntaxCommandTownAdmin", string.Join(NewLine, new[]
  1522. {
  1523. "<color=yellow>/town set</color> - Сохраняет текущее местоположение как Город.",
  1524. })
  1525. },
  1526. {
  1527. "SyntaxCommandOutpost", string.Join(NewLine, new[]
  1528. {
  1529. "Произошла синтаксическая ошибка!",
  1530. "Использование команды <color=yellow>/outpost</color> возможно только следующим образом:",
  1531. "<color=yellow>/outpost</color> - Телепортирует вас в Город NPC.",
  1532. "<color=yellow>/outpost pay</color> - Телепортирует вас в Город NPC с оплатой штрафа."
  1533. })
  1534. },
  1535. {
  1536. "SyntaxCommandOutpostAdmin", string.Join(NewLine, new[]
  1537. {
  1538. "<color=yellow>/outpost set</color> - Сохраняет текущее местоположение как Город NPC.",
  1539. })
  1540. },
  1541. {
  1542. "SyntaxCommandBandit", string.Join(NewLine, new[]
  1543. {
  1544. "Произошла синтаксическая ошибка!",
  1545. "Использование команды <color=yellow>/bandit</color> возможно только следующим образом:",
  1546. "<color=yellow>/bandit</color> - Телепортирует вас в Лагерь бандитов.",
  1547. "<color=yellow>/bandit pay</color> - Телепортирует вас в Лагерь бандитов с оплатой штрафа."
  1548. })
  1549. },
  1550. {
  1551. "SyntaxCommandBanditAdmin", string.Join(NewLine, new[]
  1552. {
  1553. "<color=yellow>/bandit set</color> - Сохраняет текущее местоположение как Лагерь бандитов.",
  1554. })
  1555. },
  1556. {
  1557. "SyntaxCommandHomeDelete", string.Join(NewLine, new[]
  1558. {
  1559. "Произошла синтаксическая ошибка!",
  1560. "Использование команды <color=yellow>/home delete</color> возможно только следующим образом:",
  1561. "<color=yellow>/home delete \"имя игрока или ID\" \"название\"</color> - Удаляет дом с указанным названием, принадлежащий указанному игроку."
  1562. })
  1563. },
  1564. {
  1565. "SyntaxCommandHomeAdminTP", string.Join(NewLine, new[]
  1566. {
  1567. "Произошла синтаксическая ошибка!",
  1568. "Использование команды <color=yellow>/home tp</color> возможно только следующим образом:",
  1569. "<color=yellow>/home tp \"имя игрока или ID\" \"название\"</color> - Телепортирует вас в дом игрока с указанным названием, принадлежащий указанному игроку."
  1570. })
  1571. },
  1572. {
  1573. "SyntaxCommandHomeHomes", string.Join(NewLine, new[]
  1574. {
  1575. "Произошла синтаксическая ошибка!",
  1576. "Использование команды <color=yellow>/home homes</color> возможно только следующим образом:",
  1577. "<color=yellow>/home homes \"имя игрока или ID\"</color> - Отображает вам список всех домов, принадлежащих указанному игроку."
  1578. })
  1579. },
  1580. {
  1581. "SyntaxCommandListHomes", string.Join(NewLine, new[]
  1582. {
  1583. "Произошла синтаксическая ошибка!",
  1584. "Использование команды <color=yellow>/home list</color> возможно только следующим образом:",
  1585. "<color=yellow>/home list</color> - Отображает список всех местоположений, сохранённых вами как дом."
  1586. })
  1587. },
  1588. {
  1589. "SyntaxCommandTPR", string.Join(NewLine, new[]
  1590. {
  1591. "Произошла синтаксическая ошибка!",
  1592. "Использование команды <color=yellow>/tpr</color> возможно только следующим образом:",
  1593. "<color=yellow>/tpr \"имя игрока или ID\"</color> - Отправляет указанному игроку запрос на телепортацию."
  1594. })
  1595. },
  1596. {
  1597. "SyntaxCommandTPA", string.Join(NewLine, new[]
  1598. {
  1599. "Произошла синтаксическая ошибка!",
  1600. "Использование команды <color=yellow>/tpa</color> возможно только следующим образом:",
  1601. "<color=yellow>/tpa</color> - Принять входящий запрос на телепортацию."
  1602. })
  1603. },
  1604. {
  1605. "SyntaxCommandTPC", string.Join(NewLine, new[]
  1606. {
  1607. "Произошла синтаксическая ошибка!",
  1608. "Использование команды <color=yellow>/tpc</color> возможно только следующим образом:",
  1609. "<color=yellow>/tpc</color> - Отменить запрос на телепортацию."
  1610. })
  1611. },
  1612. {
  1613. "SyntaxConsoleCommandToPos", string.Join(NewLine, new[]
  1614. {
  1615. "Произошла синтаксическая ошибка!",
  1616. "Использование консольной команды <color=orange>teleport.topos</color> возможно только следующим образом:",
  1617. " > <color=orange>teleport.topos \"имя игрока\" x y z</color>"
  1618. })
  1619. },
  1620. {
  1621. "SyntaxConsoleCommandToPlayer", string.Join(NewLine, new[]
  1622. {
  1623. "Произошла синтаксическая ошибка!",
  1624. "Использование консольной команды <color=orange>teleport.toplayer</color> возможно только следующим образом:",
  1625. " > <color=orange>teleport.toplayer \"имя игрока или ID\" \"имя игрока 2|id 2\"</color>"
  1626. })
  1627. },
  1628. {"LogTeleport", "{0} телепортирован к {1}."},
  1629. {"LogTeleportPlayer", "{0} телепортировал {1} к {2}."},
  1630. {"LogTeleportBack", "{0} телепортирован назад, в предыдущее местоположение."}
  1631. };
  1632.  
  1633. foreach (var key in config.DynamicCommands.Keys)
  1634. {
  1635. ru[key] = key;
  1636. }
  1637.  
  1638. lang.RegisterMessages(ru, this, "ru");
  1639.  
  1640. var uk = new Dictionary<string, string>
  1641. {
  1642. {"ErrorTPR", "Телепорт до {0} блоковано ({1})"},
  1643. {"AdminTP", "Ви телепортовані до {0}!"},
  1644. {"AdminTPTarget", "{0} телепортував вас!"},
  1645. {"AdminTPPlayers", "Ви телепортували {0} до {1}!"},
  1646. {"AdminTPPlayer", "{0} телепортував вас до {1}!"},
  1647. {"AdminTPPlayerTarget", "{0} телепортував {1} до вас!"},
  1648. {"AdminTPCoordinates", "Ви телепортовані до {0}!"},
  1649. {"AdminTPTargetCoordinates", "Ви телепортували {0} до {1}!"},
  1650. {"AdminTPOutOfBounds", "Ви намагалися телепортуватися до координат поза межами карти!"},
  1651. {"AdminTPBoundaries", "Значення X та Z повинні бути між -{0} та {0}, а значення Y між -100 та 2000!"},
  1652. {"AdminTPLocation", "Ви телепортовані до {0}!"},
  1653. {"AdminTPLocationSave", "Ви зберегли місцезнаходження!"},
  1654. {"AdminTPLocationRemove", "Ви видалили розташування {0}!"},
  1655. {"AdminLocationList", "Доступні такі розташування:"},
  1656. {"AdminLocationListEmpty", "Ви не зберегли жодних місць!"},
  1657. {"AdminTPBack", "Ви телепортовані назад, у ваше попереднє розташування!"},
  1658. {"AdminTPBackSave", "Ваше попереднє місце збережено, використовуйте <color=yellow>/tpb</color>, щоб телепортуватися назад!"},
  1659. {"AdminTPTargetCoordinatesTarget", "{0} телепортував вас до {1}!"},
  1660. {"AdminTPConsoleTP", "Ви були телепортовані до {0}"},
  1661. {"AdminTPConsoleTPPlayer", "Ви були телепортовані до {0}"},
  1662. {"AdminTPConsoleTPPlayerTarget", "{0} був телепортований до вас!"},
  1663. {"HomeTP", "Ви телепортовані до вашого будинку '{0}'!"},
  1664. {"HomeAdminTP", "Ви телепортовані до будинку '{1}', що належить {0}!"},
  1665. {"HomeSave", "Ви зберегли поточне розташування як ваш будинок!"},
  1666. {"HomeNoFoundation", "Використовувати місцезнаходження як будинок дозволено тільки на фундаменті!"},
  1667. {"HomeFoundationNotOwned", "Ви не можете використовувати команду home у чужому домі."},
  1668. {"HomeFoundationUnderneathFoundation", "Ви не можете використовувати команду home на фундаменті, що знаходиться під іншим фундаментом."},
  1669. {"HomeFoundationNotFriendsOwned", "Ви, або ваш друг, повинні бути власником будинку, щоб використати команду home!"},
  1670. {"HomeRemovedInvalid", "Ваш будинок '{0}' був видалений тому, що не на фундаменті або у фундаменту новий власник!"},
  1671. {"HighWallCollision", "Зіткнення Високих Стін!"},
  1672. {"HomeRemovedInsideBlock", "Ваш будинок '{0}' був видалений, тому що всередині фундаменту!"},
  1673. {"HomeRemove", "Ви видалили свій будинок {0}!"},
  1674. {"HomeDelete", "Ви видалили будинок '{1}', що належить {0}!"},
  1675. {"HomeList", "Доступні такі будинки:"},
  1676. {"HomeListEmpty", "Ви не зберегли жодного будинку!"},
  1677. {"HomeMaxLocations", "Неможливо встановити тут ваш будинок, ви досягли ліміту в {0} будинків!"},
  1678. {"HomeQuota", "Ви встановили {0} з {1} максимально можливих будинків!"},
  1679. {"HomeTPStarted", "Телепортація до вашого будинку {0} через {1} секунд!"},
  1680. {"PayToTown", "Стандартний платіж {0} поширюється на всі телепорти до міста!"},
  1681. {"PayToTPR", "Стандартний платіж {0} поширюється на всі tpr'и!"},
  1682. {"HomeTPCooldown", "Ваш телепорт перезаряджається. Вам необхідно почекати {0} до наступної телепортації."},
  1683. {"HomeTPCooldownBypass", "Ваш телепорт був на перезарядженні. Ви обрали уникнути очікування, сплативши {0} з вашого балансу."},
  1684. {"HomeTPCooldownBypassF", "Ваш телепорт перезаряджається. У вас недостатньо коштів - щоб уникнути очікування."},
  1685. {"HomeTPCooldownBypassP", "Ви можете вибрати оплатити {0} щоб уникнути очікування перезаряджання." },
  1686. {"HomeTPCooldownBypassP2", "Введіть <color=yellow>/home \"назва будинку\" {0}</color>." },
  1687. {"HomeTPLimitReached", "Ви вичерпали щоденний ліміт {0} телепортацій сьогодні!"},
  1688. {"HomeTPAmount", "У вас залишилось {0} телепортацій додому сьогодні!"},
  1689. {"HomesListWiped", "Ви очистили всі місця, збережені як будинок!"},
  1690. {"HomeTPBuildingBlocked", "Ви не можете зберегти місце розташування як будинок, якщо у вас немає прав на будівництво в цій зоні!"},
  1691. {"HomeTPSwimming", "Ви не можете встановлювати місце розташування в якості будинку поки пливете!"},
  1692. {"HomeTPCrafting", "Ви не можете встановлювати місце розташування як будинок в процесі крафту!"},
  1693. {"Request", "Ви запросили телепортацію до {0}!"},
  1694. {"RequestTarget", "{0} запросив телепортацію до вас! Використовуйте <color=yellow>/tpa</color>, щоб прийняти!"},
  1695. {"RequestTargetOff", "Ваш запит було скасовано, оскільки ціль зараз не в мережі." },
  1696. {"TPR_NoClan_NoFriend_NoTeam", "Ця команда доступна лише друзям, учасникам команди або клану!"},
  1697. {"PendingRequest", "У вас вже є активний запит, скасуйте його, чекайте на підтвердження, або скасування по таймууту!"},
  1698. {"PendingRequestTarget", "У гравця, до якого ви хочете телепортуватися, вже є активний запит, спробуйте пізніше!"},
  1699. {"NoPendingRequest", "Ви не маєте активних запитів на телепортацію!"},
  1700. {"AcceptOnRoof", "Ви не можете прийняти запит на телепортацію стоячи на стелі, спустіться на фундамент!"},
  1701. {"Accept", "{0} прийняв ваш запит! Телепортація через {1} секунд!"},
  1702. {"AcceptTarget", "Ви отримали запит на телепортацію {0}!"},
  1703. {"AcceptToggleOff", "Ви вимкнули автоматичне /tpa!"},
  1704. {"AcceptToggleOn", "Ви ввімкнули автоматичне /tpa!"},
  1705. {"NotAllowed", "Ви не можете використовувати цю команду!"},
  1706. {"Success", "Ви телепортовані до {0}!"},
  1707. {"SuccessTarget", "{0} телепортований до вас!"},
  1708. {"Cancelled", "Ваш запит на телепортацію до {0} було скасовано!"},
  1709. {"CancelledTarget", "Запит на телепортацію {0} було скасовано!"},
  1710. {"TPCancelled", "Ваш телепорт скасовано!"},
  1711. {"TPCancelledTarget", "{0} скасував телепортацію!"},
  1712. {"TPYouCancelledTarget", "Ви скасували телепортацію {0}!"},
  1713. {"TimedOut", "{0} не відповів на ваш запит під час!"},
  1714. {"TimedOutTarget", "Ви не вчасно відповіли на запит телепортації від {0}!"},
  1715. {"TargetDisconnected", "{0} відключився, ваша телепортація скасована!"},
  1716. {"TPRCooldown", "Ваші запити на телепортацію на даний момент на перезарядці. Вам необхідно зачекати на {0}, перш ніж надіслати наступний запит."},
  1717. {"TPRCooldownBypass", "Ваші запити на телепортацію були перезаряджені. Ви обрали уникнути очікування, сплативши {0} з вашого балансу."},
  1718. {"TPRCooldownBypassF", "Ваші запити на телепортацію на даний момент на перезарядці. У вас недостатньо коштів - щоб уникнути очікування."},
  1719. {"TPRCooldownBypassP", "Ви можете вибрати оплатити {0} щоб уникнути очікування перезаряджання." },
  1720. {"TPMoney", "{0} списано з вашого облікового запису!"},
  1721. {"TPNoMoney", "У вас немає жодного облікового запису {0}!"},
  1722. {"TPRCooldownBypassP2", "Напишіть <color=yellow>/tpr {0}</color>." },
  1723. {"TPRCooldownBypassP2a", "Напишіть <color=yellow>/tpr \"ім'я гравця\" {0}</color>." },
  1724. {"TPRLimitReached", "Ви вичерпали щоденний ліміт {0} запитів на телепортацію сьогодні!"},
  1725. {"TPRAmount", "У вас залишилось {0} запитів на телепортацію на сьогодні!"},
  1726. {"TPRTarget", "Ваша мета зараз не доступна!"},
  1727. {"TPDead", "Ви не можете телепортуватися, поки мертві!"},
  1728. {"TPWounded", "Ви не можете телепортуватися, будучи пораненим!"},
  1729. {"TPTooCold", "Вам надто холодно для телепортації!"},
  1730. {"TPTooHot", "Вам дуже жарко для телепортації!"},
  1731. {"TPBoat", "Ви не можете телепортуватися, перебуваючи на човні!"},
  1732. {"TPHostile", "Ви не можете телепортуватися в Місто NPC або Табір бандитів, поки ворожі!"},
  1733. {"TPJunkpile", "Ви не можете телепортуватися з купи сміття"},
  1734. {"HostileTimer", "Телепорт буде доступний через {0} хвилин."},
  1735. {"TPMounted", "Ви не можете телепортуватись, коли сидите!"},
  1736. {"TPBuildingBlocked", "Ви не можете телепортуватися, перебуваючи у зоні блокування будівництва!"},
  1737. //{"TPInsideTerrainFrom", "Вы не можете телепортироваться, находясь внутри местности!"},
  1738. //{"TPInsideTerrainTo", "Вы не можете телепортироваться в место, которое находится внутри местности!"},
  1739. {"TPAboveWater", "Ви не можете телепортуватися, перебуваючи над водою!"},
  1740. {"TPTargetBuildingBlocked", "Ви не можете телепортуватися до зони, де блоковано будівництво!"},
  1741. {"TPTargetInsideBlock", "Ви не можете телепортуватися у фундамент!"},
  1742. {"TPTargetInsideRock", "Ви не можете телепортуватись у скелю!"},
  1743. {"TPSwimming", "Ви не можете телепортуватися, поки пливете!"},
  1744. {"TPCargoShip", "Ви не можете телепортуватись з вантажного корабля!"},
  1745. {"TPOilRig", "Ви не можете телепортуватися з нафтової вежі!"},
  1746. {"TPExcavator", "Ви не можете телепортувати з екскаватора!"},
  1747. {"TPHotAirBalloon", "Ви не можете телепортуватися з, або на повітряну кулю!"},
  1748. {"TPLift", "Ви не можете телепортуватися, перебуваючи в ліфті або підйомнику!"},
  1749. {"TPBucketLift", "Ви не можете телепортуватися, перебуваючи в ковшовому підйомнику!"},
  1750. {"TPRegLift", "Ви не можете телепортуватися, перебуваючи в ліфті!"},
  1751. {"TPSafeZone", "Ви не можете телепортуватися із безпечної зони!"},
  1752. {"TPFlagZone", "Ви не можете телепортуватися із цієї зони!"},
  1753. {"TPNoEscapeBlocked", "Ви не можете телепортуватися поки активне блокування!"},
  1754. {"TPCrafting", "Ви не можете телепортуватись у процесі крафту!"},
  1755. {"TPBlockedItem", "Ви не можете телепортуватися поки що несете: {0}!"},
  1756. {"TooCloseToMon", "Ви не можете телепортуватися так близько до {0}!"},
  1757. {"TPHomeSafeZoneOnly", "Ви можете телепортуватися додому лише з безпечної зони!" },
  1758. {"TooCloseToCave", "Ви не можете телепортуватись так близько до печери!"},
  1759. {"HomeTooCloseToCave", "Ви не можете зберегти розташування як будинок так близько до печери!"},
  1760. {"HomeTooCloseToMon", "Ви не можете зберегти розташування як будинок так близько до пам'ятника!"},
  1761. {"CannotTeleportFromHome", "Ви повинні вийти з вашої бази, перш ніж телепортувати!"},
  1762. {"WaitGlobalCooldown", "Ви повинні почекати, поки ваш глобальний телепорт перезаряджається!" },
  1763.  
  1764. {"DM_TownTP", "Ви телепортовані в {0}!"},
  1765. {"DM_TownTPNoLocation", "Розташування <color=yellow>{0}</color> на даний момент не встановлено!"},
  1766. {"DM_TownTPDisabled", "<color=yellow>{0}</color> в даний момент вимкнено у файлі налаштувань!"},
  1767. {"DM_TownTPLocation", "Ви встановили розташування <color=yellow>{0}</color> в {1}!"},
  1768. {"DM_TownTPCreated", "Ви створили команду: <color=yellow>{0}</color>"},
  1769. {"DM_TownTPRemoved", "Ви видалили команду: <color=yellow>{0}</color>"},
  1770. {"DM_TownTPDoesNotExist", "Команда не існує: <color=yellow>{0}</color>"},
  1771. {"DM_TownTPExists", "Команда <color=yellow>{0}</color> вже існує!"},
  1772. {"DM_TownTPLocationsCleared", "Ви очистили всі місця для {0}!"},
  1773. {"DM_TownTPStarted", "Телепортація в {0} через {1} секунд!"},
  1774. {"DM_TownTPCooldown", "Ваш телепорт перезаряджається. Вам необхідно почекати {0} до наступної телепортації."},
  1775. {"DM_TownTPCooldownBypass", "Ваш телепорт був на перезарядженні. Ви обрали уникнути очікування, сплативши {0} з вашого балансу."},
  1776. {"DM_TownTPCooldownBypassF", "Ваш телепорт перезаряджається. У вас недостатньо коштів ({0}), щоб уникнути очікування."},
  1777. {"DM_TownTPCooldownBypassP", "Ви можете вибрати оплатити {0} щоб уникнути очікування перезаряджання." },
  1778. {"DM_TownTPCooldownBypassP2", "Введіть <color=yellow>/{0} {1}</color>" },
  1779. {"DM_TownTPLimitReached", "Ви вичерпали щоденний ліміт {0} телепортацій сьогодні! Ви повинні почекати {1} до наступної телепортації."},
  1780. {"DM_TownTPAmount", "У вас залишилось {0} телепортацій <color=yellow>{1}</color> сьогодні!"},
  1781.  
  1782. {"Days", "днів" },
  1783. {"Hours", "годин" },
  1784. {"Minutes", "хвилин" },
  1785. {"Seconds", "секунд" },
  1786.  
  1787. {"Interrupted", "Вашу телепортацію було перервано!"},
  1788. {"InterruptedTarget", "Телепортація {0} була перервана!"},
  1789. {"Unlimited", "Не обмежено"},
  1790. {
  1791. "TPInfoGeneral", string.Join(NewLine, new[]
  1792. {
  1793. "Будь ласка, вкажіть модуль, про який ви хочете переглянути інформацію.",
  1794. "Доступні модулі: ",
  1795. })
  1796. },
  1797. {
  1798. "TPHelpGeneral", string.Join(NewLine, new[]
  1799. {
  1800. "<color=yellow>/tpinfo</color> - Відображає ліміти та перезарядження.",
  1801. "Будь ласка, вкажіть модуль, за яким ви хочете отримати допомогу.",
  1802. "Доступні модулі: ",
  1803. })
  1804. },
  1805. {
  1806. "TPHelpadmintp", string.Join(NewLine, new[]
  1807. {
  1808. "Як адмін, ви маєте доступ до наступних команд:",
  1809. "<color=yellow>/tp \"ім'я гравця\"</color> - Телепортує вас до вказаного гравця.",
  1810. "<color=yellow>/tp \"ім'я гравця\" \"ім'я гравця 2\"</color> - Телепортує гравця з ім'ям 'ім'я гравця' до гравця 'ім'я гравця 2'.",
  1811. "<color=yellow>/tp x y z</color> - Телепортує вас до зазначених координат.",
  1812. "<color=yellow>/tpl</color> - Відображає список збережених позицій.",
  1813. "<color=yellow>/tpl \"назва розташування\"</color> - Телепортує вас у збережене місцезнаходження.",
  1814. "<color=yellow>/tpsave \"назва розташування\"</color> - Зберігає ваше поточне розташування з вказаною назвою.",
  1815. "<color=yellow>/tpremove \"назва розташування\"</color> - Видаляє розташування зі списку збережених.",
  1816. "<color=yellow>/tpb</color> - Телепортує вас назад на місце, де ви були перед телепортацією.",
  1817. "<color=yellow>/home radius \"радіус\"</color> - Знайти всі будинки в радіусі.",
  1818. "<color=yellow>/home delete \"ім'я гравця або ID\" \"назва будинку\"</color> - Видаляє будинок із вказаним ім'ям, що належить вказаному гравцю.",
  1819. "<color=yellow>/home tp \"ім'я гравця або ID\" \"назва будинку\"</color> - Телепортує вас до будинку гравця із зазначеною назвою, що належить вказаному гравцю.",
  1820. "<color=yellow>/home homes \"ім'я гравця або ID\"</color> - Відображає список усіх будинків, що належать зазначеному гравцеві."
  1821. })
  1822. },
  1823. {
  1824. "TPHelphome", string.Join(NewLine, new[]
  1825. {
  1826. "Використовуючи наступні команди, ви можете встановити місце розташування вашого будинку, щоб потім до нього телепортуватися:",
  1827. "<color=yellow>/home add \"назва будинку\"</color> - Зберігає ваше поточне розташування як ваш будинок із зазначеною назвою.",
  1828. "<color=yellow>/home list</color> - Відображає список усіх місць розташування, збережених вами як будинок.",
  1829. "<color=yellow>/home remove \"назва будинку\"</color> - Видаляє розташування збереженого будинку з вказаною назвою.",
  1830. "<color=yellow>/home \"назва будинку\"</color> - Телепортує вас у місцезнаходження будинку з вказаною назвою."
  1831. })
  1832. },
  1833. {
  1834. "TPHelptpr", string.Join(NewLine, new[]
  1835. {
  1836. "Використовуючи ці команди, ви можете надіслати запит на телепортацію до гравця або прийняти чийсь запит:",
  1837. "<color=yellow>/tpr \"ім'я гравця\"</color> - Надсилає запит на телепортацію гравцю із зазначеним ім'ям.",
  1838. "<color=yellow>/tpa</color> - Прийняти запит на телепортацію.",
  1839. "<color=yellow>/tpat</color> - Увімк./Вимк. автоматичне прийняття запитів на телепортацію до вас /tpa.",
  1840. "<color=yellow>/tpc</color> - Скасувати запит на телепортацію."
  1841. })
  1842. },
  1843. {
  1844. "TPSettingsGeneral", string.Join(NewLine, new[]
  1845. {
  1846. "Будь ласка, вкажіть модуль, налаштування якого потрібно переглянути.",
  1847. "Доступні модулі:",
  1848. })
  1849. },
  1850. {
  1851. "TPSettingshome", string.Join(NewLine, new[]
  1852. {
  1853. "Система будинків на даний момент має такі включені параметри:",
  1854. "Час між телепортами: {0}",
  1855. "Щоденний ліміт телепортацій: {1}",
  1856. "Кількість збережених будинків: {2}"
  1857. })
  1858. },
  1859. {
  1860. "TPSettingsbandit", string.Join(NewLine, new[]
  1861. {
  1862. "Система Табір бандитів наразі має такі включені параметри:",
  1863. "Час між телепортами: {0}",
  1864. "Щоденний ліміт телепортацій: {1}"
  1865. })
  1866. },
  1867. {
  1868. "TPSettingsoutpost", string.Join(NewLine, new[]
  1869. {
  1870. "Система Місто NPC в даний момент має наступні параметри:",
  1871. "Час між телепортами: {0}",
  1872. "Щоденний ліміт телепортацій: {1}"
  1873. })
  1874. },
  1875. {
  1876. "TPSettingstpr", string.Join(NewLine, new[]
  1877. {
  1878. "Система TPR в даний момент має наступні параметри:",
  1879. "Час між телепортами: {0}",
  1880. "Щоденний ліміт телепортацій: {1}"
  1881. })
  1882. },
  1883. {
  1884. "TPSettingstown", string.Join(NewLine, new[]
  1885. {
  1886. "У Системі Міст включені такі параметри:",
  1887. "Час між телепортами: {0}",
  1888. "Щоденний ліміт телепортацій: {1}"
  1889. })
  1890. },
  1891. {
  1892. "TPSettingsdynamic", string.Join(NewLine, new[]
  1893. {
  1894. "У системі {0} включені такі параметри:",
  1895. "Час між телепортами: {1}",
  1896. "Щоденний ліміт телепортацій: {2}"
  1897. })
  1898. },
  1899. {"PlayerNotFound", "Вказаного гравця не виявлено, будь ласка, спробуйте ще раз!"},
  1900. {"MultiplePlayers", "Знайдено декілька гравців: {0}"},
  1901. {"CantTeleportToSelf", "Ви не можете телепортуватися до себе!"},
  1902. {"CantTeleportPlayerToSelf", "Ви не можете телепортувати гравця до себе!"},
  1903. {"TeleportPendingTPC", "Ви не можете ініціювати телепортацію, поки ви маєте активний запит! Використовуйте <color=yellow>/tpc</color>, щоб скасувати його."},
  1904. {"TeleportPendingTarget", "Ви не можете надіслати запит до того, хто в процесі телепортації!"},
  1905. {"LocationExists", "Розташування з такою назвою вже існує в {0}!"},
  1906. {"LocationExistsNearby", "Розташування з назвою {0} вже існує поряд із поточною позицією!"},
  1907. {"LocationNotFound", "Не знайдено місцезнаходження з такою назвою!"},
  1908. {"NoPreviousLocationSaved", "Попереднє розташування не збережене!"},
  1909. {"HomeExists", "Ви вже зберегли будинок із такою назвою!"},
  1910. {"HomeExistsNearby", "Будинок з назвою {0} вже існує поряд із поточною позицією!"},
  1911. {"HomeNotFound", "Будинок з такою назвою не знайдено!"},
  1912. {"InvalidCoordinates", "Ви вказали неправильні координати!"},
  1913. {"InvalidHelpModule", "Вказано неправильний модуль!"},
  1914. {"InvalidCharacter", "Ви використовували неприпустимий символ, обмежтеся літерами від a до z та цифрами."},
  1915. {
  1916. "SyntaxCommandTP", string.Join(NewLine, new[]
  1917. {
  1918. "Сталася синтаксична помилка!",
  1919. "Використання команди <color=yellow>/tp</color> можливе лише так:",
  1920. "<color=yellow>/tp \"ім'я гравця\"</color> - Телепортує вас до вказаного гравця.",
  1921. "<color=yellow>/tp \"ім'я гравця\" \"ім'я гравця 2\"</color> - Телепортує гравця з ім'ям 'ім'я гравця' до гравця 'ім'я гравця 2'.",
  1922. "<color=yellow>/tp x y z</color> - Телепортує вас до зазначених координат.",
  1923. "<color=yellow>/tp \"ім'я гравця\" x y z</color> - Телепортує гравця з ім'ям 'ім'я гравця' до зазначених координат."
  1924. })
  1925. },
  1926. {
  1927. "SyntaxCommandTPL", string.Join(NewLine, new[]
  1928. {
  1929. "Сталася синтаксична помилка!",
  1930. "Використання команди <color=yellow>/tpl</color> можливе лише так:",
  1931. "<color=yellow>/tpl</color> - Відображає список збережених позицій.",
  1932. "<color=yellow>/tpl \"назва розташування\"</color> - Телепортує вас у місце із зазначеною назвою."
  1933. })
  1934. },
  1935. {
  1936. "SyntaxCommandTPSave", string.Join(NewLine, new[]
  1937. {
  1938. "Сталася синтаксична помилка!",
  1939. "Використання команди <color=yellow>/tpsave</color> можливе лише так:",
  1940. "<color=yellow>/tpsave \"назва розташування\"</color> - Зберігає ваше поточне розташування з вказаною назвою."
  1941. })
  1942. },
  1943. {
  1944. "SyntaxCommandTPRemove", string.Join(NewLine, new[]
  1945. {
  1946. "Сталася синтаксична помилка!",
  1947. "Використання команди <color=yellow>/tpremove</color> можливе лише так:",
  1948. "<color=yellow>/tpremove \"назва розташування\"</color> - Видаляє розташування за вказаною назвою."
  1949. })
  1950. },
  1951. {
  1952. "SyntaxCommandTPN", string.Join(NewLine, new[]
  1953. {
  1954. "Сталася синтаксична помилка!",
  1955. "Використання команди <color=yellow>/tpn</color> можливе лише так:",
  1956. "<color=yellow>/tpn \"ім'я гравця\"</color> - Телепортує вас на відстань за замовчуванням позаду гравця із зазначеним ім'ям.",
  1957. "<color=yellow>/tpn \"ім'я гравця\" \"відстань\"</color> - Телепортує вас на вказану відстань позаду гравця із вказаним ім'ям."
  1958. })
  1959. },
  1960. {
  1961. "SyntaxCommandSetHome", string.Join(NewLine, new[]
  1962. {
  1963. "Сталася синтаксична помилка!",
  1964. "Використання команди <color=yellow>/home add</color> можливе лише так:",
  1965. "<color=yellow>/home add \"назва\"</color> - Зберігає ваше поточне розташування як ваш будинок із зазначеною назвою."
  1966. })
  1967. },
  1968. {
  1969. "SyntaxCommandRemoveHome", string.Join(NewLine, new[]
  1970. {
  1971. "Сталася синтаксична помилка!",
  1972. "Використання команди <color=yellow>/home remove</color> можливе лише так:",
  1973. "<color=yellow>/home remove \"назва\"</color> - Видаляє розташування будинку з вказаною назвою."
  1974. })
  1975. },
  1976. {
  1977. "SyntaxCommandHome", string.Join(NewLine, new[]
  1978. {
  1979. "Сталася синтаксична помилка!",
  1980. "Використання команди <color=yellow>/home</color> можливе лише так:",
  1981. "<color=yellow>/home \"назва\"</color> - Телепортує вас у ваш будинок із зазначеною назвою.",
  1982. "<color=yellow>/home \"назва\" pay</color> - Телепортує вас у ваш будинок із зазначеною назвою, уникаючи перезарядки, заплативши за це.",
  1983. "<color=yellow>/home add \"назва\"</color> - Зберігає ваше поточне розташування як ваш будинок із зазначеною назвою.",
  1984. "<color=yellow>/home list</color> - Відображає список усіх місць розташування, збережених вами як будинок.",
  1985. "<color=yellow>/home remove \"назва\"</color> - Видаляє розташування будинку з вказаною назвою."
  1986. })
  1987. },
  1988. {
  1989. "SyntaxCommandHomeAdmin", string.Join(NewLine, new[]
  1990. {
  1991. "<color=yellow>/home radius \"радіус\"</color> - Відображає список усіх будинків у радіусі(10).",
  1992. "<color=yellow>/home delete \"ім'я гравця або ID\" \"назва\"</color> - Видаляє будинок із зазначеною назвою, що належить вказаному гравцю.",
  1993. "<color=yellow>/home tp \"ім'я гравця або ID\" \"назва\"</color> - Телепортує вас до будинку із зазначеною назвою, що належить вказаному гравцю.",
  1994. "<color=yellow>/home homes \"ім'я гравця або ID\"</color> - Відображає список усіх будинків, що належать вказаному гравцю."
  1995. })
  1996. },
  1997. {
  1998. "SyntaxCommandTown", string.Join(NewLine, new[]
  1999. {
  2000. "Сталася синтаксична помилка!",
  2001. "Використання команди <color=yellow>/town</color> можливе лише так:",
  2002. "<color=yellow>/town</color> - Телепортує вас до міста.",
  2003. "<color=yellow>/town pay</color> - Телепортує вас до міста з оплатою штрафу."
  2004. })
  2005. },
  2006. {
  2007. "SyntaxCommandTownAdmin", string.Join(NewLine, new[]
  2008. {
  2009. "<color=yellow>/town set</color> - Зберігає поточне розташування як Місто.",
  2010. })
  2011. },
  2012. {
  2013. "SyntaxCommandOutpost", string.Join(NewLine, new[]
  2014. {
  2015. "Сталася синтаксична помилка!",
  2016. "Використання команди <color=yellow>/outpost</color> можливе лише так:",
  2017. "<color=yellow>/outpost</color> - Телепортирует вас в Город NPC.",
  2018. "<color=yellow>/outpost pay</color> - Телепортує вас у Місто NPC з оплатою штрафу."
  2019. })
  2020. },
  2021. {
  2022. "SyntaxCommandOutpostAdmin", string.Join(NewLine, new[]
  2023. {
  2024. "<color=yellow>/outpost set</color> - Зберігає поточне розташування як Місто NPC.",
  2025. })
  2026. },
  2027. {
  2028. "SyntaxCommandBandit", string.Join(NewLine, new[]
  2029. {
  2030. "Сталася синтаксична помилка!",
  2031. "Використання команди <color=yellow>/bandit</color> можливе лише так:",
  2032. "<color=yellow>/bandit</color> - Телепортує вас до Табору бандитів.",
  2033. "<color=yellow>/bandit pay</color> - Телепортує вас до Табору бандитів з оплатою штрафу."
  2034. })
  2035. },
  2036. {
  2037. "SyntaxCommandBanditAdmin", string.Join(NewLine, new[]
  2038. {
  2039. "<color=yellow>/bandit set</color> - Зберігає поточне розташування як Табір бандитів.",
  2040. })
  2041. },
  2042. {
  2043. "SyntaxCommandHomeDelete", string.Join(NewLine, new[]
  2044. {
  2045. "Сталася синтаксична помилка!",
  2046. "Використання команди <color=yellow>/home delete</color> можливе лише так:",
  2047. "<color=yellow>/home delete \"ім'я гравця або ID\" \"назва\"</color> - Видаляє будинок із зазначеною назвою, що належить вказаному гравцю."
  2048. })
  2049. },
  2050. {
  2051. "SyntaxCommandHomeAdminTP", string.Join(NewLine, new[]
  2052. {
  2053. "Сталася синтаксична помилка!",
  2054. "Використання команди <color=yellow>/home tp</color> можливе лише так:",
  2055. "<color=yellow>/home tp \"ім'я гравця або ID\" \"назва\"</color> - Телепортує вас до будинку гравця із зазначеною назвою, що належить вказаному гравцю."
  2056. })
  2057. },
  2058. {
  2059. "SyntaxCommandHomeHomes", string.Join(NewLine, new[]
  2060. {
  2061. "Сталася синтаксична помилка!",
  2062. "Використання команди <color=yellow>/home homes</color> можливе лише так:",
  2063. "<color=yellow>/home homes \"ім'я гравця або ID\"</color> - Відображає список усіх будинків, що належать вказаному гравцю."
  2064. })
  2065. },
  2066. {
  2067. "SyntaxCommandListHomes", string.Join(NewLine, new[]
  2068. {
  2069. "Сталася синтаксична помилка!",
  2070. "Використання команди <color=yellow>/home list</color> можливе лише так:",
  2071. "<color=yellow>/home list</color> - Відображає список усіх місць розташування, збережених вами як будинок."
  2072. })
  2073. },
  2074. {
  2075. "SyntaxCommandTPR", string.Join(NewLine, new[]
  2076. {
  2077. "Сталася синтаксична помилка!",
  2078. "Використання команди <color=yellow>/tpr</color> можливе лише так:",
  2079. "<color=yellow>/tpr \"ім'я гравця або ID\"</color> - Надсилає вказаному гравцеві запит на телепортацію."
  2080. })
  2081. },
  2082. {
  2083. "SyntaxCommandTPA", string.Join(NewLine, new[]
  2084. {
  2085. "Відбулася синтаксична помилка!",
  2086. "Використання команди <color=yellow>/tpa</color> можливе лише таким чином:",
  2087. "<color=yellow>/tpa</color> - Прийняти вхідний запит на телепортацію."
  2088. })
  2089. },
  2090. {
  2091. "SyntaxCommandTPC", string.Join(NewLine, new[]
  2092. {
  2093. "Відбулася синтаксична помилка!",
  2094. "Використання команди <color=yellow>/tpc</color> можливе лише таким чином:",
  2095. "<color=yellow>/tpc</color> - Скасувати запит на телепортацію."
  2096. })
  2097. },
  2098. {
  2099. "SyntaxConsoleCommandToPos", string.Join(NewLine, new[]
  2100. {
  2101. "Відбулася синтаксична помилка!",
  2102. "Використання консольної команди <color=orange>teleport.topos</color> можливе лише таким чином:",
  2103. " > <color=orange>teleport.topos \"ім'я гравця\" x y z</color>"
  2104. })
  2105. },
  2106. {
  2107. "SyntaxConsoleCommandToPlayer", string.Join(NewLine, new[]
  2108. {
  2109. "Відбулася синтаксична помилка!",
  2110. "Використання консольної команди <color=orange>teleport.toplayer</color> можливе лише таким чином:",
  2111. " > <color=orange>teleport.toplayer \"ім'я гравця або ID\" \"ім'я гравця 2|id 2\"</color>"
  2112. })
  2113. },
  2114. {"LogTeleport", "{0} телепортовано до {1}."},
  2115. {"LogTeleportPlayer", "{0} телепортував {1} до {2}."},
  2116. {"LogTeleportBack", "{0} телепортований назад, до попереднього розташування."}
  2117. };
  2118.  
  2119. foreach (var key in config.DynamicCommands.Keys)
  2120. {
  2121. uk[key] = key;
  2122. }
  2123.  
  2124. lang.RegisterMessages(uk, this, "uk");
  2125. }
  2126.  
  2127. private void Init()
  2128. {
  2129. Unsubscribe(nameof(OnPlayerViolation));
  2130. Unsubscribe(nameof(OnEntityTakeDamage));
  2131. Unsubscribe(nameof(OnPlayerSleepEnded));
  2132. Unsubscribe(nameof(OnPlayerDisconnected));
  2133. }
  2134.  
  2135. private string OnPlayerConnected(BasePlayer player)
  2136. {
  2137. var uid = UnityEngine.Random.Range(1000, 9999).ToString();
  2138. var names = BasePlayer.activePlayerList.Select(x => x.displayName);
  2139.  
  2140. while (_ids.ContainsKey(uid) || names.Any(name => name.Contains(uid)))
  2141. {
  2142. uid = UnityEngine.Random.Range(1000, 9999).ToString();
  2143. }
  2144.  
  2145. _ids[uid] = player;
  2146. _players[player] = uid;
  2147.  
  2148. return uid;
  2149. }
  2150.  
  2151. private Dictionary<string, StoredData> _DynamicData = new Dictionary<string, StoredData>();
  2152.  
  2153. public class StoredData
  2154. {
  2155. public Dictionary<ulong, TeleportData> TPData = new Dictionary<ulong, TeleportData>();
  2156. public bool Changed = true;
  2157. }
  2158.  
  2159. private void LoadDataAndPerms()
  2160. {
  2161. dataAdmin = GetFile("Admin");
  2162. try { _Admin = dataAdmin.ReadObject<Dictionary<ulong, AdminData>>(); } catch { }
  2163. if (_Admin == null) { _Admin = new Dictionary<ulong, AdminData>(); changedAdmin = true; }
  2164.  
  2165. dataHome = GetFile("Home");
  2166. try { _Home = dataHome.ReadObject<Dictionary<ulong, HomeData>>(); } catch { }
  2167. if (_Home == null) { _Home = new Dictionary<ulong, HomeData>(); changedHome = true; }
  2168.  
  2169. dataTPT = GetFile("TPT");
  2170. try { TPTToggle = dataTPT.ReadObject<List<string>>(); } catch { }
  2171. if (TPTToggle == null) { TPTToggle = new List<string>(); changedTPT = true; }
  2172.  
  2173. foreach (var entry in config.DynamicCommands)
  2174. {
  2175. if (!entry.Value.Enabled) continue;
  2176.  
  2177. var dcf = GetFile(entry.Key);
  2178. Dictionary<ulong, TeleportData> data = null;
  2179.  
  2180. try
  2181. {
  2182. data = dcf.ReadObject<Dictionary<ulong, TeleportData>>();
  2183. }
  2184. catch
  2185. {
  2186.  
  2187. }
  2188.  
  2189. if (data == null)
  2190. {
  2191. data = new Dictionary<ulong, TeleportData>();
  2192. }
  2193.  
  2194. GetSettings(entry.Key).Teleports = _DynamicData[entry.Key] = new StoredData
  2195. {
  2196. TPData = data,
  2197. Changed = true
  2198. };
  2199. }
  2200.  
  2201. dataTPR = GetFile("TPR");
  2202. try { _TPR = dataTPR.ReadObject<Dictionary<ulong, TeleportData>>(); } catch { }
  2203. if (_TPR == null) { _TPR = new Dictionary<ulong, TeleportData>(); changedTPR = true; }
  2204.  
  2205. dataDisabled = GetFile("DisabledCommands");
  2206. try { DisabledCommandData = dataDisabled.ReadObject<DisabledData>(); } catch { }
  2207. if (DisabledCommandData == null) { DisabledCommandData = new DisabledData(); }
  2208.  
  2209. permission.RegisterPermission("nteleportation.norestrictions", this);
  2210. permission.RegisterPermission("nteleportation.globalcooldownvip", this);
  2211. permission.RegisterPermission(PermFoundationCheck, this);
  2212. permission.RegisterPermission(PermDeleteHome, this);
  2213. permission.RegisterPermission(PermHome, this);
  2214. permission.RegisterPermission(PermHomeHomes, this);
  2215. permission.RegisterPermission(PermImportHomes, this);
  2216. permission.RegisterPermission(PermRadiusHome, this);
  2217. permission.RegisterPermission(PermTp, this);
  2218. permission.RegisterPermission(PermTpB, this);
  2219. permission.RegisterPermission(PermTpR, this);
  2220. permission.RegisterPermission(PermTpConsole, this);
  2221. permission.RegisterPermission(PermTpHome, this);
  2222. permission.RegisterPermission(PermTpT, this);
  2223. permission.RegisterPermission(PermTpN, this);
  2224. permission.RegisterPermission(PermTpL, this);
  2225. permission.RegisterPermission(PermTpRemove, this);
  2226. permission.RegisterPermission(PermTpSave, this);
  2227. permission.RegisterPermission(PermWipeHomes, this);
  2228. permission.RegisterPermission(PermCraftHome, this);
  2229. permission.RegisterPermission(PermCraftTpR, this);
  2230. permission.RegisterPermission(PermExempt, this);
  2231. permission.RegisterPermission(PermTpMarker, this);
  2232.  
  2233. CheckPerms(config.Home.VIPCooldowns);
  2234. CheckPerms(config.Home.VIPCountdowns);
  2235. CheckPerms(config.Home.VIPDailyLimits);
  2236. CheckPerms(config.Home.VIPHomesLimits);
  2237. CheckPerms(config.TPR.VIPCooldowns);
  2238. CheckPerms(config.TPR.VIPCountdowns);
  2239. CheckPerms(config.TPR.VIPDailyLimits);
  2240.  
  2241. foreach (var entry in config.DynamicCommands)
  2242. {
  2243. RegisterCommand(entry.Key, entry.Value, false);
  2244. }
  2245. }
  2246.  
  2247. private bool CanBypassRestrictions(string userid) => permission.UserHasPermission(userid, "nteleportation.norestrictions");
  2248.  
  2249. private void RegisterCommand(string command, string callback, string perm = null)
  2250. {
  2251. if (!string.IsNullOrEmpty(command) && !command.Equals("null", StringComparison.OrdinalIgnoreCase))
  2252. {
  2253. AddCovalenceCommand(command, callback, perm);
  2254. }
  2255. }
  2256.  
  2257. private void UnregisterCommand(string command)
  2258. {
  2259. covalence.UnregisterCommand(command, this);
  2260. }
  2261.  
  2262. private void RegisterCommand(string key, TownSettings settings, bool justCreated)
  2263. {
  2264. CheckPerms(settings.VIPCooldowns);
  2265. CheckPerms(settings.VIPCountdowns);
  2266. CheckPerms(settings.VIPDailyLimits);
  2267.  
  2268. string tpPerm = $"{Name}.tp{key}".ToLower();
  2269. string craftPerm = $"{Name}.craft{key}".ToLower();
  2270.  
  2271. if (!permission.PermissionExists(tpPerm, this))
  2272. {
  2273. permission.RegisterPermission(tpPerm, this);
  2274. }
  2275.  
  2276. if (!permission.PermissionExists(craftPerm))
  2277. {
  2278. permission.RegisterPermission(craftPerm, this);
  2279. }
  2280.  
  2281. if (justCreated)
  2282. {
  2283. settings.Teleports = _DynamicData[key] = new StoredData();
  2284. }
  2285. }
  2286.  
  2287. private DynamicConfigFile GetFile(string name)
  2288. {
  2289. var fileName = string.IsNullOrEmpty(config.Settings.DataFileFolder) ? $"{Name}{name}" : $"{config.Settings.DataFileFolder}{Path.DirectorySeparatorChar}{name}";
  2290. var file = Interface.Oxide.DataFileSystem.GetFile(fileName);
  2291. file.Settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
  2292. file.Settings.Converters = new JsonConverter[] { new UnityVector3Converter(), new CustomComparerDictionaryCreationConverter<string>(StringComparer.OrdinalIgnoreCase) };
  2293. return file;
  2294. }
  2295.  
  2296. private void SetGlobalCooldown(BasePlayer player)
  2297. {
  2298. if (config.Settings.GlobalVIP > 0f && permission.UserHasPermission(player.UserIDString, "nteleportation.globalcooldownvip"))
  2299. {
  2300. ulong userid = player.userID;
  2301. TeleportCooldowns[userid] = Time.time + config.Settings.GlobalVIP;
  2302. timer.Once(config.Settings.GlobalVIP, () => TeleportCooldowns.Remove(userid));
  2303. }
  2304. else if (config.Settings.Global > 0f)
  2305. {
  2306. ulong userid = player.userID;
  2307. TeleportCooldowns[userid] = Time.time + config.Settings.Global;
  2308. timer.Once(config.Settings.Global, () => TeleportCooldowns.Remove(userid));
  2309. }
  2310. }
  2311.  
  2312. private float GetGlobalCooldown(BasePlayer player)
  2313. {
  2314. float cooldown;
  2315. if (!TeleportCooldowns.TryGetValue(player.userID, out cooldown))
  2316. {
  2317. return 0f;
  2318. }
  2319.  
  2320. return cooldown - Time.time;
  2321. }
  2322.  
  2323. private void CheckNewSave()
  2324. {
  2325. if (BuildingManager.server.buildingDictionary.Count == 0)
  2326. {
  2327. newSave = true;
  2328. }
  2329.  
  2330. if (!newSave)
  2331. {
  2332. return;
  2333. }
  2334.  
  2335. if (config.Settings.WipeOnUpgradeOrChange)
  2336. {
  2337. bool changed = false;
  2338.  
  2339. if (_Home.Count > 0)
  2340. {
  2341. changed = true;
  2342. _Home.Clear();
  2343. changedHome = true;
  2344. }
  2345.  
  2346. if (_TPR.Count > 0)
  2347. {
  2348. changed = true;
  2349. _TPR.Clear();
  2350. changedTPR = true;
  2351. }
  2352.  
  2353. foreach (var entry in config.DynamicCommands.ToList())
  2354. {
  2355. if (entry.Value.Location != Vector3.zero || entry.Value.Locations.Count > 0)
  2356. {
  2357. changed = true;
  2358. entry.Value.Location = Vector3.zero;
  2359. entry.Value.Locations.Clear();
  2360. }
  2361. }
  2362.  
  2363. if (!changed) return;
  2364. Puts("Rust was upgraded or map changed - clearing homes and all locations!");
  2365. SaveConfig();
  2366. }
  2367. else
  2368. {
  2369. Puts("Rust was upgraded or map changed - homes, town, islands, outpost and bandit may be invalid!");
  2370. }
  2371. }
  2372.  
  2373. void OnServerInitialized()
  2374. {
  2375. if (config.Settings.Interrupt.Hurt || config.Settings.Interrupt.Cold || config.Settings.Interrupt.Hot)
  2376. {
  2377. Subscribe(nameof(OnEntityTakeDamage));
  2378. }
  2379.  
  2380. Subscribe(nameof(OnPlayerSleepEnded));
  2381. Subscribe(nameof(OnPlayerDisconnected));
  2382.  
  2383. boundary = TerrainMeta.Size.x / 2;
  2384.  
  2385. foreach (var item in config.Settings.BlockedItems)
  2386. {
  2387. var definition = ItemManager.FindItemDefinition(item.Key);
  2388. if (definition == null)
  2389. {
  2390. Puts("Blocked item not found: {0}", item.Key);
  2391. continue;
  2392. }
  2393. ReverseBlockedItems[definition.itemid] = item.Value;
  2394. }
  2395.  
  2396. InitializeDynamicCommands();
  2397. LoadDataAndPerms();
  2398. CheckNewSave();
  2399.  
  2400. if (config.Settings.TPREnabled) AddCovalenceCommand("tpr", nameof(CommandTeleportRequest));
  2401. if (config.Settings.HomesEnabled)
  2402. {
  2403. AddCovalenceCommand("home", nameof(CommandHome));
  2404. AddCovalenceCommand("sethome", nameof(CommandSetHome));
  2405. AddCovalenceCommand("listhomes", nameof(CommandListHomes));
  2406. AddCovalenceCommand("removehome", nameof(CommandRemoveHome));
  2407. AddCovalenceCommand("radiushome", nameof(CommandHomeRadius));
  2408. AddCovalenceCommand("deletehome", nameof(CommandHomeDelete));
  2409. AddCovalenceCommand("tphome", nameof(CommandHomeAdminTP));
  2410. AddCovalenceCommand("homehomes", nameof(CommandHomeHomes));
  2411. }
  2412.  
  2413. AddCovalenceCommand("tnt", nameof(CommandToggle));
  2414. AddCovalenceCommand("tp", nameof(CommandTeleport));
  2415. AddCovalenceCommand("tpn", nameof(CommandTeleportNear));
  2416. AddCovalenceCommand("tpl", nameof(CommandTeleportLocation));
  2417. AddCovalenceCommand("tpsave", nameof(CommandSaveTeleportLocation));
  2418. AddCovalenceCommand("tpremove", nameof(CommandRemoveTeleportLocation));
  2419. AddCovalenceCommand("tpb", nameof(CommandTeleportBack));
  2420. AddCovalenceCommand("tpa", nameof(CommandTeleportAccept));
  2421. AddCovalenceCommand("tpat", nameof(CommandTeleportAcceptToggle));
  2422. AddCovalenceCommand("wipehomes", nameof(CommandWipeHomes));
  2423. AddCovalenceCommand("tphelp", nameof(CommandTeleportHelp));
  2424. AddCovalenceCommand("tpinfo", nameof(CommandTeleportInfo));
  2425. AddCovalenceCommand("tpc", nameof(CommandTeleportCancel));
  2426. AddCovalenceCommand("teleport.toplayer", nameof(CommandTeleportII));
  2427. AddCovalenceCommand("teleport.topos", nameof(CommandTeleportII));
  2428. AddCovalenceCommand("teleport.importhomes", nameof(CommandImportHomes));
  2429. AddCovalenceCommand("spm", nameof(CommandSphereMonuments));
  2430. FindMonuments();
  2431. foreach (var player in BasePlayer.activePlayerList) OnPlayerConnected(player);
  2432. }
  2433.  
  2434. void OnNewSave(string strFilename)
  2435. {
  2436. newSave = true;
  2437. }
  2438.  
  2439. void OnServerSave()
  2440. {
  2441. SaveTeleportsAdmin();
  2442. SaveTeleportsHome();
  2443. SaveTeleportsTPR();
  2444. SaveTeleportsTPT();
  2445. SaveTeleportsTown();
  2446. }
  2447.  
  2448. void OnServerShutdown() => OnServerSave();
  2449.  
  2450. void Unload() => OnServerSave();
  2451.  
  2452. void OnEntityTakeDamage(BasePlayer player, HitInfo hitInfo)
  2453. {
  2454. if (player == null || player.IsNpc || !player.userID.IsSteamId() || hitInfo == null) return;
  2455. if (hitInfo.damageTypes.Has(DamageType.Fall) && teleporting.ContainsKey(player.userID))
  2456. {
  2457. hitInfo.damageTypes = new DamageTypeList();
  2458. teleporting.Remove(player.userID);
  2459. if (teleporting.Count == 0) Unsubscribe(nameof(OnPlayerViolation));
  2460. return;
  2461. }
  2462. if (permission.UserHasPermission(player.userID.ToString(), PermExempt)) return;
  2463. TeleportTimer teleportTimer;
  2464. if (!TeleportTimers.TryGetValue(player.userID, out teleportTimer)) return;
  2465. DamageType major = hitInfo.damageTypes.GetMajorityDamageType();
  2466.  
  2467. NextTick(() =>
  2468. {
  2469. if (!player || !hitInfo.hasDamage) return;
  2470. // 1.0.84 new checks for cold/heat based on major damage for the player
  2471. if (major == DamageType.Cold)
  2472. {
  2473. if (config.Settings.Interrupt.Cold && player.metabolism.temperature.value <= config.Settings.MinimumTemp)
  2474. {
  2475. PrintMsgL(teleportTimer.OriginPlayer, "TPTooCold");
  2476. if (teleportTimer.TargetPlayer != null)
  2477. {
  2478. PrintMsgL(teleportTimer.TargetPlayer, "InterruptedTarget", teleportTimer.OriginPlayer?.displayName);
  2479. }
  2480. teleportTimer.Timer.Destroy();
  2481. TeleportTimers.Remove(player.userID);
  2482. }
  2483. }
  2484. else if (major == DamageType.Heat)
  2485. {
  2486. if (config.Settings.Interrupt.Hot && player.metabolism.temperature.value >= config.Settings.MaximumTemp)
  2487. {
  2488. PrintMsgL(teleportTimer.OriginPlayer, "TPTooHot");
  2489. if (teleportTimer.TargetPlayer != null)
  2490. {
  2491. PrintMsgL(teleportTimer.TargetPlayer, "InterruptedTarget", teleportTimer.OriginPlayer?.displayName);
  2492. }
  2493. teleportTimer.Timer.Destroy();
  2494. TeleportTimers.Remove(player.userID);
  2495. }
  2496. }
  2497. else if (config.Settings.Interrupt.Hurt)
  2498. {
  2499. PrintMsgL(teleportTimer.OriginPlayer, "Interrupted");
  2500. if (teleportTimer.TargetPlayer != null)
  2501. {
  2502. PrintMsgL(teleportTimer.TargetPlayer, "InterruptedTarget", teleportTimer.OriginPlayer?.displayName);
  2503. }
  2504. teleportTimer.Timer.Destroy();
  2505. TeleportTimers.Remove(player.userID);
  2506. }
  2507. });
  2508. }
  2509.  
  2510. object OnPlayerViolation(BasePlayer player, AntiHackType type, float amount)
  2511. {
  2512. if (type == AntiHackType.InsideTerrain && teleporting.ContainsKey(player.userID))
  2513. {
  2514. return false;
  2515. }
  2516.  
  2517. return null;
  2518. }
  2519.  
  2520. void OnPlayerSleepEnded(BasePlayer player)
  2521. {
  2522. if (!player || !teleporting.ContainsKey(player.userID)) return;
  2523. ulong userID = player.userID;
  2524. timer.Once(3f, () =>
  2525. {
  2526. teleporting.Remove(userID);
  2527.  
  2528. if (teleporting.Count == 0) Unsubscribe(nameof(OnPlayerViolation));
  2529. });
  2530. SendEffect(player);
  2531. }
  2532.  
  2533. void OnPlayerDisconnected(BasePlayer player)
  2534. {
  2535. if (!player) return;
  2536. Timer reqTimer;
  2537. if (PendingRequests.TryGetValue(player.userID, out reqTimer))
  2538. {
  2539. var originPlayer = PlayersRequests[player.userID];
  2540. if (originPlayer)
  2541. {
  2542. PlayersRequests.Remove(originPlayer.userID);
  2543. PrintMsgL(originPlayer, "RequestTargetOff");
  2544. }
  2545. reqTimer.Destroy();
  2546. PendingRequests.Remove(player.userID);
  2547. PlayersRequests.Remove(player.userID);
  2548. }
  2549. TeleportTimer teleportTimer;
  2550. if (TeleportTimers.TryGetValue(player.userID, out teleportTimer))
  2551. {
  2552. teleportTimer.Timer.Destroy();
  2553. TeleportTimers.Remove(player.userID);
  2554. }
  2555. teleporting.Remove(player.userID);
  2556. }
  2557.  
  2558. private void SaveTeleportsAdmin()
  2559. {
  2560. if (_Admin == null || !changedAdmin) return;
  2561. dataAdmin.WriteObject(_Admin);
  2562. changedAdmin = false;
  2563. }
  2564.  
  2565. private void SaveTeleportsHome()
  2566. {
  2567. if (_Home == null || !changedHome) return;
  2568. dataHome.WriteObject(_Home);
  2569. changedHome = false;
  2570. }
  2571.  
  2572. private void SaveTeleportsTPR()
  2573. {
  2574. if (_TPR == null || !changedTPR) return;
  2575. dataTPR.WriteObject(_TPR);
  2576. changedTPR = false;
  2577. }
  2578.  
  2579. private void SaveTeleportsTPT()
  2580. {
  2581. if (TPTToggle == null || !changedTPT) return;
  2582. dataTPT.WriteObject(TPTToggle);
  2583. changedTPT = false;
  2584. }
  2585.  
  2586. private void SaveTeleportsTown()
  2587. {
  2588. foreach (var entry in _DynamicData.ToList())
  2589. {
  2590. if (entry.Value.Changed)
  2591. {
  2592. var fileName = string.IsNullOrEmpty(config.Settings.DataFileFolder) ? $"{Name}{entry.Key}" : $"{config.Settings.DataFileFolder}{Path.DirectorySeparatorChar}{entry.Key}";
  2593. Interface.Oxide.DataFileSystem.WriteObject(fileName, entry.Value.TPData);
  2594. entry.Value.Changed = false;
  2595. }
  2596. }
  2597. }
  2598.  
  2599. private void SaveLocation(BasePlayer player, Vector3 position)
  2600. {
  2601. if (player == null || _Admin == null || !IsAllowed(player, PermTpB)) return;
  2602. AdminData adminData;
  2603. if (!_Admin.TryGetValue(player.userID, out adminData) || adminData == null)
  2604. _Admin[player.userID] = adminData = new AdminData();
  2605. adminData.PreviousLocation = position;
  2606. changedAdmin = true;
  2607. PrintMsgL(player, "AdminTPBackSave");
  2608. }
  2609.  
  2610. private void RemoveLocation(BasePlayer player)
  2611. {
  2612. AdminData adminData;
  2613. if (!_Admin.TryGetValue(player.userID, out adminData))
  2614. return;
  2615. adminData.PreviousLocation = Vector3.zero;
  2616. changedAdmin = true;
  2617. }
  2618.  
  2619. char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".ToCharArray();
  2620. private readonly System.Text.StringBuilder _sb = new System.Text.StringBuilder();
  2621.  
  2622. string RandomString(int minAmount = 4, int maxAmount = 10)
  2623. {
  2624. _sb.Length = 0;
  2625.  
  2626. for (int i = 0; i < UnityEngine.Random.Range(minAmount, maxAmount + 1); i++)
  2627. _sb.Append(chars.GetRandom());
  2628.  
  2629. return _sb.ToString();
  2630. }
  2631.  
  2632. void FindMonuments()
  2633. {
  2634. var bandit = GetSettings("bandit");
  2635. var outpost = GetSettings("outpost");
  2636. var realWidth = 0f;
  2637. string name = null;
  2638. foreach (var monument in UnityEngine.Object.FindObjectsOfType<MonumentInfo>())
  2639. {
  2640. var monPos = monument.transform.position;
  2641. name = monument.displayPhrase.english.TrimEnd();
  2642.  
  2643. if (string.IsNullOrEmpty(name))
  2644. {
  2645. if (monument.name.Contains("cave"))
  2646. {
  2647. name = (monument.name.Contains("cave_small") ? "Small Cave" : monument.name.Contains("cave_medium") ? "Medium Cave" : "Large Cave") + ":" + RandomString();
  2648. }
  2649. else name = monument.name;
  2650. }
  2651. realWidth = monument.name == "OilrigAI" ? 100f : monument.name == "OilrigAI2" ? 200f : 0f;
  2652. #if DEBUG
  2653. Puts($"Found {name}, extents {monument.Bounds.extents}");
  2654. #endif
  2655. if (realWidth > 0f)
  2656. {
  2657. #if DEBUG
  2658. Puts($" corrected to {realWidth}");
  2659. #endif
  2660. }
  2661. if (monument.name.Contains("cave"))
  2662. {
  2663. #if DEBUG
  2664. Puts(" Adding to cave list");
  2665. #endif
  2666. if (caves.ContainsKey(name)) name += RandomString();
  2667. caves.Add(name, monPos);
  2668. }
  2669. else if (monument.name == outpostPrefab)
  2670. {
  2671. if (outpost == null)
  2672. {
  2673. outpostEnabled = false;
  2674. continue;
  2675. }
  2676.  
  2677. float radius = monument.Bounds.size.Max();
  2678.  
  2679. if (outpost.Location != Vector3.zero && outpost.Locations.Exists(a => OutOfRange(monument, a)))
  2680. {
  2681. #if DEBUG
  2682. Puts("Invalid Outpost location detected");
  2683. #endif
  2684. outpost.Location = Vector3.zero;
  2685. outpost.Locations = new List<Vector3>();
  2686. }
  2687. if (config.Settings.AutoGenOutpost && outpost.Location == Vector3.zero)
  2688. {
  2689. #if DEBUG
  2690. Puts(" Adding Outpost target");
  2691. #endif
  2692. bool changedOutpost = false;
  2693. var ents = Pool.GetList<BaseEntity>();
  2694. Vis.Entities(monPos, radius, ents);
  2695. foreach (BaseEntity entity in ents)
  2696. {
  2697. if (OutOfRange(monument, entity.transform.position))
  2698. {
  2699. continue;
  2700. }
  2701. if (entity.prefabID == 3858860623)
  2702. {
  2703. outpost.Location = entity.transform.position + entity.transform.forward + new Vector3(0f, 1f, 0f);
  2704. if (!outpost.Locations.Contains(outpost.Location)) outpost.Locations.Add(outpost.Location);
  2705. changedOutpost = true;
  2706. }
  2707. else if (entity is Workbench)
  2708. {
  2709. outpost.Location = entity.transform.position + entity.transform.forward + new Vector3(0f, 1f, 0f);
  2710. if (!outpost.Locations.Contains(outpost.Location)) outpost.Locations.Add(outpost.Location);
  2711. changedOutpost = true;
  2712. }
  2713. else if (entity is BaseChair)
  2714. {
  2715. outpost.Location = entity.transform.position + entity.transform.right + new Vector3(0f, 1f, 0f);
  2716. if (!outpost.Locations.Contains(outpost.Location)) outpost.Locations.Add(outpost.Location);
  2717. changedOutpost = true;
  2718. }
  2719. }
  2720. if (changedOutpost) SaveConfig();
  2721. Pool.FreeList(ref ents);
  2722. }
  2723.  
  2724. if (outpost.Location == Vector3.zero)
  2725. {
  2726. outpostEnabled = false;
  2727. }
  2728. }
  2729. else if (monument.name == banditPrefab)
  2730. {
  2731. if (bandit == null)
  2732. {
  2733. banditEnabled = false;
  2734. continue;
  2735. }
  2736.  
  2737. float radius = monument.Bounds.size.Max();
  2738.  
  2739. if (bandit.Location != Vector3.zero && bandit.Locations.Exists(a => OutOfRange(monument, a)))
  2740. {
  2741. #if DEBUG
  2742. Puts("Invalid Bandit location detected");
  2743. #endif
  2744. bandit.Location = Vector3.zero;
  2745. bandit.Locations = new List<Vector3>();
  2746. }
  2747. if (config.Settings.AutoGenBandit && bandit.Location == Vector3.zero)
  2748. {
  2749. #if DEBUG
  2750. Puts(" Adding BanditTown target");
  2751. #endif
  2752. bool changedBandit = false;
  2753. var ents = Pool.GetList<BaseEntity>();
  2754. Vis.Entities(monPos, radius, ents);
  2755. foreach (BaseEntity entity in ents)
  2756. {
  2757. if (OutOfRange(monument, entity.transform.position))
  2758. {
  2759. continue;
  2760. }
  2761. if (entity.prefabID == 3858860623)
  2762. {
  2763. bandit.Location = entity.transform.position + entity.transform.forward + new Vector3(0f, 1f, 0f);
  2764. if (!bandit.Locations.Contains(bandit.Location)) bandit.Locations.Add(bandit.Location);
  2765. changedBandit = true;
  2766. }
  2767. else if (entity is Workbench)
  2768. {
  2769. bandit.Location = entity.transform.position + entity.transform.forward + new Vector3(0f, 1f, 0f);
  2770. if (!bandit.Locations.Contains(bandit.Location)) bandit.Locations.Add(bandit.Location);
  2771. changedBandit = true;
  2772. }
  2773. else if (entity is BaseChair)
  2774. {
  2775. bandit.Location = entity.transform.position + entity.transform.forward + new Vector3(0f, 1f, 0f);
  2776. if (!bandit.Locations.Contains(bandit.Location)) bandit.Locations.Add(bandit.Location);
  2777. changedBandit = true;
  2778. }
  2779. }
  2780. Pool.FreeList(ref ents);
  2781. if (changedBandit) SaveConfig();
  2782. }
  2783.  
  2784. if (bandit.Location == Vector3.zero)
  2785. {
  2786. banditEnabled = false;
  2787. }
  2788. }
  2789. else
  2790. {
  2791. if (monuments.ContainsKey(name)) name += ":" + RandomString(5, 5);
  2792. if (monument.name.Contains("power_sub")) name = monument.name.Substring(monument.name.LastIndexOf("/") + 1).Replace(".prefab", "") + ":" + RandomString(5, 5);
  2793. float radius = GetMonumentFloat(name);
  2794. monuments[name] = new MonInfo() { Position = monPos, Radius = radius };
  2795. #if DEBUG
  2796. Puts($"Adding Monument: {name}, pos: {monPos}, size: {radius}");
  2797. #endif
  2798. }
  2799. }
  2800.  
  2801. if (bandit != null && bandit.Location != Vector3.zero && !bandit.Locations.Contains(bandit.Location))
  2802. {
  2803. bandit.Locations.Add(bandit.Location);
  2804. }
  2805.  
  2806. if (outpost != null && outpost.Location != Vector3.zero && !outpost.Locations.Contains(outpost.Location))
  2807. {
  2808. outpost.Locations.Add(outpost.Location);
  2809. }
  2810. }
  2811.  
  2812. private bool OutOfRange(MonumentInfo m, Vector3 a) => m.transform.position.y - a.y > 3f || !m.IsInBounds(a);
  2813.  
  2814. private void CommandToggle(IPlayer user, string command, string[] args)
  2815. {
  2816. if (!user.IsAdmin) return;
  2817.  
  2818. if (args.Length == 0)
  2819. {
  2820. user.Reply("tnt commandname");
  2821. return;
  2822. }
  2823.  
  2824. string arg = args[0].ToLower();
  2825.  
  2826. if (arg == command.ToLower()) return;
  2827.  
  2828. if (!DisabledCommandData.DisabledCommands.Contains(arg))
  2829. DisabledCommandData.DisabledCommands.Add(arg);
  2830. else DisabledCommandData.DisabledCommands.Remove(arg);
  2831.  
  2832. dataDisabled.WriteObject(DisabledCommandData);
  2833. user.Reply("{0} {1}", null, DisabledCommandData.DisabledCommands.Contains(arg) ? "Disabled:" : "Enabled:", arg);
  2834. }
  2835.  
  2836. private void CommandTeleport(IPlayer user, string command, string[] args)
  2837. {
  2838. if (DisabledCommandData.DisabledCommands.Contains(command.ToLower())) { user.Reply("Disabled command: " + command); return; }
  2839. var player = user.Object as BasePlayer;
  2840. if (!player || !IsAllowedMsg(player, PermTp) || !player.IsConnected || (player.IsSleeping() && !player.IsAdmin)) return;
  2841. BasePlayer target;
  2842. float x, y, z;
  2843. switch (args.Length)
  2844. {
  2845. case 1:
  2846. target = FindPlayersSingle(args[0], player);
  2847. if (target == null) return;
  2848. if (target == player)
  2849. {
  2850. #if DEBUG
  2851. Puts("Debug mode - allowing self teleport.");
  2852. #else
  2853. PrintMsgL(player, "CantTeleportToSelf");
  2854. return;
  2855. #endif
  2856. }
  2857. Teleport(player, target);
  2858. PrintMsgL(player, "AdminTP", target.displayName);
  2859. Puts(_("LogTeleport", null, player.displayName, target.displayName));
  2860. if (config.Admin.AnnounceTeleportToTarget)
  2861. PrintMsgL(target, "AdminTPTarget", player.displayName);
  2862. break;
  2863. case 2:
  2864. var origin = FindPlayersSingle(args[0], player);
  2865. if (origin == null) return;
  2866. target = FindPlayersSingle(args[1], player);
  2867. if (target == null) return;
  2868. if (target == origin)
  2869. {
  2870. PrintMsgL(player, "CantTeleportPlayerToSelf");
  2871. return;
  2872. }
  2873. Teleport(origin, target);
  2874. PrintMsgL(player, "AdminTPPlayers", origin.displayName, target.displayName);
  2875. PrintMsgL(origin, "AdminTPPlayer", player.displayName, target.displayName);
  2876. if (config.Admin.AnnounceTeleportToTarget)
  2877. PrintMsgL(target, "AdminTPPlayerTarget", player.displayName, origin.displayName);
  2878. Puts(_("LogTeleportPlayer", null, player.displayName, origin.displayName, target.displayName));
  2879. break;
  2880. case 3:
  2881. if (!float.TryParse(args[0].Replace(",", string.Empty), out x) || !float.TryParse(args[1].Replace(",", string.Empty), out y) || !float.TryParse(args[2], out z))
  2882. {
  2883. PrintMsgL(player, "InvalidCoordinates");
  2884. return;
  2885. }
  2886. if (config.Settings.CheckBoundaries && !CheckBoundaries(x, y, z)) // added this option because I HATE boundaries
  2887. {
  2888. PrintMsgL(player, "AdminTPOutOfBounds");
  2889. PrintMsgL(player, "AdminTPBoundaries", boundary);
  2890. return;
  2891. }
  2892. Teleport(player, x, y, z);
  2893. PrintMsgL(player, "AdminTPCoordinates", player.transform.position);
  2894. Puts(_("LogTeleport", null, player.displayName, player.transform.position));
  2895. break;
  2896. case 4:
  2897. target = FindPlayersSingle(args[0], player);
  2898. if (target == null) return;
  2899. if (!float.TryParse(args[1].Replace(",", string.Empty), out x) || !float.TryParse(args[2].Replace(",", string.Empty), out y) || !float.TryParse(args[3], out z))
  2900. {
  2901. PrintMsgL(player, "InvalidCoordinates");
  2902. return;
  2903. }
  2904. if (!CheckBoundaries(x, y, z))
  2905. {
  2906. PrintMsgL(player, "AdminTPOutOfBounds");
  2907. PrintMsgL(player, "AdminTPBoundaries", boundary);
  2908. return;
  2909. }
  2910. Teleport(target, x, y, z);
  2911. if (player == target)
  2912. {
  2913. PrintMsgL(player, "AdminTPCoordinates", player.transform.position);
  2914. Puts(_("LogTeleport", null, player.displayName, player.transform.position));
  2915. }
  2916. else
  2917. {
  2918. PrintMsgL(player, "AdminTPTargetCoordinates", target.displayName, player.transform.position);
  2919. if (config.Admin.AnnounceTeleportToTarget)
  2920. PrintMsgL(target, "AdminTPTargetCoordinatesTarget", player.displayName, player.transform.position);
  2921. Puts(_("LogTeleportPlayer", null, player.displayName, target.displayName, player.transform.position));
  2922. }
  2923. break;
  2924. default:
  2925. PrintMsgL(player, "SyntaxCommandTP");
  2926. break;
  2927. }
  2928. }
  2929.  
  2930. private void CommandTeleportNear(IPlayer user, string command, string[] args)
  2931. {
  2932. if (DisabledCommandData.DisabledCommands.Contains(command.ToLower())) { user.Reply("Disabled command: " + command); return; }
  2933. var player = user.Object as BasePlayer;
  2934. if (!player || !IsAllowedMsg(player, PermTpN) || !player.IsConnected || player.IsSleeping()) return;
  2935. switch (args.Length)
  2936. {
  2937. case 1:
  2938. case 2:
  2939. var target = FindPlayersSingle(args[0], player);
  2940. if (target == null) return;
  2941. if (target == player)
  2942. {
  2943. #if DEBUG
  2944. Puts("Debug mode - allowing self teleport.");
  2945. #else
  2946. PrintMsgL(player, "CantTeleportToSelf");
  2947. return;
  2948. #endif
  2949. }
  2950. int distance = 0;
  2951. if (args.Length != 2 || !int.TryParse(args[1], out distance))
  2952. distance = config.Admin.TeleportNearDefaultDistance;
  2953. float x = UnityEngine.Random.Range(-distance, distance);
  2954. var z = (float)Math.Sqrt(Math.Pow(distance, 2) - Math.Pow(x, 2));
  2955. var destination = target.transform.position;
  2956. destination.x -= x;
  2957. destination.z -= z;
  2958. Teleport(player, GetGroundBuilding(destination), true);
  2959. PrintMsgL(player, "AdminTP", target.displayName);
  2960. Puts(_("LogTeleport", null, player.displayName, target.displayName));
  2961. if (config.Admin.AnnounceTeleportToTarget)
  2962. PrintMsgL(target, "AdminTPTarget", player.displayName);
  2963. break;
  2964. default:
  2965. PrintMsgL(player, "SyntaxCommandTPN");
  2966. break;
  2967. }
  2968. }
  2969.  
  2970. private void CommandTeleportLocation(IPlayer user, string command, string[] args)
  2971. {
  2972. if (DisabledCommandData.DisabledCommands.Contains(command.ToLower())) { user.Reply("Disabled command: " + command); return; }
  2973. var player = user.Object as BasePlayer;
  2974. if (!player || !IsAllowedMsg(player, PermTpL) || !player.IsConnected || player.IsSleeping()) return;
  2975. AdminData adminData;
  2976. if (!_Admin.TryGetValue(player.userID, out adminData) || adminData.Locations.Count <= 0)
  2977. {
  2978. PrintMsgL(player, "AdminLocationListEmpty");
  2979. return;
  2980. }
  2981. switch (args.Length)
  2982. {
  2983. case 0:
  2984. PrintMsgL(player, "AdminLocationList");
  2985. foreach (var location in adminData.Locations)
  2986. PrintMsgL(player, $"{location.Key} {location.Value}");
  2987. break;
  2988. case 1:
  2989. Vector3 loc;
  2990. if (!adminData.Locations.TryGetValue(args[0], out loc))
  2991. {
  2992. PrintMsgL(player, "LocationNotFound");
  2993. return;
  2994. }
  2995. Teleport(player, loc, true);
  2996. PrintMsgL(player, "AdminTPLocation", args[0]);
  2997. break;
  2998. default:
  2999. PrintMsgL(player, "SyntaxCommandTPL");
  3000. break;
  3001. }
  3002. }
  3003.  
  3004. private void CommandSaveTeleportLocation(IPlayer user, string command, string[] args)
  3005. {
  3006. if (DisabledCommandData.DisabledCommands.Contains(command.ToLower())) { user.Reply("Disabled command: " + command); return; }
  3007. var player = user.Object as BasePlayer;
  3008. if (!player || !IsAllowedMsg(player, PermTpSave) || !player.IsConnected || player.IsSleeping()) return;
  3009. if (args.Length != 1)
  3010. {
  3011. PrintMsgL(player, "SyntaxCommandTPSave");
  3012. return;
  3013. }
  3014. AdminData adminData;
  3015. if (!_Admin.TryGetValue(player.userID, out adminData))
  3016. _Admin[player.userID] = adminData = new AdminData();
  3017. Vector3 location;
  3018. if (adminData.Locations.TryGetValue(args[0], out location))
  3019. {
  3020. PrintMsgL(player, "LocationExists", location);
  3021. return;
  3022. }
  3023. var positionCoordinates = player.transform.position;
  3024. if (!CanBypassRestrictions(player.UserIDString))
  3025. {
  3026. foreach (var loc in adminData.Locations)
  3027. {
  3028. if ((positionCoordinates - loc.Value).magnitude < config.Admin.LocationRadius)
  3029. {
  3030. PrintMsgL(player, "LocationExistsNearby", loc.Key);
  3031. return;
  3032. }
  3033. }
  3034. }
  3035. adminData.Locations[args[0]] = positionCoordinates;
  3036. PrintMsgL(player, "AdminTPLocationSave");
  3037. changedAdmin = true;
  3038. }
  3039.  
  3040. private void CommandRemoveTeleportLocation(IPlayer user, string command, string[] args)
  3041. {
  3042. if (DisabledCommandData.DisabledCommands.Contains(command.ToLower())) { user.Reply("Disabled command: " + command); return; }
  3043. var player = user.Object as BasePlayer;
  3044. if (!player || !IsAllowedMsg(player, PermTpRemove) || !player.IsConnected || player.IsSleeping()) return;
  3045. if (args.Length != 1)
  3046. {
  3047. PrintMsgL(player, "SyntaxCommandTPRemove");
  3048. return;
  3049. }
  3050. AdminData adminData;
  3051. if (!_Admin.TryGetValue(player.userID, out adminData) || adminData.Locations.Count <= 0)
  3052. {
  3053. PrintMsgL(player, "AdminLocationListEmpty");
  3054. return;
  3055. }
  3056. if (adminData.Locations.Remove(args[0]))
  3057. {
  3058. PrintMsgL(player, "AdminTPLocationRemove", args[0]);
  3059. changedAdmin = true;
  3060. return;
  3061. }
  3062. PrintMsgL(player, "LocationNotFound");
  3063. }
  3064.  
  3065. private void CommandTeleportBack(IPlayer user, string command, string[] args)
  3066. {
  3067. if (DisabledCommandData.DisabledCommands.Contains(command.ToLower())) { user.Reply("Disabled command: " + command); return; }
  3068. var player = user.Object as BasePlayer;
  3069. if (!player || !IsAllowedMsg(player, PermTpB) || !player.IsConnected || player.IsSleeping()) return;
  3070. if (args.Length != 0)
  3071. {
  3072. PrintMsgL(player, "SyntaxCommandTPB");
  3073. return;
  3074. }
  3075. AdminData adminData;
  3076. if (!_Admin.TryGetValue(player.userID, out adminData) || adminData.PreviousLocation == Vector3.zero)
  3077. {
  3078. PrintMsgL(player, "NoPreviousLocationSaved");
  3079. return;
  3080. }
  3081.  
  3082. Teleport(player, adminData.PreviousLocation, false);
  3083. adminData.PreviousLocation = Vector3.zero;
  3084. changedAdmin = true;
  3085. PrintMsgL(player, "AdminTPBack");
  3086. Puts(_("LogTeleportBack", null, player.displayName));
  3087. }
  3088.  
  3089. private void CommandSetHome(IPlayer user, string command, string[] args)
  3090. {
  3091. if (DisabledCommandData.DisabledCommands.Contains(command.ToLower())) { user.Reply("Disabled command: " + command); return; }
  3092. var player = user.Object as BasePlayer;
  3093. if (!player || !IsAllowed(player, PermHome) || !player.IsConnected || player.IsSleeping()) return;
  3094. if (!config.Settings.HomesEnabled) { user.Reply("Homes are not enabled in the config."); return; }
  3095. if (args.Length != 1)
  3096. {
  3097. PrintMsgL(player, "SyntaxCommandSetHome");
  3098. return;
  3099. }
  3100. string err = null;
  3101. HomeData homeData;
  3102. if (!_Home.TryGetValue(player.userID, out homeData))
  3103. _Home[player.userID] = homeData = new HomeData();
  3104. var limit = GetHigher(player, config.Home.VIPHomesLimits, config.Home.HomesLimit, true);
  3105. if (!args[0].All(char.IsLetterOrDigit))
  3106. {
  3107. PrintMsgL(player, "InvalidCharacter");
  3108. return;
  3109. }
  3110. Vector3 location;
  3111. if (homeData.Locations.TryGetValue(args[0], out location))
  3112. {
  3113. PrintMsgL(player, "HomeExists", location);
  3114. return;
  3115. }
  3116. var positionCoordinates = player.transform.position;
  3117. if (!CanBypassRestrictions(player.UserIDString))
  3118. {
  3119. err = CheckPlayer(player, false, CanCraftHome(player), true, "sethome");
  3120. if (err != null)
  3121. {
  3122. PrintMsgL(player, err);
  3123. return;
  3124. }
  3125. if (!player.CanBuild())
  3126. {
  3127. PrintMsgL(player, "HomeTPBuildingBlocked");
  3128. return;
  3129. }
  3130. if (limit > 0 && homeData.Locations.Count >= limit)
  3131. {
  3132. PrintMsgL(player, "HomeMaxLocations", limit);
  3133. return;
  3134. }
  3135. foreach (var loc in homeData.Locations)
  3136. {
  3137. if ((positionCoordinates - loc.Value).magnitude < config.Home.LocationRadius)
  3138. {
  3139. PrintMsgL(player, "HomeExistsNearby", loc.Key);
  3140. return;
  3141. }
  3142. }
  3143. err = CanPlayerTeleport(player, positionCoordinates);
  3144. if (err != null)
  3145. {
  3146. SendReply(player, err);
  3147. return;
  3148. }
  3149. err = CheckFoundation(player.userID, positionCoordinates);
  3150. if (err != null)
  3151. {
  3152. PrintMsgL(player, err);
  3153. return;
  3154. }
  3155. }
  3156. if (player.IsAdmin && config.Settings.DrawHomeSphere) player.SendConsoleCommand("ddraw.sphere", 30f, Color.blue, GetGround(positionCoordinates), 2.5f);
  3157. homeData.Locations[args[0]] = positionCoordinates;
  3158. changedHome = true;
  3159. PrintMsgL(player, "HomeSave");
  3160. PrintMsgL(player, "HomeQuota", homeData.Locations.Count, limit);
  3161. }
  3162.  
  3163. private void CommandRemoveHome(IPlayer user, string command, string[] args)
  3164. {
  3165. if (DisabledCommandData.DisabledCommands.Contains(command.ToLower())) { user.Reply("Disabled command: " + command); return; }
  3166. if (!config.Settings.HomesEnabled) { user.Reply("Homes are not enabled in the config."); return; }
  3167. var player = user.Object as BasePlayer;
  3168. if (!player || !IsAllowed(player, PermHome) || !player.IsConnected || player.IsSleeping()) return;
  3169. if (player.IsAdmin && args.Length == 2 && args[0] == "all")
  3170. {
  3171. float radius;
  3172. if (float.TryParse(args[1], out radius))
  3173. {
  3174. int amount = 0;
  3175. foreach (var home in _Home.ToList())
  3176. {
  3177. foreach (var location in home.Value.Locations.ToList())
  3178. {
  3179. if (Vector3Ex.Distance2D(location.Value, player.transform.position) < radius)
  3180. {
  3181. string username = covalence.Players.FindPlayerById(home.Key.ToString())?.Name ?? "N/A";
  3182. Puts("{0} ({1}) removed home from {2} ({3}) at {4}", player.displayName, player.userID, username, home.Key, location.Value);
  3183. player.SendConsoleCommand("ddraw.text", 30f, Color.red, location.Value, "X");
  3184. home.Value.Locations.Remove(location.Key);
  3185. amount++;
  3186. }
  3187. }
  3188. }
  3189.  
  3190. user.Reply($"Removed {amount} homes within {radius} meters");
  3191. }
  3192. else user.Reply("/removehome all <radius>");
  3193.  
  3194. return;
  3195. }
  3196. if (args.Length != 1)
  3197. {
  3198. PrintMsgL(player, "SyntaxCommandRemoveHome");
  3199. return;
  3200. }
  3201. HomeData homeData;
  3202. if (!_Home.TryGetValue(player.userID, out homeData) || homeData.Locations.Count <= 0)
  3203. {
  3204. PrintMsgL(player, "HomeListEmpty");
  3205. return;
  3206. }
  3207. if (homeData.Locations.Remove(args[0]))
  3208. {
  3209. changedHome = true;
  3210. PrintMsgL(player, "HomeRemove", args[0]);
  3211. }
  3212. else
  3213. PrintMsgL(player, "HomeNotFound");
  3214. }
  3215.  
  3216. private void CommandHome(IPlayer user, string command, string[] args)
  3217. {
  3218. if (DisabledCommandData.DisabledCommands.Contains(command.ToLower())) { user.Reply("Disabled command: " + command); return; }
  3219. if (!config.Settings.HomesEnabled) { user.Reply("Homes are not enabled in the config."); return; }
  3220. var player = user.Object as BasePlayer;
  3221. if (!player || !IsAllowed(player, PermHome) || !player.IsConnected || player.IsSleeping()) return;
  3222. if (args.Length == 0)
  3223. {
  3224. PrintMsgL(player, "SyntaxCommandHome");
  3225. if (IsAllowed(player)) PrintMsgL(player, "SyntaxCommandHomeAdmin");
  3226. return;
  3227. }
  3228. switch (args[0].ToLower())
  3229. {
  3230. case "add":
  3231. CommandSetHome(user, command, args.Skip(1).ToArray());
  3232. break;
  3233. case "list":
  3234. CommandListHomes(user, command, args.Skip(1).ToArray());
  3235. break;
  3236. case "remove":
  3237. CommandRemoveHome(user, command, args.Skip(1).ToArray());
  3238. break;
  3239. case "radius":
  3240. CommandHomeRadius(user, command, args.Skip(1).ToArray());
  3241. break;
  3242. case "delete":
  3243. CommandHomeDelete(user, command, args.Skip(1).ToArray());
  3244. break;
  3245. case "tp":
  3246. CommandHomeAdminTP(user, command, args.Skip(1).ToArray());
  3247. break;
  3248. case "homes":
  3249. CommandHomeHomes(user, command, args.Skip(1).ToArray());
  3250. break;
  3251. case "wipe":
  3252. CommandWipeHomes(user, command, args.Skip(1).ToArray());
  3253. break;
  3254. default:
  3255. cmdChatHomeTP(player, command, args);
  3256. break;
  3257. }
  3258. }
  3259.  
  3260. private void CommandHomeRadius(IPlayer user, string command, string[] args)
  3261. {
  3262. if (DisabledCommandData.DisabledCommands.Contains(command.ToLower())) { user.Reply("Disabled command: " + command); return; }
  3263. var player = user.Object as BasePlayer;
  3264. if (!player || !IsAllowedMsg(player, PermRadiusHome) || !player.IsConnected || player.IsSleeping()) return;
  3265. float radius;
  3266. if (args.Length != 1 || !float.TryParse(args[0], out radius)) radius = 10;
  3267. var found = false;
  3268. foreach (var homeData in _Home)
  3269. {
  3270. var toRemove = new List<string>();
  3271. var target = RustCore.FindPlayerById(homeData.Key)?.displayName ?? homeData.Key.ToString();
  3272. foreach (var location in homeData.Value.Locations)
  3273. {
  3274. if ((player.transform.position - location.Value).magnitude <= radius)
  3275. {
  3276. string err = CheckFoundation(homeData.Key, location.Value);
  3277. if (err != null)
  3278. {
  3279. PrintMsgL(player, "HomeRemovedInvalid", $"{location.Key} {location.Value}");
  3280. PrintMsgL(player, err);
  3281. toRemove.Add(location.Key);
  3282. found = true;
  3283. continue;
  3284. }
  3285. var entity = GetFoundationOwned(location.Value, homeData.Key);
  3286. if (entity == null)
  3287. {
  3288. player.SendConsoleCommand("ddraw.text", 30f, Color.blue, location.Value, $"<size=20>{target} - {location.Key} {location.Value}</size>");
  3289. }
  3290. else
  3291. {
  3292. player.SendConsoleCommand("ddraw.text", 30f, Color.blue, entity.CenterPoint() + new Vector3(0, .5f), $"<size=20>{target} - {location.Key} {location.Value}</size>");
  3293. DrawBox(player, entity.CenterPoint(), entity.transform.rotation, entity.bounds.size);
  3294. }
  3295. PrintMsg(player, $"{target} - {location.Key} {location.Value}");
  3296. found = true;
  3297. }
  3298. }
  3299. foreach (var loc in toRemove)
  3300. {
  3301. homeData.Value.Locations.Remove(loc);
  3302. changedHome = true;
  3303. }
  3304. }
  3305. if (!found)
  3306. PrintMsgL(player, "HomeNoFound");
  3307. }
  3308.  
  3309. private void CommandHomeDelete(IPlayer user, string command, string[] args)
  3310. {
  3311. if (DisabledCommandData.DisabledCommands.Contains(command.ToLower())) { user.Reply("Disabled command: " + command); return; }
  3312. var player = user.Object as BasePlayer;
  3313. if (!player || !IsAllowedMsg(player, PermDeleteHome) || !player.IsConnected || player.IsSleeping()) return;
  3314. if (args.Length != 2)
  3315. {
  3316. PrintMsgL(player, "SyntaxCommandHomeDelete");
  3317. return;
  3318. }
  3319. var userId = FindPlayersSingleId(args[0], player);
  3320. if (userId <= 0) return;
  3321. HomeData targetHome;
  3322. if (!_Home.TryGetValue(userId, out targetHome) || !targetHome.Locations.Remove(args[1]))
  3323. {
  3324. PrintMsgL(player, "HomeNotFound");
  3325. return;
  3326. }
  3327. changedHome = true;
  3328. PrintMsgL(player, "HomeDelete", args[0], args[1]);
  3329. }
  3330.  
  3331. private void CommandHomeAdminTP(IPlayer user, string command, string[] args)
  3332. {
  3333. if (DisabledCommandData.DisabledCommands.Contains(command.ToLower())) { user.Reply("Disabled command: " + command); return; }
  3334. var player = user.Object as BasePlayer;
  3335. if (!player || !IsAllowedMsg(player, PermTpHome) || !player.IsConnected || player.IsSleeping()) return;
  3336. if (args.Length != 2)
  3337. {
  3338. PrintMsgL(player, "SyntaxCommandHomeAdminTP");
  3339. return;
  3340. }
  3341. var userId = FindPlayersSingleId(args[0], player);
  3342. if (userId <= 0) return;
  3343. HomeData targetHome;
  3344. Vector3 location;
  3345. if (!_Home.TryGetValue(userId, out targetHome) || !targetHome.Locations.TryGetValue(args[1], out location))
  3346. {
  3347. PrintMsgL(player, "HomeNotFound");
  3348. return;
  3349. }
  3350.  
  3351. Teleport(player, location, true);
  3352. PrintMsgL(player, "HomeAdminTP", args[0], args[1]);
  3353. }
  3354.  
  3355. // Check that plugins are available and enabled for CheckEconomy()
  3356. private bool UseEconomy()
  3357. {
  3358. return (config.Settings.UseEconomics && Economics != null) || (config.Settings.UseServerRewards && ServerRewards != null);
  3359. }
  3360.  
  3361. // Check balance on multiple plugins and optionally withdraw money from the player
  3362. private bool CheckEconomy(BasePlayer player, double bypass, bool withdraw = false, bool deposit = false)
  3363. {
  3364. if (player == null)
  3365. {
  3366. return false;
  3367. }
  3368. if (CanBypassRestrictions(player.UserIDString)) return true;
  3369. bool foundmoney = false;
  3370.  
  3371. // Check Economics first. If not in use or balance low, check ServerRewards below
  3372. if (config.Settings.UseEconomics && Economics != null)
  3373. {
  3374. var balance = (double)Economics?.CallHook("Balance", player.UserIDString);
  3375. if (balance >= bypass)
  3376. {
  3377. foundmoney = true;
  3378. if (withdraw)
  3379. {
  3380. return Convert.ToBoolean(Economics?.CallHook("Withdraw", player.userID, bypass));
  3381. }
  3382. else if (deposit)
  3383. {
  3384. Economics?.CallHook("Deposit", player.userID, bypass);
  3385. }
  3386. }
  3387. }
  3388.  
  3389. // No money via Economics, or plugin not in use. Try ServerRewards.
  3390. if (!foundmoney && config.Settings.UseServerRewards && ServerRewards != null)
  3391. {
  3392. object bal = ServerRewards?.Call("CheckPoints", player.userID);
  3393. var balance = Convert.ToDouble(bal);
  3394. if (balance >= bypass)
  3395. {
  3396. foundmoney = true;
  3397. if (withdraw)
  3398. {
  3399. return Convert.ToBoolean(ServerRewards?.Call("TakePoints", player.userID, (int)bypass));
  3400. }
  3401. else if (deposit)
  3402. {
  3403. ServerRewards?.Call("AddPoints", player.userID, (int)bypass);
  3404. }
  3405. }
  3406. }
  3407.  
  3408. // Just checking balance without withdrawal - did we find anything?
  3409. return foundmoney;
  3410. }
  3411.  
  3412. private void cmdChatHomeTP(BasePlayer player, string command, string[] args)
  3413. {
  3414. if (DisabledCommandData.DisabledCommands.Contains(command.ToLower())) { player.ChatMessage("Disabled command."); return; }
  3415. if (!IsAllowed(player, PermHome) || !player.IsConnected || player.IsSleeping()) return;
  3416. bool paidmoney = false;
  3417. if (!config.Settings.HomesEnabled) { player.ChatMessage("Homes are not enabled in the config."); return; }
  3418. if (args.Length < 1)
  3419. {
  3420. PrintMsgL(player, "SyntaxCommandHome");
  3421. return;
  3422. }
  3423. HomeData homeData;
  3424. if (!_Home.TryGetValue(player.userID, out homeData) || homeData.Locations.Count <= 0)
  3425. {
  3426. PrintMsgL(player, "HomeListEmpty");
  3427. return;
  3428. }
  3429. Vector3 location;
  3430. if (!homeData.Locations.TryGetValue(args[0], out location))
  3431. {
  3432. PrintMsgL(player, "HomeNotFound");
  3433. return;
  3434. }
  3435. int limit = 0;
  3436. string err = null;
  3437. var timestamp = Facepunch.Math.Epoch.Current;
  3438. if (!CanBypassRestrictions(player.UserIDString))
  3439. {
  3440. float globalCooldownTime = GetGlobalCooldown(player);
  3441. if (globalCooldownTime > 0f)
  3442. {
  3443. PrintMsgL(player, "WaitGlobalCooldown", FormatTime(player, (int)globalCooldownTime));
  3444. return;
  3445. }
  3446. if (config.Settings.BlockAuthorizedTeleporting && player.IsBuildingAuthed())
  3447. {
  3448. PrintMsgL(player, "CannotTeleportFromHome");
  3449. return;
  3450. }
  3451. err = CheckPlayer(player, config.Home.UsableOutOfBuildingBlocked, CanCraftHome(player), true, "home");
  3452. if (err != null)
  3453. {
  3454. PrintMsgL(player, err);
  3455. return;
  3456. }
  3457. if (config.Settings.BlockNoEscape && Convert.ToBoolean(NoEscape?.Call("IsBlockedZone", location)))
  3458. {
  3459. PrintMsgL(player, "TPNoEscapeBlocked");
  3460. return;
  3461. }
  3462. err = CheckFoundation(player.userID, location) ?? CheckTargetLocation(player, location, config.Home.UsableIntoBuildingBlocked, config.Home.CupOwnerAllowOnBuildingBlocked);
  3463. if (err != null)
  3464. {
  3465. PrintMsgL(player, "HomeRemovedInvalid", args[0]);
  3466. PrintMsgL(player, err);
  3467. homeData.Locations.Remove(args[0]);
  3468. changedHome = true;
  3469. return;
  3470. }
  3471. var cooldown = GetLower(player, config.Home.VIPCooldowns, config.Home.Cooldown);
  3472. if (cooldown > 0 && timestamp - homeData.Teleports.Timestamp < cooldown)
  3473. {
  3474. var cmdSent = args.Length >= 2 ? args[1].ToLower() : string.Empty;
  3475.  
  3476. if (!string.IsNullOrEmpty(config.Settings.BypassCMD) && !paidmoney)
  3477. {
  3478. if (cmdSent == config.Settings.BypassCMD.ToLower() && config.Home.Bypass > -1)
  3479. {
  3480. bool foundmoney = CheckEconomy(player, config.Home.Bypass);
  3481.  
  3482. if (foundmoney)
  3483. {
  3484. CheckEconomy(player, config.Home.Bypass, true);
  3485. paidmoney = true;
  3486.  
  3487. if (config.Home.Bypass > 0)
  3488. {
  3489. PrintMsgL(player, "HomeTPCooldownBypass", config.Home.Bypass);
  3490. }
  3491.  
  3492. if (config.Home.Pay > 0)
  3493. {
  3494. PrintMsgL(player, "PayToHome", config.Home.Pay);
  3495. }
  3496. }
  3497. else
  3498. {
  3499. PrintMsgL(player, "HomeTPCooldownBypassF", config.Home.Bypass);
  3500. return;
  3501. }
  3502. }
  3503. else if (UseEconomy())
  3504. {
  3505. if (config.Home.Bypass > 0)
  3506. {
  3507. var remain = cooldown - (timestamp - homeData.Teleports.Timestamp);
  3508. PrintMsgL(player, "HomeTPCooldown", FormatTime(player, remain));
  3509. PrintMsgL(player, "HomeTPCooldownBypassP", config.Home.Bypass);
  3510. PrintMsgL(player, "HomeTPCooldownBypassP2", config.Settings.BypassCMD);
  3511. return;
  3512. }
  3513. }
  3514. else
  3515. {
  3516. var remain = cooldown - (timestamp - homeData.Teleports.Timestamp);
  3517.  
  3518. PrintMsgL(player, "HomeTPCooldown", FormatTime(player, remain));
  3519. return;
  3520. }
  3521. }
  3522. else
  3523. {
  3524. var remain = cooldown - (timestamp - homeData.Teleports.Timestamp);
  3525. PrintMsgL(player, "HomeTPCooldown", FormatTime(player, remain));
  3526. return;
  3527. }
  3528. }
  3529. var currentDate = DateTime.Now.ToString("d");
  3530. if (homeData.Teleports.Date != currentDate)
  3531. {
  3532. homeData.Teleports.Amount = 0;
  3533. homeData.Teleports.Date = currentDate;
  3534. }
  3535. limit = GetHigher(player, config.Home.VIPDailyLimits, config.Home.DailyLimit, true);
  3536. if (limit > 0 && homeData.Teleports.Amount >= limit)
  3537. {
  3538. PrintMsgL(player, "HomeTPLimitReached", limit);
  3539. return;
  3540. }
  3541. err = CanPlayerTeleport(player, location);
  3542. if (err != null)
  3543. {
  3544. SendReply(player, err);
  3545. return;
  3546. }
  3547. err = CheckItems(player);
  3548. if (err != null)
  3549. {
  3550. PrintMsgL(player, "TPBlockedItem", err);
  3551. return;
  3552. }
  3553. if (config.Home.UsableFromSafeZoneOnly && !player.InSafeZone())
  3554. {
  3555. PrintMsgL(player, "TPHomeSafeZoneOnly");
  3556. return;
  3557. }
  3558. }
  3559. if (TeleportTimers.ContainsKey(player.userID))
  3560. {
  3561. PrintMsgL(player, "TeleportPendingTPC");
  3562. return;
  3563. }
  3564. var countdown = GetLower(player, config.Home.VIPCountdowns, config.Home.Countdown);
  3565. TeleportTimers[player.userID] = new TeleportTimer
  3566. {
  3567. OriginPlayer = player,
  3568. Timer = timer.Once(countdown, () =>
  3569. {
  3570. #if DEBUG
  3571. Puts("Calling CheckPlayer from cmdChatHomeTP");
  3572. #endif
  3573. if (!CanBypassRestrictions(player.UserIDString))
  3574. {
  3575. err = CheckPlayer(player, config.Home.UsableOutOfBuildingBlocked, CanCraftHome(player), true, "home");
  3576. if (err != null)
  3577. {
  3578. PrintMsgL(player, "Interrupted");
  3579. PrintMsgL(player, err);
  3580. if (paidmoney)
  3581. {
  3582. paidmoney = false;
  3583. CheckEconomy(player, config.Home.Bypass, false, true);
  3584. }
  3585. TeleportTimers.Remove(player.userID);
  3586. return;
  3587. }
  3588. err = CanPlayerTeleport(player, location);
  3589. if (err != null)
  3590. {
  3591. PrintMsgL(player, "Interrupted");
  3592. PrintMsgL(player, err);
  3593. if (paidmoney)
  3594. {
  3595. paidmoney = false;
  3596. CheckEconomy(player, config.Home.Bypass, false, true);
  3597. }
  3598. TeleportTimers.Remove(player.userID);
  3599. return;
  3600. }
  3601. err = CheckItems(player);
  3602. if (err != null)
  3603. {
  3604. PrintMsgL(player, "Interrupted");
  3605. PrintMsgL(player, "TPBlockedItem", err);
  3606. if (paidmoney)
  3607. {
  3608. paidmoney = false;
  3609. CheckEconomy(player, config.Home.Bypass, false, true);
  3610. }
  3611. TeleportTimers.Remove(player.userID);
  3612. return;
  3613. }
  3614. err = CheckFoundation(player.userID, location) ?? CheckTargetLocation(player, location, config.Home.UsableIntoBuildingBlocked, config.Home.CupOwnerAllowOnBuildingBlocked);
  3615. if (err != null)
  3616. {
  3617. PrintMsgL(player, "HomeRemovedInvalid", args[0]);
  3618. PrintMsgL(player, err);
  3619. homeData.Locations.Remove(args[0]);
  3620. changedHome = true;
  3621. if (paidmoney)
  3622. {
  3623. paidmoney = false;
  3624. CheckEconomy(player, config.Home.Bypass, false, true);
  3625. }
  3626. return;
  3627. }
  3628. if (UseEconomy())
  3629. {
  3630. if (config.Home.Pay < 0)
  3631. {
  3632. TeleportTimers.Remove(player.userID);
  3633. PrintMsgL(player, "DM_TownTPDisabled", "/home");
  3634. return;
  3635. }
  3636. else if (config.Home.Pay > 0)
  3637. {
  3638. if (!CheckEconomy(player, config.Home.Pay))
  3639. {
  3640. TeleportTimers.Remove(player.userID);
  3641. PrintMsgL(player, "TPNoMoney", config.Home.Pay);
  3642. return;
  3643. }
  3644.  
  3645. if (!paidmoney)
  3646. {
  3647. PrintMsgL(player, "TPMoney", (double)config.Home.Pay);
  3648. }
  3649.  
  3650. paidmoney = CheckEconomy(player, config.Home.Pay, true);
  3651. }
  3652. }
  3653. }
  3654. Teleport(player, location, config.Home.AllowTPB);
  3655. homeData.Teleports.Amount++;
  3656. homeData.Teleports.Timestamp = timestamp;
  3657. changedHome = true;
  3658. PrintMsgL(player, "HomeTP", args[0]);
  3659. if (limit > 0) PrintMsgL(player, "HomeTPAmount", limit - homeData.Teleports.Amount);
  3660. TeleportTimers.Remove(player.userID);
  3661. })
  3662. };
  3663.  
  3664. if (countdown > 0)
  3665. {
  3666. PrintMsgL(player, "HomeTPStarted", args[0], countdown);
  3667. }
  3668. }
  3669.  
  3670. private void CommandListHomes(IPlayer user, string command, string[] args)
  3671. {
  3672. if (DisabledCommandData.DisabledCommands.Contains(command.ToLower())) { user.Reply("Disabled command: " + command); return; }
  3673. var player = user.Object as BasePlayer;
  3674. if (!player || !player.IsConnected || player.IsSleeping()) return;
  3675. if (!config.Settings.HomesEnabled) { user.Reply("Homes are not enabled in the config."); return; }
  3676. if (args.Length != 0)
  3677. {
  3678. PrintMsgL(player, "SyntaxCommandListHomes");
  3679. return;
  3680. }
  3681. HomeData homeData;
  3682. if (!_Home.TryGetValue(player.userID, out homeData) || homeData.Locations.Count <= 0)
  3683. {
  3684. PrintMsgL(player, "HomeListEmpty");
  3685. return;
  3686. }
  3687. PrintMsgL(player, "HomeList");
  3688. ValidateHomes(player, homeData, true);
  3689. foreach (var location in homeData.Locations)
  3690. PrintMsgL(player, $"{location.Key} {location.Value}");
  3691. }
  3692.  
  3693. private void ValidateHomes(BasePlayer player, HomeData homeData, bool flag)
  3694. {
  3695. if (config.Home.CheckValidOnList)
  3696. {
  3697. var toRemove = new List<string>();
  3698. foreach (var location in homeData.Locations)
  3699. {
  3700. var err = CheckFoundation(player.userID, location.Value);
  3701. if (err != null)
  3702. {
  3703. if (flag) PrintMsgL(player, err);
  3704. toRemove.Add(location.Key);
  3705. continue;
  3706. }
  3707. if (flag) PrintMsgL(player, $"{location.Key} {location.Value}");
  3708. }
  3709. foreach (var loc in toRemove)
  3710. {
  3711. if (flag) PrintMsgL(player, "HomeRemovedInvalid", loc);
  3712. homeData.Locations.Remove(loc);
  3713. changedHome = true;
  3714. }
  3715. }
  3716. }
  3717.  
  3718. private void CommandHomeHomes(IPlayer user, string command, string[] args)
  3719. {
  3720. if (DisabledCommandData.DisabledCommands.Contains(command.ToLower())) { user.Reply("Disabled command: " + command); return; }
  3721. var player = user.Object as BasePlayer;
  3722. if (!player || !IsAllowedMsg(player, PermHomeHomes) || !player.IsConnected || player.IsSleeping()) return;
  3723. if (args.Length != 1)
  3724. {
  3725. PrintMsgL(player, "SyntaxCommandHomeHomes");
  3726. return;
  3727. }
  3728. var userId = FindPlayersSingleId(args[0], player);
  3729. if (userId <= 0) return;
  3730. HomeData homeData;
  3731. if (!_Home.TryGetValue(userId, out homeData) || homeData.Locations.Count <= 0)
  3732. {
  3733. PrintMsgL(player, "HomeListEmpty");
  3734. return;
  3735. }
  3736. PrintMsgL(player, "HomeList");
  3737. var toRemove = new List<string>();
  3738. foreach (var location in homeData.Locations)
  3739. {
  3740. var err = CheckFoundation(userId, location.Value);
  3741. if (err != null)
  3742. {
  3743. PrintMsgL(player, err);
  3744. toRemove.Add(location.Key);
  3745. continue;
  3746. }
  3747. PrintMsgL(player, $"{location.Key} {location.Value}");
  3748. }
  3749. foreach (var loc in toRemove)
  3750. {
  3751. PrintMsgL(player, "HomeRemovedInvalid", loc);
  3752. homeData.Locations.Remove(loc);
  3753. changedHome = true;
  3754. }
  3755. }
  3756.  
  3757. private void CommandTeleportAcceptToggle(IPlayer user, string command, string[] args)
  3758. {
  3759. if (DisabledCommandData.DisabledCommands.Contains(command.ToLower())) { user.Reply("Disabled command: " + command); return; }
  3760. var player = user.Object as BasePlayer;
  3761. if (!player || !player.IsConnected || player.IsSleeping()) return;
  3762.  
  3763. if (TPTToggle.Contains(player.UserIDString))
  3764. {
  3765. TPTToggle.Remove(player.UserIDString);
  3766. PrintMsgL(player, "AcceptToggleOn");
  3767. }
  3768. else
  3769. {
  3770. TPTToggle.Add(player.UserIDString);
  3771. PrintMsgL(player, "AcceptToggleOff");
  3772. }
  3773.  
  3774. changedTPT = true;
  3775. }
  3776.  
  3777. public bool IsOnSameTeam(ulong playerId, ulong targetId)
  3778. {
  3779. RelationshipManager.PlayerTeam team;
  3780. return RelationshipManager.ServerInstance.playerToTeam.TryGetValue(playerId, out team) && team.members.Contains(targetId);
  3781. }
  3782.  
  3783. private bool AreFriends(string playerId, string targetId)
  3784. {
  3785. return Friends != null && Convert.ToBoolean(Friends?.Call("AreFriends", playerId, targetId));
  3786. }
  3787.  
  3788. private bool IsInSameClan(string playerId, string targetId)
  3789. {
  3790. return Clans != null && Convert.ToBoolean(Clans?.Call("IsMemberOrAlly", playerId, targetId));
  3791. }
  3792.  
  3793. private void OnTeleportRequested(BasePlayer target, BasePlayer player)
  3794. {
  3795. if (!permission.UserHasPermission(target.UserIDString, PermTpT) || !permission.UserHasPermission(player.UserIDString, PermTpT) || TPTToggle.Contains(target.UserIDString))
  3796. {
  3797. return;
  3798. }
  3799.  
  3800. if (config.TPT.UseClans && IsInSameClan(player.UserIDString, target.UserIDString))
  3801. {
  3802. target.SendConsoleCommand("chat.say /tpa");
  3803. }
  3804. else if (config.TPT.UseFriends && AreFriends(player.UserIDString, target.UserIDString))
  3805. {
  3806. target.SendConsoleCommand("chat.say /tpa");
  3807. }
  3808. else if (config.TPT.UseTeams && IsOnSameTeam(player.userID, target.userID))
  3809. {
  3810. target.SendConsoleCommand("chat.say /tpa");
  3811. }
  3812. }
  3813.  
  3814. private string GetMultiplePlayers(List<BasePlayer> players)
  3815. {
  3816. var list = new List<string>();
  3817.  
  3818. foreach (var player in players)
  3819. {
  3820. string id;
  3821. if (!_players.TryGetValue(player, out id))
  3822. {
  3823. id = OnPlayerConnected(player);
  3824. }
  3825.  
  3826. list.Add(string.Format("<color={0}>{1}</color> - {2}", config.Settings.ChatCommandArgumentColor, id, player.displayName));
  3827. }
  3828.  
  3829. return string.Join(", ", list.ToArray());
  3830. }
  3831.  
  3832. private void CommandTeleportRequest(IPlayer user, string command, string[] args)
  3833. {
  3834. if (DisabledCommandData.DisabledCommands.Contains(command.ToLower())) { user.Reply("Disabled command: " + command); return; }
  3835. var player = user.Object as BasePlayer;
  3836. if (!player || !IsAllowedMsg(player, PermTpR) || !player.IsConnected || player.IsSleeping()) return;
  3837. if (!config.Settings.TPREnabled) { user.Reply("TPR is not enabled in the config."); return; }
  3838. string err = null;
  3839. if (args.Length == 0)
  3840. {
  3841. PrintMsgL(player, "SyntaxCommandTPR");
  3842. return;
  3843. }
  3844. var targets = FindPlayers(args[0]);
  3845. if (targets.Count <= 0)
  3846. {
  3847. PrintMsgL(player, "PlayerNotFound");
  3848. return;
  3849. }
  3850. BasePlayer target = null;
  3851. if (args.Length >= 2)
  3852. {
  3853. if (targets.Count > 1)
  3854. {
  3855. PrintMsgL(player, "MultiplePlayers", GetMultiplePlayers(targets));
  3856. return;
  3857. }
  3858. else target = targets[0];
  3859. }
  3860. else
  3861. {
  3862. if (targets.Count > 1)
  3863. {
  3864. PrintMsgL(player, "MultiplePlayers", GetMultiplePlayers(targets));
  3865. return;
  3866. }
  3867.  
  3868. target = targets[0];
  3869. }
  3870.  
  3871. if (target == player)
  3872. {
  3873. #if DEBUG
  3874. Puts("Debug mode - allowing self teleport.");
  3875. #else
  3876. PrintMsgL(player, "CantTeleportToSelf");
  3877. return;
  3878. #endif
  3879. }
  3880. #if DEBUG
  3881. Puts("Calling CheckPlayer from cmdChatTeleportRequest");
  3882. #endif
  3883. TeleportData tprData;
  3884. if (!_TPR.TryGetValue(player.userID, out tprData))
  3885. _TPR[player.userID] = tprData = new TeleportData();
  3886. if (!CanBypassRestrictions(player.UserIDString))
  3887. {
  3888. float globalCooldownTime = GetGlobalCooldown(player);
  3889. if (globalCooldownTime > 0f)
  3890. {
  3891. PrintMsgL(player, "WaitGlobalCooldown", FormatTime(player, (int)globalCooldownTime));
  3892. return;
  3893. }
  3894. if (config.Settings.BlockAuthorizedTeleporting && player.IsBuildingAuthed())
  3895. {
  3896. PrintMsgL(player, "CannotTeleportFromHome");
  3897. return;
  3898. }
  3899. err = CheckPlayer(player, config.TPR.UsableOutOfBuildingBlocked, CanCraftTPR(player), true, "tpr");
  3900. if (err != null)
  3901. {
  3902. PrintMsgL(player, err);
  3903. return;
  3904. }
  3905. var err2 = CheckPlayer(target, config.TPR.UsableIntoBuildingBlocked, CanCraftTPR(target), true, "tpr");
  3906. if (err2 != null)
  3907. {
  3908. string error = string.Format(lang.GetMessage("ErrorTPR", this, player.UserIDString), target.displayName, err2);
  3909. PrintMsg(player, error);
  3910. return;
  3911. }
  3912. err = CheckTargetLocation(target, target.transform.position, config.TPR.UsableIntoBuildingBlocked, config.TPR.CupOwnerAllowOnBuildingBlocked);
  3913. if (err != null)
  3914. {
  3915. PrintMsgL(player, err);
  3916. return;
  3917. }
  3918. var timestamp = Facepunch.Math.Epoch.Current;
  3919. var currentDate = DateTime.Now.ToString("d");
  3920.  
  3921. if (tprData.Date != currentDate)
  3922. {
  3923. tprData.Amount = 0;
  3924. tprData.Date = currentDate;
  3925. }
  3926.  
  3927. var cooldown = GetLower(player, config.TPR.VIPCooldowns, config.TPR.Cooldown);
  3928. if (cooldown > 0 && timestamp - tprData.Timestamp < cooldown)
  3929. {
  3930. var cmdSent = args.Length >= 2 ? args[1].ToLower() : string.Empty;
  3931.  
  3932. if (!string.IsNullOrEmpty(config.Settings.BypassCMD))
  3933. {
  3934. if (cmdSent == config.Settings.BypassCMD.ToLower() && config.TPR.Bypass > -1)
  3935. {
  3936. if (CheckEconomy(player, config.TPR.Bypass))
  3937. {
  3938. CheckEconomy(player, config.TPR.Bypass, true);
  3939.  
  3940. if (config.TPR.Bypass > 0)
  3941. {
  3942. PrintMsgL(player, "TPRCooldownBypass", config.TPR.Bypass);
  3943. }
  3944.  
  3945. if (config.TPR.Pay > 0)
  3946. {
  3947. PrintMsgL(player, "PayToTPR", config.TPR.Pay);
  3948. }
  3949. }
  3950. else
  3951. {
  3952. PrintMsgL(player, "TPRCooldownBypassF", config.TPR.Bypass);
  3953. return;
  3954. }
  3955. }
  3956. else if (UseEconomy())
  3957. {
  3958. var remain = cooldown - (timestamp - tprData.Timestamp);
  3959. PrintMsgL(player, "TPRCooldown", FormatTime(player, remain));
  3960. if (config.TPR.Bypass > -1)
  3961. {
  3962. if (config.TPR.Bypass > 0)
  3963. {
  3964. PrintMsgL(player, "TPRCooldownBypassP", config.TPR.Bypass);
  3965.  
  3966. if (config.TPR.Pay > 0)
  3967. {
  3968. PrintMsgL(player, "PayToTPR", config.TPR.Pay);
  3969. }
  3970.  
  3971. PrintMsgL(player, "TPRCooldownBypassP2a", config.Settings.BypassCMD);
  3972. return;
  3973. }
  3974. }
  3975. else return;
  3976. }
  3977. else
  3978. {
  3979. var remain = cooldown - (timestamp - tprData.Timestamp);
  3980. PrintMsgL(player, "TPRCooldown", FormatTime(player, remain));
  3981. return;
  3982. }
  3983. }
  3984. else
  3985. {
  3986. var remain = cooldown - (timestamp - tprData.Timestamp);
  3987. PrintMsgL(player, "TPRCooldown", FormatTime(player, remain));
  3988. return;
  3989. }
  3990. }
  3991. var limit = GetHigher(player, config.TPR.VIPDailyLimits, config.TPR.DailyLimit, true);
  3992. if (limit > 0 && tprData.Amount >= limit)
  3993. {
  3994. PrintMsgL(player, "TPRLimitReached", limit);
  3995. return;
  3996. }
  3997. err = CanPlayerTeleport(player, target.transform.position);
  3998. if (err != null)
  3999. {
  4000. SendReply(player, err);
  4001. return;
  4002. }
  4003. err = CanPlayerTeleport(target, player.transform.position);
  4004. if (err != null)
  4005. {
  4006. PrintMsgL(player, string.IsNullOrEmpty(err) ? "TPRTarget" : err);
  4007. return;
  4008. }
  4009. err = CheckItems(player);
  4010. if (err != null)
  4011. {
  4012. PrintMsgL(player, "TPBlockedItem", err);
  4013. return;
  4014. }
  4015. }
  4016. if (TeleportTimers.ContainsKey(player.userID))
  4017. {
  4018. PrintMsgL(player, "TeleportPendingTPC");
  4019. return;
  4020. }
  4021. if (TeleportTimers.ContainsKey(target.userID))
  4022. {
  4023. PrintMsgL(player, "TeleportPendingTarget");
  4024. return;
  4025. }
  4026. if (PlayersRequests.ContainsKey(player.userID))
  4027. {
  4028. PrintMsgL(player, "PendingRequest");
  4029. return;
  4030. }
  4031. if (PlayersRequests.ContainsKey(target.userID))
  4032. {
  4033. PrintMsgL(player, "PendingRequestTarget");
  4034. return;
  4035. }
  4036. if (!config.TPR.UseClans_Friends_Teams || IsInSameClan(player.UserIDString, target.UserIDString) || AreFriends(player.UserIDString, target.UserIDString) || IsOnSameTeam(player.userID, target.userID) || CanBypassRestrictions(player.UserIDString))
  4037. {
  4038. PlayersRequests[player.userID] = target;
  4039. PlayersRequests[target.userID] = player;
  4040. PendingRequests[target.userID] = timer.Once(config.TPR.RequestDuration, () => { RequestTimedOut(player, target); });
  4041. PrintMsgL(player, "Request", target.displayName);
  4042. PrintMsgL(target, "RequestTarget", player.displayName);
  4043. Interface.CallHook("OnTeleportRequested", target, player);
  4044. }
  4045. else
  4046. {
  4047. PrintMsgL(player, "TPR_NoClan_NoFriend_NoTeam");
  4048. }
  4049. }
  4050.  
  4051. private void CommandTeleportAccept(IPlayer user, string command, string[] args)
  4052. {
  4053. if (DisabledCommandData.DisabledCommands.Contains(command.ToLower())) { user.Reply("Disabled command: " + command); return; }
  4054. if (!config.Settings.TPREnabled) { user.Reply("TPR is not enabled in the config."); return; }
  4055. var player = user.Object as BasePlayer;
  4056. if (!player || !IsAllowedMsg(player, PermTpR) || !player.IsConnected || player.IsSleeping()) return;
  4057. if (args.Length != 0)
  4058. {
  4059. PrintMsgL(player, "SyntaxCommandTPA");
  4060. return;
  4061. }
  4062. Timer reqTimer;
  4063. if (!PendingRequests.TryGetValue(player.userID, out reqTimer))
  4064. {
  4065. PrintMsgL(player, "NoPendingRequest");
  4066. return;
  4067. }
  4068. #if DEBUG
  4069. Puts("Calling CheckPlayer from cmdChatTeleportAccept");
  4070. #endif
  4071. string err = null;
  4072. var originPlayer = PlayersRequests[player.userID];
  4073. if (!CanBypassRestrictions(player.UserIDString))
  4074. {
  4075. err = CheckPlayer(player, config.TPR.UsableIntoBuildingBlocked, CanCraftTPR(player), false, "tpa");
  4076. if (err != null)
  4077. {
  4078. PrintMsgL(player, err);
  4079. return;
  4080. }
  4081. err = CheckPlayer(originPlayer, config.TPR.UsableOutOfBuildingBlocked, CanCraftTPR(originPlayer), true, "tpa");
  4082. if (err != null)
  4083. {
  4084. PrintMsgL(originPlayer, err);
  4085. return;
  4086. }
  4087. err = CheckTargetLocation(originPlayer, player.transform.position, config.TPR.UsableIntoBuildingBlocked, config.TPR.CupOwnerAllowOnBuildingBlocked);
  4088. if (err != null)
  4089. {
  4090. PrintMsgL(player, err);
  4091. return;
  4092. }
  4093. err = CanPlayerTeleport(player, originPlayer.transform.position);
  4094. if (err != null)
  4095. {
  4096. SendReply(player, err);
  4097. return;
  4098. }
  4099. if (config.TPR.BlockTPAOnCeiling)
  4100. {
  4101. if (GetFloor(player.eyes.position).Count > 0)
  4102. {
  4103. PrintMsgL(player, "AcceptOnRoof");
  4104. return;
  4105. }
  4106. }
  4107. float globalCooldownTime = GetGlobalCooldown(player);
  4108. if (globalCooldownTime > 0f)
  4109. {
  4110. PrintMsgL(player, "WaitGlobalCooldown", FormatTime(player, (int)globalCooldownTime));
  4111. return;
  4112. }
  4113. if (config.Settings.BlockAuthorizedTeleporting && player.IsBuildingAuthed())
  4114. {
  4115. PrintMsgL(player, "CannotTeleportFromHome");
  4116. return;
  4117. }
  4118. }
  4119. var countdown = GetLower(originPlayer, config.TPR.VIPCountdowns, config.TPR.Countdown);
  4120. PrintMsgL(originPlayer, "Accept", player.displayName, countdown);
  4121. PrintMsgL(player, "AcceptTarget", originPlayer.displayName);
  4122. var timestamp = Facepunch.Math.Epoch.Current;
  4123. TeleportTimers[originPlayer.userID] = new TeleportTimer
  4124. {
  4125. OriginPlayer = originPlayer,
  4126. TargetPlayer = player,
  4127. Timer = timer.Once(countdown, () =>
  4128. {
  4129. #if DEBUG
  4130. Puts("Calling CheckPlayer from cmdChatTeleportAccept timer loop");
  4131. #endif
  4132. if (!CanBypassRestrictions(player.UserIDString))
  4133. {
  4134. if (config.Settings.BlockAuthorizedTeleporting && player.IsBuildingAuthed())
  4135. {
  4136. PrintMsgL(player, "CannotTeleportFromHome");
  4137. return;
  4138. }
  4139. err = CheckPlayer(originPlayer, config.TPR.UsableOutOfBuildingBlocked, CanCraftTPR(originPlayer), true, "tpa") ?? CheckPlayer(player, false, CanCraftTPR(player), true, "tpa");
  4140. if (err != null)
  4141. {
  4142. PrintMsgL(player, "InterruptedTarget", originPlayer.displayName);
  4143. PrintMsgL(originPlayer, "Interrupted");
  4144. PrintMsgL(originPlayer, err);
  4145. TeleportTimers.Remove(originPlayer.userID);
  4146. return;
  4147. }
  4148. err = CheckTargetLocation(originPlayer, player.transform.position, config.TPR.UsableIntoBuildingBlocked, config.TPR.CupOwnerAllowOnBuildingBlocked);
  4149. if (err != null)
  4150. {
  4151. PrintMsgL(player, err);
  4152. PrintMsgL(originPlayer, "Interrupted");
  4153. PrintMsgL(originPlayer, err);
  4154. TeleportTimers.Remove(originPlayer.userID);
  4155. return;
  4156. }
  4157. err = CanPlayerTeleport(originPlayer, player.transform.position) ?? CanPlayerTeleport(player, originPlayer.transform.position);
  4158. if (err != null)
  4159. {
  4160. SendReply(player, err);
  4161. PrintMsgL(originPlayer, "Interrupted");
  4162. SendReply(originPlayer, err);
  4163. TeleportTimers.Remove(originPlayer.userID);
  4164. return;
  4165. }
  4166. err = CheckItems(originPlayer);
  4167. if (err != null)
  4168. {
  4169. PrintMsgL(player, "InterruptedTarget", originPlayer.displayName);
  4170. PrintMsgL(originPlayer, "Interrupted");
  4171. PrintMsgL(originPlayer, "TPBlockedItem", err);
  4172. TeleportTimers.Remove(originPlayer.userID);
  4173. return;
  4174. }
  4175. if (UseEconomy())
  4176. {
  4177. if (config.TPR.Pay > -1)
  4178. {
  4179. if (!CheckEconomy(originPlayer, config.TPR.Pay))
  4180. {
  4181. if (config.TPR.Pay > 0)
  4182. {
  4183. PrintMsgL(originPlayer, "TPNoMoney", config.TPR.Pay);
  4184. }
  4185.  
  4186. PrintMsgL(player, "InterruptedTarget", originPlayer.displayName);
  4187. TeleportTimers.Remove(originPlayer.userID);
  4188. return;
  4189. }
  4190. else
  4191. {
  4192. CheckEconomy(originPlayer, config.TPR.Pay, true);
  4193.  
  4194. if (config.TPR.Pay > 0)
  4195. {
  4196. PrintMsgL(originPlayer, "TPMoney", (double)config.TPR.Pay);
  4197. }
  4198. }
  4199. }
  4200. }
  4201. }
  4202. Teleport(originPlayer, player.transform.position, config.TPR.AllowTPB);
  4203. var tprData = _TPR[originPlayer.userID];
  4204. tprData.Amount++;
  4205. tprData.Timestamp = timestamp;
  4206. changedTPR = true;
  4207. PrintMsgL(player, "SuccessTarget", originPlayer.displayName);
  4208. PrintMsgL(originPlayer, "Success", player.displayName);
  4209. var limit = GetHigher(originPlayer, config.TPR.VIPDailyLimits, config.TPR.DailyLimit, true);
  4210. if (limit > 0) PrintMsgL(originPlayer, "TPRAmount", limit - tprData.Amount);
  4211. TeleportTimers.Remove(originPlayer.userID);
  4212. })
  4213. };
  4214. reqTimer.Destroy();
  4215. PendingRequests.Remove(player.userID);
  4216. PlayersRequests.Remove(player.userID);
  4217. PlayersRequests.Remove(originPlayer.userID);
  4218. }
  4219.  
  4220. private void CommandWipeHomes(IPlayer user, string command, string[] args)
  4221. {
  4222. if (DisabledCommandData.DisabledCommands.Contains(command.ToLower())) { user.Reply("Disabled command: " + command); return; }
  4223. var player = user.Object as BasePlayer;
  4224. if (!player || !IsAllowedMsg(player, PermWipeHomes) || !player.IsConnected || player.IsSleeping()) return;
  4225. _Home.Clear();
  4226. changedHome = true;
  4227. PrintMsgL(player, "HomesListWiped");
  4228. }
  4229.  
  4230. private void CommandTeleportHelp(IPlayer user, string command, string[] args)
  4231. {
  4232. if (DisabledCommandData.DisabledCommands.Contains(command.ToLower())) { user.Reply("Disabled command: " + command); return; }
  4233. var player = user.Object as BasePlayer;
  4234. if (!player || !player.IsConnected || player.IsSleeping()) return;
  4235. if (!config.Settings.HomesEnabled && !config.Settings.TPREnabled && !IsAllowedMsg(player)) return;
  4236. if (args.Length == 1)
  4237. {
  4238. var key = $"TPHelp{args[0].ToLower()}";
  4239. var msg = _(key, player);
  4240. if (key.Equals(msg))
  4241. PrintMsgL(player, "InvalidHelpModule");
  4242. else
  4243. PrintMsg(player, msg);
  4244. }
  4245. else
  4246. {
  4247. var msg = _("TPHelpGeneral", player);
  4248. if (IsAllowed(player))
  4249. msg += NewLine + "/tphelp AdminTP";
  4250. if (config.Settings.HomesEnabled)
  4251. msg += NewLine + "/tphelp Home";
  4252. if (config.Settings.TPREnabled)
  4253. msg += NewLine + "/tphelp TPR";
  4254. PrintMsg(player, msg);
  4255. }
  4256. }
  4257.  
  4258. private List<string> _tpid = new List<string> { "home", "bandit", "outpost", "tpr", "town" };
  4259.  
  4260. private void CommandTeleportInfo(IPlayer user, string command, string[] args)
  4261. {
  4262. if (DisabledCommandData.DisabledCommands.Contains(command.ToLower())) { user.Reply("Disabled command: " + command); return; }
  4263. var player = user.Object as BasePlayer;
  4264. if (!player || !player.IsConnected || player.IsSleeping()) return;
  4265. if (args.Length == 1)
  4266. {
  4267. var module = args[0].ToLower();
  4268. var settings = GetSettings(module);
  4269. var msg = _(_tpid.Contains(module) || settings == null ? $"TPSettings{module}" : "TPSettingsdynamic", player);
  4270. var timestamp = Facepunch.Math.Epoch.Current;
  4271. var currentDate = DateTime.Now.ToString("d");
  4272. int limit;
  4273. int cooldown;
  4274.  
  4275. switch (module)
  4276. {
  4277. case "home":
  4278. limit = GetHigher(player, config.Home.VIPDailyLimits, config.Home.DailyLimit, true);
  4279. cooldown = GetLower(player, config.Home.VIPCooldowns, config.Home.Cooldown);
  4280. int homeLimits = GetHigher(player, config.Home.VIPHomesLimits, config.Home.HomesLimit, true);
  4281. PrintMsg(player, string.Format(msg, FormatTime(player, cooldown), limit > 0 ? limit.ToString() : _("Unlimited", player), homeLimits));
  4282. HomeData homeData;
  4283. if (!_Home.TryGetValue(player.userID, out homeData))
  4284. _Home[player.userID] = homeData = new HomeData();
  4285. if (homeData.Teleports.Date != currentDate)
  4286. {
  4287. homeData.Teleports.Amount = 0;
  4288. homeData.Teleports.Date = currentDate;
  4289. }
  4290. if (limit > 0) PrintMsgL(player, "HomeTPAmount", limit - homeData.Teleports.Amount);
  4291. if (cooldown > 0 && timestamp - homeData.Teleports.Timestamp < cooldown)
  4292. {
  4293. var remain = cooldown - (timestamp - homeData.Teleports.Timestamp);
  4294. PrintMsgL(player, "HomeTPCooldown", FormatTime(player, remain));
  4295. }
  4296. break;
  4297. case "tpr":
  4298. limit = GetHigher(player, config.TPR.VIPDailyLimits, config.TPR.DailyLimit, true);
  4299. cooldown = GetLower(player, config.TPR.VIPCooldowns, config.TPR.Cooldown);
  4300. PrintMsg(player, string.Format(msg, FormatTime(player, cooldown), limit > 0 ? limit.ToString() : _("Unlimited", player)));
  4301. TeleportData tprData;
  4302. if (!_TPR.TryGetValue(player.userID, out tprData))
  4303. _TPR[player.userID] = tprData = new TeleportData();
  4304. if (tprData.Date != currentDate)
  4305. {
  4306. tprData.Amount = 0;
  4307. tprData.Date = currentDate;
  4308. }
  4309. if (limit > 0) PrintMsgL(player, "TPRAmount", limit - tprData.Amount);
  4310. if (cooldown > 0 && timestamp - tprData.Timestamp < cooldown)
  4311. {
  4312. var remain = cooldown - (timestamp - tprData.Timestamp);
  4313. PrintMsgL(player, "TPRCooldown", FormatTime(player, remain));
  4314. }
  4315. break;
  4316. default: // town island outpost bandit etc
  4317. if (settings == null)
  4318. {
  4319. PrintMsgL(player, "InvalidHelpModule");
  4320. break;
  4321. }
  4322.  
  4323. limit = GetHigher(player, settings.VIPDailyLimits, settings.DailyLimit, true);
  4324. cooldown = GetLower(player, settings.VIPCooldowns, settings.Cooldown);
  4325. if (_tpid.Contains(module)) PrintMsg(player, string.Format(msg, FormatTime(player, cooldown), limit > 0 ? limit.ToString() : _("Unlimited", player)));
  4326. else PrintMsg(player, string.Format(msg, module.SentenceCase(), FormatTime(player, cooldown), limit > 0 ? limit.ToString() : _("Unlimited", player)));
  4327. TeleportData tpData;
  4328. if (!settings.Teleports.TPData.TryGetValue(player.userID, out tpData))
  4329. settings.Teleports.TPData[player.userID] = tpData = new TeleportData();
  4330. if (tpData.Date != currentDate)
  4331. {
  4332. tpData.Amount = 0;
  4333. tpData.Date = currentDate;
  4334. }
  4335. var language = lang.GetMessage(settings.Command, this, user.Id);
  4336. if (limit > 0) PrintMsgL(player, "DM_TownTPAmount", limit - tpData.Amount, language);
  4337. if (!string.IsNullOrEmpty(config.Settings.BypassCMD) && cooldown > 0 && timestamp - tpData.Timestamp < cooldown)
  4338. {
  4339. var remain = cooldown - (timestamp - tpData.Timestamp);
  4340.  
  4341. PrintMsgL(player, "DM_TownTPCooldown", FormatTime(player, remain));
  4342.  
  4343. if (settings.Bypass > 0)
  4344. {
  4345. PrintMsgL(player, "DM_TownTPCooldownBypassP", settings.Bypass);
  4346. PrintMsgL(player, "DM_TownTPCooldownBypassP2", language, config.Settings.BypassCMD);
  4347. }
  4348. }
  4349. break;
  4350. }
  4351. }
  4352. else
  4353. {
  4354. var msg = _("TPInfoGeneral", player);
  4355. if (config.Settings.HomesEnabled)
  4356. msg += NewLine + "/tpinfo Home";
  4357. if (config.Settings.TPREnabled)
  4358. msg += NewLine + "/tpinfo TPR";
  4359. foreach (var entry in config.DynamicCommands)
  4360. {
  4361. if (entry.Value.Enabled)
  4362. {
  4363. if (command == "bandit" && !banditEnabled) continue;
  4364. if (command == "outpost" && !outpostEnabled) continue;
  4365. if (!IsAllowed(player, $"{Name}.tp{entry.Key}")) continue;
  4366. msg += NewLine + $"/tpinfo {entry.Key}";
  4367. }
  4368. }
  4369. PrintMsgL(player, msg);
  4370. }
  4371. }
  4372.  
  4373. private void CommandTeleportCancel(IPlayer user, string command, string[] args)
  4374. {
  4375. var player = user.Object as BasePlayer;
  4376. if (!player || !player.IsConnected || player.IsSleeping()) return;
  4377. if (args.Length != 0)
  4378. {
  4379. PrintMsgL(player, "SyntaxCommandTPC");
  4380. return;
  4381. }
  4382. TeleportTimer teleportTimer;
  4383. if (TeleportTimers.TryGetValue(player.userID, out teleportTimer))
  4384. {
  4385. teleportTimer.Timer?.Destroy();
  4386. PrintMsgL(player, "TPCancelled");
  4387. PrintMsgL(teleportTimer.TargetPlayer, "TPCancelledTarget", player.displayName);
  4388. TeleportTimers.Remove(player.userID);
  4389. return;
  4390. }
  4391. foreach (var keyValuePair in TeleportTimers)
  4392. {
  4393. if (keyValuePair.Value.TargetPlayer != player) continue;
  4394. keyValuePair.Value.Timer?.Destroy();
  4395. PrintMsgL(keyValuePair.Value.OriginPlayer, "TPCancelledTarget", player.displayName);
  4396. PrintMsgL(player, "TPYouCancelledTarget", keyValuePair.Value.OriginPlayer.displayName);
  4397. TeleportTimers.Remove(keyValuePair.Key);
  4398. return;
  4399. }
  4400. BasePlayer target;
  4401. if (!PlayersRequests.TryGetValue(player.userID, out target))
  4402. {
  4403. PrintMsgL(player, "NoPendingRequest");
  4404. return;
  4405. }
  4406. Timer reqTimer;
  4407. if (PendingRequests.TryGetValue(player.userID, out reqTimer))
  4408. {
  4409. reqTimer.Destroy();
  4410. PendingRequests.Remove(player.userID);
  4411. }
  4412. else if (PendingRequests.TryGetValue(target.userID, out reqTimer))
  4413. {
  4414. reqTimer.Destroy();
  4415. PendingRequests.Remove(target.userID);
  4416. var temp = player;
  4417. player = target;
  4418. target = temp;
  4419. }
  4420. PlayersRequests.Remove(target.userID);
  4421. PlayersRequests.Remove(player.userID);
  4422. PrintMsgL(player, "Cancelled", target.displayName);
  4423. PrintMsgL(target, "CancelledTarget", player.displayName);
  4424. }
  4425.  
  4426. private void CommandDynamic(IPlayer user, string command, string[] args)
  4427. {
  4428. if (!user.HasPermission(PermAdmin) || args.Length != 2 || args[0].Equals("list", StringComparison.OrdinalIgnoreCase))
  4429. {
  4430. CommandTeleportInfo(user, command, args);
  4431. return;
  4432. }
  4433.  
  4434. var value = args[1].ToLower();
  4435.  
  4436. if (args[0].Equals("add", StringComparison.OrdinalIgnoreCase))
  4437. {
  4438. TownSettings settings;
  4439. if (GetSettings(value) == null)
  4440. {
  4441. config.DynamicCommands.Add(value, settings = new TownSettings());
  4442. RegisterCommand(value, settings, true);
  4443. RegisterCommand(value, nameof(CommandCustom));
  4444. PrintMsgL(user, "DM_TownTPCreated", value);
  4445. SaveConfig();
  4446. }
  4447. else PrintMsgL(user, "DM_TownTPExists", value);
  4448. }
  4449. else if (args[0].Equals("remove", StringComparison.OrdinalIgnoreCase))
  4450. {
  4451. var key = config.DynamicCommands.Keys.FirstOrDefault(x => x.Equals(value, StringComparison.OrdinalIgnoreCase));
  4452.  
  4453. if (!string.IsNullOrEmpty(key))
  4454. {
  4455. PrintMsgL(user, "DM_TownTPRemoved", key);
  4456. config.DynamicCommands.Remove(key);
  4457. UnregisterCommand(value);
  4458. SaveConfig();
  4459. }
  4460. else PrintMsgL(user, "DM_TownTPDoesNotExist", value);
  4461. }
  4462. else CommandTeleportInfo(user, command, args);
  4463. }
  4464.  
  4465. private void CommandCustom(IPlayer user, string command, string[] args)
  4466. {
  4467. CommandTown(user, command, args);
  4468. }
  4469.  
  4470. private TownSettings GetSettings(string command, ulong userid = 0uL)
  4471. {
  4472. if (command.Equals("home", StringComparison.OrdinalIgnoreCase) && _Home.ContainsKey(userid))
  4473. {
  4474. return new TownSettings
  4475. {
  4476. VIPCooldowns = config.Home.VIPCooldowns,
  4477. Cooldown = config.Home.Cooldown,
  4478. Countdown = config.Home.Countdown,
  4479. Teleports = new StoredData
  4480. {
  4481. TPData = new Dictionary<ulong, TeleportData>
  4482. {
  4483. [userid] = _Home[userid].Teleports
  4484. }
  4485. }
  4486. };
  4487. }
  4488.  
  4489. if (command.Equals("tpr", StringComparison.OrdinalIgnoreCase) && _TPR.ContainsKey(userid))
  4490. {
  4491. return new TownSettings
  4492. {
  4493. VIPCooldowns = config.TPR.VIPCooldowns,
  4494. Cooldown = config.TPR.Cooldown,
  4495. Countdown = config.TPR.Countdown,
  4496. Teleports = new StoredData
  4497. {
  4498. TPData = new Dictionary<ulong, TeleportData>
  4499. {
  4500. [userid] = _TPR[userid]
  4501. }
  4502. }
  4503. };
  4504. }
  4505.  
  4506. foreach (var x in config.DynamicCommands)
  4507. {
  4508. if (x.Key.Equals(command, StringComparison.OrdinalIgnoreCase))
  4509. {
  4510. return x.Value;
  4511. }
  4512. }
  4513.  
  4514. return null;
  4515. }
  4516.  
  4517. private void CommandTown(IPlayer user, string command, string[] args)
  4518. {
  4519. if (DisabledCommandData.DisabledCommands.Contains(command)) { user.Reply("Disabled command: " + command); return; }
  4520. var player = user.Object as BasePlayer;
  4521. if (!player || !player.IsConnected || player.IsSleeping()) return;
  4522. #if DEBUG
  4523. Puts($"cmdChatTown: command={command}");
  4524. #endif
  4525. if (!IsAllowedMsg(player, $"{Name}.tp{command}".ToLower())) return;
  4526.  
  4527. if (!CanBypassRestrictions(player.UserIDString))
  4528. {
  4529. float globalCooldownTime = GetGlobalCooldown(player);
  4530. if (globalCooldownTime > 0f)
  4531. {
  4532. PrintMsgL(player, "WaitGlobalCooldown", FormatTime(player, (int)globalCooldownTime));
  4533. return;
  4534. }
  4535.  
  4536. if (config.Settings.BlockAuthorizedTeleporting && player.IsBuildingAuthed())
  4537. {
  4538. PrintMsgL(player, "CannotTeleportFromHome");
  4539. return;
  4540. }
  4541. }
  4542.  
  4543. var settings = GetSettings(command);
  4544.  
  4545. if (settings == null)
  4546. {
  4547. return;
  4548. }
  4549.  
  4550. var language = lang.GetMessage(settings.Command, this, user.Id);
  4551.  
  4552. // For admin using set, add, clear or show command locations
  4553. if (args.Length >= 1 && IsAllowed(player, PermAdmin))
  4554. {
  4555. var param = args[0].ToLower();
  4556.  
  4557. if (param.Equals("clear"))
  4558. {
  4559. settings.Location = Vector3.zero;
  4560. settings.Locations.Clear();
  4561. SaveConfig();
  4562. PrintMsgL(player, "DM_TownTPLocationsCleared", language);
  4563. return;
  4564. }
  4565. else if (param.Equals("set"))
  4566. {
  4567. if (settings.Locations.Count > 0)
  4568. {
  4569. settings.Locations.RemoveAt(0);
  4570. }
  4571. var position = player.transform.position;
  4572. settings.Locations.Insert(0, settings.Location = position);
  4573. SaveConfig();
  4574. PrintMsgL(player, "DM_TownTPLocation", language, position);
  4575. return;
  4576. }
  4577. else if (param.Equals("add"))
  4578. {
  4579. var position = player.transform.position;
  4580. int num = settings.Locations.RemoveAll(x => Vector3.Distance(position, x) < 25f);
  4581. settings.Locations.Add(position);
  4582. SaveConfig();
  4583. PrintMsgL(player, "DM_TownTPLocation", language, position);
  4584. return;
  4585. }
  4586. else if (args[0].Equals("show", StringComparison.OrdinalIgnoreCase))
  4587. {
  4588. settings.Locations.ForEach(x => player.SendConsoleCommand("ddraw.text", 30f, Color.green, x, command));
  4589. return;
  4590. }
  4591. }
  4592.  
  4593. bool paidmoney = false;
  4594.  
  4595. // Is command usage enabled?
  4596. if (!settings.Enabled)
  4597. {
  4598. PrintMsgL(player, "DM_TownTPDisabled", language.SentenceCase());
  4599. return;
  4600. }
  4601.  
  4602. if (settings.Location != Vector3.zero && !settings.Locations.Contains(settings.Location))
  4603. {
  4604. settings.Locations.Add(settings.Location);
  4605. }
  4606.  
  4607. // Is location set?
  4608. if (settings.Locations.Count == 0)
  4609. {
  4610. PrintMsgL(player, "DM_TownTPNoLocation", language.SentenceCase());
  4611. return;
  4612. }
  4613.  
  4614. // Are they trying to bypass cooldown or did they just type something else?
  4615. if (args.Length == 1 && !string.IsNullOrEmpty(config.Settings.BypassCMD) && args[0].ToLower() != config.Settings.BypassCMD.ToLower() && !args[0].All(char.IsDigit))
  4616. {
  4617. string com = command ?? "town";
  4618. string msg = "SyntaxCommand" + char.ToUpper(com[0]) + com.Substring(1);
  4619. PrintMsgL(player, msg);
  4620. if (IsAllowed(player)) PrintMsgL(player, msg + "Admin");
  4621. return;
  4622. }
  4623.  
  4624. TeleportData teleportData;
  4625. if (!settings.Teleports.TPData.TryGetValue(player.userID, out teleportData))
  4626. {
  4627. settings.Teleports.TPData[player.userID] = teleportData = new TeleportData();
  4628. }
  4629. int limit = 0;
  4630. var timestamp = Facepunch.Math.Epoch.Current;
  4631. var currentDate = DateTime.Now.ToString("d");
  4632.  
  4633. // Setup vars for checks below
  4634. string err = null;
  4635. if (!CanBypassRestrictions(player.UserIDString))
  4636. {
  4637. err = CheckPlayer(player, settings.UsableOutOfBuildingBlocked, settings.CanCraft(player, command), true, command);
  4638. if (err != null)
  4639. {
  4640. PrintMsgL(player, err);
  4641. return;
  4642. }
  4643. var cooldown = GetLower(player, settings.VIPCooldowns, settings.Cooldown);
  4644.  
  4645. if (teleportData.Date != currentDate)
  4646. {
  4647. teleportData.Amount = 0;
  4648. teleportData.Date = currentDate;
  4649. }
  4650. limit = GetHigher(player, settings.VIPDailyLimits, settings.DailyLimit, true);
  4651. #if DEBUG
  4652. Puts("Calling CheckPlayer from cmdChatTown");
  4653. #endif
  4654.  
  4655. // Check and process cooldown, bypass, and payment for all modes
  4656. if (cooldown > 0 && timestamp - teleportData.Timestamp < cooldown)
  4657. {
  4658. var cmdSent = args.Length >= 1 ? args[0].ToLower() : string.Empty;
  4659.  
  4660. if (!string.IsNullOrEmpty(config.Settings.BypassCMD))
  4661. {
  4662. if (cmdSent == config.Settings.BypassCMD.ToLower() && settings.Bypass > -1)
  4663. {
  4664. bool foundmoney = CheckEconomy(player, settings.Bypass);
  4665.  
  4666. if (foundmoney)
  4667. {
  4668. CheckEconomy(player, settings.Bypass, true);
  4669. paidmoney = true;
  4670.  
  4671. if (settings.Bypass > 0)
  4672. {
  4673. PrintMsgL(player, "DM_TownTPCooldownBypass", settings.Bypass);
  4674. }
  4675.  
  4676. if (settings.Pay > 0)
  4677. {
  4678. PrintMsgL(player, "PayToTown", settings.Pay, language);
  4679. }
  4680. }
  4681. else
  4682. {
  4683. PrintMsgL(player, "DM_TownTPCooldownBypassF", settings.Bypass);
  4684. return;
  4685. }
  4686. }
  4687. else if (UseEconomy())
  4688. {
  4689. var remain = cooldown - (timestamp - teleportData.Timestamp);
  4690. PrintMsgL(player, "DM_TownTPCooldown", FormatTime(player, remain));
  4691. if (settings.Bypass > -1)
  4692. {
  4693. PrintMsgL(player, "DM_TownTPCooldownBypassP", settings.Bypass);
  4694. PrintMsgL(player, "DM_TownTPCooldownBypassP2", language, config.Settings.BypassCMD);
  4695. }
  4696. return;
  4697. }
  4698. else
  4699. {
  4700. var remain = cooldown - (timestamp - teleportData.Timestamp);
  4701. PrintMsgL(player, "DM_TownTPCooldown", FormatTime(player, remain));
  4702. return;
  4703. }
  4704. }
  4705. else
  4706. {
  4707. var remain = cooldown - (timestamp - teleportData.Timestamp);
  4708. PrintMsgL(player, "DM_TownTPCooldown", FormatTime(player, remain));
  4709. return;
  4710. }
  4711. }
  4712.  
  4713. if (limit > 0 && teleportData.Amount >= limit)
  4714. {
  4715. var left = FormatTime(player, (int)SecondsUntilTomorrow());
  4716. PrintMsgL(player, "DM_TownTPLimitReached", limit, left);
  4717. return;
  4718. }
  4719. }
  4720. if (TeleportTimers.ContainsKey(player.userID))
  4721. {
  4722. PrintMsgL(player, "TeleportPendingTPC");
  4723. return;
  4724. }
  4725.  
  4726. Vector3 location;
  4727. int index;
  4728. if (args.Length == 1 && int.TryParse(args[0], out index))
  4729. {
  4730. index = Mathf.Clamp(index, 0, settings.Locations.Count - 1);
  4731. location = settings.Locations[index];
  4732. }
  4733. else if (settings.Random)
  4734. {
  4735. location = settings.Locations.GetRandom();
  4736. }
  4737. else location = settings.Locations.First();
  4738.  
  4739. if (!CanBypassRestrictions(player.UserIDString))
  4740. {
  4741. err = CanPlayerTeleport(player, location);
  4742. if (err != null)
  4743. {
  4744. SendReply(player, err);
  4745. return;
  4746. }
  4747. err = CheckItems(player);
  4748. if (err != null)
  4749. {
  4750. PrintMsgL(player, "TPBlockedItem", err);
  4751. return;
  4752. }
  4753. }
  4754. int countdown = GetLower(player, settings.VIPCountdowns, settings.Countdown);
  4755. TeleportTimers[player.userID] = new TeleportTimer
  4756. {
  4757. OriginPlayer = player,
  4758. Timer = timer.Once(countdown, () =>
  4759. {
  4760. #if DEBUG
  4761. Puts($"Calling CheckPlayer from cmdChatTown {command} timer loop");
  4762. #endif
  4763. if (!CanBypassRestrictions(player.UserIDString))
  4764. {
  4765. if (config.Settings.BlockAuthorizedTeleporting && player.IsBuildingAuthed())
  4766. {
  4767. PrintMsgL(player, "CannotTeleportFromHome");
  4768. return;
  4769. }
  4770. err = CheckPlayer(player, settings.UsableOutOfBuildingBlocked, settings.CanCraft(player, command.ToLower()), true, command.ToLower(), settings.AllowCave);
  4771. if (err != null)
  4772. {
  4773. Interrupt(player, paidmoney, settings.Bypass);
  4774. PrintMsgL(player, err);
  4775. return;
  4776. }
  4777. err = CanPlayerTeleport(player, location);
  4778. if (err != null)
  4779. {
  4780. Interrupt(player, paidmoney, settings.Bypass);
  4781. PrintMsgL(player, err);
  4782. return;
  4783. }
  4784. err = CheckItems(player);
  4785. if (err != null)
  4786. {
  4787. Interrupt(player, paidmoney, settings.Bypass);
  4788. PrintMsgL(player, "TPBlockedItem", err);
  4789. return;
  4790. }
  4791. if (settings.Locations.Count == 0)
  4792. {
  4793. Interrupt(player, paidmoney, settings.Bypass);
  4794. return;
  4795. }
  4796. if (UseEconomy())
  4797. {
  4798. if (settings.Pay < 0)
  4799. {
  4800. return;
  4801. }
  4802. if (settings.Pay > 0 && !CheckEconomy(player, settings.Pay))
  4803. {
  4804. Interrupt(player, false, 0);
  4805. PrintMsgL(player, "TPNoMoney", settings.Pay);
  4806. return;
  4807. }
  4808. if (settings.Pay > -1 && !paidmoney)
  4809. {
  4810. CheckEconomy(player, settings.Pay, true);
  4811.  
  4812. if (settings.Pay > 0)
  4813. {
  4814. PrintMsgL(player, "TPMoney", (double)settings.Pay);
  4815. }
  4816. }
  4817. }
  4818. }
  4819. Teleport(player, location, settings.AllowTPB);
  4820. teleportData.Amount++;
  4821. teleportData.Timestamp = timestamp;
  4822. settings.Teleports.Changed = true;
  4823. PrintMsgL(player, "DM_TownTP", language);
  4824. if (limit > 0) PrintMsgL(player, "DM_TownTPAmount", limit - teleportData.Amount, language);
  4825. TeleportTimers.Remove(player.userID);
  4826. })
  4827. };
  4828.  
  4829. if (countdown > 0)
  4830. {
  4831. PrintMsgL(player, "DM_TownTPStarted", language, countdown);
  4832. }
  4833. }
  4834.  
  4835. private double SecondsUntilTomorrow()
  4836. {
  4837. var tomorrow = DateTime.Now.AddDays(1).Date;
  4838. return (tomorrow - DateTime.Now).TotalSeconds;
  4839. }
  4840.  
  4841. private void Interrupt(BasePlayer player, bool paidmoney, double bypass)
  4842. {
  4843. PrintMsgL(player, "Interrupted");
  4844. if (paidmoney)
  4845. {
  4846. CheckEconomy(player, bypass, false, true);
  4847. }
  4848. TeleportTimers.Remove(player.userID);
  4849. }
  4850.  
  4851. private void CommandTeleportII(IPlayer user, string command, string[] args)
  4852. {
  4853. if (DisabledCommandData.DisabledCommands.Contains(command.ToLower())) { user.Reply("Disabled command: " + command); return; }
  4854. var player = user.Object as BasePlayer;
  4855. if (player != null && (!IsAllowedMsg(player, PermTpConsole) || !player.IsConnected || player.IsSleeping())) return;
  4856.  
  4857. List<BasePlayer> players;
  4858. switch (command)
  4859. {
  4860. case "teleport.topos":
  4861. if (args.Length < 4)
  4862. {
  4863. user.Reply(_("SyntaxConsoleCommandToPos", player));
  4864. return;
  4865. }
  4866. players = FindPlayers(args[0], true);
  4867. if (players.Count <= 0)
  4868. {
  4869. user.Reply(_("PlayerNotFound", player));
  4870. return;
  4871. }
  4872. if (players.Count > 1)
  4873. {
  4874. user.Reply(_("MultiplePlayers", player, GetMultiplePlayers(players)));
  4875. return;
  4876. }
  4877. var targetPlayer = players.First();
  4878. players.Clear();
  4879. float x;
  4880. if (!float.TryParse(args[1], out x)) x = -10000f;
  4881. float y;
  4882. if (!float.TryParse(args[2], out y)) y = -10000f;
  4883. float z;
  4884. if (!float.TryParse(args[3], out z)) z = -10000f;
  4885. if (!CheckBoundaries(x, y, z))
  4886. {
  4887. user.Reply(_("AdminTPOutOfBounds", player) + System.Environment.NewLine + _("AdminTPBoundaries", player, boundary));
  4888. return;
  4889. }
  4890. Teleport(targetPlayer, x, y, z);
  4891. if (config.Admin.AnnounceTeleportToTarget)
  4892. PrintMsgL(targetPlayer, "AdminTPConsoleTP", targetPlayer.transform.position);
  4893. user.Reply(_("AdminTPTargetCoordinates", player, targetPlayer.displayName, targetPlayer.transform.position));
  4894. Puts(_("LogTeleportPlayer", null, player?.displayName, targetPlayer.displayName, targetPlayer.transform.position));
  4895. break;
  4896. case "teleport.toplayer":
  4897. if (args.Length < 2)
  4898. {
  4899. user.Reply(_("SyntaxConsoleCommandToPlayer", player));
  4900. return;
  4901. }
  4902. players = FindPlayers(args[0], true);
  4903. if (players.Count <= 0)
  4904. {
  4905. user.Reply(_("PlayerNotFound", player));
  4906. return;
  4907. }
  4908. if (players.Count > 1)
  4909. {
  4910. user.Reply(_("MultiplePlayers", player, GetMultiplePlayers(players)));
  4911. return;
  4912. }
  4913. var originPlayer = players.First();
  4914. players = FindPlayers(args[1], true);
  4915. if (players.Count <= 0)
  4916. {
  4917. user.Reply(_("PlayerNotFound", player));
  4918. return;
  4919. }
  4920. if (players.Count > 1)
  4921. {
  4922. user.Reply(_("MultiplePlayers", player, GetMultiplePlayers(players)));
  4923. players.Clear();
  4924. return;
  4925. }
  4926. targetPlayer = players.First();
  4927. if (targetPlayer == originPlayer)
  4928. {
  4929. players.Clear();
  4930. user.Reply(_("CantTeleportPlayerToSelf", player));
  4931. return;
  4932. }
  4933. players.Clear();
  4934. Teleport(originPlayer, targetPlayer);
  4935. user.Reply(_("AdminTPPlayers", player, originPlayer.displayName, targetPlayer.displayName));
  4936. PrintMsgL(originPlayer, "AdminTPConsoleTPPlayer", targetPlayer.displayName);
  4937. if (config.Admin.AnnounceTeleportToTarget)
  4938. PrintMsgL(targetPlayer, "AdminTPConsoleTPPlayerTarget", originPlayer.displayName);
  4939. Puts(_("LogTeleportPlayer", null, player?.displayName, originPlayer.displayName, targetPlayer.displayName));
  4940. break;
  4941. }
  4942. }
  4943.  
  4944. private float GetMonumentFloat(string monumentName)
  4945. {
  4946. string name = monumentName.Contains(":") ? monumentName.Substring(0, monumentName.LastIndexOf(":")) : monumentName.TrimEnd();
  4947.  
  4948. switch (name)
  4949. {
  4950. case "Abandoned Cabins":
  4951. return 54f;
  4952. case "Abandoned Supermarket":
  4953. return 50f;
  4954. case "Airfield":
  4955. return 200f;
  4956. case "Barn":
  4957. case "Large Barn":
  4958. return 75f;
  4959. case "Fishing Village":
  4960. case "Large Fishing Village":
  4961. return 50f;
  4962. case "Bandit Camp":
  4963. return 125f;
  4964. case "Junkyard":
  4965. return 100f;
  4966. case "Giant Excavator Pit":
  4967. return 225f;
  4968. case "Harbor":
  4969. return 150f;
  4970. case "HQM Quarry":
  4971. return 37.5f;
  4972. case "Ice Lake":
  4973. return 50f;
  4974. case "Large Oil Rig":
  4975. return 200f;
  4976. case "Launch Site":
  4977. return 300f;
  4978. case "Lighthouse":
  4979. return 48f;
  4980. case "Military Tunnel":
  4981. return 100f;
  4982. case "Mining Outpost":
  4983. return 45f;
  4984. case "Oil Rig":
  4985. return 100f;
  4986. case "Outpost":
  4987. return 250f;
  4988. case "Oxum's Gas Station":
  4989. return 65f;
  4990. case "Power Plant":
  4991. return 140f;
  4992. case "power_sub_small_1":
  4993. case "power_sub_small_2":
  4994. case "power_sub_big_1":
  4995. case "power_sub_big_2":
  4996. return 30f;
  4997. case "Ranch":
  4998. return 75f;
  4999. case "Satellite Dish":
  5000. return 90f;
  5001. case "Sewer Branch":
  5002. return 100f;
  5003. case "Stone Quarry":
  5004. return 27.5f;
  5005. case "Sulfur Quarry":
  5006. return 27.5f;
  5007. case "The Dome":
  5008. return 70f;
  5009. case "Train Yard":
  5010. return 150f;
  5011. case "Underwater Lab":
  5012. return 100f;
  5013. case "Water Treatment Plant":
  5014. return 185f;
  5015. case "Water Well":
  5016. return 24f;
  5017. case "Wild Swamp":
  5018. return 24f;
  5019. }
  5020.  
  5021. return config.Settings.DefaultMonumentSize;
  5022. }
  5023.  
  5024. private void CommandSphereMonuments(IPlayer user, string command, string[] args)
  5025. {
  5026. if (DisabledCommandData.DisabledCommands.Contains(command.ToLower())) { user.Reply("Disabled command: " + command); return; }
  5027. var player = user.Object as BasePlayer;
  5028. if (!player || !player.IsAdmin || !player.IsConnected || player.IsSleeping()) return;
  5029.  
  5030. //foreach (var monument in TerrainMeta.Path.Monuments) player.SendConsoleCommand("ddraw.sphere", 30f, Color.blue, monument.transform.position, monument.Bounds.size.Max());
  5031.  
  5032. foreach (var monument in monuments)
  5033. {
  5034. string name = monument.Key.Contains(":") ? monument.Key.Substring(0, monument.Key.LastIndexOf(":")) : monument.Key.TrimEnd();
  5035.  
  5036. player.SendConsoleCommand("ddraw.sphere", 30f, Color.red, monument.Value.Position, GetMonumentFloat(name));
  5037. player.SendConsoleCommand("ddraw.text", 30f, Color.blue, monument.Value.Position, name);
  5038. }
  5039.  
  5040. foreach (var cave in caves)
  5041. {
  5042. string name = cave.Key.Contains(":") ? cave.Key.Substring(0, cave.Key.LastIndexOf(":")) : cave.Key.TrimEnd();
  5043. float realdistance = cave.Key.Contains("Small") ? config.Settings.CaveDistanceSmall : cave.Key.Contains("Medium") ? config.Settings.CaveDistanceMedium : config.Settings.CaveDistanceLarge;
  5044. realdistance += 50f;
  5045.  
  5046. player.SendConsoleCommand("ddraw.sphere", 30f, Color.black, cave.Value, realdistance);
  5047. player.SendConsoleCommand("ddraw.text", 30f, Color.cyan, cave.Value, name);
  5048. }
  5049. }
  5050.  
  5051. private void CommandImportHomes(IPlayer user, string command, string[] args)
  5052. {
  5053. if (DisabledCommandData.DisabledCommands.Contains(command.ToLower())) { user.Reply("Disabled command: " + command); return; }
  5054. var player = user.Object as BasePlayer;
  5055.  
  5056. if (player != null && (!IsAllowedMsg(player, PermImportHomes) || !player.IsConnected || player.IsSleeping()))
  5057. {
  5058. user.Reply(_("NotAllowed", player));
  5059. return;
  5060. }
  5061. var fileName = string.IsNullOrEmpty(config.Settings.DataFileFolder) ? "m-Teleportation" : $"{config.Settings.DataFileFolder}{Path.DirectorySeparatorChar}m-Teleportation";
  5062. var datafile = Interface.Oxide.DataFileSystem.GetFile(fileName);
  5063. if (!datafile.Exists())
  5064. {
  5065. user.Reply("No m-Teleportation.json exists.");
  5066. return;
  5067. }
  5068. datafile.Load();
  5069. var allHomeData = datafile["HomeData"] as Dictionary<string, object>;
  5070. if (allHomeData == null)
  5071. {
  5072. user.Reply(_("HomeListEmpty", player));
  5073. return;
  5074. }
  5075. var count = 0;
  5076. foreach (var kvp in allHomeData)
  5077. {
  5078. var homeDataOld = kvp.Value as Dictionary<string, object>;
  5079. if (homeDataOld == null) continue;
  5080. if (!homeDataOld.ContainsKey("HomeLocations")) continue;
  5081. var homeList = homeDataOld["HomeLocations"] as Dictionary<string, object>;
  5082. if (homeList == null) continue;
  5083. var userId = Convert.ToUInt64(kvp.Key);
  5084. HomeData homeData;
  5085. if (!_Home.TryGetValue(userId, out homeData))
  5086. _Home[userId] = homeData = new HomeData();
  5087. foreach (var kvp2 in homeList)
  5088. {
  5089. var positionData = kvp2.Value as Dictionary<string, object>;
  5090. if (positionData == null) continue;
  5091. if (!positionData.ContainsKey("x") || !positionData.ContainsKey("y") || !positionData.ContainsKey("z")) continue;
  5092. var position = new Vector3(Convert.ToSingle(positionData["x"]), Convert.ToSingle(positionData["y"]), Convert.ToSingle(positionData["z"]));
  5093. homeData.Locations[kvp2.Key] = position;
  5094. changedHome = true;
  5095. count++;
  5096. }
  5097. }
  5098. user.Reply(string.Format("Imported {0} homes.", count));
  5099. }
  5100.  
  5101. private void RequestTimedOut(BasePlayer player, BasePlayer target)
  5102. {
  5103. PlayersRequests.Remove(player.userID);
  5104. PlayersRequests.Remove(target.userID);
  5105. PendingRequests.Remove(target.userID);
  5106. PrintMsgL(player, "TimedOut", target.displayName);
  5107. PrintMsgL(target, "TimedOutTarget", player.displayName);
  5108. }
  5109.  
  5110. #region Util
  5111.  
  5112. private string FormatTime(BasePlayer player, int seconds) // Credits MoNaH
  5113. {
  5114. if (config.Settings.UseSeconds) return $"{seconds} {_("Seconds", player)}";
  5115.  
  5116. TimeSpan _ts = TimeSpan.FromSeconds(seconds);
  5117.  
  5118. _sb.Length = 0;
  5119.  
  5120. if (_ts.TotalDays >= 1)
  5121. {
  5122. _sb.Append($"<color={config.Settings.ChatCommandArgumentColor}>{_ts.Days}</color> {_("Days", player)} ");
  5123. }
  5124.  
  5125. if (_ts.TotalHours >= 1)
  5126. {
  5127. _sb.Append($"<color={config.Settings.ChatCommandArgumentColor}>{_ts.Hours}</color> {_("Hours", player)} ");
  5128. }
  5129.  
  5130. if (_ts.TotalMinutes >= 1)
  5131. {
  5132. _sb.Append($"<color={config.Settings.ChatCommandArgumentColor}>{_ts.Minutes}</color> {_("Minutes", player)} ");
  5133. }
  5134.  
  5135. _sb.Append($"<color={config.Settings.ChatCommandArgumentColor}>{_ts.Seconds}</color> {_("Seconds", player)} ");
  5136.  
  5137. return _sb.ToString();
  5138. }
  5139.  
  5140. private double ConvertToRadians(double angle)
  5141. {
  5142. return System.Math.PI / 180 * angle;
  5143. }
  5144. #endregion
  5145.  
  5146. #region Teleport
  5147.  
  5148. public void Teleport(BasePlayer player, BasePlayer target) => Teleport(player, target.transform.position, true);
  5149.  
  5150. public void Teleport(BasePlayer player, float x, float y, float z) => Teleport(player, new Vector3(x, y, z), true);
  5151.  
  5152. [HookMethod("Teleport")]
  5153. public void Teleport(BasePlayer player, Vector3 newPosition, bool allowTPB)
  5154. {
  5155. if (!player.IsValid() || Vector3.Distance(newPosition, Vector3.zero) < 5f) return;
  5156. if (allowTPB)
  5157. {
  5158. if (config.Settings.TPBTime > 0)
  5159. {
  5160. Vector3 position = player.transform.position;
  5161. timer.In(config.Settings.TPBTime, () => SaveLocation(player, position));
  5162. }
  5163. else SaveLocation(player, player.transform.position);
  5164. }
  5165.  
  5166. newPosition.y += 0.1f;
  5167.  
  5168. teleporting[player.userID] = newPosition;
  5169.  
  5170. Subscribe(nameof(OnPlayerViolation));
  5171.  
  5172. var oldPosition = player.transform.position;
  5173.  
  5174. try
  5175. {
  5176. player.UpdateActiveItem(0u); // Prevent weapons when going to safe zone
  5177. player.EnsureDismounted(); // 1.1.2 @Def
  5178. player.Server_CancelGesture();
  5179.  
  5180. if (player.HasParent())
  5181. {
  5182. player.SetParent(null, true, true);
  5183. }
  5184.  
  5185. if (player.IsConnected) // 1.1.2 @Def
  5186. {
  5187. player.EndLooting();
  5188. StartSleeping(player);
  5189. }
  5190.  
  5191. player.RemoveFromTriggers(); // 1.1.2 @Def recommendation to use natural method for issue with triggers
  5192. player.Teleport(newPosition); // 1.1.6
  5193.  
  5194. if (player.IsConnected && !Net.sv.visibility.IsInside(player.net.group, newPosition))
  5195. {
  5196. player.SetPlayerFlag(BasePlayer.PlayerFlags.ReceivingSnapshot, true);
  5197. player.ClientRPCPlayer(null, player, "StartLoading");
  5198. player.SendEntityUpdate();
  5199.  
  5200. if (!IsInvisible(player)) // fix for becoming networked briefly with vanish while teleporting
  5201. {
  5202. player.UpdateNetworkGroup(); // 1.1.1 building fix @ctv
  5203. player.SendNetworkUpdateImmediate(false);
  5204. }
  5205. }
  5206. }
  5207. finally
  5208. {
  5209. if (!IsInvisible(player))
  5210. player.ForceUpdateTriggers(); // 1.1.4 exploit fix for looting sleepers in safe zones
  5211. }
  5212.  
  5213. SetGlobalCooldown(player);
  5214.  
  5215. Interface.CallHook("OnPlayerTeleported", player, oldPosition, newPosition);
  5216. }
  5217.  
  5218. private void OnMapMarkerAdded(BasePlayer player, ProtoBuf.MapNote note)
  5219. {
  5220. if (player.IsAlive() && permission.UserHasPermission(player.UserIDString, PermTpMarker))
  5221. {
  5222. float y = TerrainMeta.HeightMap.GetHeight(note.worldPosition);
  5223. if (player.IsFlying) y = Mathf.Max(y, player.transform.position.y);
  5224. Teleport(player, note.worldPosition + new Vector3(0f, y, 0f), true);
  5225. }
  5226. }
  5227.  
  5228. bool IsInvisible(BasePlayer player)
  5229. {
  5230. return Vanish != null && Convert.ToBoolean(Vanish?.Call("IsInvisible", player));
  5231. }
  5232.  
  5233. public void StartSleeping(BasePlayer player) // custom as to not cancel crafting, or remove player from vanish
  5234. {
  5235. if (!player.IsSleeping())
  5236. {
  5237. Interface.CallHook("OnPlayerSleep", player);
  5238. player.SetPlayerFlag(BasePlayer.PlayerFlags.Sleeping, true);
  5239. player.sleepStartTime = Time.time;
  5240. BasePlayer.sleepingPlayerList.Add(player);
  5241. player.CancelInvoke("InventoryUpdate");
  5242. player.CancelInvoke("TeamUpdate");
  5243. }
  5244. }
  5245.  
  5246. #endregion
  5247.  
  5248. #region Checks
  5249. private string CanPlayerTeleport(BasePlayer player, Vector3 to)
  5250. {
  5251. if (CanBypassRestrictions(player.UserIDString)) return null;
  5252. return Interface.Oxide.CallHook("CanTeleport", player, to) as string;
  5253. }
  5254.  
  5255. private bool CanCraftHome(BasePlayer player)
  5256. {
  5257. return config.Home.AllowCraft || permission.UserHasPermission(player.UserIDString, PermCraftHome) || CanBypassRestrictions(player.UserIDString);
  5258. }
  5259.  
  5260. private bool CanCraftTPR(BasePlayer player)
  5261. {
  5262. return config.TPR.AllowCraft || permission.UserHasPermission(player.UserIDString, PermCraftTpR) || CanBypassRestrictions(player.UserIDString);
  5263. }
  5264.  
  5265. public bool AboveWater(BasePlayer player)
  5266. {
  5267. var pos = player.transform.position;
  5268. #if DEBUG
  5269. Puts($"Player position: {pos}. Checking for water...");
  5270. #endif
  5271. if ((TerrainMeta.HeightMap.GetHeight(pos) - TerrainMeta.WaterMap.GetHeight(pos)) < 0)
  5272. {
  5273. #if DEBUG
  5274. Puts("Player is above water!");
  5275. #endif
  5276. return true;
  5277. }
  5278. else
  5279. {
  5280. #if DEBUG
  5281. Puts("Player not above water.");
  5282. #endif
  5283. return false;
  5284. }
  5285. }
  5286.  
  5287. private string NearMonument(Vector3 target)
  5288. {
  5289. foreach (var entry in monuments)
  5290. {
  5291. if (entry.Key.ToLower().Contains("power_")) continue;
  5292. if (entry.Key.ToLower().Contains("swamp")) continue;
  5293. if (entry.Key.Contains("monument_marker.prefab") && config.Settings.Interrupt.BypassMonumentMarker) continue;
  5294.  
  5295. var pos = entry.Value.Position;
  5296. pos.y = target.y;
  5297. float dist = (target - pos).magnitude;
  5298. #if DEBUG
  5299. Puts($"Checking {entry.Key} dist: {dist}, realdistance: {entry.Value.Radius}");
  5300. #endif
  5301. if (dist < entry.Value.Radius)
  5302. {
  5303. if (config.Home.AllowedMonuments.Any(m => entry.Key.Equals(m, StringComparison.OrdinalIgnoreCase)))
  5304. {
  5305. return null;
  5306. }
  5307.  
  5308. if (config.Settings.Interrupt.Monuments.Count > 0)
  5309. {
  5310. if (config.Settings.Interrupt.Monuments.Exists(value => entry.Key.Contains(value, CompareOptions.OrdinalIgnoreCase)))
  5311. {
  5312. #if DEBUG
  5313. Puts($"Player in range of {entry.Key}");
  5314. #endif
  5315. return entry.Key;
  5316. }
  5317.  
  5318. return null;
  5319. }
  5320. #if DEBUG
  5321. Puts($"Player in range of {entry.Key}");
  5322. #endif
  5323. return entry.Key;
  5324. }
  5325. }
  5326.  
  5327. if (IsMonument(target))
  5328. {
  5329. return "monument";
  5330. }
  5331.  
  5332. return null;
  5333. }
  5334.  
  5335. private bool ContainsTopology(TerrainTopology.Enum mask, Vector3 position)
  5336. {
  5337. return (TerrainMeta.TopologyMap.GetTopology(position) & (int)mask) != 0;
  5338. }
  5339.  
  5340. public bool IsMonument(Vector3 position)
  5341. {
  5342. if (!config.Settings.MonumentTopologyCheck) return false;
  5343. return !ContainsTopology(TerrainTopology.Enum.Building, position) && ContainsTopology(TerrainTopology.Enum.Monument, position);
  5344. }
  5345.  
  5346. public bool IsNearCave(BasePlayer player)
  5347. {
  5348. if (!config.Settings.CaveTopologyCheck) return false;
  5349. return !player.IsOutside() && ContainsTopology(TerrainTopology.Enum.Building | TerrainTopology.Enum.Monument, player.transform.position);
  5350. }
  5351.  
  5352. private bool NearCave(BasePlayer player)
  5353. {
  5354. if (player.IsOutside())
  5355. {
  5356. return false;
  5357. }
  5358.  
  5359. foreach (var entry in caves)
  5360. {
  5361. float realdistance = entry.Key.Contains("Small") ? config.Settings.CaveDistanceSmall : entry.Key.Contains("Medium") ? config.Settings.CaveDistanceMedium : config.Settings.CaveDistanceLarge;
  5362.  
  5363. if (realdistance <= 0)
  5364. {
  5365. continue;
  5366. }
  5367.  
  5368. if (Vector3.Distance(player.transform.position, entry.Value) < realdistance + 50f)
  5369. {
  5370. #if DEBUG
  5371. Puts("NearCave: {0} nearby.", entry.Key.Contains(":") ? entry.Key.Substring(0, entry.Key.LastIndexOf(":")) : entry.Key);
  5372. #endif
  5373. return true;
  5374. }
  5375. else
  5376. {
  5377. #if DEBUG
  5378. Puts("NearCave: Not near this cave, or above it.");
  5379. #endif
  5380. }
  5381. }
  5382.  
  5383. if (IsNearCave(player))
  5384. {
  5385. return true;
  5386. }
  5387.  
  5388. return false;
  5389. }
  5390.  
  5391. private string CheckPlayer(BasePlayer player, bool build = false, bool craft = false, bool origin = true, string mode = "home", bool allowcave = true)
  5392. {
  5393. if (CanBypassRestrictions(player.UserIDString)) return null;
  5394. if (config.Settings.Interrupt.Oilrig || config.Settings.Interrupt.Excavator || config.Settings.Interrupt.Monument || mode == "sethome")
  5395. {
  5396. string monname = NearMonument(player.transform.position);
  5397.  
  5398. if (!string.IsNullOrEmpty(monname))
  5399. {
  5400. if (mode == "sethome")
  5401. {
  5402. if (config.Home.AllowAtAllMonuments || config.Home.AllowedMonuments.Exists(value => monname.Contains(value, CompareOptions.OrdinalIgnoreCase)))
  5403. {
  5404. return null;
  5405. }
  5406.  
  5407. return "HomeTooCloseToMon";
  5408. }
  5409. else
  5410. {
  5411. if (config.Settings.Interrupt.Oilrig && monname.Contains("Oil Rig"))
  5412. {
  5413. return "TPOilRig";
  5414. }
  5415.  
  5416. if (config.Settings.Interrupt.Excavator && monname.Contains("Excavator"))
  5417. {
  5418. return "TPExcavator";
  5419. }
  5420.  
  5421. if (config.Settings.Interrupt.Monument)
  5422. {
  5423. if (config.Home.AllowedMonuments.Exists(value => monname.Contains(value, CompareOptions.OrdinalIgnoreCase)))
  5424. {
  5425. return null;
  5426. }
  5427.  
  5428. if (monname.Contains(":")) monname = monname.Substring(0, monname.IndexOf(":"));
  5429. return _("TooCloseToMon", player, monname);
  5430. }
  5431. }
  5432. }
  5433. }
  5434.  
  5435. #if DEBUG
  5436. Puts($"CheckPlayer(): called mode is {mode}");
  5437. #endif
  5438. switch (mode)
  5439. {
  5440. case "tpt":
  5441. allowcave = config.TPT.AllowCave;
  5442. break;
  5443. case "home":
  5444. allowcave = config.Home.AllowCave;
  5445. break;
  5446. case "tpa":
  5447. case "tpr":
  5448. allowcave = config.TPR.AllowCave;
  5449. break;
  5450. default:
  5451. #if DEBUG
  5452. Puts("Skipping cave check...");
  5453. #endif
  5454. break;
  5455. }
  5456. if (!allowcave)
  5457. {
  5458. #if DEBUG
  5459. Puts("Checking cave distance...");
  5460. #endif
  5461. if (NearCave(player))
  5462. {
  5463. return "TooCloseToCave";
  5464. }
  5465. }
  5466.  
  5467. if (config.Settings.Interrupt.Hostile && (mode == "bandit" || mode == "outpost" || mode == "town") && player.IsHostile())
  5468. {
  5469. return "TPHostile";
  5470. }
  5471.  
  5472. if (config.Settings.Interrupt.Junkpiles && IsOnJunkPile(player))
  5473. {
  5474. return "TPJunkpile";
  5475. }
  5476.  
  5477. if (config.Settings.Interrupt.Mounted && player.GetMounted() is BaseMountable)
  5478. {
  5479. return "TPMounted";
  5480. }
  5481.  
  5482. if (config.Settings.Interrupt.Boats && player.isMounted && player.GetMounted() is BaseBoat)
  5483. {
  5484. return "TPBoat";
  5485. }
  5486.  
  5487. if (config.Settings.Interrupt.Hurt && origin && player.IsWounded())
  5488. {
  5489. return "TPWounded";
  5490. }
  5491.  
  5492. if (config.Settings.Interrupt.Cold && player.metabolism.temperature.value <= config.Settings.MinimumTemp)
  5493. {
  5494. return "TPTooCold";
  5495. }
  5496.  
  5497. if (config.Settings.Interrupt.Hot && player.metabolism.temperature.value >= config.Settings.MaximumTemp)
  5498. {
  5499. return "TPTooHot";
  5500. }
  5501.  
  5502. if (config.Settings.Interrupt.AboveWater && AboveWater(player))
  5503. {
  5504. return "TPAboveWater";
  5505. }
  5506.  
  5507. if (config.Settings.Interrupt.Swimming && player.IsSwimming())
  5508. {
  5509. return "TPSwimming";
  5510. }
  5511.  
  5512. if (config.Settings.Interrupt.Cargo && player.GetComponentInParent<CargoShip>())
  5513. {
  5514. return "TPCargoShip";
  5515. }
  5516.  
  5517. if (config.Settings.Interrupt.Balloon && player.GetComponentInParent<HotAirBalloon>())
  5518. {
  5519. return "TPHotAirBalloon";
  5520. }
  5521.  
  5522. if (config.Settings.Interrupt.Lift && player.GetComponentInParent<Lift>())
  5523. {
  5524. return "TPBucketLift";
  5525. }
  5526.  
  5527. if (config.Settings.Interrupt.Lift && GetLift(player.transform.position))
  5528. {
  5529. return "TPRegLift";
  5530. }
  5531.  
  5532. if (config.Settings.Interrupt.Safe && player.InSafeZone())
  5533. {
  5534. return "TPSafeZone";
  5535. }
  5536.  
  5537. if (!craft && player.inventory.crafting.queue.Count > 0)
  5538. {
  5539. return "TPCrafting";
  5540. }
  5541.  
  5542. if (player.IsDead())
  5543. {
  5544. return "TPDead";
  5545. }
  5546.  
  5547. if (!build && !player.CanBuild())
  5548. {
  5549. return "TPBuildingBlocked";
  5550. }
  5551.  
  5552. if (config.Settings.BlockZoneFlag && ZoneManager != null)
  5553. {
  5554. var success = ZoneManager?.Call("PlayerHasFlag", player, "notp");
  5555.  
  5556. if (success is bool && (bool)success)
  5557. {
  5558. return "TPFlagZone";
  5559. }
  5560. }
  5561.  
  5562. if (config.Settings.BlockNoEscape && NoEscape != null)
  5563. {
  5564. if (Convert.ToBoolean(NoEscape?.Call("IsBlocked", player)))
  5565. {
  5566. return "TPNoEscapeBlocked";
  5567. }
  5568. }
  5569.  
  5570. //if (AntiHack.TestInsideTerrain(player.transform.position + new Vector3(0f, 0.1f, 0f))) return "TPInsideTerrainFrom";
  5571.  
  5572. return null;
  5573. }
  5574.  
  5575. private string CheckTargetLocation(BasePlayer player, Vector3 targetLocation, bool usableIntoBuildingBlocked, bool cupOwnerAllowOnBuildingBlocked)
  5576. {
  5577. if (CanBypassRestrictions(player.UserIDString)) return null;
  5578. // ubb == UsableIntoBuildingBlocked
  5579. // obb == CupOwnerAllowOnBuildingBlocked
  5580. var entities = Pool.GetList<BuildingBlock>();
  5581. Vis.Entities(targetLocation, 3f, entities, Layers.Mask.Construction, QueryTriggerInteraction.Ignore);
  5582. bool denied = false;
  5583.  
  5584. foreach (var block in entities)
  5585. {
  5586. if (CheckCupboardBlock(block, player, cupOwnerAllowOnBuildingBlocked))
  5587. {
  5588. denied = false;
  5589. #if DEBUG
  5590. Puts("Cupboard either owned or there is no cupboard");
  5591. #endif
  5592. }
  5593. else if (usableIntoBuildingBlocked && player.userID != block.OwnerID)
  5594. {
  5595. denied = false;
  5596. #if DEBUG
  5597. Puts("Player does not own block, but UsableIntoBuildingBlocked=true");
  5598. #endif
  5599. }
  5600. else if (player.userID == block.OwnerID)
  5601. {
  5602. #if DEBUG
  5603. Puts("Player owns block");
  5604. #endif
  5605.  
  5606. if (!player.IsBuildingBlocked(targetLocation, new Quaternion(), block.bounds))
  5607. {
  5608. #if DEBUG
  5609. Puts("Player not BuildingBlocked. Likely unprotected building.");
  5610. #endif
  5611. denied = false;
  5612. break;
  5613. }
  5614. else if (usableIntoBuildingBlocked)
  5615. {
  5616. #if DEBUG
  5617. Puts("Player not blocked because UsableIntoBuildingBlocked=true");
  5618. #endif
  5619. denied = false;
  5620. break;
  5621. }
  5622. else
  5623. {
  5624. #if DEBUG
  5625. Puts("Player owns block but blocked by UsableIntoBuildingBlocked=false");
  5626. #endif
  5627. denied = true;
  5628. break;
  5629. }
  5630. }
  5631. else
  5632. {
  5633. #if DEBUG
  5634. Puts("Player blocked");
  5635. #endif
  5636. denied = true;
  5637. break;
  5638. }
  5639. }
  5640. Pool.FreeList(ref entities);
  5641.  
  5642. return denied ? "TPTargetBuildingBlocked" : null;
  5643. }
  5644.  
  5645. // Check that a building block is owned by/attached to a cupboard, allow tp if not blocked unless allowed by config
  5646. private bool CheckCupboardBlock(BuildingBlock block, BasePlayer player, bool cupOwnerAllowOnBuildingBlocked)
  5647. {
  5648. // obb == CupOwnerAllowOnBuildingBlocked
  5649. var building = block.GetBuilding();
  5650. if (building != null)
  5651. {
  5652. #if DEBUG
  5653. Puts("Found building, checking privileges...");
  5654. Puts($"Building ID: {building.ID}");
  5655. #endif
  5656. // cupboard overlap. Check privs.
  5657. if (building.buildingPrivileges == null)
  5658. {
  5659. #if DEBUG
  5660. Puts("No cupboard found, allowing teleport");
  5661. #endif
  5662. return player.CanBuild();
  5663. }
  5664.  
  5665. foreach (var priv in building.buildingPrivileges)
  5666. {
  5667. if (priv.IsAuthed(player))
  5668. {
  5669. // player is authorized to the cupboard
  5670. #if DEBUG
  5671. Puts("Player owns cupboard with auth");
  5672. #endif
  5673. return true;
  5674. }
  5675. }
  5676.  
  5677. if (player.userID == block.OwnerID)
  5678. {
  5679. if (cupOwnerAllowOnBuildingBlocked)
  5680. {
  5681. #if DEBUG
  5682. // player set the cupboard and is allowed in by config
  5683. Puts("Player owns cupboard with no auth, but allowed by CupOwnerAllowOnBuildingBlocked=true");
  5684. #endif
  5685. return true;
  5686. }
  5687. #if DEBUG
  5688. // player set the cupboard but is blocked by config
  5689. Puts("Player owns cupboard with no auth, but blocked by CupOwnerAllowOnBuildingBlocked=false");
  5690. #endif
  5691. return false;
  5692. }
  5693.  
  5694. #if DEBUG
  5695. // player not authed
  5696. Puts("Player does not own cupboard and is not authorized");
  5697. #endif
  5698. return false;
  5699. }
  5700. #if DEBUG
  5701. Puts("No cupboard or building found - we cannot tell the status of this block");
  5702. #endif
  5703. return true;
  5704. }
  5705.  
  5706. private string CheckInsideEntity(Vector3 targetLocation, ulong userid)
  5707. {
  5708. Vector3 a = targetLocation + new Vector3(0, 0.55f);
  5709. var entities = FindEntitiesOfType<BaseEntity>(a, 0.5f, Layers.Mask.Construction | Layers.Mask.Deployed);
  5710. if (entities.Any(e => e is BuildingBlock || e is SimpleBuildingBlock || e is IceFence || e is ElectricBattery || e is Door))
  5711. {
  5712. return "TPTargetInsideEntity";
  5713. }
  5714. if (Exploits.TestRock(targetLocation))
  5715. {
  5716. LogToFile("exploiters", $"{userid} sethome inside a rock at {targetLocation}", this, true);
  5717. PrintMsgL(userid, "TPTargetInsideRock");
  5718. return "TPTargetInsideRock";
  5719. }
  5720. if (Exploits.TestFoundation(targetLocation))
  5721. {
  5722. LogToFile("exploiters", $"{userid} sethome inside a foundation at {targetLocation}", this, true);
  5723. PrintMsgL(userid, "TPTargetInsideBlock");
  5724. return "TPTargetInsideBlock";
  5725. }
  5726. return null;
  5727. }
  5728.  
  5729. private static List<T> FindEntitiesOfType<T>(Vector3 a, float n, int m = -1) where T : BaseNetworkable
  5730. {
  5731. int hits = Physics.OverlapSphereNonAlloc(a, n, Vis.colBuffer, m, QueryTriggerInteraction.Collide);
  5732. List<T> entities = new List<T>();
  5733. for (int i = 0; i < hits; i++)
  5734. {
  5735. var entity = Vis.colBuffer[i]?.ToBaseEntity();
  5736. if (entity is T) entities.Add(entity as T);
  5737. Vis.colBuffer[i] = null;
  5738. }
  5739. return entities;
  5740. }
  5741.  
  5742. private string CheckItems(BasePlayer player)
  5743. {
  5744. foreach (var blockedItem in ReverseBlockedItems)
  5745. {
  5746. if (player.inventory.FindItemID(blockedItem.Key) != null)
  5747. {
  5748. return blockedItem.Value;
  5749. }
  5750. }
  5751. return null;
  5752. }
  5753.  
  5754. private string CheckFoundation(ulong userid, Vector3 position)
  5755. {
  5756. if (CanBypassRestrictions(userid.ToString())) return null;
  5757. string insideErr = CheckInsideEntity(position, userid);
  5758. if (insideErr != null)
  5759. {
  5760. return insideErr;
  5761. }
  5762. if (permission.UserHasPermission(userid.ToString(), PermFoundationCheck))
  5763. {
  5764. return null;
  5765. }
  5766. if (!config.Home.ForceOnTopOfFoundation) return null; // Foundation/floor not required
  5767. if (UnderneathFoundation(position))
  5768. {
  5769. return "HomeFoundationUnderneathFoundation";
  5770. }
  5771.  
  5772. var entities = new List<BuildingBlock>();
  5773. if (config.Home.AllowAboveFoundation) // Can set on a foundation or floor
  5774. {
  5775. #if DEBUG
  5776. Puts($"CheckFoundation() looking for foundation or floor at {position}");
  5777. #endif
  5778. entities = GetFoundationOrFloor(position);
  5779. }
  5780. else // Can only use foundation, not floor/ceiling
  5781. {
  5782. #if DEBUG
  5783. Puts($"CheckFoundation() looking for foundation at {position}");
  5784. #endif
  5785. entities = GetFoundation(position);
  5786. }
  5787.  
  5788. entities.RemoveAll(x => !x.IsValid() || x.IsDestroyed);
  5789. if (entities.Count == 0) return "HomeNoFoundation";
  5790.  
  5791. if (!config.Home.CheckFoundationForOwner) return null;
  5792. for (var i = 0; i < entities.Count; i++)
  5793. {
  5794. if (IsFriend(userid, entities[i].OwnerID)) return null;
  5795. }
  5796.  
  5797. return "HomeFoundationNotFriendsOwned";
  5798. }
  5799.  
  5800. private BuildingBlock GetFoundationOwned(Vector3 position, ulong userID)
  5801. {
  5802. #if DEBUG
  5803. Puts("GetFoundationOwned() called...");
  5804. #endif
  5805. var entities = GetFoundation(position);
  5806. if (entities.Count == 0) return null;
  5807. if (!config.Home.CheckFoundationForOwner) return entities[0];
  5808.  
  5809. for (var i = 0; i < entities.Count; i++)
  5810. {
  5811. if (IsFriend(userID, entities[i].OwnerID)) return entities[i];
  5812. }
  5813. return null;
  5814. }
  5815.  
  5816. // Borrowed/modified from PreventLooting and Rewards
  5817. // playerid = active player, ownerid = owner of building block, who may be offline
  5818. bool IsFriend(ulong playerid, ulong ownerid)
  5819. {
  5820. if (playerid == ownerid) return true;
  5821. if (config.Home.UseFriends && Friends != null && Friends.IsLoaded)
  5822. {
  5823. #if DEBUG
  5824. Puts("Checking Friends...");
  5825. #endif
  5826. var fr = Friends?.CallHook("AreFriends", playerid, ownerid);
  5827. if (fr != null && fr is bool && (bool)fr)
  5828. {
  5829. #if DEBUG
  5830. Puts(" IsFriend: true based on Friends plugin");
  5831. #endif
  5832. return true;
  5833. }
  5834. }
  5835. if (config.Home.UseClans && Clans != null && Clans.IsLoaded)
  5836. {
  5837. #if DEBUG
  5838. Puts("Checking Clans...");
  5839. #endif
  5840. string playerclan = (string)Clans?.CallHook("GetClanOf", playerid);
  5841. string ownerclan = (string)Clans?.CallHook("GetClanOf", ownerid);
  5842. if (playerclan != null && ownerclan != null && playerclan == ownerclan)
  5843. {
  5844. #if DEBUG
  5845. Puts(" IsFriend: true based on Clans plugin");
  5846. #endif
  5847. return true;
  5848. }
  5849. }
  5850. if (config.Home.UseTeams)
  5851. {
  5852. #if DEBUG
  5853. Puts("Checking Rust teams...");
  5854. #endif
  5855. RelationshipManager.PlayerTeam playerTeam;
  5856. if (RelationshipManager.ServerInstance.playerToTeam.TryGetValue(playerid, out playerTeam))
  5857. {
  5858. if (playerTeam.members.Contains(ownerid))
  5859. {
  5860. #if DEBUG
  5861. Puts(" IsFriend: true based on Rust teams");
  5862. #endif
  5863. return true;
  5864. }
  5865. }
  5866. }
  5867. return false;
  5868. }
  5869.  
  5870. // Check that we are near the middle of a block. Also check for high wall overlap
  5871. private bool ValidBlock(BaseEntity entity, Vector3 position)
  5872. {
  5873. if (!config.Settings.StrictFoundationCheck)
  5874. {
  5875. return true;
  5876. }
  5877. #if DEBUG
  5878. Puts($"ValidBlock() called for {entity.ShortPrefabName}");
  5879. #endif
  5880. Vector3 center = entity.CenterPoint();
  5881.  
  5882. List<BaseEntity> ents = new List<BaseEntity>();
  5883. Vis.Entities<BaseEntity>(center, 1.5f, ents);
  5884. foreach (BaseEntity wall in ents)
  5885. {
  5886. if (wall.name.Contains("external.high"))
  5887. {
  5888. #if DEBUG
  5889. Puts($" Found: {wall.name} @ center {center}, pos {position}");
  5890. #endif
  5891. return false;
  5892. }
  5893. }
  5894. #if DEBUG
  5895. Puts($" Checking block: {entity.name} @ center {center}, pos: {position}");
  5896. #endif
  5897. if (entity.PrefabName.Contains("triangle.prefab"))
  5898. {
  5899. if (Math.Abs(center.x - position.x) < 0.5f && Math.Abs(center.z - position.z) < 0.5f)
  5900. {
  5901. #if DEBUG
  5902. Puts($" Found: {entity.ShortPrefabName} @ center: {center}, pos: {position}");
  5903. #endif
  5904. return true;
  5905. }
  5906. }
  5907. else if (entity.PrefabName.Contains("foundation.prefab") || entity.PrefabName.Contains("floor.prefab"))
  5908. {
  5909. if (Math.Abs(center.x - position.x) < 0.7f && Math.Abs(center.z - position.z) < 0.7f)
  5910. {
  5911. #if DEBUG
  5912. Puts($" Found: {entity.ShortPrefabName} @ center: {center}, pos: {position}");
  5913. #endif
  5914. return true;
  5915. }
  5916. }
  5917.  
  5918. return false;
  5919. }
  5920.  
  5921. private List<BuildingBlock> GetFoundation(Vector3 position)
  5922. {
  5923. RaycastHit hit;
  5924. var entities = new List<BuildingBlock>();
  5925.  
  5926. if (Physics.Raycast(position + new Vector3(0f, 0.2f, 0f), Vector3.down, out hit, 3f, Layers.Mask.Construction))
  5927. {
  5928. var entity = hit.GetEntity();
  5929.  
  5930. if (entity.IsValid())
  5931. {
  5932. if (entity.PrefabName.Contains("foundation")) // || position.y < entity.WorldSpaceBounds().ToBounds().max.y)
  5933. {
  5934. if (ValidBlock(entity, position))
  5935. {
  5936. #if DEBUG
  5937. Puts($" GetFoundation() found {entity.PrefabName} at {entity.transform.position}");
  5938. #endif
  5939. entities.Add(entity as BuildingBlock);
  5940. }
  5941. }
  5942. }
  5943. }
  5944. #if DEBUG
  5945. if (entities.Count == 0)
  5946. {
  5947. Puts(" GetFoundation() none found.");
  5948. }
  5949. #endif
  5950. return entities;
  5951. }
  5952.  
  5953. private List<BuildingBlock> GetFloor(Vector3 position)
  5954. {
  5955. RaycastHit hitinfo;
  5956. var entities = new List<BuildingBlock>();
  5957.  
  5958. if (Physics.Raycast(position, Vector3.down, out hitinfo, 3f, Layers.Mask.Construction, QueryTriggerInteraction.Ignore) && hitinfo.GetEntity().IsValid())
  5959. {
  5960. var entity = hitinfo.GetEntity();
  5961.  
  5962. if (entity.IsValid() && entity.PrefabName.Contains("floor"))
  5963. {
  5964. #if DEBUG
  5965. Puts($" GetFloor() found {entity.PrefabName} at {entity.transform.position}");
  5966. #endif
  5967. entities.Add(entity as BuildingBlock);
  5968. }
  5969. }
  5970. else
  5971. {
  5972. #if DEBUG
  5973. Puts(" GetFloor() none found.");
  5974. #endif
  5975. }
  5976.  
  5977. return entities;
  5978. }
  5979.  
  5980. private List<BuildingBlock> GetFoundationOrFloor(Vector3 position)
  5981. {
  5982. RaycastHit hitinfo;
  5983. var entities = new List<BuildingBlock>();
  5984.  
  5985. if (Physics.Raycast(position + new Vector3(0f, 0.2f, 0f), Vector3.down, out hitinfo, 3f, Layers.Mask.Construction) && hitinfo.GetEntity().IsValid())
  5986. {
  5987. var entity = hitinfo.GetEntity();
  5988. if (entity.PrefabName.Contains("floor") || entity.PrefabName.Contains("foundation"))// || position.y < entity.WorldSpaceBounds().ToBounds().max.y))
  5989. {
  5990. #if DEBUG
  5991. Puts($" GetFoundationOrFloor() found {entity.PrefabName} at {entity.transform.position}");
  5992. #endif
  5993. if (ValidBlock(entity, position))
  5994. {
  5995. entities.Add(entity as BuildingBlock);
  5996. }
  5997. }
  5998. }
  5999. else
  6000. {
  6001. #if DEBUG
  6002. Puts(" GetFoundationOrFloor() none found.");
  6003. #endif
  6004. }
  6005.  
  6006. return entities;
  6007. }
  6008.  
  6009. private bool CheckBoundaries(float x, float y, float z)
  6010. {
  6011. return x <= boundary && x >= -boundary && y <= 2000 && y >= -100 && z <= boundary && z >= -boundary;
  6012. }
  6013.  
  6014. private Vector3 GetGround(Vector3 sourcePos)
  6015. {
  6016. if (!config.Home.AllowAboveFoundation) return sourcePos;
  6017. var newPos = sourcePos;
  6018. newPos.y = TerrainMeta.HeightMap.GetHeight(newPos);
  6019. sourcePos.y += .5f;
  6020. RaycastHit hitinfo;
  6021. var done = false;
  6022.  
  6023. #if DEBUG
  6024. Puts("GetGround(): Looking for iceberg or cave");
  6025. #endif
  6026. //if (Physics.SphereCast(sourcePos, .1f, Vector3.down, out hitinfo, 250, groundLayer))
  6027. if (Physics.Raycast(sourcePos, Vector3.down, out hitinfo, 250f, Layers.Mask.Terrain | Layers.Mask.World))
  6028. {
  6029. if ((config.Home.AllowIceberg && hitinfo.collider.name.Contains("iceberg")) || (config.Home.AllowCave && hitinfo.collider.name.Contains("cave_")))
  6030. {
  6031. #if DEBUG
  6032. Puts("GetGround(): found iceberg or cave");
  6033. #endif
  6034. sourcePos.y = hitinfo.point.y;
  6035. done = true;
  6036. }
  6037. else
  6038. {
  6039. var mesh = hitinfo.collider.GetComponentInChildren<MeshCollider>();
  6040. if (mesh != null && mesh.sharedMesh.name.Contains("rock_"))
  6041. {
  6042. sourcePos.y = hitinfo.point.y;
  6043. done = true;
  6044. }
  6045. }
  6046. }
  6047. #if DEBUG
  6048. Puts("GetGround(): Looking for cave or rock");
  6049. #endif
  6050. //if (!_config.Home.AllowCave && Physics.SphereCast(sourcePos, .1f, up, out hitinfo, 250, Layers.Mask.Terrain | Layers.Mask.World) && hitinfo.collider.name.Contains("rock_"))
  6051. if (!config.Home.AllowCave && Physics.Raycast(sourcePos, Vector3.up, out hitinfo, 250f, Layers.Mask.Terrain | Layers.Mask.World) && hitinfo.collider.name.Contains("rock_"))
  6052. {
  6053. #if DEBUG
  6054. Puts("GetGround(): found cave or rock");
  6055. #endif
  6056. sourcePos.y = newPos.y - 10;
  6057. done = true;
  6058. }
  6059. return done ? sourcePos : newPos;
  6060. }
  6061.  
  6062. private bool GetLift(Vector3 position)
  6063. {
  6064. List<ProceduralLift> nearObjectsOfType = new List<ProceduralLift>();
  6065. Vis.Entities<ProceduralLift>(position, 0.5f, nearObjectsOfType);
  6066. if (nearObjectsOfType.Count > 0)
  6067. {
  6068. return true;
  6069. }
  6070. return false;
  6071. }
  6072.  
  6073. private bool IsOnJunkPile(BasePlayer player)
  6074. {
  6075. if (player.GetParentEntity() is JunkPile)
  6076. {
  6077. return true;
  6078. }
  6079.  
  6080. RaycastHit hit;
  6081. if (Physics.Raycast(player.transform.position + new Vector3(0f, 0.5f, 0f), Vector3.down, out hit, 3f, Layers.Mask.World, QueryTriggerInteraction.Ignore))
  6082. {
  6083. return hit.GetEntity() is JunkPile;
  6084. }
  6085.  
  6086. return false;
  6087. }
  6088.  
  6089. private Vector3 GetGroundBuilding(Vector3 sourcePos)
  6090. {
  6091. sourcePos.y = TerrainMeta.HeightMap.GetHeight(sourcePos);
  6092. RaycastHit hitinfo;
  6093. if (Physics.Raycast(sourcePos, Vector3.down, out hitinfo, Layers.Mask.Terrain | Layers.Mask.World | Layers.Mask.Construction | Layers.Mask.Deployed))
  6094. {
  6095. sourcePos.y = Mathf.Max(hitinfo.point.y, sourcePos.y);
  6096. return sourcePos;
  6097. }
  6098. if (Physics.Raycast(sourcePos, Vector3.up, out hitinfo, Layers.Mask.Terrain | Layers.Mask.World | Layers.Mask.Construction | Layers.Mask.Deployed))
  6099. sourcePos.y = Mathf.Max(hitinfo.point.y, sourcePos.y);
  6100. return sourcePos;
  6101. }
  6102.  
  6103. private bool UnderneathFoundation(Vector3 position)
  6104. {
  6105. RaycastHit hit;
  6106. if (Physics.Raycast(position + new Vector3(0f, 3f, 0f), Vector3.down, out hit, 5f, Layers.Mask.Construction, QueryTriggerInteraction.Ignore))
  6107. {
  6108. var block = hit.GetEntity() as BuildingBlock;
  6109.  
  6110. if (block.IsValid() && (block.prefabID == 72949757 || block.prefabID == 3234260181))
  6111. {
  6112. return hit.point.y > position.y;
  6113. }
  6114. }
  6115. return false;
  6116. }
  6117.  
  6118. private bool IsAllowed(BasePlayer player, string perm = null)
  6119. {
  6120. var playerAuthLevel = player.net?.connection?.authLevel;
  6121.  
  6122. int requiredAuthLevel = 3;
  6123. if (config.Admin.UseableByModerators)
  6124. {
  6125. requiredAuthLevel = 1;
  6126. }
  6127. else if (config.Admin.UseableByAdmins)
  6128. {
  6129. requiredAuthLevel = 2;
  6130. }
  6131. if (playerAuthLevel >= requiredAuthLevel) return true;
  6132.  
  6133. return !string.IsNullOrEmpty(perm) && permission.UserHasPermission(player.UserIDString, perm);
  6134. }
  6135.  
  6136. private bool IsAllowedMsg(BasePlayer player, string perm = null)
  6137. {
  6138. if (IsAllowed(player, perm)) return true;
  6139. PrintMsgL(player, "NotAllowed");
  6140. return false;
  6141. }
  6142.  
  6143. private Effect reusableSoundEffectInstance = new Effect();
  6144.  
  6145. private void SendEffect(BasePlayer player, string sound = null)
  6146. {
  6147. if (config.Settings.PlaySounds && config.Settings.PrefabSounds.Count != 0)
  6148. {
  6149. if (string.IsNullOrEmpty(sound)) sound = config.Settings.PrefabSounds.GetRandom();
  6150.  
  6151. reusableSoundEffectInstance.Init(Effect.Type.Generic, player, 0, Vector3.zero, Vector3.forward);
  6152. reusableSoundEffectInstance.pooledString = sound;
  6153.  
  6154. EffectNetwork.Send(reusableSoundEffectInstance, player.Connection);
  6155. }
  6156. }
  6157.  
  6158. private int GetHigher(BasePlayer player, Dictionary<string, int> limits, int limit, bool unlimited)
  6159. {
  6160. if (unlimited && limit == 0) return limit;
  6161.  
  6162. foreach (var l in limits)
  6163. {
  6164. if (permission.UserHasPermission(player.UserIDString, l.Key))
  6165. {
  6166. if (unlimited && l.Value == 0) return l.Value;
  6167.  
  6168. limit = Math.Max(l.Value, limit);
  6169. }
  6170. }
  6171. return limit;
  6172. }
  6173.  
  6174. private int GetLower(BasePlayer player, Dictionary<string, int> times, int time)
  6175. {
  6176. foreach (var l in times)
  6177. {
  6178. if (permission.UserHasPermission(player.UserIDString, l.Key))
  6179. {
  6180. time = Math.Min(l.Value, time);
  6181. }
  6182. }
  6183. return time;
  6184. }
  6185.  
  6186. private void CheckPerms(Dictionary<string, int> limits)
  6187. {
  6188. foreach (var limit in limits)
  6189. {
  6190. if (!permission.PermissionExists(limit.Key))
  6191. {
  6192. permission.RegisterPermission(limit.Key, this);
  6193. }
  6194. }
  6195. }
  6196. #endregion
  6197.  
  6198. #region Message
  6199. private string _(string msgId, BasePlayer player, params object[] args)
  6200. {
  6201. var msg = lang.GetMessage(msgId, this, player?.UserIDString);
  6202. return args.Length > 0 ? string.Format(msg, args) : msg;
  6203. }
  6204.  
  6205. private void PrintMsgL(IPlayer user, string msgId, params object[] args)
  6206. {
  6207. if (user.IsServer)
  6208. {
  6209. user.Reply(string.Format(lang.GetMessage(msgId, this, user.Id), args));
  6210. }
  6211. else PrintMsgL(user.Object as BasePlayer, msgId, args);
  6212. }
  6213.  
  6214. private void PrintMsgL(BasePlayer player, string msgId, params object[] args)
  6215. {
  6216. if (player == null) return;
  6217. PrintMsg(player, _(msgId, player, args));
  6218. }
  6219.  
  6220. private void PrintMsgL(ulong userid, string msgId, params object[] args)
  6221. {
  6222. var player = BasePlayer.FindAwakeOrSleeping(userid.ToString());
  6223. if (player == null) return;
  6224. PrintMsgL(player, msgId, args);
  6225. }
  6226.  
  6227. private void PrintMsg(BasePlayer player, string message)
  6228. {
  6229. if (player == null || string.IsNullOrEmpty(message)) return;
  6230. if (config.Settings.UsePopup)
  6231. {
  6232. PopupNotifications?.Call("CreatePopupNotification", config.Settings.ChatName + message, player);
  6233. }
  6234. else Player.Message(player, $"{config.Settings.ChatName}{message}", config.Settings.ChatID);
  6235. }
  6236.  
  6237. #endregion
  6238.  
  6239. #region DrawBox
  6240. private static void DrawBox(BasePlayer player, Vector3 center, Quaternion rotation, Vector3 size)
  6241. {
  6242. size /= 2;
  6243. var point1 = RotatePointAroundPivot(new Vector3(center.x + size.x, center.y + size.y, center.z + size.z), center, rotation);
  6244. var point2 = RotatePointAroundPivot(new Vector3(center.x + size.x, center.y - size.y, center.z + size.z), center, rotation);
  6245. var point3 = RotatePointAroundPivot(new Vector3(center.x + size.x, center.y + size.y, center.z - size.z), center, rotation);
  6246. var point4 = RotatePointAroundPivot(new Vector3(center.x + size.x, center.y - size.y, center.z - size.z), center, rotation);
  6247. var point5 = RotatePointAroundPivot(new Vector3(center.x - size.x, center.y + size.y, center.z + size.z), center, rotation);
  6248. var point6 = RotatePointAroundPivot(new Vector3(center.x - size.x, center.y - size.y, center.z + size.z), center, rotation);
  6249. var point7 = RotatePointAroundPivot(new Vector3(center.x - size.x, center.y + size.y, center.z - size.z), center, rotation);
  6250. var point8 = RotatePointAroundPivot(new Vector3(center.x - size.x, center.y - size.y, center.z - size.z), center, rotation);
  6251.  
  6252. player.SendConsoleCommand("ddraw.line", 30f, Color.blue, point1, point2);
  6253. player.SendConsoleCommand("ddraw.line", 30f, Color.blue, point1, point3);
  6254. player.SendConsoleCommand("ddraw.line", 30f, Color.blue, point1, point5);
  6255. player.SendConsoleCommand("ddraw.line", 30f, Color.blue, point4, point2);
  6256. player.SendConsoleCommand("ddraw.line", 30f, Color.blue, point4, point3);
  6257. player.SendConsoleCommand("ddraw.line", 30f, Color.blue, point4, point8);
  6258.  
  6259. player.SendConsoleCommand("ddraw.line", 30f, Color.blue, point5, point6);
  6260. player.SendConsoleCommand("ddraw.line", 30f, Color.blue, point5, point7);
  6261. player.SendConsoleCommand("ddraw.line", 30f, Color.blue, point6, point2);
  6262. player.SendConsoleCommand("ddraw.line", 30f, Color.blue, point8, point6);
  6263. player.SendConsoleCommand("ddraw.line", 30f, Color.blue, point8, point7);
  6264. player.SendConsoleCommand("ddraw.line", 30f, Color.blue, point7, point3);
  6265. }
  6266.  
  6267. private static Vector3 RotatePointAroundPivot(Vector3 point, Vector3 pivot, Quaternion rotation)
  6268. {
  6269. return rotation * (point - pivot) + pivot;
  6270. }
  6271. #endregion
  6272.  
  6273. #region FindPlayer
  6274. private ulong FindPlayersSingleId(string nameOrIdOrIp, BasePlayer player)
  6275. {
  6276. var targets = FindPlayers(nameOrIdOrIp, true);
  6277. if (targets.Count > 1)
  6278. {
  6279. PrintMsgL(player, "MultiplePlayers", GetMultiplePlayers(targets));
  6280. return 0;
  6281. }
  6282. ulong userId;
  6283. if (targets.Count <= 0)
  6284. {
  6285. if (ulong.TryParse(nameOrIdOrIp, out userId)) return userId;
  6286. PrintMsgL(player, "PlayerNotFound");
  6287. return 0;
  6288. }
  6289. else
  6290. userId = targets.First().userID;
  6291.  
  6292. return userId;
  6293. }
  6294.  
  6295. private BasePlayer FindPlayersSingle(string value, BasePlayer player)
  6296. {
  6297. if (string.IsNullOrEmpty(value)) return null;
  6298. BasePlayer target;
  6299. if (_ids.TryGetValue(value, out target) && target.IsValid())
  6300. {
  6301. return target;
  6302. }
  6303. var targets = FindPlayers(value, true);
  6304. if (targets.Count <= 0)
  6305. {
  6306. PrintMsgL(player, "PlayerNotFound");
  6307. return null;
  6308. }
  6309. if (targets.Count > 1)
  6310. {
  6311. PrintMsgL(player, "MultiplePlayers", GetMultiplePlayers(targets));
  6312. return null;
  6313. }
  6314.  
  6315. return targets.First();
  6316. }
  6317.  
  6318. private List<BasePlayer> FindPlayers(string arg, bool all = false)
  6319. {
  6320. var players = new List<BasePlayer>();
  6321.  
  6322. if (string.IsNullOrEmpty(arg))
  6323. {
  6324. return players;
  6325. }
  6326.  
  6327. BasePlayer target;
  6328. if (_ids.TryGetValue(arg, out target) && target.IsValid())
  6329. {
  6330. if (all || target.IsConnected)
  6331. {
  6332. players.Add(target);
  6333. return players;
  6334. }
  6335. }
  6336.  
  6337. foreach (var user in all ? BasePlayer.allPlayerList : BasePlayer.activePlayerList)
  6338. {
  6339. if (user == null || string.IsNullOrEmpty(user.displayName) || players.Contains(user))
  6340. {
  6341. continue;
  6342. }
  6343.  
  6344. if (user.UserIDString == arg || user.displayName.Contains(arg, CompareOptions.OrdinalIgnoreCase))
  6345. {
  6346. players.Add(user);
  6347. }
  6348. }
  6349.  
  6350. return players;
  6351. }
  6352. #endregion
  6353.  
  6354. private class UnityVector3Converter : JsonConverter
  6355. {
  6356. public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
  6357. {
  6358. var vector = (Vector3)value;
  6359. writer.WriteValue($"{vector.x} {vector.y} {vector.z}");
  6360. }
  6361.  
  6362. public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
  6363. {
  6364. if (reader.TokenType == JsonToken.String)
  6365. {
  6366. var values = reader.Value.ToString().Trim().Split(' ');
  6367. return new Vector3(Convert.ToSingle(values[0]), Convert.ToSingle(values[1]), Convert.ToSingle(values[2]));
  6368. }
  6369. var o = JObject.Load(reader);
  6370. return new Vector3(Convert.ToSingle(o["x"]), Convert.ToSingle(o["y"]), Convert.ToSingle(o["z"]));
  6371. }
  6372.  
  6373. public override bool CanConvert(Type objectType)
  6374. {
  6375. return objectType == typeof(Vector3);
  6376. }
  6377. }
  6378.  
  6379. private class CustomComparerDictionaryCreationConverter<T> : CustomCreationConverter<IDictionary>
  6380. {
  6381. private readonly IEqualityComparer<T> comparer;
  6382.  
  6383. public CustomComparerDictionaryCreationConverter(IEqualityComparer<T> comparer)
  6384. {
  6385. if (comparer == null)
  6386. throw new ArgumentNullException(nameof(comparer));
  6387. this.comparer = comparer;
  6388. }
  6389.  
  6390. public override bool CanConvert(Type objectType)
  6391. {
  6392. return HasCompatibleInterface(objectType) && HasCompatibleConstructor(objectType);
  6393. }
  6394.  
  6395. private static bool HasCompatibleInterface(Type objectType)
  6396. {
  6397. return objectType.GetInterfaces().Where(i => HasGenericTypeDefinition(i, typeof(IDictionary<,>))).Any(i => typeof(T).IsAssignableFrom(i.GetGenericArguments().First()));
  6398. }
  6399.  
  6400. private static bool HasGenericTypeDefinition(Type objectType, Type typeDefinition)
  6401. {
  6402. return objectType.GetTypeInfo().IsGenericType && objectType.GetGenericTypeDefinition() == typeDefinition;
  6403. }
  6404.  
  6405. private static bool HasCompatibleConstructor(Type objectType)
  6406. {
  6407. return objectType.GetConstructor(new[] { typeof(IEqualityComparer<T>) }) != null;
  6408. }
  6409.  
  6410. public override IDictionary Create(Type objectType)
  6411. {
  6412. return Activator.CreateInstance(objectType, comparer) as IDictionary;
  6413. }
  6414. }
  6415.  
  6416. public class Exploits
  6417. {
  6418. public static bool TestFoundation(Vector3 a)
  6419. {
  6420. Physics.queriesHitBackfaces = true;
  6421.  
  6422. bool flag = IsFoundationUpwards(a);
  6423.  
  6424. Physics.queriesHitBackfaces = false;
  6425.  
  6426. return flag;
  6427. }
  6428.  
  6429. private static bool IsFoundationUpwards(Vector3 point)
  6430. {
  6431. RaycastHit hit;
  6432. if (!Physics.Raycast(point, Vector3.up, out hit, 3f, Layers.Construction)) return false;
  6433. return hit.collider.name.Contains("foundation");
  6434. }
  6435.  
  6436. public static bool TestRock(Vector3 a)
  6437. {
  6438. Physics.queriesHitBackfaces = true;
  6439.  
  6440. bool flag = IsRockFaceUpwards(a);
  6441.  
  6442. Physics.queriesHitBackfaces = false;
  6443.  
  6444. return flag || IsRockFaceDownwards(a);
  6445. }
  6446.  
  6447. private static bool IsRockFaceDownwards(Vector3 a)
  6448. {
  6449. Vector3 b = a + new Vector3(0f, 20f, 0f);
  6450. Vector3 d = a - b;
  6451. var hits = Physics.RaycastAll(b, d, d.magnitude, Layers.World);
  6452. return Array.Exists(hits, hit => IsRock(hit.collider.name));
  6453. }
  6454.  
  6455. private static bool IsRockFaceUpwards(Vector3 point)
  6456. {
  6457. RaycastHit hit;
  6458. if (!Physics.Raycast(point, Vector3.up, out hit, 20f, Layers.World)) return false;
  6459. return IsRock(hit.collider.gameObject.name);
  6460. }
  6461.  
  6462. private static bool IsRock(string name) => name.Contains("rock", CompareOptions.OrdinalIgnoreCase) || name.Contains("formation", CompareOptions.OrdinalIgnoreCase) || name.Contains("cliff", CompareOptions.OrdinalIgnoreCase);
  6463. }
  6464.  
  6465. [HookMethod("SendHelpText")]
  6466. private void SendHelpText(BasePlayer player)
  6467. {
  6468. PrintMsgL(player, "<size=14>NTeleportation</size> by <color=#ce422b>Nogrod</color>\n<color=#ffd479>/sethome NAME</color> - Set home on current foundation\n<color=#ffd479>/home NAME</color> - Go to one of your homes\n<color=#ffd479>/home list</color> - List your homes\n<color=#ffd479>/town</color> - Go to town, if set\n/tpb - Go back to previous location\n/tpr PLAYER - Request teleport to PLAYER\n/tpa - Accept teleport request");
  6469. }
  6470.  
  6471. private bool API_HavePendingRequest(BasePlayer player)
  6472. {
  6473. return PendingRequests.ContainsKey(player.userID) || PlayersRequests.ContainsKey(player.userID) || TeleportTimers.ContainsKey(player.userID);
  6474. }
  6475.  
  6476. private bool API_HaveAvailableHomes(BasePlayer player)
  6477. {
  6478. HomeData homeData;
  6479. if (!_Home.TryGetValue(player.userID, out homeData))
  6480. {
  6481. _Home[player.userID] = homeData = new HomeData();
  6482. }
  6483.  
  6484. ValidateHomes(player, homeData, false);
  6485.  
  6486. var limit = GetHigher(player, config.Home.VIPHomesLimits, config.Home.HomesLimit, true);
  6487.  
  6488. if (limit == 0) return true;
  6489.  
  6490. return homeData.Locations.Count < limit;
  6491. }
  6492.  
  6493. private Dictionary<string, Vector3> API_GetHomes(BasePlayer player)
  6494. {
  6495. HomeData homeData;
  6496. if (!_Home.TryGetValue(player.userID, out homeData))
  6497. {
  6498. _Home[player.userID] = homeData = new HomeData();
  6499. }
  6500.  
  6501. ValidateHomes(player, homeData, false);
  6502.  
  6503. return homeData.Locations;
  6504. }
  6505.  
  6506. private List<Vector3> API_GetLocations(string command)
  6507. {
  6508. var settings = GetSettings(command);
  6509.  
  6510. if (settings == null)
  6511. {
  6512. return new List<Vector3>();
  6513. }
  6514.  
  6515. return settings.Locations;
  6516. }
  6517.  
  6518. private Dictionary<string, List<Vector3>> API_GetAllLocations()
  6519. {
  6520. var dict = new Dictionary<string, List<Vector3>>();
  6521.  
  6522. foreach (var dc in config.DynamicCommands)
  6523. {
  6524. dict[dc.Key] = dc.Value.Locations;
  6525. }
  6526.  
  6527. return dict;
  6528. }
  6529.  
  6530. private int GetLimitRemaining(BasePlayer player, string type)
  6531. {
  6532. if (player == null || string.IsNullOrEmpty(type)) return -1;
  6533. var settings = GetSettings(type, player.userID);
  6534. if (settings == null) return -1;
  6535. var currentDate = DateTime.Now.ToString("d");
  6536. var limit = GetHigher(player, settings.VIPDailyLimits, settings.DailyLimit, true);
  6537. TeleportData data;
  6538. if (!settings.Teleports.TPData.TryGetValue(player.userID, out data))
  6539. {
  6540. settings.Teleports.TPData[player.userID] = data = new TeleportData();
  6541. }
  6542. if (data.Date != currentDate)
  6543. {
  6544. data.Amount = 0;
  6545. data.Date = currentDate;
  6546. }
  6547. if (limit > 0)
  6548. {
  6549. return limit - data.Amount;
  6550. }
  6551. return 0;
  6552. }
  6553.  
  6554. private int GetCooldownRemaining(BasePlayer player, string type)
  6555. {
  6556. if (player == null || string.IsNullOrEmpty(type)) return -1;
  6557. var settings = GetSettings(type, player.userID);
  6558. if (settings == null) return -1;
  6559. var currentDate = DateTime.Now.ToString("d");
  6560. var timestamp = Facepunch.Math.Epoch.Current;
  6561. var cooldown = GetLower(player, settings.VIPCooldowns, settings.Cooldown);
  6562. TeleportData data;
  6563. if (!settings.Teleports.TPData.TryGetValue(player.userID, out data))
  6564. {
  6565. settings.Teleports.TPData[player.userID] = data = new TeleportData();
  6566. }
  6567. if (data.Date != currentDate)
  6568. {
  6569. data.Amount = 0;
  6570. data.Date = currentDate;
  6571. }
  6572. if (cooldown > 0 && timestamp - data.Timestamp < cooldown)
  6573. {
  6574. return cooldown - (timestamp - data.Timestamp);
  6575. }
  6576. return 0;
  6577. }
  6578.  
  6579. private int GetCountdownRemaining(BasePlayer player, string type)
  6580. {
  6581. if (player == null || string.IsNullOrEmpty(type))
  6582. {
  6583. return -1;
  6584. }
  6585.  
  6586. TownSettings settings = GetSettings(type, player.userID);
  6587. if (settings == null)
  6588. {
  6589. return -1;
  6590. }
  6591.  
  6592. return GetLower(player, settings.VIPCountdowns, settings.Countdown);
  6593. }
  6594. }
  6595. }
Advertisement
Add Comment
Please, Sign In to add comment