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

FREE ZombieHorde : 0.2.4 0.2.4

Нет прав для скачивания
C#:
using Facepunch;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core.Plugins;
using Rust.Ai.HTN;
using Rust.Ai.HTN.Sensors;
using Rust.Ai.HTN.Reasoning;
using Rust.Ai.HTN.Murderer;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.AI;
namespace Oxide.Plugins {
    [Info("ZombieHorde", "https://topplugin.ru/", "0.2.4")]
    [Description("Плагин куплен на https://topplugin.ru/ | Спасибо за покупку!")]
    class ZombieHorde : RustPlugin {
        [PluginReference]
        Plugin Kits, RandomSpawns, Spawns, Vanish;
        private static ZombieHorde Instance {
            get;
            set;
        }
        private static bool IsUnloading {
            get;
            set;
        }
        private RestrictedTickRate restrictedTickRate;
        private List<Vector3> spawnPoints = new List<Vector3>();
        private SpawnSystem spawnSystem = SpawnSystem.None;
        private ItemDefinition blueprintBase = ItemManager.FindItemDefinition("blueprintbase");
        private ItemDefinition glowEyes = ItemManager.FindItemDefinition("gloweyes");
        private int navmeshAreaMask;
        private const string SCARECROW_PREFAB = "assets/prefabs/npc/scarecrow/scarecrow.prefab";
        private const int WORLD_LAYER = 65536;
#region Oxide Hooks
        private void OnServerInitialized() {
            Instance = this;
            IsUnloading = false;
            permission.RegisterPermission("zombiehorde.admin", this);
            permission.RegisterPermission("zombiehorde.ignore", this);
            restrictedTickRate = new GameObject().AddComponent<RestrictedTickRate>();
            navmeshAreaMask = GameManager.server.FindPrefab(SCARECROW_PREFAB).GetComponent<HTNPlayer>()?.AiDomain?.NavAgent?.areaMask ?? 1;
            VerifyLoadoutProfiles();
            VerifySpawnSystem();
            FindMonuments();
        }
        private void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info) {
            HordeMember hordeMember = info?.InitiatorPlayer?.GetComponent<HordeMember>();
            if (hordeMember != null) {
                if (hordeMember.damageMultiplier != 1f) info.damageTypes.ScaleAll(hordeMember.damageMultiplier);
                return;
            }
            if (configData.Member.HeadshotKills) {
                hordeMember = entity.GetComponent<HordeMember>();
                if (hordeMember != null && (info?.isHeadshot ?? false)) info.damageTypes.ScaleAll(1000);
            }
        }
        private void OnPlayerDeath(BasePlayer player, HitInfo hitInfo) {
            if (player == null || hitInfo == null) return;
            HordeMember hordeMember = player.GetComponent<HordeMember>();
            if (hordeMember != null) {
                if (configData.Loot.DropInventory) hordeMember.PrepareInventory();
                hordeMember.Manager.OnMemberDeath(hordeMember);
                return;
            }
            if (configData.Horde.CreateOnDeath) {
                HordeMember attacker = hitInfo?.InitiatorPlayer?.GetComponent<HordeMember>();
                if (attacker != null) {
                    for (int i = 0; i < HordeManager._allHordes.Count; i++) HordeManager._allHordes[i].OnPlayerDeath(player, attacker);
                }
            }
        }
        private object CanBeTargeted(BaseCombatEntity player, MonoBehaviour behaviour) {
            HordeMember hordeMember = player?.GetComponent<HordeMember>();
            if (hordeMember != null) {
                if (((behaviour is AutoTurret) || (behaviour is GunTrap) || (behaviour is FlameTurret)) && configData.Member.TargetedByTurrets) return null;
                return false;
            }
            return null;
        }
        private object CanBradleyApcTarget(BradleyAPC bradleyAPC, BaseEntity entity) {
            HordeMember hordeMember = entity?.GetComponent<HordeMember>();
            if (hordeMember != null && !configData.Member.TargetedByAPC) return false;
            return null;
        }
        private void OnPlayerCorpse(HTNPlayer npc, BaseCorpse corpse) {
            HordeMember hordeMember = npc?.GetComponent<HordeMember>();
            if (hordeMember == null) return;
            LootableCorpse lootableCorpe = corpse as LootableCorpse;
            if (lootableCorpe != null) {
                lootableCorpe.playerName = npc.displayName;
                ClearContainer(lootableCorpe.containers[0]);
                ClearContainer(lootableCorpe.containers[2]);
                if (configData.Loot.DropInventory) {
                    ClearContainer(lootableCorpe.containers[1]);
                    hordeMember.MoveInventoryTo(lootableCorpe);
                }
                else SpawnIntoContainer(lootableCorpe);
            }
        }
        private void Unload() {
            IsUnloading = true;
            HordeManager.Order._queue.Clear();
            UnityEngine.Object.Destroy(restrictedTickRate.gameObject);
            for (int i = HordeManager._allHordes.Count - 1; i >= 0; i--) HordeManager._allHordes[i].Destroy();
            HordeManager._allHordes.Clear();
            configData = null;
            Instance = null;
        }
#endregion
#region Functions
#region Horde Spawning
        private T ParseType<T>(string type) {
            try {
                return (T)Enum.Parse(typeof(T), type, true);
            }
            catch {
                return default(T);
            }
        }
        private void VerifyLoadoutProfiles() {
            Puts("Verifying horde profiles");
            bool hasChanged = false;
            for (int i = configData.HordeProfiles.Count - 1; i >= 0; i--) {
                string key = configData.HordeProfiles.ElementAt(i).Key;
                for (int y = configData.HordeProfiles[key].Count - 1; y >= 0; y--) {
                    string loadoutId = configData.HordeProfiles[key][y];
                    if (!configData.Member.Loadouts.Any(x => x.LoadoutID == loadoutId)) {
                        Puts($"Loadout profile {loadoutId} does not exist.Removing from config");
                        configData.HordeProfiles[key].Remove(loadoutId);
                        hasChanged = true;
                    }
                }
                if (configData.HordeProfiles[key].Count <= 0) {
                    Puts($"Horde profile {key} does not have any valid loadouts.Removing from config");
                    configData.HordeProfiles.Remove(key);
                    hasChanged = true;
                }
            }
            if (hasChanged) SaveConfig();
        }
        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 Vector3 GetSpawnPoint() {
            switch (spawnSystem) {
                case SpawnSystem.None : break;
                case SpawnSystem.Default : if (SpawnHandler.Instance != null) {
                    Vector3 spawnPoint = SpawnHandler.GetSpawnPoint()?.pos ?? Vector3.zero;
                    if (spawnPoint != Vector3.zero) return spawnPoint;
                }
                break;
                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;
                }
                object randomSpawns = RandomSpawns.Call("GetSpawnPoint");
                if (randomSpawns != null) return (Vector3)randomSpawns;
                break;
            }
            Vector2 random = UnityEngine.Random.insideUnitCircle * (World.Size / 3f);
            Vector3 position = new Vector3(random.x, 0, random.y);
            position.y = TerrainMeta.HeightMap.GetHeight(position);
            return position;
        }
        private void FindMonuments() {
            int count = 0;
            GameObject[] allobjects = UnityEngine.Object.FindObjectsOfType<GameObject>();
            foreach (var gobject in allobjects) {
                if (count >= configData.Horde.MaximumHordes) break;
                if (gobject.name.Contains("autospawn/monument")) {
                    Transform tr = gobject.transform;
                    Vector3 position = tr.position;
                    if (position == Vector3.zero) continue;
                    if (gobject.name.Contains("powerplant_1") && configData.Monument.Powerplant.Enabled) {
                        HordeManager.Order.CreateOrder(tr.TransformPoint(new Vector3(-30.8f, 0.2f, -15.8f)), configData.Monument.Powerplant);
                        count++;
                        continue;
                    }
                    if (gobject.name.Contains("military_tunnel_1") && configData.Monument.Tunnels.Enabled) {
                        HordeManager.Order.CreateOrder(tr.TransformPoint(new Vector3(-7.4f, 13.4f, 53.8f)), configData.Monument.Tunnels);
                        count++;
                        continue;
                    }
                    if (gobject.name.Contains("harbor_1") && configData.Monument.LargeHarbor.Enabled) {
                        HordeManager.Order.CreateOrder(tr.TransformPoint(new Vector3(54.7f, 5.1f, -39.6f)), configData.Monument.LargeHarbor);
                        count++;
                        continue;
                    }
                    if (gobject.name.Contains("harbor_2") && configData.Monument.SmallHarbor.Enabled) {
                        HordeManager.Order.CreateOrder(tr.TransformPoint(new Vector3(-66.6f, 4.9f, 16.2f)), configData.Monument.SmallHarbor);
                        count++;
                        continue;
                    }
                    if (gobject.name.Contains("airfield_1") && configData.Monument.Airfield.Enabled) {
                        HordeManager.Order.CreateOrder(tr.TransformPoint(new Vector3(-12.4f, 0.2f, -28.9f)), configData.Monument.Airfield);
                        count++;
                        continue;
                    }
                    if (gobject.name.Contains("trainyard_1") && configData.Monument.Trainyard.Enabled) {
                        HordeManager.Order.CreateOrder(tr.TransformPoint(new Vector3(35.8f, 0.2f, -0.8f)), configData.Monument.Trainyard);
                        count++;
                        continue;
                    }
                    if (gobject.name.Contains("water_treatment_plant_1") && configData.Monument.WaterTreatment.Enabled) {
                        HordeManager.Order.CreateOrder(tr.TransformPoint(new Vector3(11.1f, 0.3f, -80.2f)), configData.Monument.WaterTreatment);
                        count++;
                        continue;
                    }
                    if (gobject.name.Contains("warehouse") && configData.Monument.Warehouse.Enabled) {
                        HordeManager.Order.CreateOrder(tr.TransformPoint(new Vector3(-2.8f, 0.1f, -8.1f)), configData.Monument.Warehouse);
                        count++;
                        continue;
                    }
                    if (gobject.name.Contains("satellite_dish") && configData.Monument.Satellite.Enabled) {
                        HordeManager.Order.CreateOrder(tr.TransformPoint(new Vector3(18.6f, 6.0f, -7.5f)), configData.Monument.Satellite);
                        count++;
                        continue;
                    }
                    if (gobject.name.Contains("sphere_tank") && configData.Monument.Dome.Enabled) {
                        HordeManager.Order.CreateOrder(tr.TransformPoint(new Vector3(-8.8f, 0.7f, 4.5f)), configData.Monument.Dome);
                        count++;
                        continue;
                    }
                    if (gobject.name.Contains("radtown_small_3") && configData.Monument.Radtown.Enabled) {
                        HordeManager.Order.CreateOrder(tr.TransformPoint(new Vector3(-16.3f, -2.1f, -3.3f)), configData.Monument.Radtown);
                        count++;
                        continue;
                    }
                    if (gobject.name.Contains("launch_site_1") && configData.Monument.LaunchSite.Enabled) {
                        HordeManager.Order.CreateOrder(tr.TransformPoint(new Vector3(222.1f, 3.3f, 0.0f)), configData.Monument.LaunchSite);
                        count++;
                        continue;
                    }
                    if (gobject.name.Contains("gas_station_1") && configData.Monument.GasStation.Enabled) {
                        HordeManager.Order.CreateOrder(tr.TransformPoint(new Vector3(-9.8f, 3.0f, 7.2f)), configData.Monument.GasStation);
                        count++;
                        continue;
                    }
                    if (gobject.name.Contains("supermarket_1") && configData.Monument.Supermarket.Enabled) {
                        HordeManager.Order.CreateOrder(tr.TransformPoint(new Vector3(3.4f, 0.0f, -8.9f)), configData.Monument.Supermarket);
                        count++;
                        continue;
                    }
                    if (gobject.name.Contains("mining_quarry_c") && configData.Monument.HQMQuarry.Enabled) {
                        HordeManager.Order.CreateOrder(tr.TransformPoint(new Vector3(15.8f, 4.5f, -1.5f)), configData.Monument.HQMQuarry);
                        count++;
                        continue;
                    }
                    if (gobject.name.Contains("mining_quarry_a") && configData.Monument.SulfurQuarry.Enabled) {
                        HordeManager.Order.CreateOrder(tr.TransformPoint(new Vector3(-0.8f, 0.6f, 11.4f)), configData.Monument.SulfurQuarry);
                        count++;
                        continue;
                    }
                    if (gobject.name.Contains("mining_quarry_b") && configData.Monument.StoneQuarry.Enabled) {
                        HordeManager.Order.CreateOrder(tr.TransformPoint(new Vector3(-7.6f, 0.2f, 12.3f)), configData.Monument.StoneQuarry);
                        count++;
                        continue;
                    }
                    if (gobject.name.Contains("junkyard_1") && configData.Monument.Junkyard.Enabled) {
                        HordeManager.Order.CreateOrder(tr.TransformPoint(new Vector3(12.8f, 10.8f, -58.4f)), configData.Monument.Junkyard);
                        count++;
                        continue;
                    }
                }
            }
            if (count < configData.Horde.MaximumHordes) CreateRandomHordes();
        }
        private void CreateRandomHordes() {
            int amountToCreate = configData.Horde.MaximumHordes - HordeManager._allHordes.Count;
            for (int i = 0; i < amountToCreate; i++) {
                float roamDistance = configData.Horde.LocalRoam ? configData.Horde.RoamDistance : -1;
                string profile = configData.Horde.UseProfiles ? configData.HordeProfiles.Keys.ToArray().GetRandom() : string.Empty;
                HordeManager.Order.CreateOrder(GetSpawnPoint(), configData.Horde.InitialMemberCount, configData.Horde.MaximumMemberCount, roamDistance, profile);
            }
        }
#endregion
#region Inventory and Loot
        private void SpawnIntoContainer(LootableCorpse lootableCorpse) {
            int count = UnityEngine.Random.Range(configData.Loot.Random.Minimum, configData.Loot.Random.Maximum);
            int spawnedCount = 0;
            int loopCount = 0;
            while (true) {
                loopCount++;
                if (loopCount > 3) return;
                float probability = UnityEngine.Random.Range(0f, 1f);
                List<ConfigData.LootTable.RandomLoot.LootDefinition> definitions = new List<ConfigData.LootTable.RandomLoot.LootDefinition>(configData.Loot.Random.List);
                for (int i = 0; i < configData.Loot.Random.List.Count; i++) {
                    ConfigData.LootTable.RandomLoot.LootDefinition lootDefinition = definitions.GetRandom();
                    definitions.Remove(lootDefinition);
                    if (lootDefinition.Probability >= probability) {
                        CreateItem(lootDefinition, lootableCorpse.containers[0]);
                        spawnedCount++;
                        if (spawnedCount >= count) return;
                    }
                }
            }
        }
        private void CreateItem(ConfigData.LootTable.RandomLoot.LootDefinition lootDefinition, ItemContainer container) {
            Item item = null;
            if (!lootDefinition.IsBlueprint) item = ItemManager.CreateByName(lootDefinition.Shortname, lootDefinition.GetAmount(), lootDefinition.SkinID);
            else {
                item = ItemManager.Create(blueprintBase);
                item.blueprintTarget = ItemManager.FindItemDefinition(lootDefinition.Shortname).itemid;
            }
            if (item != null) {
                item.OnVirginSpawn();
                if (!item.MoveToContainer(container, -1, true)) item.Remove(0f);
            }
            if (lootDefinition.Required != null) CreateItem(lootDefinition.Required, container);
        }
        private static void StripInventory(BasePlayer player, bool skipWear = false) {
            List<Item> list = Pool.GetList<Item>();
            player.inventory.AllItemsNoAlloc(ref list);
            for (int i = list.Count - 1; i >= 0; i--) {
                Item item = list[i];
                if (skipWear && item?.parent == player.inventory.containerWear) continue;
                item.RemoveFromContainer();
                item.Remove();
            }
            Pool.FreeList(ref list);
        }
        private static void ClearContainer(ItemContainer container, bool skipWear = false) {
            if (container == null || container.itemList == null) return;
            while (container.itemList.Count > 0) {
                Item item = container.itemList[0];
                item.RemoveFromContainer();
                item.Remove(0f);
            }
        }
#endregion
#region Spawning
        private static HTNPlayer InstantiateEntity(Vector3 position) {
            GameObject gameObject = Facepunch.Instantiate.GameObject(GameManager.server.FindPrefab(SCARECROW_PREFAB), position, new Quaternion());
            gameObject.name = SCARECROW_PREFAB;
            UnityEngine.SceneManagement.SceneManager.MoveGameObjectToScene(gameObject, Rust.Server.EntityScene);
            UnityEngine.Object.Destroy(gameObject.GetComponent<Spawnable>());
            if (!gameObject.activeSelf) gameObject.SetActive(true);
            HTNPlayer component = gameObject.GetComponent<HTNPlayer>();
            return component;
        }
        private static NavMeshHit navHit;
        private static RaycastHit raycastHit;
        private static object FindPointOnNavmesh(Vector3 targetPosition, float maxDistance = 4f) {
            List<Collider> list = Pool.GetList<Collider>();
            try {
                for (int i = 0; i < 10; i++) {
                    list.Clear();
                    if (NavMesh.SamplePosition(targetPosition, out navHit, maxDistance, Instance.navmeshAreaMask)) {
                        if (IsNearOrInWorldCollider(list, navHit.position)) continue;
                        float terrainHeight = TerrainMeta.HeightMap.GetHeight(navHit.position);
                        if (terrainHeight > navHit.position.y || navHit.position.y - terrainHeight > 3f) continue;
                        return navHit.position;
                    }
                }
                return null;
            }
            finally {
                Pool.FreeList(ref list);
            }
        }
        private static bool IsNearOrInWorldCollider(List<Collider> list, Vector3 position) {
            GamePhysics.OverlapSphere(position, 1f, list, WORLD_LAYER, QueryTriggerInteraction.Ignore);
            list.RemoveAll(x => x.gameObject.name.Contains("road"));
            return list.Count > 0;
        }
#endregion
#endregion
#region Components
        private class RestrictedTickRate : MonoBehaviour {
            private int lastIndex = 0;
            private float nextTick;
            private const float TICK_RATE = 0.2f;
            private void Update() {
                int count = HordeManager._allHordes?.Count ?? 0;
                if (Time.time < nextTick || count == 0) return;
                if (lastIndex >= count - 1) lastIndex = 0;
                HordeManager manager = HordeManager._allHordes[lastIndex];
                if (manager.members.Count == 0) manager.Destroy();
                else manager.HordeTick();
                lastIndex++;
                nextTick = Time.time + TICK_RATE;
            }
        }
        internal class HordeManager {
            internal static List<HordeManager> _allHordes = new List<HordeManager>();
            internal List<HordeMember> members;
            internal Vector3 Destination;
            internal Vector3 AverageLocation;
            internal BaseEntity PrimaryTarget;
            internal NpcPlayerInfo NpcPlayerInfo;
            internal AnimalInfo AnimalInfo;
            private bool knownTargetNull = false;
            private bool isRoaming = true;
            private bool isRegrouping = false;
            private Vector3 initialSpawnPosition;
            private int initialMemberCount;
            private bool isLocalHorde = false;
            private float maximumRoamDistance;
            internal string hordeProfile;
            private float nextGrowthTime = Time.time + configData.Horde.GrowthRate;
            private int maximumMemberCount;
            private float nextMergeTime = Time.time + MERGE_COOLDOWN;
            private float refreshRoamTime;
            private const float MERGE_COOLDOWN = 180f;
            private const float ROAM_REFRESH_RATE = 3f;
            internal static bool Create(Order order) {
                HordeManager manager = new HordeManager();
                manager.members = Pool.GetList<HordeMember>();
                manager.initialSpawnPosition = order.position;
                if (order.maximumRoamDistance > 0) {
                    manager.isLocalHorde = true;
                    manager.maximumRoamDistance = order.maximumRoamDistance;
                }
                manager.initialMemberCount = order.initialMemberCount;
                manager.maximumMemberCount = order.maximumMemberCount;
                manager.hordeProfile = order.hordeProfile;
                for (int i = 0; i < order.initialMemberCount; i++) manager.SpawnMember(order.position, false);
                if (manager.members.Count == 0) {
                    manager.Destroy(true);
                    return false;
                }
                manager.SetPrimaryTarget(null, default(NpcPlayerInfo));
                _allHordes.Add(manager);
                return true;
            }
            internal void Destroy(bool permanent = false) {
                for (int i = members.Count - 1; i >= 0; i--) {
                    HTNPlayer npc = members[i]?.NPC;
                    if (npc != null && !npc.IsDestroyed) npc.Kill();
                }
                Pool.FreeList(ref members);
                _allHordes.Remove(this);
                if (!IsUnloading) {
                    InvokeHandler.Invoke(Instance.restrictedTickRate, () => Order.CreateOrder(isLocalHorde ? initialSpawnPosition : Instance.GetSpawnPoint(), initialMemberCount, maximumMemberCount, isLocalHorde ? maximumRoamDistance : -1f, hordeProfile), configData.Horde.RespawnTime);
                }
            }
            internal void HordeTick() {
                if (members.Count == 0) return;
                AverageLocation = GetAverageVector();
                TryMergeHordes();
                TryGrowHorde();
                if (!knownTargetNull && !IsValidTarget(PrimaryTarget)) {
                    SetPrimaryTarget(null, default(NpcPlayerInfo));
                    knownTargetNull = true;
                }
                bool hasSeentargetRecently = false;
                float currentTime = Time.time;
                for (int i = 0; i < members.Count; i++) {
                    HordeMember member = members[i];
                    member.OnTick();
                    if (!isRoaming && !hasSeentargetRecently) {
                        if (currentTime - member.lastSeenTargetTime < configData.Horde.ForgetTime) {
                            hasSeentargetRecently = true;
                            if (PrimaryTarget != null) Destination = PrimaryTarget.ServerPosition;
                        }
                    }
                }
                if (!isRoaming && !hasSeentargetRecently) {
                    isRoaming = true;
                    SendMemberUpdate(default(NpcPlayerInfo));
                    return;
                }
                if (isRoaming) {
                    if (Time.time > refreshRoamTime) {
                        refreshRoamTime = Time.time + ROAM_REFRESH_RATE;
                        if (GetMaximumSeperation() > 10f && !isRegrouping) {
                            isRegrouping = true;
                            Destination = AverageLocation;
                            SendMemberUpdate(default(NpcPlayerInfo));
                            return;
                        }
                        if (Vector3.Distance(Destination, AverageLocation) < 5f) {
                            isRegrouping = false;
                            Destination = GetRandomLocation();
                            SendMemberUpdate(default(NpcPlayerInfo));
                            return;
                        }
                        UpdateRoamTarget();
                    }
                }
            }
            internal void EvaluateTarget(NpcPlayerInfo target) {
                if (PrimaryTarget == target.Player) return;
                if (PrimaryTarget == null) {
                    SetPrimaryTarget(target.Player, target);
                    return;
                }
                if (Vector3.Distance(AverageLocation, target.Player.transform.position) < Vector3.Distance(AverageLocation, PrimaryTarget.transform.position) || PrimaryTarget is BaseNpc) {
                    SetPrimaryTarget(target.Player, target);
                    return;
                }
            }
            internal void EvaluateTarget(AnimalInfo target) {
                if (PrimaryTarget == target.Animal) return;
                if (PrimaryTarget == null) {
                    SetPrimaryTarget(target.Animal, target);
                    return;
                }
                if (PrimaryTarget is BasePlayer) return;
                if (Vector3.Distance(AverageLocation, target.Animal.transform.position) < Vector3.Distance(AverageLocation, PrimaryTarget.transform.position)) {
                    SetPrimaryTarget(target.Animal, target);
                    return;
                }
            }
            internal void SetPrimaryTarget(BaseEntity target, NpcPlayerInfo info) {
                SetPrimaryTarget(target);
                PrimaryTarget = target;
                NpcPlayerInfo = info;
                AnimalInfo = default(AnimalInfo);
                for (int i = 0; i < members.Count; i++) {
                    members[i].OnTargetUpdated(info);
                }
            }
            internal void SetPrimaryTarget(BaseEntity target, AnimalInfo info) {
                SetPrimaryTarget(target);
                PrimaryTarget = target;
                NpcPlayerInfo = default(NpcPlayerInfo);
                AnimalInfo = info;
                SendMemberUpdate(info);
            }
            internal void SetPrimaryTarget(BaseEntity target) {
                if (target == null) {
                    NpcPlayerInfo = default(NpcPlayerInfo);
                    AnimalInfo = default(AnimalInfo);
                    isRoaming = true;
                    Destination = GetRandomLocation();
                }
                else {
                    knownTargetNull = false;
                    isRoaming = false;
                    isRegrouping = false;
                    Destination = target.transform.position;
                }
            }
            private void SendMemberUpdate(NpcPlayerInfo info) {
                for (int i = 0; i < members.Count; i++) {
                    members[i]?.OnTargetUpdated(info);
                }
            }
            private void SendMemberUpdate(AnimalInfo info) {
                for (int i = 0; i < members.Count; i++) {
                    members[i]?.OnTargetUpdated(info);
                }
            }
            private void UpdateRoamTarget() {
                for (int i = 0; i < members.Count; i++) {
                    members[i]?.SetRoamToDestination();
                }
            }
            internal Vector3 GetAverageVector() {
                Vector3 location = Vector3.zero;
                if (members.Count == 0) return location;
                int count = 0;
                for (int i = 0; i < members.Count; i++) {
                    HordeMember hordeMember = members[i];
                    if (hordeMember == null || hordeMember.NPC == null) continue;
                    location += hordeMember.transform.position;
                    count++;
                }
                return location /= count;
            }
            private Vector3 GetRandomLocation() {
                Vector3 position = Vector3.zero;
                if (isLocalHorde) {
                    Vector2 randomInCircle = UnityEngine.Random.insideUnitCircle * maximumRoamDistance;
                    position = initialSpawnPosition + new Vector3(randomInCircle.x, 0, randomInCircle.y);
                    position.y = TerrainMeta.HeightMap.GetHeight(position);
                }
                else {
                    if (Instance.RandomSpawns) {
                        object success = Instance.RandomSpawns.Call("GetSpawnPoint");
                        if (success is Vector3) position = (Vector3)success;
                    }
                    if (position == Vector3.zero) {
                        Vector2 randomInCircle = UnityEngine.Random.insideUnitCircle * (World.Size / 3f);
                        position.x = randomInCircle.x;
                        position.z = randomInCircle.y;
                        position.y = TerrainMeta.HeightMap.GetHeight(position);
                    }
                }
                if (NavMesh.SamplePosition(position, out navHit, 150, Instance.navmeshAreaMask)) return navHit.position;
                return position;
            }
            private float GetMaximumSeperation() {
                float distance = 0;
                for (int i = 0; i < members.Count; i++) {
                    HordeMember member = members[i];
                    if (member?.NPC != null) {
                        float d = Vector3.Distance(members[i].NPC.transform.position, AverageLocation);
                        if (d > distance) distance = d;
                    }
                }
                return distance;
            }
            internal bool IsValidTarget(BaseEntity target) {
                if (target == null || target.IsDestroyed) return false;
                if (target.Health() <= 0f) return false;
                if (target is BasePlayer) {
                    BasePlayer player = target as BasePlayer;
                    if (Instance.Vanish != null && (bool)Instance.Vanish?.Call("IsInvisible", player)) return false;
                    if (player.IsFlying) return false;
                    if (player.IsNpc) {
                        if ((player as HTNPlayer)?.AiDefinition?.Info?.Family == BaseNpcDefinition.Family.Murderer) return false;
                        if (!configData.Member.TargetNPCs && (player is Scientist || player is ScientistNPC || player is HTNPlayer || player is NPCPlayerApex)) return false;
                    }
                    if (player.HasPlayerFlag(BasePlayer.PlayerFlags.SafeZone)) return false;
                    if (configData.Member.IgnoreSleepers && player.IsSleeping()) return false;
                    if (Instance.permission.UserHasPermission(player.UserIDString, "zombiehorde.ignore")) return false;
                }
                return true;
            }
            internal bool SpawnMember(Vector3 position, bool alreadyInitialized = true) {
                Vector2 random = UnityEngine.Random.insideUnitCircle * 3;
                Vector3 spawnPosition = Vector3.zero;
                object success = FindPointOnNavmesh(position + new Vector3(random.x, 0, random.y), maximumRoamDistance == -1 ? 4f : 1f);
                if (success == null) {
                    if (members?.Count > 0) {
                        spawnPosition = members.GetRandom().transform.position;
                        Vector2 r = UnityEngine.Random.insideUnitCircle.normalized;
                        spawnPosition += new Vector3(r.x, 0f, r.y);
                    }
                    else return false;
                }
                else spawnPosition = (Vector3)success;
                HTNPlayer npc = InstantiateEntity(spawnPosition);
                if (npc == null) return false;
                npc.enableSaving = false;
                npc.Spawn();
                HordeMember member = npc.gameObject.AddComponent<HordeMember>();
                member.Manager = this;
                members.Add(member);
                if (alreadyInitialized) {
                    if (PrimaryTarget == null || PrimaryTarget is BasePlayer) member.OnTargetUpdated(NpcPlayerInfo);
                    else if (PrimaryTarget is BaseNpc) member.OnTargetUpdated(AnimalInfo);
                }
                return true;
            }
            internal void OnPlayerDeath(BasePlayer player, HordeMember hordeMember) {
                if (hordeMember == null || !members.Contains(hordeMember)) return;
                if (members.Count < maximumMemberCount) SpawnMember(player.transform.position);
            }
            internal void OnMemberDeath(HordeMember hordeMember) {
                members.Remove(hordeMember);
                if (members.Count == 0) Destroy();
            }
            private void TryGrowHorde() {
                if (nextGrowthTime < Time.time) {
                    if (members.Count < maximumMemberCount) {
                        for (int i = 0; i < 5; i++) {
                            if (SpawnMember(AverageLocation)) break;
                        }
                    }
                    nextGrowthTime = Time.time + configData.Horde.GrowthRate;
                }
            }
            private void TryMergeHordes() {
                if (!configData.Horde.MergeHordes || nextMergeTime > Time.time) return;
                for (int y = _allHordes.Count - 1; y >= 0; y--) {
                    HordeManager manager = _allHordes[y];
                    if (manager == this) continue;
                    if (members.Count >= maximumMemberCount) return;
                    if (Vector3.Distance(AverageLocation, manager.AverageLocation) < 20) {
                        int amountToMerge = maximumMemberCount - members.Count;
                        if (amountToMerge >= manager.members.Count) {
                            for (int i = 0; i < manager.members.Count; i++) {
                                HordeMember member = manager.members[i];
                                members.Add(member);
                                member.Manager = this;
                            }
                            manager.members.Clear();
                            manager.Destroy();
                            nextMergeTime = Time.time + MERGE_COOLDOWN;
                        }
                        else {
                            bool hasMerged = false;
                            for (int i = 0; i < amountToMerge; i++) {
                                if (manager.members.Count > 0) {
                                    HordeMember member = manager.members[0];
                                    members.Add(member);
                                    member.Manager = this;
                                    manager.members.Remove(member);
                                    hasMerged = true;
                                }
                            }
                            if (hasMerged) nextMergeTime = Time.time + MERGE_COOLDOWN;
                        }
                    }
                }
            }
            public class Order {
                public Vector3 position;
                public int initialMemberCount;
                public int maximumMemberCount;
                public float maximumRoamDistance;
                public string hordeProfile;
                public Order(Vector3 position, int initialMemberCount, string hordeProfile) {
                    this.position = position;
                    this.initialMemberCount = initialMemberCount;
                    maximumMemberCount = configData.Horde.MaximumMemberCount;
                    maximumRoamDistance = -1f;
                    this.hordeProfile = hordeProfile;
                }
                public Order(Vector3 position, int initialMemberCount, int maximumMemberCount, float maximumRoamDistance, string hordeProfile) {
                    this.position = position;
                    this.initialMemberCount = initialMemberCount;
                    this.maximumMemberCount = maximumMemberCount;
                    this.maximumRoamDistance = maximumRoamDistance;
                    this.hordeProfile = hordeProfile;
                }
                internal static Queue<Order> _queue = new Queue<Order>();
                private static bool IsRunning {
                    get;
                    set;
                }
                public static void CreateOrder(Vector3 position, int initialMemberCount, int maximumMemberCount, float maximumRoamDistance, string hordeProfile) {
                    _queue.Enqueue(new Order(position, initialMemberCount, maximumMemberCount, maximumRoamDistance, hordeProfile));
                    if (!IsRunning) ServerMgr.Instance.StartCoroutine(ProcessOrders());
                }
                public static void CreateOrder(Vector3 position, ConfigData.MonumentSpawn.MonumentSettings settings) {
                    object success = FindPointOnNavmesh(position, 0.1f);
                    if (position == null) return;
                    _queue.Enqueue(new Order(position, configData.Horde.InitialMemberCount, settings.HordeSize, settings.RoamDistance, settings.Profile));
                    if (!IsRunning) ServerMgr.Instance.StartCoroutine(ProcessOrders());
                }
                private static IEnumerator ProcessOrders() {
                    IsRunning = true;
                    while (HordeManager._allHordes?.Count >= configData.Horde.MaximumHordes) {
                        yield return CoroutineEx.waitForSeconds(10f);
                    }
                    Order order = _queue.Dequeue();
                    if (order != null) HordeManager.Create(order);
                    if (_queue.Count > 0) {
                        yield return CoroutineEx.waitForSeconds(3f);
                        yield return ServerMgr.Instance.StartCoroutine(ProcessOrders());
                    }
                    IsRunning = false;
                }
            }
        }
        internal class HordeMember : MonoBehaviour {
            internal HTNPlayer NPC {
                get;
                private set;
            }
            internal MurdererDomain Domain {
                get;
                private set;
            }
            internal MurdererContext Context {
                get;
                private set;
            }
            internal MurdererMemory Memory {
                get;
                private set;
            }
            internal HordeManager Manager {
                get;
                set;
            }
            internal List<AnimalInfo> animalsLineOfSight = Pool.GetList<AnimalInfo>();
            internal float damageMultiplier;
            internal float lastSeenTargetTime;
            private ItemContainer[] containers;
            private void Awake() {
                NPC = GetComponent<HTNPlayer>();
                Domain = NPC.AiDomain as MurdererDomain;
                Context = Domain.MurdererContext;
                Memory = Context.Memory;
                InitializeSensorsAndReasoners();
                InitializeNpc();
            }
            private void OnDestroy() {
                Pool.Free(ref animalsLineOfSight);
            }
            private void InitializeSensorsAndReasoners() {
                int index = Domain.Reasoners.FindIndex(x => x is Rust.Ai.HTN.Murderer.Reasoners.ReturnHomeReasoner);
                Domain.Reasoners.RemoveAt(index);
                index = Domain.Sensors.FindIndex(x => x is Rust.Ai.HTN.Sensors.PlayersInRangeSensor);
                Domain.Sensors.RemoveAt(index);
                Domain.Sensors.Insert(index, new PlayersInRangeSensor(this));
                index = Domain.Sensors.FindIndex(x => x is Rust.Ai.HTN.Murderer.Sensors.AnimalsInRangeSensor);
                Domain.Sensors.RemoveAt(index);
                if (configData.Member.TargetAnimals) {
                    Domain.Sensors.Insert(index, new AnimalsInRangeSensor(this));
                    index = Domain.Reasoners.FindIndex(x => x is Rust.Ai.HTN.Murderer.Reasoners.EnemyRangeReasoner);
                    Domain.Reasoners.RemoveAt(index);
                    Domain.Reasoners.Add(new EnemyRangeReasoner(this));
                    index = Domain.Reasoners.FindIndex(x => x is Rust.Ai.HTN.Murderer.Reasoners.EnemyTargetReasoner);
                    Domain.Reasoners.RemoveAt(index);
                    Domain.Reasoners.Add(new EnemyTargetReasoner(this));
                    index = Domain.Reasoners.FindIndex(x => x is Rust.Ai.HTN.Murderer.Reasoners.EnemyPlayerLineOfSightReasoner);
                    Domain.Reasoners.RemoveAt(index);
                    Domain.Reasoners.Add(new EnemyPlayerLineOfSightReasoner(this));
                    index = Domain.Reasoners.FindIndex(x => x is Rust.Ai.HTN.Murderer.Reasoners.FireTacticReasoner);
                    Domain.Reasoners.RemoveAt(index);
                    Domain.Reasoners.Add(new FireTacticReasoner(this));
                    index = Domain.Reasoners.FindIndex(x => x is Rust.Ai.HTN.Murderer.Reasoners.PreferredFightingRangeReasoner);
                    Domain.Reasoners.RemoveAt(index);
                    Domain.Reasoners.Add(new PreferredFightingRangeReasoner(this));
                    index = Domain.Reasoners.FindIndex(x => x is Rust.Ai.HTN.Murderer.Reasoners.AtLastKnownEnemyPlayerLocationReasoner);
                    Domain.Reasoners.RemoveAt(index);
                    Domain.Reasoners.Add(new AtLastKnownEnemyPlayerLocationReasoner(this));
                }
            }
            private void InitializeNpc() {
                StripInventory(NPC);
                InvokeHandler.Invoke(NPC, SpawnLoadout, 0.1f);
            }
            private void SpawnLoadout() {
                ConfigData.MemberOptions.Loadout loadout;
                if (!string.IsNullOrEmpty(Manager.hordeProfile) && configData.HordeProfiles.ContainsKey(Manager.hordeProfile)) {
                    string loadoutId = configData.HordeProfiles[Manager.hordeProfile].GetRandom();
                    loadout = configData.Member.Loadouts.Find(x => x.LoadoutID == loadoutId);
                }
                else loadout = configData.Member.Loadouts.GetRandom();
                var Max = 8730;
                if (Max == 0) {
                }
                NPC.displayName = loadout.Names.Length > 0 ? loadout.Names.GetRandom() : "Zombie";
                NPC.InitializeHealth(loadout.Health, loadout.Health);
                NPC.AiDefinition.Sensory.VisionRange = loadout.VisionRange;
                NPC.AiDefinition.Sensory.HearingRange = loadout.VisionRange * 0.5f;
                NPC.AiDefinition.Movement.RunSpeed = loadout.MovementSpeed;
                damageMultiplier = loadout.DamageMultiplier;
                for (int i = 0; i < loadout.BeltItems.Count; i++) {
                    ConfigData.LootTable.InventoryItem loadoutItem = loadout.BeltItems[i];
                    ItemManager.CreateByName(loadoutItem.Shortname, loadoutItem.Amount, loadoutItem.SkinID).MoveToContainer(NPC.inventory.containerBelt);
                }
                for (int i = 0; i < loadout.MainItem
// ... [Code preview truncated due to length. Full source in attached file] ...

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