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

FREE BetterNpc : 1.1.8 1.1.8

Нет прав для скачивания
C#:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Plugins;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
using Oxide.Plugins.BetterNpcExtensionMethods;
namespace Oxide.Plugins {
    [Info("BetterNpc", "KpucTaJl", "1.1.8")]
    internal class BetterNpc : RustPlugin {
#region Config
        private const bool En = true;
        private PluginConfig _config;
        protected override void LoadDefaultConfig() {
            Puts("Creating a default config...");
            _config = PluginConfig.DefaultConfig();
            _config.PluginVersion = Version;
            SaveConfig();
            Puts("Creation of the default config completed!");
        }
        protected override void LoadConfig() {
            base.LoadConfig();
            _config = Config.ReadObject<PluginConfig>();
            if (_config.PluginVersion < Version) UpdateConfigValues();
        }
        private void UpdateConfigValues() {
            Puts("Config update detected! Updating config values...");
            if (_config.PluginVersion < new VersionNumber(1, 0, 9)) {
                _config.UnderwaterSpawnPoints = new HashSet<string> {
                    "Military Tunnel", "module_900x900_2way_moonpool", "moonpool_1200x1500_1way", "moonpool_1200x1500_2way", "moonpool_1200x1500_3way", "moonpool_1200x1800_ladder", "module_1200x1200_1way", "module_1200x1200_1way_ladder", "module_1200x1200_3way", "module_1200x1200_3way_ladder", "module_1200x1200_4way", "module_1200x1200_4way_ladder", "module_1200x1800_2way", "module_1200x600_2way_corridor", "module_1500x1500_4way_lshaped", "module_1500x1500_ladder", "module_1500x1800_2way_ladder", "module_1500x600_2way_corridor", "module_1800x1800_4way_lshaped", "module_2100x600_3way_corridor", "module_900x900_1way", "module_900x900_1way_ladder", "module_900x900_3way", "module_900x900_3way_ladder", "module_900x900_4way", "module_900x900_4way_ladder"
                }
                ;
                _config.SafeZoneRange = 150f;
            }
            if (_config.PluginVersion < new VersionNumber(1, 1, 2)) {
                HashSet<string> names = new HashSet<string> {
                    "curve-ne-0", "curve-ne-1", "curve-nw-0", "curve-nw-1", "curve-se-0", "curve-se-1", "curve-sw-0", "curve-sw-1", "intersection", "intersection-e", "intersection-n", "intersection-s", "intersection-w", "station-sn-0", "station-sn-1", "station-sn-2", "station-sn-3", "station-we-0", "station-we-1", "station-we-2", "station-we-3", "straight-sn-0", "straight-sn-1", "straight-sn-2", "straight-sn-3", "straight-sn-4", "straight-sn-5", "straight-we-0", "straight-we-1", "straight-we-2", "straight-we-3", "straight-we-4", "straight-we-5"
                }
                ;
                foreach (string name in names) _config.UnderwaterSpawnPoints.Add(name);
            }
            if (_config.PluginVersion < new VersionNumber(1, 1, 7)) {
                _config.OtherNpc = new HashSet<string> {
                    "NpcRaider", "RandomRaider"
                }
                ;
            }
            if (_config.PluginVersion < new VersionNumber(1, 1, 8)) {
                if (!_config.OtherNpc.Contains("56485621526987")) _config.OtherNpc.Add("56485621526987");
            }
            _config.PluginVersion = Version;
            Puts("Config update completed!");
            SaveConfig();
        }
        protected override void SaveConfig() => Config.WriteObject(_config);
        public class ItemConfig {
            [JsonProperty("ShortName")]
            public string ShortName {
                get;
                set;
            }
            [JsonProperty(En ? "Minimum" : "Минимальное кол-во")]
            public int MinAmount {
                get;
                set;
            }
            [JsonProperty(En ? "Maximum" : "Максимальное кол-во")]
            public int MaxAmount {
                get;
                set;
            }
            [JsonProperty(En ? "Chance [0.0-100.0]" : "Шанс выпадения предмета [0.0-100.0]")]
            public float Chance {
                get;
                set;
            }
            [JsonProperty(En ? "Is this a blueprint? [true/false]" : "Это чертеж? [true/false]")]
            public bool IsBluePrint {
                get;
                set;
            }
            [JsonProperty("SkinID (0 - default)")]
            public ulong SkinID {
                get;
                set;
            }
            [JsonProperty(En ? "Name (empty - default)" : "Название (empty - default)")]
            public string Name {
                get;
                set;
            }
        }
        public class LootTableConfig {
            [JsonProperty(En ? "Minimum numbers of items" : "Минимальное кол-во элементов")]
            public int Min {
                get;
                set;
            }
            [JsonProperty(En ? "Maximum numbers of items" : "Максимальное кол-во элементов")]
            public int Max {
                get;
                set;
            }
            [JsonProperty(En ? "Use minimum and maximum values? [true/false]" : "Использовать минимальное и максимальное значение? [true/false]")]
            public bool UseCount {
                get;
                set;
            }
            [JsonProperty(En ? "List of items" : "Список предметов")]
            public List<ItemConfig> Items {
                get;
                set;
            }
        }
        public class PrefabConfig {
            [JsonProperty(En ? "Chance [0.0-100.0]" : "Шанс выпадения [0.0-100.0]")]
            public float Chance {
                get;
                set;
            }
            [JsonProperty(En ? "The path to the prefab" : "Путь к prefab-у")]
            public string PrefabDefinition {
                get;
                set;
            }
        }
        public class PrefabLootTableConfig {
            [JsonProperty(En ? "Minimum numbers of prefabs" : "Минимальное кол-во prefab-ов")]
            public int Min {
                get;
                set;
            }
            [JsonProperty(En ? "Maximum numbers of prefabs" : "Максимальное кол-во prefab-ов")]
            public int Max {
                get;
                set;
            }
            [JsonProperty(En ? "Use minimum and maximum values? [true/false]" : "Использовать минимальное и максимальное значение? [true/false]")]
            public bool UseCount {
                get;
                set;
            }
            [JsonProperty(En ? "List of prefabs" : "Список prefab-ов")]
            public List<PrefabConfig> Prefabs {
                get;
                set;
            }
        }
        public class NpcBelt {
            [JsonProperty("ShortName")]
            public string ShortName {
                get;
                set;
            }
            [JsonProperty(En ? "Amount" : "Кол-во")]
            public int Amount {
                get;
                set;
            }
            [JsonProperty("SkinID (0 - default)")]
            public ulong SkinID {
                get;
                set;
            }
            [JsonProperty(En ? "Mods" : "Модификации на оружие")]
            public List<string> Mods {
                get;
                set;
            }
            [JsonProperty(En ? "Ammo" : "Боеприпасы")]
            public string Ammo {
                get;
                set;
            }
        }
        public class NpcWear {
            [JsonProperty("ShortName")]
            public string ShortName {
                get;
                set;
            }
            [JsonProperty("SkinID (0 - default)")]
            public ulong SkinID {
                get;
                set;
            }
        }
        public class NpcEconomic {
            [JsonProperty("Economics")]
            public double Economics {
                get;
                set;
            }
            [JsonProperty(En ? "Server Rewards (minimum 1)" : "Server Rewards (минимум 1)")]
            public int ServerRewards {
                get;
                set;
            }
            [JsonProperty(En ? "IQEconomic (minimum 1)" : "IQEconomic (минимум 1)")]
            public int IQEconomic {
                get;
                set;
            }
        }
        public class NpcConfig {
            [JsonProperty(En ? "Names" : "Названия")]
            public List<string> Names {
                get;
                set;
            }
            [JsonProperty(En ? "Health" : "Кол-во ХП")]
            public float Health {
                get;
                set;
            }
            [JsonProperty(En ? "Roam Range" : "Дальность патрулирования местности")]
            public float RoamRange {
                get;
                set;
            }
            [JsonProperty(En ? "Chase Range" : "Дальность погони за целью")]
            public float ChaseRange {
                get;
                set;
            }
            [JsonProperty(En ? "Attack Range Multiplier" : "Множитель радиуса атаки")]
            public float AttackRangeMultiplier {
                get;
                set;
            }
            [JsonProperty(En ? "Sense Range" : "Радиус обнаружения цели")]
            public float SenseRange {
                get;
                set;
            }
            [JsonProperty(En ? "Target Memory Duration [sec.]" : "Длительность памяти цели [sec.]")]
            public float MemoryDuration {
                get;
                set;
            }
            [JsonProperty(En ? "Scale damage" : "Множитель урона")]
            public float DamageScale {
                get;
                set;
            }
            [JsonProperty(En ? "Aim Cone Scale" : "Множитель разброса")]
            public float AimConeScale {
                get;
                set;
            }
            [JsonProperty(En ? "Detect the target only in the NPC's viewing vision cone? [true/false]" : "Обнаруживать цель только в углу обзора NPC? [true/false]")]
            public bool CheckVisionCone {
                get;
                set;
            }
            [JsonProperty(En ? "Vision Cone" : "Угол обзора")]
            public float VisionCone {
                get;
                set;
            }
            [JsonProperty(En ? "Speed" : "Скорость")]
            public float Speed {
                get;
                set;
            }
            [JsonProperty(En ? "Minimum time of appearance after death (not used for Events) [sec.]" : "Минимальное время появления после смерти (не используется для Events) [sec.]")]
            public float MinTime {
                get;
                set;
            }
            [JsonProperty(En ? "Maximum time of appearance after death (not used for Events) [sec.]" : "Максимальное время появления после смерти (не используется для Events) [sec.]")]
            public float MaxTime {
                get;
                set;
            }
            [JsonProperty(En ? "Disable radio effects? [true/false]" : "Отключать эффекты рации? [true/false]")]
            public bool DisableRadio {
                get;
                set;
            }
            [JsonProperty(En ? "Is this a stationary NPC? [true/false]" : "Это стационарный NPC? [true/false]")]
            public bool Stationary {
                get;
                set;
            }
            [JsonProperty(En ? "Remove a corpse after death? (it is recommended to use the true value to improve performance) [true/false]" : "Удалять труп после смерти? (рекомендуется использовать значение true для повышения производительности) [true/false]")]
            public bool IsRemoveCorpse {
                get;
                set;
            }
            [JsonProperty(En ? "Wear items" : "Одежда")]
            public List<NpcWear> WearItems {
                get;
                set;
            }
            [JsonProperty(En ? "Belt items" : "Быстрые слоты")]
            public List<NpcBelt> BeltItems {
                get;
                set;
            }
            [JsonProperty(En ? "Kits (it is recommended to use the previous 2 settings to improve performance)" : "Kits (рекомендуется использовать предыдущие 2 пункта настройки для повышения производительности)")]
            public List<string> Kits {
                get;
                set;
            }
        }
        public class PresetConfig {
            [JsonProperty(En ? "Enabled? [true/false]" : "Включен? [true/false]")]
            public bool Enabled {
                get;
                set;
            }
            [JsonProperty(En ? "Minimum numbers - Day" : "Минимальное кол-во днем")]
            public int MinDay {
                get;
                set;
            }
            [JsonProperty(En ? "Maximum numbers - Day" : "Максимальное кол-во днем")]
            public int MaxDay {
                get;
                set;
            }
            [JsonProperty(En ? "Minimum numbers - Night" : "Минимальное кол-во ночью")]
            public int MinNight {
                get;
                set;
            }
            [JsonProperty(En ? "Maximum numbers - Night" : "Максимальное кол-во ночью")]
            public int MaxNight {
                get;
                set;
            }
            [JsonProperty(En ? "NPCs setting" : "Настройки NPC")]
            public NpcConfig Config {
                get;
                set;
            }
            [JsonProperty(En ? "The amount of economics that is given for killing the NPC" : "Кол-во экономики, которое выдается за убийство NPC")]
            public NpcEconomic Economic {
                get;
                set;
            }
            [JsonProperty(En ? "Type of appearance (0 - random; 1 - own list) (not used for Road and Biome)" : "Тип появления (0 - рандомное; 1 - собственный список) (не используется для Road и Biome)")]
            public int TypeSpawn {
                get;
                set;
            }
            [JsonProperty(En ? "Own list of locations (not used for Road and Biome)" : "Собственный список расположений (не используется для Road и Biome)")]
            public List<string> OwnPositions {
                get;
                set;
            }
            [JsonProperty(En ? "The path to the crate that appears at the place of death (empty - not used)" : "Путь к ящику, который появляется на месте смерти (empty - not used)")]
            public string CratePrefab {
                get;
                set;
            }
            [JsonProperty(En ? "Which loot table should the plugin use? (0 - default; 1 - own; 2 - AlphaLoot; 3 - CustomLoot; 4 - loot table of the Rust objects; 5 - combine the 1 and 4 methods)" : "Какую таблицу предметов необходимо использовать? (0 - стандартную; 1 - собственную; 2 - AlphaLoot; 3 - CustomLoot; 4 - таблица предметов объектов Rust; 5 - совместить 1 и 4 методы)")]
            public int TypeLootTable {
                get;
                set;
            }
            [JsonProperty(En ? "Loot table from prefabs (if the loot table type is 4 or 5)" : "Таблица предметов из prefab-ов (если тип таблицы предметов - 4 или 5)")]
            public PrefabLootTableConfig PrefabLootTable {
                get;
                set;
            }
            [JsonProperty(En ? "Own loot table (if the loot table type is 1 or 5)" : "Собственная таблица предметов (если тип таблицы предметов - 1 или 5)")]
            public LootTableConfig OwnLootTable {
                get;
                set;
            }
        }
        private class PluginConfig {
            [JsonProperty(En ? "Start time of the day" : "Время начала дня")]
            public string StartDayTime {
                get;
                set;
            }
            [JsonProperty(En ? "Start time of the night" : "Время начала ночи")]
            public string StartNightTime {
                get;
                set;
            }
            [JsonProperty(En ? "Use the PVE mode of the plugin? (only for users PveMode plugin)" : "Использовать PVE режим работы плагина? (только для тех, кто использует плагин PveMode)")]
            public bool Pve {
                get;
                set;
            }
            [JsonProperty(En ? "List of spawn points for the appearance of NPCs that are under water" : "Список точек для появления NPC, которые находятся под водой")]
            public HashSet<string> UnderwaterSpawnPoints {
                get;
                set;
            }
            [JsonProperty(En ? "The distance from the center of the safe zone to the nearest place where the NPC appears [m.]" : "Расстояние от центра безопасной зоны до ближайшего места появления NPC [m.]")]
            public float SafeZoneRange {
                get;
                set;
            }
            [JsonProperty(En ? "List of Npc types that should not be deleted" : "Список типов Npc, которые не должны удаляться")]
            public HashSet<string> OtherNpc {
                get;
                set;
            }
            [JsonProperty(En ? "Configuration version" : "Версия конфигурации")]
            public VersionNumber PluginVersion {
                get;
                set;
            }
            public static PluginConfig DefaultConfig() {
                return new PluginConfig() {
                    StartDayTime = "8:00", StartNightTime = "20:00", Pve = false, UnderwaterSpawnPoints = new HashSet<string> {
                        "Military Tunnel", "module_900x900_2way_moonpool", "moonpool_1200x1500_1way", "moonpool_1200x1500_2way", "moonpool_1200x1500_3way", "moonpool_1200x1800_ladder", "module_1200x1200_1way", "module_1200x1200_1way_ladder", "module_1200x1200_3way", "module_1200x1200_3way_ladder", "module_1200x1200_4way", "module_1200x1200_4way_ladder", "module_1200x1800_2way", "module_1200x600_2way_corridor", "module_1500x1500_4way_lshaped", "module_1500x1500_ladder", "module_1500x1800_2way_ladder", "module_1500x600_2way_corridor", "module_1800x1800_4way_lshaped", "module_2100x600_3way_corridor", "module_900x900_1way", "module_900x900_1way_ladder", "module_900x900_3way", "module_900x900_3way_ladder", "module_900x900_4way", "module_900x900_4way_ladder", "curve-ne-0", "curve-ne-1", "curve-nw-0", "curve-nw-1", "curve-se-0", "curve-se-1", "curve-sw-0", "curve-sw-1", "intersection", "intersection-e", "intersection-n", "intersection-s", "intersection-w", "station-sn-0", "station-sn-1", "station-sn-2", "station-sn-3", "station-we-0", "station-we-1", "station-we-2", "station-we-3", "straight-sn-0", "straight-sn-1", "straight-sn-2", "straight-sn-3", "straight-sn-4", "straight-sn-5", "straight-we-0", "straight-we-1", "straight-we-2", "straight-we-3", "straight-we-4", "straight-we-5"
                    }
                    , SafeZoneRange = 150f, OtherNpc = new HashSet<string> {
                        "NpcRaider", "RandomRaider", "56485621526987"
                    }
                    , PluginVersion = new VersionNumber()
                }
                ;
            }
        }
#endregion Config
#region Oxide Hooks
        [PluginReference]
        private readonly Plugin NpcSpawn, PveMode;
        private static BetterNpc _ins;
        private void Init() => _ins = this;
        private void OnServerInitialized() {
            if (!plugins.Exists("NpcSpawn")) {
                PrintError("NpcSpawn plugin doesn`t exist! Please read the file ReadMe.txt");
                NextTick(() => Interface.Oxide.UnloadPlugin(Name));
                return;
            }
            _isDay = TOD_Sky.Instance.Cycle.Hour < TimeSpan.Parse(_config.StartNightTime).TotalHours && TOD_Sky.Instance.Cycle.Hour > TimeSpan.Parse(_config.StartDayTime).TotalHours;
            _loadCoroutine = ServerMgr.Instance.StartCoroutine(LoadAllFiles());
        }
        private void Unload() {
            if (_loadCoroutine != null) ServerMgr.Instance.StopCoroutine(_loadCoroutine);
            if (_checkDayCoroutine != null) ServerMgr.Instance.StopCoroutine(_checkDayCoroutine);
            foreach (ControllerSpawnPoint controller in _controllers) if (controller != null) UnityEngine.Object.Destroy(controller.gameObject);
            _ins = null;
        }
        private void OnCorpsePopulate(ScientistNPC entity, NPCPlayerCorpse corpse) {
            if (entity == null || corpse == null) return;
            ControllerSpawnPoint controller = _controllers.FirstOrDefault(x => x.ActiveNpc.Any(y => y.Npc == entity));
            if (controller != null) controller.DieNpc(entity, corpse);
        }
        private void OnEntitySpawned(NPCPlayer npc) {
            ControllerSpawnPoint controller = _controllers.FirstOrDefault(s => s.RemoveOtherNpc && Vector3.Distance(s.transform.position, npc.transform.position) < (s.Size.x > s.Size.y ? s.Size.x : s.Size.y) * 2f && s.IsOtherNpc(npc));
            if (controller != null) NextTick(() => {
                if (npc.IsExists()) npc.Kill();
            }
            );
        }
#endregion Oxide Hooks
#region Day or Night
        private Coroutine _checkDayCoroutine = null;
        private bool _isDay;
        private IEnumerator CheckDay() {
            while (true) {
                if (_isDay) {
                    if (TOD_Sky.Instance.Cycle.Hour > TimeSpan.Parse(_config.StartNightTime).TotalHours || TOD_Sky.Instance.Cycle.Hour < TimeSpan.Parse(_config.StartDayTime).TotalHours) {
                        _isDay = false;
                        foreach (ControllerSpawnPoint controller in _controllers) controller.SetDay(_isDay);
                    }
                }
                else {
                    if (TOD_Sky.Instance.Cycle.Hour < TimeSpan.Parse(_config.StartNightTime).TotalHours && TOD_Sky.Instance.Cycle.Hour > TimeSpan.Parse(_config.StartDayTime).TotalHours) {
                        _isDay = true;
                        foreach (ControllerSpawnPoint controller in _controllers) controller.SetDay(_isDay);
                    }
                }
                yield return CoroutineEx.waitForSeconds(30f);
            }
        }
#endregion Day or Night
#region Controller
        private readonly HashSet<ControllerSpawnPoint> _controllers = new HashSet<ControllerSpawnPoint>();
        internal class ControllerSpawnPoint : FacepunchBehaviour {
            internal string Name;
            internal bool IsEvent;
            internal bool RemoveOtherNpc;
            internal Vector2 Size;
            internal List<PresetConfig> Presets;
            internal bool IsDay;
            internal HashSet<ActiveScientistNpc> ActiveNpc = new HashSet<ActiveScientistNpc>();
            private readonly HashSet<DeadScientistNpc> DeadNpc = new HashSet<DeadScientistNpc>();
            private int GetAmountPreset(PresetConfig preset) => ActiveNpc.Where(x => x.Preset == preset).Count + DeadNpc.Where(x => x.Preset == preset).Count;
            private int GetAmountPresetConfig(PresetConfig preset) => IsDay ? UnityEngine.Random.Range(preset.MinDay, preset.MaxDay) : UnityEngine.Random.Range(preset.MinNight, preset.MaxNight);
            private void OnDestroy() {
                CancelInvoke(ChangeDeadNpcTime);
                foreach (ActiveScientistNpc activeScientistNpc in ActiveNpc.Where(x => x.Npc.IsExists())) activeScientistNpc.Npc.Kill();
            }
            internal void Init() {
                if (RemoveOtherNpc) {
                    List<NPCPlayer> list = new List<NPCPlayer>();
                    Vis.Entities(transform.position, (Size.x > Size.y ? Size.x : Size.y) * 2f, list, 1 << 17);
                    foreach (NPCPlayer npc in list.Where(IsOtherNpc)) npc.Kill();
                }
                foreach (PresetConfig preset in Presets.Where(x => x.Enabled)) {
                    int amount = GetAmountPresetConfig(preset);
                    for (int i = 0; i < amount; i++) SpawnNpc(preset);
                }
            }
            private void ChangeDeadNpcTime() {
                foreach (DeadScientistNpc deadScientistNpc in DeadNpc) deadScientistNpc.TimeToSpawn--;
                while (DeadNpc.Any(x => x.TimeToSpawn == 0)) {
                    DeadScientistNpc deadScientistNpc = DeadNpc.FirstOrDefault(x => x.TimeToSpawn == 0);
                    int amountPresetConfig = GetAmountPresetConfig(deadScientistNpc.Preset);
                    int amountPreset = GetAmountPreset(deadScientistNpc.Preset) - 1;
                    if (amountPresetConfig > amountPreset) SpawnNpc(deadScientistNpc.Preset);
                    DeadNpc.Remove(deadScientistNpc);
                }
                if (DeadNpc.Count == 0) CancelInvoke(ChangeDeadNpcTime);
            }
            internal void SetDay(bool day) {
                IsDay = day;
                foreach (PresetConfig preset in Presets) {
                    int amountPresetConfig = GetAmountPresetConfig(preset);
                    int amountPreset = GetAmountPreset(preset);
                    if (amountPresetConfig > amountPreset) {
                        int amount = amountPresetConfig - amountPreset;
                        for (int i = 0; i < amount; i++) SpawnNpc(preset);
                    }
                    else if (amountPresetConfig < amountPreset) {
                        int amount = amountPreset - amountPresetConfig;
                        for (int i = 0; i < amount; i++) KillNpc(preset);
                    }
                }
            }
            private void SpawnNpc(PresetConfig preset) {
                Vector3 pos = Vector3.zero;
                int attempts = 0;
                while (pos == Vector3.zero && attempts < 100) {
                    attempts++;
                    if (Name == "Arid" || Name == "Temperate" || Name == "Tundra" || Name == "Arctic") {
                        object point = _ins.NpcSpawn.Call("GetSpawnPoint", Name);
                        if (point is Vector3) pos = (Vector3)point;
                    }
                    else if (preset.TypeSpawn == 0) pos = GetRandomSpawnPos();
                    else pos = transform.TransformPoint(preset.OwnPositions.GetRandom().ToVector3());
                    if (ActiveNpc.Any(x => Vector3.Distance(x.Npc.transform.position, pos) < 5f)) pos = Vector3.zero;
                    if (!_ins._config.UnderwaterSpawnPoints.Contains(Name) && pos.y < -0.25f) pos = Vector3.zero;
                    if (pos != Vector3.zero && TriggerSafeZone.allSafeZones.Count > 0) {
                        TriggerSafeZone nearSafeZone = TriggerSafeZone.allSafeZones.Min(x => Vector3.Distance(pos, x.transform.position));
                        if (nearSafeZone != null && Vector3.Distance(pos, nearSafeZone.transform.position) < _ins._config.SafeZoneRange) pos = Vector3.zero;
                    }
                }
                if (pos != Vector3.zero) {
                    ScientistNPC npc = (ScientistNPC)_ins.NpcSpawn.Call("SpawnNpc", pos, GetObjectConfig(preset.Config));
                    if (npc != null) {
                        ActiveNpc.Add(new ActiveScientistNpc {
                            Preset = preset, Npc = npc
                        }
                        );
                        if (_ins._config.Pve && _ins.plugins.Exists("PveMode")) _ins.PveMode.Call("ScientistAddPveMode", npc);
                    }
                }
            }
            private void KillNpc(PresetConfig preset) {
                if (DeadNpc.Any(x => x.Preset == preset)) {
                    DeadScientistNpc deadScientistNpc = DeadNpc.Where(x => x.Preset == preset).ToList().GetRandom();
                    DeadNpc.Remove(deadScientistNpc);
                }
                else {
                    ActiveScientistNpc activeScientistNpc = ActiveNpc.Where(x => x.Preset == preset).ToList().GetRandom();
                    if (activeScientistNpc.Npc.IsExists()) activeScientistNpc.Npc.Kill();
                    ActiveNpc.Remove(activeScientistNpc);
                }
            }
            internal void DieNpc(ScientistNPC npc, NPCPlayerCorpse corpse) {
                ActiveScientistNpc activeScientistNpc = ActiveNpc.FirstOrDefault(x => x.Npc == npc);
                PresetConfig preset = activeScientistNpc.Preset;
                if (!string.IsNullOrEmpty(preset.CratePrefab)) {
                    BaseEntity entity = GameManager.server.CreateEntity(preset.CratePrefab, npc.transform.position, npc.transform.rotation);
                    if (entity == null) _ins.PrintWarning($"Unknown entity! ({preset.CratePrefab})");
                    else {
                        entity.enableSaving = false;
                        entity.Spawn();
                    }
                }
                if (!IsEvent) {
                    DeadNpc.Add(new DeadScientistNpc {
                        Preset = preset, TimeToSpawn = (int)UnityEngine.Random.Range(preset.Config.MinTime, preset.Config.MaxTime)
                    }
                    );
                    if (DeadNpc.Count == 1) InvokeRepeating(ChangeDeadNpcTime, 1f, 1f);
                }
                ActiveNpc.Remove(activeScientistNpc);
                BasePlayer attacker = npc.lastAttacker as BasePlayer;
                if (attacker.IsPlayer()) _ins.SendBalance(attacker.userID, preset.Economic);
                _ins.NextTick(() => {
                    if (preset.TypeLootTable == 1 || preset.TypeLootTable == 4 || preset.TypeLootTable == 5) {
                        ItemContainer container = corpse.containers[0];
                        for (int i = container.itemList.Count - 1; i >= 0; i--) {
                            Item item = container.itemList[i];
                            item.RemoveFromContainer();
                            item.Remove();
                        }
                        if (preset.TypeLootTable == 4 || preset.TypeLootTable == 5) _ins.AddToContainerPrefab(container, preset.PrefabLootTable);
                        if (preset.TypeLootTable == 1 || preset.TypeLootTable == 5) _ins.AddToContainerItem(container, preset.OwnLootTable);
                    }
                    if (preset.Config.IsRemoveCorpse && corpse.IsExists()) corpse.Kill();
                    if (IsEvent && ActiveNpc.Count == 0) {
                        _ins._controllers.Remove(this);
                        Destroy(gameObject);
                    }
                }
                );
            }
            internal bool IsOtherNpc(NPCPlayer npc) {
                if (!npc.IsExists()) return false;
                if (_ins._config.OtherNpc.Contains(npc.GetType().Name)) return false;
                if (_ins._config.OtherNpc.Contains(npc.displayName)) return false;
                if (_ins._config.OtherNpc.Contains(npc.skinID.ToString())) return false;
                if (npc.ShortPrefabName.Contains("scientistnpc_patrol") || npc.ShortPrefabName.Contains("scientistnpc_excavator") || npc.ShortPrefabName.Contains("scientistnpc_roamtethered") || npc.ShortPrefabName.Contains("scientistnpc_full") || npc.ShortPrefabName.Contains("scientistnpc_roam") || npc.ShortPrefabName.Contains("scientistnpc_oilrig") || npc.ShortPrefabName.Contains("npc_underwaterdweller") || npc.ShortPrefabName.Contains("npc_tunneldweller") || npc.ShortPrefabName.Contains("scarecrow")) return true;
                return false;
            }
            private Vector3 GetRandomSpawnPos() {
                RaycastHit raycastHit;
                NavMeshHit navmeshHit;
                int attempts = 0;
                while (attempts < 10) {
                    attempts++;
                    Vector3 pos = transform.TransformPoint(new Vector3(UnityEngine.Random.Range(-Size.x, Size.x), 500f, UnityEngine.Random.Range(-Size.y, Size.y)));
                    if (!Physics.Raycast(pos, Vector3.down, out raycastHit, 500f, 1 << 16 | 1 << 23)) continue;
                    pos.y = raycastHit.point.y;
                    if (!NavMesh.SamplePosition(pos, out navmeshHit, 2f, 1)) continue;
                    pos = navmeshHit.position;
                    if (pos.y < -0.25f) continue;
                    return pos;
                }
                return Vector3.zero;
            }
            private JObject GetObjectConfig(NpcConfig config) {
                HashSet<string> states = config.Stationary ? new HashSet<string> {
                    "IdleState", "CombatStationaryState"
                }
                : new HashSet<string> {
                    "RoamState", "ChaseState", "CombatState"
                }
                ;
                if (config.BeltItems.Any(x => x.ShortName == "rocket.launcher" || x.ShortName == "explosive.timed")) states.Add("RaidState");
                return new JObject {
                    ["Name"]
                    = config.Names.GetRandom(), ["WearItems"] = new JArray {
                        config.WearItems.Select(x => new JObject {
                            ["ShortName"]
                            = x.ShortName, ["SkinID"] = x.SkinID
                        }
                        )
                    }
                    , ["BeltItems"] = new JArray {
                        config.BeltItems.Select(x => new JObject {
                            ["ShortName"]
                            = x.ShortName, ["Amount"] = x.Amount, ["SkinID"] = x.SkinID, ["Mods"] = new JArray {
                                x.Mods
                            }
                            , ["Ammo"] = x.Ammo
                        }
                        )
                    }
                    , ["Kit"] = config.Kits.GetRandom(), ["Health"] = config.Health, ["RoamRange"] = config.RoamRange, ["ChaseRange"] = config.ChaseRange, ["DamageScale"] = config.DamageScale, ["TurretDamageScale"] = 1f, ["AimConeScale"] = config.AimConeScale, ["DisableRadio"] = config.DisableRadio, ["CanUseWeaponMounted"] = true, ["CanRunAwayWater"] = !_ins._config.UnderwaterSpawnPoints.Contains(Name), ["Speed"] = config.Speed, ["AreaMask"] = Name == "Large Oil Rig" || Name == "Oil Rig" || _ins._underwaterLabSpawnPoints.ContainsKey(Name) ? 25 : 1, ["AgentTypeID"] = Name == "Large Oil Rig" || Name == "Oil Rig" || _ins._underwaterLabSpawnPoints.ContainsKey(Name) ? 0 : -1372625422, ["HomePosition"] = string.Empty, ["States"] = new JArray {
                        states
                    }
                    , ["Sensory"] = new JObject {
                        ["AttackRangeMultiplier"]
                        = config.AttackRangeMultiplier, ["SenseRange"] = config.SenseRange, ["MemoryDuration"] = config.MemoryDuration, ["CheckVisionCone"] = config.CheckVisionCone, ["VisionCone"] = config.VisionCone
                    }
                }
                ;
            }
            internal class ActiveScientistNpc {
                public PresetConfig Preset;
                public ScientistNPC Npc;
            }
            internal class DeadScientistNpc {
                public PresetConfig Preset;
                public int TimeToSpawn;
            }
        }
#endregion Controller
#region Economy
        [PluginReference]
        private readonly Plugin Economics, ServerRewards, IQEconomic;
        internal void SendBalance(ulong playerId, NpcEconomic economic) {
            if (plugins.Exists("Economics") && economic.Economics > 0) Economics.Call("Deposit", playerId.ToString(), economic.Economics);
            if (plugins.Exists("ServerRewards") && economic.ServerRewards > 0) ServerRewards.Call("AddPoints", playerId, economic.ServerRewards);
            if (plugins.Exists("IQEconomic") && economic.IQEconomic > 0) IQEconomic.Call("API_SET_BALANCE", playerId, economic.IQEconomic);
        }
#endregion Economy
#region Loot Spawn
        private void AddToContainerPrefab(ItemContainer container, PrefabLootTableConfig lootTable) {
            if (lootTable.UseCount) {
                int count = UnityEngine.Random.Range(lootTable.Min, lootTable.Max + 1);
                HashSet<string> prefabsInContainer = new HashSet<string>();
                while (prefabsInContainer.Count < count) {
                    foreach (PrefabConfig prefab in lootTable.Prefabs) {
                        if (prefabsInContainer.Contains(prefab.PrefabDefinition)) continue;
                        if (UnityEngine.Random.Range(0.0f, 100.0f) <= prefab.Chance) {
                            if (_allLootSpawnSlots.ContainsKey(prefab.PrefabDefinition)) {
                                LootContainer.LootSpawnSlot[] lootSpawnSlots = _allLootSpawnSlots[prefab.PrefabDefinition];
                                foreach (LootContainer.LootSpawnSlot lootSpawnSlot in lootSpawnSlots) for (int j = 0; j < lootSpawnSlot.numberToSpawn; j++) if (UnityEngine.Random.Range(0f, 1f) <= lootSpawnSlot.probability) lootSpawnSlot.definition.SpawnIntoContainer(container);
                            }
                            else _allLootSpawn[prefab.PrefabDefinition].SpawnIntoContainer(container);
                            prefabsInContainer.Add(prefab.PrefabDefinition);
                            if (prefabsInContainer.Count == count) return;
                        }
                    }
                }
            }
            else {
                HashSet<string> prefabsInContainer = new HashSet<string>();
                foreach (PrefabConfig prefab in lootTable.Prefabs) {
                    if (prefabsInContainer.Contains(prefab.PrefabDefinition)) continue;
                    if (UnityEngine.Random.Range(0.0f, 100.0f) <= prefab.Chance) {
                        if (_allLootSpawnSlots.ContainsKey(prefab.PrefabDefinition)) {
                            LootContainer.LootSpawnSlot[] lootSpawnSlots = _allLootSpawnSlots[prefab.PrefabDefinition];
                            foreach (LootContainer.LootSpawnSlot lootSpawnSlot in lootSpawnSlots) for (int j = 0; j < lootSpawnSlot.numberToSpawn; j++) if (UnityEngine.Random.Range(0f, 1f) <= lootSpawnSlot.probability) lootSpawnSlot.definition.SpawnIntoContainer(container);
                        }
                        else _allLootSpawn[prefab.PrefabDefinition].SpawnIntoContainer(container);
                        prefabsInContainer.Add(prefab.PrefabDefinition);
                    }
                }
            }
        }
        private void AddToContainerItem(ItemContainer container, LootTableConfig lootTable) {
            if (lootTable.UseCount) {
                int count = UnityEngine.Random.Range(lootTable.Min, lootTable.Max + 1);
                HashSet<int> indexMove = new HashSet<int>();
                while (indexMove.Count < count) {
                    foreach (ItemConfig item in lootTable.Items) {
                        if (indexMove.Contains(lootTable.Items.IndexOf(item))) continue;
                        if (UnityEngine.Random.Range(0.0f, 100.0f) <= item.Chance) {
                            Item newItem = item.IsBluePrint ? ItemManager.CreateByName("blueprintbase") : ItemManager.CreateByName(item.ShortName, UnityEngine.Random.Range(item.MinAmount, item.MaxAmount + 1), item.SkinID);
                            if (newItem == null) {
                                PrintWarning($"Failed to create item! ({item.ShortName})");
                                continue;
                            }
                            if (item.IsBluePrint) newItem.blueprintTarget = ItemManager.FindItemDefinition(item.ShortName).itemid;
                            if (!string.IsNullOrEmpty(item.Name)) newItem.name = item.Name;
                            if (container.capacity < container.itemList.Count + 1) container.capacity++;
                            if (!newItem.MoveToContainer(container)) newItem.Remove();
                            else {
                                indexMove.Add(lootTable.Items.IndexOf(item));
                                if (indexMove.Count == count) return;
                            }
                        }
                    }
                }
            }
            else {
                HashSet<int> indexMove = new HashSet<int>();
                foreach (ItemConfig item in lootTable.Items) {
                    if (indexMove.Contains(lootTable.Items.IndexOf(item))) continue;
                    if (UnityEngine.Random.Range(0.0f, 100.0f) <= item.Chance) {
                        Item newItem = item.IsBluePrint ? ItemManager.CreateByName("blueprintbase") : ItemManager.CreateByName(item.ShortName, UnityEngine.Random.Range(item.MinAmount, item.MaxAmount + 1), item.SkinID);
                        if (newItem == null) {
                            PrintWarning($"Failed to create item! ({item.ShortName})");
                            continue;
                        }
                        if (item.IsBluePrint) newItem.blueprintTarget = ItemManager.FindItemDefinition(item.ShortName).itemid;
                        if (!string.IsNullOrEmpty(item.Name)) newItem.name = item.Name;
                        if (container.capacity < container.itemList.Count + 1) container.capacity++;
                        if (!newItem.MoveToContainer(container)) newItem.Remove();
                        else indexMove.Add(lootTable.Items.IndexOf(item));
                    }
                }
            }
        }
        private void CheckAllLootTables() {
            foreach (KeyValuePair<string, MonumentSpawnPoint> dic in _monumentSpawnPoints) {
                foreach (PresetConfig preset in dic.Value.Presets.Where(x => x.Enabled)) {
                    CheckLootTable(preset.OwnLootTable);
                    CheckPrefabLootTable(preset.PrefabLootTable);
                }
                Interface.Oxide.DataFileSystem.WriteObject($"BetterNpc/Monument/{dic.Key}", dic.Value);
            }
            foreach (KeyValuePair<string, MonumentSpawnPoint> dic in _underwaterLabSpawnPoints) {
                foreach (PresetConfig preset in dic.Value.Presets.Where(x => x.Enabled)) {
                    CheckLootTable(preset.OwnLootTable);
                    CheckPrefabLootTable(preset.PrefabLootTable);
                }
                Interface.Oxide.DataFileSystem.WriteObject($"BetterNpc/Monument/Underwater Lab/{dic.Key}", dic.Value);
            }
            foreach (KeyValuePair<string, MonumentSpawnPoint> dic in _tunnelSpawnPoints) {
                foreach (PresetConfig preset in dic.Value.Presets.Where(x => x.Enabled)) {
                    CheckLootTable(preset.OwnLootTable);
                    CheckPrefabLootTable(preset.PrefabLootTable);
                }
                Interface.Oxide.DataFileSystem.WriteObject($"BetterNpc/Monument/Tunnel/{dic.Key}", dic.Value);
            }
            foreach (KeyValuePair<string, CustomSpawnPoint> dic in _customSpawnPoints) {
                foreach (PresetConfig preset in dic.Value.Presets.Where(x => x.Enabled)) {
                    CheckLootTable(preset.OwnLootTable);
                    CheckPrefabLootTable(preset.PrefabLootTable);
                }
                Interface.Oxide.DataFileSystem.WriteObject($"BetterNpc/Custom/{dic.Key}", dic.Value);
            }
            foreach (KeyValuePair<string, EventSpawnPoint> dic in _eventSpawnPoints) {
                foreach (PresetConfig preset in dic.Value.Presets.Where(x => x.Enabled)) {
                    CheckLootTable(preset.OwnLootTable);
                    CheckPrefabLootTable(preset.PrefabLootTable);
                }
                Interface.Oxide.DataFileSystem.WriteObject($"BetterNpc/Event/{dic.Key}", dic.Value);
            }
            foreach (KeyValuePair<string, RoadSpawnPoint> dic in _roadSpawnPoints) {
                foreach (PresetConfig preset in dic.Value.Presets.Where(x => x.Enabled)) {
                    CheckLootTable(preset.OwnLootTable);
                    CheckPrefabLootTable(preset.PrefabLootTable);
                }
                Interface.Oxide.DataFileSystem.WriteObject($"BetterNpc/Road/{dic.Key}", dic.Value);
            }
            foreach (KeyValuePair<string, BiomeSpawnPoint> dic in _biomeSpawnPoints) {
                foreach (PresetConfig preset in dic.Value.Presets.Where(x => x.Enabled)) {
                    CheckLootTable(preset.OwnLootTable);
                    CheckPrefabLootTable(preset.PrefabLootTable);
                }
                Interface.Oxide.DataFileSystem.WriteObject($"BetterNpc/Biome/{dic.Key}", dic.Value);
            }
        }
        private void CheckLootTable(LootTableConfig lootTable) {
            lootTable.Items = lootTable.Items.OrderBy(x => x.Chance);
            if (lootTable.Max > lootTable.Items.Count) lootTable.Max = lootTable.Items.Count;
            if (lootTable.Min > lootTable.Max) lootTable.Min = lootTable.Max;
        }
        private void CheckPrefabLootTable(PrefabLootTableConfig lootTable) {
            HashSet<PrefabConfig> prefabs = new HashSet<PrefabConfig>();
            foreach (PrefabConfig prefabConfig in lootTable.Prefabs) {
                if (prefabs.Any(x => x.PrefabDefinition == prefabConfig.PrefabDefinition)) PrintWarning($"Duplicate prefab removed from loot table! ({prefabConfig.PrefabDefinition})");
                else {
                    GameObject gameObject = GameManager.server.FindPrefab(prefabConfig.PrefabDefinition);
                    global : : HumanNPC humanNpc = gameObject.GetComponent<global : : HumanNPC>();
                    ScarecrowNPC scarecrowNPC = gameObject.GetComponent<ScarecrowNPC>();
                    LootContainer lootContainer = gameObject.GetComponent<LootContainer>();
                    if (humanNpc != null && humanNpc.LootSpawnSlots.Length != 0) {
                        if (!_allLootSpawnSlots.ContainsKey(prefabConfig.PrefabDefinition)) _allLootSpawnSlots.Add(prefabConfig.PrefabDefinition, humanNpc.LootSpawnSlots);
                        prefabs.Add(prefabConfig);
                    }
                    else if (scarecrowNPC != null && scarecrowNPC.LootSpawnSlots.Length != 0) {
                        if (!_allLootSpawnSlots.ContainsKey(prefabConfig.PrefabDefinition)) _allLootSpawnSlots.Add(prefabConfig.PrefabDefinition, scarecrowNPC.LootSpawnSlots);
                        prefabs.Add(prefabConfig);
                    }
                    else if (lootContainer != null && lootContainer.LootSpawnSlots.Length != 0) {
                        if (!_allLootSpawnSlots.ContainsKey(prefabConfig.PrefabDefinition)) _allLootSpawnSlots.Add(prefabConfig.PrefabDefinition, lootContainer.LootSpawnSlots);
                        prefabs.Add(prefabConfig);
                    }
                    else if (lootContainer != null && lootContainer.lootDefinition != null) {
                        if (!_allLootSpawn.ContainsKey(prefabConfig.PrefabDefinition)) _allLootSpawn.Add(prefabConfig.PrefabDefinition, lootContainer.lootDefinition);
                        prefabs.Add(prefabConfig);
                    }
                    else PrintWarning($"Unknown prefab removed! ({prefabConfig.PrefabDefinition})");
                }
            }
            lootTable.Prefabs = prefab
// ... [Code preview truncated due to length. Full source in attached file] ...

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

Другие ресурсы пользователя 15FPS

Сверху