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

FREE ZombieHorde : 0.3.5 0.3.5

Нет прав для скачивания
C#:
using Facepunch;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core.Plugins;
using Rust.Ai.HTN.Murderer;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.AI;
using Rust;
using System.Reflection;
using Rust.Ai;
namespace Oxide.Plugins {
    [Info("ZombieHorde", "k1lly0u", "0.3.5")]
    class ZombieHorde : RustPlugin {
        [PluginReference]
        private Plugin Kits, Spawns;
        private static ZombieHorde Instance {
            get;
            set;
        }
#region Oxide Hooks
        private void OnServerInitialized() {
            Instance = this;
            HordeThinkManager.Create();
            permission.RegisterPermission("zombiehorde.admin", this);
            permission.RegisterPermission("zombiehorde.ignore", this);
            _blueprintBase = ItemManager.FindItemDefinition("blueprintbase");
            _glowEyes = ItemManager.FindItemDefinition("gloweyes");
            if (!configData.Member.TargetedByPeaceKeeperTurrets) Unsubscribe(nameof(CanEntityBeHostile));
            ValidateLoadoutProfiles();
            ValidateSpawnSystem();
            CreateMonumentHordeOrders();
        }
        private void OnEntityTakeDamage(BaseCombatEntity baseCombatEntity, HitInfo hitInfo) {
            if (hitInfo != null) {
                HordeMember hordeMember;
                if (hitInfo.InitiatorPlayer != null) {
                    hordeMember = hitInfo.InitiatorPlayer.GetComponent<HordeMember>();
                    if (hordeMember != null) {
                        if (hitInfo.damageTypes.Get(DamageType.Explosion) > 0) {
                            hitInfo.damageTypes.ScaleAll(ConVar.Halloween.scarecrow_beancan_vs_player_dmg_modifier);
                            return;
                        }
                        if (hordeMember.DamageScale != 1f) hitInfo.damageTypes.ScaleAll(hordeMember.DamageScale);
                        return;
                    }
                }
                hordeMember = baseCombatEntity.GetComponent<HordeMember>();
                if (hordeMember != null) {
                    if (configData.Member.HeadshotKills && hitInfo.isHeadshot) hitInfo.damageTypes.ScaleAll(1000);
                }
            }
        }
        private void OnPlayerDeath(BasePlayer player, HitInfo hitInfo) {
            if (player == null || hitInfo == null) return;
            HordeMember hordeMember = player.GetComponent<HordeMember>();
            if (hordeMember != null) {
                for (int i = 0; i < player.inventory.containerWear.itemList.Count; i++) {
                    Item item = player.inventory.containerWear.itemList[i];
                    if (item != null && item.info == _glowEyes) {
                        player.inventory.containerWear.Remove(item);
                        break;
                    }
                }
                if (configData.Loot.DropInventory) hordeMember.PrepareInventory();
                hordeMember.Manager.OnMemberDeath(hordeMember, hitInfo.Initiator as BaseCombatEntity);
                return;
            }
            if (configData.Horde.CreateOnDeath && hitInfo.InitiatorPlayer != null) {
                HordeMember attacker = hitInfo.InitiatorPlayer.GetComponent<HordeMember>();
                if (attacker != null && attacker.Manager != null) attacker.Manager.OnPlayerDeath(player, attacker);
            }
        }
        private void OnEntityKill(ScientistNPC scientistNPC) {
            HordeMember hordeMember = scientistNPC.GetComponent<HordeMember>();
            if (hordeMember != null && hordeMember.Manager != null) hordeMember.Manager.OnMemberDeath(hordeMember, null);
        }
        private object CanBeTargeted(ScientistNPC scientistNPC, MonoBehaviour behaviour) {
            if (HordeMember._allHordeScientists.Contains(scientistNPC)) {
                if (((behaviour is AutoTurret) || (behaviour is GunTrap) || (behaviour is FlameTurret)) && configData.Member.TargetedByTurrets) return null;
                return false;
            }
            return null;
        }
        private object CanEntityBeHostile(ScientistNPC scientistNPC) => HordeMember._allHordeScientists.Contains(scientistNPC) ? (object)true : null;
        private object CanBradleyApcTarget(BradleyAPC bradleyAPC, ScientistNPC scientistNPC) {
            if (scientistNPC != null) {
                if (HordeMember._allHordeScientists.Contains(scientistNPC) && !configData.Member.TargetedByAPC) return false;
            }
            return null;
        }
        private object OnCorpsePopulate(ScientistNPC scientistNPC, NPCPlayerCorpse npcPlayerCorpse) {
            if (scientistNPC != null && npcPlayerCorpse != null) {
                HordeMember hordeMember = scientistNPC.GetComponent<HordeMember>();
                if (hordeMember == null) return null;
                npcPlayerCorpse.playerName = scientistNPC.displayName;
                if (configData.Loot.DropInventory) {
                    hordeMember.MoveInventoryTo(npcPlayerCorpse);
                    return npcPlayerCorpse;
                }
                SpawnIntoContainer(npcPlayerCorpse);
                return npcPlayerCorpse;
            }
            return null;
        }
        private object CanPopulateLoot(ScientistNPC scientistNPC, NPCPlayerCorpse corpse) => HordeMember._allHordeScientists.Contains(scientistNPC) ? (object)false : null;
        private void Unload() {
            HordeManager.Order.OnUnload();
            _hordeThinkManager.Destroy();
            for (int i = HordeManager._allHordes.Count - 1; i >= 0; i--) HordeManager._allHordes[i].Destroy(true, true);
            HordeManager._allHordes.Clear();
            _spawnState = SpawnState.Spawn;
            configData = null;
            Instance = null;
        }
#endregion
#region Sensations
        private void OnEntityKill(TimedExplosive timedExplosive) {
            if (!configData.Horde.UseSenses) return;
            HordeManager.Stimulate(new Sensation() {
                Type = SensationType.Explosion, Position = timedExplosive.transform.position, Radius = timedExplosive.explosionRadius * 17f,
            }
            );
        }
        private void OnEntityKill(Landmine landmine) {
            if (!configData.Horde.UseSenses) return;
            HordeManager.Stimulate(new Sensation() {
                Type = SensationType.Explosion, Position = landmine.transform.position, Radius = landmine.explosionRadius * 17f,
            }
            );
        }
        private void OnEntityKill(TreeEntity treeEntity) {
            if (!configData.Horde.UseSenses) return;
            HordeManager.Stimulate(new Sensation() {
                Type = SensationType.Gunshot, Position = treeEntity.transform.position, Radius = 30f,
            }
            );
        }
        private void OnEntityKill(OreResourceEntity oreResourceEntity) {
            if (!configData.Horde.UseSenses) return;
            HordeManager.Stimulate(new Sensation() {
                Type = SensationType.Gunshot, Position = oreResourceEntity.transform.position, Radius = 30f,
            }
            );
        }
        private void OnWeaponFired(BaseProjectile baseProjectile, BasePlayer player, ItemModProjectile itemModProjectile, ProtoBuf.ProjectileShoot projectileShoot) {
            if (!configData.Horde.UseSenses) return;
            HordeManager.Stimulate(new Sensation() {
                Type = SensationType.Gunshot, Position = player.transform.position, Radius = baseProjectile.NoiseRadius, Initiator = player
            }
            );
        }
        private void OnDispenserGather(ResourceDispenser dispenser, BaseEntity entity, Item item) {
            if (!configData.Horde.UseSenses) return;
            HordeManager.Stimulate(new Sensation() {
                Type = SensationType.Gunshot, Position = dispenser.transform.position, Radius = 10f
            }
            );
        }
#endregion
#region Functions
#region Horde Spawning
        private List<Vector3> _spawnPoints;
        private SpawnSystem _spawnSystem = SpawnSystem.None;
        private bool ValidateSpawnSystem() {
            _spawnSystem = ParseType<SpawnSystem>(configData.Horde.SpawnType);
            if (_spawnSystem == SpawnSystem.None) {
                PrintError("You have set an invalid value in the config entry \"Spawn Type\".Unable to spawn hordes!");
                return false;
            }
            else if (_spawnSystem == 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) return true;
                    }
                    PrintError("You have selected SpawnsDatabase as your method of spawning hordes, however the spawn file you have chosen is either invalid, or has no spawn points.Unable to spawn hordes!");
                    return false;
                }
                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;
            }
            return true;
        }
        private const int SPAWN_RAYCAST_MASK = 1 << 0 | 1 << 8 | 1 << 15 | 1 << 17 | 1 << 21 | 1 << 29;
        private const TerrainTopology.Enum SPAWN_TOPOLOGY_MASK = (TerrainTopology.Enum.Ocean | TerrainTopology.Enum.River | TerrainTopology.Enum.Lake | TerrainTopology.Enum.Cliff | TerrainTopology.Enum.Cliffside | TerrainTopology.Enum.Offshore | TerrainTopology.Enum.Summit | TerrainTopology.Enum.Decor);
        private Vector3 GetSpawnPoint() {
            switch (_spawnSystem) {
                case SpawnSystem.None : 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");
                        break;
                    }
                    if (_spawnPoints == null || _spawnPoints.Count == 0) {
                        PrintError("No spawnpoints have been loaded from the designated spawnfile.Defaulting to Rust spawns");
                        break;
                    }
                    Vector3 spawnPoint = _spawnPoints.GetRandom();
                    _spawnPoints.Remove(spawnPoint);
                    if (_spawnPoints.Count == 0) _spawnPoints = (List<Vector3>)Spawns.Call("LoadSpawnFile", configData.Horde.SpawnFile);
                    return spawnPoint;
                }
            }
            float size = (World.Size / 2f) * 0.75f;
            NavMeshHit navMeshHit;
            for (int i = 0; i < 10; i++) {
                Vector2 randomInCircle = UnityEngine.Random.insideUnitCircle * size;
                Vector3 position = new Vector3(randomInCircle.x, 0, randomInCircle.y);
                position.y = TerrainMeta.HeightMap.GetHeight(position);
                if (NavMesh.SamplePosition(position, out navMeshHit, 25f, 1)) {
                    position = navMeshHit.position;
                    if (Physics.SphereCast(new Ray(position + (Vector3.up * 5f), Vector3.down), 10f, 10f, SPAWN_RAYCAST_MASK)) continue;
                    if (ContainsTopologyAtPoint(SPAWN_TOPOLOGY_MASK, position)) continue;
                    if (WaterLevel.GetWaterDepth(position, true, null) <= 0.01f) return position;
                }
            }
            return ServerMgr.FindSpawnPoint().pos;
        }
        private void CreateMonumentHordeOrders() {
            int count = 0;
            GameObject[] allobjects = UnityEngine.Object.FindObjectsOfType<GameObject>();
            foreach (GameObject 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(16.6f, 0.1f, -7.5f)), 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(-44.6f, 5.8f, -3.0f)), 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(5.5f, 0.0f, -20.5f)), 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(-16.7f, 0.2f, 1.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 ItemDefinition _blueprintBase;
        private ItemDefinition _glowEyes;
        private static MurdererDefinition _defaultDefinition;
        private static MurdererDefinition DefaultDefinition {
            get {
                if (_defaultDefinition == null) _defaultDefinition = GameManager.server.FindPrefab("assets/prefabs/npc/scarecrow/scarecrow.prefab").GetComponent<HTNPlayer>().AiDefinition as MurdererDefinition;
                return _defaultDefinition;
            }
        }
        private void ValidateLoadoutProfiles() {
            Puts("Validating 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;
                }
            }
            foreach (ConfigData.MemberOptions.Loadout loadout in configData.Member.Loadouts) {
                if (loadout.Vitals == null) {
                    loadout.Vitals = new ConfigData.MemberOptions.Loadout.VitalStats() {
                        Health = DefaultDefinition.Vitals.HP
                    }
                    ;
                    hasChanged = true;
                }
                if (loadout.Movement == null) {
                    loadout.Movement = new ConfigData.MemberOptions.Loadout.MovementStats() {
                        DuckSpeed = DefaultDefinition.Movement.DuckSpeed, RunSpeed = DefaultDefinition.Movement.RunSpeed, WalkSpeed = DefaultDefinition.Movement.WalkSpeed
                    }
                    ;
                    hasChanged = true;
                }
                if (loadout.Sensory == null) {
                    loadout.Sensory = new ConfigData.MemberOptions.Loadout.SensoryStats() {
                        VisionRange = DefaultDefinition.Sensory.VisionRange
                    }
                    ;
                    hasChanged = true;
                }
            }
            if (hasChanged) SaveConfig();
        }
        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;
            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 ScientistNPC InstantiateEntity(Vector3 position) {
            const string SCIENTIST_PREFAB = "assets/rust.ai/agents/npcplayer/humannpc/heavyscientist/heavyscientist.prefab";
            GameObject gameObject = Instantiate.GameObject(GameManager.server.FindPrefab(SCIENTIST_PREFAB), position, Quaternion.identity);
            gameObject.name = SCIENTIST_PREFAB;
            UnityEngine.SceneManagement.SceneManager.MoveGameObjectToScene(gameObject, Rust.Server.EntityScene);
            UnityEngine.Object.Destroy(gameObject.GetComponent<Spawnable>());
            if (!gameObject.activeSelf) gameObject.SetActive(true);
            ScientistNPC component = gameObject.GetComponent<ScientistNPC>();
            return component;
        }
        private static NavMeshHit navmeshHit;
        private static RaycastHit raycastHit;
        private static Collider[] _buffer = new Collider[256];
        private const int WORLD_LAYER = 65536;
        private static object FindPointOnNavmesh(Vector3 targetPosition, float maxDistance = 4f) {
            for (int i = 0; i < 10; i++) {
                Vector3 position = i == 0 ? targetPosition : targetPosition + (UnityEngine.Random.onUnitSphere * maxDistance);
                if (NavMesh.SamplePosition(position, out navmeshHit, maxDistance, 1)) {
                    if (IsInRockPrefab(navmeshHit.position)) continue;
                    if (IsNearWorldCollider(navmeshHit.position)) continue;
                    return navmeshHit.position;
                }
            }
            return null;
        }
        private static bool IsInRockPrefab(Vector3 position) {
            Physics.queriesHitBackfaces = true;
            bool isInRock = Physics.Raycast(position, Vector3.up, out raycastHit, 20f, WORLD_LAYER, QueryTriggerInteraction.Ignore) && blockedColliders.Any(s => raycastHit.collider?.gameObject?.name.Contains(s) ?? false);
            Physics.queriesHitBackfaces = false;
            return isInRock;
        }
        private static bool IsNearWorldCollider(Vector3 position) {
            Physics.queriesHitBackfaces = true;
            int count = Physics.OverlapSphereNonAlloc(position, 2f, _buffer, WORLD_LAYER, QueryTriggerInteraction.Ignore);
            Physics.queriesHitBackfaces = false;
            int removed = 0;
            for (int i = 0; i < count; i++) {
                if (acceptedColliders.Any(s => _buffer[i].gameObject.name.Contains(s))) removed++;
            }
            return count - removed > 0;
        }
        private static readonly string[] acceptedColliders = new string[] {
            "road", "carpark", "rocket_factory", "range", "train_track", "runway", "_grounds", "concrete_slabs", "lighthouse", "cave", "office", "walkways", "sphere", "tunnel", "industrial", "junkyard"
        }
        ;
        private static readonly string[] blockedColliders = new string[] {
            "rock", "junk", "range", "invisible"
        }
        ;
#endregion
        private T ParseType<T>(string type) {
            try {
                return (T)Enum.Parse(typeof(T), type, true);
            }
            catch {
                return default(T);
            }
        }
        private static bool ContainsTopologyAtPoint(TerrainTopology.Enum mask, Vector3 position) => (TerrainMeta.TopologyMap.GetTopology(position, 1f) & (int)mask) != 0;
#endregion
#region Think Manager
        private HordeThinkManager _hordeThinkManager;
        private static SpawnState _spawnState = SpawnState.Spawn;
        private class HordeThinkManager : MonoBehaviour {
            internal static void Create() => Instance._hordeThinkManager = new GameObject("ZombieHorde-ThinkManager").AddComponent<HordeThinkManager>();
            private void Awake() {
                _spawnState = configData.TimedSpawns.Enabled ? (ShouldSpawn() ? SpawnState.Spawn : SpawnState.Despawn) : SpawnState.Spawn;
                if (configData.TimedSpawns.Enabled) InvokeHandler.InvokeRepeating(this, CheckTimeTick, 0f, 1f);
            }
            internal void Update() {
                HordeManager._hordeTickQueue.RunQueue(0.5);
            }
            internal void Destroy() {
                if (configData.TimedSpawns.Enabled) InvokeHandler.CancelInvoke(this, CheckTimeTick);
                Destroy(gameObject);
            }
            private bool ShouldSpawn() {
                float currentTime = TOD_Sky.Instance.Cycle.Hour;
                if (configData.TimedSpawns.Start > configData.TimedSpawns.End) return currentTime > configData.TimedSpawns.Start || currentTime < configData.TimedSpawns.End;
                else return currentTime > configData.TimedSpawns.Start && currentTime < configData.TimedSpawns.End;
            }
            private void CheckTimeTick() {
                if (ShouldSpawn()) {
                    if (_spawnState == SpawnState.Despawn) {
                        _spawnState = SpawnState.Spawn;
                        HordeManager.Order.StopDespawning();
                        HordeManager.Order.BeginSpawning();
                    }
                }
                else {
                    if (_spawnState == SpawnState.Spawn) {
                        _spawnState = SpawnState.Despawn;
                        if (configData.TimedSpawns.Despawn) {
                            HordeManager.Order.StopSpawning();
                            HordeManager.Order.BeginDespawning();
                        }
                    }
                }
            }
        }
        internal class HordeTickQueue : ObjectWorkQueue<HordeManager> {
            protected override void RunJob(HordeManager hordeManager) {
                if (!ShouldAdd(hordeManager)) return;
                hordeManager.HordeTick();
                Instance.timer.In(3f, ()=> HordeManager._hordeTickQueue.Add(hordeManager));
            }
            protected override bool ShouldAdd(HordeManager hordeManager) {
                if (!base.ShouldAdd(hordeManager)) return false;
                return hordeManager != null && !hordeManager.isDestroyed && hordeManager.members?.Count > 0;
            }
        }
#endregion
#region Horde Manager
        internal class HordeManager {
            internal static List<HordeManager> _allHordes = new List<HordeManager>();
            internal static HordeTickQueue _hordeTickQueue = new HordeTickQueue();
            internal List<HordeMember> members;
            private Vector3 destination;
            private Vector3 interestPoint;
            internal Vector3 AverageLocation {
                get;
                private set;
            }
            internal BaseCombatEntity PrimaryTarget;
            private bool isRegrouping = false;
            internal bool isDestroyed = 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 = 1f;
            internal bool HasInterestPoint => interestPoint != destination;
            internal Vector3 Destination => HasInterestPoint ? interestPoint : destination;
            private static readonly BasePlayer[] playersInVicinityQuery = new BasePlayer[1];
            private static readonly Func<BasePlayer, bool> filter = new Func<BasePlayer, bool>(IsHumanPlayer);
            internal static bool Create(Order order) {
                HordeManager manager = new HordeManager {
                    members = Pool.GetList<HordeMember>(), initialSpawnPosition = order.position, isLocalHorde = order.maximumRoamDistance > 0, maximumRoamDistance = order.maximumRoamDistance, initialMemberCount = order.initialMemberCount, maximumMemberCount = order.maximumMemberCount, hordeProfile = order.hordeProfile
                }
                ;
                for (int i = 0; i < order.initialMemberCount; i++) manager.SpawnMember(order.position, false);
                if (manager.members.Count == 0) {
                    manager.Destroy();
                    return false;
                }
                _allHordes.Add(manager);
                _hordeTickQueue.Add(manager);
                return true;
            }
            internal void Destroy(bool permanent = false, bool killNpcs = false) {
                isDestroyed = true;
                if (killNpcs) {
                    for (int i = members.Count - 1; i >= 0; i--) {
                        HordeMember hordeMember = members[i];
                        if (hordeMember != null && hordeMember.Entity != null && !hordeMember.Entity.IsDestroyed) hordeMember.Despawn();
                    }
                }
                members.Clear();
                Pool.FreeList(ref members);
                _allHordes.Remove(this);
                if (!permanent && _allHordes.Count <= configData.Horde.MaximumHordes) InvokeHandler.Invoke(Instance._hordeThinkManager, () => Order.CreateOrder(isLocalHorde ? initialSpawnPosition : Instance.GetSpawnPoint(), initialMemberCount, maximumMemberCount, isLocalHorde ? maximumRoamDistance : -1f, hordeProfile), configData.Horde.RespawnTime);
            }
            internal void HordeTick() {
                if (members.Count == 0 || isDestroyed) return;
                AverageLocation = GetAverageVector();
                UpdateDormancy();
                if (_isDormant) return;
                TryMergeHordes();
                TryGrowHorde();
                bool hasValidTarget = HasTarget();
                if ((PrimaryTarget is BasePlayer && ShouldIgnorePlayer(PrimaryTarget as BasePlayer)) || ShouldForgetTarget(this, PrimaryTarget)) {
                    PrimaryTarget = null;
                    hasValidTarget = false;
                }
                if (hasValidTarget) {
                    interestPoint = destination = PrimaryTarget.transform.position;
                    for (int i = 0; i < members.Count; i++) members[i].SetTarget();
                }
                else {
                    if (Time.time > refreshRoamTime) {
                        refreshRoamTime = Time.time + ROAM_REFRESH_RATE;
                        if ((!isRegrouping && GetMaximumSeperation() > 15f) || (isRegrouping && GetMaximumSeperation() > 5)) {
                            isRegrouping = true;
                            interestPoint = destination = members.GetRandom().Transform.position;
                        }
                        if (Destination == Vector3.zero || Vector3.Distance(Destination, AverageLocation) < 10f) {
                            isRegrouping = false;
                            interestPoint = destination = GetRandomLocation(isLocalHorde ? initialSpawnPosition : AverageLocation);
                        }
                    }
                }
            }
            internal bool HasTarget() => PrimaryTarget != null && PrimaryTarget.transform != null && !PrimaryTarget.IsDead();
            internal void SetPrimaryTarget(BaseCombatEntity baseCombatEntity) {
                if (baseCombatEntity == null || baseCombatEntity.transform == null) {
                    PrimaryTarget = null;
                    interestPoint = destination = AverageLocation;
                    return;
                }
                PrimaryTarget = baseCombatEntity;
                interestPoint = destination = PrimaryTarget.transform.position;
                for (int i = 0; i < members.Count; i++) {
                    members[i].SetTarget();
                }
            }
            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.Entity == null) continue;
                    location += hordeMember.Transform.position;
                    count++;
                }
                return location /= count;
            }
            private const TerrainTopology.Enum DESTINATION_TOPOLOGY_MASK = (TerrainTopology.Enum.Ocean | TerrainTopology.Enum.River | TerrainTopology.Enum.Lake | TerrainTopology.Enum.Offshore | TerrainTopology.Enum.Cliff);
            private Vector3 GetRandomLocation(Vector3 from) {
                for (int i = 0; i < 10; i++) {
                    Vector2 vector2 = UnityEngine.Random.insideUnitCircle * (isLocalHorde ? maximumRoamDistance : 100f);
                    Vector3 destination = from + new Vector3(vector2.x, 0f, vector2.y);
                    if (TerrainMeta.HeightMap != null) destination.y = TerrainMeta.HeightMap.GetHeight(destination);
                    if (IsInSafeZone(destination)) continue;
                    NavMeshHit navMeshHit;
                    if (NavMesh.FindClosestEdge(destination, out navMeshHit, 1)) {
                        destination = navMeshHit.position;
                        if (WaterLevel.GetWaterDepth(destination, true, null) <= 0.01f && !ContainsTopologyAtPoint(DESTINATION_TOPOLOGY_MASK, destination)) return destination;
                    }
                    else if (NavMesh.SamplePosition(destination, out navMeshHit, 5f, 1) && !ContainsTopologyAtPoint(DESTINATION_TOPOLOGY_MASK, destination)) {
                        destination = navMeshHit.position;
                        if (WaterLevel.GetWaterDepth(destination, true, null) <= 0.01f) return destination;
                    }
                }
                return AverageLocation;
            }
            private bool IsInSafeZone(Vector3 position) {
                int hits = Physics.OverlapSphereNonAlloc(position, 0.1f, Vis.colBuffer, 1 << 18);
                for (int i = 0; i < hits; i++) {
                    Collider col = Vis.colBuffer[i];
                    if (col.GetComponent<TriggerSafeZone>()) return true;
                }
                return false;
            }
            private float GetMaximumSeperation() {
                float distance = 0;
                for (int i = 0; i < members.Count; i++) {
                    HordeMember hordeMember = members[i];
                    if (hordeMember != null && hordeMember.Entity != null) {
                        float d = Vector3.Distance(hordeMember.Transform.position, AverageLocation);
                        if (d > distance) distance = d;
                    }
                }
                return distance;
            }
#region Dormancy
            private float _nextDormancyCheck;
            private bool _isDormant = false;
            private void UpdateDormancy() {
                if (configData.Member.DisableDormantSystem) return;
                if (Time.time < _nextDormancyCheck) return;
                _nextDormancyCheck = Time.time + UnityEngine.Random.Range(0.5f, 1.5f);
                if (IsHordeCloseToPlayers()) {
                    members.ForEach((HordeMember hordeMember) => hordeMember.Entity.IsDormant = false);
                    _isDormant = false;
                }
                else {
                    members.ForEach((HordeMember hordeMember) => hordeMember.Entity.IsDormant = true);
                    _isDormant = true;
                }
            }
            private bool IsHordeCloseToPlayers() => BaseEntity.Query.Server.GetPlayersInSphere(AverageLocation, AiManager.ai_to_player_distance_wakeup_range, HordeManager.playersInVicinityQuery, HordeManager.filter) > 0;
            private static bool IsHumanPlayer(BaseEntity entity) {
                BasePlayer basePlayer = entity as BasePlayer;
                if (basePlayer == null) return false;
                if (basePlayer is IAIAgent) return false;
                if (basePlayer.IsNpc || basePlayer is NPCPlayer || basePlayer is global : : HumanNPC || basePlayer is HTNPlayer) return false;
                if (!basePlayer.IsSleeping() && basePlayer.IsConnected) return true;
                return false;
            }
#endregion
            internal bool SpawnMember(Vector3 position, bool alreadyInitialized = true) {
                ScientistNPC scientistNPC = InstantiateEntity(position);
                scientistNPC.enableSaving = false;
                HordeMember._allHordeScientists.Add(scientistNPC);
                BaseAIBrain<global : : HumanNPC> defaultBrain = scientistNPC.GetComponent<BaseAIBrain<global : : HumanNPC>>();
                defaultBrain._baseEntity = scientistNPC;
                UnityEngine.Object.DestroyImmediate(defaultBrain);
                HordeMember member = scientistNPC.gameObject.AddComponent<HordeMember>();
                member.Manager = this;
                scientistNPC._brain = scientistNPC.gameObject.AddComponent<ZombieBrain>();
                scientistNPC.Spawn();
                member.Setup();
                members.Add(member);
                if (alreadyInitialized) {
                    if (PrimaryTarget != null) member.SetTarget();
                }
                return true;
            }
            internal void OnPlayerDeath(BasePlayer player, HordeMember hordeMember) {
                if (hordeMember == null || !members.Contains(hordeMember)) return;
                if (members.Count < maximumMemberCount) SpawnMember(hordeMember.Transform.position);
            }
            internal void OnMemberDeath(HordeMember hordeMember, BaseCombatEntity initiator) {
                if (isDestroyed || members == null) return;
                members.Remove(hordeMember);
                if (members.Count == 0) Destroy();
                else {
                    if (PrimaryTarget == null && initiator is BasePlayer) SetPrimaryTarget(initiator);
                }
            }
            private void TryGrowHorde() {
                if (nextGrowthTime < Time.time) {
                    if (members.Count < maximumMemberCount) {
                        for (int i = 0; i < 5; i++) {
                            if (SpawnMember(members.GetRandom().Transform.position)) 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;
                        }
                    }
                }
            }
            internal static bool ShouldForgetTarget(HordeManager hordeManager, BaseEntity baseEntity) {
                if (!configData.Horde.RestrictLocalChaseDistance || !hordeManager.isLocalHorde || hordeManager.maximumRoamDistance <= 0f) return false;
                if (baseEntity == null || baseEntity.transform == null) return false;
                return Vector3.Distance(hordeManager.initialSpawnPosition, baseEntity.transform.position) > hordeManager.maximumRoamDistance * 1.5f;
            }
            internal static bool ShouldIgnorePlayer(BasePlayer player) {
                if (player.IsDead()) return true;
                if (player._limitedNetworking) return true;
                if (player.IsFlying) return true;
                if (player.HasPlayerFlag(BasePlayer.PlayerFlags.SafeZone)) return true;
                if (configData.Member.IgnoreSleepers && player.IsSleeping()) return true;
                if (player.userID.IsSteamId() && Instance.permission.UserHasPermission(player.UserIDString, "zombiehorde.ignore")) return true;
                if (player is ScientistNPC && HordeMember._allHordeScientists.Contains(player as ScientistNPC)) return true;
                return false;
            }
            internal static void Stimulate(Sensation sensation) {
                float radius = sensation.Radius * sensation.Radius;
                BasePlayer target = sensation.Initiator as BasePlayer;
                for (int i = 0; i < _allHordes.Count; i++) {
                    HordeManager hordeManager = _allHordes[i];
                    if ((hordeManager.AverageLocation - sensation.Position).sqrMagnitude <= radius) {
    
// ... [Code preview truncated due to length. Full source in attached file] ...

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