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

FREE PlaneCrash : 0.2.2 0.2.2

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

namespace Oxide.Plugins
{
    [Info("PlaneCrash", "SkuliDropek", "0.2.2")]
    [Description("Call cargo planes that can be shot down by players to score loot")]
    class PlaneCrash : RustPlugin
    {
        #region Fields
        [PluginReference] Plugin Clans, Friends, FancyDrop, LustyMap, Kits;

        private StoredData storedData;
        private DynamicConfigFile data;

        private static PlaneCrash Instance { get; set; }

        private float mapSize;

        private Timer callTimer;
        private bool initialized;

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

        // Effects
        private const string C4EXPLOSION_EFFECT = "assets/prefabs/tools/c4/effects/c4_explosion.prefab";
        private const string HELIEXPLOSION_EFFECT = "assets/prefabs/npc/patrol helicopter/effects/heli_explosion.prefab";
        private const string DEBRIS_EFFECT = "assets/prefabs/npc/patrol helicopter/damage_effect_debris.prefab";
        private const string FIREBALL_EFFECT = "assets/bundled/prefabs/oilfireballsmall.prefab";
        private const string SMOKE_EFFECT = "assets/bundled/prefabs/fx/smoke_signal_full.prefab";

        // Prefabs
        private const string CARGOPLANE_PREFAB = "assets/prefabs/npc/cargo plane/cargo_plane.prefab";
        private const string GIBS_PREFAB = "assets/prefabs/npc/patrol helicopter/servergibs_patrolhelicopter.prefab";
        private const string CRATE_PREFAB = "assets/prefabs/npc/patrol helicopter/heli_crate.prefab";
        private const string SUPPLYDROP_PREFAB = "assets/prefabs/misc/supply drop/supply_drop.prefab";
        private const string ZOMBIE_PREFAB = "assets/prefabs/npc/murderer/murderer.prefab";
        private const string SCIENTIST_PREFAB = "assets/prefabs/npc/scientist/scientist.prefab";
        private const string HEAVYSCIENTIST_PREFAB = "assets/rust.ai/agents/npcplayer/humannpc/heavyscientist/heavyscientist.prefab";
        private const string CORPSE_PREFAB = "assets/prefabs/player/player_corpse.prefab";
        private const string DEBRISMARKER_PREFAB = "assets/prefabs/tools/map/explosionmarker.prefab";
        #endregion

        #region Oxide Hooks
        private void Loaded()
        {           
            mapSize = TerrainMeta.Size.x;
           
            data = Interface.Oxide.DataFileSystem.GetFile("planecrash_cooldowns");

            foreach (KeyValuePair<string, int> kvp in configData.Cooldowns)
            {
                if (!kvp.Key.StartsWith("planecrash."))
                    permission.RegisterPermission("planecrash." + kvp.Key, this);
                else permission.RegisterPermission(kvp.Key, this);
            }
            permission.RegisterPermission("planecrash.cancall", this);

            lang.RegisterMessages(Messages, this);
        }

        private void OnServerInitialized()
        {
            Instance = this;
            initialized = true;

            LoadData();

            if (configData.EventTimers.Random)
                StartCrashTimer();
        }

        private void OnServerSave() => SaveData();

        private void OnEntitySpawned(BaseNetworkable entity)
        {
            if (!initialized || entity == null)
                return;

            if (entity is CargoPlane)
            {
                if (!configData.Plane.ApplyToAll)
                    return;

                NextTick(() =>
                {
                    if (entity == null)
                        return;

                    object success = Interface.Call("isStrikePlane", entity as CargoPlane);
                    if (success is bool && (bool)success)
                        return;

                    object location = (entity as CargoPlane).dropPosition;
                    if (!(location is Vector3))
                        location = Vector3Ex.Range(-(mapSize / 6f), mapSize / 6f);

                    timer.In(2, () => AddCrashComponent(entity as CargoPlane, (Vector3)location, true));
                });
            }

            if (entity is LootableCorpse)
            {
                if (!configData.NPCOptions.ReplaceCorpseLoot)
                    return;

                LootableCorpse corpse = entity as LootableCorpse;              

                InventoryData inventoryData;

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

                deadMemberIds.Remove(corpse.playerSteamID);

                timer.In(2, () =>
                {
                    if (inventoryData != null)
                        inventoryData.RestoreItemsTo(corpse);

                    corpse.ResetRemovalTime(configData.NPCOptions.DespawnTime);
                });
            }
        }

        private void OnEntityDeath(BaseCombatEntity entity, HitInfo info)
        {
            if (entity == null || !configData.NPCOptions.ReplaceCorpseLoot)
                return;

            NPCController npcController = entity.GetComponent<NPCController>();
            if (npcController != null)
            {
                if (!deadMemberIds.ContainsKey(npcController.Entity.userID))
                    deadMemberIds.Add(npcController.Entity.userID, new InventoryData(npcController.Entity));

                StripInventory(npcController.Entity, true);
                return;
            }
        }

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

            CrashPlane crashComponent = entity.GetComponent<CrashPlane>();
            if (crashComponent != null)
                UnityEngine.Object.Destroy(crashComponent);
        }

        private object CanLootEntity(BasePlayer player, LootContainer container)
        {
            LootLock lootLock = container.GetComponent<LootLock>();
            if (lootLock != null && !lootLock.IsUnlocked())
            {
                if (player.userID == lootLock.ownerID)                
                    return null;
                
                if (configData.Loot.LockSettings.LockToPlayerTeam)
                {
                    RelationshipManager.PlayerTeam ownerTeam = RelationshipManager.ServerInstance.FindPlayersTeam(lootLock.ownerID);
                    RelationshipManager.PlayerTeam playerTeam = RelationshipManager.ServerInstance.FindPlayersTeam(player.userID);
                    if (ownerTeam != null && playerTeam != null && ownerTeam == playerTeam)                    
                        return null;                    
                }

                if (configData.Loot.LockSettings.LockToPlayerClans && IsClanmate(lootLock.ownerID, player.userID))                                   
                    return null;
                
                if (configData.Loot.LockSettings.LockToPlayerFriends && AreFriends(lootLock.ownerID, player.userID))                
                    return null;
                
                player.ChatMessage(msg("LootLocked", player.UserIDString));
                return false;
            }
            return null;
        }

        private void Unload()
        {
            CrashPlane[] planes = UnityEngine.Object.FindObjectsOfType<CrashPlane>();

            for (int i = 0; i < planes?.Length; i++)            
                UnityEngine.Object.Destroy(planes[i]);
            
            configData = null;
            Instance = null;
        }
        #endregion

        #region Components
        private enum FlightStatus { Flying, Crashing }

        private class CrashPlane : MonoBehaviour
        {
            private CargoPlane entity;
            private Transform tr;

            public FlightStatus status;

            private BasePlayer lastAttacker;

            private FireBall engineFireLeft;
            private FireBall engineFireRight;

            private Vector3 engineFireLeftOffset = new Vector3(-10, 6, 10);
            private Vector3 engineFireRightOffset = new Vector3(10, 6, 10);

            private Vector3 startPos;
            private Vector3 endPos;
            
            private int rocketHits;

            private float speed;
            private float currentSpeed;

            private float crashTimeTaken;
            private float crashTimeToTake;           

            private bool isDying;
            private bool isSmoking;
            private bool hasDropped;
            private bool isDropPlane;

            private bool isFancyDrop;

            private bool willAutoCrash;
            private float autoCrashAt;
            private float randomCrashDirection = -1;
            private float crashDelay = 0;
            private Vector3 baseEulerAngles;

            private Type[] interactableTypes = new Type[] { typeof(TreeEntity), typeof(ResourceEntity), typeof(BuildingBlock), typeof(SimpleBuildingBlock), typeof(BaseHelicopter) };

            private void Awake()
            {
                entity = GetComponent<CargoPlane>();
                entity.enabled = false;

                tr = entity.transform;

                gameObject.layer = (int)Layer.Reserved2;
                gameObject.name = "CrashPlane";

                AttachCollider();

                speed = currentSpeed = configData.Plane.Speed;

                crashTimeTaken = 0;
                crashTimeToTake = 20;
                status = FlightStatus.Flying;

                willAutoCrash = UnityEngine.Random.Range(0, 100) < configData.Plane.AutoCrashChance;
                autoCrashAt = UnityEngine.Random.Range(configData.Plane.CrashMinimumRange, configData.Plane.CrashMaximumRange);

                if (configData.Plane.RandomizeCrashDirection)
                    randomCrashDirection = UnityEngine.Random.value;
            }

            private void Update()
            {
                if (tr.position.y <= 0)
                {
                    if (!isDying)
                        Die();
                    return;
                }

                if (status == FlightStatus.Crashing)
                {
                    crashTimeTaken = crashTimeTaken + Time.deltaTime;

                    float delta = Mathf.InverseLerp(0, crashTimeToTake, crashTimeTaken);
                    if (delta < 1)
                    {
                        currentSpeed = speed + Mathf.Lerp(0, 10, delta);

                        Vector3 direction = baseEulerAngles;

                        direction.x = Mathf.Lerp(0, 25f, delta);

                        if (randomCrashDirection != -1)
                        {
                            float yaw = Mathf.Lerp(0f, 25f, delta * 1.75f);
                            float roll = Mathf.Lerp(0f, 35f, delta * 2.25f);

                            if (randomCrashDirection <= 0.5f)
                            {
                                direction.y -= yaw;
                                direction.z += roll;
                            }
                            else
                            {
                                direction.y += yaw;
                                direction.z -= roll;
                            }
                        }
                        tr.eulerAngles = direction;
                    }
                   
                    tr.position = Vector3.MoveTowards(tr.position, tr.position + (tr.forward * 10), currentSpeed * UnityEngine.Time.deltaTime);                    
                }
                else
                {
                    tr.position = Vector3.MoveTowards(tr.position, endPos, currentSpeed * UnityEngine.Time.deltaTime);

                    float delta = InverseLerp(startPos, endPos, tr.position);

                    if (isDropPlane)
                    {                        
                        entity.secondsTaken = entity.secondsToTake * delta;
                        
                        if (!hasDropped && delta >= 0.5f)
                        {
                            hasDropped = true;
                            if (!Instance.FancyDrop || !isFancyDrop)
                            {
                                BaseEntity drop = GameManager.server.CreateEntity(SUPPLYDROP_PREFAB, tr.position);
                                drop.globalBroadcast = true;
                                drop.Spawn();
                            }
                        }
                    }

                    if (willAutoCrash)
                    {
                        if (delta >= autoCrashAt && crashDelay < Time.time)
                        {
                            if (TerrainMeta.HeightMap.GetHeight(tr.position) < 0)
                            {
                                crashDelay = Time.time + 3f;
                                return;
                            }

                            SendChatMessage("AutoCrashMessage");
                            BeginCrash();
                        }
                    }
                }

                if (engineFireLeft != null)                
                    engineFireLeft.transform.position = tr.TransformPoint(engineFireLeftOffset);

                if (engineFireRight != null)
                    engineFireRight.transform.position = tr.TransformPoint(engineFireRightOffset);                

                tr.hasChanged = true;
            }

            private float InverseLerp(Vector3 a, Vector3 b, Vector3 value)
            {
                Vector3 ab = b - a;
                Vector3 av = value - a;
                return Vector3.Dot(av, ab) / Vector3.Dot(ab, ab);
            }

            private void OnDestroy()
            {
                enabled = false;
                CancelInvoke();

                if (engineFireLeft != null && !engineFireLeft.IsDestroyed)
                    engineFireLeft.Extinguish();

                if (engineFireRight != null && !engineFireRight.IsDestroyed)
                    engineFireRight.Extinguish();

                if (entity != null && !entity.IsDestroyed)
                    entity.Kill();
            }

            private void OnTriggerEnter(Collider col)
            {
                if (col is TerrainCollider)
                {
                    Die();
                    return;
                }

                BasePlayer player = col.gameObject.GetComponentInParent<BasePlayer>();
                if (player != null && col.gameObject.layer == 17)
                {
                    if (player.IsNpc)
                        return;

                    player.Die();
                    return;
                }

                ServerProjectile serverProjectile = col.GetComponentInParent<ServerProjectile>();
                if (serverProjectile != null)
                {
                    SmallExplosion();
                    col.GetComponentInParent<TimedExplosive>()?.Explode();
                    rocketHits++;

                    BasePlayer attacker = col.GetComponent<BaseEntity>()?.creatorEntity?.ToPlayer();
                   
                    if (configData.Loot.CrateHit > 0)
                        ServerMgr.Instance.StartCoroutine(SpawnLoot(configData.Loot.CrateHit, false));

                    if (configData.Loot.SupplyHit > 0)
                        ServerMgr.Instance.StartCoroutine(SpawnLoot(configData.Loot.SupplyHit, true));

                    if (rocketHits == 1)                    
                        AddFire(ref engineFireLeft);                    

                    if (rocketHits >= configData.Plane.DestroyHits)
                    {
                        if (attacker != null)
                            lastAttacker = attacker;

                        if (configData.Messages.DisplayAttacker && lastAttacker != null)
                            SendChatMessage("AttackerMessage2", lastAttacker.displayName);

                        Die();
                        return;
                    }

                    if (rocketHits >= configData.Plane.DownHits && status == FlightStatus.Flying)
                    {
                        if (attacker != null)
                            lastAttacker = attacker;

                        if (lastAttacker != null && configData.Messages.DisplayAttacker)
                            SendChatMessage("AttackerMessage1", lastAttacker.displayName);

                        BeginCrash();
                        return;
                    }
                }

                if (configData.Plane.Destruction)
                {
                    for (int i = 0; i < interactableTypes.Length; i++)
                    {
                        if (col.GetComponentInParent(interactableTypes[i]) != null)
                        {
                            BaseEntity baseEntity = col.GetComponentInParent<BaseEntity>();
                            BaseCombatEntity baseCombatEntity = baseEntity as BaseCombatEntity;
                            if (baseCombatEntity != null)
                            {
                                baseCombatEntity.Die();
                                return;
                            }
                            
                            if (baseEntity != null)
                            {
                                baseEntity.Kill(BaseNetworkable.DestroyMode.Gib);
                                return;
                            }
                        }
                    }            
                } 
            }

            #region Initialization
            public void SetFlightPath(Vector3 newDropPosition, bool isStandard = false)
            {
                if (entity == null)
                {
                    print("[ERROR] Error in SetFlightPath, the plane is null.Something (likely another plugin) has destroyed it...");
                    return;
                }

                if (!isStandard)
                {
                    if (configData.Plane.RandomDistance != 0)                    
                        newDropPosition += new Vector3(UnityEngine.Random.Range(-configData.Plane.RandomDistance, configData.Plane.RandomDistance), 0, UnityEngine.Random.Range(-configData.Plane.RandomDistance, configData.Plane.RandomDistance));
                    
                    float size = TerrainMeta.Size.x;
                    startPos = Vector3Ex.Range(-1f, 1f);
                    startPos.y = 0f;
                    startPos.Normalize();
                    startPos = startPos * (size * 2f);
                    endPos = startPos * -1f;
                    startPos = startPos + newDropPosition;
                    endPos = endPos + newDropPosition;
                    startPos.y = 150 + configData.Plane.Height;
                    endPos.y = startPos.y;

                    if (configData.Plane.SmokeTrail)
                        RunEffect(SMOKE_EFFECT, entity, new Vector3(), Vector3.up * 3);
                }
                else
                {
                    startPos = entity.startPos;
                    endPos = entity.endPos;
                    isDropPlane = true;
                }

                tr.position = startPos;
                tr.rotation = Quaternion.LookRotation(endPos - startPos);

                if (configData.Plane.RandomizeCrashDirection)
                {
                    Vector3 perp = Vector3.Cross(tr.forward, Vector3.zero - tr.position);
                    float dir = Vector3.Dot(perp, Vector3.up);

                    randomCrashDirection = dir >= 0 ? 1 : 0f;
                }

                entity.secondsToTake = Vector3.Distance(startPos, endPos) / speed;

                isFancyDrop = Instance.FancyDrop ? (bool)Instance.FancyDrop?.CallHook("IsFancyDrop", entity) : false;
                if (isDropPlane && isFancyDrop)
                    Instance.FancyDrop?.CallHook("OverrideDropTime", entity, entity.secondsToTake);

                Destroy(this, entity.secondsToTake);
            }

            private void AttachCollider()
            {
                Rigidbody rigidbody = gameObject.AddComponent<Rigidbody>();
                rigidbody.useGravity = false;
                rigidbody.isKinematic = true;
                rigidbody.detectCollisions = true;
                rigidbody.collisionDetectionMode = CollisionDetectionMode.Discrete;

                BoxCollider collider = gameObject.AddComponent<BoxCollider>();
                collider.isTrigger = true;
                collider.size = new Vector3(50, 10, 50);
                collider.transform.localPosition = Vector3.up * 6;
            }

            public void BeginCrash()
            {
                endPos = new Vector3(endPos.x, 0, endPos.z);
                status = FlightStatus.Crashing;

                baseEulerAngles = tr.eulerAngles;

                SmallExplosion();
                AddFire(ref engineFireLeft);
                AddFire(ref engineFireRight);
            }
            #endregion

            #region Effects
            private void BigExplosion()
            {
                RunEffect(HELIEXPLOSION_EFFECT, null, tr.position);
                RunEffect(DEBRIS_EFFECT, null, tr.position);
            }

            private void SmallExplosion()
            {
                RunEffect(C4EXPLOSION_EFFECT, null, tr.position);
                RunEffect(DEBRIS_EFFECT, null, tr.position);
            }

            private void AddFire(ref FireBall fireBall, float lifetime = 600)
            {
                if (fireBall != null)
                    return;

                fireBall = GameManager.server.CreateEntity(FIREBALL_EFFECT, tr.position) as FireBall;
                fireBall.enableSaving = false;
                fireBall.Spawn();

                Rigidbody rb = fireBall.GetComponent<Rigidbody>();                
                rb.isKinematic = true;

                fireBall.CancelInvoke(fireBall.Extinguish);
                fireBall.CancelInvoke(fireBall.TryToSpread);

                fireBall.Invoke(fireBall.Extinguish, lifetime);
            }

            #endregion

            private void Die()
            {
                if (isDying)
                    return;

                isDying = true;
                BigExplosion();
                CreateLootSpawns();

                if (configData.NPCOptions.Enabled)
                    ServerMgr.Instance.StartCoroutine(CreateNPCs(tr.position));

                if (configData.LustyOptions.CrashIcon)
                    InvokeHandler.Invoke(this, UpdateCrashMarker, 1.5f);

                if (configData.MapOptions.CrashIcon)
                    InvokeHandler.Invoke(this, UpdateMapMarker, 1.5f);

                InvokeHandler.Invoke(this, SmallExplosion, 0.25f);
                InvokeHandler.Invoke(this, SmallExplosion, 0.5f);
                InvokeHandler.Invoke(this, BigExplosion, 1.25f);
                InvokeHandler.Invoke(this, SmallExplosion, 1.75f);
                InvokeHandler.Invoke(this, BigExplosion, 2.25f);

                Destroy(this, 2.5f);
            }

            #region Loot
            private void CreateLootSpawns()
            {
                List<ServerGib> serverGibs = ServerGib.CreateGibs(GIBS_PREFAB, gameObject, entity.gameObject, tr.forward * 2, 5f);
                for (int i = 0; i < 12; i++)
                {
                    BaseEntity fireBall = GameManager.server.CreateEntity(FIREBALL_EFFECT, tr.position, tr.rotation, true);
                    if (fireBall)
                    {
                        Vector3 randsphere = UnityEngine.Random.onUnitSphere;
                        fireBall.transform.position = (tr.position + new Vector3(0f, 1.5f, 0f)) + (randsphere * UnityEngine.Random.Range(-4f, 4f));

                        Collider collider = fireBall.GetComponent<Collider>();
                        fireBall.Spawn();
                        fireBall.SetVelocity(tr.forward + randsphere);

                        foreach (ServerGib serverGib in serverGibs)
                            Physics.IgnoreCollision(collider, serverGib.GetCollider(), true);
                    }
                }

                if (configData.Loot.CrateCrash > 0)
                    ServerMgr.Instance.StartCoroutine(SpawnLoot(configData.Loot.CrateCrash, false, true));

                if (configData.Loot.SupplyCrash > 0)
                    ServerMgr.Instance.StartCoroutine(SpawnLoot(configData.Loot.SupplyCrash, true, true));

                if (configData.Messages.DisplayDestroy)
                {
                    if (configData.Messages.UseGrid)
                        SendChatMessage("DestroyMessage.Grid", GetGridString(tr.position));
                    else SendChatMessage("DestroyMessage", tr.position.x, tr.position.z);
                }
            }

            private IEnumerator SpawnLoot(int amount, bool isDrop, bool isCrashing = false)
            {
                for (int j = 0; j < amount; j++)
                {
                    Vector3 position = (tr.position + new Vector3(0f, 1.5f, 0f)) + (UnityEngine.Random.onUnitSphere * UnityEngine.Random.Range(-2f, 3f));

                    position.y = Mathf.Max(TerrainMeta.HeightMap.GetHeight(position), position.y);
                    
                    string ent = isDrop ? SUPPLYDROP_PREFAB : CRATE_PREFAB;

                    LootContainer container = GameManager.server.CreateEntity(ent, position, Quaternion.LookRotation(UnityEngine.Random.onUnitSphere), true) as LootContainer;
                    container.enableSaving = false;
                    container.Spawn();

                    if (configData.Loot.LockSettings.LockToPlayer && lastAttacker != null)                    
                        LootLock.Initialize(container, lastAttacker.userID);
                    
                    if (j == 0 && configData.Plane.Smoke && isCrashing && !isSmoking)
                    {
                        RunEffect(SMOKE_EFFECT, container);
                        isSmoking = true;
                    }

                    Rigidbody rigidbody;
                    if (!isDrop)
                        rigidbody = container.gameObject.AddComponent<Rigidbody>();
                    else
                    {
                        container.GetComponent<SupplyDrop>().RemoveParachute();
                        rigidbody = container.GetComponent<Rigidbody>();
                    }

                    if (rigidbody != null)
                    {
                        rigidbody.isKinematic = false;
                        rigidbody.useGravity = true;
                        rigidbody.mass = 1.25f;
                        rigidbody.interpolation = RigidbodyInterpolation.Interpolate;
                        rigidbody.drag = 0.25f;
                        rigidbody.angularDrag = 0.1f;
                        rigidbody.AddForce((tr.forward + (tr.right * UnityEngine.Random.Range(-10f, 10f))) * 100);
                    }

                    FireBall fireBall = null;
                    AddFire(ref fireBall, configData.Loot.FireLife);                    
                    fireBall.SetParent(container, 0, false, true);
                    
                    InvokeHandler.Invoke(container, () => FillLootContainer(container, isDrop), 2f);

                    if (configData.Loot.LootDespawnTime > 0)
                    {
                        container.Invoke(() =>
                        {
                            if (container.HasFlag(BaseEntity.Flags.Open))
                                return;
                            container?.Kill();
                        }, 
                        configData.NPCOptions.DespawnTime);
                    }

                    yield return CoroutineEx.waitForEndOfFrame;
                }
            }
            #endregion

            #region NPCs
            private IEnumerator CreateNPCs(Vector3 position)
            {
                string type = configData.NPCOptions.Type.ToLower() == "murderer" ? ZOMBIE_PREFAB : configData.NPCOptions.Type.ToLower() == "heavyscientist" ? HEAVYSCIENTIST_PREFAB : SCIENTIST_PREFAB;

                int amount = configData.NPCOptions.Amount + (configData.NPCOptions.CorpseEnabled ? configData.NPCOptions.CorpseAmount : 0);

                for (int i = 0; i < amount; i++)
                {
                    Vector3 newPosition = position + (UnityEngine.Random.onUnitSphere * 20);

                    object point = Instance.FindPointOnNavmesh(newPosition);
                    if (point is Vector3)
                        newPosition = (Vector3)point;
                    else newPosition.y = TerrainMeta.HeightMap.GetHeight(newPosition);

                    if (newPosition.y < -0.25f)
                        continue;

                    NPCPlayer npcPlayer = InstantiateEntity(type, newPosition);
                    npcPlayer.enableSaving = false;
                    npcPlayer.Spawn();

                    bool isCorpse = i >= configData.NPCOptions.Amount;

                    NPCController npcController = npcPlayer.gameObject.AddComponent<NPCController>();
                    npcController.Setup(lastAttacker, isCorpse);

                    yield return CoroutineEx.waitForEndOfFrame;
                }
            }
            
            private NPCPlayer InstantiateEntity(string type, Vector3 position)
            {
                GameObject gameObject = Facepunch.Instantiate.GameObject(GameManager.server.FindPrefab(type), position, new Quaternion());
                gameObject.name = type;

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

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

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

                NPCPlayer component = gameObject.GetComponent<NPCPlayer>();
                return component;
            }
            #endregion

            #region Map Markers
            private void UpdateCrashMarker()
            {
                if (!Instance.LustyMap || entity == null)
                    return;

                Instance.LustyMap.Call("AddTemporaryMarker", tr.position.x, tr.position.z, "Crashed Plane", configData.LustyOptions.IconURL, 0);
                Instance.timer.In(configData.LustyOptions.CrashIconTime, () => Instance.LustyMap.Call("RemoveTemporaryMarker", "Crashed Plane"));
            }

            private void UpdateMapMarker()
            {
                if (entity == null)
                    return;

                BaseEntity baseEntity = GameManager.server.CreateEntity(DEBRISMARKER_PREFAB, tr.position, Quaternion.identity, true);
                baseEntity.Spawn();
                baseEntity.SendMessage("SetDuration", configData.MapOptions.CrashIconTime, SendMessageOptions.DontRequireReceiver);
            }
            #endregion
        }

        public class LootLock : MonoBehaviour
        {
            internal LootContainer Container { get; private set; }

            internal ulong ownerID;

            private float lockExpiretime;

            private void Awake()
            {
                Container = GetComponent<LootContainer>();
                lockExpiretime = Time.time + configData.Loot.LockSettings.LockTime;
                Destroy(this, configData.Loot.LockSettings.LockTime);
            }

            internal bool IsUnlocked() => Time.time >= lockExpiretime;

            internal static void Initialize(LootContainer container, ulong ownerId)
            {
                LootLock lootLock = container.gameObject.AddComponent<LootLock>();
                lootLock.ownerID = ownerId;                
            }
        }

        public class NPCController : MonoBehaviour
        {
            public NPCPlayer Entity { get; private set; }

            private Vector3 basePosition;

            private BasePlayer lastAttacker;

            private float woundedDuration;

            private float woundedStartTime;

            private float secondsSinceWoundedStarted
            {
                get
                {
                    return Time.realtimeSinceStartup - this.woundedStartTime;
                }
            }

            private void Awake()
            {
                Entity = GetComponent<NPCPlayer>();
                enabled = false;
                basePosition = Entity.transform.position;

                Entity.NavAgent.areaMask = 1;
                Entity.NavAgent.agentTypeID = -1372625422;

                //if (Entity is NPCPlayerApex)
                  //  (Entity as NPCPlayerApex).CommunicationRadius = -1f;

                Entity.displayName = configData.NPCOptions.Names?.Length > 0 ? configData.NPCOptions.Names.GetRandom() : Entity.ShortPrefabName;
                Entity.InitializeHealth(configData.NPCOptions.Health, configData.NPCOptions.Health);                
            }

            public void Setup(BasePlayer lastAttacker, bool isCorpse)
            {
                this.lastAttacker = lastAttacker;

                if (!isCorpse)
                {
                    if (UnityEngine.Random.Range(0, 100) <= configData.NPCOptions.WoundedChance)
                    {
                        woundedDuration = UnityEngine.Random.Range(300f, 600f);
                        woundedStartTime = Time.realtimeSinceStartup;
                        Entity.SetPlayerFlag(BasePlayer.PlayerFlags.Wounded, true);
                        Entity.ServerFall();
                        Entity.SendNetworkUpdateImmediate(false);
                        Entity.Invoke(WoundingTick, 1f);
                    }

                    InvokeHandler.Invoke(Entity, Despawn, configData.NPCOptions.DespawnTime);
                }

                string kit = isCorpse ? configData.NPCOptions.CorpseKit : configData.NPCOptions.Kit;

                if (Entity is ScarecrowNPC && configData.NPCOptions.ReplaceCorpseLoot)
                    (Entity as ScarecrowNPC).LootSpawnSlots = new LootContainer.LootSpawnSlot[0];

                if (Entity is global::HumanNPC && configData.NPCOptions.ReplaceCorpseLoot)
                    (Entity as global::HumanNPC).LootSpawnSlots = new LootContainer.LootSpawnSlot[0];

                if (!string.IsNullOrEmpty(kit))
                {
                    if (Entity.IsInvoking(Entity.EquipTest))
                        Entity.CancelInvoke(Entity.EquipTest);

                    StripInventory(Entity);

                    Instance.NextTick(() =>
                    {
                        Instance.Kits?.Call("GiveKit", Entity, kit);

                        if (isCorpse)
                            InvokeHandler.Invoke(Entity, () => Entity.Die(new HitInfo(lastAttacker ?? Entity, Entity, DamageType.Explosion, 1000f)), UnityEngine.Random.Range(1f, 3f));
                        else Instance.NextTick(() => Entity.EquipTest());
                    });
                }
                else
                {
                    if (isCorpse)
                        InvokeHandler.Invoke(Entity, () => Entity.Die(new HitInfo(lastAttacker ?? Entity, Entity, DamageType.Explosion, 1000f)), UnityEngine.Random.Range(1f, 3f));
                }

                if (!isCorpse)
                    InvokeHandler.InvokeRandomized(this, CheckNPCLocation, 1f, 5f, 1f);
            }

            private void Despawn()
            {
                if (Entity == null || Entity.IsDestroyed || Entity.IsDead())
                    return;

                Entity.inventory.Strip();
                Entity.Die(new HitInfo(lastAttacker ?? Entity, Entity, DamageType.Explosion, 1000f));
            }

            private void WoundingTick()
            {
                if (!Entity.IsDead())
                {
                    if (secondsSinceWoundedStarted < woundedDuration)
                    {
                        Entity.Invoke(WoundingTick, 1f);
                    }
                    else if (UnityEngine.Random.Range(0, 100) >= configData.NPCOptions.WoundedRecoveryChance)
                    {
                        Entity.Die(new HitInfo(lastAttacker ?? Entity, Entity, DamageType.Explosion, 1000f));
                    }
                    else
                    {
                        Entity.SetPlayerFlag(BasePlayer.PlayerFlags.Wounded, false);
                    }
                }
            }

            public void CheckNPCLocation()
            {
                if (Entity == null || Entity.IsDestroyed)
                {
                    Destroy(this);
                    return;
                }

                if (Vector3.Distance(Entity.transform.position, basePosition) > 30)                
                    ResetPosition(); 
            }
            
            private void ResetPosition() => Entity.SetDestination(basePosition);            
        }
        #endregion

        #region Functions
        private void StartCrashTimer()
        {
            callTimer = timer.In(UnityEngine.Random.Range(configData.EventTimers.Min, configData.EventTimers.Max) * 60, () =>
            {
                CargoPlane plane = (CargoPlane)GameManager.server.CreateEntity(CARGOPLANE_PREFAB, new Vector3(), new Quaternion(), true);
                plane.enableSaving = false;
                plane.Spawn();

                CrashPlane crash = plane.gameObject.AddComponent<CrashPlane>();
                crash.SetFlightPath(Vector3Ex.Range(-(mapSize / 6f), mapSize / 6f));

                if (configData.Messages.DisplayIncoming)
                    SendChatMessage("IncomingMessage");

                StartCrashTimer();
            });
        }

        private static void RunEffect(string name, BaseEntity entity = null, Vector3 position = new Vector3(), Vector3 offset = new Vector3())
        {
            if (entity != null)
                Effect.server.Run(name, entity, 0, offset, position, null, true);
            else Effect.server.Run(name, position, Vector3.up, null, true);
        }

        private void AddCrashComponent(CargoPlane plane, Vector3 location, bool isStandard = false)
        {
            if (plane.GetComponent<CrashPlane>())
                return;

            CrashPlane crash = plane.gameObject.AddComponent<CrashPlane>();
            crash.SetFlightPath(location, isStandard);

            if (!isStandard && configData.Messages.DisplayIncoming)
                SendChatMessage("IncomingMessage");
        }

        private static void FillLootContainer(BaseEntity entity, bool isDrop)
        {
            if (entity == null)
                return;

            ItemContainer container = isDrop ? entity.GetComponent<SupplyDrop>()?.inventory : entity.GetComponentInParent<LootContainer>()?.inventory;
            ConfigData.LootSettings.LootTables lootTable = isDrop ? configData.Loot.SupplyLoot : configData.Loot.CrateLoot;
           
            if (container == null || lootTable == null)
                return;

            if (lootTable.Enabled)
            {
                while (container.itemList.Count > 0)
                {
                    Item item = container.itemList[0];
                    item.RemoveFromContainer();
                    item.Remove(0f);
                }

                List<ConfigData.LootSettings.LootTables.LootItem> items = new List<ConfigData.LootSettings.LootTables.LootItem>(lootTable.Items);

                int count = UnityEngine.Random.Range(lootTable.Minimum, lootTable.Maximum);
                for (int i = 0; i < count; i++)
                {
                    ConfigData.LootSettings.LootTables.LootItem lootItem = items.GetRandom();
                    if (lootItem == null)
                        continue;

                    items.Remove(lootItem);
                    if (items.Count == 0)
                        items.AddRange(lootTable.Items);

                    Item item = ItemManager.CreateByName(lootItem.Shortname, UnityEngine.Random.Range(lootItem.Min, lootItem.Max));
                    if (item != null)
                        item.MoveToContainer(container);
                }
            }
            if (configData.Loot.LockSettings.LockCrates)
            {
                entity.SetFlag(BaseEntity.Flags.Locked, true, false);
                InvokeHandler.Invoke(entity, () => { entity.SetFlag(BaseEntity.Flags.Locked, false, false); }, configData.Loot.LockSettings.LockTimer);                
            }
        }

        private static void StripInventory(BasePlayer player, bool skipWear = false)
        {
            Item[] allItems = player.inventory.AllItems();

            for (int i = allItems.Length - 1; i >= 0; i--)
            {
                Item item = allItems[i];
                if (skipWear && item?.parent == player.inventory.containerWear)
                    continue;

                item.RemoveFromContainer();
                item.Remove();
            }
        }

        private object FindPointOnNavmesh(Vector3 targetPosition)
        {
            NavMeshHit navHit;
            if (NavMesh.SamplePosition(targetPosition, out navHit, 100, 1))
                return navHit.position;
            return null;
        }

        private static string GetGridString(Vector3 position)
        {
            Vector2 adjPosition = new Vector2((World.Size / 2) + position.x, (World.Size / 2) - position.z);
            return $"{NumberToString((int)(adjPosition.x / 145))}{((int)(adjPosition.y / 145)) - 1}";
        }

        private static string NumberToString(int number)
        {
            bool a = number > 26;
            Char c = (Char)(65 + (a ? number - 26 : number));
            return a ? "A" + c : c.ToString();
        }

        private bool IsCrashPlane(CargoPlane plane) => plane.GetComponent<CrashPlane>();        

        private string FormatTime(double time)
        {
            TimeSpan dateDifference = TimeSpan.FromSeconds((float)time);
            var days = dateDifference.Days;
            var hours = dateDifference.Hours;
            hours += (days * 24);
            var mins = dateDifference.Minutes;
            var secs = dateDifference.Seconds;
            return string.Format("{0:00}:{1:00}:{2:00}", hours, mins, secs);
        }

        private static void SendChatMessage(string key, params object[] args)
        {
            for (int i = 0; i < BasePlayer.activePlayerList.Count; i++)
            {
                BasePlayer player = BasePlayer.activePlayerList[i];           
                player.ChatMessage(args != null ? string.Format(msg(key, player.UserIDString), args) : msg(key, player.UserIDString));
            }
        }
        #endregion

        #region Friends
        private bool AreFriends(ulong playerId, ulong friendId)
        {
            if (Friends)
                return (bool)Friends?.Call("AreFriends", playerId.ToString(), friendId.ToString());
            return false;
        }
        private bool IsClanmate(ulong playerId, ulong friendId)
        {
            if (Clans)
            {
                object playerTag = Clans?.Call("GetClanOf", playerId);
                object friendTag = Clans?.Call("GetClanOf", friendId);
                if (playerTag is string && friendTag is string)
                {
                    if (!string.IsNullOrEmpty((string)playerTag) && !string.IsNullOrEmpty((string)friendTag) && (playerTag == friendTag))
                        return true;
                }
            }
            return false;
        }
        #endregion

        #region Commands
        [ConsoleCommand("callcrash")]
        void ccmdSendCrash(ConsoleSystem.Arg arg)
        {
            if (arg.Connection != null)
                return;

            Vector3 location = Vector3.zero;
            if (arg.Args != null)
            {
                if (arg.Args.Length == 1 && arg.Args[0].ToLower() == "help")
                {
                    SendReply(arg, $"{Title}  v{Version} - k1lly0u @ chaoscode.io");
                    SendReply(arg, "callcrash - Send a random crash plane");
                    SendReply(arg, "callcrash \"X\" \"Z\" - Send a crash plane towards the specified X and Z co-ordinates");
                    SendReply(arg, "callcrash \"playername\" - Send a crash plane towards the specified player's position");
                    SendReply(arg, "callcrash crashall - Force crash any active planes");
                    return;
                }

                if (arg.Args.Length > 0)
                {
                    if (arg.Args.Length == 2)
                    {
                        float x;
                        float z;
                        if (float.TryParse(arg.Args[0], out x) && float.TryParse(arg.Args[1], out z))
                        {
                            location = new Vector3(x, 0, z);
                            SendReply(arg, $"Crash plane sent to X: {x}, Z: {z}");
                        }
                    }
                    if (arg.Args.Length == 1)
                    {
                        if (arg.Args[0].ToLower() == "crashall")
                        {
                            CrashPlane[] crashPlanes = UnityEngine.Object.FindObjectsOfType<CrashPlane>();
                            if (crashPlanes == null || crashPlanes.Length == 0)
                            {
                                SendReply(arg, "There are no planes currently active");
                                return;
                            }

                            for (int i = 0; i < crashPlanes.Length; i++)
                            {
                                CrashPlane crashPlane = crashPlanes[i];
                                if (crashPlane.status == FlightStatus.Flying)
                                    crashPlane.BeginCrash();
                            }
                            
                            SendReply(arg, $"Force crashing {crashPlanes.Length} planes!");
                            return;
                        }
                        else
                        {
                            IPlayer targetPlayer = covalence.Players.FindPlayer(arg.Args[0]);
                            if (targetPlayer != null && targetPlayer.IsConnected)
                            {
                                BasePlayer target = targetPlayer?.Object as BasePlayer;
                                if (target != null)
// ... [Code preview truncated due to length. Full source in attached file] ...

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