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

FREE HeliControl : 1.4.0 1.4.0

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Oxide.Core;
using System;
using System.Collections.Generic;
using UnityEngine;
using Oxide.Core.Plugins;
using System.Text;
using Newtonsoft.Json;
using Oxide.Core.Libraries.Covalence;
using System.Linq;
namespace Oxide.Plugins {
    [Info("HeliControl", "Shady", "1.4.0", ResourceId = 1348)]
    [Description("Tweak various settings of helicopters.")]
    internal class HeliControl : RustPlugin {
        //Soli Deo gloria
#region Config/Init
        private const string heliPrefab = "assets/prefabs/npc/patrol helicopter/patrolhelicopter.prefab";
        private const string chinookPrefab = "assets/prefabs/npc/ch47/ch47scientists.entity.prefab";
        private StoredData lootData = new StoredData();
        private StoredData2 weaponsData = new StoredData2();
        private StoredData3 cooldownData = new StoredData3();
        private StoredData4 spawnsData = new StoredData4();
        private float boundary;
        private readonly HashSet<BaseHelicopter> BaseHelicopters = new HashSet<BaseHelicopter>();
        private readonly HashSet<CH47HelicopterAIController> Chinooks = new HashSet<CH47HelicopterAIController>();
        private readonly HashSet<HelicopterDebris> Gibs = new HashSet<HelicopterDebris>();
        private readonly HashSet<FireBall> FireBalls = new HashSet<FireBall>();
        private readonly HashSet<BaseHelicopter> forceCalled = new HashSet<BaseHelicopter>();
        private readonly HashSet<CH47HelicopterAIController> forceCalledCH = new HashSet<CH47HelicopterAIController>();
        private readonly HashSet<LockedByEntCrate> lockedCrates = new HashSet<LockedByEntCrate>();
        private readonly HashSet<HackableLockedCrate> hackLockedCrates = new HashSet<HackableLockedCrate>();
        private readonly Dictionary<BaseHelicopter, int> strafeCount = new Dictionary<BaseHelicopter, int>();
        private bool init;
        private static readonly System.Random rng = new System.Random();
        //used for loot crates
        private readonly int groundLayer = LayerMask.GetMask("Terrain", "World", "Default");
        private bool DisableHeli;
        private bool DisableDefaultHeliSpawns;
        private bool DisableDefaultChinookSpawns;
        private bool UseCustomLoot;
        private bool DisableGibs;
        private bool DisableNapalm;
        private bool AutoCallIfExists;
        private bool AutoCallIfExistsCH47;
        private bool DisableCratesDeath;
        private bool HelicopterCanShootWhileDying;
        private bool UseCustomHeliSpawns;
        private bool UseOldSpawning;
        private bool UseOldSpawningCH47;
        private float GlobalDamageMultiplier;
        private float HeliBulletDamageAmount;
        private float MainRotorHealth;
        private float TailRotorHealth;
        private float BaseHealth;
        private float HeliSpeed;
        private float HeliStartSpeed;
        private float HeliStartLength;
        private float HeliAccuracy;
        private float TimeBeforeUnlocking;
        private float TimeBeforeUnlockingHack;
        private float TurretFireRate;
        private float TurretburstLength;
        private float TurretTimeBetweenBursts;
        private float TurretMaxRange;
        private float GibsTooHotLength;
        private float GibsHealth;
        private float TimeBetweenRockets;
        private float MinSpawnTime;
        private float MinSpawnTimeCH47;
        private float MaxSpawnTime;
        private float MaxSpawnTimeCH47;
        private float RocketDamageBlunt;
        private float RocketDamageExplosion;
        private float RocketExplosionRadius;
        private int MaxLootCrates;
        private int MaxHeliRockets;
        private int BulletSpeed;
        private int LifeTimeMinutes;
        private int LifeTimeMinutesCH47;
        private int MaxActiveHelicopters;
        private int HelicoptersToSpawn;
        private int ChinooksToSpawn;
        private Dictionary<string, object> Cds => GetConfig("Cooldowns", new Dictionary<string, object>());
        private Dictionary<string, object> Limits => GetConfig("Limits", new Dictionary<string, object>());
        [PluginReference]
        private readonly Plugin Vanish;
        private float LastSpawnTimer;
        private float LastSpawnTimerCH47;
        private DateTime LastTimerStart;
        private DateTime LastTimerStartCH47;
        private Timer _callTimer;
        private Timer _callTimerCH47;
        private Timer CallTimer {
            get {
                return _callTimer;
            }
            set {
                if (_callTimer != null) _callTimer.Destroy();
                LastTimerStart = DateTime.UtcNow;
                LastSpawnTimer = value.Delay;
                _callTimer = value;
            }
        }
        private Timer CallTimerCH47 {
            get {
                return _callTimerCH47;
            }
            set {
                if (_callTimerCH47 != null) _callTimerCH47.Destroy();
                LastTimerStartCH47 = DateTime.UtcNow;
                LastSpawnTimerCH47 = value.Delay;
                _callTimerCH47 = value;
            }
        }
        private BaseHelicopter TimerHeli;
        private CH47HelicopterAIController TimerCH47;
        private bool UseNapalm {
            get;
            set;
        }
        = false;
        //not a config option!
        protected override void LoadDefaultConfig() {
            Config["Spawning - Disable Helicopter"] = DisableHeli = GetConfig("Spawning - Disable Helicopter", false);
            Config["Spawning - Disable Rust's default spawns"] = DisableDefaultHeliSpawns = GetConfig("Spawning - Disable Rust's default spawns", false);
            Config["Spawning - Disable CH47 default spawns"] = DisableDefaultChinookSpawns = GetConfig("Spawning - Disable CH47 default spawns", false);
            Config["Loot - Use Custom loot spawns"] = UseCustomLoot = GetConfig("Loot - Use Custom loot spawns", false);
            Config["Damage - Global damage multiplier"] = GlobalDamageMultiplier = GetConfig("Damage - Global damage multiplier", 1f);
            Config["Turrets - Helicopter bullet damage"] = HeliBulletDamageAmount = GetConfig("Turrets - Helicopter bullet damage", 20f);
            Config["Misc - Helicopter can shoot while dying"] = HelicopterCanShootWhileDying = GetConfig("Misc - Helicopter can shoot while dying", true);
            Config["Health - Main rotor health"] = MainRotorHealth = GetConfig("Health - Main rotor health", 750f);
            Config["Health - Tail rotor health"] = TailRotorHealth = GetConfig("Health - Tail rotor health", 375f);
            Config["Health - Base Helicopter health"] = BaseHealth = GetConfig("Health - Base Helicopter health", 10000f);
            Config["Loot - Max Crates to drop"] = MaxLootCrates = GetConfig("Loot - Max Crates to drop", 4);
            Config["Misc - Helicopter speed"] = HeliSpeed = GetConfig("Misc - Helicopter speed", 25f);
            Config["Turrets - Helicopter bullet accuracy"] = HeliAccuracy = GetConfig("Turrets - Helicopter bullet accuracy", 2f);
            Config["Rockets - Max helicopter rockets"] = MaxHeliRockets = GetConfig("Rockets - Max helicopter rockets", 12);
            Config["Spawning - Disable helicopter gibs"] = DisableGibs = GetConfig("Spawning - Disable helicopter gibs", false);
            Config["Spawning - Disable helicopter napalm"] = DisableNapalm = GetConfig("Spawning - Disable helicopter napalm", false);
            Config["Turrets - Helicopter bullet speed"] = BulletSpeed = GetConfig("Turrets - Helicopter bullet speed", 250);
            Config["Loot - Time before unlocking crates"] = TimeBeforeUnlocking = GetConfig("Loot - Time before unlocking crates", -1f);
            Config["Loot - Time before unlocking CH47 crates"] = TimeBeforeUnlockingHack = GetConfig("Loot - Time before unlocking CH47 crates", -1f);
            Config["Misc - Maximum helicopter life time in minutes"] = LifeTimeMinutes = GetConfig("Misc - Maximum helicopter life time in minutes", 15);
            Config["Misc - Maximum CH47 life time in minutes"] = LifeTimeMinutesCH47 = GetConfig("Misc - Maximum helicopter life time in minutes", 15);
            Config["Rockets - Time between each rocket in seconds"] = TimeBetweenRockets = GetConfig("Rockets - Time between each rocket in seconds", 0.2f);
            Config["Turrets - Turret fire rate in seconds"] = TurretFireRate = GetConfig("Turrets - Turret fire rate in seconds", 0.125f);
            Config["Turrets - Turret burst length in seconds"] = TurretburstLength = GetConfig("Turrets - Turret burst length in seconds", 3f);
            Config["Turrets - Time between turret bursts in seconds"] = TurretTimeBetweenBursts = GetConfig("Turrets - Time between turret bursts in seconds", 3f);
            Config["Turrets - Max range"] = TurretMaxRange = GetConfig("Turrets - Max range", 300f);
            Config["Rockets - Blunt damage to deal"] = RocketDamageBlunt = GetConfig("Rockets - Blunt damage to deal", 175f);
            Config["Rockets - Explosion damage to deal"] = RocketDamageExplosion = GetConfig("Rockets - Explosion damage to deal", 100f);
            Config["Rockets - Explosion radius"] = RocketExplosionRadius = GetConfig("Rockets - Explosion radius", 6f);
            Config["Gibs - Time until gibs can be harvested in seconds"] = GibsTooHotLength = GetConfig("Gibs - Time until gibs can be harvested in seconds", 480f);
            Config["Gibs - Health of gibs"] = GibsHealth = GetConfig("Gibs - Health of gibs", 500f);
            Config["Spawning - Automatically call helicopter between min seconds"] = MinSpawnTime = GetConfig("Spawning - Automatically call helicopter between min seconds", 0f);
            Config["Spawning - Automatically call helicopter between max seconds"] = MaxSpawnTime = GetConfig("Spawning - Automatically call helicopter between max seconds", 0f);
            Config["Spawning - Automatically call CH47 between min seconds"] = MinSpawnTimeCH47 = GetConfig("Spawning - Automatically call CH47 between min seconds", 0f);
            Config["Spawning - Automatically call CH47 between max seconds"] = MaxSpawnTimeCH47 = GetConfig("Spawning - Automatically call CH47 between max seconds", 0f);
            Config["Spawning - Use static spawning"] = UseOldSpawning = GetConfig("Spawning - Use static spawning", false);
            Config["Spawning - Use static spawning for CH47"] = UseOldSpawningCH47 = GetConfig("Spawning - Use static spawning for CH47", false);
            Config["Spawning - Automatically call helicopter if one is already flying"] = AutoCallIfExists = GetConfig("Spawning - Automatically call helicopter if one is already flying", false);
            Config["Spawning - Automatically call CH47 if one is already flying"] = AutoCallIfExistsCH47 = GetConfig("Spawning - Automatically call CH47 if one is already flying", false);
            Config["Spawning - Helicopters to spawn"] = HelicoptersToSpawn = GetConfig("Spawning - Helicopters to spawn", 1);
            Config["Spawning - Chinooks to spawn"] = ChinooksToSpawn = GetConfig("Spawning - Chinooks to spawn", 1);
            Config["Spawning - Use custom helicopter spawns"] = UseCustomHeliSpawns = GetConfig("Spawning - Use custom helicopter spawns", false);
            Config["Misc - Helicopter startup speed"] = HeliStartSpeed = GetConfig("Misc - Helicopter startup speed", 25f);
            Config["Misc - Helicopter startup length in seconds"] = HeliStartLength = GetConfig("Misc - Helicopter startup length in seconds", 0f);
            Config["Misc - Prevent crates from spawning when forcefully killing helicopter"] = DisableCratesDeath = GetConfig("Misc - Prevent crates from spawning when forcefully killing helicopter", true);
            Config["Spawning - Max active helicopters"] = MaxActiveHelicopters = GetConfig("Spawning - Max active helicopters", -1);
            for (int i = 0; i < 10; i++) {
                object outObj;
                var cd = "Cooldown." + i;
                var limit = "Limit." + i;
                var cdCh47 = "cooldown.ch47." + i;
                var limitCh47 = "limit.ch47." + i;
                if (!Cds.TryGetValue(cd, out outObj)) Cds[cd] = 86400f;
                if (!Limits.TryGetValue(limit, out outObj)) Limits[limit] = 5;
                if (!Cds.TryGetValue(cdCh47, out outObj)) Cds[cdCh47] = 86400f;
                if (!Limits.TryGetValue(limitCh47, out outObj)) Limits[limitCh47] = 5;
            }
            Config["Cooldowns"] = Cds;
            Config["Limits"] = Limits;
            SaveConfig();
        }
        private void Init() {
            cooldownData = Interface.Oxide?.DataFileSystem?.ReadObject<StoredData3>("HeliControlCooldowns") ?? new StoredData3();
            LoadDefaultConfig();
            Config["Cooldowns"] = Cds;
            // unsure if needed
            Config["Limits"] = Limits;
            SaveConfig();
            string[] perms = {
                "callheli", "callheliself", "callhelitarget", "callch47", "callch47self", "callch47target", "killch47", "killheli", "strafe", "update", "destination", "dropcrate", "killnapalm", "killgibs", "unlockcrates", "admin", "ignorecooldown", "ignorelimits", "tpheli", "tpch47", "helispawn", "callmultiple", "callmultiplech47", "dropcrates", "nextheli"
            }
            ;
            for (int j = 0; j < perms.Length; j++) permission.RegisterPermission("helicontrol." + perms[j], this);
            foreach (var limit in Limits.Keys) permission.RegisterPermission("helicontrol." + limit, this);
            foreach (var cd in Cds.Keys) permission.RegisterPermission("helicontrol." + cd, this);
            if (HelicopterCanShootWhileDying) {
                Unsubscribe(nameof(CanBeTargeted));
                Unsubscribe(nameof(OnHelicopterTarget));
                Unsubscribe(nameof(CanHelicopterStrafeTarget));
                Unsubscribe(nameof(CanHelicopterStrafe));
                Unsubscribe(nameof(CanHelicopterTarget));
            }
            if (!DisableNapalm) Unsubscribe(nameof(CanHelicopterUseNapalm));
            AddCovalenceCommand("unlockcrates", "cmdUnlockCrates");
            AddCovalenceCommand("tpheli", "cmdTeleportHeli");
            AddCovalenceCommand("killheli", "cmdKillHeli");
            AddCovalenceCommand("killch47", "cmdKillCH47");
            AddCovalenceCommand("dropcrate", "cmdDropCH47Crate");
            AddCovalenceCommand("updatehelis", "cmdUpdateHelicopters");
            AddCovalenceCommand("strafe", "cmdStrafeHeli");
            AddCovalenceCommand("helidest", "cmdDestChangeHeli");
            AddCovalenceCommand("killnapalm", "cmdKillFB");
            AddCovalenceCommand("killgibs", "cmdKillGibs");
            AddCovalenceCommand("nextheli", "cmdNextHeli");
            LoadDefaultMessages();
        }
        protected override void LoadDefaultMessages() {
            var messages = new Dictionary<string, string> {
                //DO NOT EDIT LANGUAGE FILES HERE! Navigate to oxide\lang
                {
                    "noPerms", "You do not have permission to use this command!"
                }
                , {
                    "invalidSyntax", "Invalid Syntax, usage example: {0} {1}"
                }
                , {
                    "invalidSyntaxMultiple", "Invalid Syntax, usage example: {0} {1} or {2} {3}"
                }
                , {
                    "heliCalled", "Helicopter Inbound!"
                }
                , {
                    "helisCalledPlayer", "{0} Helicopter(s) called on: {1}"
                }
                , {
                    "entityDestroyed", "{0} {1}(s) were annihilated!"
                }
                , {
                    "helisForceDestroyed", "{0} Helicopter(s) were forcefully destroyed!"
                }
                , {
                    "heliAutoDestroyed", "Helicopter auto-destroyed because config has it disabled!"
                }
                , {
                    "playerNotFound", "Could not find player: {0}"
                }
                , {
                    "noHelisFound", "No active helicopters were found!"
                }
                , {
                    "cannotBeCalled", "This can only be called on a single Helicopter, there are: {0} active."
                }
                , {
                    "strafingOtherPosition", "Helicopter is now strafing {0}'s position."
                }
                , {
                    "destinationOtherPosition", "Helicopter's destination has been set to {0}'s position."
                }
                , {
                    "IDnotFound", "Could not find player by ID: {0}"
                }
                , {
                    "updatedHelis", "{0} helicopters were updated successfully!"
                }
                , {
                    "callheliCooldown", "You must wait before using this again! You've waited: {0}/{1}"
                }
                , {
                    "invalidCoordinate", "Incorrect argument supplied for {0} coordinate!"
                }
                , {
                    "coordinatesOutOfBoundaries", "Coordinates are out of map boundaries!"
                }
                , {
                    "callheliLimit", "You've used your daily limit of {0} heli calls!"
                }
                , {
                    "unlockedAllCrates", "Unlocked all Helicopter crates!"
                }
                , {
                    "teleportedToHeli", "You've been teleported to the ground below the active Helicopter!"
                }
                , {
                    "removeAddSpawn", "To remove a Spawn, type: /helispawn remove SpawnName\n\nTo add a Spawn, type: /helispawn add SpawnName -- This will add the spawn on your current position."
                }
                , {
                    "addedSpawn", "Added helicopter spawn {0} with the position of: {1}"
                }
                , {
                    "spawnExists", "A spawn point with this name already exists!"
                }
                , {
                    "noSpawnsExist", "No Helicopter spawns have been created!"
                }
                , {
                    "removedSpawn", "Removed Helicopter spawn point: {0}: {1}"
                }
                , {
                    "noSpawnFound", "No spawn could be found with that name!"
                }
                , {
                    "onlyCallSelf", "You can only call a Helicopter on yourself, try: /callheli {0}"
                }
                , {
                    "spawnCommandLiner", "<color=orange>----</color>Spawns<color=orange>----</color>\n"
                }
                , {
                    "spawnCommandBottom", "\n<color=orange>----------------</color>"
                }
                , {
                    "cantCallTargetOrSelf", "You do not have the permission to call a Helicopter on a target! Try: /callheli"
                }
                , {
                    "maxHelis", "Killing helicopter because the maximum active helicopters has been reached"
                }
                , {
                    "cmdError", "An error happened while using this command.Please report this to your server administrator."
                }
                , {
                    "ch47AlreadyDropped", "This CH47 has already dropped a crate!"
                }
                , {
                    "ch47DroppedCrate", "Dropped crate!"
                }
                , {
                    "noTimeFound", "No spawn time found for helicopter."
                }
                , {
                    "noTimeFoundCH47", "No spawn time found for CH47."
                }
                , {
                    "nextHeliSpawn", "Next helicopter spawn: {0}"
                }
                , {
                    "nextCH47Spawn", "Next CH47 spawn: {0}"
                }
                , {
                    "nextAlreadyActive", "A helicopter is already active."
                }
                , {
                    "tooManyActiveHelis", "The maximum amount of Helicopters active has been reached.Please try again later."
                }
                , {
                    "itemNotFound", "Item not found!"
                }
                ,
            }
            ;
            lang.RegisterMessages(messages, this);
        }
        private string GetMessage(string key, string steamId = null) => lang.GetMessage(key, this, steamId);
        private void OnServerInitialized() {
            CheckHelicopter = new Action(() => {
                BaseHelicopters.RemoveWhere(p => (p?.IsDestroyed ?? true));
                Chinooks.RemoveWhere(p => (p?.IsDestroyed ?? true));
                Gibs.RemoveWhere(p => (p?.IsDestroyed ?? true));
                FireBalls.RemoveWhere(p => (p?.IsDestroyed ?? true));
                forceCalled.RemoveWhere(p => (p?.IsDestroyed ?? true));
                forceCalledCH.RemoveWhere(p => (p?.IsDestroyed ?? true));
                lockedCrates.RemoveWhere(p => (p?.IsDestroyed ?? true));
            }
            );
            if (ServerMgr.Instance != null) ServerMgr.Instance.InvokeRepeating(CheckHelicopter, 10f, 10f);
            //ServerMgr.Instance should never be null after server init, but we check anyway
            foreach(var entity in BaseNetworkable.serverEntities) {
                if (entity == null) continue;
                var heli = entity as BaseHelicopter;
                var ch47 = entity as CH47HelicopterAIController;
                var crate = entity as LockedByEntCrate;
                var hackCrate = entity as HackableLockedCrate;
                var debris = entity as HelicopterDebris;
                var fireball = entity as FireBall;
                if (heli != null) {
                    BaseHelicopters.Add(heli);
                    UpdateHeli(heli, false);
                }
                if (ch47 != null) Chinooks.Add(ch47);
                if (crate != null) lockedCrates.Add(crate);
                if (hackCrate != null) hackLockedCrates.Add(hackCrate);
                if (debris != null) Gibs.Add(debris);
                if (fireball != null && (fireball.ShortPrefabName.Contains("napalm") || fireball.ShortPrefabName.Contains("oilfire"))) FireBalls.Add(fireball);
            }
            if (DisableDefaultHeliSpawns || DisableDefaultChinookSpawns) {
                var eventPrefabs = UnityEngine.Object.FindObjectsOfType<TriggeredEventPrefab>();
                if (DisableDefaultHeliSpawns) {
                    for (int i = 0; i < eventPrefabs.Length; i++) {
                        var eve = eventPrefabs[i];
                        if ((eve?.targetPrefab?.resourcePath?.Contains("heli") ?? false)) {
                            UnityEngine.Object.Destroy(eve);
                            Puts("Disabled default Helicopter spawning.");
                            break;
                        }
                    }
                }
                if (DisableDefaultChinookSpawns) {
                    for (int i = 0; i < eventPrefabs.Length; i++) {
                        var eve = eventPrefabs[i];
                        if ((eve?.targetPrefab?.resourcePath?.Contains("ch47") ?? false)) {
                            UnityEngine.Object.Destroy(eve);
                            Puts("Disabled default Chinook spawning.");
                            break;
                        }
                    }
                }
            }
            ConVar.PatrolHelicopter.bulletAccuracy = HeliAccuracy;
            ConVar.PatrolHelicopter.lifetimeMinutes = LifeTimeMinutes;
            if (TimeBeforeUnlockingHack > 0f) HackableLockedCrate.requiredHackSeconds = TimeBeforeUnlockingHack;
            if (UseCustomLoot) LoadSavedData();
            LoadHeliSpawns();
            LoadWeaponData();
            boundary = TerrainMeta.Size.x / 2;
            foreach(var ch47 in Chinooks) {
                CH47Instance = ch47;
                //I feel like this is better than LINQ's FirstOrDefault for a hashset.maybe hashsets shouldn't have been used at all.who knows
                break;
            }
            var rngTime = GetRandomSpawnTime();
            var rngTimeCH47 = GetRandomSpawnTime(true);
            if (rngTime > 0f) {
                if (!UseOldSpawning) {
                    CallTimer = timer.Once(rngTime, () => {
                        if (HeliCount < 1 || AutoCallIfExists) {
                            var helis = callHelis(HelicoptersToSpawn, forced : false);
                            if (helis != null && helis.Count > 0) TimerHeli = helis[0];
                        }
                    }
                    );
                }
                else {
                    Timer newTimer = null;
                    newTimer = timer.Every(rngTime, () => {
                        if (HeliCount < 1 || AutoCallIfExists) callHelis(HelicoptersToSpawn, forced : false);
                        LastTimerStart = DateTime.UtcNow.AddSeconds(-newTimer.Delay);
                        LastSpawnTimer = newTimer.Delay * 2;
                        Puts("Next Helicopter spawn: " + (rngTime >= 60 ? ((rngTime / 60).ToString("N0") + " minutes") : rngTime.ToString("N0") + " seconds"));
                    }
                    );
                    CallTimer = newTimer;
                }
                Puts("Next Helicopter spawn: " + (rngTime >= 60 ? ((rngTime / 60).ToString("N0") + " minutes") : rngTime.ToString("N0") + " seconds"));
            }
            if (rngTimeCH47 > 0f) {
                if (!UseOldSpawningCH47) {
                    CallTimerCH47 = timer.Once(rngTimeCH47, () => {
                        if (CH47Count < 1 || AutoCallIfExistsCH47) {
                            var chinooks = callChinooks(ChinooksToSpawn, forced : false);
                            if (chinooks != null && chinooks.Count > 0) TimerCH47 = chinooks[0];
                        }
                    }
                    );
                }
                else {
                    Timer newTimer = null;
                    newTimer = timer.Every(rngTime, () => {
                        if (CH47Count < 1 || AutoCallIfExistsCH47) callChinooks(ChinooksToSpawn, forced : false);
                        LastTimerStart = DateTime.UtcNow.AddSeconds(-newTimer.Delay);
                        LastSpawnTimer = newTimer.Delay * 2;
                        Puts("Next CH47 spawn: " + (rngTimeCH47 >= 60 ? ((rngTimeCH47 / 60).ToString("N0") + " minutes") : rngTimeCH47.ToString("N0") + " seconds"));
                    }
                    );
                    CallTimerCH47 = newTimer;
                }
                Puts("Next CH47 spawn: " + (rngTimeCH47 >= 60 ? ((rngTimeCH47 / 60).ToString("N0") + " minutes") : rngTimeCH47.ToString("N0") + " seconds"));
            }
            init = true;
        }
#endregion
#region Hooks
        private void Unload() {
            if (ServerMgr.Instance != null) ServerMgr.Instance.CancelInvoke(CheckHelicopter);
            SaveData3();
            SaveData4();
        }
        private void OnServerSave() {
            var saveAction = new Action(() => {
                using (TimeWarning.New("HeliControl.OnServerSave", 140)) {
                    SaveData3();
                    SaveData4();
                }
                //retain the timewarning that would typically occur if it was slow to save on OnServerSave (or don't.apparently timewarnings were replaced with empty code in Rust)
            }
            );
            if (ServerMgr.Instance != null) ServerMgr.Instance.Invoke(saveAction, 4f);
            //ServerMgr.Instance should never be null on a server save, but we'll check anyway.We want to delay saving a few seconds because a lot of things are often called on OnServerSave
            else saveAction.Invoke();
        }
        private void OnEntitySpawned(BaseNetworkable entity) {
            if (!init || entity == null || entity.IsDestroyed || entity.gameObject == null) return;
            //entity should never be destroyed on spawn, but lets do a check anyway
            var prefabname = entity?.ShortPrefabName ?? string.Empty;
            var longprefabname = entity?.PrefabName ?? string.Empty;
            if (string.IsNullOrEmpty(prefabname) || string.IsNullOrEmpty(longprefabname)) return;
            //another likely impossibility, but lets just check EVERYTHING
            var ownerID = (entity as BaseEntity)?.OwnerID ?? 0;
            var lockedEntCrate = entity as LockedByEntCrate;
            if (lockedEntCrate != null) lockedCrates.Add(lockedEntCrate);
            var hackableCrate = entity as HackableLockedCrate;
            if (hackableCrate != null) hackLockedCrates.Add(hackableCrate);
            var ch = entity as CH47HelicopterAIController;
            if (ch != null) {
                ch.Invoke(() => {
                    if (!ch.IsDestroyed) ch.Kill();
                }
                , (LifeTimeMinutesCH47 * 60));
                Chinooks.Add(ch);
                CH47Instance = ch;
            }
            var fireBall = entity as FireBall;
            if (fireBall != null && (entity.ShortPrefabName.Contains("napalm") || entity.ShortPrefabName.Contains("oil"))) FireBalls.Add(fireBall);
            if (prefabname.Contains("rocket_heli")) {
                var explosion = entity as TimedExplosive;
                if (explosion == null || explosion.IsDestroyed || explosion.gameObject == null) return;
                //super ultra extra safe null checking
                if (prefabname != "rocket_heli_napalm") UseNapalm = false;
                else {
                    if (explosion.OwnerID != 1337) UseNapalm = true;
                }
                if (MaxHeliRockets < 1) explosion.Kill();
                else {
                    explosion.explosionRadius = RocketExplosionRadius;
                    if (MaxHeliRockets > 12 && ownerID == 0) {
                        BaseHelicopter strafeHeli = null;
                        foreach (var heli in BaseHelicopters) {
                            if (heli == null || heli.IsDestroyed || heli.gameObject == null || heli.IsDead()) continue;
                            //super ultra extra safe null checking
                            var state = heli?.GetComponent<PatrolHelicopterAI>()?._currentState ?? PatrolHelicopterAI.aiState.IDLE;
                            if (state == PatrolHelicopterAI.aiState.STRAFE) {
                                strafeHeli = heli;
                                break;
                            }
                        }
                        if (strafeHeli == null || strafeHeli.IsDestroyed || strafeHeli.gameObject == null || strafeHeli.IsDead()) return;
                        //super ultra extra safe null checking
                        var curCount = 0;
                        if (!strafeCount.TryGetValue(strafeHeli, out curCount)) curCount = (strafeCount[strafeHeli] = 1);
                        else curCount = (strafeCount[strafeHeli] += 1);
                        if (curCount >= 12) {
                            var heliAI = strafeHeli?.GetComponent<PatrolHelicopterAI>() ?? null;
                            if (heliAI == null || heliAI.gameObject == null) return;
                            //extra null checking
                            var actCount = 0;
                            Action fireAct = null;
                            fireAct = new Action(() => {
                                if (heliAI == null || heliAI.gameObject == null || actCount >= (MaxHeliRockets - 12)) {
                                    InvokeHandler.CancelInvoke(heliAI, fireAct);
                                    return;
                                }
                                actCount++;
                                FireRocket(heliAI);
                            }
                            );
                            InvokeHandler.InvokeRepeating(heliAI, fireAct, TimeBetweenRockets, TimeBetweenRockets);
                            strafeCount[strafeHeli] = 0;
                        }
                    }
                    else if (MaxHeliRockets < 12 && (HeliInstance != null && HeliInstance.gameObject != null && HeliInstance.ClipRocketsLeft() > MaxHeliRockets)) {
                        explosion.Kill();
                        return;
                    }
                    var dmgTypes = explosion?.damageTypes ?? null;
                    if (dmgTypes != null && dmgTypes.Count > 0) {
                        for (int i = 0; i < dmgTypes.Count; i++) {
                            var dmg = dmgTypes[i];
                            if (dmg == null) continue;
                            //impossible? who knows.but we're gonna null check it anyway cause that's what you do
                            if (dmg.type == Rust.DamageType.Blunt) dmg.amount = RocketDamageBlunt;
                            if (dmg.type == Rust.DamageType.Explosion) dmg.amount = RocketDamageExplosion;
                        }
                    }
                }
            }
            if (prefabname == "heli_crate") {
                if (UseCustomLoot && lootData?.HeliInventoryLists != null && lootData.HeliInventoryLists.Count > 0) {
                    var heli_crate = entity as LootContainer;
                    if (heli_crate == null || heli_crate?.inventory == null) return;
                    //possible that the inventory is somehow null? not sure
                    int index;
                    index = rng.Next(lootData.HeliInventoryLists.Count);
                    var inv = lootData.HeliInventoryLists[index];
                    if (inv?.lootBoxContents != null && inv.lootBoxContents.Count > 0) {
                        if (heli_crate?.inventory?.itemList != null && heli_crate.inventory.itemList.Count > 0) {
                            var itemList = new List<Item>(heli_crate.inventory.itemList);
                            if (itemList != null && itemList.Count > 0) for (int i = 0; i < itemList.Count; i++) RemoveFromWorld(itemList[i]);
                            //completely remove all existing items in crate
                        }
                        for (int i = 0; i < inv.lootBoxContents.Count; i++) {
                            var itemDef = inv.lootBoxContents[i];
                            if (itemDef == null) continue;
                            var amount = (itemDef.amountMin > 0 && itemDef.amountMax > 0) ? UnityEngine.Random.Range(itemDef.amountMin, itemDef.amountMax) : itemDef.amount;
                            var skinID = 0ul;
                            ulong.TryParse(itemDef.skinID.ToString(), out skinID);
                            var def = ItemManager.FindItemDefinition(itemDef.name);
                            if (def != null) {
                                var item = ItemManager.Create(def, amount, skinID);
                                if (item != null && !item.MoveToContainer(heli_crate.inventory)) RemoveFromWorld(item);
                                //ensure the item is completely removed if we can't move it, so we're not causing issues
                            }
                        }
                        heli_crate.inventory.MarkDirty();
                    }
                }
                if (TimeBeforeUnlocking >= 0f) {
                    var crate2 = entity as LockedByEntCrate;
                    if (crate2 != null) {
                        if (TimeBeforeUnlocking == 0f) UnlockCrate(crate2);
                        else crate2.Invoke(() => {
                            if (entity == null || entity.IsDestroyed || crate2 == null) return;
                            UnlockCrate(crate2);
                        }
                        , TimeBeforeUnlocking);
                    }
                }
            }
            var debris = entity as HelicopterDebris;
            if (debris != null) {
                if (DisableGibs || GibsHealth <= 0) {
                    NextTick(() => {
                        if (!(entity?.IsDestroyed ?? true)) entity.Kill();
                    }
                    );
                    return;
                }
                if (GibsHealth != 500f) {
                    debris.InitializeHealth(GibsHealth, GibsHealth);
                    debris.SendNetworkUpdate();
                }
                Gibs.Add(debris);
                if (GibsTooHotLength != 480f) debris.tooHotUntil = Time.realtimeSinceStartup + GibsTooHotLength;
            }
            var BaseHeli = entity as BaseHelicopter;
            if (BaseHeli != null) {
                var isMax = (HeliCount >= MaxActiveHelicopters && MaxActiveHelicopters != -1);
                if (DisableHeli || isMax) {
                    NextTick(() => {
                        if (!(entity?.IsDestroyed ?? true)) entity.Kill();
                    }
                    );
                }
                if (DisableHeli) {
                    Puts(GetMessage("heliAutoDestroyed"));
                    return;
                }
                else if (isMax) {
                    Puts(GetMessage("maxHelis"));
                    return;
                }
                var AIHeli = entity?.GetComponent<PatrolHelicopterAI>() ?? null;
                if (AIHeli == null) return;
                BaseHelicopters.Add(BaseHeli);
                UpdateHeli(BaseHeli, true);
                if (UseCustomHeliSpawns && spawnsData?.HelicopterSpawns != null && spawnsData.HelicopterSpawns.Count > 0 && !forceCalled.Contains(BaseHeli)) {
                    var valCount = spawnsData.HelicopterSpawns.Count;
                    var rng = UnityEngine.Random.Range(0, valCount);
                    var pos = spawnsData.HelicopterSpawns[rng].Position;
                    BaseHeli.transform.position = pos;
                    AIHeli.transform.position = pos;
                }
                if (HeliStartLength > 0.0f && HeliStartSpeed != HeliSpeed) {
                    AIHeli.maxSpeed = HeliStartSpeed;
                    AIHeli.Invoke(() => {
                        if (AIHeli == null || AIHeli.gameObject == null || BaseHeli == null || BaseHeli.IsDestroyed || BaseHeli.gameObject == null || BaseHeli.IsDead()) return;
                        AIHeli.maxSpeed = HeliSpeed;
                    }
                    , HeliStartLength);
                }
            }
        }
        private object CanBeTargeted(BaseCombatEntity entity, MonoBehaviour monoTurret) {
            if (!init || entity == null || (entity?.IsDestroyed ?? true) || monoTurret == null) return null;
            var aiHeli = (monoTurret as HelicopterTurret)?._heliAI ?? null;
            if (aiHeli == null) return null;
            var player = entity as BasePlayer;
            if (player != null && Vanish != null && (Vanish?.Call<bool>("IsInvisible", player) ?? false)) return null;
            if ((aiHeli?._currentState ?? PatrolHelicopterAI.aiState.DEATH) == PatrolHelicopterAI.aiState.DEATH) return false;
            return null;
        }
        private object OnHelicopterTarget(HelicopterTurret turret, BaseCombatEntity entity) {
            if (turret == null || entity == null) return null;
            if ((turret?._heliAI?._currentState ?? PatrolHelicopterAI.aiState.DEATH) == PatrolHelicopterAI.aiState.DEATH) return false;
            return null;
        }
        private object CanHelicopterStrafeTarget(PatrolHelicopterAI entity, BasePlayer target) {
            if (entity == null || target == null) return null;
            if ((entity?._currentState ?? PatrolHelicopterAI.aiState.DEATH) == PatrolHelicopterAI.aiState.DEATH) return false;
            return null;
        }
        private object CanHelicopterStrafe(PatrolHelicopterAI entity) {
            if (entity == null) return null;
            if ((entity?._currentState ?? PatrolHelicopterAI.aiState.DEATH) == PatrolHelicopterAI.aiState.DEATH) return false;
            return null;
        }
        private object CanHelicopterTarget(PatrolHelicopterAI entity, BasePlayer player) {
            if (entity == null) return null;
            if ((entity?._currentState ?? PatrolHelicopterAI.aiState.DEATH) == PatrolHelicopterAI.aiState.DEATH) return false;
            return null;
        }
        private object CanHelicopterUseNapalm(PatrolHelicopterAI entity)  //this hook is unsubscribed if the config option isn't enabled!
        {
            if (entity == null) return null;
            return false;
        }
        private void OnEntityKill(BaseNetworkable entity) {
            if (entity == null || entity.gameObject == null) return;
            var name = entity?.ShortPrefabName ?? string.Empty;
            var crate = entity as LockedByEntCrate;
            var CH47 = entity as CH47HelicopterAIController;
            var baseHeli = entity as BaseHelicopter;
            if (crate != null) lockedCrates.Remove(crate);
            if (baseHeli != null) {
                if (BaseHelicopters.Contains(baseHeli)) BaseHelicopters.Remove(baseHeli);
                if (forceCalled.Contains(baseHeli)) forceCalled.Remove(baseHeli);
                if (!UseOldSpawning && (CallTimer == null || CallTimer.Destroyed) && baseHeli == TimerHeli) {
                    var rngTime = GetRandomSpawnTime();
                    CallTimer = timer.Once(rngTime, () => {
                        if (HeliCount < 1 || AutoCallIfExists) {
                            var helis = callHelis(HelicoptersToSpawn, forced : false);
                            if (helis != null && helis.Count > 0) TimerHeli = helis[0];
                        }
                    }
                    );
                    LastTimerStart = DateTime.UtcNow;
                    LastSpawnTimer = rngTime;
                    Puts("Next Helicopter spawn: " + (rngTime >= 60 ? ((rngTime / 60).ToString("N0") + " minutes") : rngTime.ToString("N0") + " seconds"));
                }
                //otherwise, a timer is already firing (or heli is not a timer heli or old spawning is enabled)
            }
            if (CH47 != null) {
                if (Chinooks.Contains(CH47)) Chinooks.Remove(CH47);
                if (forceCalledCH.Contains(CH47)) forceCalledCH.Remove(CH47);
                if (!UseOldSpawningCH47 && (CallTimerCH47 == null || CallTimerCH47.Destroyed) && CH47 == TimerCH47) {
                    var rngTime = GetRandomSpawnTime(true);
                    CallTimerCH47 = timer.Once(rngTime, () => {
                        if (CH47Count < 1 || AutoCallIfExistsCH47) {
                            var chinooks = callChinooks(ChinooksToSpawn, forced : false);
                            if (chinooks != null && chinooks.Count > 0) TimerCH47 = chinooks[0];
                        }
                    }
                    );
                    LastTimerStartCH47 = DateTime.UtcNow;
                    LastSpawnTimerCH47 = rngTime;
                    Puts("Next CH47 spawn: " + (rngTime >= 60 ? ((rngTime / 60).ToString("N0") + " minutes") : rngTime.ToString("N0") + " seconds"));
                }
                //otherwise, a timer is already firing (or heli is not a timer heli or old spawning is enabled)
            }
            if (name.Contains("fireball") || name.Contains("napalm")) {
                var fireball = entity as FireBall;
                if (fireball != null && FireBalls.Contains(fireball)) FireBalls.Remove(fireball);
            }
            var debris = entity as HelicopterDebris;
            if (debris != null) Gibs.Remove(debris);
        }
        private void OnPlayerAttack(BasePlayer attacker, HitInfo hitInfo) {
            if (attacker == null || hitInfo?.HitEntity == null) return;
            if (hitInfo?.HitEntity is BaseHelicopter) {
                if (GlobalDamageMultiplier != 1f && GlobalDamageMultiplier >= 0) {
                    hitInfo?.damageTypes?.ScaleAll(GlobalDamageMultiplier);
                    return;
                }
                var shortName = hitInfo?.Weapon?.GetItem()?.info?.shortname ?? string.Empty;
                var displayName = hitInfo?.Weapon?.GetItem()?.info?.displayName?.english ?? string.Empty;
                float weaponConfig;
                if (weaponsData.WeaponList.TryGetValue(shortName, out weaponConfig) || weaponsData.WeaponList.TryGetValue(displayName, out weaponConfig)) {
                    if (weaponConfig != 0.0f && weaponConfig != 1.0f) hitInfo?.damageTypes?.ScaleAll(weaponConfig);
                }
            }
        }
#endregion
#region Main
        private void UpdateHeli(BaseHelicopter heli, bool justCreated = false) {
            if (heli == null || heli.IsDestroyed || heli.IsDead()) return;
            heli.startHealth = BaseHealth;
            if (justCreated) heli.InitializeHealth(BaseHealth, BaseHealth);
            heli.maxCratesToSpawn = MaxLootCrates;
            heli.bulletDamage = HeliBulletDamageAmount;
            heli.bulletSpeed = BulletSpeed;
            var weakspots = heli.weakspots;
            if (weakspots != null && weakspots.Length > 1)  //not even sure if this is needed, but may fix some very strange NRE
            {
                if (justCreated) {
                    weakspots[0].health = MainRotorHealth;
                    weakspots[1].health = TailRotorHealth;
                }
                weakspots[0].maxHealth = MainRotorHealth;
                weakspots[1].maxHealth = TailRotorHealth;
            }
            var heliAI = heli?.GetComponent<PatrolHelicopterAI>() ?? null;
            if (heliAI == null) return;
            heliAI.maxSpeed = Mathf.Clamp(HeliSpeed, 0.1f, 125);
            heliAI.timeBetweenRockets = Mathf.Clamp(TimeBetweenRockets, 0.1f, 1f);
            heliAI.numRocketsLeft = Mathf.Clamp(MaxHeliRockets, 0, 48);
            UpdateTurrets(heliAI);
            heli.SendNetworkUpdateImmediate(justCreated);
        }
        //nearly exact code used by Rust to fire helicopter rockets
        private void FireRocket(PatrolHelicopterAI heliAI) {
            if (heliAI == null || !(heliAI?.IsAlive() ?? false)) return;
            var num1 = 4f;
            var strafeTarget = heliAI.strafe_target_position;
            if (strafeTarget == Vector3.zero) return;
            var vector3 = heliAI.transform.position + heliAI.transform.forward * 1f;
            var direction = (strafeTarget - vector3).normalized;
            if (num1 > 0.0) direction = Quaternion.Euler(UnityEngine.Random.Range((float)(-num1 * 0.5), num1 * 0.5f), UnityEngine.Random.Range((float)(-num1 * 0.5), num1 * 0.5f), UnityEngine.Random.Range((float)(-num1 * 0.5), num1 * 0.5f)) * direction;
            var flag = heliAI.leftTubeFiredLast;
            heliAI.leftTubeFiredLast = !flag;
            Effect.server.Run(heliAI.helicopterBase.rocket_fire_effect.resourcePath, heliAI.helicopterBase, StringPool.Get("rocket_tube_" + (!flag ? "right" : "left")), Vector3.zero, Vector3.forward, null, true);
         
// ... [Code preview truncated due to length. Full source in attached file] ...

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