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

FREE ZombieHorde : 0.1.13 0.1.13

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

namespace Oxide.Plugins
{
    [Info("ZombieHorde", "k1lly0u", "0.1.13", ResourceId = 0)]
    [Description("Ужастная орда зомби! Приобретено на Oxide-Russia.RU у Ernieleo")]
    class ZombieHorde : RustPlugin
    {
        #region Fields
        [PluginReference] Plugin Kits, Vanish, RandomSpawns, Spawns;

        private static ZombieHorde ins; 
        private List<HordeManager> managers = new List<HordeManager>();

        private SpawnSystem spawnSystem = SpawnSystem.None;

        private LootType lootType = LootType.Default;

        private List<Vector3> spawnPoints = new List<Vector3>();

        private Queue<HordeOrder> hordeQueue = new Queue<HordeOrder>();

        private Dictionary<ulong, InventoryData> deadMemberIds = new Dictionary<ulong, InventoryData>();

        private Dictionary<string, int> itemNameToId = new Dictionary<string, int>();

        private bool IsQueueRunning { get; set; } = false;

        private int groundLayer = LayerMask.GetMask("Terrain", "World");

        const string zombiePrefab = "assets/prefabs/npc/murderer/murderer.prefab";
        #endregion

        #region Oxide Hooks        
        private void OnServerInitialized()
        {
            ins = this;
            permission.RegisterPermission("zombiehorde.admin", this);
            permission.RegisterPermission("zombiehorde.ignore", this);

            itemNameToId = ItemManager.itemList.ToDictionary(x => x.shortname, y => y.itemid);

            if (!configData.Member.TargetedByTurrets)
                Unsubscribe(nameof(CanBeTargeted));

            lootType = ParseType<LootType>(configData.Member.Loot);
            if (lootType == LootType.Default)                            
                Unsubscribe(nameof(OnEntitySpawned));            

            if (!VerifySpawnSystem())
                return;

            FindMonuments();
        }

        private void Unload()
        {
            for (int i = managers.Count - 1; i >= 0; i--)            
                UnityEngine.Object.Destroy(managers.ElementAt(i));

            ins = null;
        }

        private void OnEntitySpawned(BaseNetworkable networkable)
        {
            NPCPlayerCorpse corpse = networkable.GetComponent<NPCPlayerCorpse>();
            if (corpse == null)
                return;

            if (lootType == LootType.Default)
                return;

            InventoryData inventoryData;

            if (!deadMemberIds.TryGetValue(corpse.playerSteamID, out inventoryData))
                return;

            deadMemberIds.Remove(corpse.playerSteamID);

            timer.In(2, () =>
            {
                if (inventoryData == null || lootType == LootType.Random)
                    FillLootContainer(corpse);
                else inventoryData.RestoreItemsTo(corpse);
            });            
        }

        private void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info)
        {
            if (entity == null)
                return;

            HordeMember hordeMember = entity.GetComponent<HordeMember>();
            if (hordeMember != null)
            {
                BasePlayer attacker = info.InitiatorPlayer;
                if (attacker != null)
                    hordeMember.Manager.OnTargetAquired(attacker);
                return;
            }

            hordeMember = info?.InitiatorPlayer?.GetComponent<HordeMember>();
            if (hordeMember != null && configData.Member.DamageMultiplier != 1)            
                info.damageTypes.ScaleAll(configData.Member.DamageMultiplier);            
        }

        private void OnEntityDeath(BaseCombatEntity entity, HitInfo info)
        {
            if (entity == null)
                return;

            HordeMember hordeMember = entity.GetComponent<HordeMember>();
            if (hordeMember != null)
            {
                if (lootType != LootType.Default)
                {
                    if (!deadMemberIds.ContainsKey(hordeMember.Player.userID))
                        deadMemberIds.Add(hordeMember.Player.userID, lootType == LootType.Kit ? new InventoryData(hordeMember.Player) : null);
                }

                hordeMember.Manager.OnMemberDeath(hordeMember);
                if (hordeMember.Manager.Members.Count == 0)
                {
                    HordeManager manager = hordeMember.Manager;
                    NextTick(() =>
                    {
                        OnHordeDestroyed(manager);
                    });
                }
                return;
            }

            foreach (HordeManager manager in managers)            
                manager.OnEntityDeath(entity, info);
        }

        private void OnEntityKill(BaseNetworkable entity)
        {
            if (entity == null)
                return;

            HordeMember hordeMember = entity.GetComponent<HordeMember>();
            if (hordeMember != null)
            {
                if (lootType != LootType.Default)
                {
                    if (!deadMemberIds.ContainsKey(hordeMember.Player.userID))
                        deadMemberIds.Add(hordeMember.Player.userID, lootType == LootType.Kit ? new InventoryData(hordeMember.Player) : null);
                }                    

                hordeMember.Manager.OnMemberDeath(hordeMember);
                if (hordeMember.Manager.Members.Count == 0)
                {
                    HordeManager manager = hordeMember.Manager;
                    NextTick(() =>
                    {
                        OnHordeDestroyed(manager);
                    });
                }
                return;
            }
        }

        private object CanBeTargeted(BaseCombatEntity player, MonoBehaviour behaviour)
        {
            if (player == null)
                return null;

            HordeMember hordeMember = player.GetComponent<HordeMember>();
            if (hordeMember != null)
                return false;

            return null;
        }

        private object OnNpcDestinationSet(NPCPlayerApex npcPlayer, Vector3 destination)
        {
            HordeMember hordeMember = npcPlayer.GetComponent<HordeMember>();
            if (hordeMember != null)
            {
                if (hordeMember.Player.AttackTarget != null)
                    return null;
                return false;
            }
            return null;
        }

        private object OnNpcStopMoving(NPCPlayerApex npcPlayer)
        {
            HordeMember hordeMember = npcPlayer.GetComponent<HordeMember>();
            if (hordeMember != null)
                return false;
            return null;
        }

        private object OnNpcPlayerTarget(NPCPlayerApex npcPlayer, BaseEntity target)
        {
            HordeMember hordeMember = npcPlayer.GetComponent<HordeMember>();
            if (hordeMember != null && target != null)
            {
                if (!target.HasAnyTrait(configData.Member.TargetAnimals ? BaseEntity.TraitFlag.Animal | BaseEntity.TraitFlag.Human : BaseEntity.TraitFlag.Human))                
                    return true;
                
                if (target.GetComponent<HordeMember>())
                    return true;
                
                if (target.Health() <= 0f)
                    return true;

                if (target is BasePlayer)
                {
                    BasePlayer player = target as BasePlayer;
                    
                    if (Vanish != null && (bool)Vanish.Call("IsInvisible", player))
                        return null;
                    
                    if (configData.Member.TargetScientists && player is Scientist)
                        return true;

                    if (player.IsFlying)
                        return true;

                    if (player.HasPlayerFlag(BasePlayer.PlayerFlags.SafeZone))
                        return true;

                    if (permission.UserHasPermission(player.UserIDString, "zombiehorde.ignore"))
                        return true;
                }

                if (Vector3.Distance(npcPlayer.transform.position, target.transform.position) > configData.Horde.ChaseDistance)
                    return true;

                if (hordeMember.IsHordeLeader)
                    hordeMember.Manager.OnTargetAquired(target);
            }
            return null;
        }
        #endregion

        #region Functions
        private T ParseType<T>(string type)
        {
            try
            {
                return (T)Enum.Parse(typeof(T), type, true);
            }
            catch
            {
                return default(T);
            }
        }

        private bool VerifySpawnSystem()
        {
            spawnSystem = ParseType<SpawnSystem>(configData.Horde.SpawnType);
            switch (spawnSystem)
            {
                case SpawnSystem.None:
                    PrintError("You have set an invalid value in the config entry \"Spawn Type\".Unable to spawn hordes!");
                    return false;
                case SpawnSystem.Default:
                    return true;
                case SpawnSystem.SpawnsDatabase:
                    if (Spawns != null)
                    {
                        if (string.IsNullOrEmpty(configData.Horde.SpawnFile))
                        {
                            PrintError("You have selected SpawnsDatabase as your method of spawning hordes, however you have not specified a spawn file.Unable to spawn hordes!");
                            return false;
                        }

                        object success = Spawns?.Call("LoadSpawnFile", configData.Horde.SpawnFile);
                        if (success is List<Vector3>)
                        {
                            spawnPoints = success as List<Vector3>;
                            if (spawnPoints.Count == 0)
                            {
                                PrintError("You have selected SpawnsDatabase as your method of spawning hordes, however the spawn file you have chosen has no spawn points.Unable to spawn hordes!");
                                return false;
                            }
                            return true;
                        }
                    }
                    else PrintError("You have selected SpawnsDatabase as your method of spawning hordes, however SpawnsDatabase is not loaded on your server.Unable to spawn hordes!");
                    return false;
                case SpawnSystem.RandomSpawns:
                    if (RandomSpawns != null)
                        return true;
                    else PrintError("You have selected RandomSpawns as your method of spawning hordes, however RandomSpawns is not loaded on your server.Unable to spawn hordes!");
                    return false;                
            }
            return false;
        }

        private object GetSpawnPoint()
        {
            switch (spawnSystem)
            {
                case SpawnSystem.None:
                    return null;
                case SpawnSystem.Default:
                    return ServerMgr.FindSpawnPoint().pos;
                case SpawnSystem.SpawnsDatabase:
                    {
                        if (Spawns == null)
                        {
                            PrintError("Tried getting a spawn point but SpawnsDatabase is null.Make sure SpawnsDatabase is still loaded to continue using custom spawn points");
                            goto case SpawnSystem.Default;
                        }

                        Vector3 spawnPoint = spawnPoints.GetRandom();
                        spawnPoints.Remove(spawnPoint);
                        if (spawnPoints.Count == 0)
                            spawnPoints = (List<Vector3>)Spawns.Call("LoadSpawnFile", configData.Horde.SpawnFile);
                        return spawnPoint;
                    }
                case SpawnSystem.RandomSpawns:
                    if (RandomSpawns == null)
                    {
                        PrintError("Tried getting a spawn point but RandomSpawns is null.Make sure RandomSpawns is still loaded to continue using randomised spawn points");
                        goto case SpawnSystem.Default;
                    }
                    return RandomSpawns.Call("GetSpawnPoint");
            }
            return null;
        }

        private static object FindPointOnNavmesh(Vector3 targetPosition)
        {
            for (int i = 0; i < 10; i++)
            {
                NavMeshHit navHit;
                if (NavMesh.SamplePosition(targetPosition, out navHit, 100, 1))
                {
                    if (navHit.position.y < TerrainMeta.HeightMap.GetHeight(navHit.position) + 1)
                    {
                        if (IsNearOrInRock(targetPosition + Vector3.up))
                            continue;
                        return navHit.position;
                    }
                }
            }           
            return null;
        }

        private static bool IsNearOrInRock(Vector3 position)
        {
            int entities = Physics.OverlapSphereNonAlloc(position, 2f, Vis.colBuffer, LayerMask.GetMask("World"));
            if (entities == 0)
                return false;

            bool flag = false;
            for (int i = 0; i < entities; i++)
            {
                flag = Vis.colBuffer[i].gameObject?.name.Contains("rock_") ?? false;
                Vis.colBuffer[i] = null;
            }

            return flag;
        }

        private void CreateRandomHordes()
        {
            for (int i = 0; i < configData.Horde.HordeAmount - managers.Count; i++)            
                hordeQueue.Enqueue(new HordeOrder(Vector3.zero, configData.Horde.RoamLocal, configData.Horde.RoamDistance, false));

            ProcessHordeOrders();
        }

        private void ProcessHordeOrders(bool force = false)
        {
            if (IsQueueRunning)
                return;

            if (force || (hordeQueue.Count > 0 && managers.Count < configData.Horde.HordeAmount))
            {
                IsQueueRunning = true;

                HordeOrder hordeOrder = hordeQueue.Dequeue();
                ServerMgr.Instance.StartCoroutine(CreateZombieHorde(hordeOrder));
            }
        }

        private IEnumerator CreateZombieHorde(HordeOrder hordeOrder)
        {
            Vector3 spawnPosition = hordeOrder.position;

            if (spawnPosition == Vector3.zero)
            {
                object success = GetSpawnPoint();
                if (success is Vector3)
                    spawnPosition = (Vector3)success;
                else yield break;                
            }

            HordeManager manager = new GameObject().AddComponent<HordeManager>();
            if (hordeOrder.roamLocal)
                manager.Initialize(configData, spawnPosition, hordeOrder.distanceOverride, hordeOrder.isMonumentSpawned);
            else manager.Initialize(configData);

            managers.Add(manager);

            for (int y = 0; y < configData.Horde.InitialSize; y++)
            {
                CreateHordeMember(spawnPosition, manager);
                yield return new WaitForEndOfFrame();
                yield return new WaitForEndOfFrame();
                yield return new WaitForEndOfFrame();
            }

            manager.SetHordeDestination(manager.GetAverageVector());
            manager.SetHordeLeader();

            yield return new WaitForSecondsRealtime(1f);

            IsQueueRunning = false;

            if (hordeQueue.Count > 0)
                ProcessHordeOrders();
        }

        private NPCPlayerApex InstantiateEntity(Vector3 position)
        {
            GameObject gameObject = Facepunch.Instantiate.GameObject(GameManager.server.FindPrefab(zombiePrefab), position, new Quaternion());
            gameObject.name = zombiePrefab;

            UnityEngine.SceneManagement.SceneManager.MoveGameObjectToScene(gameObject, Rust.Server.EntityScene);

            UnityEngine.Object.Destroy(gameObject.GetComponent<Spawnable>());

            if (!gameObject.activeSelf)
                gameObject.SetActive(true);

            NPCPlayerApex component = gameObject.GetComponent<NPCPlayerApex>();
            return component;
        }

        private void CreateHordeMember(Vector3 position, HordeManager manager)
        {
            Vector2 random = UnityEngine.Random.insideUnitCircle * 3;
            object success = FindPointOnNavmesh(position + new Vector3(random.x, 0, random.y));
            if (success == null)           
                return;            

            NPCPlayerApex player = InstantiateEntity((Vector3)success);
            if (player == null)
                return;

            player.enableSaving = false;
            player.Spawn();

            player.displayName = Facepunch.RandomUsernames.All.GetRandom();
            player.InitializeHealth(configData.Member.Health, configData.Member.Health);
            player.Stats.AggressionRange = player.Stats.DeaggroRange = configData.Horde.ChaseDistance;

            if (lootType != LootType.Default)
                (player as NPCMurderer).LootSpawnSlots = new LootContainer.LootSpawnSlot[0];

            if (Kits != null && configData.Member.Kits.Length > 0)
            {
                player.CancelInvoke(player.EquipTest);
                StripInventory(player);
                NextTick(() =>
                {
                    if (player == null)
                        return;

                    string kitName = configData.Member.Kits.GetRandom();
                    Kits?.Call("GiveKit", player, kitName);
                    ins.timer.In(3, () =>
                    {
                        if (player == null)
                            return;

                        if (player.inventory.containerBelt.GetSlot(0) == null)                        
                            PrintError($"The kit '{kitName}' does not have a active weapon in the first slot of the tool belt.You must re-adjust the kit for NPC players to utilize a weapon!");  
                        else player.EquipTest();
                    });
                });                
            }

            HordeMember member = player.gameObject.AddComponent<HordeMember>();
            member.Manager = manager;
            manager.Members.Add(member);
        }

        private void OnHordeDestroyed(HordeManager manager)
        {
            HordeOrder hordeOrder = manager.IsMonumentSpawned ? manager.CreateHordeOrder() : new HordeOrder(Vector3.zero, configData.Horde.RoamLocal, configData.Horde.RoamDistance, false);

            managers.Remove(manager);
            UnityEngine.Object.Destroy(manager);
            

            timer.In(configData.Horde.RespawnTime, () =>
            {
                if (hordeOrder != null)
                {
                    hordeQueue.Enqueue(hordeOrder);
                    ProcessHordeOrders();
                }                
            });
        }

        private void StripInventory(BasePlayer player)
        {
            Item[] allItems = player.inventory.AllItems();

            for (int i = allItems.Length - 1; i >= 0; i--)
            {
                Item item = allItems[i];
                item.RemoveFromContainer();
                item.Remove();
            }
        }

        private void FillLootContainer(NPCPlayerCorpse corpse)
        {
            if (corpse == null) return;
            ItemContainer itemContainer = corpse.containers[0];
            if (itemContainer == null)
                return;

            int count = UnityEngine.Random.Range(configData.Loot.Minimum, configData.Loot.Maximum);

            if (itemContainer.capacity < count)
                itemContainer.capacity = count;

            List<ConfigData.LootTable.LootItem> Items = new List<ConfigData.LootTable.LootItem>(configData.Loot.Items);
            for (int i = 0; i < count; i++)
            {
                ConfigData.LootTable.LootItem lootItem = Items.GetRandom();
                if (lootItem == null) continue;

                bool isBlueprint = lootItem.Name.EndsWith(".bp");
                string shortname = isBlueprint ? lootItem.Name.Substring(0, lootItem.Name.Length - 3) : lootItem.Name;

                if (!itemNameToId.ContainsKey(shortname))
                {
                    PrintError($"Invalid item shortname set in loot list : {shortname}");
                    continue;
                }

                Item item = null;
                if (isBlueprint)
                {
                    item = ItemManager.CreateByItemID(-996920608, 1, 0);
                    item.blueprintTarget = itemNameToId[shortname];
                    item.amount = UnityEngine.Random.Range(lootItem.Minimum, lootItem.Maximum);
                }
                else item = ItemManager.CreateByName(shortname);

                if (item != null)
                {
                    item.amount = UnityEngine.Random.Range(lootItem.Minimum, lootItem.Maximum);
                    item.MoveToContainer(itemContainer, -1, false);
                }
                Items.Remove(lootItem);
            }            
        }

        private void FindMonuments()
        {
            int count = 0;
            GameObject[] allobjects = UnityEngine.Object.FindObjectsOfType<GameObject>();
            foreach (var gobject in allobjects)
            {
                if (count >= configData.Horde.HordeAmount)
                    break;

                if (gobject.name.Contains("autospawn/monument"))
                {
                    Vector3 position = gobject.transform.position;
                    if (position == Vector3.zero)
                        continue;
                  
                    if (gobject.name.Contains("powerplant_1"))
                    {
                        if (configData.Monument.Powerplant.Enabled)
                        {
                            hordeQueue.Enqueue(new HordeOrder(position, configData.Monument.Powerplant.RoamLocal, configData.Monument.Powerplant.RoamDistance, true));                            
                            count++;
                        }
                        continue;
                    }

                    if (gobject.name.Contains("military_tunnel_1"))
                    {
                        if (configData.Monument.Tunnels.Enabled)
                        {
                            hordeQueue.Enqueue(new HordeOrder(position, configData.Monument.Tunnels.RoamLocal, configData.Monument.Tunnels.RoamDistance, true));
                            count++;
                        }
                        continue;
                    }

                    if (gobject.name.Contains("harbor_1"))
                    {
                        if (configData.Monument.LargeHarbor.Enabled)
                        {
                            hordeQueue.Enqueue(new HordeOrder(position, configData.Monument.LargeHarbor.RoamLocal, configData.Monument.LargeHarbor.RoamDistance, true));
                            count++;
                        }
                        continue;
                    }

                    if (gobject.name.Contains("harbor_2"))
                    {
                        if (configData.Monument.SmallHarbor.Enabled)
                        {
                            hordeQueue.Enqueue(new HordeOrder(position, configData.Monument.SmallHarbor.RoamLocal, configData.Monument.SmallHarbor.RoamDistance, true));
                            count++;
                        }
                        continue;
                    }

                    if (gobject.name.Contains("airfield_1"))
                    {
                        if (configData.Monument.Airfield.Enabled)
                        {
                            hordeQueue.Enqueue(new HordeOrder(position, configData.Monument.Airfield.RoamLocal, configData.Monument.Airfield.RoamDistance, true));
                            count++;
                        }
                        continue;
                    }

                    if (gobject.name.Contains("trainyard_1"))
                    {
                        if (configData.Monument.Trainyard.Enabled)
                        {
                            hordeQueue.Enqueue(new HordeOrder(position, configData.Monument.Trainyard.RoamLocal, configData.Monument.Trainyard.RoamDistance, true));
                            count++;
                        }
                        continue;
                    }

                    if (gobject.name.Contains("water_treatment_plant_1"))
                    {
                        if (configData.Monument.WaterTreatment.Enabled)
                        {
                            hordeQueue.Enqueue(new HordeOrder(position, configData.Monument.WaterTreatment.RoamLocal, configData.Monument.WaterTreatment.RoamDistance, true));
                            count++;
                        }
                        continue;
                    }

                    if (gobject.name.Contains("warehouse"))
                    {
                        if (configData.Monument.Warehouse.Enabled)
                        {
                            hordeQueue.Enqueue(new HordeOrder(position, configData.Monument.Warehouse.RoamLocal, configData.Monument.Warehouse.RoamDistance, true));
                            count++;
                        }
                        continue;
                    }

                    if (gobject.name.Contains("satellite_dish"))
                    {
                        if (configData.Monument.Satellite.Enabled)
                        {
                            hordeQueue.Enqueue(new HordeOrder(position, configData.Monument.Satellite.RoamLocal, configData.Monument.Satellite.RoamDistance, true));
                            count++;
                        }
                        continue;
                    }

                    if (gobject.name.Contains("sphere_tank"))
                    {
                        if (configData.Monument.Dome.Enabled)
                        {
                            hordeQueue.Enqueue(new HordeOrder(position, configData.Monument.Dome.RoamLocal, configData.Monument.Dome.RoamDistance, true));
                            count++;
                        }
                        continue;
                    }

                    if (gobject.name.Contains("radtown_small_3"))
                    {
                        if (configData.Monument.Radtown.Enabled)
                        {
                            hordeQueue.Enqueue(new HordeOrder(position, configData.Monument.Radtown.RoamLocal, configData.Monument.Radtown.RoamDistance, true));
                            count++;
                        }
                        continue;
                    }

                    if (gobject.name.Contains("launch_site_1"))
                    {
                        if (configData.Monument.RocketFactory.Enabled)
                        {
                            hordeQueue.Enqueue(new HordeOrder(position, configData.Monument.RocketFactory.RoamLocal, configData.Monument.RocketFactory.RoamDistance, true));
                            count++;
                        }
                        continue;
                    }

                    if (gobject.name.Contains("gas_station_1"))
                    {
                        if (configData.Monument.GasStation.Enabled)
                        {
                            hordeQueue.Enqueue(new HordeOrder(position, configData.Monument.GasStation.RoamLocal, configData.Monument.GasStation.RoamDistance, true));
                            count++;
                        }
                        continue;
                    }

                    if (gobject.name.Contains("supermarket_1"))
                    {
                        if (configData.Monument.Supermarket.Enabled)
                        {
                            hordeQueue.Enqueue(new HordeOrder(position, configData.Monument.Supermarket.RoamLocal, configData.Monument.Supermarket.RoamDistance, true));
                            count++;
                        }
                        continue;
                    }

                    if (gobject.name.Contains("mining_quarry_c"))
                    {
                        if (configData.Monument.Quarry_HQM.Enabled)
                        {
                            hordeQueue.Enqueue(new HordeOrder(position, configData.Monument.Quarry_HQM.RoamLocal, configData.Monument.Quarry_HQM.RoamDistance, true));
                            count++;
                        }
                        continue;
                    }

                    if (gobject.name.Contains("mining_quarry_a"))
                    {
                        if (configData.Monument.Quarry_Sulfur.Enabled)
                        {
                            hordeQueue.Enqueue(new HordeOrder(position, configData.Monument.Quarry_Sulfur.RoamLocal, configData.Monument.Quarry_Sulfur.RoamDistance, true));
                            count++;
                        }
                        continue;
                    }

                    if (gobject.name.Contains("mining_quarry_b"))
                    {
                        if (configData.Monument.Quarry_Stone.Enabled)
                        {
                            hordeQueue.Enqueue(new HordeOrder(position, configData.Monument.Quarry_Stone.RoamLocal, configData.Monument.Quarry_Stone.RoamDistance, true));
                            count++;
                        }
                        continue;
                    }

                    if (gobject.name.Contains("junkyard_1"))
                    {
                        if (configData.Monument.Junkyard.Enabled)
                        {
                            hordeQueue.Enqueue(new HordeOrder(position, configData.Monument.Junkyard.RoamLocal, configData.Monument.Junkyard.RoamDistance, true));
                            count++;
                        }
                        continue;
                    }
                }
            }

            if (count < configData.Horde.HordeAmount)
                CreateRandomHordes();
            else ProcessHordeOrders();
        }
        #endregion

        #region Behaviours
        private class HordeManager : MonoBehaviour
        {
            public List<HordeMember> Members { get; private set; }
            public ConfigData Config { get; set; }

            public HordeMember GetHordeLeader
            {
                get
                {
                    return Members.FirstOrDefault(x => x.IsHordeLeader);
                }
            }

            public bool JustMergedHorde
            {
                get
                {
                    return justMerged;
                }
                set
                {
                    justMerged = value;
                    InvokeHandler.Invoke(this, () => justMerged = false, 180);
                }
            }

            public bool IsMonumentSpawned { get; private set; }   

            private BaseEntity targetEntity = null;
            private Vector3 targetPosition;

            private Vector3 initialSpawnPoint;
            private float roamDistance;
            private bool localRoam;

            private float nextGrowthTime;
            private bool justMerged;

            private void Awake()
            {
                enabled = false;               
            }

            private void OnDestroy()
            {
                InvokeHandler.CancelInvoke(this, HordeTick);

                for (int i = Members.Count - 1; i >= 0; i--)                
                    Destroy(Members.ElementAt(i));                
            }

            public void Initialize(ConfigData config, Vector3 initialSpawnPoint, object distanceOverride, bool isMonumentSpawned)
            {
                this.initialSpawnPoint = initialSpawnPoint;
                IsMonumentSpawned = isMonumentSpawned;

                if (distanceOverride is float)
                    roamDistance = (float)distanceOverride;
                else roamDistance = config.Horde.RoamDistance;
                localRoam = true;
                Initialize(config);
            }

            public void Initialize(ConfigData config)
            {
                Members = new List<HordeMember>();
                Config = config;

                nextGrowthTime = Time.realtimeSinceStartup + Config.Horde.GrowthRate;

                InvokeHandler.InvokeRandomized(this, HordeTick, 1f, 5f, 1f);
            }

            public void SetHordeDestination(Vector3 destination)
            {
                targetPosition = destination;

                foreach (HordeMember member in Members)               
                    member.UpdateTargetPosition(destination);               
            }

            public void OnTargetAquired(BaseEntity targetEntity)
            {
                if (targetEntity == null || this.targetEntity == targetEntity)
                    return;

                Vector3 averageVector = GetAverageVector();

                if (Vector3.Distance(averageVector, targetEntity.transform.position) > Config.Horde.ChaseDistance || (localRoam && Vector3.Distance(averageVector, initialSpawnPoint) > roamDistance))
                {
                    targetEntity = null;
                    return;
                }

                if (this.targetEntity == null || Vector3.Distance(targetEntity.transform.position, averageVector) < Vector3.Distance(this.targetEntity.transform.position, averageVector))
                {
                    this.targetEntity = targetEntity;
                    foreach (HordeMember hordeMember in Members)
                        hordeMember.UpdateTargetEntity(targetEntity);
                }
            }

            private void HordeTick()
            {
                if (Members.Count == 0)
                {
                    ins.OnHordeDestroyed(this);
                    Destroy(this);
                    return;
                }

                HordeMember hordeLeader = GetHordeLeader;
                if (hordeLeader == null)
                {
                    SetHordeLeader();
                    return;
                }

                if (hordeLeader.Player.IsDormant)
                    return;

                TryMergeHordes();
                TryGrowHorde();  

                if (IsValidTarget(targetEntity))
                {
                    foreach (HordeMember hordeMember in Members)                    
                       hordeMember.UpdateTargetEntity(targetEntity);                    
                }
                else
                {
                    targetEntity = null;

                    Vector3 averageVector = GetAverageVector();

                    if (Vector3.Distance(averageVector, targetPosition) < 30)
                    {
                        SetHordeDestination(GetRandomLocation());
                        return;
                    }

                    foreach (HordeMember hordeMember in Members)
                    {
                        if (hordeMember == null)
                            continue;

                        if (Vector3.Distance(hordeMember.transform.position, averageVector) > 10)                      
                            hordeMember.UpdateTargetPosition(averageVector, true);                        
                        else hordeMember.UpdateTargetPosition(targetPosition);                        
                    }                   
                }               
            }            

            public void OnEntityDeath(BaseCombatEntity entity, HitInfo info)
            {                
                if (targetEntity == entity)                
                    targetEntity = null;
                
                HordeMember hordeMember = info?.InitiatorPlayer?.GetComponent<HordeMember>();
                if (hordeMember == null || !Members.Contains(hordeMember))
                    return;

                if (entity is BasePlayer && Config.Horde.CreateOnDeath && Members.Count < Config.Horde.MaximumSize)
                    AddHordeMember();
            }

            public void OnMemberDeath(HordeMember hordeMember)
            {                
                bool isHordeLeader = hordeMember.IsHordeLeader;
                Members.Remove(hordeMember);

                if (isHordeLeader && Members.Count > 0)
                    SetHordeLeader();
            }

            public Vector3 GetAverageVector()
            {
                float x = 0;
                float y = 0;
                float z = 0;

                foreach (HordeMember hordeMember in Members)
                {
                    if (hordeMember == null || hordeMember.Player == null)
                        continue;

                    x += hordeMember.transform.position.x;
                    y += hordeMember.transform.position.y;
                    z += hordeMember.transform.position.z;
                }

                return new Vector3(x / Members.Count, y / Members.Count, z / Members.Count);
            }

            public void SetHordeLeader()
            {
                if (Members.Count > 0)
                    Members.GetRandom().IsHordeLeader = true;
            }

            private Vector3 GetRandomLocation()
            {
                Vector3 position = Vector3.zero;

                if (localRoam)
                {
                    Vector2 randomInCircle = UnityEngine.Random.insideUnitCircle * roamDistance;

                    position = initialSpawnPoint + new Vector3(randomInCircle.x, 0, randomInCircle.y);
                    position.y = TerrainMeta.HeightMap.GetHeight(position);
                }
                else
                {
                    if (ins.RandomSpawns)
                    {
                        object success = ins.RandomSpawns.Call("GetSpawnPoint");
                        if (success is Vector3)
                            position = (Vector3)success;
                    }

                    if (position == Vector3.zero)
                        position = ServerMgr.FindSpawnPoint().pos;
                }

                NavMeshHit navHit;
                if (NavMesh.SamplePosition(position, out navHit, 250, 1))              
                    return navHit.position;                
                return position;
            }

            private bool IsValidTarget(BaseEntity target)
            {
                if (target == null || target.IsDestroyed)
                    return false; 

                if (!target.HasAnyTrait(Config.Member.TargetAnimals ? BaseEntity.TraitFlag.Animal | BaseEntity.TraitFlag.Human : BaseEntity.TraitFlag.Human))
                    return false;

                if (target.GetComponent<HordeMember>())
                    return false;

                if (target.Health() <= 0f)
                    return false;

                if (target is BasePlayer)
                {
                    BasePlayer player = target as BasePlayer;

                    if (ins.Vanish != null && (bool)ins.Vanish.Call("IsInvisible", player))
                        return false;

                    if (player.IsFlying)
                        return false;

                    if (player.HasPlayerFlag(BasePlayer.PlayerFlags.SafeZone))
                        return false;
                }

                if (Vector3.Distance(GetAverageVector(), target.transform.position) > Config.Horde.ChaseDistance)
                    return false;

                return true;
            }

            private void TryGrowHorde()
            {     
                float time = Time.realtimeSinceStartup;
                if (time > nextGrowthTime)
                {
                    if (Members.Count < Config.Horde.MaximumSize)
                        AddHordeMember();

                    nextGrowthTime = time + Config.Horde.GrowthRate;
                }
            }

            private void AddHordeMember()
            {
                Vector3 spawnPosition = GetAverageVector();                
                ins.CreateHordeMember(spawnPosition, this);
            }

            private void TryMergeHordes()
            {
                if (!Config.Horde.MergeHordes || JustMergedHorde)
                    return;

                foreach(HordeManager manager in ins.managers)
                {
                    if (manager == this)
                        continue;

                    if (Members.Count >= Config.Horde.MaximumSize)
                        return;

                    HordeMember otherLeader = manager.GetHordeLeader;
                    if (otherLeader == null)
                        continue;

                    if (Vector3.Distance(GetHordeLeader.transform.position, otherLeader.transform.position) < 30)
                    {
                        int amountToMerge = Config.Horde.MaximumSize - Members.Count;
                        if (amountToMerge >= manager.Members.Count)
                        {
                            otherLeader.IsHordeLeader = false;
                            Members.AddRange(manager.Members);
                            manager.Members.Clear();
                        }
                        else
                        {     
                            for (int i = 0; i < amountToMerge; i++)
                            {
                                if (manager.Members.Count > 0)
                                {
                                    HordeMember member = manager.Members[0];
                                    manager.Members.Remove(member);
                                    Members.Add(member);
                                    manager.SetHordeLeader();
                                    manager.JustMergedHorde = true;
                                }
                            }
                        }
                    }
                }                
            }

            public HordeOrder CreateHordeOrder() => new HordeOrder(initialSpawnPoint, localRoam, roamDistance, IsMonumentSpawned);
        }

        private class HordeMember : MonoBehaviour
        {
            public NPCPlayerApex Player { get; private set; }
            public HordeManager Manager { get; set; }
            public bool IsHordeLeader { get; set; }            
            
            public Vector3 targetPosition = Vector3.zero;           

            private void Awake()
            {
                Player = GetComponent<NPCPlayerApex>();
                enabled = false;
                Player.clothingMoveSpeedReduction = -ins.configData.Member.SpeedModifier;
            }

            private void OnDestroy()
            {
                if (Player != null && !Player.IsDestroyed)
                    Player.Kill();
            }

            public void UpdateTargetPosition(Vector3 targetPosition, bool isRegrouping = false)
            {
                if (Player == null || Player.GetNavAgent == null)
                    return;

                Player.AttackTarget = null;
                this.targetPosition = targetPosition;

                Player.finalDestination = targetPosition;
                Player.Destination = targetPosition;
                Player.IsStopped = false;
                Player.SetFact(NPCPlayerApex.Facts.Speed, isRegrouping ? (byte)NPCPlayerApex.SpeedEnum.Sprint : (byte)NPCPlayerApex.SpeedEnum.Walk, true, true);
            }

            public void UpdateTargetEntity(BaseEntity targetEntity)
            {
                if (Player == null || Player.GetNavAgent == null)
                    return;

                if (targetEntity == null)
                {
                    Player.AttackTarget = null;
                    return;
                }

                if (targetEntity == Player.AttackTarget)
                    return;
                
                Player.AttackTarget = targetEntity;
                Player.SetFact(NPCPlayerApex.Facts.Speed, (byte)NPCPlayerApex.SpeedEnum.Sprint, true, true);
            }            
        }

        public class HordeOrder
        {
            public Vector3 position;
            public bool roamLocal;
            public object distanceOverride;
            public bool isMonumentSpawned;

            public HordeOrder(Vector3 position, bool roamLocal, object distanceOverride, bool isMonumentSpawned)
            {
                this.position = position;
                this.roamLocal = roamLocal;
                this.distanceOverride = distanceOverride;
                this.isMonumentSpawned = isMonumentSpawned;
            }
        }

        public class InventoryData
        {
            public List<InventoryItem> items = new List<InventoryItem>();

            public InventoryData(NPCPlayerApex player)
            {
                items = player.inventory.AllItems().Select(item => new InventoryItem
                {
                    itemid = item.info.itemid,
                    amount = item.amount > 1 ? UnityEngine.Random.Range(1, item.amount) : item.amount,
                    ammo = (item.GetHeldEntity() as BaseProjectile)?.primaryMagazine.contents ?? 0,
                    ammotype = (item.GetHeldEntity() as BaseProjectile)?.primaryMagazine.ammoType.shortname ?? null,
                    skin = item.skin,
                    condition = UnityEngine.Random.Range(1, item.condition),
                    instanceData = new InventoryItem.InstanceData(item),
                    contents = item.contents?.itemList.Select(item1 => new InventoryItem
                    {
                        itemid = item1.info.itemid,
                        amount = item1.amount,
                        condition = UnityEngine.Random.Range(1, item1.condition)
                    }).ToArray()
                }).ToList();
            }

            public void RestoreItemsTo(NPCPlayerCorpse corpse)
            {
                for (int i = 0; i < items.Count; i++)
                {
                    Item item = CreateItem(items[i]);
                    item.MoveToContainer(corpse.containers[0]);
                }
            }

            private Item CreateItem(InventoryItem itemData)
            {
                Item item = ItemManager.CreateByItemID(itemData.itemid, itemData.amount, itemData.skin);
                item.condition = itemData.condition;

                if (itemData.instanceData != null)
                    itemData.instanceData.Restore(item);

                BaseProjectile weapon = item.GetHeldEntity() as BaseProjectile;
                if (weapon != null)
                {
                    if (!string.IsNullOrEmpty(itemData.ammotype))
                        weapon.primaryMagazine.ammoType = ItemManager.FindItemDefinition(itemData.ammotype);
                    weapon.primaryMagazine.contents = itemData.ammo;
                }
                if (itemData.contents != null)
                {
                    foreach (var contentData in itemData.contents)
                    {
                        var newContent = ItemManager.CreateByItemID(contentData.itemid, contentData.amount);
                        if (newContent != null)
                        {
                            newConte
// ... [Code preview truncated due to length. Full source in attached file] ...

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