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

FREE BotReSpawn : 1.4.1 1.4.1

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Facepunch;
using System;
using System.Linq;
using System.Globalization;
using System.Collections.Generic;
using Oxide.Core;
using Oxide.Core.Plugins;
using UnityEngine;
using UnityEngine.AI;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Game.Rust.Cui;
using System.Reflection;
using UnityEngine.UI;
using HarmonyLib;
using Rust.Ai.Gen2;
using Facepunch.Utility;
namespace Oxide.Plugins {
    //  For previous version changes, see end of file.//To do
    //  Make info show more info - Ui maybe? Proximity based?
    //  Map markers option.//  Make melee npcs retreat if player is mounted.//  Detect when target is dead and loot corpse.//  Register permission for every profile created + ignore players with that permission @Venedas.//  Add glowing eyes optional
    //  Offer GUIAnnouncements for spawn announcement.//  Make eokas great again.//  Spawn X profile after Y kills of Z profile
    //  Add back in move/spawn/kill commands.//  Work on grenade aim where target is higher than npc.//  Make grenade and syringe limited to the number in the kit.////////////////
    //  Option to re-read data + config from file, without reloading profiles/plugin.//  Make data prefix + reload option in UI.//  Make rocket npcs fire smoke from time to time, if LOS is lost.//  Add Night_Profile option.//  Add Only_throw_In_Building priv
    //  Parachuters flying away at heli kill profile - can't replicate
    //  Dont_Spawn_For_X_Hours_After_Wipe
    //  Add proper NPC shield use.Maybe immediately after player reload, if player has bullet weapon?
    //  If not, randomise.//  Add additional damage types, such as radiation.Amount per hit and % chance.//  Adjustable melee attack speed? MelodyZE
    //  Suppressed weapons and quiet weapons - Ai_Assist
    //  Add console command to reload one or all profiles - No longer needed.Guy had NPCLoadouts, fighting with BRS.//  Make rocket npcs continue shooting even if building block is in the way.//  Support Jungle Biome.//  Changes in 1.4.1
    //  Reverted to 1.3.9 navmesh behaviour.Roaming in weird areas shouldn't happen anymore.//  Revisited navmesh spam (server log file) issue.BotReSpawn now catches and handles issues with minimal server log output.//  Fixed prevent death messages issue.//  Added autofocus = false to input fields.//  Ignore commands from input fields where content didn't change (people couldn't access behaviour tab)
    //  Fixed Instant_Death_From_Headshot_Allowed_Weapons 'Manage' taking you to edit BotNames page.//  Added valid-shortname check when adding Instant_Death_From_Headshot_Allowed_Weapons.//  Added various missing descriptions from UI (when setting name is clicked)
    //  Improved /botrespawn info command.Now shows some detail on screen for any+all BotReSpawn npcs in close proximity.//  Reduced the load-spreading delay when initially spawning profiles.Full population will be reached 5X faster now.[Info("BotReSpawn", "Steenamaroo", "1.4.1", ResourceId = 0)]
    [Description("Spawn tailored AI with kits at monuments, custom locations, or randomly.")]
    class BotReSpawn : RustPlugin {
        [PluginReference]
        Plugin Convoy, NoSash, Kits, CustomLoot, RustRewards, XPerience, AlphaLoot;
        int no_of_AI;
        bool loaded;
        static BotReSpawn bs;
        static System.Random random = new System.Random();
        public static string Get(ulong v) => RandomUsernames.Get((int)(v % 2147483647uL));
        public static bool IsNight() {
            if (bs?.configData?.Global == null || bs.Unloading) return true;
            var hour = TOD_Sky.Instance.Cycle.Hour;
            if (bs.configData.Global.UseServerTime == true) return TOD_Sky.Instance.IsNight;
            if (bs.configData.Global.NightStartHour > bs.configData.Global.DayStartHour) return hour >= bs.configData.Global.NightStartHour || hour < bs.configData.Global.DayStartHour;
            else return hour >= bs.configData.Global.NightStartHour && hour < bs.configData.Global.DayStartHour;
        }
        int GetRand(int l, int h) => random.Next(l, h);
        bool HasPermission(string id, string perm) => permission.UserHasPermission(id, perm);
        const string permAllowed = "BotReSpawn.allowed";
        const string huff = "assets/prefabs/npc/murderer/sound/breathing.prefab";
        const string Parachute = "assets/prefabs/misc/parachute/parachute.prefab";
        const string RocketExplosion = "assets/prefabs/weapons/rocketlauncher/effects/rocket_explosion.prefab";
        const string LockedCrate = "assets/prefabs/deployable/chinooklockedcrate/codelockedhackablecrate.prefab";
        ItemDefinition fuel = ItemManager.FindItemDefinition("lowgradefuel");
        ItemDefinition scrap;
        PlayerInventoryProperties[] scloadouts;
        LootContainer.LootSpawnSlot[] sc;
        public List<ulong> HumanNPCs = new List<ulong>();
        public Dictionary<string, Profile> Profiles = new Dictionary<string, Profile>();
        Dictionary<string, LootContainer> Containers = new Dictionary<string, LootContainer>() {
            {
                "Default NPC", null
            }
        }
        ;
        public Dictionary<ulong, BotData> NPCPlayers = new Dictionary<ulong, BotData>();
        public Dictionary<Gender, Dictionary<SkinTone, List<ulong>>> Models = new Dictionary<Gender, Dictionary<SkinTone, List<ulong>>>();
#region Setup + TakeDown
        void Init() {
            JsonConvert.DefaultSettings = () => new JsonSerializerSettings {
                Formatting = Formatting.Indented, ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
            }
            ;
            no_of_AI = 0;
        }
        void Loaded() {
            ConVar.AI.npc_families_no_hurt = false;
            lang.RegisterMessages(Messages, this);
            permission.RegisterPermission(permAllowed, this);
        }
        bool Unloading = false;
        void Unload() {
            Unloading = true;
            DestroySpawnGroups();
            foreach (BasePlayer player in BasePlayer.activePlayerList) DestroyMenu(player, true);
            harmony.UnpatchAll("BotReSpawn");
        }
        List<string> WeaponShortNames = new List<string>();
        void OnServerInitialized() {
            bs = this;
            scrap = ItemManager.FindItemDefinition("scrap");
            var crow = (ScarecrowNPC)GameManager.server.FindPrefab("assets/prefabs/npc/scarecrow/scarecrow.prefab")?.GetComponent<ScarecrowNPC>();
            if (crow != null) {
                scloadouts = crow.loadouts;
                sc = crow.LootSpawnSlots;
            }
            foreach (BasePlayer player in BaseNetworkable.serverEntities.OfType<BasePlayer>()) ProcessHumanNPC(player);
            timer.Once(1f, () => {
                if (NoSash) {
                    PrintWarning("NoSash plugin is installed");
                    PrintWarning("Target_Noobs option is now disabled.");
                    PrintWarning("BotReSpawn NPCs will target noob players.");
                }
                GetBiomePoints();
                CheckMonuments(false);
                LoadConfigVariables();
                ImportFiles();
                loaded = true;
                SaveData();
                SetupProfiles();
                CheckKits();
                SetupLootSources();
                newsave = false;
                timer.Once(0.1f, () => CreateSpawnGroups());
                foreach (BradleyAPC apc in BaseNetworkable.serverEntities.OfType<BradleyAPC>()) SetupAPC(apc);
                CheckAPCSafe();
                CheckGunTrapSafe();
            }
            );
            // Remove in V1.1.0
            BaseEntity.saveList.RemoveWhere(p => !p);
            BaseEntity.saveList.RemoveWhere(p => p == null);
            harmony.UnpatchAll("BotReSpawn");
            ApplyPatches();
            GetModels();
            WeaponShortNames = ItemManager.itemList.Select(x => x.shortname).ToList();
        }
        void GetModels() {
            Models[Gender.Male] = new Dictionary<SkinTone, List<ulong>>();
            Models[Gender.Female] = new Dictionary<SkinTone, List<ulong>>();
            for (int i = 1; i < 5; i++) {
                Models[Gender.Male].Add((SkinTone)i, new List<ulong>());
                Models[Gender.Female].Add((SkinTone)i, new List<ulong>());
            }
            for (ulong j = 1; j < 10000000; j++) {
                int skinType;
                float meshNumber, skinNumber;
                GetPlayerRandomBodyDetails(j, out skinType, out skinNumber, out meshNumber);
                if (skinType == 1) {
                    if (meshNumber < 0.41 && meshNumber > 0.4 && (skinNumber < 1 && skinNumber > 0.66)) Models[Gender.Female][(SkinTone)1].Add(j);
                    if (meshNumber < 0.61 && meshNumber > 0.6 && (skinNumber < 0.33 && skinNumber > 0.0)) Models[Gender.Female][(SkinTone)2].Add(j);
                    if (meshNumber < 0.71 && meshNumber > 0.7) {
                        if (skinNumber < 1 && skinNumber > 0.66) Models[Gender.Female][(SkinTone)3].Add(j);
                        if (skinNumber < 0.2 && skinNumber > 0.0) Models[Gender.Female][(SkinTone)4].Add(j);
                    }
                }
                else if (skinType == 0) {
                    if (meshNumber < 1.00 && meshNumber > 0.99 && (skinNumber < 0.2 && skinNumber > 0.0)) Models[Gender.Male][(SkinTone)1].Add(j);
                    if (meshNumber < 0.01 && meshNumber > 0.0 && (skinNumber < 1 && skinNumber > 0.8)) Models[Gender.Male][(SkinTone)2].Add(j);
                    if (meshNumber < 0.71 && meshNumber > 0.7) {
                        if (skinNumber < 1 && skinNumber > 0.8) Models[Gender.Male][(SkinTone)3].Add(j);
                        if (skinNumber < 0.2 && skinNumber > 0.0) Models[Gender.Male][(SkinTone)4].Add(j);
                    }
                }
            }
        }
        public void GetPlayerRandomBodyDetails(ulong userID, out int skinType, out float skinNumber, out float meshNumber) {
            skinType = (GetRandomFloatBasedOnUserID(userID, (ulong)4332) > 0.5f ? 1 : 0);
            meshNumber = GetRandomFloatBasedOnUserID(userID, (ulong)2647);
            //skinColor = GetRandomFloatBasedOnUserID(userID, (ulong)5977);
            skinNumber = GetRandomFloatBasedOnUserID(userID, (ulong)3975);
        }
        public float GetRandomFloatBasedOnUserID(ulong steamid, ulong seed) {
            UnityEngine.Random.State state = UnityEngine.Random.state;
            UnityEngine.Random.InitState((int)(seed + steamid));
            float single = UnityEngine.Random.Range(0f, 1f);
            UnityEngine.Random.state = state;
            return single;
        }
        void CheckAPCSafe() {
            bool APCSafe = false;
            foreach (var profile in Profiles) if (profile.Value.Spawn.AutoSpawn && profile.Value.Other.APC_Safe) APCSafe = true;
            if (APCSafe) Subscribe("CanBradleyApcTarget");
            else Unsubscribe("CanBradleyApcTarget");
        }
        void CheckGunTrapSafe() {
            bool GunTrapSafe = false;
            foreach (var profile in Profiles) if (profile.Value.Spawn.AutoSpawn && profile.Value.Other.WeaponTrap_Safe) GunTrapSafe = true;
            if (GunTrapSafe) Subscribe("CanBeTargeted");
            else Unsubscribe("CanBeTargeted");
        }
        void ProcessHumanNPC(BasePlayer player) {
            if (player == null || player.net?.connection != null || player.gameObject?.name == "BotReSpawn") return;
            foreach (var comp in player.GetComponents<Component>()) if (comp?.GetType()?.Name == "HumanPlayer") {
                HumanNPCs.Add(player.userID);
                break;
            }
        }
#endregion
#region Setup Methods
        void GetBiomePoints() {
            var trees = BaseNetworkable.serverEntities.OfType<ResourceEntity>().Where(x => x is TreeEntity || x.ShortPrefabName.Contains("cactus"));
            string biomename = "";
            List<string> names = new List<string>();
            int biome = -1;
            Vector3 point = Vector3.zero;
            foreach (var tree in trees.ToList()) {
                biome = TerrainMeta.BiomeMap.GetBiomeMaxType(tree.transform.position, -1);
                point = CalculateGroundPos(tree.transform.position + Vector3.forward / 2f, false, false, true);
                if (point != Vector3.zero) {
                    biomename = $"Biome{Enum.GetName(typeof(TerrainBiome.Enum), biome)}";
                    if (BiomeSpawns.ContainsKey(biomename)) BiomeSpawns[biomename].Add(point);
                    else BiomeSpawns.Add(biomename, new List<Vector3> {
                        point
                    }
                    );
                }
            }
        }
        List<Vector3> OilRigs = new List<Vector3>();
        void CheckMonuments(bool add) {
            GameObject gobject;
            Vector3 pos;
            float rot;
            foreach (var monumentInfo in TerrainMeta.Path.Monuments.OrderBy(x => x.displayPhrase.english)) {
                var displayPhrase = monumentInfo.displayPhrase.english.Replace("\n", String.Empty);
                if (add) {
                    if (displayPhrase.Contains("Water Well") && configData.Global.Disable_WaterWells) continue;
                    if (displayPhrase.Contains("Substation") && configData.Global.Disable_Substations) continue;
                    if (displayPhrase.Contains("Underground Cave") && configData.Global.Disable_UndergroundCaves) continue;
                    if (displayPhrase.Contains("Underwater Lab") && configData.Global.Disable_UnderwaterLabs) continue;
                    if (displayPhrase.Contains("Oil Rig") && !configData.Global.Allow_Oilrigs) continue;
                }
                if (monumentInfo?.gameObject?.name != null) displayPhrase = ProcessName(monumentInfo.gameObject.name, displayPhrase);
                gobject = monumentInfo.gameObject;
                pos = gobject.transform.position;
                rot = gobject.transform.eulerAngles.y;
                int counter = 0;
                if (displayPhrase != String.Empty) {
                    if (add) {
                        if (displayPhrase.Contains("Oil Rig")) OilRigs.Add(pos);
                        foreach (var entry in Profiles.Where(x => x.Key.Contains(displayPhrase) && (x.Key.Length == displayPhrase.Length + 2 || x.Key.Length == displayPhrase.Length + 3))) counter++;
                        AddProfile(gobject, $"{displayPhrase} {counter}", null, pos);
                    }
                    else {
                        foreach (var entry in GotMonuments.Where(x => x.Key.Contains(displayPhrase) && (x.Key.Length == displayPhrase.Length + 2 || x.Key.Length == displayPhrase.Length + 3))) counter++;
                        GotMonuments.Add($"{displayPhrase} {counter}", new Profile(ProfileType.Monument));
                    }
                }
            }
        }
        List<string> numerical = new List<string>() {
            "mountain_", "power_sub_big_", "power_sub_small_", "ice_lake_"
        }
        ;
        string ProcessName(string name, string displayPhrase) {
            foreach (var n in numerical) {
                int num;
                if (name.Length > n.Length && int.TryParse(name.Substring(name.IndexOf(n) + n.Length, 1), out num)) {
                    displayPhrase += name.Contains("sub_big_") ? "_Large" : name.Contains("sub_small_") ? "_Small" : "";
                    return displayPhrase + $"_{num}";
                }
            }
            if (displayPhrase == "Harbor") displayPhrase += name.Contains("_1") ? "_Small" : "_Large";
            else if (displayPhrase == "Fishing Village" || displayPhrase == "Wild Swamp" || displayPhrase == "Abandoned Military Base") displayPhrase += name.Contains("_a.") ? "_A" : name.Contains("_b.") ? "_B" : name.Contains("_c.") ? "_C" : "_D";
            return displayPhrase;
        }
        void ImportFiles() {
            storedData = Interface.Oxide.DataFileSystem.ReadObject<StoredData>($"BotReSpawn/{configData.DataPrefix}-CustomProfiles");
            defaultData = Interface.Oxide.DataFileSystem.ReadObject<DefaultData>($"BotReSpawn/{configData.DataPrefix}-DefaultProfiles");
            if (!configData.Global.Allow_Oilrigs) defaultData.Monuments = defaultData.Monuments.Where(x => !x.Key.Contains("Oil Rig")).ToDictionary(pair => pair.Key, pair => pair.Value);
            spawnsData = Interface.Oxide.DataFileSystem.ReadObject<SpawnsData>($"BotReSpawn/{configData.DataPrefix}-SpawnsData");
            templateData = Interface.Oxide.DataFileSystem.ReadObject<TemplateData>("BotReSpawn/TemplateData");
        }
        Dictionary<string, List<Vector3>> BiomeSpawns = new Dictionary<string, List<Vector3>>() {
            {
                "BiomeArid", new List<Vector3>()
            }
            , {
                "BiomeTemperate", new List<Vector3>()
            }
            , {
                "BiomeTundra", new List<Vector3>()
            }
            , {
                "BiomeArctic", new List<Vector3>()
            }
            , {
                "BiomeJungle", new List<Vector3>()
            }
        }
        ;
        private void SetupProfiles() {
            CheckMonuments(true);
            foreach (var biome in defaultData.Biomes) AddProfile(new GameObject(), biome.Key, biome.Value, new Vector3());
            foreach (var e in defaultData.Events) AddProfile(new GameObject(), e.Key, e.Value, new Vector3());
            foreach (var profile in storedData.Profiles) AddData(profile.Key, profile.Value);
            SaveData();
            SetupSpawnsFile();
            foreach (var profile in Profiles.Where(x => x.Value.type == ProfileType.Custom || x.Value.type == ProfileType.Monument)) if (profile.Value.Spawn.Kit.Count > 0 && Kits == null) PrintWarning(lang.GetMessage("nokits", this), profile.Key);
        }
        void CheckKits() {
            ValidKits.Clear();
            Kits?.Call("GetKitNames", new object[] {
                ValidKits
            }
            );
            var names = Kits?.Call("GetAllKits");
            if (names != null) ValidKits.AddRange((string[])names);
            ValidKits = ValidKits.Distinct().ToList();
            foreach (var kit in ValidKits.ToList()) {
                object checkKit = Kits?.CallHook("GetKitInfo", kit, true);
                bool weaponInKit = false;
                JObject kitContents = checkKit as JObject;
                if (kitContents != null) {
                    JArray items = kitContents["items"] as JArray;
                    foreach (var weap in items) {
                        JObject item = weap as JObject;
                        if (Isweapon(Convert.ToInt32(item["itemid"]), null)) {
                            weaponInKit = true;
                            break;
                        }
                    }
                }
                if (!weaponInKit) ValidKits.Remove(kit);
            }
            if (Kits) foreach (var profile in Profiles) profile.Value.Spawn.Kit = profile.Value.Spawn.Kit.Where(x => ValidKits.Contains(x)).ToList();
            ValidKits = ValidKits.OrderBy(x => x.ToString()).ToList();
        }
        void SetupLootSources() {
            List<string> ignore = new List<string>();
            ignore.AddRange("hidden,test,shelves,stocking,mission".Split(','));
            Containers.Add("ScarecrowNPC", null);
            Containers.Add("Random", null);
            foreach (var entry in Resources.FindObjectsOfTypeAll<LootContainer>().Where(x => x != null && !x.isSpawned).ToList()) {
                bool skip = false;
                foreach (var i in ignore) if (entry.PrefabName.Contains(i)) skip = true;
                if (skip) continue;
                string name = GetLootName(entry.PrefabName, entry.ShortPrefabName);
                if (Containers.ContainsKey(name)) continue;
                Containers.Add(name, entry);
            }
        }
#endregion
#region Helpers
        public string GetLootName(string name, string name2) => name.Contains("underwater_labs") ? "underwater_labs_" + name2 : name2;
        public void PopulateLoot(LootContainer source, ItemContainer container, bool doscrap) {
            LootContainer.LootSpawnSlot[] lootSpawnSlots = source == null ? sc : source.LootSpawnSlots;
            if (lootSpawnSlots.Length != 0) {
                for (int i = 0; i < lootSpawnSlots.Length; i++) {
                    LootContainer.LootSpawnSlot lootSpawnSlot = lootSpawnSlots[i];
                    for (int j = 0; j < lootSpawnSlot.numberToSpawn; j++) if (UnityEngine.Random.Range(0f, 1f) <= lootSpawnSlot.probability) lootSpawnSlot.definition.SpawnIntoContainer(container);
                }
            }
            else if (source?.lootDefinition != null) for (int k = 0; k < source.maxDefinitionsToSpawn; k++) source.lootDefinition.SpawnIntoContainer(container);
            if (source?.SpawnType == LootContainer.spawnType.ROADSIDE || source?.SpawnType == LootContainer.spawnType.TOWN) foreach (Item item in container.itemList) if (item.hasCondition) item.condition = UnityEngine.Random.Range(item.info.condition.foundCondition.fractionMin, item.info.condition.foundCondition.fractionMax) * item.info.condition.max;
            if (doscrap && source != null && source.scrapAmount > 0) {
                var sc = ItemManager.Create(scrap, source.scrapAmount, 0);
                if (!sc.MoveToContainer(container)) sc.Remove(0f);
            }
        }
        static BasePlayer FindPlayerByName(string name) {
            BasePlayer result = null;
            foreach (BasePlayer current in BasePlayer.activePlayerList) {
                if (current.displayName.Equals(name, StringComparison.OrdinalIgnoreCase) || current.UserIDString.Contains(name, CompareOptions.OrdinalIgnoreCase) || current.displayName.Contains(name, CompareOptions.OrdinalIgnoreCase)) result = current;
            }
            return result;
        }
        public bool Isweapon(int i, Item item) {
            if (i != 0) item = ItemManager.CreateByItemID(i, 1);
            var held = item?.GetHeldEntity();
            bool weapon = item?.info?.category == ItemCategory.Weapon || (held != null && (held as ThrownWeapon || held as BaseMelee || held as TorchWeapon));
            if (i != 0 && item != null) item.Remove();
            return weapon;
        }
#endregion
#region Hooks
        bool newsave = false;
        void OnNewSave(string filename) => newsave = true;
        object OnNpcKits(ulong userID) => NPCPlayers.ContainsKey(userID) ? true : (object)null;
        object OnNpcDuck(global : : HumanNPC npc) => NPCPlayers.ContainsKey(npc.userID) ? true : (object)null;
        private object CanEntityBeHostile(ScientistNPC npc) => npc != null && NPCPlayers.ContainsKey(npc.userID) ? true : (object)null;
        private object CanBeTargeted(NPCPlayer npc, BaseEntity entity) {
            BotData bData;
            if (NPCPlayers.TryGetValue(npc.userID, out bData)) if (bData.profile.Other.WeaponTrap_Safe) return false;
            return null;
        }
        private object CanBradleyApcTarget(BradleyAPC bradley, NPCPlayer npc) {
            if (Convoy && (bool)Convoy?.Call("IsConvoyVehicle", bradley)) return null;
            BotData bData;
            if (NPCPlayers.TryGetValue(npc.userID, out bData)) return !bData.profile.Other.APC_Safe;
            return null;
        }
        void OnEntitySpawned(BasePlayer player) => NextTick(() => {
            ProcessHumanNPC(player);
        }
        );
        private void OnEntitySpawned(BradleyAPC apc) => SetupAPC(apc);
        void SetupAPC(BradleyAPC apc) {
            if (apc != null) apc.InvokeRepeating(() => UpdateTargetList(apc, Convoy && (bool)Convoy?.Call("IsConvoyVehicle", apc)), 0f, 2f);
        }
        public void UpdateTargetList(BradleyAPC apc, bool convoy) {
            List<BaseEntity> list = Pool.Get<List<BaseEntity>>();
            Vis.Entities<BaseEntity>(apc.transform.position, apc.searchRange, list, 133120, QueryTriggerInteraction.Collide);
            BotData bData;
            foreach (BaseEntity baseEntity in list) {
                if ((ConVar.AI.ignoreplayers && !baseEntity.IsNpc) || !(baseEntity is BasePlayer)) continue;
                BasePlayer basePlayer = baseEntity as BasePlayer;
                if (basePlayer is HumanNPC || basePlayer is NPCPlayer) {
                    bData = null;
                    if (NPCPlayers.TryGetValue(basePlayer.userID, out bData)) {
                        if (!convoy && bData.profile.Other.APC_Safe) continue;
                    }
                    else continue;
                }
                if (basePlayer.IsDead() || basePlayer.InSafeZone() && !basePlayer.IsHostile() || !apc.VisibilityTest(baseEntity)) {
                    continue;
                }
                bool flag = false;
                foreach (BradleyAPC.TargetInfo targetInfo in apc.targetList) {
                    if (targetInfo.entity != baseEntity) continue;
                    targetInfo.lastSeenTime = Time.time;
                    flag = true;
                    break;
                }
                if (flag) continue;
                BradleyAPC.TargetInfo targetInfo1 = new BradleyAPC.TargetInfo();
                targetInfo1.Setup(baseEntity, Time.time);
                apc.targetList.Add(targetInfo1);
            }
            for (int i = apc.targetList.Count - 1; i >= 0; i--) {
                BradleyAPC.TargetInfo item = apc.targetList[i];
                BasePlayer basePlayer1 = item.entity as BasePlayer;
                if (item.entity == null || Time.time - item.lastSeenTime > apc.memoryDuration || basePlayer1.IsDead() || (basePlayer1.InSafeZone() && !basePlayer1.IsHostile()) || (ConVar.AI.ignoreplayers && !basePlayer1.IsNpc)) apc.targetList.Remove(item);
            }
            list.Clear();
            Pool.FreeUnmanaged<BaseEntity>(ref list);
            //Pool.FreeList<BaseEntity>(ref list);
            apc.targetList.Sort(new Comparison<BradleyAPC.TargetInfo>(apc.SortTargets));
        }
        List<BaseEntity> LiveGrenades = new List<BaseEntity>();
        object CanWaterBallSplash(ItemDefinition liquidDef, Vector3 position, float radius, int amount) {
            foreach (var entity in LiveGrenades) if (entity != null && !entity.IsDestroyed && entity?.transform != null) if (Vector3.Distance(entity.transform.position, position) < radius + 1) return false;
            return null;
        }
        object OnEntityTakeDamage(BaseHelicopter heli, HitInfo info) => info?.InitiatorPlayer != null && NPCPlayers.ContainsKey(info.InitiatorPlayer.userID) ? true : (object)null;
        object OnEntityTakeDamage(ScientistNPC player, HitInfo info) {
            if (player == null || info == null) return null;
            BotData bData1;
            NPCPlayers.TryGetValue(player.userID, out bData1);
            if (bData1?.profile == null) return null;
            if (info?.Initiator == player || (!configData.Global.Animal_Safe && info?.Initiator is BaseAnimalNPC)) return true;
            if (bData1.invincible || (bData1.profile.Other.Fire_Safe && info.damageTypes.GetMajorityDamageType() == Rust.DamageType.Heat)) return true;
            if (bData1.profile.Behaviour.NPCs_Defend_Against_Drones) {
                if (info.Initiator is Drone) {
                    bData1.CurrentEntity = info.Initiator as Drone;
                    return null;
                }
                if (info.Initiator is AutoTurret) {
                    var sphere = info.Initiator.GetParentEntity() as SphereEntity;
                    if (sphere != null) {
                        bData1.CurrentEntity = sphere.GetParentEntity() as Drone;
                        return null;
                    }
                }
            }
            if (info.InitiatorPlayer != null) {
                if (bData1.profile.Behaviour.Friendly_Fire_Safe && NPCPlayers.ContainsKey(info.InitiatorPlayer.userID) && info.InitiatorPlayer != bData1.CurrentTarget) return true;
                if (bData1.brain != null) {
                    info.damageTypes.ScaleAll((float)bData1.profile.Spawn.Bot_Take_Damage_Percent / 100f);
                    if (bData1.inAir) {
                        if (bData1.profile.Other.Invincible_Whilst_Chuting) return true;
                        info.damageTypes.ScaleAll(10);
                    }
                    if (bData1.profile.Behaviour.Respect_Safe_Zones && player.InSafeZone()) return true;
                    if (info.InitiatorPlayer != bData1.CurrentTarget && Vector3.Distance(info.InitiatorPlayer.transform.position, player.transform.position) >= bData1.profile.Other.Immune_From_Damage_Beyond) return true;
                    if (player.lastAttacker == info.InitiatorPlayer && (info.InitiatorPlayer == bData1.CurrentTarget || bData1.Targets.ContainsKey(info.InitiatorPlayer) && (!player.limitNetworking && !player._limitedNetworking))) SetTarget(bData1, bData1.brain, info.InitiatorPlayer, true);
                    else if (bData1.WantsAttack(info.InitiatorPlayer, true)) {
                        SetTarget(bData1, bData1.brain, info.InitiatorPlayer, true);
                        if (configData.Global.NPCs_Assist_NPCs && info.InitiatorPlayer.net?.connection != null) {
                            // if (check weapon is quiet or silenced)
                            List<BotData> bDatas = Pool.Get<List<BotData>>();
                            Vis.Components<BotData>(player.transform.position, Mathf.Min(300, bData1.profile.Behaviour.Assist_Sense_Range), bDatas);
                            foreach (var bData in bDatas) {
                                if (bData.brain == null || bData == bData1) continue;
                                if (info.InitiatorPlayer == bData.CurrentTarget || bData.profilename == bData1.profilename || bData.Targets.ContainsKey(info.InitiatorPlayer)) //bData.WantsAttack(info.InitiatorPlayer, true))
                                {
                                    timer.Once(Mathf.Min(5, Vector3.Distance(bData.transform.position, bData1.transform.position) / 20f), () => {
                                        if (bData?.profile != null && bData.brain?.Senses != null && info.InitiatorPlayer != null && !info.InitiatorPlayer.IsDead()) {
                                            SetTarget(bData, bData.brain, info.InitiatorPlayer, false);
                                            bData.npc.Brain.Senses.Memory.SetKnown(info.InitiatorPlayer, bData.npc, bData.npc.Brain.Senses);
                                            // added not tested
                                        }
                                    }
                                    );
                                }
                                //else
                                //{
                                //    No LOS? SetDestination(...//}
                            }
                            bDatas.Clear();
                            Pool.FreeUnmanaged<BotData>(ref bDatas);
                            //Pool.FreeList<BotData>(ref bDatas);
                        }
                    }
                }
                if (info != null && bData1.profile.Other.Die_Instantly_From_Headshot && info.isHeadshot) {
                    var weap = info?.Weapon?.GetItem()?.info?.shortname;
                    var weaps = bData1.profile.Other.Instant_Death_From_Headshot_Allowed_Weapons;
                    if (weaps.Count == 0 || (weap != null && weaps.Contains(weap))) {
                        if (!bData1.profile.Other.Require_Two_Headshots || Headshots.Contains(player.userID)) info.damageTypes.Set(0, player.health);
                        else Headshots.Add(player.userID);
                        return null;
                    }
                }
            }
            if (configData.Global.Pve_Safe) {
                var att = info.Initiator?.ToString();
                if (att == null && info.damageTypes.GetMajorityDamageType() == Rust.DamageType.Bullet) return true;
                if (att == null || att.Contains("cactus") || att.Contains("barricade")) return true;
                if (info.damageTypes.GetMajorityDamageType() == Rust.DamageType.ElectricShock) return true;
            }
            return null;
        }
        public List<ulong> Headshots = new List<ulong>();
        void SetTarget(BotData bData, BaseAIBrain brain, BasePlayer target, bool delay) {
            brain.Navigator.SetFacingDirectionEntity(target);
            if (delay) {
                timer.Once(random.Next(2, 15) / 10f, () => {
                    bData.Addto(bData.Players, target);
                    bData.Addto(bData.Targets, target);
                    bData.CurrentTarget = target;
                }
                );
            }
            else {
                bData.Addto(bData.Players, target);
                bData.Addto(bData.Targets, target);
                bData.CurrentTarget = target;
            }
        }
        private void OnTimedExplosiveExplode(TimedExplosive exp, Vector3 pos) {
            if (exp?.ShortPrefabName != "grenade.flashbang.deployed") return;
            List<BotData> brs = Pool.Get<List<BotData>>();
            Vis.Components<BotData>(pos, 10f, brs);
            foreach (var npc in brs) {
                if (npc?.BlindedTime != null && Vector2.Angle(npc.npc.eyes.transform.forward, pos - npc.transform.position) < 90)  // Vector3.Angle(pos - npc.transform.position, npc.npc.eyes.BodyForward()) < 90
                npc.BlindedTime = Time.time + 5f;
            }
            brs.Clear();
            Pool.FreeUnmanaged<BotData>(ref brs);
        }
        object OnEntityKill(ScientistNPC npc) {
            if (npc == null || npc.IsDestroyed) return null;
            return !Unloading && npc?.gameObject?.name == "BotReSpawn" ? true : (object)null;
        }
        void OnPlayerDeath(BasePlayer player, HitInfo info) {
            if (player == null) return;
            if (HumanNPCs.Contains(player.userID)) HumanNPCs.Remove(player.userID);
            if (player?.net?.connection != null) DestroyMenu(player, true);
            ScientistNPC npc = player as ScientistNPC;
            if (npc != null) OnEntityKill(npc, info, info?.InitiatorPlayer != null);
        }
        Dictionary<ulong, ulong> BSCrates = new Dictionary<ulong, ulong>();
        void OnEntityKill(ScientistNPC npc, HitInfo info, bool killed) {
            if (npc?.userID != null && NPCPlayers.ContainsKey(npc.userID) && !botInventories.ContainsKey(npc.userID)) {
                botInventories.Add(npc.userID, null);
                if (Headshots.Contains(npc.userID)) Headshots.Remove(npc.userID);
                BotData bData;
                NPCPlayers.TryGetValue(npc.userID, out bData);
                if (bData == null || !Profiles.ContainsKey(bData?.profilename)) return;
                if (!bData.temporary) timer.Once(Mathf.Max(5, bData.profile.Death.Respawn_Timer * 60), () => bData.sg?.SpawnBot(1, bData.profile.type == ProfileType.Biome || bData.profile.Spawn.Change_SpawnPoint_On_Death ? null : bData.sp));
                if (killed) {
                    if (!info.InitiatorPlayer.IsNpc) {
                        if (bData.profile.Death.RustRewardsValue != 0) {
                            var weapon = info?.Weapon?.GetItem()?.info?.shortname ?? info?.WeaponPrefab?.ShortPrefabName ?? "";
                            RustRewards?.Call("GiveRustReward", info.InitiatorPlayer, 0, bData.profile.Death.RustRewardsValue, npc, weapon, Vector3.Distance(info.InitiatorPlayer.transform.position, npc.transform.position), null);
                        }
                        if (bData.profile.Death.XPerienceValue > 0) XPerience?.Call("GiveXP", info.InitiatorPlayer, bData.profile.Death.XPerienceValue);
                    }
                    if (bData.profile.Death.Spawn_Hackable_Death_Crate_Percent > 0 && bData.profile.Death.Spawn_Hackable_Death_Crate_Percent > GetRand(1, 101) && npc.WaterFactor() < 0.1f) {
                        var pos = npc.transform.position;
                        var ID = npc.userID.Get();
                        timer.Once(2f, () => {
                            if (DisplayNames.ContainsKey(ID)) DisplayNames.Remove(ID);
                            if (bData?.profile == null) return;
                            var Crate = (HackableLockedCrate)GameManager.server.CreateEntity(LockedCrate, pos + new Vector3(2, 3, 2), Quaternion.Euler(0, 0, 0));
                            Crate.Spawn();
                            BSCrates.Add(Crate.net.ID.Value, info?.InitiatorPlayer != null && !info.InitiatorPlayer.IsNpc && bData.profile.Death.Lock_Death_Crate_To_Killer_Player ? info.InitiatorPlayer.userID : 0);
                            Crate.hackSeconds = HackableLockedCrate.requiredHackSeconds - bData.profile.Death.Death_Crate_LockDuration * 60;
                            timer.Once(1.4f, () => {
                                if (Crate == null || bData?.profile == null) return;
                                if (CustomLoot && bData.profile.Death.Death_Crate_CustomLoot_Profile != string.Empty) {
                                    if (Crate != null)  ////Check
                                    {
                                        Crate.inventory.capacity = 36;
                                        Crate.onlyAcceptCategory = ItemCategory.All;
                                        Crate.SendNetworkUpdateImmediate();
                                        Crate.inventory.Clear();
                                        List<Item> loot = (List<Item>)CustomLoot?.Call("MakeLoot", bData.profile.Death.Death_Crate_CustomLoot_Profile);
                                        if (loot != null) foreach (var item in loot) if (!item.MoveToContainer(Crate.inventory, -1, true)) item.Remove();
                                    }
                                }
                            }
                            );
                        }
                        );
                    }
                    Interface.CallHook("OnBotReSpawnNPCKilled", npc, bData.profilename, bData.group, info);
                }
                Item activeItem = npc.GetActiveItem();
                if (activeItem != null && bData.profile.Death.Weapon_Drop_Percent > 0 && bData.profile.Death.Weapon_Drop_Percent >= GetRand(1, 101)) {
                    var numb = GetRand(Mathf.Min(bData.profile.Death.Min_Weapon_Drop_Condition_Percent, bData.profile.Death.Max_Weapon_Drop_Condition_Percent), bData.profile.Death.Max_Weapon_Drop_Condition_Percent);
                    numb = Convert.ToInt16((numb / 100f) * activeItem.maxCondition);
                    activeItem.condition = numb;
                    activeItem.Drop(npc.eyes.position, new Vector3(), new Quaternion());
                    npc.svActiveItemID = new ItemId();
                    npc.SendNetworkUpdate(BasePlayer.NetworkQueue.Update);
                }
                ItemContainer[] source = {
                    npc.inventory.containerMain, npc.inventory.containerWear, npc.inventory.containerBelt
                }
                ;
                Inv botInv = new Inv() {
                    profile = bData.profile, name = npc.displayName,
                }
                ;
                botInventories[npc.userID] = botInv;
                for (int i = 0; i < source.Length; i++) foreach (var item in source[i].itemList) {
                    botInv.inventory[i].Add(new InvContents {
                        ID = item.info.itemid, amount = item.amount, skinID = item.skin, name = item.name, text = item.text
                    }
                    );
                }
                botInv.sacr.ServerInitialize(null, 36);
                DeadNPCPlayerIds.Add(npc.userID, bData.profile.Other.Backpack_Duration * 60);
                no_of_AI--;
            }
        }
#endregion
#region Events
        List<ulong> CHCrates = new List<ulong>();
        List<CH47Helicopter> helis = new List<CH47Helicopter>();
        bool NearCH(HackableLockedCrate crate) {
            helis.Clear();
            Vis.Entities<CH47Helicopter>(crate.transform.position, 10f, helis);
            return helis.Any();
        }
        List<ulong> ORCrates = new List<ulong>();
        bool NearOR(HackableLockedCrate crate) {
            foreach (var entry in OilRigs) if (Vector3.Distance(crate.transform.position, entry) < 100) return true;
            return false;
        }
        bool ValidCrate(HackableLockedCrate crate) {
            if (crate.OwnerID != 0) return configData.Global.Allow_HackableCrates_With_OwnerID;
            if (CHCrates.Contains(crate.net.ID.Value)) return configData.Global.Allow_HackableCrates_From_CH47;
            if (ORCrates.Contains(crate.net.ID.Value)) return configData.Global.Allow_HackableCrates_At_Oilrig;
            if (crate.HasParent() || crate.transform?.parent != null) return configData.Global.Allow_Parented_HackedCrates;
            return configData.Global.Allow_All_Other_HackedCrates;
        }
        object CanHackCrate(BasePlayer player, HackableLockedCrate crate) => CanLootEntity(player, crate);
        object CanLootEntity(BasePlayer player, HackableLockedCrate crate) {
            if (crate?.net?.ID.Value == null) return null;
            ulong owner = 0;
            if (BSCrates.TryGetValue(crate.net.ID.Value, out owner)) if (owner != 0 && owner != player.userID) return true;
            return null;
        }
        void OnEntitySpawned(HackableLockedCrate crate) {
            if (!loaded || crate?.net?.ID == null) return;
            NextTick(() => {
                if (crate?.net?.ID == null || !loaded || BSCrates.ContainsKey(crate.net.ID.Value)) return;
                if (Interface.CallHook("OnBotReSpawnCrateDropped", crate) != null) return;
                if (NearCH(crate)) CHCrates.Add(crate.net.ID.Value);
                if (NearOR(crate)) ORCrates.Add(crate.net.ID.Value);
                var nearest = FindNearestDefault(crate.transform.position);
                if (nearest != null && nearest.Other.Block_Event_LockedCrate_Spawn) return;
                if (ValidCrate(crate)) DoEvent("LockedCrate_Spawn", crate.transform.position);
            }
            );
        }
        void OnCrateHack(HackableLockedCrate crate) {
            NextTick(() => {
                if (crate?.net?.ID == null || !loaded) return;
                if (Interface.CallHook("OnBotReSpawnCrateHackBegin", crate) != null) return;
                var nearest = FindNearestDefault(crate.transform.position);
                if (nearest != null && nearest.Other.Block_Event_LockedCrate_HackStart) return;
                if (ValidCrate(crate)) DoEvent("LockedCrate_HackStart", crate.transform.position);
            }
            );
        }
        void OnEntityDeath(BaseEntity entity) {
            if (entity == null || entity.transform == null || entity is BasePlayer) return;
            string prof = string.Empty;
            if (entity is BradleyAPC) {
                if (Interface.CallHook("OnBotReSpawnAPCKill", entity) != null) return;
                var nearest = FindNearestDefault(entity.transform.position);
                if (nearest != null && nearest.Other.Block_Event_APC_Kill) return;
                prof = "APC_Kill";
            }
            else if (entity is PatrolHelicopter) {
                if (Interface.CallHook("OnBotReSpawnPatrolHeliKill", entity) != null) return;
                var nearest = FindNearestDefault(entity.transform.position);
                if (nearest != null && nearest.Other.Block_Event_PatrolHeli_Kill) return;
                prof = "PatrolHeli_Kill";
            }
            else if (entity is CH47Helicopter) {
                if (Interface.CallHook("OnBotReSpawnCH47Kill", entity) != null) return;
                var nearest = FindNearestDefault(entity.transform.position);
                if (nearest != null && nearest.Other.Block_Event_CH47_Kill) return;
                prof = "CH47_Kill";
            }
            if (prof != string.Empty) DoEvent(prof, entity.transform.position);
        }
        void DoEvent(string name, Vector3 pos) {
            Profile profile = Profiles[name];
            if (profile.Spawn.AutoSpawn == true && GetPop(profile) > 0) {
                int quantity = GetPop(profile);
                if (profile.Spawn.AutoSpawn == true && quantity > 0) {
                    profile.Other.Location = pos;
                    CreateTempSpawnGroup(null, pos, name, profile, string.Empty, quantity);
                }
            }
        }
#endregion
#region SpawningHooks
        void OnEntitySpawned(DroppedItemContainer container) {
            NextTick(() => {
                if (!loaded || container?.playerSteamID == null || container.IsDestroyed || container.playerSteamID == 0) return;
                if (DeadNPCPlayerIds.ContainsKey(container.playerSteamID)) {
                    if (configData.Global.Remove_BackPacks_Percent >= GetRand(1, 101)) {
                        if (container != null && !container.IsDestroyed) container.Kill();
                    }
                    else {
                        container.CancelInvoke(container.RemoveMe);
                        timer.Once(DeadNPCPlayerIds[container.playerSteamID], () => {
                            if (container != null && !container.IsDestroyed) container?.Kill();
                        }
                        );
                    }
                    DeadNPCPlayerIds.Remove(container.playerSteamID);
                }
            }
            );
        }
        // TEST AND ADD
        //List<ulong> Ignore = new List<ulong>();
        //void OnCargoPlaneSignaled(CargoPlane plane, SupplySignal signal)
        //{
        //    if (!loaded || !configData.Global.Supply_Enabled || (configData.Global.Ignore_Skinned_Supply_Grenades && signal.skinID != 0))
        //        Ignore.Add(plane.net.ID.Value);
        //}
        //void OnSupplyDropDropped(SupplyDrop drop, CargoPlane plane)
        //{
        //    if (Ignore.Contains(plane.net.ID.Value))
        //    {
        //        Ignore.Remove(plane.net.ID.Value);
        //        Ignore.Add(drop.net.ID.Value);
        //        return;
        //    }
        //    DoDrop(drop, false);
        //}
        //void OnSupplyDropLanded(SupplyDrop drop)
        //{
        //    if (Ignore.Contains(drop.net.ID.Value))
        //    {
        //        Ignore.Remove(drop.net.ID.Value);
        //        return;
        //    }
        //    DoDrop(drop, true);
        //}
        //void DoDrop(SupplyDrop drop, bool landed)
        //{
        //    if (landed != configData.Global.Spawn_Airdrop_On_Landing)
        //        return;
        //    if (Interface.CallHook("OnBotReSpawnAirdrop", drop) != null)
        //        return;
        //    Profile profile = null;
        //    Profiles.TryGetValue("AirDrop", out profile);
        //    if (profile != null)
        //      
// ... [Code preview truncated due to length. Full source in attached file] ...

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