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

FREE BountyHunter : 1.2.8 1.2.8

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System;
using System.Collections.Generic;
using System.Linq;
using Oxide.Core;
using UnityEngine;
using Quaternion = UnityEngine.Quaternion;
using Random = UnityEngine.Random;
using Newtonsoft.Json;
using Oxide.Core.Libraries;
using Oxide.Core.Plugins;
using UnityEngine.AI;
using Time = UnityEngine.Time;
using Facepunch;
/*Developer API
Dictionary<ulong, int> GetBountyStats() */
// Returns a Dictionary<ulong, int> where the key is the player's ID and the value is the number of bounty kills.// If no data is available, it returns an empty dictionary./*
* Changelog : * * Version 1.2.8 : * - Added a Delay on Dependency Check for NPC To Spawn On Initial Load.* - Added Kits Support to Bounties */namespace Oxide.Plugins {
    [Info("Bounty Hunter", "Wrecks", "1.2.8")]
    [Description("Spawns Bounties at Monuments for Customizable Rewards.")]
    public class BountyHunter : RustPlugin {
        [PluginReference]
        private Plugin Economics, ServerRewards, Kits, MarkerManager, SkillTree;
#region lang
        protected override void LoadDefaultMessages() {
            lang.RegisterMessages (new Dictionary<string, string> {
                ["NoPerms"]
                = "[<color=#b5a642>Bounty Hunter</color>] You do not have permission to run this <color=#b54251>Command</color>!", ["NoTokens"] = "[<color=#b5a642>Bounty Hunter</color>] :coffeecan: You have no <color=#b5a642>Bounty Tokens</color> on you that I can cash out.\nBe on the look out, see you soon!\n\n:exclamation:", ["BountyHunterCooldownMessage"] = "[<color=#b5a642>Bounty Hunter</color>] :angry: Wait <color=#a642b5>{0}</color> second(s)!, I think I spotted a <color=#b5a642>Bounty</color>...", ["EconomicsMessage"] = "[<color=#b5a642>Bounty Hunter</color>] :eyes: \n\n I can net you <color=#85bb65>$</color><color=#42b5a6>{0}</color> for your <color=#42b5a6>{1}x</color> <color=#a642b5>{2}</color>(s).", ["SrMessage"] = "[<color=#b5a642>Bounty Hunter</color>] :eyes: \n\n I can net you <color=#42b5a6>{0}</color> <color=#cd5c5c>RP</color> for your <color=#42b5a6>{1}x</color> <color=#a642b5>{2}</color>(s).", ["SaleDisabled"] = "[<color=#b5a642>Bounty Hunter</color>] <color=#42b5a6>Sales</color> are Disabled in the Config, Enable and Try again.", ["NoBountyHunterLicense"] = "[<color=#b5a642>Bounty Hunter</color>] :eyebrow: Are you out there targeting Bounties without a <color=#42b5a6>License</color>? \nUse <color=#42b5a6>/BuyBL</color> to purchase one.", ["AlreadyHasLicense"] = "[<color=#b5a642>Bounty Hunter</color>] You already have a <color=#b54251>Bounty Hunter License</color>.", ["BuyBountyHunterLicenseSuccess"] = "[<color=#b5a642>Bounty Hunter</color>] <color=#b54251>Bounty Hunter License</color> Obtained.\nYou were charged {0}<color=#3e9c35>{1}</color>, Stay Vigilant, <color=#8bb542>{2}</color>!", ["InsufficientFunds"] = "[<color=#b5a642>Bounty Hunter</color>] You don't have enough funds to purchase a <color=#b5a642>Bounty Hunter License</color>.\nIt costs <color=#42b5a6>{0}</color><color=#a642b5>{1}</color>.", ["Despawn"] = "[<color=#b5a642>Bounty Hunter</color>] The <color=#42b5a6>{0}</color> has <color=#b54251>Fled</color> the Island.", ["BountySpotted"] = "[<color=#b5a642>Bounty Hunter</color>]\n\n A <color=#42b5a6>{0}</color> has been spotted near <color=#b56d42>{1}</color>.", ["BountyEliminated"] = "[<color=#b5a642>Bounty Hunter</color>] The <color=#42b5a6>{0}</color> was <color=#b5a642>Eliminated</color> by <color=#8bb542>{1}</color>!", ["BountyDrop"] = "[<color=#b5a642>Bounty Hunter</color>] The <color=#42b5a6>{0}</color> dropped a pouch! Open it and deliver the <color=#42b5a6>Bounty Token</color> to the Bounty Hunter for your Reward!", ["Revoked"] = "[<color=#b5a642>Bounty Hunter</color>] Your <color=#42b5a6>Bounty License</color> has been <color=#42b5a6>Revoked</color> be wary of Death next time!"
            }
            , this);
        }
#endregion
#region rewardhandling
        private void RewardHandler(BasePlayer player, BountyTiers tier, int quantity, int baseSalePrice) {
            double bonusPercentage = Random.Range(tier.MaxDiscount, tier.MaxBonus + 1);
            bonusPercentage = Mathf.Clamp((float)bonusPercentage, -100f, 100f);
            var adjustedSalePrice = baseSalePrice * (1 + bonusPercentage / 100);
            var totalReward = quantity * (int)adjustedSalePrice;
            switch (_config.EconomyPlugin) {
                case 1 : {
                    PayoutEco(player, tier, quantity, totalReward, bonusPercentage);
                    break;
                }
                case 2 : {
                    PayoutSR(player, tier, quantity, totalReward, bonusPercentage);
                    break;
                }
            }
        }
        private void PayoutSR(BasePlayer player, BountyTiers tier, int quantity, int totalReward, double bonusPercentage) {
            ServerRewards.Call("AddPoints", player.UserIDString, totalReward);
            var message = lang.GetMessage("SrMessage", this, player.UserIDString);
            Player.Message(player, string.Format(message, totalReward, quantity, tier.TokenName, bonusPercentage), null, _config.ChatIcon);
            SendSrFx(player);
            SendDiscord(player, tier, quantity, totalReward);
        }
        private void PayoutEco(BasePlayer player, BountyTiers tier, int quantity, int totalReward, double bonusPercentage) {
            Economics.Call("Deposit", player.UserIDString, (double)totalReward);
            var message = lang.GetMessage("EconomicsMessage", this, player.UserIDString);
            Player.Message(player, string.Format(message, totalReward, quantity, tier.TokenName, bonusPercentage), null, _config.ChatIcon);
            SendEcoFx(player);
            SendDiscord(player, tier, quantity, totalReward);
            return;
        }
#endregion
#region bountytiers
        public class BountyTiers {
            [JsonProperty("Tier Name")]
            public string TierName {
                get;
                set;
            }
            [JsonProperty("Skill Tree Xp Value")]
            public double Value {
                get;
                set;
            }
            [JsonProperty("Bounty Kit Enabled?")]
            public bool BountyKitEnabled {
                get;
                set;
            }
            [JsonProperty("Bounty Kit Name?")]
            public string BountyKitName {
                get;
                set;
            }
            = "";
            [JsonProperty("Bounty Clothing Options")]
            public List<BountyClothingOption> BountyClothingOptions {
                get;
                set;
            }
            [JsonProperty("Bounty Total Health")]
            public int BountyHealth {
                get;
                set;
            }
            [JsonProperty("Bounty Damage Scaling")]
            public float BountyDamageOutput {
                get;
                set;
            }
            [JsonProperty("Aim Cone Scale")]
            public float AimConeScale {
                get;
                set;
            }
            [JsonProperty("Weapon to Equip?")]
            public string WeaponName {
                get;
                set;
            }
            [JsonProperty("Weapon Skin ID")]
            public ulong WeaponSkin {
                get;
                set;
            }
            [JsonProperty("Bounty Token Name")]
            public string TokenName {
                get;
                set;
            }
            [JsonProperty("Bounty Token Skin")]
            public ulong TokenSkinID {
                get;
                set;
            }
            [JsonProperty("Is the Token Marketable to the Bounty NPC?")]
            public bool Sellable {
                get;
                set;
            }
            [JsonProperty("Sale Price?")]
            public double SalePrice {
                get;
                set;
            }
            [JsonProperty("Max Discount Buy Variation in %? (Negative Values) (To Simulate Supply & Demand)")]
            public float MaxDiscount {
                get;
                set;
            }
            [JsonProperty("Maximum Bonus Variation in %? (Positive Values) (To Simulate Supply & Demand)")]
            public float MaxBonus {
                get;
                set;
            }
            [JsonProperty("Min Item Drop")]
            public int MinItemDrop {
                get;
                set;
            }
            = 1;
            [JsonProperty("Max Item Drop")]
            public int MaxItemDrop {
                get;
                set;
            }
            = 3;
            [JsonProperty("Bounty Optional Drops")]
            public List<BountyDrops> BountyDropsList {
                get;
                set;
            }
        }
#endregion
#region Declarations
        private int _botCount;
        private Timer spawnTimer;
        private const string AdminPermission = "BountyHunter.Admin";
        private const string LifetimeLicense = "BountyHunter.LifetimeLicense";
        private readonly Dictionary<string, List<Vector3>> _monumentSpawnPoints = new();
        private readonly Dictionary<string, List<Vector3>> _dynamicSpawnPoints = new();
        private Dictionary<string, List<Vector3>> _customSpawnPoints = new();
        private readonly Dictionary<ulong, float> _interactionCooldowns = new();
        private readonly Dictionary<string, BountyTiers> _botTierMap = new();
        private readonly List<ScientistNPC> _spawnedBounties = new();
        private readonly Dictionary<string, Timer> _despawnTimers = new();
        private readonly List<NpcData> _npcDataList = new();
        private readonly List<NPCTalking> _bountyNpCs = new();
        private List<BountyLicense> _playerLicenses = new();
        private Dictionary<ulong, int> _playerData = new();
        private const string CustomSpawn = "CustomSpawn";
        private const string ReloadFx = "assets/prefabs/weapons/grenade launcher/effects/reload_end.prefab";
        private const string DeniedFx = "assets/prefabs/locks/keypad/effects/lock.code.denied.prefab";
        private const string SpawnedFx = "assets/prefabs/deployable/research table/effects/research-success.prefab";
        private const string DespawnedFx = "assets/bundled/prefabs/fx/notice/stack.world.fx.prefab";
        private const string SuccessFx = "assets/prefabs/weapons/spas12/effects/pump_forward.prefab";
        private const string RicochetFx = "assets/bundled/prefabs/fx/ricochet/ricochet2.prefab";
        private const string NoTokensFx = "assets/prefabs/instruments/jerrycanguitar/effects/guitardeploy.prefab";
        private const string Drop = "assets/prefabs/misc/item drop/item_drop_backpack.prefab";
        private const string Npc = "assets/prefabs/npc/bandit/missionproviders/missionprovider_bandit_a.prefab";
        private const string NpcFx = "assets/prefabs/misc/easter/painted eggs/effects/gold_open.prefab";
        private const string RemovalFx = "assets/prefabs/misc/easter/painted eggs/effects/bronze_open.prefab";
        private const string ServerRewardsFx = "assets/prefabs/food/small water bottle/effects/water-bottle-deploy.prefab";
        private const string EconomicsFx = "assets/prefabs/deployable/vendingmachine/effects/vending-machine-purchase-human.prefab";
        private const string DiscordArt = "https://cdn.discordapp.com/attachments/1200248277640163344/1204607519981572126/BOUNTYHUNTERDRAFT.png?ex=65d5592d&is=65c2e42d&hm=1b0dad7de65f6c8bfa798ede2074cdde30572722ba8b1b961d923d16dd6f95f2&";
#endregion
#region Config
        private static Configuration _config;
        public class Configuration {
            [JsonProperty("Announce Top Bounty Hunters To Chat Every x Seconds (0 To Disable)")]
            public int AnnounceInterval {
                get;
                set;
            }
            = 600;
            [JsonProperty("Bounty Prefab Path")]
            public string BountyPrefab {
                get;
                set;
            }
            = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_heavy.prefab";
            [JsonProperty("Discord Webhook URL")]
            public string Webhook {
                get;
                set;
            }
            [JsonProperty("Enable Skill Tree Xp Gain?")]
            public bool EnabledSkillTreeXp {
                get;
                set;
            }
            [JsonProperty("Require License for Xp Gain?")]
            public bool XpLicReq {
                get;
                set;
            }
            [JsonProperty("Enable Monument Spawns?")]
            public bool EnableMonumentSpawns {
                get;
                set;
            }
            [JsonProperty("Enable Custom Spawns?")]
            public bool EnableCustomSpawns {
                get;
                set;
            }
            [JsonProperty("Clear Custom Spawns File On Wipe?")]
            public bool ClearCustomSpawns {
                get;
                set;
            }
            [JsonProperty("Chat Icon")]
            public ulong ChatIcon {
                get;
                set;
            }
            [JsonProperty("Maximum Active Bounties")]
            public int MaxBounties {
                get;
                set;
            }
            [JsonProperty("Drop Bounty Tokens In Pouch?")]
            public bool TokensEnabled {
                get;
                set;
            }
            [JsonProperty("Base Item for the Bounty Tokens?")]
            public string PlaceholderItem {
                get;
                set;
            }
            [JsonProperty("Tokens Marketable to the Bounty NPC?")]
            public bool TokensMarketable {
                get;
                set;
            }
            [JsonProperty("Console Command to Purchase a Bounty License? (For GUI Shops)")]
            public string ConsoleCommand {
                get;
                set;
            }
            = "buybl";
            [JsonProperty("Chat Command to Purchase a Bounty License?")]
            public string ChatCommand {
                get;
                set;
            }
            = "buybl";
            [JsonProperty("Require a Bounty License To Cash In Tokens to the Bounty NPC?")]
            public bool LicenseRequired {
                get;
                set;
            }
            [JsonProperty("Price to Purchase a Bounty License?")]
            public int LicenseFee {
                get;
                set;
            }
            [JsonProperty("Lose Bounty License on Death?")]
            public bool RemoveLicense {
                get;
                set;
            }
            [JsonProperty("Clear Licenses on Wipe?")]
            public bool ClearLicenses {
                get;
                set;
            }
            [JsonProperty("Clear Kill Counters on Wipe?")]
            public bool ClearKills {
                get;
                set;
            }
            [JsonProperty("Dynamic (Bandit Camp) Spawn Of The NPC Enabled?")]
            public bool DynamicSpawn {
                get;
                set;
            }
            = true;
            [JsonProperty("Economy Plugin - 1 Economics - 2 Server Rewards")]
            public int EconomyPlugin {
                get;
                set;
            }
            [JsonProperty("Maximum Amount of Like Tokens Sold at a Time")]
            public int MaxTradeQuantity {
                get;
                set;
            }
            [JsonProperty("NPC Interaction Cooldown In Seconds")]
            public float InteractionCooldown {
                get;
                set;
            }
            [JsonProperty("NPC Kit Enabled?")]
            public bool NpcKitEnabled {
                get;
                set;
            }
            [JsonProperty("NPC Kit Name?")]
            public string NpcKitName {
                get;
                set;
            }
            [JsonProperty("Amount of Time In Seconds Between Bounty Spawns")]
            public int BountySpawnRate {
                get;
                set;
            }
            [JsonProperty("Amount of Time In Seconds for a Bounty to Despawn")]
            public int BountyDespawnTimer {
                get;
                set;
            }
            [JsonProperty("Enable Spawn SFX?")]
            public bool SpawnFX {
                get;
                set;
            }
            = true;
            [JsonProperty("Enable Despawn SFX?")]
            public bool DespawnFX {
                get;
                set;
            }
            = true;
            [JsonProperty("Announce to Chat When Bounty is Active?")]
            public bool AnnounceBountyActive {
                get;
                set;
            }
            [JsonProperty("Announce to Chat When Bounty is Claimed?")]
            public bool AnnounceBountyClaimed {
                get;
                set;
            }
            [JsonProperty("Enable Marker Manager from UMOD, To Mark Bounties?")]
            public bool MarkerEnabled {
                get;
                set;
            }
            [JsonProperty("Enable Marker Manager from UMOD, To Mark NPC Location?")]
            public bool MarkerEnabledForNPC {
                get;
                set;
            }
            = true;
            [JsonProperty("Bounty Tiers")]
            public List<BountyTiers> BountyTiers {
                get;
                set;
            }
            [JsonProperty("NPC Weapon")]
            public string NpcWeapon {
                get;
                set;
            }
            = "rifle.bolt";
            [JsonProperty("NPC Weapon Skin")]
            public ulong NpcWeaponSkin {
                get;
                set;
            }
            = 819149392;
            [JsonProperty("NPC Clothing Options")]
            public List<ClothingOption> NpcClothingOptions {
                get;
                set;
            }
            public static Configuration DefaultConfig() {
                return new Configuration {
                    AnnounceInterval = 600, BountyPrefab = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_heavy.prefab", Webhook = "INSERT_WEBHOOK_URL", EnabledSkillTreeXp = false, XpLicReq = true, EnableMonumentSpawns = true, EnableCustomSpawns = false, ClearCustomSpawns = false, ChatIcon = 0, MaxBounties = 3, TokensEnabled = true, PlaceholderItem = "blood", LicenseRequired = true, LicenseFee = 10000, RemoveLicense = true, ClearLicenses = false, ClearKills = false, DynamicSpawn = true, TokensMarketable = true, ConsoleCommand = "buybl", ChatCommand = "buybl", EconomyPlugin = 1, MaxTradeQuantity = 3, InteractionCooldown = 3f, NpcKitEnabled = false, NpcKitName = "", BountySpawnRate = 600, BountyDespawnTimer = 1200, SpawnFX = true, DespawnFX = true, AnnounceBountyActive = true, AnnounceBountyClaimed = true, MarkerEnabled = true, MarkerEnabledForNPC = true, NpcWeapon = "rifle.bolt", NpcWeaponSkin = 819149392, NpcClothingOptions = new List<ClothingOption> {
                        new() {
                            Shortname = "burlap.trousers", Skin = 1760352876
                        }
                        , new() {
                            Shortname = "burlap.shirt", Skin = 1760350097
                        }
                        , new() {
                            Shortname = "shoes.boots", Skin = 547978997
                        }
                        , new() {
                            Shortname = "hat.boonie", Skin = 3077061771
                        }
                        , new() {
                            Shortname = "burlap.gloves", Skin = 1338273501
                        }
                    }
                    , BountyTiers = new List<BountyTiers> {
                        new() {
                            TierName = "Tier 1 Bounty Target", Value = 100, BountyKitEnabled = false, BountyKitName = "", BountyClothingOptions = new List<BountyClothingOption> {
                                new() {
                                    Shortname = "hazmatsuittwitch", Skin = 0
                                }
                            }
                            , BountyHealth = 150, BountyDamageOutput = 1f, AimConeScale = 2f, WeaponName = "rifle.ak", WeaponSkin = 3140321604, TokenName = "Tier 1 Bounty Token", TokenSkinID = 3155517347, Sellable = true, SalePrice = 1000, MaxDiscount = -10, MaxBonus = 5, MinItemDrop = 1, MaxItemDrop = 3, BountyDropsList = new List<BountyDrops> {
                                new() {
                                    Shortname = "stones", Skin = 0, CustomName = "", AmountMin = 3, AmountMax = 10, ChanceToDrop = 20.0f
                                }
                                , new() {
                                    Shortname = "scrap", Skin = 0, CustomName = "", AmountMin = 5, AmountMax = 30, ChanceToDrop = 30.0f
                                }
                                , new() {
                                    Shortname = "paper", Skin = 3048132587, CustomName = "Cash", AmountMin = 1, AmountMax = 3, ChanceToDrop = 40.0f
                                }
                            }
                        }
                        , new() {
                            TierName = "Tier 2 Bounty Target", Value = 200, BountyKitEnabled = false, BountyKitName = "", BountyClothingOptions = new List<BountyClothingOption> {
                                new() {
                                    Shortname = "hazmatsuit.arcticsuit", Skin = 0
                                }
                            }
                            , BountyHealth = 225, BountyDamageOutput = 1.5f, AimConeScale = 2.5f, WeaponName = "rifle.lr300", WeaponSkin = 2715918380, TokenName = "Tier 2 Bounty Token", TokenSkinID = 3155517539, Sellable = true, SalePrice = 2000, MaxDiscount = -5, MaxBonus = 15, MinItemDrop = 1, MaxItemDrop = 3, BountyDropsList = new List<BountyDrops> {
                                new() {
                                    Shortname = "metal.fragments", Skin = 0, CustomName = "", AmountMin = 200, AmountMax = 500, ChanceToDrop = 30.0f
                                }
                                , new() {
                                    Shortname = "scrap", Skin = 0, CustomName = "", AmountMin = 240, AmountMax = 300, ChanceToDrop = 30.0f
                                }
                                , new() {
                                    Shortname = "paper", Skin = 3048132587, CustomName = "Cash", AmountMin = 10, AmountMax = 15, ChanceToDrop = 40.0f
                                }
                            }
                        }
                        , new() {
                            TierName = "Tier 3 Bounty Target", Value = 300, BountyKitEnabled = false, BountyKitName = "", BountyClothingOptions = new List<BountyClothingOption> {
                                new() {
                                    Shortname = "scientistsuit_heavy", Skin = 0
                                }
                            }
                            , BountyHealth = 325, BountyDamageOutput = 2f, AimConeScale = 3f, WeaponName = "rifle.ak.ice", WeaponSkin = 0, TokenName = "Tier 3 Bounty Token", TokenSkinID = 3155517732, Sellable = true, SalePrice = 3200, MaxDiscount = -3, MaxBonus = 20, MinItemDrop = 1, MaxItemDrop = 3, BountyDropsList = new List<BountyDrops> {
                                new() {
                                    Shortname = "metal.refined", Skin = 0, CustomName = "", AmountMin = 200, AmountMax = 500, ChanceToDrop = 30.0f
                                }
                                , new() {
                                    Shortname = "scrap", Skin = 0, CustomName = "", AmountMin = 440, AmountMax = 600, ChanceToDrop = 30.0f
                                }
                                , new() {
                                    Shortname = "paper", Skin = 3048132587, CustomName = "Cash", AmountMin = 20, AmountMax = 35, ChanceToDrop = 40.0f
                                }
                            }
                        }
                    }
                }
                ;
            }
        }
        protected override void LoadConfig() {
            base.LoadConfig();
            try {
                _config = Config.ReadObject<Configuration>();
                if (_config == null) LoadDefaultConfig();
                SaveConfig();
            }
            catch (Exception e) {
                Debug.LogException(e);
                PrintWarning("Creating new config file.");
                LoadDefaultConfig();
            }
        }
        protected override void LoadDefaultConfig() {
            _config = Configuration.DefaultConfig();
        }
        protected override void SaveConfig() {
            Config.WriteObject(_config);
        }
#endregion
#region npcdatastuff
        public class ClothingOption {
            [JsonProperty("Shortname")]
            public string Shortname {
                get;
                set;
            }
            [JsonProperty("Skin")]
            public ulong Skin {
                get;
                set;
            }
        }
        public class BountyClothingOption {
            [JsonProperty("Shortname")]
            public string Shortname {
                get;
                set;
            }
            [JsonProperty("Skin")]
            public ulong Skin {
                get;
                set;
            }
        }
        public class BountyDrops {
            [JsonProperty("Shortname")]
            public string Shortname {
                get;
                set;
            }
            [JsonProperty("Skin")]
            public ulong Skin {
                get;
                set;
            }
            [JsonProperty("Custom Name")]
            public string CustomName {
                get;
                set;
            }
            [JsonProperty("Amount Min")]
            public int AmountMin {
                get;
                set;
            }
            [JsonProperty("Amount Max")]
            public int AmountMax {
                get;
                set;
            }
            [JsonProperty("Chance to Drop")]
            public float ChanceToDrop {
                get;
                set;
            }
        }
        private class NpcData {
            public string NpcName {
                get;
                set;
            }
            public string ShortPrefabName {
                get;
                set;
            }
            public PositionData Position {
                get;
                set;
            }
            public RotationData Rotation {
                get;
                set;
            }
        }
        public class PositionData {
            public float X, Y, Z;
            public Vector3 ToVector3() {
                return new Vector3(X, Y, Z);
            }
        }
        public class RotationData {
            public float X, Y, Z;
            public RotationData(Vector3 rotation) {
                X = rotation.x;
                Y = rotation.y;
                Z = rotation.z;
            }
            public Vector3 ToVector3() {
                return new Vector3(X, Y, Z);
            }
        }
#endregion
#region data
        private void SaveData() {
            try {
                Interface.Oxide.DataFileSystem.WriteObject("Bounty/Licenses", _playerLicenses);
                Interface.Oxide.DataFileSystem.WriteObject("Bounty/CustomSpawns", _customSpawnPoints);
                Interface.Oxide.DataFileSystem.WriteObject("Bounty/NPCData", new List<NpcData>());
                if (!_config.DynamicSpawn) Interface.Oxide.DataFileSystem.WriteObject("Bounty/NPCData", _npcDataList);
            }
            catch (Exception ex) {
                PrintError($"Error saving data: {ex.Message}");
            }
        }
        private void LoadData() {
            try {
                var loadedNpcData = Interface.Oxide.DataFileSystem.ReadObject<List<NpcData>>("Bounty/NPCData");
                if (loadedNpcData != null) _npcDataList.AddRange(loadedNpcData);
                _playerLicenses = Interface.Oxide.DataFileSystem.ReadObject<List<BountyLicense>>("Bounty/Licenses") ?? new List<BountyLicense>();
                var customSpawns = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<string, List<Vector3>>>("Bounty/CustomSpawns") ?? new Dictionary<string, List<Vector3>>();
                foreach (var pair in customSpawns) _customSpawnPoints[pair.Key] = pair.Value;
            }
            catch (Exception ex) {
                PrintError($"Error loading data: {ex.Message}");
            }
        }
        private void LoadTopKills() {
            var savedData = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<ulong, int>>("Bounty/playerData");
            _playerData = savedData ?? new Dictionary<ulong, int>();
            foreach (var playerId in _playerData.Keys.ToList()) {
                _playerData.TryAdd(playerId, 0);
            }
        }
        private void ClearKills() {
            LoadTopKills();
            _playerData.Clear();
            SaveTopKills();
            Puts("Wipe Detected Clearing Top Kills");
        }
        private void SaveTopKills() {
            Interface.Oxide.DataFileSystem.WriteObject("Bounty/playerData", _playerData);
        }
#endregion
#region markerRemover
        private static bool InRange(Vector3 a, Vector3 b, float distance) {
            return (a - b).sqrMagnitude <= distance * distance;
        }
        private void OnEntitySpawned(MapMarkerMissionProvider marker) {
            timer.Once (1f, () => {
                if (marker == null || marker.IsDestroyed) return;
                if (_bountyNpCs == null || _bountyNpCs.Count == 0) return;
                foreach (var npc in _bountyNpCs) {
                    if (npc == null || npc.transform == null || marker.transform == null) continue;
                    if (InRange(npc.transform.position, marker.transform.position, 0.1f)) {
                        NextTick(() => marker?.Kill());
                    }
                }
            }
            );
        }
#endregion
#region hooks
        private object OnEntityTakeDamage(BaseEntity entity, HitInfo info) {
            if (entity == null || info?.Initiator == null) {
                return null;
            }
            if (_bountyNpCs.Contains(entity)) {
                // Blocks NPCs from being damaged
                return false;
            }
            return null;
        }
        private object OnNpcKits(NPCTalking npc) {
            return _bountyNpCs.Contains(npc) ? true : null;
        }
        private void OnPlayerSleepEnded(BasePlayer player) {
            if (!permission.UserHasPermission(player.UserIDString, LifetimeLicense)) return;
            if (!HasBountyLicense(player.userID)) GiveLicense(player.userID);
        }
        private void OnServerInitialized(bool initial) {
            RegisterCommands();
            RegisterPerms();
            if (_config.EnableMonumentSpawns) LoadMonumentSpawnPoints();
            LoadCustomSpawnPoints();
            LoadDynamicSpawnPoints();
            LoadData();
            CheckDependencies(initial);
            CheckST();
            StartSpawnTimer();
            LoadTopKills();
            CheckAnnounce();
        }
        private void RegisterCommands() {
            var consoleCommand = _config.ConsoleCommand;
            var chatCommand = _config.ChatCommand;
            cmd.AddConsoleCommand(consoleCommand, this, nameof(BuyBLCcmd));
            cmd.AddChatCommand(chatCommand, this, nameof(BuyBountyLicCmd));
        }
        private void RegisterPerms() {
            permission.RegisterPermission(AdminPermission, this);
            permission.RegisterPermission(LifetimeLicense, this);
        }
        private void CheckDependencies(bool initial) {
            if (initial) {
                timer.Once(6f, SpawnNpCsFromData);
                timer.Once(7f, CheckPlugin);
            }
            else {
                SpawnNpCsFromData();
                CheckPlugin();
            }
        }
        private void CheckAnnounce() {
            if (_config.AnnounceInterval > 0) {
                timer.Repeat(_config.AnnounceInterval, 0, () => AnnounceTop());
            }
        }
        private void CheckST() {
            if (_config.EnabledSkillTreeXp) {
                Subscribe("STCanGainXP");
            }
        }
        private void OnNewSave(string filename) {
            LoadData();
            ClearNpcData();
            Puts("Wipe Detected, Removing Bounty Hunter NPCs.");
            if (_config.ClearLicenses) ClearPlayerLicenses();
            if (_config.ClearCustomSpawns) ClearCustomSpawnPoints();
            if (_config.ClearKills) ClearKills();
        }
        private void ClearNpcData() {
            _npcDataList.Clear();
            SaveData();
        }
        private void ClearPlayerLicenses() {
            _playerLicenses.Clear();
            Interface.Oxide.DataFileSystem.WriteObject("Bounty/Licenses", _playerLicenses);
            SaveData();
            Puts("Clearing Bounty Hunter Licenses.");
        }
        private void ClearCustomSpawnPoints() {
            _customSpawnPoints.Clear();
            Interface.Oxide.DataFileSystem.WriteObject("Bounty/CustomSpawns", _customSpawnPoints);
            SaveData();
            Puts("Clearing Bounty Hunter Custom Spawns.");
        }
        private void OnPlayerDeath(BasePlayer player, HitInfo info, string tierName, ScientistNPC bounty) {
            try {
                if (info.Initiator.IsNpc) return;
                var attacker = info.Initiator as BasePlayer;
                if (attacker == null || !player.name.StartsWith("Bounty_")) return;
                RemoveMarker(player.name);
                var pos = player.transform.position + new Vector3(0f, 2f, 0f);
                var container = GameManager.server.CreateEntity(Drop, pos) as DroppedItemContainer;
                if (container == null) return;
                if (container.inventory != null) return;
                if (container.inventory == null) {
                    container.inventory = new ItemContainer();
                    container.inventory.ServerInitialize(null, 36);
                    container.inventory.SetFlag(ItemContainer.Flag.NoItemInput, true);
                }
                var playerID = player.UserIDString;
                if (_botTierMap.TryGetValue(playerID, out var selectedBountyTier)) {
                    var bountyDropsList = selectedBountyTier.BountyDropsList;
                    ShuffleList(bountyDropsList);
                    var lootcount = Random.Range(selectedBountyTier.MinItemDrop, selectedBountyTier.MaxItemDrop);
                    //Puts("lootcount" + lootcount);
                    for (var i = 0; i < lootcount;) {
                        var entry = bountyDropsList[Random.Range(0, bountyDropsList.Count)];
                        var chance = Random.Range(0f, 100f);
                        if (chance > entry.ChanceToDrop) {
                            continue;
                        }
                        var amount = Random.Range(entry.AmountMin, entry.AmountMax);
                        var item = ItemManager.CreateByName(entry.Shortname, amount, entry.Skin);
                        if (!string.IsNullOrEmpty(entry.CustomName)) {
                            item.name = entry.CustomName;
                        }
                        container.inventory.GiveItem(item);
                        i++;
                        // Puts("giving item" + item.name);
                    }
                }
                if (selectedBountyTier != null && _config.TokensEnabled) {
                    var bountyClaim = ItemManager.CreateByName(_config.PlaceholderItem, 1, selectedBountyTier.TokenSkinID);
                    bountyClaim.name = selectedBountyTier.TokenName;
                    container.inventory.GiveItem(bountyClaim);
                }
                container.inventory.MarkDirty();
                container.Spawn();
                container.name = $"{attacker.displayName} Bounty Drop";
                container.SendNetworkUpdateImmediate();
                _botCount--;
                if (_botCount == 0) Interface.CallHook("OnBountyInactive");
                _spawnedBounties.Remove(bounty);
                foreach (var pair in _despawnTimers.ToList().Where(pair => pair.Key != null && pair.Key == player.UserIDString)) {
                    pair.Value.Destroy();
                    _despawnTimers.Remove(pair.Key);
                    break;
                }
                _playerData.TryAdd(attacker.userID, 0);
                _playerData[attacker.userID]++;
                SaveTopKills();
                //Adding Kills to the tally
                var elimMessage = lang.GetMessage("BountyEliminated", this);
                if (selectedBountyTier == null) return;
                var bountyName = selectedBountyTier.TierName;
                var attackerName = attacker.displayName;
                timer.Repeat(0.3f, 5, () => Effect.server.Run(RicochetFx, pos));
                var message = lang.GetMessage("BountyDrop", this);
                if (_config.TokensEnabled) attacker.SendMessage(message, bountyName);
                if (_config.AnnounceBountyClaimed) Server.Broadcast(string.Format(elimMessage, bountyName, attackerName), null, _config.ChatIcon);
                if (!SkillTree || !_config.EnabledSkillTreeXp) return;
                if (_config.XpLicReq && !HasBountyLicense(attacker.userID) && !permission.UserHasPermission(attacker.UserIDString, LifetimeLicense)) return;
                AwardXp(attacker, selectedBountyTier);
            }
            catch (Exception ex) {
                //Debug.LogError;
            }
        }
        private void AwardXp(BasePlayer player, BountyTiers tier) {
            if (tier.Value == 0) return;
            timer.Once (2f, () => {
                SkillTree?.Call("AwardXP", player, tier.Value);
                player.ChatMessage("[<color=#b5a642>Bounty Hunter</color>] You gained <color=#b5a642>" + tier.Value + "</color> <color=#42b5a6>Xp</color> for the <color=#b5a642>Bounty</color> Takedown.");
                CommandSuccess(player);
            }
            );
        }
        private object CanLootEntity(BasePlayer player, DroppedItemContainer container) {
            if (!container.name.Contains("Bounty Drop")) return null;
            var attackerName = container.name.Replace(" Bounty Drop", "");
            if (player.displayName == attackerName) return null;
            return false;
        }
        private object OnNpcConversationStart(NPCTalking npcTalking, BasePlayer player, ConversationData conversationData) {
            if (!_bountyNpCs.Contains(npcTalking)) return null;
            if (!_config.TokensMarketable) {
                var salesdisabled = lang.GetMessage("SaleDisabled", this, player.UserIDString);
                Player.Message(player, string.Format(salesdisabled), null, _config.ChatIcon);
                DeniedFX(player);
                return false;
                //returning false to prevent any dialogue built into the prefab npc
            }
            if (_config.LicenseRequired && !HasBountyLicense(player.userID)) {
                var noLicenseMessage = lang.GetMessage("NoBountyHunterLicense", this, player.UserIDString);
                Player.Message(player, string.Format(noLicenseMessage), null, _config.ChatIcon);
                CommandSuccess(player);
                return false;
            }
            if (!_bountyNpCs.Contains(npcTalking)) return null;
            if (_interactionCooldowns.ContainsKey(player.userID) && Time.realtimeSinceStartup < _interactionCooldowns[player.userID]) {
                var remainingCooldown = _interactionCooldowns[player.userID] - Time.realtimeSinceStartup;
                var cooldownMessage = lang.GetMessage("BountyHunterCooldownMessage", this, player.UserIDString);
                Player.Message(player, string.Format(cooldownMessage, (int)Math.Ceiling(remainingCooldown)), null, _config.ChatIcon);
                DeniedFX(player);
                return true;
            }
            _interactionCooldowns[player.userID] = Time.realtimeSinceStartup + _config.InteractionCooldown;
            HandleBountyTrade(player);
            return true;
        }
        private void Unload() {
            ClearTimers();
            ClearBounties();
            ClearBountyNPCs();
            SaveData();
            SaveTopKills();
            Unsubscribe("STCanGainXP");
        }
        private void ClearTimers() {
            spawnTimer?.Destroy();
        }
#endregion
#region tradehandler
        private void HandleBountyTrade(BasePlayer player) {
            foreach (var tokens in _config.BountyTiers) if (tokens.Sellable) if (PlayerHasTokens(player, tokens)) {
                var quantity = GetTotalTokenQuantity(player, tokens);
                if (quantity > _config.MaxTradeQuantity) quantity = _config.MaxTradeQuantity;
                RemoveTokensFromPlayer(player, tokens, quantity);
                var salePriceInt = (int)tokens.SalePrice;
                RewardHandler(player, tokens, quantity, salePriceInt);
                return;
            }
            var noTokens = lang.GetMessage("NoTokens", this, player.UserIDString);
            Player.Message(player, string.Format(noTokens), null, _config.ChatIcon);
            EffectNetwork.Send(new Effect(NoTokensFx, player.transform.position, player.transform.position), player.net.connection);
        }
        private void RemoveTokensFromPlayer(BasePlayer player, BountyTiers token, int quantity) {
            foreach (var item in player.inventory.containerMain.itemList.ToList()) if (IsToken(item, token)) {
                var itemsToRemove = Mathf.Min(item.amount, quantity);
                if (item.amount > itemsToRemove) {
                    item.amount -= itemsToRemove;
                    item.MarkDirty();
                    player.SendNetworkUpdateImmediate();
                }
                else {
                    item.RemoveFromContainer();
                    item.Remove();
                }
                quantity -= itemsToRemove;
                if (quantity <= 0) return;
            }
            foreach (var item in player.inventory.containerBelt.itemList.ToList()) if (IsToken(item, token)) {
                var itemsToRemove = Mathf.Min(item.amount, quantity);
                if (item.amount > itemsToRemove) {
                    item.amount -= itemsToRemove;
                    item.MarkDirty();
                    player.SendNetworkUpdateImmediate();
                }
                else {
                    item.RemoveFromContainer();
                    item.Remove();
                }
                quantity -= itemsToRemove;
                if (quantity <= 0) return;
            }
        }
        private int GetTotalTokenQuantity(BasePlayer player, BountyTiers token) {
            return player.inventory.containerMain.itemList.Concat(player.inventory.containerBelt.itemList).Where(item => IsToken(item, token)).Sum(item => item.amount);
        }
        private bool PlayerHasTokens(BasePlayer player, BountyTiers token) {
            return player.inventory.containerMain.itemList.Concat(player.inventory.containerBelt.itemList).Any(item => IsToken(item, token));
        }
        private bool IsToken(Item item, BountyTiers token) {
            return item.skin == token.TokenSkinID;
        }
#endregion
#region helpers
        void ShuffleList<T>(List<T> list) {
            for (var i = list.Count - 1; i > 0; i--) {
                var randomIndex = Random.Range(0, i + 1);
                (list[i], list[randomIndex]) = (list[randomIndex], list[i]);
            }
        }
        private void SpawnNpCsFromData() {
            if (_config.DynamicSpawn) {
                SpawnNpcsDynamically();
            }
            else {
                var npcDataCopy = Pool.Get<List<NpcData>>();
                npcDataCopy.AddRange(_npcDataList);
                foreach (var npcData in npcDataCopy) {
                    var spawnPosition = npcData.Position.ToVector3();
                    var npcRotation = npcData.Rotation.ToVector3();
                    var spawnRotation = Quaternion.Euler(npcRotation);
                    RespawnBountyNpc(ref spawnPosition, ref spawnRotation, npcData.NpcName, _npcDataList);
                }
                Pool.FreeUnmanaged(ref npcDataCopy);
            }
        }
        private void RespawnBountyNpc(ref Vector3 position, ref Quaternion rotation, string oldNpcName, List<NpcData> npcDataList) {
            if (!Economics && !ServerRewards) return;
            var oldNpcData = npcDataList.Find(data => data.NpcName == oldNpcName);
            if (oldNpcData == null) return;
            var npc = GameManager.server.CreateEntity(Npc, position, rotation) as NPCTalking;
            if (npc == null) return;
            npc.loadouts = Array.Empty<PlayerInventoryProperties>();
            var colliders = Physics.OverlapSphere(position, 1.0f);
            foreach (var collider in colliders) {
                var nearbyNpc = collider.GetComponent<NPCTalking>();
                if (nearbyNpc != null && nearbyNpc.PrefabName == Npc) nearbyNpc.Kill();
            }
            npc.Spawn();
            npc.enableSaving = false;
            npc.gameObject.name = oldNpcName;
            _bountyNpCs.Add(npc);
            if (_config.NpcKitEnabled && !string.IsNullOrEmpty(_config.NpcKitName)) {
                Kits?.Call("GiveKit", npc, _config.NpcKitName);
            }
            else {
                foreach (var clothingOption in _config.NpcClothingOptions) {
                    var clothingItemDef = ItemManager.FindItemDefinition(clothingOption.Shortname);
                    if (clothingItemDef == null) continue;
                    var clothingItem = ItemManager.Create(clothingItemDef);
                    if (clothingOption.Skin != 0) {
                        clothingItem.skin = clothingOption.Skin;
                        clothingItem.MarkDirty();
                    }
                    if (clothingItem.MoveToContainer(npc.inventory.containerWear)) {
                        // Puts("BountyHunter Outfit Complete");
                    }
                    else {
                        clothingItem.Remove();
                    }
                }
                var npcWeapon = _config.NpcWeapo
// ... [Code preview truncated due to length. Full source in attached file] ...

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