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

FREE PlaneCrash : 0.3.12 0.3.12

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Facepunch;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Ext.ChaosNPC;
using Rust;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

using Random = UnityEngine.Random;

namespace Oxide.Plugins
{
    [Info("PlaneCrash", "k1lly0u", "0.3.12")]
    [Description("Call cargo planes that can be shot down by players to score loot")]
    class PlaneCrash : RustPlugin, IChaosNPCPlugin
    {
        #region Fields
        [PluginReference] Plugin Clans, Friends, LustyMap;
       
        private static PlaneCrash Instance { get; set; }

        private Timer callTimer;
        private bool initialized;

        private readonly SpawnFilter Filter = new SpawnFilter
        {
            BiomeType = (TerrainBiome.Enum)15,
            TopologyAll = (TerrainTopology.Enum)0,
            TopologyAny = ~(TerrainTopology.Enum)0,
            SplatType = (TerrainSplat.Enum)255,
            TopologyNot = (TerrainTopology.Enum)2705030
        };

        // 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 DEBRISMARKER_PREFAB = "assets/prefabs/tools/map/explosionmarker.prefab";
        #endregion

        #region Oxide Hooks
        private void Loaded()
        {
            LoadData();

            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);
            
            if (!configData.Plane.ApplyOnSpawn)
                Unsubscribe(nameof(OnEntitySpawned));

            lang.RegisterMessages(Messages, this);
        }

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

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

        private void OnServerSave() => SaveData();

        private void OnEntitySpawned(CargoPlane cargoPlane)
        {
            NextFrame(() =>
            {
                if (cargoPlane)
                {
                    SpawnCrashPlane(cargoPlane);

                    Debug.Log("[PlaneCrash] - Replaced game spawned plane");

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

        private object CanLootEntity(BasePlayer player, LootContainer container)
        {
            LootLock lootLock = container.GetComponent<LootLock>();
            if (lootLock && !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++)            
                planes[i].Kill(BaseNetworkable.DestroyMode.None);
            
            configData = null;
            Instance = null;
        }
        #endregion

        #region CustomNPC
        public bool InitializeStates(BaseAIBrain customNPCBrain) => false;

        public bool WantsToPopulateLoot(CustomScientistNPC customNpc, NPCPlayerCorpse npcplayerCorpse) => false;

        public byte[] GetCustomDesign() => null;
        #endregion

        #region Components
        public enum FlightStatus { Flying, Crashing }

        public class CrashPlane : BaseEntity
        {
            public Transform Transform { get; private set; }

            public BoxCollider Collider { get; private set; }

            public FlightStatus status;

            private BasePlayer lastAttacker;

            public Vector3 startPosition;

            public Vector3 endPosition;

            public float secondsToTake;

            public float secondsTaken;

            private FireballHandler engineFireballLeft;
            private FireballHandler engineFireballRight;

            private DestructionTrigger destructionTrigger;

            private int rocketHitsTaken;

            private float speed;
            private float currentSpeed;

            private float crashTimeTaken = 0;
            private readonly float crashTimeToTake = 20;           

            private bool isDying;
            private bool isSmoking;

            public bool shouldDropCrate;
            private bool hasDropped;

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

            private Vector3 crashRotation;

            public bool isPaused = false;

            private void Awake()
            {
                Transform = transform;

                gameObject.layer = 0;
                gameObject.name = "CrashPlane";

                CreateColliders();

                speed = currentSpeed = configData.Plane.Speed;

                status = FlightStatus.Flying;

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

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

            private void CreateColliders()
            {
                Collider = gameObject.AddComponent<BoxCollider>();
                Collider.size = new Vector3(25, 15, 55);
                Collider.center = Vector3.up * 10f;

                destructionTrigger = gameObject.CreateChild().AddComponent<DestructionTrigger>();
                destructionTrigger.Setup(this);
            }

            public override void OnAttacked(HitInfo info)
            {               
                base.OnAttacked(info);

                if (info == null)
                    return;

                TimedExplosive timedExplosive = info.WeaponPrefab as TimedExplosive;
                if (timedExplosive)
                {
                    SmallExplosion();
                                        
                    rocketHitsTaken++;

                    BasePlayer attacker = info.InitiatorPlayer;

                    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 (rocketHitsTaken == 1 && engineFireballLeft == null)
                        engineFireballLeft = new FireballHandler(new Vector3(-14.5f, 7.5f, 9f), Transform);

                    if (rocketHitsTaken >= configData.Plane.DestroyHits)
                    {
                        if (attacker)
                            lastAttacker = attacker;

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

                        Die();
                        return;
                    }

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

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

                        BeginCrash();
                        return;
                    }
                }
            }

            public override void PostInitShared()
            {
                base.PostInitShared();

                if (configData.Plane.SmokeTrail)
                    Invoke(()=> RunEffect(SMOKE_EFFECT, this, Vector3.zero, Vector3.up * 3), 5f);
            }

            public override void DestroyShared()
            {
                Destroy(destructionTrigger);
                base.DestroyShared();
            }
                       

            private void Update()
            {
                if (isPaused)
                    return;

                if (Transform.position.y <= 0)
                {
                    if (!isDying)
                        Die();
                    return;
                }

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

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

                        Vector3 direction = crashRotation;

                        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;
                            }
                        }
                        Transform.eulerAngles = direction;
                    }
                   
                    Transform.position = Vector3.MoveTowards(Transform.position, Transform.position + (Transform.forward * 10), currentSpeed * Time.deltaTime);                    
                }
                else
                {
                    Transform.position = Vector3.MoveTowards(Transform.position, endPosition, currentSpeed * Time.deltaTime);

                    float delta = InverseLerp(startPosition, endPosition, Transform.position);

                    secondsTaken = secondsToTake * delta;

                    if (shouldDropCrate && !hasDropped && delta >= 0.5f)
                    {
                        hasDropped = true;

                        SupplyDrop supplyDrop = GameManager.server.CreateEntity(SUPPLYDROP_PREFAB, Transform.position + (Transform.forward * -10f) + (Vector3.down * 3f)) as SupplyDrop;
                        supplyDrop.globalBroadcast = true;   
                        supplyDrop.Spawn();

                        supplyDrop.Invoke(() => VerifySupplyDropParachute(supplyDrop), 2f);

                        Interface.CallHook("OnSupplyDropDropped", supplyDrop, this);
                    }

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

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

                engineFireballLeft?.Update();
                engineFireballRight?.Update();             

                Transform.hasChanged = true;
            }

            private void VerifySupplyDropParachute(SupplyDrop supplyDrop)
            {
                supplyDrop.SetFlag(Flags.Reserved2, true);
                /*if (!supplyDrop.parachute || supplyDrop.parachute.IsDestroyed)
                {
                    supplyDrop.parachute = GameManager.server.CreateEntity(supplyDrop.parachutePrefab.resourcePath);
                    supplyDrop.parachute.SetParent(supplyDrop, "parachute_attach", false, false);
                    supplyDrop.parachute.Spawn();

                    supplyDrop.isLootable = false;

                    supplyDrop.Invoke(()=> VerifySupplyDropParachute(supplyDrop), 1f);
                }*/
            }

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

                if (engineFireballLeft != null)
                    engineFireballLeft.Destroy();

                if (engineFireballRight != null)
                    engineFireballRight.Destroy();

                if (!IsDestroyed)
                    Kill();
            }

            #region Initialization
            public void SetFlightPath(Vector3 dropPosition)
            {
                if (configData.Plane.RandomDistance != 0)
                {
                    Vector2 random = Random.insideUnitCircle * configData.Plane.RandomDistance;
                    dropPosition.x += random.x;
                    dropPosition.z += random.y;
                }

                dropPosition = dropPosition.XZ3D();

                startPosition = Vector3Ex.Range(-1f, 1f);
                startPosition.y = 0f;
                startPosition.Normalize();
                startPosition *= (TerrainMeta.Size.x * 2f);
                startPosition.y = 150f + configData.Plane.Height;
                endPosition = startPosition * -1f;
                endPosition.y = startPosition.y;
                startPosition += dropPosition;
                endPosition += dropPosition;

                secondsToTake = Vector3.Distance(startPosition, endPosition) / speed;

                transform.position = startPosition;
                transform.rotation = Quaternion.LookRotation(endPosition - startPosition);

                if (configData.Plane.RandomizeCrashDirection)
                {
                    Vector3 perp = Vector3.Cross(Transform.forward, Vector3.zero - Transform.position);
                    randomCrashDirection = Vector3.Dot(perp, Vector3.up) >= 0 ? 1 : 0f;
                }

                Destroy(this, secondsToTake);
            }
            
            public void SetFlightPath(CargoPlane cargoPlane)
            {
                startPosition = cargoPlane.startPos;
                startPosition.y = 150f + configData.Plane.Height;
                
                endPosition = cargoPlane.endPos;
                endPosition.y = startPosition.y;

                secondsToTake = Vector3.Distance(startPosition, endPosition) / speed;
                secondsToTake = cargoPlane.secondsToTake;

                willAutoCrash = false;

                Vector3 position = cargoPlane.transform.position;
                transform.position = new Vector3(position.x, startPosition.y, position.z);
                transform.rotation =  cargoPlane.transform.rotation;

                if (configData.Plane.RandomizeCrashDirection)
                {
                    Vector3 perp = Vector3.Cross(Transform.forward, Vector3.zero - Transform.position);
                    randomCrashDirection = Vector3.Dot(perp, Vector3.up) >= 0 ? 1 : 0f;
                }

                Destroy(this, secondsToTake);
            }
            
            public void BeginCrash()
            {
                endPosition = new Vector3(endPosition.x, 0, endPosition.z);
                status = FlightStatus.Crashing;

                crashRotation = Transform.eulerAngles;

                SmallExplosion();

                if (engineFireballLeft == null)
                    engineFireballLeft = new FireballHandler(new Vector3(-14.5f, 7.5f, 9f), Transform);

                if (engineFireballRight == null)
                    engineFireballRight = new FireballHandler(new Vector3(14.5f, 7.5f, 9f), Transform);
            }
            #endregion

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

            private void SmallExplosion()
            {
                RunEffect(C4EXPLOSION_EFFECT, null, Transform.position);
                RunEffect(DEBRIS_EFFECT, null, Transform.position);
            }            
            #endregion

            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 Die()
            {
                if (isDying)
                    return;

                isDying = true;
                BigExplosion();
                FinalLootNPCSpawn();
                
                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 FinalLootNPCSpawn()
            {
                Vector3 velocity = Transform.forward * currentSpeed;

                if (configData.Loot.FireLife > 0)
                {
                    List<ServerGib> serverGibs = ServerGib.CreateGibs(GIBS_PREFAB, gameObject, gameObject, velocity, 5f);
                    for (int i = 0; i < 12; i++)
                    {
                        FireBall fireBall = GameManager.server.CreateEntity(FIREBALL_EFFECT, Transform.position, Transform.rotation, true) as FireBall;
                        if (fireBall)
                        {
                            Vector3 randsphere = Random.onUnitSphere;
                            fireBall.transform.position = (Transform.position + new Vector3(0f, 1.5f, 0f)) + (randsphere * Random.Range(-4f, 4f));

                            Collider collider = fireBall.GetComponent<Collider>();
                            fireBall.lifeTimeMin = fireBall.lifeTimeMax = configData.Loot.FireLife;
                            fireBall.Spawn();

                            fireBall.SetVelocity(velocity + (randsphere * Random.Range(3f, 10f)));

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

                List<BaseEntity> list = Facepunch.Pool.Get<List<BaseEntity>>();

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

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

                if (configData.NPCOptions.Enabled)
                    Instance.timer.In(5f, () => SpawnNPCs(list, lastAttacker));
                else Facepunch.Pool.FreeUnmanaged(ref list);

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

            private IEnumerator SpawnLoot(int amount, bool isDrop, bool isCrashing = false, List<BaseEntity> lootList = null)
            {
                Vector3 lastMoveDir = Transform.forward * currentSpeed;

                for (int j = 0; j < amount; j++)
                {
                    Vector3 position = (Transform.position + new Vector3(0f, 1.5f, 0f)) + (Random.onUnitSphere * Random.Range(-2f, 3f));

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

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

                    if (lootList != null)
                        lootList.Add(container);

                    if (configData.Loot.LockSettings.LockToPlayer && lastAttacker)                    
                        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.GetComponent<Rigidbody>();
                        if (!rigidbody)
                            rigidbody = container.gameObject.AddComponent<Rigidbody>();
                    }
                    else
                    {
                        container.GetComponent<SupplyDrop>().RemoveParachute();
                        rigidbody = container.GetComponent<Rigidbody>();
                    }

                    if (rigidbody)
                    {
                        rigidbody.isKinematic = false;
                        rigidbody.useGravity = true;
                        rigidbody.mass = 2f;
                        rigidbody.interpolation = RigidbodyInterpolation.Interpolate;
                        rigidbody.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;

                        rigidbody.velocity = Vector3.ClampMagnitude(lastMoveDir, 35) + (Random.onUnitSphere * Random.Range(1f, configData.Loot.LootSpread));
                        rigidbody.angularVelocity = Vector3Ex.Range(-1.75f, 1.75f);
                        rigidbody.drag = 0.5f * (rigidbody.mass / 5f);
                        rigidbody.angularDrag = 0.2f * (rigidbody.mass / 5f);                        
                    }

                    if (configData.Loot.FireLife > 0f)
                        FireballHandler.Create(container);
                    
                    InvokeHandler.Invoke(container, () => FillLootContainer(container, isDrop), 2f);

                    if (configData.Loot.LootDespawnTime > 0)
                    {
                        container.Invoke(() =>
                        {
                            if (!container || container.HasFlag(BaseEntity.Flags.Open))
                                return;

                            container.Kill();
                        }, configData.Loot.LootDespawnTime);
                    }

                    yield return CoroutineEx.waitForEndOfFrame;
                }
            }
            #endregion            

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

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

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

            private class DestructionTrigger : MonoBehaviour
            {
                private CrashPlane crashPlane;

                private BoxCollider collider;

                public void Setup(CrashPlane crashPlane)
                {
                    this.crashPlane = crashPlane;

                    gameObject.layer = (int)Layer.Reserved2;

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

                    collider = gameObject.AddComponent<BoxCollider>();
                    collider.isTrigger = true;
                    collider.size = new Vector3(60, 15, 55);
                    collider.center = Vector3.up * 10f;

                    Physics.IgnoreCollision(crashPlane.Collider, collider, true);
                }

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

                    BaseEntity baseEntity = col.gameObject.ToBaseEntity();

                    if (baseEntity is BasePlayer)
                    {
                        if ((baseEntity as BasePlayer).IsNpc)
                            return;

                        (baseEntity as BasePlayer).Die();
                        return;
                    }

                    if (configData.Plane.Destruction)
                    {
                        if (baseEntity is TreeEntity or ResourceEntity or BuildingBlock or SimpleBuildingBlock or PatrolHelicopter)
                        {
                            BaseCombatEntity baseCombatEntity = baseEntity as BaseCombatEntity;
                            if (baseCombatEntity)
                            {
                                baseCombatEntity.Die();
                                return;
                            }

                            if (baseEntity)
                            {
                                baseEntity.Kill(BaseNetworkable.DestroyMode.Gib);
                                return;
                            }
                        }
                    }
                }
            }

            private class FireballHandler
            {
                private readonly Vector3 offset;
                private readonly Transform parent;
                private FireBall fireBall;

                public FireballHandler(Vector3 offset, Transform parent)
                {
                    this.offset = offset;
                    this.parent = parent;

                    fireBall = Create(parent.TransformPoint(offset), 600f);
                }

                public void Update()
                {
                    if (fireBall)
                        fireBall.transform.position = parent.TransformPoint(offset);
                }

                public void Destroy()
                {
                    if (fireBall && !fireBall.IsDestroyed)
                    {
                        fireBall.Extinguish();
                        fireBall = null;
                    }
                }

                public static FireBall Create(Vector3 position, float lifetime)
                {
                    FireBall fireBall = GameManager.server.CreateEntity(FIREBALL_EFFECT, 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);
                    return fireBall;
                }

                public static FireBall Create(BaseEntity parent)
                {
                    FireBall fireBall = GameManager.server.CreateEntity(FIREBALL_EFFECT) as FireBall;
                    fireBall.SetParent(parent, false, false);
                    fireBall.transform.localPosition = Vector3.zero;

                    fireBall.lifeTimeMin = fireBall.lifeTimeMax = configData.Loot.FireLife;                   
                    fireBall.Spawn();

                    fireBall.GetComponent<Rigidbody>().isKinematic = true;
                    fireBall.GetComponent<Collider>().enabled = false;

                    parent.SetFlag(Flags.OnFire, true, false, true);
                    parent.SetFlag(Flags.Locked, true, false, true);

                    parent.Invoke(() =>
                    {
                        if (fireBall && !fireBall.IsDestroyed)
                            fireBall.Kill(DestroyMode.None);

                        if (parent && !parent.IsDestroyed)
                        {
                            parent.SetFlag(Flags.OnFire, false, false, true);
                            parent.SetFlag(Flags.Locked, false, false, true);
                        }
                    }, configData.Loot.FireLife);
                    
                    return fireBall;
                }
            }
        }

        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;                
            }
        }

        #region NPCs
        private static void SpawnNPCs(List<BaseEntity> lootContainers, BasePlayer lastAttacker)
        {            
            Vector3 position = Vector3.zero;

            int count = 0;
            lootContainers.ForEach((BaseEntity baseEntity) =>
            {
                if (baseEntity)
                {
                    position += baseEntity.transform.position;
                    count++;
                }
            });

            position /= count;

            Facepunch.Pool.FreeUnmanaged(ref lootContainers);

            ServerMgr.Instance.StartCoroutine(CreateNPCs(position, lastAttacker));
        }

        private static IEnumerator CreateNPCs(Vector3 position, BasePlayer lastAttacker)
        {            
            int amount = configData.NPCOptions.Amount + (configData.NPCOptions.CorpseEnabled ? configData.NPCOptions.CorpseAmount : 0);

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

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

                NPCSettings settings = configData.NPCOptions.CustomNPCSettings;
                settings.StartDead = spawnDead;

                ChaosNPC.SpawnNPC(Instance, newPosition, settings);

                yield return CoroutineEx.waitForSeconds(0.5f);
            }
        }                
        #endregion
        #endregion

        #region Functions
        private Vector3 GetRandomDropPosition()
        {
            Vector3 dropPosition;
            int attempts = 100;
            float mapSize = TerrainMeta.Size.x;
            do
            {
                dropPosition = Vector3Ex.Range(-(mapSize / 6f), mapSize / 6f);
            }
            while (Filter.GetFactor(dropPosition, true) == 0f && (attempts -= 1) > 0f);
            
            dropPosition.y = 0f;
            return dropPosition;
        }

        private void StartCrashTimer()
        {
            callTimer = timer.In(Random.Range(configData.EventTimers.Min, configData.EventTimers.Max) * 60, () =>
            {
                Vector3 position = GetRandomDropPosition();
                SpawnCrashPlane(position, configData.Loot.DropOnAutoSpawn);

                Debug.Log($"[PlaneCrash] - Auto-spawned plane with a drop target at {position}");

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

                StartCrashTimer();
            });
        }

        private CrashPlane SpawnCrashPlane(Vector3 dropPosition, bool dropCrate)
        {
            CargoPlane cargoPlane = (CargoPlane)GameManager.server.CreateEntity(CARGOPLANE_PREFAB, Vector3.zero, Quaternion.identity, true);

            CrashPlane crashPlane = cargoPlane.gameObject.AddComponent<CrashPlane>();

            crashPlane.prefabID = cargoPlane.prefabID;
            crashPlane.bounds = new Bounds(new Vector3(0f, 10f, 0f), new Vector3(60f, 15f, 55f));
            crashPlane.syncPosition = true;
            crashPlane.globalBroadcast = true;
            crashPlane.shouldDropCrate = dropCrate;

            crashPlane.SetFlightPath(dropPosition);

            UnityEngine.Object.DestroyImmediate(cargoPlane);

            crashPlane.Spawn();

            return crashPlane;
        }
        
        private CrashPlane SpawnCrashPlane(CargoPlane replaceCargoPlane)
        {
            CargoPlane cargoPlane = (CargoPlane)GameManager.server.CreateEntity(CARGOPLANE_PREFAB, replaceCargoPlane.transform.position, replaceCargoPlane.transform.rotation, true);

            CrashPlane crashPlane = cargoPlane.gameObject.AddComponent<CrashPlane>();

            crashPlane.prefabID = cargoPlane.prefabID;
            crashPlane.bounds = new Bounds(new Vector3(0f, 10f, 0f), new Vector3(60f, 15f, 55f));
            crashPlane.syncPosition = true;
            crashPlane.globalBroadcast = true;
            crashPlane.shouldDropCrate = true;

            crashPlane.SetFlightPath(replaceCargoPlane);

            UnityEngine.Object.DestroyImmediate(cargoPlane);
            replaceCargoPlane.Kill();

            crashPlane.Spawn();

            return crashPlane;
        }

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

        private static void FillLootContainer(BaseEntity entity, bool isDrop)
        {
            if (!entity)
                return;
            
            ItemContainer container = isDrop && entity is SupplyDrop ? (entity as SupplyDrop).inventory : entity is LootContainer ? (entity as LootContainer).inventory : null;

            if (configData.Loot.DespawnSafezone && IsInSafeZone(entity.transform.position))
            {
                container.Clear();
                entity.Kill();
                return;
            }

            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 = 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, 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 bool IsInSafeZone(Vector3 position)
        {
            int count = Physics.OverlapSphereNonAlloc(position, 1f, Vis.colBuffer, 1 << 18, QueryTriggerInteraction.Collide);
            for (int i = 0; i < count; i++)
            {
                Collider collider = Vis.colBuffer[i];
                if (collider.GetComponent<TriggerSafeZone>())
                    return true;
            }

            return false;
        }

        private static void StripInventory(BasePlayer player, bool skipWear = false)
        {
            List<Item> allItems = Pool.Get<List<Item>>();
            player.inventory.GetAllItems(allItems);

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

                item.RemoveFromContainer();
                item.Remove();
            }
            
            Pool.FreeUnmanaged(ref allItems);
        }        
               
        private bool IsCrashPlane(BaseEntity baseEntity) => baseEntity is CrashPlane;        

        private string FormatTime(double time)
        {
            TimeSpan dateDifference = TimeSpan.FromSeconds((float)time);
            int days = dateDifference.Days;
            int hours = dateDifference.Hours;
            hours += (days * 24);
            int mins = dateDifference.Minutes;
            int 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)
                    {
                        if (float.TryParse(arg.Args[0], out float x) && float.TryParse(arg.Args[1], out float 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)
                                {
                                    location = target.transform.position;
                                    SendReply(arg, $"Crash plane sent towards {target.displayName}'s current position");
                                }
                            }
                            else
                            {
                                SendReply(arg, "Could not locate the specified player");
                                return;
                            }
                        }
                    }
                    else
                    {
                        location = GetRandomDropPosition();
                        SendReply(arg, "Crash plane sent to random location");
                    }
                }
            }
            else
            {
                location = GetRandomDropPosition();
                SendReply(arg, "Crash plane sent to random location");
            }

            SpawnCrashPlane(location, false);
        }
               
        [ChatCommand("callcrash")]
        void cmdSendCrash(BasePlayer player, string command, string[] args)
        {
            int cooldown = -1;

            if (player.IsAdmin || permission.UserHasPermission(player.UserIDString, "planecrash.cancall"))
                cooldown = 0;
            else
            {
                foreach (KeyValuePair<string, int> kvp in configData.Cooldowns.OrderBy(x => x.Value))
                {
                    if (permission.UserHasPermission(player.UserIDString, kvp.Key))
                    {
                        cooldown = kvp.Value;
                        break;
                    }
                }
            }

            if (cooldown < 0)
                return;

            if (args.Length == 1 && args[0].ToLower() == "help")
            {
                SendReply(player, $"<color=#ce422b>{Title}</color>  <color=#939393>v</color><color=#ce422b>{Version}</color> <color=#939393>-</color> <color=#ce422b>k1lly0u</color><color=#939393> @</color> <color=#ce422b>chaoscode.io</color>");

                if (player.IsAdmin || permission.UserHasPermission(player.UserIDString, "planecrash.cancall"))
                {
                    SendReply(player, "<color=#ce422b>/callcrash</color><color=#939393> - Send a random crash plane</color>");
                    SendReply(player, "<color=#ce422b>/callcrash \"X\" \"Z\" 
// ... [Code preview truncated due to length. Full source in attached file] ...

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