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

FREE NpcSpawn : 2.7.1 2.7.1

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System;
using Facepunch;
using Newtonsoft.Json.Linq;
using Oxide.Core.Plugins;
using Rust;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using Oxide.Core;
using UnityEngine;
using UnityEngine.AI;
using System.IO;
using ProtoBuf;
using Newtonsoft.Json;
using Rust.AI;
using Oxide.Plugins.NpcSpawnExtensionMethods;
namespace Oxide.Plugins {
    [Info("NpcSpawn", "KpucTaJl", "2.7.1")]
    internal class NpcSpawn : RustPlugin {
#region Config
        private const bool En = false;
        private PluginConfig _config;
        protected override void LoadDefaultConfig() {
            Puts("Creating a default config...");
            _config = PluginConfig.DefaultConfig();
            _config.PluginVersion = Version;
            SaveConfig();
            Puts("Creation of the default config completed!");
        }
        protected override void LoadConfig() {
            base.LoadConfig();
            _config = Config.ReadObject<PluginConfig>();
            if (_config.PluginVersion < Version) UpdateConfigValues();
        }
        private void UpdateConfigValues() {
            Puts("Config update detected! Updating config values...");
            _config.PluginVersion = Version;
            Puts("Config update completed!");
            SaveConfig();
        }
        protected override void SaveConfig() => Config.WriteObject(_config);
        private class PluginConfig {
            [JsonProperty(En ? "Can NpcSpawn NPCs attack animals? [true/false]" : "Могут ли кастомные NPC атаковать животных? [true/false]")]
            public bool CanTargetAnimal {
                get;
                set;
            }
            [JsonProperty(En ? "Can NpcSpawn NPCs attack other NPCs? [true/false]" : "Могут ли кастомные NPC атаковать других NPC? [true/false]")]
            public bool CanTargetNpc {
                get;
                set;
            }
            [JsonProperty(En ? "Can NpcSpawn NPCs attack sleeping players? [true/false]" : "Могут ли кастомные NPC атаковать спящих игроков? [true/false]")]
            public bool CanTargetSleepingPlayer {
                get;
                set;
            }
            [JsonProperty(En ? "Can NpcSpawn NPCs attack wounded players? [true/false]" : "Могут ли кастомные NPC атаковать игроков в состоянии Wounded? [true/false]")]
            public bool CanTargetWoundedPlayer {
                get;
                set;
            }
            [JsonProperty(En ? "Can NpcSpawn NPCs attack players in SafeZone? [true/false]" : "Могут ли кастомные NPC атаковать игроков в SafeZone? [true/false]")]
            public bool CanTargetSafeZonePlayer {
                get;
                set;
            }
            [JsonProperty(En ? "Prefab path used for all NpcSpawn NPCs" : "Используемый prefab для кастомных NPC")]
            public string Prefab {
                get;
                set;
            }
            [JsonProperty(En ? "Configuration version" : "Версия конфигурации")]
            public VersionNumber PluginVersion {
                get;
                set;
            }
            public static PluginConfig DefaultConfig() {
                return new PluginConfig {
                    CanTargetAnimal = false, CanTargetNpc = false, CanTargetSleepingPlayer = false, CanTargetWoundedPlayer = false, CanTargetSafeZonePlayer = false, Prefab = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_heavy.prefab", PluginVersion = new VersionNumber()
                }
                ;
            }
        }
#endregion Config
#region NpcConfig
        internal class NpcBelt {
            public string ShortName;
            public int Amount;
            public ulong SkinID;
            public HashSet<string> Mods;
            public string Ammo;
        }
        internal class NpcWear {
            public string ShortName;
            public ulong SkinID;
        }
        internal class NpcConfig {
            public string Name {
                get;
                set;
            }
            public HashSet<NpcWear> WearItems {
                get;
                set;
            }
            public HashSet<NpcBelt> BeltItems {
                get;
                set;
            }
            public string Kit {
                get;
                set;
            }
            public float Health {
                get;
                set;
            }
            public float RoamRange {
                get;
                set;
            }
            public float ChaseRange {
                get;
                set;
            }
            public float SenseRange {
                get;
                set;
            }
            public float ListenRange {
                get;
                set;
            }
            public float AttackRangeMultiplier {
                get;
                set;
            }
            public bool CheckVisionCone {
                get;
                set;
            }
            public float VisionCone {
                get;
                set;
            }
            public bool HostileTargetsOnly {
                get;
                set;
            }
            public float DamageScale {
                get;
                set;
            }
            public float TurretDamageScale {
                get;
                set;
            }
            public float AimConeScale {
                get;
                set;
            }
            public bool DisableRadio {
                get;
                set;
            }
            public bool CanRunAwayWater {
                get;
                set;
            }
            public bool CanSleep {
                get;
                set;
            }
            public float SleepDistance {
                get;
                set;
            }
            public float Speed {
                get;
                set;
            }
            public int AreaMask {
                get;
                set;
            }
            public int AgentTypeID {
                get;
                set;
            }
            public string HomePosition {
                get;
                set;
            }
            public float MemoryDuration {
                get;
                set;
            }
            public HashSet<string> States {
                get;
                set;
            }
        }
#endregion NpcConfig
#region Methods
        private static bool IsCustomScientist(BaseEntity entity) => entity != null && entity.skinID == 11162132011012;
        private ScientistNPC SpawnNpc(Vector3 position, JObject configJson) {
            CustomScientistNpc npc = CreateCustomNpc(position, configJson.ToObject<NpcConfig>());
            if (npc == null) return null;
            npc.skinID = 11162132011012;
            Scientists.Add(npc.net.ID.Value, npc);
            return npc;
        }
        private CustomScientistNpc CreateCustomNpc(Vector3 position, NpcConfig config) {
            ScientistNPC scientistNpc = GameManager.server.CreateEntity(_config.Prefab, position, Quaternion.identity, false) as ScientistNPC;
            ScientistBrain scientistBrain = scientistNpc.GetComponent<ScientistBrain>();
            CustomScientistNpc customScientist = scientistNpc.gameObject.AddComponent<CustomScientistNpc>();
            CustomScientistBrain customScientistBrain = scientistNpc.gameObject.AddComponent<CustomScientistBrain>();
            CopySerializableFields(scientistNpc, customScientist);
            CopySerializableFields(scientistBrain, customScientistBrain);
            UnityEngine.Object.DestroyImmediate(scientistNpc, true);
            UnityEngine.Object.DestroyImmediate(scientistBrain, true);
            customScientist.Config = config;
            customScientist.Brain = customScientistBrain;
            customScientist.enableSaving = false;
            customScientist.gameObject.AwakeFromInstantiate();
            customScientist.Spawn();
            return customScientist;
        }
        private static void CopySerializableFields<T>(T src, T dst) {
            FieldInfo[] srcFields = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Instance);
            foreach (FieldInfo field in srcFields) {
                object value = field.GetValue(src);
                field.SetValue(dst, value);
            }
        }
        private void AddTargetRaid(CustomScientistNpc npc, HashSet<BuildingBlock> foundations) {
            if (IsCustomScientist(npc)) npc.Foundations = foundations;
        }
        private void AddTargetGuard(CustomScientistNpc npc, BaseEntity target) {
            if (IsCustomScientist(npc) && target != null) npc.AddTargetGuard(target);
        }
        private void SetParentEntity(CustomScientistNpc npc, BaseEntity parent, Vector3 pos) {
            if (IsCustomScientist(npc) && parent != null) npc.SetParentEntity(parent, pos);
        }
        private void SetHomePosition(CustomScientistNpc npc, Vector3 pos) {
            if (IsCustomScientist(npc)) npc.HomePosition = pos;
        }
        private void SetCurrentWeapon(CustomScientistNpc npc, Item weapon) {
            if (IsCustomScientist(npc)) npc.EquipCurrentWeapon(weapon);
        }
        private void SetCustomNavMesh(CustomScientistNpc npc, Transform transform, string navMeshName) {
            if (!IsCustomScientist(npc) || transform == null || !AllNavMeshes.ContainsKey(navMeshName)) return;
            Dictionary<int, Dictionary<int, PointNavMeshFile>> navMesh = AllNavMeshes[navMeshName];
            for (int i = 0; i < navMesh.Count; i++) {
                if (!npc.CustomNavMesh.ContainsKey(i)) npc.CustomNavMesh.Add(i, new Dictionary<int, PointNavMesh>());
                for (int j = 0; j < navMesh[i].Count; j++) {
                    PointNavMeshFile pointNavMesh = navMesh[i][j];
                    npc.CustomNavMesh[i].Add(j, new PointNavMesh {
                        Position = transform.TransformPoint(pointNavMesh.Position.ToVector3()), Enabled = pointNavMesh.Enabled
                    }
                    );
                }
            }
            npc.InitCustomNavMesh();
        }
        private BasePlayer GetCurrentTarget(CustomScientistNpc npc) => IsCustomScientist(npc) && npc.IsBasePlayerTarget ? npc.GetBasePlayerTarget : null;
#endregion Methods
#region Controller
        internal class DefaultSettings {
            public float EffectiveRange;
            public float AttackLengthMin;
            public float AttackLengthMax;
        }
        private static readonly Dictionary<string, DefaultSettings> Weapons = new Dictionary<string, DefaultSettings> {
            ["rifle.bolt"]
            = new DefaultSettings {
                EffectiveRange = 150f, AttackLengthMin = -1f, AttackLengthMax = -1f
            }
            , ["speargun"] = new DefaultSettings {
                EffectiveRange = 15f, AttackLengthMin = -1f, AttackLengthMax = -1f
            }
            , ["bow.compound"] = new DefaultSettings {
                EffectiveRange = 15f, AttackLengthMin = -1f, AttackLengthMax = -1f
            }
            , ["crossbow"] = new DefaultSettings {
                EffectiveRange = 15f, AttackLengthMin = -1f, AttackLengthMax = -1f
            }
            , ["bow.hunting"] = new DefaultSettings {
                EffectiveRange = 15f, AttackLengthMin = -1f, AttackLengthMax = -1f
            }
            , ["smg.2"] = new DefaultSettings {
                EffectiveRange = 20f, AttackLengthMin = 0.4f, AttackLengthMax = 0.4f
            }
            , ["shotgun.double"] = new DefaultSettings {
                EffectiveRange = 10f, AttackLengthMin = 0.3f, AttackLengthMax = 1f
            }
            , ["pistol.eoka"] = new DefaultSettings {
                EffectiveRange = 10f, AttackLengthMin = -1f, AttackLengthMax = -1f
            }
            , ["rifle.l96"] = new DefaultSettings {
                EffectiveRange = 150f, AttackLengthMin = -1f, AttackLengthMax = -1f
            }
            , ["pistol.nailgun"] = new DefaultSettings {
                EffectiveRange = 15f, AttackLengthMin = 0f, AttackLengthMax = 0.46f
            }
            , ["pistol.python"] = new DefaultSettings {
                EffectiveRange = 15f, AttackLengthMin = 0.175f, AttackLengthMax = 0.525f
            }
            , ["pistol.semiauto"] = new DefaultSettings {
                EffectiveRange = 15f, AttackLengthMin = 0f, AttackLengthMax = 0.46f
            }
            , ["pistol.prototype17"] = new DefaultSettings {
                EffectiveRange = 15f, AttackLengthMin = 0f, AttackLengthMax = 0.46f
            }
            , ["smg.thompson"] = new DefaultSettings {
                EffectiveRange = 20f, AttackLengthMin = 0.4f, AttackLengthMax = 0.4f
            }
            , ["shotgun.waterpipe"] = new DefaultSettings {
                EffectiveRange = 10f, AttackLengthMin = -1f, AttackLengthMax = -1f
            }
            , ["multiplegrenadelauncher"] = new DefaultSettings {
                EffectiveRange = 20f, AttackLengthMin = -1f, AttackLengthMax = -1f
            }
            , ["snowballgun"] = new DefaultSettings {
                EffectiveRange = 5f, AttackLengthMin = 2f, AttackLengthMax = 2f
            }
            , ["legacy bow"] = new DefaultSettings {
                EffectiveRange = 15f, AttackLengthMin = -1f, AttackLengthMax = -1f
            }
        }
        ;
        private static readonly HashSet<string> MeleeWeapons = new HashSet<string> {
            "bone.club", "knife.bone", "knife.butcher", "candycaneclub", "knife.combat", "longsword", "mace", "machete", "paddle", "pitchfork", "salvaged.cleaver", "salvaged.sword", "spear.stone", "spear.wooden", "chainsaw", "hatchet", "jackhammer", "pickaxe", "axe.salvaged", "hammer.salvaged", "icepick.salvaged", "stonehatchet", "stone.pickaxe", "torch", "sickle", "rock", "snowball", "mace.baseballbat", "concretepickaxe", "concretehatchet", "lumberjack.hatchet", "lumberjack.pickaxe", "diverhatchet", "diverpickaxe", "knife.skinning", "vampire.stake", "shovel", "spear.cny"
        }
        ;
        private static readonly HashSet<string> FirstDistanceWeapons = new HashSet<string> {
            "speargun", "bow.compound", "crossbow", "bow.hunting", "shotgun.double", "pistol.eoka", "flamethrower", "pistol.m92", "pistol.nailgun", "multiplegrenadelauncher", "shotgun.pump", "pistol.python", "pistol.revolver", "pistol.semiauto", "pistol.prototype17", "snowballgun", "shotgun.spas12", "shotgun.waterpipe", "shotgun.m4", "legacy bow", "military flamethrower"
        }
        ;
        private static readonly HashSet<string> SecondDistanceWeapons = new HashSet<string> {
            "smg.2", "smg.mp5", "rifle.semiauto", "smg.thompson", "rifle.sks"
        }
        ;
        private static readonly HashSet<string> ThirdDistanceWeapons = new HashSet<string> {
            "rifle.ak", "rifle.lr300", "lmg.m249", "rifle.m39", "hmlmg", "rifle.ak.ice", "rifle.ak.diver", "minigun"
        }
        ;
        private static readonly HashSet<string> FourthDistanceWeapons = new HashSet<string> {
            "rifle.bolt", "rifle.l96"
        }
        ;
        public class CustomScientistNpc : ScientistNPC {
            public NpcConfig Config {
                get;
                set;
            }
            = null;
            public Vector3 HomePosition {
                get;
                set;
            }
            = Vector3.zero;
            public float DistanceFromBase => Vector3.Distance(transform.position, HomePosition);
            public override void ServerInit() {
                base.ServerInit();
                HomePosition = string.IsNullOrEmpty(Config.HomePosition) ? transform.position : Config.HomePosition.ToVector3();
                if (NavAgent == null) NavAgent = GetComponent<NavMeshAgent>();
                if (NavAgent != null) {
                    NavAgent.areaMask = Config.AreaMask;
                    NavAgent.agentTypeID = Config.AgentTypeID;
                }
                startHealth = Config.Health;
                _health = Config.Health;
                damageScale = Config.DamageScale;
                if (Config.DisableRadio) {
                    CancelInvoke(PlayRadioChatter);
                    RadioChatterEffects = Array.Empty<GameObjectRef>();
                    DeathEffects = Array.Empty<GameObjectRef>();
                }
                inventory.containerWear.ClearItemsContainer();
                inventory.containerBelt.ClearItemsContainer();
                if (!string.IsNullOrEmpty(Config.Kit) && _ins.Kits != null) _ins.Kits.Call("GiveKit", this, Config.Kit);
                else UpdateInventory();
                displayName = Config.Name;
                if (IsBomber) SpawnTimedExplosive();
                InvokeRepeating(LightCheck, 1f, 30f);
                InvokeRepeating(UpdateTick, 1f, 2f);
            }
            private void UpdateInventory() {
                if (Config.WearItems.Count > 0) {
                    foreach (NpcWear wear in Config.WearItems) {
                        Item item = ItemManager.CreateByName(wear.ShortName, 1, wear.SkinID);
                        if (item == null) continue;
                        if (!item.MoveToContainer(inventory.containerWear)) item.Remove();
                    }
                }
                if (Config.BeltItems.Count > 0) {
                    foreach (NpcBelt belt in Config.BeltItems) {
                        Item item = ItemManager.CreateByName(belt.ShortName, belt.Amount, belt.SkinID);
                        if (item == null) continue;
                        if (item.MoveToContainer(inventory.containerBelt)) {
                            foreach (string shortname in belt.Mods) {
                                ItemDefinition mod = ItemManager.FindItemDefinition(shortname);
                                if (mod == null) continue;
                                item.contents.AddItem(mod, 1);
                            }
                        }
                        else item.Remove();
                    }
                }
            }
            private void OnDestroy() {
                if (HealCoroutine != null) ServerMgr.Instance.StopCoroutine(HealCoroutine);
                if (FireC4Coroutine != null) ServerMgr.Instance.StopCoroutine(FireC4Coroutine);
                if (FireRocketLauncherCoroutine != null) ServerMgr.Instance.StopCoroutine(FireRocketLauncherCoroutine);
                CancelInvoke();
                if (BomberTimedExplosive.IsExists()) BomberTimedExplosive.Kill();
            }
            private void UpdateTick() {
                if (CanRunAwayWater()) RunAwayWater();
                if (CanThrownGrenade()) ThrownGrenade(CurrentTarget.transform.position);
                if (CanHeal()) HealCoroutine = ServerMgr.Instance.StartCoroutine(Heal());
                EquipWeapon();
                TryRaidWithoutFoundations();
                UpdateGuardPosition();
                UpdateSleep();
            }
#region Targeting
            public new BaseEntity GetBestTarget() {
                BaseEntity target = null;
                float single = float.MinValue;
                foreach (SimpleAIMemory.SeenInfo info in Brain.Senses.Memory.All) {
                    BaseEntity entity = info.Entity;
                    if (entity != CurrentTarget && !CanSeeTarget(entity)) continue;
                    if (!CanTargetEntity(entity)) continue;
                    float single2 = GetSingle2(entity);
                    if (single2 <= single) continue;
                    target = entity;
                    single = single2;
                }
                return target;
            }
            private float GetSingle2(BaseEntity entity) {
                float single2 = 1f - Mathf.InverseLerp(1f, Brain.SenseRange, Vector3.Distance(entity.transform.position, transform.position));
                single2 += Mathf.InverseLerp(Brain.VisionCone, 1f, Vector3.Dot((entity.transform.position - eyes.position).normalized, eyes.BodyForward())) / 2f;
                single2 += Brain.Senses.Memory.IsLOS(entity) ? 2f : 0f;
                return single2;
            }
            internal bool CanTargetEntity(BaseEntity target) {
                if (target == null || target.Health() <= 0f) return false;
                if (target is BasePlayer) {
                    BasePlayer basePlayer = target as BasePlayer;
                    if (basePlayer.IsDead()) return false;
                    object hook = Interface.CallHook("OnCustomNpcTarget", this, basePlayer);
                    if (hook is bool) return (bool)hook;
                    if (basePlayer.userID.IsSteamId()) return CanTargetPlayer(basePlayer);
                    if (basePlayer.skinID != 0 && _ins.SkinIDs.Contains(basePlayer.skinID)) return true;
                    if (basePlayer is NPCPlayer) return CanTargetNpcPlayer(basePlayer as NPCPlayer);
                    return false;
                }
                if (target is BaseAnimalNPC) return CanTargetAnimal(target as BaseAnimalNPC);
                if (target is Drone) return CanTargetDrone(target as Drone);
                return false;
            }
            internal bool CanTargetNpcPlayer(NPCPlayer target) {
                if (target is FrankensteinPet) return true;
                if (target.skinID == 11162132011012) return false;
                return _ins._config.CanTargetNpc;
            }
            internal bool CanTargetPlayer(BasePlayer target) {
                if (target._limitedNetworking) return false;
                if (!_ins._config.CanTargetSleepingPlayer && target.IsSleeping()) return false;
                if (!_ins._config.CanTargetWoundedPlayer && target.IsWounded()) return false;
                if (!_ins._config.CanTargetSafeZonePlayer && target.InSafeZone()) return false;
                return true;
            }
            internal bool CanTargetAnimal(BaseAnimalNPC animal) {
                if (animal.IsDead()) return false;
                if (animal.skinID == 11491311214163) return false;
                if (Vector3.Distance(transform.position, animal.transform.position) > 30f) return false;
                return _ins._config.CanTargetAnimal;
            }
            private bool CanTargetDrone(Drone target) => !(CurrentWeapon is BaseMelee);
            public BaseEntity CurrentTarget {
                get;
                set;
            }
            public float DistanceToTarget => Vector3.Distance(transform.position, CurrentTarget.transform.position);
            public bool IsBasePlayerTarget => CurrentTarget is BasePlayer;
            internal BasePlayer GetBasePlayerTarget => CurrentTarget as BasePlayer;
            internal void SetKnown(BaseEntity entity) {
                for (int i = 0; i < Brain.Senses.Memory.All.Count; i++) {
                    SimpleAIMemory.SeenInfo info = Brain.Senses.Memory.All[i];
                    if (info.Entity != entity) continue;
                    info.Position = entity.transform.position;
                    info.Timestamp = Time.realtimeSinceStartup;
                    return;
                }
                Brain.Senses.Memory.All.Add(new SimpleAIMemory.SeenInfo {
                    Entity = entity, Position = entity.transform.position, Timestamp = Time.realtimeSinceStartup
                }
                );
            }
#endregion Targeting
#region Visible
            private int VisibleLayerMask {
                get;
            }
            = 1218519041;
            internal new bool CanSeeTarget(BaseEntity target) {
                if (target == null) return false;
                Vector3 main = isMounted ? eyes.worldMountedPosition : IsDucked() ? eyes.worldCrouchedPosition : IsCrawling() ? eyes.worldCrawlingPosition : eyes.worldStandingPosition;
                if (target is BasePlayer) {
                    BasePlayer targetBp = target as BasePlayer;
                    if (!targetBp.IsVisibleSpecificLayers(main, targetBp.CenterPoint(), VisibleLayerMask) && !targetBp.IsVisibleSpecificLayers(main, targetBp.transform.position, VisibleLayerMask) && !targetBp.IsVisibleSpecificLayers(main, targetBp.eyes.position, VisibleLayerMask)) return false;
                    if (!IsVisibleSpecificLayers(targetBp.CenterPoint(), main, VisibleLayerMask) && !IsVisibleSpecificLayers(targetBp.transform.position, main, VisibleLayerMask) && !IsVisibleSpecificLayers(targetBp.eyes.position, main, VisibleLayerMask)) return false;
                }
                else {
                    if (!target.IsVisibleSpecificLayers(main, target.CenterPoint(), VisibleLayerMask) && !target.IsVisibleSpecificLayers(main, target.transform.position, VisibleLayerMask)) return false;
                    if (!IsVisibleSpecificLayers(target.CenterPoint(), main, VisibleLayerMask) && !IsVisibleSpecificLayers(target.transform.position, main, VisibleLayerMask)) return false;
                }
                return true;
            }
#endregion Visible
#region Equip Weapons
            public AttackEntity CurrentWeapon {
                get;
                set;
            }
            private bool IsEquipping {
                get;
                set;
            }
            = false;
            private bool CanEquipWeapon() {
                if (inventory == null || inventory.containerBelt == null) return false;
                if (IsEquipping) return false;
                if (IsFireRocketLauncher) return false;
                if (IsHealing) return false;
                return true;
            }
            public override void EquipWeapon(bool skipDeployDelay = false) {
                if (!CanEquipWeapon()) return;
                Item weapon = null;
                if (CurrentTarget == null) {
                    if (CurrentWeapon == null) {
                        Dictionary<int, List<Item>> weapons = new Dictionary<int, List<Item>> {
                            [0]
                            = new List<Item>(), [1] = new List<Item>(), [2] = new List<Item>(), [3] = new List<Item>(), [4] = new List<Item>()
                        }
                        ;
                        foreach (Item item in inventory.containerBelt.itemList) {
                            int type = GetTypeWeaponItem(item);
                            if (type == -1) continue;
                            weapons[type].Add(item);
                        }
                        if (weapons[3].Count > 0) weapon = weapons[3].GetRandom();
                        else if (weapons[2].Count > 0) weapon = weapons[2].GetRandom();
                        else if (weapons[1].Count > 0) weapon = weapons[1].GetRandom();
                        else if (weapons[4].Count > 0) weapon = weapons[4].GetRandom();
                        else if (weapons[0].Count > 0) weapon = weapons[0].GetRandom();
                    }
                    else return;
                }
                else {
                    float distanceToTarget = DistanceToTarget;
                    int type = -1;
                    foreach (Item item in inventory.containerBelt.itemList) {
                        int currentType = GetTypeWeaponItem(item);
                        if (currentType == -1) continue;
                        if (type == -1) {
                            weapon = item;
                            type = currentType;
                        }
                        else {
                            if (type == currentType) continue;
                            float oldDistance = type > 0 ? Config.AttackRangeMultiplier * type * 10f : 2f;
                            float newDistance = currentType > 0 ? Config.AttackRangeMultiplier * currentType * 10f : 2f;
                            if ((oldDistance > distanceToTarget && newDistance > distanceToTarget && newDistance < oldDistance) || (oldDistance < distanceToTarget && newDistance > distanceToTarget) || (oldDistance < distanceToTarget && newDistance < distanceToTarget && newDistance > oldDistance)) {
                                weapon = item;
                                type = currentType;
                            }
                        }
                    }
                }
                EquipCurrentWeapon(weapon);
            }
            internal void EquipCurrentWeapon(Item weapon) {
                if (weapon == null) return;
                AttackEntity attackEntity = weapon.GetHeldEntity() as AttackEntity;
                if (attackEntity == null) return;
                if (CurrentWeapon == attackEntity) return;
                IsEquipping = true;
                UpdateActiveItem(weapon.uid);
                CurrentWeapon = attackEntity;
                attackEntity.TopUpAmmo();
                if (attackEntity is Chainsaw) (attackEntity as Chainsaw).ServerNPCStart();
                if (attackEntity is BaseProjectile) {
                    if (Weapons.ContainsKey(weapon.info.shortname)) {
                        attackEntity.effectiveRange = Weapons[weapon.info.shortname].EffectiveRange;
                        attackEntity.attackLengthMin = Weapons[weapon.info.shortname].AttackLengthMin;
                        attackEntity.attackLengthMax = Weapons[weapon.info.shortname].AttackLengthMax;
                    }
                    attackEntity.aiOnlyInRange = true;
                    BaseProjectile baseProjectile = attackEntity as BaseProjectile;
                    if (baseProjectile.MuzzlePoint == null) baseProjectile.MuzzlePoint = baseProjectile.transform;
                    NpcBelt npcBelt = Config.BeltItems.FirstOrDefault(x => x.ShortName == weapon.info.shortname);
                    if (npcBelt != null) {
                        string ammo = Config.BeltItems.FirstOrDefault(x => x.ShortName == weapon.info.shortname).Ammo;
                        if (!string.IsNullOrEmpty(ammo)) {
                            baseProjectile.primaryMagazine.ammoType = ItemManager.FindItemDefinition(ammo);
                            baseProjectile.SendNetworkUpdateImmediate();
                        }
                    }
                }
                Invoke(FinishEquiping, 1.5f);
            }
            private void FinishEquiping() => IsEquipping = false;
            private static int GetTypeWeaponItem(Item item) {
                if (MeleeWeapons.Contains(item.info.shortname)) return 0;
                if (FirstDistanceWeapons.Contains(item.info.shortname)) return 1;
                if (SecondDistanceWeapons.Contains(item.info.shortname)) return 2;
                if (ThirdDistanceWeapons.Contains(item.info.shortname)) return 3;
                if (FourthDistanceWeapons.Contains(item.info.shortname)) return 4;
                return -1;
            }
#endregion Equip Weapons
            public override void AttackerInfo(PlayerLifeStory.DeathInfo info) {
                base.AttackerInfo(info);
                if (CurrentWeapon != null) info.inflictorName = CurrentWeapon.ShortPrefabName;
                info.attackerName = displayName;
            }
            protected override string OverrideCorpseName() => displayName;
            public override float GetAimConeScale() => Config.AimConeScale;
            internal bool IsAttackingBaseProjectile {
                get;
                set;
            }
            = false;
            public override bool IsNpc {
                get {
                    if (_ins?._config == null || Brain == null || Brain.CurrentState == null) return true;
                    if (IsAttackingBaseProjectile && (_ins._config.CanTargetNpc || _ins._config.CanTargetAnimal) && (Brain.CurrentState.StateType == AIState.Combat || Brain.CurrentState.StateType == AIState.CombatStationary)) return false;
                    if (HasBarricadeTriggerBox()) return false;
                    return true;
                }
            }
#region NPCBarricadeTriggerBox
            private bool HasBarricadeTriggerBox() {
                List<BoxCollider> list = Pool.GetList<BoxCollider>();
                Vis.Colliders<BoxCollider>(transform.position, 2f, list, 1 << 18);
                bool hasCollider = list.Any(x => x.gameObject.GetComponent<NPCBarricadeTriggerBox>() != null);
                Pool.FreeList(ref list);
                return hasCollider;
            }
#endregion NPCBarricadeTriggerBox
#region Heal
            private Coroutine HealCoroutine {
                get;
                set;
            }
            = null;
            private bool IsHealing {
                get;
                set;
            }
            = false;
            private bool CanHeal() {
                if (IsHealing || health >= Config.Health || CurrentTarget != null || IsFireC4 || IsFireRocketLauncher || IsEquipping || inventory == null || inventory.containerBelt == null) return false;
                return inventory.containerBelt.itemList.Any(x => x.info.shortname == "syringe.medical");
            }
            private IEnumerator Heal() {
                IsHealing = true;
                Item syringe = inventory.containerBelt.itemList.FirstOrDefault(x => x.info.shortname == "syringe.medical");
                CurrentWeapon = null;
                UpdateActiveItem(syringe.uid);
                MedicalTool medicalTool = syringe.GetHeldEntity() as MedicalTool;
                yield return CoroutineEx.waitForSeconds(1.5f);
                if (medicalTool != null) medicalTool.ServerUse();
                InitializeHealth(health + 15f > Config.Health ? Config.Health : health + 15f, Config.Health);
                yield return CoroutineEx.waitForSeconds(2f);
                IsHealing = false;
                EquipWeapon();
            }
#endregion Heal
#region Grenades
            private HashSet<string> Barricades {
                get;
            }
            = new HashSet<string> {
                "barricade.cover.wood", "barricade.sandbags", "barricade.concrete", "barricade.stone"
            }
            ;
            private bool IsReloadGrenade {
                get;
                set;
            }
            = false;
            private bool IsReloadSmoke {
                get;
                set;
            }
            = false;
            private void FinishReloadGrenade() => IsReloadGrenade = false;
            private void FinishReloadSmoke() => IsReloadSmoke = false;
            private bool CanThrownGrenade() {
                if (IsReloadGrenade || CurrentTarget == null || !IsBasePlayerTarget || inventory == null || inventory.containerBelt == null) return false;
                return DistanceToTarget < 15f && inventory.containerBelt.itemList.Any(x => x.info.shortname == "grenade.f1" || x.info.shortname == "grenade.beancan" || x.info.shortname == "grenade.molotov" || x.info.shortname == "grenade.flashbang") && (!CanSeeTarget(CurrentTarget) || IsBehindBarricade());
            }
            internal bool IsBehindBarricade() => CanSeeTarget(CurrentTarget) && IsBarricade();
            private bool IsBarricade() {
                SetAimDirection((CurrentTarget.transform.position - transform.position).normalized);
                RaycastHit[] hits = Physics.RaycastAll(eyes.HeadRay());
                GamePhysics.Sort(hits);
                return hits.Select(x => x.GetEntity() as Barricade).Any(x => x != null && Barricades.Contains(x.ShortPrefabName) && Vector3.Distance(transform.position, x.transform.position) < DistanceToTarget);
            }
            private void ThrownGrenade(Vector3 target) {
                Item item = inventory.containerBelt.itemList.FirstOrDefault(x => x.info.shortname == "grenade.f1" || x.info.shortname == "grenade.beancan" || x.info.shortname == "grenade.molotov" || x.info.shortname == "grenade.flashbang");
                if (item == null) return;
                GrenadeWeapon weapon = item.GetHeldEntity() as GrenadeWeapon;
                if (weapon == null) return;
                Brain.Navigator.Stop();
                SetAimDirection((target - transform.position).normalized);
                weapon.ServerThrow(target);
                IsReloadGrenade = true;
                Invoke(FinishReloadGrenade, 10f);
            }
            internal void ThrownSmoke() {
                if (IsReloadSmoke) return;
                Item item = inventory.containerBelt.itemList.FirstOrDefault(x => x.info.shortname == "grenade.smoke");
                if (item == null) return;
                GrenadeWeapon weapon = item.GetHeldEntity() as GrenadeWeapon;
                if (weapon == null) return;
                weapon.ServerThrow(transform.position);
                IsReloadSmoke = true;
                Invoke(FinishReloadSmoke, 30f);
            }
#endregion Grenades
#region Run Away Water
            internal bool IsRunAwayWater {
                get;
                set;
            }
            = false;
            private bool CanRunAwayWater() {
                if (!Config.CanRunAwayWater || IsRunAwayWater) return false;
                if (CurrentTarget == null) {
                    if (transform.position.y < -0.25f) return true;
                    else return false;
                }
                if (transform.position.y > -0.25f || TerrainMeta.HeightMap.GetHeight(CurrentTarget.transform.position) > -0.25f) return false;
                if (CurrentWeapon is BaseProjectile && DistanceToTarget < EngagementRange()) return false;
                if (CurrentWeapon is BaseMelee && DistanceToTarget < CurrentWeapon.effectiveRange) return false;
                return true;
            }
            private void RunAwayWater() {
                IsRunAwayWater = true;
                CurrentTarget = null;
                Invoke(FinishRunAwayWater, 20f);
            }
            private void FinishRunAwayWater() => IsRunAwayWater = false;
#endregion Run Away Water
#region Raid
            internal bool IsRaidState {
                get;
                set;
            }
            = false;
            internal bool IsRaidStateMelee {
                get;
                set;
            }
            = false;
            internal bool IsReloadC4 {
                get;
                set;
            }
            = false;
            internal bool IsReloadRocketLauncher {
                get;
                set;
            }
            = false;
            internal bool IsFireRocketLauncher {
                get;
                set;
            }
            = false;
            internal bool IsFireC4 {
                get;
                set;
            }
            = false;
            private Coroutine FireC4Coroutine {
                get;
                set;
            }
            = null;
            private Coroutine FireRocketLauncherCoroutine {
                get;
                set;
            }
            = null;
            internal BaseCombatEntity Turret {
                get;
                set;
            }
            = null;
            internal BaseCombatEntity PlayerTarget {
                get;
                set;
            }
            = null;
            internal HashSet<BuildingBlock> Foundations {
                get;
                set;
            }
            = new HashSet<BuildingBlock>();
            internal BaseCombatEntity CurrentRaidTarget {
                get;
                set;
            }
            = null;
            internal float DistanceToCurrentRaidTarget => Vector3.Distance(transform.position, CurrentRaidTarget.transform.position);
            internal void AddTurret(BaseCombatEntity turret) {
                if (!Turret.IsExists() || Vector3.Distance(transform.position, turret.transform.position) < Vector3.Distance(transform.position, Turret.transform.position)) {
                    Turret = turret;
                    BuildingBlock block = GetNearEntity<BuildingBlock>(Turret.transform.position, 0.1f, 1 << 21);
                    CurrentRaidTarget = block.IsExists() ? block : Turret;
                }
            }
            private static T GetNearEntity<T>(Vector3 position, float radius, int layerMask) where T : BaseCombatEntity {
                List<T> list = Pool.GetList<T>();
                Vis.Entities<T>(position, radius, list, layerMask);
                T result = list.Count == 0 ? null : list.Min(s => Vector3.Distance(position, s.transform.position));
                Pool.FreeList(ref list);
                return result;
            }
            internal BaseCombatEntity GetRaidTarget() {
                UpdateTargets();
                BaseCombatEntity main = null;
                if (IsRaidState) {
                    if (Turret != null) {
                        BuildingBlock block = GetNearEntity<BuildingBlock>(Turret.transform.position, 0.1f, 1 << 21);
                        main = block.IsExists() ? block : Turret;
                    }
                    else if (Foundations.Count > 0) main = Foundations.Min(x => Vector3.Distance(transform.position, x.transform.position));
                    else if (PlayerTarget != null) main = PlayerTarget;
                }
                else if (IsRaidStateMelee) {
                    if (Foundations.Count > 0) main = Foundations.Min(x => Vector3.Distance(transform.position, x.transform.position));
                }
                if (main == null) return null;
                if (IsMounted()) return main;
                NavMeshHit navMeshHit;
                if (IsRaidState) {
                    float heightGround = TerrainMeta.HeightMap.GetHeight(main.transform.position);
                    if (main.transform.position.y - heightGround > 15f) {
                        main = GetNearEntity<BuildingBlock>(new Vector3(main.transform.position.x, heightGround, main.transform.position.z), 15f, 1 << 21);
                        if (main == null) return null;
                    }
                    if (NavMesh.SamplePosition(main.transform.position, out navMeshHit, 30f, NavAgent.areaMask)) {
                        NavMeshPath path = new NavMeshPath();
                        if (NavMesh.CalculatePath(transform.position, navMeshHit.position, NavAgent.areaMask, path)) {
                            if (path.status == NavMeshPathStatus.PathComplete) return main;
                            else return GetNearEntity<BaseCombatEntity>(path.corners.Last(), 5f, 1 << 8 | 1 << 21);
                        }
                    }
                    Vector2 pos1 = new Vector2(transform.position.x, transform.position.z);
                    Vector2 pos2 = new Vector2(main.transform.position.x, main.transform.position.z);
                    Vector2 pos3 = pos1 + (pos2 - pos1).normalized * (Vector2.Distance(pos1, pos2) - 30f);
                    Vector3 pos = new Vector3(pos3.x, 0f, pos3.y);
                    pos.y = TerrainMeta.HeightMap.GetHeight(pos);
                    main = GetNearEntity<BuildingBlock>(pos, 15f, 1 << 21);
                    if (main == null) return null;
                    if (NavMesh.SamplePosition(main.transform.position, out navMeshHit, 30f, NavAgent.areaMask)) {
                        NavMeshPath path = new NavMeshPath();
                        if (NavMesh.CalculatePath(transform.position, navMeshHit.position, NavAgent.areaMask, path)) {
                            if (path.status == NavMeshPathStatus.PathComplete) return main;
                            else return GetNearEntity<BaseCombatEntity>(path.corners.Last(), 5f, 1 << 8 | 1 << 21);
                        }
                    }
                }
                else if (IsRaidStateMelee) {
                    if (NavMesh.SamplePosition(main.transform.position, out navMeshHit, 30f, NavAgent.areaMask)) {
                        NavMeshPath path = new NavMeshPath();
                        if (NavMesh.CalculatePath(transform.position, navMeshHit.position, NavAgent.areaMask, path)) {
                            if (path.status == NavMeshPathStatus.PathComplete && Vector3.Distance(navMeshHit.position, main.transform.position) < 6f) return main;
                            else return GetNearEntity<BaseCombatEntity>(path.corners.Last(), 6f, 1 << 8 | 1 << 21);
                        }
                    }
                }
                return main;
            }
            private void UpdateTargets() {
                if (!Turret.IsExists()) Turret = null;
                if (!PlayerTarget.IsExists()) PlayerTarget = null;
                foreach (BuildingBlock ent in Foundations.Where(x => !x.IsExists())) Foundations.Remove(ent);
                if (!CurrentRaidTarget.IsExists()) CurrentRaidTarget = null;
            }
            internal bool StartExplosion(BaseCombatEntity target) {
                if (target == null) return false;
                if (CanThrownC4(target)) {
                    FireC4Coroutine = ServerMgr.Instance.StartCoroutine(ThrownC4(target));
                    return true;
                }
                if (CanRaidRocketLauncher(target)) {
                    ThrownSmoke();
                    FireRocketLauncherCoroutine = ServerMgr.Instance.StartCoroutine(ProcessFireRocketLauncher(target));
                    return true;
                }
                return false;
            }
            internal bool HasRocketLauncher() => inventory.containerBelt.itemList.Any(x => x.info.shortname == "rocket.launcher");
            private bool CanRaidRocketLauncher(BaseCombatEntity target) => !IsReloadRocketLauncher && !IsFireRocketLauncher && !IsEquipping && !IsHealing && HasRocketLauncher() && Vector3.Distance(transform.position, target.transform.position) < 30f;
            private IEnumerator ProcessFireRocketLauncher(BaseCombatEntity target) {
                IsFireRocketLauncher = true;
                EquipRocketLauncher();
                if (!IsMounted()) SetDucked(true);
                Brain.Navigator.Stop();
                Brain.Navigator.SetFacingDirectionEntity(target);
                yield return CoroutineEx.waitForSeconds(1.5f);
                if (target.IsExists()) {
                    if (target.ShortPrefabName.Contains("foundation")) {
                        Brain.Navigator.ClearFacingDirectionOverride();
                        SetAimDirection((target.transform.position - new Vector3(0f, 1.5f, 0f) - transform.position).normalized);
                    }
                    FireRocketLauncher();
                    IsReloadRocketLauncher = true;
                    Invoke(FinishReloadRocketLauncher, 6f);
                }
                IsFireRocketLauncher = false;
                EquipWeapon();
                Brain.Navigator.ClearFacingDirectionOverride();
                if (!IsMounted()) SetDucked(false);
            }
            private void EquipRocketLauncher()
// ... [Code preview truncated due to length. Full source in attached file] ...

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