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

FREE NPCGrenades : 1.2.8 1.2.8

Нет прав для скачивания
C#:
using Facepunch;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Rust;
using System;
using System.Linq;
using System.Collections;
using System.Globalization;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

namespace Oxide.Plugins
{
    [Info("NPC Grenades", "ZEODE", "1.2.8")]
    [Description("F1 grenades spawn various NPCs when thrown.")]
    public class NPCGrenades: CovalencePlugin
    {
        #region Plugin References
        [PluginReference]
        private Plugin Friends, Clans, Kits;
        #endregion

        #region Consts
        private static NPCGrenades plugin;
        private static System.Random random = new System.Random();
        private static VersionNumber previousVersion;

        public const int f1GrenadeId = 143803535;

        public const ulong scientistSkinID = 2640541557;
        public const ulong heavySkinID = 2640541496;
        public const ulong juggernautSkinID = 2647297156;
        public const ulong tunnelSkinID = 2676146196;
        public const ulong underwaterSkinID = 2676146329;
        public const ulong murdererSkinID = 2643502595;
        public const ulong scarecrowSkinID = 2647297210;
        public const ulong mummySkinID = 2643385137;
        public const ulong bearSkinID = 2647301111;
        public const ulong polarbearSkinID = 2868239755;
        public const ulong wolfSkinID = 2647303718;
        public const ulong boarSkinID = 2643502513;
        public const ulong stagSkinID = 2647297256;
        public const ulong chickenSkinID = 2647297056;
        public const ulong bradleySkinID = 2643385052;

        public const string permScientist = "npcgrenades.scientist";
        public const string permHeavy = "npcgrenades.heavy";
        public const string permJuggernaut = "npcgrenades.juggernaut";
        public const string permTunnel = "npcgrenades.tunnel";
        public const string permUnderwater = "npcgrenades.underwater";
        public const string permMurderer = "npcgrenades.murderer";
        public const string permScarecrow = "npcgrenades.scarecrow";
        public const string permMummy = "npcgrenades.mummy";
        public const string permBear = "npcgrenades.bear";
        public const string permPolarbear = "npcgrenades.polarbear";
        public const string permWolf = "npcgrenades.wolf";
        public const string permBoar = "npcgrenades.boar";
        public const string permStag = "npcgrenades.stag";
        public const string permChicken = "npcgrenades.chicken";
        public const string permBradley = "npcgrenades.bradley";
        public const string permAdmin = "npcgrenades.admin";

        public const string scientistNade = "Scientist Grenade";
        public const string heavyNade = "Heavy Scientist Grenade";
        public const string juggernautNade = "Juggernaut Grenade";
        public const string tunnelNade = "Tunnel Dweller Grenade";
        public const string underwaterNade = "Underwater Dweller Grenade";
        public const string murdererNade = "Murderer Grenade";
        public const string scarecrowNade = "Scarecrow Grenade";
        public const string mummyNade = "Mummy Grenade";
        public const string bearNade = "Bear Grenade";
        public const string polarbearNade = "Polar Bear Grenade";
        public const string wolfNade = "Wolf Grenade";
        public const string boarNade = "Boar Grenade";
        public const string stagNade = "Stag Grenade";
        public const string chickenNade = "Chicken Grenade";
        public const string bradleyNade = "Bradley Grenade";

        public const string scientistPrefab = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_roam.prefab";
        public const string heavyPrefab = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_heavy.prefab";
        public const string scarecrowPrefab = "assets/prefabs/npc/scarecrow/scarecrow.prefab";
        public const string bradleyPrefab = "assets/prefabs/npc/m2bradley/bradleyapc.prefab";
        public const string bearPrefab = "assets/rust.ai/agents/bear/bear.prefab";
        public const string polarbearPrefab = "assets/rust.ai/agents/bear/polarbear.prefab";
        public const string wolfPrefab = "assets/rust.ai/agents/wolf/wolf.prefab";
        public const string boarPrefab = "assets/rust.ai/agents/boar/boar.prefab";
        public const string stagPrefab = "assets/rust.ai/agents/stag/stag.prefab";
        public const string chickenPrefab = "assets/rust.ai/agents/chicken/chicken.prefab";

        public const string murdererChatter = "assets/prefabs/npc/murderer/sound/breathing.prefab";
        public const string murdererDeath = "assets/prefabs/npc/murderer/sound/death.prefab";
        public const string fleshBloodImpact = "assets/bundled/prefabs/fx/impacts/slash/flesh/fleshbloodimpact.prefab";
        public const string explosionEffect = "assets/prefabs/weapons/f1 grenade/effects/f1grenade_explosion.prefab";
        public const string bradleyExplosion = "assets/prefabs/npc/m2bradley/effects/bradley_explosion.prefab";
        public const string chutePrefab = "assets/prefabs/misc/parachute/parachute.prefab";
        #endregion

        #region Language
        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
            {
                ["SyntaxPlayer"] = "Invalid syntax, use: /npcnade.give <type> <SteamID/PlayerName> <amount>",
                ["WrongType"] = "Grenade type \"{0}\" not recognised, please check & try again.",
                ["Receive"] = "You received {0} {1}(s)!",
                ["PlayerReceive"] = "Player {0} ({1}) received {2} {3}(s)!",
                ["Permission"] = "You do not have permission to use {0}!",
                ["NotEnabled"] = "{0} is not enabled!",
                ["NotAdmin"] = "You do not have permission to use that command!",
                ["PlayerNotFound"] = "Can't find a player with the name or ID: {0}",
                ["PlayersFound"] = "Multiple players found, please be more specific: {0}",
                ["UnderWater"] = "{0} ({1}) spawned under water and was killed.",
                ["InSafeZone"] = "{0} ({1}) spawned in as Safe Zone and was killed.",
                ["Inside"] = "{0} ({1}) spawned inside and was killed.",
                ["OnStructure"] = "{0} ({1}) spawned on a building and was killed.",
                ["NadeOnStructure"] = "{0} was thrown on a building and will not spawn.",
                ["IsInRock"] = "{0} ({1}) spawned inside terrain and was killed.",
                ["SyntaxConsole"] = "Invalid syntax, use: npcnade.give <type> <SteamID/PlayerName> <amount>",
                ["InvalidNade"] = "Grenade type \"{0}\" not recognised, please check and try again!"
            }, this);
        }

        private string Lang(string messageKey, string playerID, params object[] args) {
            return string.Format(lang.GetMessage(messageKey, this, playerID), args);
        }

        private void Message(IPlayer player, string messageKey, params object[] args)
        {
            var message = Lang(messageKey, player.Id, args);
            if (config.options.usePrefix)
            {
                player.Reply(config.options.chatPrefix + message);
            }
            else
            {
                player.Reply(message);
            }
        }

        private void Message(BasePlayer player, string messageKey, params object[] args)
        {
            if (player is NPCPlayer)
            {
                return;
            }
            var message = Lang(messageKey, player.UserIDString, args);
            if (config.options.usePrefix && config.options.chatPrefix != string.Empty)
            {
                player.ChatMessage(config.options.chatPrefix + message);
            }
            else
            {
                player.ChatMessage(message);
            }
        }
        #endregion

        #region Oxide Hooks
        private void OnServerInitialized()
        {
            plugin = this;
        }

        private void Init()
        {
            LoadNadeInfo();
            permission.RegisterPermission(permAdmin, this);
            foreach (var item in NadeInfo.Keys)
            {
                permission.RegisterPermission(NadeInfo[item].Perm, this);
            }
            try
            {
                storedData = Interface.Oxide.DataFileSystem.ReadObject<StoredData>(Name);
                if (storedData == null)
                {
                    Puts("Data file is blank. Creating default data file.");
                    storedData = new StoredData();
                }
            }
            catch (Exception ex)
            {
                if (ex is JsonSerializationException || ex is NullReferenceException || ex is JsonReaderException)
                {
                    Puts($"Exception Type: {ex.GetType()}");
                    Puts("Data file contains errors. Either fix the errors or delete the data file and reload the plugin for default values.");
                    return;
                }
                throw;
            }
            LoadData();
        }

        private void Unload()
        {
            //SaveData();
            plugin = null;
            NadeInfo.Clear();
            GrenadeNPCData.Clear();
            BaseNpcData.Clear();
            BradleyAPCData.Clear();
            NPCInventories.Clear();
        }

        private void OnServerSave()
        {
            int delay  = random.Next(4, 8);
            timer.Once(delay, () =>
            {
                SaveData();
            });
        }

        private void OnEntityDeath(BaseCombatEntity entity, HitInfo info)
        {
            if (entity.skinID != 0 && IsNpcGrenade(entity.skinID))
            {
                NPCPlayer npc = entity as NPCPlayer;
                if (npc is ScientistNPC || npc is ScarecrowNPC)
                {
                    if (GrenadeNPCData.ContainsKey(npc.userID) && !NPCInventories.ContainsKey(npc.userID)) 
                    {
                        ItemContainer[] source = { npc.inventory.containerMain, npc.inventory.containerWear, npc.inventory.containerBelt };
                        Inv npcInv = new Inv() { name = npc.displayName, };
                        NPCInventories.Add(npc.userID, npcInv);
                        for (int i = 0; i < source.Length; i++)
                        {
                            foreach (var item in source[i].itemList)
                            {
                                npcInv.inventory[i].Add(new InvContents
                                {
                                    ID = item.info.itemid,
                                    amount = item.amount,
                                    skinID = item.skin,
                                });
                            }
                        }
                    }
                    timer.Once(5.0f, () =>
                    {
                        RemoveNpcData(npc.userID);
                    });
                }
                else
                {
                    RemoveNpcData(entity.net.ID.Value);
                }
            }
        }

        // Below adds proper grenade names to items added via kits/loadouts by plugins which don't specify a custom item display name
        // This means when players click on the item in inventory it shows the NPC Nade name, which is also needed for checks later on.
        private void OnItemAddedToContainer(ItemContainer container, Item item)
        {
            if (item.skin != 0)
            {
                if (item.name == null && IsNpcGrenade(item.skin))
                {
                    if (NadeInfo.ContainsKey(item.skin))
                    {
                        item.name = NadeInfo[item.skin].Name;
                    }
                }
            }
        }

        // This hook works regardless of whether a Player or NPCPlayer. OnExplosiveThrown only hooks for Player.
        private void OnExplosiveFuseSet(TimedExplosive explosive, float fuseLength)
        {
            var player = explosive.creatorEntity as BasePlayer;
            if (player == null || !player.IsAlive())
            {
                return;
            }
            var item = player.GetActiveItem();
            var skin = item.skin;
            if (item == null || skin == 0)
            {
                return;
            }
            else if (IsNpcGrenade(skin))
            {
                var name = item.name;
                if (name == null)
                {
                    if (!NadeInfo.ContainsKey(skin))
                    {
                        return;
                    }
                    name = NadeInfo[skin].Name;
                }
                OnNpcNadeThrown(player, explosive, item);
            }
        }

        private void OnExplosiveDropped(BasePlayer player, BaseEntity entity, Item item)
        {
        	var skin = item.skin;
            if (skin == 0)
            {
                return;
            }
            else if (IsNpcGrenade(skin))
            {
                OnNpcNadeThrown(player, entity, item);
            }
        }

        private object OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info)
        {
        	var skin = entity.skinID;
            if (info == null || skin == 0)
            {
                return null;
            }
            else if (info.Initiator == info.HitEntity)
            {
                // Stop melee armed NPC injuring themselves which happens when their swing misses the target
                if (IsNpcGrenade(skin))
                {
                    return true;
                }
            }

            if (!config.bradley.bradleyBaseDamage)
            {
                var damageType = info.damageTypes.GetMajorityDamageType();
                if (entity is BasePlayer)
                {
                    return null;
                }
                else if (damageType == DamageType.Blunt)
                {
                    if(entity.GetBuildingPrivilege() && info.WeaponPrefab.name == "MainCannonShell")
                    {
                        // Blunt damage from APC cannon shells blocked
                        CancelHit(info);
                        return true;
                    }
                }
                else if (damageType == DamageType.Bullet && info.Initiator is BradleyAPC)
                {
                    // Bullet damage from APC machine gun bullets blocked
                    CancelHit(info);
                    return true;
                }
            }

            return null;
        }

        private object OnNpcTarget(BaseEntity entity, BaseEntity target)
        {
            var isEntityNade = IsNpcGrenade(entity.skinID);
            var isTargetNade = IsNpcGrenade(target.skinID);

            if (isEntityNade && isTargetNade)
            {
                return true;
            }
            else if (isEntityNade && !isTargetNade)
            {
                if (target is BasePlayer)
                {
                    var player = target as BasePlayer;
                    if (config.options.sleeperSafe && player.IsSleeping())
                    {
                        return true;
                    }
                    if (!config.options.attackOwner && entity.OwnerID == player.userID)
                    {
                        return true;
                    }
                    if (config.options.useFriends || config.options.useClans || config.options.useTeams)
                    {
                        if (entity.OwnerID != player.userID && IsFriend(entity.OwnerID, player.userID))
                        {
                            return true;
                        }
                    }
                }
                if (target is NPCPlayer)
                {
                    if (config.options.npcSafe)
                    {
                        return true;
                    }
                }
                if (target is BaseNpc)
                {
                    if (config.options.animalSafe)
                    {
                        return true;
                    }
                }
            }
            else if (isTargetNade && !isEntityNade)
            {
                if (config.options.npcSafe && entity is NPCPlayer)
                {
                    return true;
                }
                else if (config.options.animalSafe && entity is BaseNpc)
                {
                    return true;
                }
            }

            return null;
        }

        private object OnTurretTarget(AutoTurret turret, BaseEntity target)
        {
            if (target != null)
            {
                if (config.options.turretSafe && IsNpcGrenade(target.skinID))
                {
                    return true;
                }
            }
            return null;
        }

        private object CanBradleyApcTarget(BradleyAPC bradley, BaseEntity target)
        {
            if (target != null)
            {
                if (config.options.bradleySafe && IsNpcGrenade(target.skinID))
                {
                    return false;
                }
                var player = target as BasePlayer;
                if (IsNpcGrenade(bradley.skinID))
                {
                    if (config.options.sleeperSafe && player.IsSleeping())
                    {
                        return false;
                    }
                    if (!config.options.attackOwner && bradley.OwnerID == player.userID)
                    {
                        return false;
                    }
                    if (config.options.useFriends || config.options.useClans || config.options.useTeams)
                    {
                        if (bradley.OwnerID != player.userID && IsFriend(bradley.OwnerID, player.userID))
                        {
                            return true;
                        }
                    }
                }
            }
            return null;
        }

        private object OnBradleyApcInitialize(BradleyAPC bradley)
        {
            if (!IsNpcGrenade(bradley.skinID))
                return null;

            bradley._maxHealth = storedData.BradleyNPC[bradleyNade].Health;
            bradley.health = storedData.BradleyNPC[bradleyNade].Health;
            bradley.searchRange = storedData.BradleyNPC[bradleyNade].SearchRange;
            bradley.viewDistance = storedData.BradleyNPC[bradleyNade].ViewDistance;
            bradley.maxCratesToSpawn = storedData.BradleyNPC[bradleyNade].CratesToSpawn;
            bradley.throttle = storedData.BradleyNPC[bradleyNade].ThrottleResponse;
            bradley.leftThrottle = bradley.throttle;
            bradley.rightThrottle = bradley.throttle;
            bradley.ClearPath();
            bradley.currentPath.Clear();
            bradley.currentPathIndex = 0;
            bradley.DoAI = true;
            bradley.DoSimpleAI();

            var position = bradley.transform.position;
            for (int i = 0; i < storedData.BradleyNPC[bradleyNade].PatrolPathNodes; i++)
            {
                position = position + UnityEngine.Random.onUnitSphere * storedData.BradleyNPC[bradleyNade].PatrolRange;
                position.y = TerrainMeta.HeightMap.GetHeight(position);
                bradley.currentPath.Add(position);
            }
            return true;
        }

        void OnEntitySpawned(NPCPlayerCorpse corpse)
        {
            corpse.lootPanelName = "generic_resizable";
            Inv npcInv = new Inv();
            timer.Once(0.2f, () =>
            {
                if (corpse == null || corpse.IsDestroyed)
                {
                    return;
                }

                ulong id = corpse.playerSteamID;
                if (!NPCInventories.ContainsKey(id)) return;
                corpse.containers[0].Clear();
                npcInv = NPCInventories[id];
                if (npcInv == null) return;
                corpse._playerName = npcInv.name;
                var key = npcInv.name + " Grenade";
                if (storedData.HumanNPC[key].StripCorpseLoot)
                {
                    corpse.blockBagDrop = true;
                    corpse.containers[0].Clear();
                    timer.Once(5f, () => NPCInventories?.Remove(id));
                }
                else
                {
                    for (int i = 0; i < npcInv.inventory.Length; i++)
                    {
                        foreach (var item in npcInv.inventory[i])
                        {
                            var giveItem = ItemManager.CreateByItemID(item.ID, item.amount, item.skinID);
                            if (i != 0)
                            {
                                if (giveItem.info.category == ItemCategory.Weapon || giveItem.info.category == ItemCategory.Attire)
                                    continue;
                            }

                            if (!giveItem.MoveToContainer(corpse.containers[0], -1, true))
                                giveItem.Remove();
                        }
                    }
                }
                ItemManager.DoRemoves();
            });
        }

        void OnEntitySpawned(DroppedItemContainer bag)
        {
            Inv npcInv = new Inv();
            bag.inventory.capacity = 36;
            
            NextTick(() =>
            {
                if (bag == null) return;
                ulong id = bag.playerSteamID;
                npcInv = NPCInventories[id];
                if (npcInv == null) return;
                bag.inventory.Clear();
                if (!NPCInventories.ContainsKey(id)) return;
                bag._playerName = npcInv.name;
                bag.lootPanelName = "generic_resizable";

                for (int i = 0; i < npcInv.inventory.Length; i++)
                {
                    foreach (var item in npcInv.inventory[i])
                    {
                        var giveItem = ItemManager.CreateByItemID(item.ID, item.amount, item.skinID);
                        if (i != 0)
                        {
                            if (giveItem.info.category == ItemCategory.Weapon || giveItem.info.category == ItemCategory.Attire)
                                continue;
                        }

                        if (!giveItem.MoveToContainer(bag.inventory, -1, true, false, null, true))
                            giveItem.Remove();
                    }
                }
                timer.Once(5f, () => NPCInventories?.Remove(id));
            });
        }

        #endregion

        #region Main

        // Changed to a custom method due to OnExplosiveThrown not hooking explosives thrown by NPCs
        private void OnNpcNadeThrown(BaseEntity thrower, BaseEntity entity, Item npcNade)
        {
            var player = thrower as BasePlayer;
            var nadeName = npcNade.name;
            var nadeSkin = npcNade.skin;

            if (!NadeInfo[nadeSkin].Enabled)
            {
                NextTick(() =>
                {
                    if (entity != null)
                        entity.Kill();
                });

                if (player is NPCPlayer)
                {
                    Puts($"An NPC player is trying to throw an NPCGrenade which is not enabled in the config: {nadeName}");
                }
                else
                {
                    GiveNade(player, nadeSkin, nadeName, 1, "refund");
                    Message(player, "NotEnabled", nadeName);
                }
                return;
            }
            else if (config.options.usePerms && !permission.UserHasPermission(player.UserIDString, NadeInfo[nadeSkin].Perm))
            {
                if (player is BasePlayer)
                {
                    NextTick(() =>
                    {
                        if (entity != null)
                            entity.Kill();
                    });

                    GiveNade(player, nadeSkin, nadeName, 1, "refund");
                    Message(player, "Permission", nadeName);
                    return;
                }
            }

            timer.Once(2.4f, () =>
            {
                if (entity == null)
                    return;
                
                var position = entity.transform.position;

                if (player == null || !player.IsAlive())
                    return;

                if (storedData.HumanNPC.ContainsKey(nadeName))
                {                        
                    NPCPlayerData settings = new NPCPlayerData
                    {
                        Name = storedData.HumanNPC[nadeName].Name,
                        Prefab = storedData.HumanNPC[nadeName].Prefab,
                        Health = storedData.HumanNPC[nadeName].Health,
                        MaxRoamRange = storedData.HumanNPC[nadeName].MaxRoamRange,
                        SenseRange = storedData.HumanNPC[nadeName].SenseRange,
                        ListenRange = storedData.HumanNPC[nadeName].ListenRange,
                        AggroRange = storedData.HumanNPC[nadeName].AggroRange,
                        DeAggroRange = storedData.HumanNPC[nadeName].DeAggroRange,
                        TargetLostRange = storedData.HumanNPC[nadeName].TargetLostRange,
                        MemoryDuration = storedData.HumanNPC[nadeName].MemoryDuration,
                        VisionCone = storedData.HumanNPC[nadeName].VisionCone,
                        CheckVisionCone = storedData.HumanNPC[nadeName].CheckVisionCone,
                        CheckLOS = storedData.HumanNPC[nadeName].CheckLOS,
                        IgnoreNonVisionSneakers = storedData.HumanNPC[nadeName].IgnoreNonVisionSneakers,
                        DamageScale = storedData.HumanNPC[nadeName].DamageScale,
                        PeaceKeeper = storedData.HumanNPC[nadeName].PeaceKeeper,
                        IgnoreSafeZonePlayers = storedData.HumanNPC[nadeName].IgnoreSafeZonePlayers,
                        RadioChatter = storedData.HumanNPC[nadeName].RadioChatter,
                        DeathSound = storedData.HumanNPC[nadeName].DeathSound,
                        NumberToSpawn = storedData.HumanNPC[nadeName].NumberToSpawn,
                        SpawnRadius = storedData.HumanNPC[nadeName].SpawnRadius,
                        DespawnTime = storedData.HumanNPC[nadeName].DespawnTime,
                        KillInSafeZone = storedData.HumanNPC[nadeName].KillInSafeZone,
                        StripCorpseLoot = storedData.HumanNPC[nadeName].StripCorpseLoot,
                        Speed = storedData.HumanNPC[nadeName].Speed,
                        Acceleration = storedData.HumanNPC[nadeName].Acceleration,
                        FastSpeedFraction = storedData.HumanNPC[nadeName].FastSpeedFraction,
                        NormalSpeedFraction = storedData.HumanNPC[nadeName].NormalSpeedFraction,
                        SlowSpeedFraction = storedData.HumanNPC[nadeName].SlowSpeedFraction,
                        SlowestSpeedFraction = storedData.HumanNPC[nadeName].SlowestSpeedFraction,
                        LowHealthMaxSpeedFraction = storedData.HumanNPC[nadeName].LowHealthMaxSpeedFraction,
                        TurnSpeed = storedData.HumanNPC[nadeName].TurnSpeed,
                        ExplosionSound = storedData.HumanNPC[nadeName].ExplosionSound
                    };

                    if (settings.Prefab.Contains("scarecrow"))
                    {
                        SpawnScarecrow(player, nadeName, nadeSkin, position, settings);
                    }
                    else
                    {
                        SpawnScientist(player, nadeName, nadeSkin, position, settings);
                    }
                }

                
                if (storedData.AnimalNPC.ContainsKey(nadeName))
                {
                    SpawnAnimal(player, nadeName, nadeSkin, position);
                }
                
                if (storedData.BradleyNPC.ContainsKey(nadeName))
                {
                    SpawnBradley(player, nadeName, nadeSkin, position);
                }

                NextTick(() =>
                {
                    if (entity != null)
                        entity.Kill();
                });
            });
        }

        private void SpawnScientist(BasePlayer player, string nadeName, ulong nadeSkin, Vector3 position, NPCPlayerData settings)
        {
            if (player == null || nadeName == null || nadeSkin == 0 || position == null || settings == null)
                return;
            
            for (int i = 0; i < settings.NumberToSpawn; i++)
            {
                if (settings.NumberToSpawn > 1)
                {
                    Vector2 rand;
                    rand = UnityEngine.Random.insideUnitCircle * settings.SpawnRadius;
                    position = position + new Vector3(rand.x, 0, rand.y);
                }
                var groundLevel = TerrainMeta.HeightMap.GetHeight(position);
                var heightDiff = position.y - groundLevel;
                if (heightDiff < 6.0)
                {
                    position.y = groundLevel;
                }
                var npc = (ScientistNPC)GameManager.server.CreateEntity(settings.Prefab, position + new Vector3(0, 0.1f, 0), new Quaternion(), true);
                if (npc == null)
                {
                    return;
                }
                DoExplosion(settings.ExplosionSound, position);
                npc.Spawn();

                npc.skinID = nadeSkin;
                npc.OwnerID = player.userID;
                npc.displayName = settings.Name;
                npc.damageScale = settings.DamageScale;
                npc.startHealth = settings.Health;
                npc.InitializeHealth(settings.Health, settings.Health);
                npc.EnablePlayerCollider();

                var brain = npc.gameObject.AddComponent<ScientistAI>();
                brain.Settings = settings;

                var move = npc.gameObject.AddComponent<ScientistMovement>();
                move.Settings = settings;
                move.HomeLoc = position;

                if (heightDiff >= 6.0)
                {
                    AddChute(npc, position);
                    move.isFalling = true;
                }
                timer.Once(0.2f, () =>
                {
                    if (npc == null || npc.IsDestroyed)
                    {
                        return;
                    }
                    else if (SpawnAborted(player, npc, nadeName, position))
                    {
                        return;
                    }
                    GiveGrenadeNpcKit(npc, nadeName);
                    if (settings.DespawnTime > 0)
                    {
                        DespawnNPC(npc, npc.userID, settings.DespawnTime);
                    }
                    GrenadeNPCData.Add(npc.userID, npc);
                });
            }
        }

        private void SpawnScarecrow(BasePlayer player, string nadeName, ulong nadeSkin, Vector3 position, NPCPlayerData settings)
        {
            if (player == null || nadeName == null || nadeSkin == 0 || position == null || settings == null)
                return;
            
            for (int i = 0; i < settings.NumberToSpawn; i++)
            {
                if (settings.NumberToSpawn > 1)
                {
                    Vector2 rand;
                    rand = UnityEngine.Random.insideUnitCircle * settings.SpawnRadius;
                    position = position + new Vector3(rand.x, 0, rand.y);
                }
                var groundLevel = TerrainMeta.HeightMap.GetHeight(position);
                var heightDiff = position.y - groundLevel;
                if (heightDiff < 6.0)
                {
                    position.y = groundLevel;
                }

                var npc = (ScarecrowNPC)GameManager.server.CreateEntity(settings.Prefab, position + new Vector3(0, 0.1f, 0), new Quaternion(), true);
                if (npc == null)
                {
                    return;
                }

                DoExplosion(settings.ExplosionSound, position);
                npc.Spawn();

                npc.skinID = nadeSkin;
                npc.OwnerID = player.userID;
                npc.displayName = settings.Name;
                npc.damageScale = settings.DamageScale;
                npc.startHealth = settings.Health;
                npc.InitializeHealth(settings.Health, settings.Health);
                npc.EnablePlayerCollider();

                var brain = npc.gameObject.AddComponent<ScarecrowAI>();
                brain.Settings = settings;

                var move = npc.gameObject.AddComponent<ScarecrowMovement>();
                move.HomeLoc = position;
                move.Settings = settings;

                if (heightDiff >= 6.0)
                {
                    AddChute(npc, position);
                    move.isFalling = true;
                }

                timer.Once(0.2f, () =>
                {
                    if (npc == null || npc.IsDestroyed)
                    {
                        Puts("NPC is Null or Destroyed");
                        return;
                    }
                    if (SpawnAborted(player, npc, nadeName, position))
                    {
                        Puts("Spawn Aborted!");
                        return;
                    }
                    GiveGrenadeNpcKit(npc, nadeName);

                    if (settings.DespawnTime > 0)
                    {
                        DespawnNPC(npc, npc.userID, settings.DespawnTime);
                    }
                    GrenadeNPCData.Add(npc.userID, npc);
                });
            }
        }

        private void SpawnAnimal(BasePlayer player, string nadeName, ulong nadeSkin, Vector3 position)
        {
            if (player == null || nadeName == null || nadeSkin == 0 || position == null)
                return;

            if (storedData.AnimalNPC.ContainsKey(nadeName))
            {
                string npcPrefab = storedData.AnimalNPC[nadeName].Prefab;
                string npcName = storedData.AnimalNPC[nadeName].Name;
                int spawnAmount = storedData.AnimalNPC[nadeName].NumberToSpawn;
                string exploSound = storedData.AnimalNPC[nadeName].ExplosionSound;

                for (int i = 0; i < spawnAmount; i++)
                {
                    if (spawnAmount > 1)
                    {
                        Vector2 rand;
                        rand = UnityEngine.Random.insideUnitCircle * storedData.AnimalNPC[nadeName].SpawnRadius;
                        position = position + new Vector3(rand.x, 0, rand.y);
                    }
                    var groundLevel = TerrainMeta.HeightMap.GetHeight(position);
                    var heightDiff = position.y - groundLevel;
                    if (heightDiff > 6.0)
                    {
                        position.y = groundLevel;
                    }
                    BaseNpc npc = (BaseNpc)GameManager.server.CreateEntity(npcPrefab, position + new Vector3(0, 0.1f, 0));
                    if (npc == null)
                    {
                        return;
                    }
                    DoExplosion(exploSound, position);
                    npc.Spawn();

                    npc.OwnerID = player.userID;
                    npc.skinID = nadeSkin;
                    npc.CurrentBehaviour = BaseNpc.Behaviour.Attack;
                    npc.startHealth = storedData.AnimalNPC[nadeName].Health;
                    npc.InitializeHealth(storedData.AnimalNPC[nadeName].Health, storedData.AnimalNPC[nadeName].Health);
                    npc.SetFact(BaseNpc.Facts.CanTargetEnemies, 1, true, true);
                    npc.SetFact(BaseNpc.Facts.IsAggro, 1, true, true);

                    if (SpawnAborted(player, npc, nadeName, position))
                    {
                        return;
                    }
                    float despawnTime = storedData.AnimalNPC[nadeName].DespawnTime;
                    if (despawnTime > 0)
                    {
                        DespawnNPC(npc, npc.net.ID.Value, despawnTime);
                    }
                    BaseNpcData.Add(npc.net.ID.Value, npc);
                }
            }
        }
            
        private void SpawnBradley(BasePlayer player, string nadeName, ulong nadeSkin, Vector3 position)
        {
            if (player == null || nadeName == null || nadeSkin == 0 || position == null)
                return;

            if (storedData.BradleyNPC.ContainsKey(nadeName))
            {
                string npcPrefab = storedData.BradleyNPC[nadeName].Prefab;
                string npcName = storedData.BradleyNPC[nadeName].Name;
                int spawnAmount = storedData.BradleyNPC[nadeName].NumberToSpawn;
                string exploSound = storedData.BradleyNPC[nadeName].ExplosionSound;

                DoExplosion(exploSound, position);

                for (int i = 0; i < spawnAmount; i++)
                {
                    if (spawnAmount > 1)
                    {
                        Vector2 rand;
                        rand = UnityEngine.Random.insideUnitCircle * storedData.AnimalNPC[nadeName].SpawnRadius;
                        position = position + new Vector3(rand.x, 0, rand.y);
                    }
                    var groundLevel = TerrainMeta.HeightMap.GetHeight(position);
                    var heightDiff = position.y - groundLevel;
                    position.y = groundLevel;
                    BradleyAPC npc = (BradleyAPC)GameManager.server.CreateEntity(npcPrefab, position + new Vector3(0, 0.1f, 0));
                    npc.OwnerID = player.userID;
                    npc.skinID = nadeSkin;
                    npc.Spawn();

                    if (SpawnAborted(player, npc, nadeName, position))
                    {
                        return;
                    }
                    float despawnTime = storedData.BradleyNPC[nadeName].DespawnTime;
                    if (despawnTime > 0)
                    {
                        DespawnNPC(npc, npc.net.ID.Value, despawnTime);
                    }
                    BradleyAPCData.Add(npc.net.ID.Value, npc);
                }
            }
        }

        #endregion

        #region Helpers

        private void DespawnNPC(BaseEntity npc, ulong botId, float despawnTime)
        {
            timer.Once(despawnTime, () =>
            {
                if (npc != null && !npc.IsDestroyed)
                {
                    NextTick(() =>
                    {
                        npc.Kill();
                        RemoveNpcData(botId);
                    });
                    return;
                }
            });
        }

        void AddChute(BaseEntity npc, Vector3 position)
        {
            var playerRigidbody = npc.gameObject.GetComponent<Rigidbody>();
            playerRigidbody.isKinematic = false;
            playerRigidbody.useGravity = true;
            playerRigidbody.linearDamping = config.options.chuteDrag;
            npc.gameObject.layer = 0;

            var Chute = GameManager.server.CreateEntity(chutePrefab, npc.transform.position, Quaternion.Euler(0, 0, 0));
            Chute.gameObject.Identity();
            Chute.SetParent(npc);
            Chute.transform.localPosition += new Vector3(0, 1.4f, 0);
            Chute.Spawn();
            Chute.enableSaving = false;
        }

        private void CancelHit(HitInfo info)
        {
            info.damageTypes = new DamageTypeList();
            info.DidHit = false;
            info.DoHitEffects = false;
        }

        private object OnNpcKits(ulong npcUserID) // Prevents conflict with NPCKits.
        {
            return GrenadeNPCData.ContainsKey(npcUserID) ? true : (object)null;
        }

        private void GiveNade(BasePlayer player, ulong skinId, string nadeName, int nadeAmount, string reason)
        {
            if (player == null && skinId == 0 || nadeName == null || reason == null)
                return;

            Item npcNade = ItemManager.CreateByItemID(f1GrenadeId, nadeAmount, skinId);
            npcNade.name = nadeName;
            if (reason == "give")
            {
                player.inventory.GiveItem(npcNade);
                Message(player, "Receive", nadeAmount, nadeName);
            }
            else if (reason == "refund")
            {
                player.inventory.GiveItem(npcNade);
            }
        }

        public Item GiveInventoryItem(ItemContainer itemContainer, string shortName, int itemAmount, ulong skinId)
        {
            Item item = ItemManager.CreateByName(shortName, itemAmount, skinId);
            if (item == null) return null;
            if (!item.MoveToContainer(itemContainer))
            {
                item.Remove(0f);
                return null;
            }
            return item;
        }

        private bool CheckPermission(BasePlayer player, Item npcNade)
        {
            if (player == null || npcNade == null)
            {
                return false;
            }
            var perm = NadeInfo[npcNade.skin].Perm;
            if (player is NPCPlayer)
            {
                // Allow NPCs spawned by plugins which arm with NPCGrenades to work regardless of perms
                return true;
            }
            else if (permission.UserHasPermission(player.UserIDString, perm))
            {
                return true;
            }
            return false;
        }

        private bool IsNpcGrenade(ulong skinId)
        {
            if (skinId == 0)
                return false;

            if(NadeInfo.ContainsKey(skinId))
                return true;
            
            return false;
        }

        public Vector3 GetNavPoint(Vector3 position)
        {
            NavMeshHit hit;
            if (!NavMesh.SamplePosition(position, out hit, 5, -1))
            {
                return position;
            }
            else if (Physics.RaycastAll(hit.position + new Vector3(0, 100, 0), Vector3.down, 99f, 1235288065).Any())
            {
                return position;
            }
            else if (hit.position.y < TerrainMeta.WaterMap.GetHeight(hit.position))
            {
                return position;
            }
            position = hit.position;
            return position;
        }

        private bool IsInSafeZone(Vector3 position)
        {
            int loop = Physics.OverlapSphereNonAlloc(position, 1f, Vis.colBuffer, 1 << 18, QueryTriggerInteraction.Collide);
            for (int i = 0; i < loop; i++)
            {
                Collider collider = Vis.colBuffer[i];
                if (collider.GetComponent<TriggerSafeZone>())
                {
                    return true;
                }
            }
            return false;
        }

        private bool IsOnStructure(Vector3 position)
        {
            RaycastHit hit;
            var heightOffset = new Vector3(0, 3.0f, 0);
            if (Physics.Raycast(position + heightOffset, Vector3.down,
                    out hit, 10f, LayerMask.GetMask("Construction")) && hit.GetEntity().IsValid())
            {
                if (hit.GetEntity().name.Contains("building"))
                {
                    return true;
                }
            }
            return false;
        }

        private bool IsInRock(Vector3 position)
        {
            RaycastHit hit;
            string[] colliders = new string[] { "rock", "cliff", "junk", "range", "invisible" };
            Physics.queriesHitBackfaces = true;
            if (Physics.Raycast(position, Vector3.up, out hit, 25f, 65536, QueryTriggerInteraction.Ignore))
            {
                if (colliders.Any(x => hit.collider?.gameObject?.name.Contains(x, CompareOptions.OrdinalIgnoreCase) != null))
                {
                    return true;
                }
            }
            Physics.queriesHitBackfaces = false;
            return false;
        }

        private void DoExplosion(string sound, Vector3 position)
        {
            try
            {
                Effect.server.Run(sound, position);
            }
            catch
            {
                Puts($"Invalid explosion effect path specified.");
            }
        }

        private IPlayer FindPlayer(string nameOrIdOrIp)
        {
            foreach (var activePlayer in covalence.Players.Connected)
            {
                if (activePlayer.Id == nameOrIdOrIp)
                    return activePlayer;
                if (activePlayer.Name.Contains(nameOrIdOrIp))
                    return activePlayer;
                if (activePlayer.Name.ToLower().Contains(nameOrIdOrIp.ToLower()))
                    return activePlayer;
                if (activePlayer.Address == nameOrIdOrIp)
                    return activePlayer;
            }
            return null;
        }

        private bool IsFriend(ulong playerId, ulong targetId)
        {
            if (playerId == 0 || targetId == 0)
            {
                return false;
            }
            if (playerId == targetId)
            {
                return true;
            }
            if (Clans)
            {
                var result = Clans?.Call("IsMemberOrAlly", playerId, targetId);
                if (result != null && Convert.ToBoolean(result))
                {
                    return true;
                }
            }
            if (Friends)
            {
                var result = Friends?.Call("AreFriends", playerId, targetId);
                if (result != null && Convert.ToBoolean(result))
                {
                    return true;
                }
            }
            RelationshipManager.PlayerTeam team;
            RelationshipManager.ServerInstance.playerToTeam.TryGetValue(playerId, out team);
            if (team == null)
            {
                return false;
            }
            if (team.members.Contains(targetId))
            {
                return true;
            }
            return false;
        }

        private bool SpawnAborted(BasePlayer player, BaseEntity npc, string nadeName, Vector3 position)
        {
            if (npc == null || npc.IsDestroyed || nadeName == null)
            {
                return true;
            }
            else if (player == null || !player.IsAlive())
            {
                return true;
            }

            if (npc.WaterFactor() > 0.7f)
            {
                NextTick(() => {
                    npc.Kill();
                });
                Message(player, "UnderWater", nadeName, npc.net.ID.Value);
                return true;
            }
            else if (IsInSafeZone(position))
            {
                NextTick(() => {
                    npc.Kill();
                });
                Message(player, "InSafeZone", nadeName, npc.net.ID.Value);
                return true;
            }
            else if (!npc.IsOutside())
            {
                NextTick(() => {
                    npc.Kill();
                });
                Message(player, "Inside", nadeName, npc.net.ID.Value);
                return true;
            }
            else if (IsOnStructure(position))
            {
                NextTick(() => {
                    npc.Kill();
                });
                Message(player, "OnStructure", nade
// ... [Code preview truncated due to length. Full source in attached file] ...

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