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

FREE BotSpawn : 1.6.8 1.6.8

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using Oxide.Core;
using Oxide.Core.Plugins;
using UnityEngine;
using Oxide.Game.Rust;
using System.Globalization;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using UnityEngine.SceneManagement;
using Facepunch;
using Rust;

namespace Oxide.Plugins

{
    [Info("BotSpawn", "Steenamaroo", "1.6.8", ResourceId = 2580)]

    [Description("Spawn tailored AI with kits at monuments, custom locations, or randomly.")]

    class BotSpawn : RustPlugin
    {
        [PluginReference]
        Plugin Vanish, Kits;

        const string permAllowed = "botspawn.allowed";
        bool HasPermission(string id, string perm) => permission.UserHasPermission(id, perm);
        int no_of_AI = 0;
        static System.Random random = new System.Random();

        public Dictionary<string, List<Vector3>> spawnLists = new Dictionary<string, List<Vector3>>();

        public Timer aridTimer;
        public Timer temperateTimer;
        public Timer tundraTimer;
        public Timer arcticTimer;

        bool isBiome(string name)
        {
            if (name == "BiomeArid" || name == "BiomeTemperate" || name == "BiomeTundra" || name == "BiomeArctic")
                return true;
            return false;
        }

        #region Data 
        class StoredData
        {
            public Dictionary<string, DataProfile> DataProfiles = new Dictionary<string, DataProfile>();
            public Dictionary<string, ProfileRelocation> MigrationDataDoNotEdit = new Dictionary<string, ProfileRelocation>();
            public StoredData()
            {
            }
        }

        ///////////////////////////////////////////////////////////////////MIGRATION INFO TO REMOVE in 1.6.7
        class StoredDataOld
        {
            public Dictionary<string, MonumentSettings> CustomProfiles = new Dictionary<string, MonumentSettings>();
            public StoredDataOld()
            {
            }
        }
        public class MonumentSettings
        {
            public bool AutoSpawn = false;
            public bool Murderer = false;
            public int Bots = 5;
            public int BotHealth = 100;
            public int Radius = 100;
            public List<string> Kit = new List<string>();
            public string BotNamePrefix = "";
            public List<string> BotNames = new List<string>();
            public int Bot_Accuracy = 4;
            public float Bot_Damage = 0.4f;
            public int Respawn_Timer = 60;
            public bool Disable_Radio = true;
            public float LocationX;
            public float LocationY;
            public float LocationZ;
            public int Roam_Range = 40;
            public bool Peace_Keeper = true;
            public int Peace_Keeper_Cool_Down = 5;
            public bool Weapon_Drop = true;
            public bool Keep_Default_Loadout = false;
            public bool Wipe_Belt = true;
            public bool Wipe_Clothing = true;
            public bool Allow_Rust_Loot = true;
            public int Suicide_Timer = 300;
            public bool Chute = false;
            public int Long_Attack_Distance = 120;
        }
        StoredDataOld storedDataOld;
        ///////////////////////////////////////////////////////////////////////////

        StoredData storedData;
        #endregion

        void Init()
        {
            JsonConvert.DefaultSettings = () => new JsonSerializerSettings
            {
                Formatting = Newtonsoft.Json.Formatting.Indented,
                ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
            };
            var filter = RustExtension.Filter.ToList();                                                                                                     //Thanks Fuji.:)
            filter.Add("cover points");
            filter.Add("resulted in a conflict");
            RustExtension.Filter = filter.ToArray();
            no_of_AI = 0;
            LoadConfigVariables();
        }

        void OnServerInitialized()
        {
            FindMonuments();
        }

        void Loaded()
        {
            spawnLists.Add("AridSpawns", new List<Vector3>());
            spawnLists.Add("TemperateSpawns", new List<Vector3>());
            spawnLists.Add("TundraSpawns", new List<Vector3>());
            spawnLists.Add("ArcticSpawns", new List<Vector3>()); 

            lang.RegisterMessages(messages, this);
            permission.RegisterPermission(permAllowed, this);

            storedData = Interface.Oxide.DataFileSystem.ReadObject<StoredData>("BotSpawn");

            ///////////////////////////////////////////////////////////////////////////MIGRATION INFO TO REMOVE in 1.6.7
            storedDataOld = Interface.Oxide.DataFileSystem.ReadObject<StoredDataOld>("BotSpawn");
            var oldDeser = JsonConvert.SerializeObject(storedDataOld);
            if (oldDeser.ToString().Length != 28 && oldDeser.ToString().Length != 26)
            {
                oldDeser = oldDeser.Replace(("\"CustomProfiles\":"), ("\"DataProfiles\":"));
                int lastPos = oldDeser.LastIndexOf('}');
                oldDeser = oldDeser.Insert(lastPos, ",\"MigrationDataDoNotEdit\":{}");
                var migratedData = JsonConvert.DeserializeObject<StoredData>(oldDeser);
                Interface.Oxide.DataFileSystem.WriteObject("BotSpawn", migratedData); 
                storedData = Interface.Oxide.DataFileSystem.ReadObject<StoredData>("BotSpawn");
                foreach (var profile in storedData.DataProfiles)
                {
                    storedData.MigrationDataDoNotEdit.Add(profile.Key, new ProfileRelocation());
                };
            }
            ///////////////////////////////////////////////////////////////////////////  
            SaveData();
        }
        void Unload()
        {
            var filter = RustExtension.Filter.ToList();
            filter.Remove("cover points");
            filter.Remove("resulted in a conflict");
            RustExtension.Filter = filter.ToArray();
            Wipe();
        }

        bool isAuth(BasePlayer player)
        {
            if (player.net.connection != null)
                if (player.net.connection.authLevel < 2)
                    return false;
            return true;
        }

        void UpdateRecords(NPCPlayerApex player)
        {
            if (TempRecord.NPCPlayers.Contains(player))
                TempRecord.NPCPlayers.Remove(player);
        }

        void Wipe()
        {
            foreach (var bot in TempRecord.NPCPlayers)
            {
                if (bot == null)
                    continue;
                else
                    bot.Kill();
            }
            TempRecord.NPCPlayers.Clear();
        }

        // Facepunch.RandomUsernames
        public static string Get(ulong v)                                                                                                                      //credit Fujikura.{
            return Facepunch.RandomUsernames.Get((int)(v % 2147483647uL));
        }

        #region BiomeSpawnsSetup
        void GenerateSpawnPoints(List<Vector3> spawnlist, string name, int number, Timer myTimer, int biomeNo)
        {
            int getBiomeAttempts = 0;
            myTimer = timer.Repeat(0.1f, 0, () =>
            {
                int halfish = Convert.ToInt16((ConVar.Server.worldsize / 2) / 1.1f);

                int x = x = random.Next(-halfish, halfish);
                int z = random.Next(-halfish, halfish);
                Vector3 randomSpot = new Vector3(x, 0, z);
                bool finished = true;

                if (spawnlist.Count < number)
                {
                    getBiomeAttempts++;
                    if (getBiomeAttempts > 50 && spawnlist.Count == 0)  
                    {
                        Puts($"Failed to find spawnpoints in {name}."); 
                        myTimer.Destroy();
                        return;
                    }

                    finished = false;
                    x = random.Next(-halfish, halfish);
                    z = random.Next(-halfish, halfish);
                    if (TerrainMeta.BiomeMap.GetBiome(randomSpot, biomeNo) > 0.5f
                        && CalculateGroundPos(new Vector3(randomSpot.x, 200, randomSpot.z), true) != new Vector3())
                        spawnlist.Add(CalculateGroundPos(new Vector3(randomSpot.x, 200, randomSpot.z), true));
                }
                if (finished)
                {
                    int i = 0;
                    timer.Repeat(2, number, () =>
                    {
                        SpawnBots(name, TempRecord.AllProfiles[name], "biome", null, spawnlist[i]);
                        i++;
                    });
                    myTimer.Destroy();
                }
            });
        }

        public static Vector3 CalculateGroundPos(Vector3 sourcePos, bool Biome)                                                                                                      //credit Wulf & Nogrod 
        {
            RaycastHit hitInfo;

            if (Physics.Raycast(sourcePos, Vector3.down, out hitInfo, 1000f, LayerMask.GetMask("Terrain", "World", "Construction", "Water"), QueryTriggerInteraction.Ignore))
            {
                if (hitInfo.collider.tag == "Main Terrain" && Biome)
                {
                    sourcePos.y = hitInfo.point.y;
                    sourcePos.y = Mathf.Max(sourcePos.y, TerrainMeta.HeightMap.GetHeight(sourcePos));
                    return sourcePos;
                }
                if (!Biome)
                {
                    sourcePos.y = hitInfo.point.y;
                    sourcePos.y = Mathf.Max(sourcePos.y, TerrainMeta.HeightMap.GetHeight(sourcePos));
                    return sourcePos;
                }
            }
            return new Vector3();
        }

        Vector3 TryGetSpawn(Vector3 centerPoint, int radius)
        {
            int attempts = 0;
            var spawnPoint = new Vector3();

            while (attempts < 50 && spawnPoint == new Vector3())
            {
                attempts++;
                RaycastHit hitInfo;

                int X = random.Next((-radius), (radius));
                int Z = random.Next((-radius), (radius));
                if (CalculateGroundPos(new Vector3((centerPoint.x + X), 200, (centerPoint.z + Z)), false) != new Vector3())
                {
                    spawnPoint = CalculateGroundPos(new Vector3(centerPoint.x + X, 200, centerPoint.z + Z), false);
                }
            }
            return spawnPoint;
        }
        #endregion


        #region BotSetup
        void AttackPlayer(Vector3 location, string name, DataProfile profile, string group)
        {
            timer.Repeat(1f, profile.Bots, () => SpawnBots(name, profile, "Attack", group, location));
        }

        void SpawnBots(string name, DataProfile zone, string type, string group, Vector3 location)
        {
            var pos = new Vector3(zone.LocationX, zone.LocationY, zone.LocationZ);
            var finalPoint = new Vector3();
            if (location != new Vector3())
                pos = location;

            var randomTerrainPoint = TryGetSpawn(pos, zone.Radius);
            if (randomTerrainPoint == new Vector3())
            {
                Puts($"Failed to find a suitable spawnpoint : Moving on to next.{name}");
                return;
            }
            else
            {
                finalPoint = randomTerrainPoint;
            }

            if (zone.Chute)
            {
                if (type == "AirDrop")
                    finalPoint = (pos - new Vector3(0, -40, 0));
                else
                    finalPoint = new Vector3(randomTerrainPoint.x, 200, (randomTerrainPoint.z));
            }

            NPCPlayer entity = (NPCPlayer)InstantiateSci(finalPoint, Quaternion.Euler(0, 0, 0), zone.Murderer);
            var botapex = entity.GetComponent<NPCPlayerApex>();

            TempRecord.NPCPlayers.Add(botapex);

            botapex.Spawn();
            botapex.SendNetworkUpdateImmediate();

            no_of_AI++;

            var bData = botapex.gameObject.AddComponent<botData>();
            if (group != null)
                bData.group = group;
            else
                bData.group = null;

            bData.spawnPoint = CalculateGroundPos(randomTerrainPoint, false);
            bData.accuracy = zone.Bot_Accuracy;
            bData.damage = zone.Bot_Damage;
            bData.health = zone.BotHealth;
            bData.monumentName = name;
            bData.respawn = true;
            bData.roamRange = zone.Roam_Range;
            bData.dropweapon = zone.Weapon_Drop;
            bData.keepAttire = zone.Keep_Default_Loadout;
            bData.peaceKeeper = zone.Peace_Keeper;
            bData.chute = zone.Chute;
            bData.peaceKeeper_CoolDown = zone.Peace_Keeper_Cool_Down;
            if (type == "biome")
                bData.biome = true;
            if (zone.Long_Attack_Distance < 55) zone.Long_Attack_Distance = 55;
            bData.LongRangeAttack = zone.Long_Attack_Distance;

            if (zone.Chute)
                addChute(botapex, finalPoint);

            int kitRnd;
            kitRnd = random.Next(zone.Kit.Count);

            if (zone.BotNames.Count == zone.Kit.Count && zone.Kit.Count != 0)
                setName(zone, botapex, kitRnd);
            else
                setName(zone, botapex, random.Next(zone.BotNames.Count));

            giveKit(botapex, zone, kitRnd);

            sortWeapons(botapex);

            int suicInt = random.Next((zone.Suicide_Timer), (zone.Suicide_Timer + 10));                                        //slightly randomise suicide de-spawn time
            if (type == "AirDrop" || type == "Attack")
            {
                bData.respawn = false;
                runSuicide(botapex, suicInt);
            }

            if (zone.Disable_Radio)
                botapex.RadioEffect = new GameObjectRef();

            botapex.Stats.VisionRange = zone.Long_Attack_Distance + 20f; // to allow out of range attack over ride  

            if (!zone.Murderer)
            {
                timer.Once(4, () =>
                {
                    if (botapex != null)
                    {
                        botapex.Stats.IsMobile = true;
                        botapex.SetFact(NPCPlayerApex.Facts.IsRoamReady, 1, true, true);
                        botapex.SetFact(NPCPlayerApex.Facts.IsMoving, 1, true, true);
                    }
                });
            }
        }

        BaseEntity InstantiateSci(Vector3 position, Quaternion rotation, bool murd)                                                                            //Spawn population spam fix - credit Fujikura
        {
            string prefabname = "assets/prefabs/npc/scientist/scientist.prefab";
            if (murd)
                prefabname = "assets/prefabs/npc/murderer/murderer.prefab";

            var prefab = GameManager.server.FindPrefab(prefabname);
            GameObject gameObject = Instantiate.GameObject(prefab, position, rotation);
            gameObject.name = prefabname;
            SceneManager.MoveGameObjectToScene(gameObject, Rust.Server.EntityScene);
            if (gameObject.GetComponent<Spawnable>())
                UnityEngine.Object.Destroy(gameObject.GetComponent<Spawnable>());
            if (!gameObject.activeSelf)
                gameObject.SetActive(true);
            BaseEntity component = gameObject.GetComponent<BaseEntity>();
            return component;
        }

        void addChute(NPCPlayerApex botapex, Vector3 newPos)
        {
            float wind = random.Next(0, 50);
            float fall = random.Next(40, 80);
            var rb = botapex.gameObject.GetComponent<Rigidbody>();
            rb.isKinematic = false;
            rb.useGravity = false;
            rb.drag = 0f;
            botapex.gameObject.layer = 3;

            rb.velocity = new Vector3((botapex.transform.forward.x * (wind / 20f)), 0, (botapex.transform.forward * (wind / 20f)).z) + new Vector3(0, -(fall / 10f), 0);

            var col = botapex.gameObject.AddComponent<BoxCollider>();
            col.size = new Vector3(1, 0.5f, 1);  //feet above ground

            var Chute = GameManager.server.CreateEntity("assets/prefabs/misc/parachute/parachute.prefab", newPos, Quaternion.Euler(0, 0, 0));
            Chute.gameObject.Identity();
            Chute.SetParent(botapex, "parachute");
            Chute.Spawn();
        }

        void setName(DataProfile zone, NPCPlayerApex botapex, int number)
        {
            if (zone.BotNames.Count == 0 || zone.BotNames.Count <= number)
            {
                botapex.displayName = Get(botapex.userID);
                botapex.displayName = char.ToUpper(botapex.displayName[0]) + botapex.displayName.Substring(1);
            }
            else if (zone.BotNames[number] == "")
            {
                botapex.displayName = Get(botapex.userID);
                botapex.displayName = char.ToUpper(botapex.displayName[0]) + botapex.displayName.Substring(1);
            }
            else
                botapex.displayName = zone.BotNames[number];

            if (zone.BotNamePrefix != "")
                botapex.displayName = zone.BotNamePrefix + " " + botapex.displayName;
        } 

        void giveKit(NPCPlayerApex botapex, DataProfile zone, int kitRnd)
        {
            var bData = botapex.GetComponent<botData>();

            if (zone.Kit.Count != 0)
            {
                if (zone.Kit[kitRnd] != null)  
                {
                    object checkKit = (Kits.CallHook("GetKitInfo", zone.Kit[kitRnd], true));
                    if (checkKit == null) 
                    {
                        if (zone.Murderer)
                            PrintWarning($"Kit {zone.Kit[kitRnd]} does not exist - Spawning default Murderer.");
                        else
                            PrintWarning($"Kit {zone.Kit[kitRnd]} does not exist - Spawning default Scientist.");
                    }
                    else
                    {
                        bool weaponInBelt = false;
                        if (checkKit != null && checkKit is JObject)
                        {
                            JObject kitContents = checkKit as JObject;

                            JArray items = kitContents["items"] as JArray;
                            foreach (var weap in items)
                            {
                                JObject item = weap as JObject;
                                if (item["container"].ToString() == "belt")
                                    weaponInBelt = true;                                                                                                    //doesn't actually check for weapons - just any item.}
                        }
                        if (!weaponInBelt)
                        {
                            if (zone.Murderer)
                                PrintWarning($"Kit {zone.Kit[kitRnd]} has no items in belt - Spawning default Murderer.");
                            else
                                PrintWarning($"Kit {zone.Kit[kitRnd]} does not exist - Spawning default Scientist.");
                        }
                        else
                        {
                            if (bData.keepAttire == false)
                                botapex.inventory.Strip();
                            Kits.Call($"GiveKit", botapex, zone.Kit[kitRnd], true);
                            if (!(kitList.ContainsKey(botapex.userID)))
                            {
                                kitList.Add(botapex.userID, new kitData
                                {
                                    Kit = zone.Kit[kitRnd],
                                    Wipe_Belt = zone.Wipe_Belt,
                                    Wipe_Clothing = zone.Wipe_Clothing,
                                    Allow_Rust_Loot = zone.Allow_Rust_Loot,
                                });
                            }
                        }
                    }
                }
            }
            else
            {
                if (!(kitList.ContainsKey(botapex.userID)))
                {
                    kitList.Add(botapex.userID, new kitData
                    {
                        Kit = "",
                        Wipe_Belt = zone.Wipe_Belt,
                        Wipe_Clothing = zone.Wipe_Clothing,
                        Allow_Rust_Loot = zone.Allow_Rust_Loot,
                    });
                }
            }
        }

        void sortWeapons(NPCPlayerApex botapex)
        {
            var bData = botapex.GetComponent<botData>();
            foreach (Item item in botapex.inventory.containerBelt.itemList)                                                                                 //store organised weapons lists
            {
                var held = item.GetHeldEntity();
                if (held as HeldEntity != null)
                {
                    if (held.name.Contains("bow") || held.name.Contains("launcher"))
                        continue;
                    if (held as BaseMelee != null || held as TorchWeapon != null)
                        bData.MeleeWeapons.Add(item);
                    else
                    {
                        if (held as BaseProjectile != null)
                        {
                            bData.AllProjectiles.Add(item);
                            if (held.name.Contains("m92") || held.name.Contains("pistol") || held.name.Contains("python") || held.name.Contains("waterpipe"))
                                bData.CloseRangeWeapons.Add(item);
                            else if (held.name.Contains("bolt"))
                                bData.LongRangeWeapons.Add(item);
                            else
                                bData.MediumRangeWeapons.Add(item);
                        }
                    }
                }
            }
        }

        void runSuicide(NPCPlayerApex botapex, int suicInt)
        {
            if (TempRecord.NPCPlayers.Contains(botapex))
            {
                timer.Once(suicInt, () =>
                {
                    if (botapex != null)
                    {
                        if (botapex.AttackTarget != null && Vector3.Distance(botapex.transform.position, botapex.AttackTarget.transform.position) < 10 && botapex.GetNavAgent.isOnNavMesh)
                        {
                            if (botapex.AttackTarget != null)
                            {
                                var position = botapex.AttackTarget.transform.position;
                                botapex.svActiveItemID = 0;
                                botapex.SendNetworkUpdate(BasePlayer.NetworkQueue.Update);
                                botapex.inventory.UpdatedVisibleHolsteredItems();
                                timer.Repeat(0.05f, 100, () =>
                                {
                                    if (botapex == null) return;
                                    botapex.SetDestination(position);
                                });
                            }
                        }
                        timer.Once(4, () =>
                        {
                            if (botapex == null) return;
                            Effect.server.Run("assets/prefabs/weapons/rocketlauncher/effects/rocket_explosion.prefab", botapex.transform.position);
                            HitInfo nullHit = new HitInfo();
                            nullHit.damageTypes.Add(Rust.DamageType.Explosion, 10000);
                            botapex.IsInvinsible = false;
                            botapex.Die(nullHit);
                        }
                        );
                    }
                });
            }
        }
        #endregion

        static BasePlayer FindPlayerByName(string name)
        {
            BasePlayer result = null;
            foreach (BasePlayer current in BasePlayer.activePlayerList)
            {
                if (current.displayName.Equals(name, StringComparison.OrdinalIgnoreCase))
                {
                    BasePlayer result2 = current;
                    return result2;
                }
                if (current.UserIDString.Contains(name, CompareOptions.OrdinalIgnoreCase))
                {
                    BasePlayer result2 = current;
                    return result2;
                }
                if (current.displayName.Contains(name, CompareOptions.OrdinalIgnoreCase))
                {
                    result = current;
                }
            }
            return result;
        }

        private void OnEntityKill(BaseNetworkable entity)
        {
            NPCPlayerApex npc = entity.GetComponent<NPCPlayerApex>();
            if (npc != null && npc is NPCMurderer) 
                NPCSensesLoadBalancer.NpcSensesLoadBalancer.Remove(npc);
        }

        #region Hooks
        object OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info)
        {
            var botMelee = info.Initiator as BaseMelee;
            bool melee = false;
            if (botMelee != null)
            {
                melee = true;
                info.Initiator = botMelee.GetOwnerPlayer();
            }
            NPCPlayerApex bot = null;

            if (entity is NPCPlayerApex)
            {
                bot = entity as NPCPlayerApex;

                if (!TempRecord.NPCPlayers.Contains(bot))
                    return null;
                var bData = bot.GetComponent<botData>();
                if (info.Initiator?.ToString() == null && configData.Global.Pve_Safe)
                    info.damageTypes.ScaleAll(0);
                if (info.Initiator is BasePlayer && !(info.Initiator is NPCPlayer))
                {
                    var canNetwork = Vanish?.Call("IsInvisible", info.Initiator);                                                                       //bots wont retaliate to vanished players
                    if ((canNetwork is bool))
                        if ((bool)canNetwork)
                            info.Initiator = null;

                    if (bData.peaceKeeper)                                                                                                               //prevent melee farming with peacekeeper on
                    {
                        var heldMelee = info.Weapon as BaseMelee;
                        var heldTorchWeapon = info.Weapon as TorchWeapon;
                        if (heldMelee != null || heldTorchWeapon != null)
                            info.damageTypes.ScaleAll(0);
                    }
                }
                float multiplier = 100f / bData.health;
                info.damageTypes.ScaleAll(multiplier);
            }

            if (info?.Initiator is NPCPlayer && entity is BasePlayer)                                                                                       //add in bot accuracy
            {
                var attacker = info.Initiator as NPCPlayerApex;

                if (TempRecord.NPCPlayers.Contains(attacker))
                {
                    var bData = attacker.GetComponent<botData>();
                    int rand = random.Next(1, 100);
                    float distance = (Vector3.Distance(info.Initiator.transform.position, entity.transform.position));

                    var newAccuracy = (bData.accuracy * 10f);
                    var newDamage = (bData.damage);
                    if (distance > 100f)
                    {
                        newAccuracy = ((bData.accuracy * 10f) / (distance / 100f));
                        newDamage = bData.damage / (distance / 100f);
                    }
                    if (!melee && newAccuracy < rand)                                                                                                          //scale bot attack damage
                    {
                        return true;
                    }
                    else
                    {
                        info.damageTypes.ScaleAll(newDamage);
                        return null;
                    }
                }
            }
            return null;
        }

        void OnPlayerDie(BasePlayer player)
        {
            string respawnLocationName = "";
            NPCPlayerApex Scientist = null;
            if (player is NPCPlayerApex)
            {
                Scientist = player as NPCPlayerApex;
                if (!TempRecord.NPCPlayers.Contains(Scientist))
                    return;

                if (TempRecord.NPCPlayers.Contains(Scientist))
                {
                    var bData = Scientist.GetComponent<botData>();
                    Item activeItem = player.GetActiveItem();
                    if (bData.dropweapon == true && activeItem != null)
                    {
                        using (TimeWarning timeWarning = TimeWarning.New("PlayerBelt.DropActive", 0.1f))
                        {
                            activeItem.Drop(player.eyes.position, new Vector3(), new Quaternion());
                            player.svActiveItemID = 0;
                            player.SendNetworkUpdate(BasePlayer.NetworkQueue.Update);
                            kitRemoveList.Add(player.userID, activeItem.info.name);
                        }
                    }
                    no_of_AI--;
                    respawnLocationName = bData.monumentName;
                    DeadNPCPlayerIds.Add(Scientist.userID);
                    if (TempRecord.AllProfiles[respawnLocationName].Disable_Radio == true)
                        Scientist.DeathEffect = new GameObjectRef();                                                                                               //kill radio effects

                    if (bData.respawn == false)
                    {
                        UnityEngine.Object.Destroy(Scientist.GetComponent<botData>());
                        UpdateRecords(Scientist);
                        return;
                    }
                    if (bData.biome)
                    {
                        List<Vector3> spawnList = new List<Vector3>();

                        if (spawnLists.ContainsKey(bData.monumentName))
                        {
                            spawnList = spawnLists[bData.monumentName];
                            int spawnPos = random.Next(spawnList.Count);
                            SpawnBots(bData.monumentName, TempRecord.AllProfiles[bData.monumentName], "biome", null, spawnList[spawnPos]);
                            return;
                        }
                        else return;
                    }
                    foreach (var profile in TempRecord.AllProfiles)
                    {
                        timer.Once(profile.Value.Respawn_Timer, () => {
                            if (profile.Key == respawnLocationName)
                            {
                                SpawnBots(profile.Key, profile.Value, null, null, new Vector3());
                            }
                        });
                        UnityEngine.Object.Destroy(Scientist.GetComponent<botData>());
                        UpdateRecords(Scientist);
                    }
                }
            }
        }

        void OnEntitySpawned(BaseEntity entity) // handles smoke signals, backpacks, corpses(applying kit)
        {
            NPCPlayerApex npc = entity.GetComponent<NPCPlayerApex>();
            if (npc != null && npc is NPCMurderer)
                npc.NewAI = false;
            
            var KitDetails = new kitData();
            if (entity != null)
            {
                if (entity is NPCPlayerCorpse)
                {
                    var corpse = entity as NPCPlayerCorpse;
                    corpse.ResetRemovalTime(configData.Global.Corpse_Duration);

                    if (kitList.ContainsKey(corpse.playerSteamID))
                    {
                        KitDetails = kitList[corpse.playerSteamID];
                        NextTick(() =>
                        {
                            if (corpse == null)
                                return;
                            if (!KitDetails.Allow_Rust_Loot)
                            {
                                corpse.containers[0].Clear();
                                corpse.containers[1].Clear();
                                corpse.containers[2].Clear();
                            }
                            if (KitDetails.Kit != "")
                            {
                                string[] checkKit = (Kits.CallHook("GetKitContents", KitDetails.Kit)) as string[];

                                var tempbody = GameManager.server.CreateEntity("assets/prefabs/player/player.prefab", (corpse.transform.position - new Vector3(0, -100, 0)), corpse.transform.rotation).ToPlayer();
                                tempbody.Spawn();

                                Kits?.Call($"GiveKit", tempbody, KitDetails.Kit, true);

                                var source = new ItemContainer[] { tempbody.inventory.containerMain, tempbody.inventory.containerWear, tempbody.inventory.containerBelt };

                                for (int i = 0; i < (int)source.Length; i++)
                                {
                                    Item[] array = source[i].itemList.ToArray();
                                    for (int j = 0; j < (int)array.Length; j++)
                                    {
                                        Item item = array[j];
                                        if (!item.MoveToContainer(corpse.containers[i], -1, true))
                                        {
                                            item.Remove(0f);
                                        }
                                    }
                                }
                                tempbody.Kill();
                            }
                            if (kitList[corpse.playerSteamID].Wipe_Belt)
                                corpse.containers[2].Clear();
                            else
                            if (kitRemoveList.ContainsKey(corpse.playerSteamID))
                            {
                                foreach (var thing in corpse.containers[2].itemList)                                                                            //If weapon drop is enabled, this removes the weapon from the corpse's inventory.{
                                    if (kitRemoveList[corpse.playerSteamID] == thing.info.name)
                                    {
                                        thing.Remove();
                                        kitRemoveList.Remove(corpse.playerSteamID);
                                        break;
                                    }
                                }
                            }

                            if (kitList[corpse.playerSteamID].Wipe_Clothing)
                            {
                                corpse.containers[1].Clear();
                            }

                            kitList.Remove(corpse.playerSteamID);
                        });
                    }
                }

                if (entity is DroppedItemContainer)
                {
                    NextTick(() =>
                    {
                        if (entity == null || entity.IsDestroyed) return;
                        var container = entity as DroppedItemContainer;

                        ulong ownerID = container.playerSteamID;
                        if (ownerID == 0) return;
                        if (configData.Global.Remove_BackPacks)
                        {
                            if (DeadNPCPlayerIds.Contains(ownerID))
                            {
                                entity.Kill();
                                DeadNPCPlayerIds.Remove(ownerID);
                                return;
                            }
                        }

                    });
                }

                if (entity.name.Contains("grenade.smoke.deployed"))
                    timer.Once(2.3f, () =>
                    {
                        if (entity != null)
                            smokeGrenades.Add(new Vector3(entity.transform.position.x, 0, entity.transform.position.z));
                    });

                if (!(entity.name.Contains("supply_drop")))
                    return;

                Vector3 dropLocation = new Vector3(entity.transform.position.x, 0, entity.transform.position.z);

                if (!(configData.Global.Supply_Enabled))
                {
                    foreach (var location in smokeGrenades)
                    {
                        if (Vector3.Distance(location, dropLocation) < 35f)
                        {
                            smokeGrenades.Remove(location);
                            return;
                        }
                    }
                }
                if (TempRecord.AllProfiles.ContainsKey("AirDrop"))
                {
                    var profile = TempRecord.AllProfiles["AirDrop"];
                    if (profile.AutoSpawn == true)
                    {
                        timer.Repeat(0.1f, profile.Bots, () =>
                        {
                            profile.LocationX = entity.transform.position.x;
                            profile.LocationY = entity.transform.position.y;
                            profile.LocationZ = entity.transform.position.z;
                            SpawnBots("AirDrop", profile, "AirDrop", null, new Vector3());
                        }
                        );
                    }
                }
            }
        }
        #endregion

        #region WeaponSwitching
        void SelectWeapon(NPCPlayerApex npcPlayer, BasePlayer victim, bool hasAttacker)
        {
            if (npcPlayer == null)
                return;

            if (npcPlayer.svActiveItemID == 0)
                return;

            var active = npcPlayer.GetActiveItem();
            HeldEntity heldEntity1 = null;

            if (active != null)
                heldEntity1 = active.GetHeldEntity() as HeldEntity;

            var bData = npcPlayer.GetComponent<botData>();

            if (hasAttacker == false)
            {
                List<int> weapons = new List<int>();                                                                                                    //check all their weapons
                foreach (Item item in npcPlayer.inventory.containerBelt.itemList)
                {
                    var held = item.GetHeldEntity();
                    if (held is BaseProjectile || held is BaseMelee || held is TorchWeapon)
                        weapons.Add(Convert.ToInt16(item.position));
                }

                if (weapons.Count == 0)
                {
                    PrintWarning(lang.GetMessage("noWeapon", this), bData.monumentName);
                    return;
                }
                int index = random.Next(weapons.Count);
                var currentTime = TOD_Sky.Instance.Cycle.Hour;

                if (currentTime > 20 || currentTime < 8)
                {
                    foreach (Item item in npcPlayer.inventory.containerBelt.itemList)
                    {
                        HeldEntity held = item.GetHeldEntity() as HeldEntity;

                        if (item.ToString().Contains("flashlight"))
                        {
                            if (heldEntity1 != null)
                                heldEntity1.SetHeld(false);
                            var UID = item.uid;

                            ChangeWeapon(npcPlayer, held, UID);
                            return;
                        }
                    }
                }
                else
                {
                    foreach (Item item in npcPlayer.inventory.containerBelt.itemList)                                                                   //pick one at random to start with
                    {
                        HeldEntity held = item.GetHeldEntity() as HeldEntity;

                        if (item.position == weapons[index])
                        {
                            if (heldEntity1 != null)
                                heldEntity1.SetHeld(false);
                            var UID = npcPlayer.inventory.containerBelt.GetSlot(weapons[index]).uid;

                            ChangeWeapon(npcPlayer, held, UID);
                            return;
                        }
                    }
                }
            }

            if (hasAttacker == true)
            {
                bData.canChangeWeapon++;

                if (bData.canChangeWeapon > 3)
                {
                    bData.canChangeWeapon = 0;
                    if (npcPlayer == null)
                        return;

                    if (heldEntity1 == null)
                        bData.currentWeaponRange = 0;

                    float distance = Vector3.Distance(npcPlayer.transform.position, victim.transform.position);
                    int noOfAvailableWeapons = 0;
                    int selectedWeapon;
                    Item chosenWeapon = null;
                    HeldEntity held = null;
                    int newCurrentRange = 0;
                    var currentTime = TOD_Sky.Instance.Cycle.Hour;
                    bool night = false;

                    if (currentTime > 20 || currentTime < 8)
                        night = true;

                    if (npcPlayer.AttackTarget == null && night)
                    {
                        foreach (var weap in bData.MeleeWeapons)
                        {
                            if (weap.ToString().Contains("flashlight"))
                            {
                                chosenWeapon = weap;
                                newCurrentRange = 1;
                            }
                        }
                    }
                    else
                    {
                        if (distance < 2f && bData.MeleeWeapons.Count != 0)
                        {
                            bData.enemyDistance = 1;
                            foreach (var weap in bData.MeleeWeapons)
                            {
                                noOfAvailableWeapons++;
                            }
                            if (noOfAvailableWeapons > 0)
                            {
                                selectedWeapon = random.Next(bData.MeleeWeapons.Count);
                                chosenWeapon = bData.MeleeWeapons[selectedWeapon];
                                newCurrentRange = 1;
                            }
                        }
                        else if (distance > 1f && distance < 20f && bData.CloseRangeWeapons != null)
                        {
                            bData.enemyDistance = 2;
                            foreach (var weap in bData.CloseRangeWeapons)
                            {
                                noOfAvailableWeapons++;
                            }
                            if (noOfAvailableWeapons > 0)
                            {
                                selectedWeapon = random.Next(bData.CloseRangeWeapons.Count);
                                chosenWeapon = bData.CloseRangeWeapons[selectedWeapon];
                                newCurrentRange = 2;
                            }
                            else
                            {
                                foreach (var weap in bData.MediumRangeWeapons)                                                                          //if no close weapon, prioritise medium
                                {
                                    noOfAvailableWeapons++;
                                }
                                if (noOfAvailableWeapons > 0)
                                {
                                    selectedWeapon = random.Next(bData.MediumRangeWeapons.Count);
                                    chosenWeapon = bData.MediumRangeWeapons[selectedWeapon];
                                    newCurrentRange = 3;
                                }
                            }
                        }
                        else if (distance > 19f && distance < 40f && bData.MediumRangeWeapons != null)
                        {
                            bData.enemyDistance = 3;
                            foreach (var weap in bData.MediumRangeWeapons)
                            {
                                noOfAvailableWeapons++;
                            }
                            if (noOfAvailableWeapons > 0)
                            {
                                selectedWeapon = random.Next(bData.MediumRangeWeapons.Count);
                                chosenWeapon = bData.MediumRangeWeapons[selectedWeapon];
                                newCurrentRange = 3;
                            }
                        }
                        else if (distance > 39 && bData.LongRangeWeapons != null)
                        {
                            bData.enemyDistance = 4;
                            foreach (var weap in bData.LongRangeWeapons)
                            {
                                noOfAvailableWeapons++;
                            }
                            if (noOfAvailableWeapons > 0)
                            {
                                selectedWeapon = random.Next(bData.LongRangeWeapons.Count);
                                chosenWeapon = bData.LongRangeWeapons[selectedWeapon];
                                newCurrentRange = 4;
                            }
                            else
                            {
                                foreach (var weap in bData.MediumRangeWeapons)                                                                          //if no long weapon, prioritise medium
                                {
                                    noOfAvailableWeapons++;
                                }
                                if (noOfAvailableWeapons > 0)
                                {
                                    selectedWeapon = random.Next(bData.MediumRangeWeapons.Count);
                                    chosenWeapon = bData.MediumRangeWeapons[selectedWeapon];
                                    newCurrentRange = 3;
                                }
                            }
                        }
                        if (chosenWeapon == null)                                                                                                       //if no weapon suited to range, pick any random bullet weapon
                        {                                                                                                                               //prevents sticking with melee @>2m when no pistol is available
                            bData.enemyDistance = 5;
                            if (heldEntity1 != null && bData.AllProjectiles.Contains(active))                                                           //prevents choosing a random weapon if the existing one is fine
                                return;
                            foreach (var weap in bData.AllProjectiles)
                            {
                                noOfAvailableWeapons++;
                            }
                      
// ... [Code preview truncated due to length. Full source in attached file] ...

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