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

FREE HeliSignals : 1.2.6 1.2.6

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

1.2.6
 - Fixed: Error where the calling player cannot damage the heli unless in a clan
 
1.2.5
 - Fixed: Memory leak leading to poor performance/stuttering in certain cases (Thanks Death for the help)
 - Updated: Code cleanup and edits for better performance
 - Added: Option to award XP via SkillTree instead of XPerience
 - Added: Option to award XP including players XP boosts

1.2.4
 - Fixed: Hook conflict with NpcSpawn
 - Fixed: OnEntityTakeDamage NullReferenceException error
 - Fixed: Occasional bug where killed heli regains HP and is then invincible

1.2.3
 - Fixed: Compatibility with Carbon (Helis now fire rockets on Carbon servers)
 - Fixed: Heli not firing rockets in some circumstances
 - Fixed: NRE console error message
 - Fixed: Heli flying away and not returning when it should
 - Fixed: Heli signals not enabled for buying showing up in the buy list
 
1.2.2
 - Fixed: Wave signals not being purchasable via buy command
 - Added: Separate skin IDs in the config for default wave signals (prevents item name stacking bug)

1.2.1
 - Added: Config option to always block damage to a list of specified entities
 - Added: Config option to give XP as a reward (requires XPerience plugin)
 - Added: Config option to specify number of helis spawned with a signal - default 1 (new skins available on plugin page)
 - Added: Config option to reward with a custom item (shortname, skin, name)
 - Added: Config option to also give damage report if helicopter retires
 - Added: Config option for new Heli Wave Signal (Calls helis in waves, one after the other)
 - Added: Config option to display damage report for vanilla patrol helicopter
 - Added: Config option for display and owner for vanilla patrol helicopter for damage report

1.1.12
 - Fixed: HackableLockedCrate loot BP amounts not calculating correctly
 - Fixed: Occasional OnEntityTakeDamage error
 - Fixed: Occasional CanHackCrate error
 - Added: Config option to prevent players calling in monuments

1.1.11
 - Fixed: For 7th Sep 2023 Rust update
 - Fixed: Hackable crates not giving correct loot in some cases when enabled in the config
 - Fixed: Players being able to kill retiring heli and only getting vanilla loot

1.1.10
 - Fixed: Hook conflict on CanCombineDroppedItem returning false instead of true
 - Fixed: Added missing config option to allow compatibility with Dynamic PVP plugin
 - Updated: Changed some code to be more performant

1.1.9
 - Fixed: OnEntityKill NRE when one or more heli kill team members are offline
 - Fixed: Bug where rewards were not received in cases where team members offline
 - Fixed: Bug where no rewards earned if players take heli with auto turret
 - Fixed: AlphaLoot not being able to populate hackable crates
 - Added: Custom chat icon config option

1.1.8
 - Fixed: Final fix for language defaulting to English (hopefully)

1.1.7
 - Fixed: Language defaulting always to English, users who use their own lang files should now be able to
 - Fixed: Better compatibility with NextGenPVE/TruePVE (Any plugins using CanEntityTakeDamage hook)
 - Fixed: Compatibility with Dynamic PVP now works properly
 - Fixed: BotReSpawn vanilla heli profile triggering as well as bot profile set in HeliSignals config
 - Added: BP chance & max BPs to loot table config
 - Added: Config option to announce to player/team only or global chat
 - Added: Config option to force return heli to original called position instead of calling player
 - Added: Check to allow players with admin perm to override crate and gibs protection

1.1.6:
 - Fixed: Unlootable crate bug, re-introduced in error by last update

1.1.5
 - Fixed: "KeyNotFoundException" error when clear cooldown command used
 - Fixed: Bug which prevented players looting own boxes after crate lock expired
 - Fixed: Bug which prevented harvesting gibs when unlock gibs timer expired
 - Fixed: Retire command retiring other peoples helis in some cases in error

1.1.4
 - Fixed: Typo in OnHelicopterRetire hook causing "ArgumentNullException" error

1.1.3
 - Fixed: report command not using custom command if edited in the config
 - Fixed: Vanilla helicopter event not despawning correctly
 - Added: Clear cooldown admin command (hsclearcd) requires admin perm
 - Added: Separate cooldowns for each Heli tier/profile
 - Added: Config option to enable per tier cooldown or not
 - Added: Player heli limit config option

1.1.2
 - Fixed: Bug where players were prevented from looting crates from other Bradley or Heli in certain cases

1.1.1
 - Fixed: Bullet accuracy option not working
 - Fixed: Return to called position height not using the config value correctly
 - Fixed: Bug where in certain cases players would get kill rewards after heli retired
 - Fixed: NRE when players shoot helis with remote Auto Turrets
 - Added: Config option to allow/disallow damage to helis by remote Auto Turret
 - Added: Report command is now usable by players for their owned helis (admin perm allows all helis)
 - Added: Config option to specify custom report command (default = hsreport)
 - Updated: Re-write of some methods for improvements in damage handling and code efficiency
 - Info: Code cleanup

1.0.26
 - Added example items to loot tables

1.0.25
 - Fixed: Hackable locked crate not despawning at time specified in config
 - Fixed: Custom loot not populating after 1.0.22 update (sorry)
 - Fixed: Occasional NullReferenceException error on CanStackItem
 - Added: Hackable locked crate loot table options

*/
namespace Oxide.Plugins {
    [Info("Heli Signals", "ZEODE", "1.2.6")]
    [Description("Call Patrol Helicopters to your location with custom supply signals.")]
    public class HeliSignals : RustPlugin {
#region Plugin References
        [PluginReference]
        Plugin Friends, Clans, FancyDrop, RewardPlugin, Vanish, NoEscape, BotReSpawn, DynamicPVP, XPerience, SkillTree, NpcSpawn;
#endregion Plugin References
#region Constants
        private static HeliSignals Instance;
        private static System.Random random = new System.Random();
        private const string permAdmin = "helisignals.admin";
        private const string permBuy = "helisignals.buy";
        private const string permBypasscooldown = "helisignals.bypasscooldown";
        private const string heliPrefab = "assets/prefabs/npc/patrol helicopter/patrolhelicopter.prefab";
        private const string heliExplosion = "assets/prefabs/npc/patrol helicopter/effects/heli_explosion.prefab";
        private const string hackableCrate = "assets/prefabs/deployable/chinooklockedcrate/codelockedhackablecrate.prefab";
        private const string shockSound = "assets/prefabs/locks/keypad/effects/lock.code.shock.prefab";
        private const string deniedSound = "assets/prefabs/locks/keypad/effects/lock.code.denied.prefab";
        private const string defaultWebhookUrl = "https://support.discordapp.com/hc/en-us/articles/228383668-Intro-to-Webhooks";
        private const int supplySignalId = 1397052267;
        private const int scrapId = -932201673;
        // Default config item skins
        // Single
        private const ulong easySkinID = 2920175997;
        private const ulong medSkinID = 2920176079;
        private const ulong hardSkinID = 2920176050;
        private const ulong eliteSkinID = 2920176024;
        private const ulong expertSkinID = 3099117081;
        private const ulong nightmareSkinID = 3099117372;
        // Multi
        private const ulong easyMultiSkinID = 3083234542;
        private const ulong medMultiSkinID = 3083234833;
        private const ulong hardMultiSkinID = 3083234755;
        private const ulong eliteMultiSkinID = 3083234647;
        private const ulong elxpertMultiSkinID = 3099124338;
        private const ulong nightmareMultiSkinID = 3099124426;
        // Wave
        private const ulong normalWaveSkinID = 3104667036;
        private const ulong hardWaveSkinID = 3104666951;
        // Default config item names
        // Single
        private const string easyHeli = "Heli Signal (Easy)";
        private const string medHeli = "Heli Signal (Medium)";
        private const string hardHeli = "Heli Signal (Hard)";
        private const string eliteHeli = "Heli Signal (Elite)";
        // Multi
        private const string easyMulti = "Multi Heli (Easy)";
        private const string medMulti = "Multi Heli (Medium)";
        private const string hardMulti = "Multi Heli (Hard)";
        private const string eliteMulti = "Multi Heli (Elite)";
        // Wave
        private const string normalWave = "Heli Wave Signal (Normal)";
        private const string hardWave = "Heli Wave Signal (Hard)";
#endregion Constants
#region Language
        protected override void LoadDefaultMessages() {
            lang.RegisterMessages(new Dictionary<string, string> {
                ["SyntaxPlayer"]
                = "<color=red>Invalid syntax</color>, use:\n\n<color=green>/hsgive <type> <SteamID/PlayerName> <amount></color>", ["SyntaxConsole"] = "Invalid syntax, use: hsgive <type> <SteamID/PlayerName> <amount>", ["ClearSyntaxPlayer"] = "<color=red>Invalid syntax</color>, use:\n\n<color=green>/hsclearcd</color> (clears all cooldowns)\n\nOr\n\n<color=green>/hsclearcd <SteamID/PlayerName></color>", ["ClearSyntaxConsole"] = "Invalid syntax, use: \"hsclearcd\" (clears all cooldowns) or \"hsclearcd <SteamID/PlayerName>\"", ["Receive"] = "You received <color=orange>{0}</color> x <color=orange>{1}</color>!", ["PlayerReceive"] = "Player {0} ({1}) received {2} x {3}!", ["Permission"] = "You do not have permission to use <color=orange>{0}</color>!", ["RaidBlocked"] = "You cannot use <color=orange>{0}</color> while raid blocked!", ["CombatBlocked"] = "You cannot use <color=orange>{0}</color> while combat blocked!", ["CooldownTime"] = "Cooldown active! You can call another in {0}!", ["TeamCooldownTime"] = "Team cooldown active! You can call another in {0}!", ["GlobalLimit"] = "Global limit of {0} active helicopters is reached, please try again later", ["PlayerLimit"] = "Player limit of {0} active helicopters is reached, please try again later", ["NotAdmin"] = "You do not have permission to use that command!", ["PlayerNotFound"] = "Can't find a player with the name or ID: {0}", ["InGameOnly"] = "Error: This command is only for use in game!", ["PlayerDead"] = "Player with name or ID {0} is dead, try again when they have respawned", ["InMonument"] = "You cannot call <color=orange>{0}</color> in a <color=red>monument</color>, signal refunded, check inventory.", ["InSafeZone"] = "<color=orange>{0}</color> was thrown in a <color=green>Safe Zone</color> and was refunded, check inventory.", ["InvalidDrop"] = "Signal type \"{0}\" not recognised, please check and try again!", ["CannotLoot"] = "You cannot loot this because it is not yours!", ["CannotHack"] = "You cannot hack this because it is not yours!", ["CannotHarvest"] = "You cannot harvest this because it is not yours!", ["BuyCmdSyntax"] = "Buy Command Usage (prefix / for chat):\n\n{0}{1}", ["NoBuy"] = "Buy Command for <color=orange>{0}</color> Is Not Enabled!", ["BuyPermission"] = "You do not have permission to buy Heli Signal \"<color=orange>{0}</color>\".", ["PriceList"] = "Heli Signal Prices:\n\n{0}", ["HeliKilledTime"] = "<color=orange>{0}</color> killed by <color=green>{1}</color> in grid <color=green>{2}</color> (Time Taken: {3})", ["HeliCalled"] = "<color=green>{0}</color> just called in <color=orange>{1}</color> to their location in grid <color=green>{2}</color>", ["PointsGiven"] = "<color=green>{0} {1}</color> received for destroying <color=orange>{2}</color>!", ["XPGiven"] = "<color=green>{0} XP</color> received for destroying <color=orange>{1}</color>!", ["ScrapGiven"] = "<color=green>{0} Scrap</color> received for destroying <color=orange>{1}</color>!", ["CustomGiven"] = "<color=green>{0} {1}</color> received for destroying <color=orange>{2}</color>!", ["CannotDamage"] = "You <color=red>Cannot</color> damage this <color=orange>{0}</color>!", ["NoTurret"] = "You <color=red>Cannot</color> damage this <color=orange>{0}</color> with remote turrets!", ["TooFarAway"] = "You are <color=red>Too Far</color> away to engage this <color=orange>{0}</color> ({1} m)", ["CantAfford"] = "You <color=red>Cannot</color> afford this! Cost: <color=orange>{0}</color> Required: <color=orange>{1}</color>", ["FullInventory"] = "<color=green>{0}</color> <color=red>NOT</color> purchased - no inventory space.You have not been charged.", ["PlayerFull"] = "<color=green>{0}</color> <color=red>NOT</color> given to {1} - No inventory space.", ["HeliReportTitle"] = "There are currently <color=orange>{0}</color> active Helicopters", ["HeliReportItem"] = "<size=9><color=orange>{0}/{1}</color> - <color=green>{2}</color> (Owner: <color=orange>{3}</color> Grid: <color=orange>{4}</color> Health: <color=orange>{5}</color> Rotors: <color=orange>{6}/{7}</color> State: <color=orange>{8}</color>)\n</size>", ["HeliReportTitleCon"] = "There are currently {0} active Helicopters", ["HeliReportItemCon"] = "{0}/{1} - {2} (Owner: {3} Grid: {4} Health: {5} Rotors: {6}/{7} State: {8})\n", ["HeliReportList"] = "{0}", ["RetireHeli"] = "<color=orange>{0}</color> is retiring, you were warned! <color=red>{1}</color>/<color=red>{2}</color>", ["RetireWarn"] = "<color=red>Damage Blocked!</color> You may only attack from a base with TC auth.If you continue, the <color=orange>{0}</color> will retire.Warning Level: <color=red>{1}</color>/<color=red>{2}</color>", ["DmgReport"] = "<color=orange>Damage Report</color> / <color=orange>Rotor Accuracy</color>\n\n{0}\n{1}", ["DmgReportOwner"] = "<size=11>Type: <color=orange>{0}</color> Owner: <color=green>{1}</color> Status: <color=red>{2}</color>\n</size>", ["DmgReportIndex"] = "<size=11>{0}.<color=green>{1}</color> -> {2} HP / {3}%\n</size>", ["DiscordCall"] = "**{0}** just called a **{1}** to their location in grid **{2}**", ["DiscordKill"] = "**{0}** just took down a **{1}** in grid **{2}**", ["DiscordRetire"] = "**{0}** called by **{1}** just retired from grid **{2}**", ["RetiredHelis"] = "You have retired ALL your (your teams) called Patrol Helicopters", ["CooldownsCleared"] = "All player cooldowns have been cleared!", ["PlayerCooldownCleared"] = "Cooldown cleared for player {0} ({1})", ["PlayerNoCooldown"] = "No active cooldown for player {0} ({1})", ["NoWaveProfiles"] = "There are no wave heli profiles set up for <color=orange>{0}</color>, please report to an Admin.", ["WaveProfileError"] = "There is an error in the plugin config <color=orange>{0}</color>, please report to an Admin.", ["NextHeliCalled"] = "<color=green>{0}</color> destroyed! Stand by, a <color=red>{1}</color> is now on route to your location!", ["WaveFinished"] = "<color=green>{0}</color> destroyed! <color=red>Hostile forces have no more airbourne assets to send to your location.</color> Well Done!", ["WaveRetired"] = "<color=green>{0}</color> finished operations in the area and is retiring.Hostile airbourne forces are returning to base."
            }
            , this);
        }
        private string Lang(string messageKey, string playerId, params object[] args) {
            return string.Format(lang.GetMessage(messageKey, this, playerId), args);
        }
        private void Message(IPlayer player, string messageKey, params object[] args) {
            if (player == null || !player.IsConnected) return;
            var message = Lang(messageKey, player.Id, args);
            if (config.options.usePrefix && config.options.chatPrefix != string.Empty) {
                if (player.IsServer) {
                    Regex regex = new Regex(@"(\[.*?\])");
                    Match match = regex.Match(config.options.chatPrefix);
                    player.Reply($"{match}: {message}");
                }
                else {
                    player.Reply($"{config.options.chatPrefix}: {message}");
                }
            }
            else {
                player.Reply(message);
            }
        }
        private void Message(BasePlayer player, string messageKey, params object[] args) {
            if (player == null || player is NPCPlayer || !player.IPlayer.IsConnected) return;
            var message = Lang(messageKey, player.UserIDString, args);
            Player.Message(player, message, config.options.usePrefix ? config.options.chatPrefix : null, config.options.chatIcon);
        }
#endregion Language
#region Oxide Hooks
        private void OnServerInitialized() {
            Instance = this;
            CheckRewardPlugins();
            if (!config.options.useStacking) {
                Unsubscribe(nameof(CanStackItem));
                Unsubscribe(nameof(CanCombineDroppedItem));
            }
            if (config.options.noVanillaHeli) Puts($"INFO: Vanilla patrol Helicopter server event is disabled");
        }
        private void Init() {
            permission.RegisterPermission(permAdmin, this);
            permission.RegisterPermission(permBuy, this);
            permission.RegisterPermission(permBypasscooldown, this);
            config.rewards.RegisterPermissions(permission, this);
            config.heli.RegisterPermissions(permission, this);
            foreach (var key in config.heli.heliConfig.Keys) {
                var permSuffix = config.heli.heliConfig[key].GiveItemCommand.ToLower();
                var perm = $"{Name.ToLower()}.{permSuffix}";
                permission.RegisterPermission(perm, this);
                HeliProfiles.Add(config.heli.heliConfig[key].GiveItemCommand);
                HeliSkins.Add(config.heli.heliConfig[key].SignalSkinID);
            }
            foreach (var key in config.heli.waveConfig.Keys) {
                var permSuffix = config.heli.waveConfig[key].GiveItemCommand.ToLower();
                var perm = $"{Name.ToLower()}.{permSuffix}";
                permission.RegisterPermission(perm, this);
                WaveProfiles.Add(config.heli.waveConfig[key].GiveItemCommand);
                HeliSkins.Add(config.heli.waveConfig[key].SkinId);
                if (config.heli.waveConfig[key].WaveProfiles.Count == 0) {
                    // If loading fresh, populate default wav profiles without multi profiles
                    foreach (var profile in config.heli.heliConfig.Keys) {
                        if (!profile.Contains("Multi")) config.heli.waveConfig[key].WaveProfiles.Add(profile);
                    }
                    SaveConfig();
                }
            }
            AddCovalenceCommand(config.options.reportCommand, nameof(CmdReport));
            AddCovalenceCommand(config.purchasing.buyCommand, nameof(CmdBuySignal));
            AddCovalenceCommand(config.heli.retireCommand, nameof(CmdRetireHeli));
            AddCovalenceCommand("hsgive", nameof(CmdGiveSignal));
            AddCovalenceCommand("hsclearcd", nameof(CmdClearCooldown));
        }
        private void Unload() {
            foreach (var netId in HeliSignalData.Keys) {
                var heli = BaseNetworkable.serverEntities.Find(new NetworkableId(netId)) as PatrolHelicopter;
                if (heli != null) heli.Kill();
            }
            if (config.options.noVanillaHeli) Puts($"INFO: Vanilla patrol Helicopter server event has been re-enabled");
            HeliSignalData.Clear();
            PlayerCooldowns.Clear();
            TierCooldowns.Clear();
            LockedCrates.Clear();
            HeliProfiles.Clear();
            WaveProfiles.Clear();
            HeliSkins.Clear();
            RewardPlugin = null;
            Instance = null;
        }
        private object OnEventTrigger(TriggeredEventPrefab eventPrefab) {
            if (eventPrefab.name.Contains("event_helicopter") && config.options.noVanillaHeli) return true;
            return null;
        }
        // Re-Adds supply signal names to items added via kits/loadouts by plugins
        // which don't specify a custom item display name.private void OnItemAddedToContainer(ItemContainer container, Item item)
        {
            if (item.info.itemid == supplySignalId) if (HeliSkins.Contains(item.skin)) NextTick(()=> FixSignalInfo(item));
        }
        private void OnExplosiveThrown(BasePlayer player, SupplySignal entity, ThrownWeapon item) {
            var signal = item.GetItem();
            if (signal == null) return;
            if (HeliSkins.Contains(signal.skin)) {
                entity.EntityToCreate = null;
                entity.CancelInvoke(entity.Explode);
                entity.skinID = signal.skin;
                NextTick(()=> HeliSignalThrown(player, entity, signal));
            }
        }
        private void OnExplosiveDropped(BasePlayer player, SupplySignal entity, ThrownWeapon item) => OnExplosiveThrown(player, entity, item);
        private object CanStackItem(Item item, Item targetItem) {
            if (item == null || targetItem == null) return null;
            if (item.info.itemid == targetItem.info.itemid && item.skin != targetItem.skin) return false;
            return null;
        }
        private object CanCombineDroppedItem(DroppedItem item, DroppedItem targetItem) {
            if (item == null || targetItem == null) return null;
            if (item.item.info.itemid == targetItem.item.info.itemid && item.item.skin != targetItem.item.skin) return true;
            return null;
        }
        private void OnEntitySpawned(BaseNetworkable entity) {
            if (entity.ShortPrefabName.Contains("rocket_heli")) {
                NextTick(()=> {
                    if (HeliSignalData.Count == 0 || entity == null) return;
                    var heliList = Facepunch.Pool.GetList<PatrolHelicopter>();
                    var rocketEnt = entity as BaseEntity;
                    Vis.Entities(rocketEnt.transform.position, 10f, heliList);
                    var ent = heliList[0];
                    if (ent.IsDestroyed) {
                        Facepunch.Pool.FreeList(ref heliList);
                        return;
                    }
                    PatrolHelicopter heli = ent as PatrolHelicopter;
                    var heliProfile = heli?._name;
                    if (heliProfile == null) {
                        Facepunch.Pool.FreeList(ref heliList);
                        return;
                    }
                    if (!config.heli.heliConfig.ContainsKey(heliProfile)) {
                        Facepunch.Pool.FreeList(ref heliList);
                        return;
                    }
                    rocketEnt.creatorEntity = heli;
                    rocketEnt.OwnerID = heli.OwnerID;
                    SetDamageScale((rocketEnt as TimedExplosive), config.heli.heliConfig[heliProfile].RocketDamageScale);
                    Facepunch.Pool.FreeList(ref heliList);
                }
                );
            }
            else if (entity.ShortPrefabName.Equals("napalm")) {
                // Set the owner ID & name of fire/napalm from heli rockets to stop NRE which occurs in
                // OnEntityTakeDamage from leftover napalm fire after heli is destroyed.NextTick(()=>
                {
                    BaseEntity baseEnt = entity as BaseEntity;
                    if (baseEnt.creatorEntity != null) {
                        baseEnt.OwnerID = baseEnt.creatorEntity.OwnerID;
                        baseEnt._name = baseEnt.creatorEntity._name;
                    }
                }
                );
            }
        }
        private object OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info) {
            var Initiator = info?.Initiator;
            if (Initiator == null) return null;
            var ownerId = entity.OwnerID;
            if (Initiator is PatrolHelicopter) {
                PatrolHelicopter heli = Initiator as PatrolHelicopter;
                if (heli == null) return null;
                if (!HeliSignalData.ContainsKey(heli.net.ID.Value)) return null;
                string heliProfile = heli?._name;
                if (heliProfile == null) return null;
                var heliOwnerId = heli.OwnerID;
                if (heliOwnerId == null) return null;
                if (config.heli.heliConfig.ContainsKey(heliProfile)) {
                    if (entity is BasePlayer) {
                        BasePlayer player = entity as BasePlayer;
                        if (player == null) return null;
                        if (config.heli.heliConfig[heliProfile].BlockPlayerDamage && !IsOwnerOrFriend(heliOwnerId, player.userID)) {
                            info.damageTypes.ScaleAll(0);
                            return true;
                        }
                        else if (info.damageTypes.GetMajorityDamageType() == DamageType.Bullet) {
                            float hitProb = (float)random.Next(1, 100);
                            if (config.heli.heliConfig[heliProfile].BulletAccuracy < hitProb) {
                                info.damageTypes.ScaleAll(0);
                                return true;
                            }
                        }
                    }
                    else if (ownerId.IsSteamId()) {
                        if (config.heli.heliConfig[heliProfile].BlockProtectedList && config.heli.protectedPrefabs.Contains(entity.name)) {
                            info.damageTypes.ScaleAll(0);
                            return true;
                        }
                        else if (config.heli.heliConfig[heliProfile].BlockOtherDamage && !IsOwnerOrFriend(heliOwnerId, ownerId)) {
                            info.damageTypes.ScaleAll(0);
                            return true;
                        }
                        else if (config.heli.heliConfig[heliProfile].BlockOwnerDamage && IsOwnerOrFriend(heliOwnerId, ownerId)) {
                            info.damageTypes.ScaleAll(0);
                            return true;
                        }
                    }
                }
            }
            else if (Initiator.ShortPrefabName.Equals("napalm")) {
                string heliProfile = Initiator?._name;
                if (heliProfile == null) return null;
                if (!config.heli.heliConfig.ContainsKey(heliProfile)) return null;
                var heliOwner = Initiator.OwnerID;
                if (heliOwner == null) return null;
                if (entity is BasePlayer) {
                    BasePlayer player = entity as BasePlayer;
                    if (player == null) return null;
                    if (config.heli.heliConfig[heliProfile].BlockPlayerDamage && !IsOwnerOrFriend(heliOwner, player.userID)) {
                        info.damageTypes.ScaleAll(0);
                        return true;
                    }
                }
                else if (ownerId.IsSteamId()) {
                    if (config.heli.heliConfig[heliProfile].BlockProtectedList && config.heli.protectedPrefabs.Contains(entity.name)) {
                        info.damageTypes.ScaleAll(0);
                        return true;
                    }
                    else if (config.heli.heliConfig[heliProfile].BlockOtherDamage && !IsOwnerOrFriend(heliOwner, ownerId)) {
                        info.damageTypes.ScaleAll(0);
                        return true;
                    }
                    else if (config.heli.heliConfig[heliProfile].BlockOwnerDamage && IsOwnerOrFriend(heliOwner, ownerId)) {
                        info.damageTypes.ScaleAll(0);
                        return true;
                    }
                }
            }
            return null;
        }
        private object OnEntityTakeDamage(PatrolHelicopter heli, HitInfo info) {
            var Initiator = info?.Initiator;
            if (heli == null || Initiator == null) return null;
            var heliProfile = heli._name;
            bool isVanilla = false;
            if (heliProfile == null && heli.skinID == 0) isVanilla = true;
            else if (heliProfile == null && heli.skinID != 0) return null;
            else if (heliProfile != null && !config.heli.heliConfig.ContainsKey(heliProfile)) return null;
            var heliAI = heli.myAI;
            var heliId = heli.net.ID.Value;
            var ownerId = heli.OwnerID;
            ulong attackerId = 0;
            BasePlayer attacker = Initiator as BasePlayer;
            if (Initiator is BasePlayer) {
                attackerId = attacker.userID;
            }
            else if (Initiator is AutoTurret) {
                AutoTurret turret = Initiator as AutoTurret;
                if (turret == null) return null;
                ulong turretPlayerId = turret.ControllingViewerId.GetValueOrDefault().SteamId;
                if (turretPlayerId == null) return null;
                attacker = BasePlayer.FindByID(turretPlayerId);
                if (attacker == null) return null;
                attackerId = attacker.userID;
            }
            else {
                return null;
            }
            if (attacker == null || attackerId == null) return null;
            if (isVanilla && (heliAI.isRetiring || heliAI.isDead)) return null;
            HeliComponent heliComp = heli.GetComponent<HeliComponent>();
            if (!isVanilla && heliComp == null) return null;
            if (!HeliSignalData.ContainsKey(heliId)) {
                HeliSignalData.Add(heliId, new HeliStats());
                HeliSignalData[heliId].OwnerID = ownerId;
                HeliSignalData[heliId].OwnerName = isVanilla ? config.announce.vanillaOwner : heliComp.owner.displayName;
            }
            if (!isVanilla) {
                var heliDisplayName = config.heli.heliConfig[heliProfile].HeliName;
                if (config.heli.heliConfig.ContainsKey(heliProfile)) {
                    if (heliComp.isRetiring || heliComp.isDying) {
                        info.damageTypes.ScaleAll(0);
                        return true;
                    }
                    if ((Initiator is AutoTurret) && !config.heli.allowTurretDamage) {
                        info.damageTypes.ScaleAll(0);
                        ComputerStation station = attacker.GetMounted() as ComputerStation;
                        if (station != null) {
                            timer.Once(0.25f, ()=> Effect.server.Run(shockSound, station.transform.position));
                            timer.Once(0.5f, ()=> Effect.server.Run(deniedSound, station.transform.position));
                        }
                        attacker.EnsureDismounted();
                        Message(attacker, "NoTurret", heliDisplayName);
                        return true;
                    }
                }
                if (config.heli.heliConfig[heliProfile].OwnerDamage && !IsOwnerOrFriend(attackerId, ownerId)) {
                    info.damageTypes.ScaleAll(0);
                    Message(attacker, "CannotDamage", heliDisplayName);
                    return true;
                }
                var dist = Vector3.Distance(heli.transform.position, attacker.transform.position);
                var maxDist = config.heli.maxHitDistance;
                if (maxDist > 0 && dist > maxDist) {
                    info.damageTypes.ScaleAll(0);
                    Message(attacker, "TooFarAway", heliDisplayName, maxDist);
                    return true;
                }
                if (config.heli.RetireWarning && attacker.IsBuildingBlocked() && IsOwnerOrFriend(attackerId, ownerId)) {
                    HeliSignalData[heliId].WarningLevel++;
                    if (!heliComp.isRetiring && HeliSignalData[heliId].WarningLevel >= config.heli.WarningThreshold) {
                        heliComp.isRetiring = true;
                        info.damageTypes.ScaleAll(0);
                        RetireHeli(heliAI, heliId);
                        Message(attacker, "RetireHeli", heliDisplayName, HeliSignalData[heliId].WarningLevel, config.heli.WarningThreshold);
                        return true;
                    }
                    info.damageTypes.ScaleAll(0);
                    Message(attacker, "RetireWarn", heliDisplayName, HeliSignalData[heliId].WarningLevel, config.heli.WarningThreshold);
                    return true;
                }
            }
            if (HeliSignalData[heliId].FirstHitTime == 0) HeliSignalData[heliId].FirstHitTime = UnityEngine.Time.realtimeSinceStartup;
            if (!HeliSignalData[heliId].Attackers.ContainsKey(attackerId)) {
                HeliSignalData[heliId].Attackers.Add(attackerId, new AttackersStats());
                HeliSignalData[heliId].Attackers[attackerId].Name = attacker.displayName;
            }
            HeliSignalData[heliId].LastAttacker = attacker;
            HeliSignalData[heliId].Attackers[attackerId].DamageDealt += info.damageTypes.Total();
            HeliSignalData[heliId].Attackers[attackerId].TotalHits++;
            if (info.HitMaterial == 2306822461) HeliSignalData[heliId].Attackers[attackerId].RotorHits++;
            if (!isVanilla) {
                if (heliAI._currentState == PatrolHelicopterAI.aiState.DEATH && !heliComp.isDying) {
                    // Give rewards as soon as heli enters death state, otherwise if
                    // players die before it crashes they might not get rewards
                    heliComp.isDying = true;
                    NextTick(()=> ProcessRewards(heliId, ownerId, heliProfile));
                    timer.Once(11f, ()=> {
                        if (heli != null) heli.Hurt(heli.health * 2f, DamageType.Generic, null, false);
                    }
                    );
                }
            }
            return null;
        }
        private object OnEntityKill(PatrolHelicopter heli) {
            if (!HeliSignalData.ContainsKey(heli.net.ID.Value) || heli.myAI.isRetiring) return null;
            var skinId = heli.skinID;
            var heliProfile = heli._name;
            bool isVanilla = false;
            if (heliProfile == null && skinId == 0) isVanilla = true;
            else if (heliProfile == null && skinId != 0) return null;
            var position = heli.transform.position;
            var ownerId = heli.OwnerID;
            var heliId = heli.net.ID.Value;
            var heliDisplayName = isVanilla ? config.announce.vanillaName : config.heli.heliConfig[heliProfile].HeliName;
            var gridPos = PositionToGrid(position);
            if (gridPos == null) gridPos = "Unknown";
            BasePlayer lastAttacker = HeliSignalData[heliId].LastAttacker;
            if (lastAttacker == null) return null;
            if (config.announce.killChat) {
                if (!isVanilla || (isVanilla && config.announce.killVanilla)) {
                    TimeSpan timeSpan = TimeSpan.FromSeconds(UnityEngine.Time.realtimeSinceStartup - HeliSignalData[heliId].FirstHitTime);
                    string time = timeSpan.ToString(@"hh\:mm\:ss");
                    var message = string.Format(lang.GetMessage("HeliKilledTime", this, lastAttacker.UserIDString), heliDisplayName, lastAttacker.displayName, gridPos, time);
                    AnnounceToChat(lastAttacker, message);
                }
            }
            if (config.announce.reportChat) {
                if (!isVanilla || (isVanilla && config.announce.reportVanilla)) {
                    var heliOwnerName = config.announce.vanillaOwner;
                    var heliComp = heli.GetComponent<HeliComponent>();
                    if (heliComp != null) heliOwnerName = heliComp.owner.displayName;
                    string topReport = string.Empty;
                    string ownerReport = string.Format(lang.GetMessage("DmgReportOwner", this, lastAttacker.UserIDString), heliDisplayName, heliOwnerName, "Killed");
                    int count = 1;
                    foreach (var key in HeliSignalData[heliId].Attackers.Keys.OrderByDescending(x => HeliSignalData[heliId].Attackers[x].DamageDealt)) {
                        if (count >= config.announce.maxReported) break;
                        string playerName = HeliSignalData[heliId].Attackers[key].Name;
                        float damageDealt = HeliSignalData[heliId].Attackers[key].DamageDealt;
                        int totalHits = HeliSignalData[heliId].Attackers[key].TotalHits;
                        int rotorHits = HeliSignalData[heliId].Attackers[key].RotorHits;
                        double rotorAccuracy = ((double)rotorHits / (double)totalHits) * 100;
                        topReport += string.Format(lang.GetMessage("DmgReportIndex", this, lastAttacker.UserIDString), count, playerName, Math.Round(damageDealt, 2), Math.Round(rotorAccuracy, 2));
                        count++;
                    }
                    var dmgReport = string.Format(lang.GetMessage("DmgReport", this, lastAttacker.UserIDString), ownerReport, topReport);
                    AnnounceToChat(lastAttacker, dmgReport);
                }
            }
            if (!isVanilla) {
                if (config.discord.sendHeliKill) SendToDiscord(string.Format(lang.GetMessage("DiscordKill", this, lastAttacker.UserIDString), lastAttacker.displayName, heliProfile, gridPos));
                if (config.heli.heliConfig[heliProfile].LockedCratesToSpawn > 0) SpawnLockedCrates(ownerId, skinId, heliProfile, position);
                NextTick(() => {
                    var ents = Facepunch.Pool.GetList<BaseEntity>();
                    Vis.Entities(position, 15f, ents);
                    foreach (var ent in ents) {
                        if ((ent is ServerGib) || (ent is LockedByEntCrate) || (ent is FireBall)) {
                            ent.OwnerID = ownerId;
                            ent.skinID = skinId;
                            ent._name = heliProfile;
                            if ((ent is ServerGib) || (ent is LockedByEntCrate)) {
                                // COMMENT: Adding box collider & changing rb values to help stop
                                // gibs & crates falling through map on occasion
                                BoxCollider box = ent.gameObject.AddComponent<BoxCollider>();
                                if (box != null) box.size = new Vector3(0.6f, 0.6f, 0.6f);
                                Rigidbody rigidbody = ent.gameObject.GetComponent<Rigidbody>();
                                if (rigidbody) {
                                    rigidbody.drag = 0.5f;
                                    rigidbody.angularDrag = 0.5f;
                                    rigidbody.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
                                }
                            }
                            ProcessHeliEnt(ent);
                        }
                    }
                    Facepunch.Pool.FreeList(ref ents);
                }
                );
                if (BotReSpawn && BotReSpawn.IsLoaded) {
                    var botReSpawnProfile = config.heli.heliConfig[heliProfile].BotReSpawnProfile;
                    if (botReSpawnProfile != string.Empty) BotReSpawn?.Call("AddGroupSpawn", position, botReSpawnProfile, $"{botReSpawnProfile}Group", 0);
                }
            }
            timer.Once(60f, () => {
                if (HeliSignalData.ContainsKey(heliId)) HeliSignalData.Remove(heliId);
            }
            );
            return null;
        }
        private object CanHelicopterStrafeTarget(PatrolHelicopterAI heliAI, BasePlayer player) {
            PatrolHelicopter heli = heliAI?.helicopterBase;
            string heliProfile = heli._name;
            if (heliProfile == null) return null;
            if (!config.heli.heliConfig.ContainsKey(heliProfile)) return null;
            if (!config.heli.heliConfig[heliProfile].TargetOtherPlayers && !IsOwnerOrFriend(player.userID, heli.OwnerID)) {
                heliAI.ExitCurrentState();
                for (int i = 0; i < heliAI._targetList.Count; i++) {
                    if (heliAI._targetList[i].ply == player) {
                        heliAI._targetList.Remove(heliAI._targetList[i]);
                        continue;
                    }
                }
                return false;
            }
            return null;
        }
        private object CanHelicopterUseNapalm(PatrolHelicopterAI heliAI) {
            HeliComponent heliComp = heliAI?.helicopterBase.GetComponent<HeliComponent>();
            if (heliComp != null) {
                var heliProfile = heliAI?.helicopterBase._name;
                if (heliProfile == null) return null;
                if (heliComp.isRetiring) return false;
                return (Oxide.Core.Random.Range(0f, 1f) <= config.heli.heliConfig[heliProfile].NapalmChance);
            }
            return true;
        }
        private object CanHelicopterStrafe(PatrolHelicopterAI heliAI) {
            HeliComponent heliComp = heliAI?.helicopterBase.GetComponent<HeliComponent>();
            if (heliComp != null) {
                if (heliComp.isRetiring) return false;
            }
            return null;
        }
        private object OnHelicopterTarget(HelicopterTurret turret, BasePlayer player) {
            PatrolHelicopter heli = turret._heliAI?.helicopterBase;
            PatrolHelicopterAI heliAI = turret?._heliAI;
            if (heli == null || heliAI == null) return null;
            string heliProfile = heli._name;
            if (heliProfile == null) return null;
            if (config.heli.heliConfig.ContainsKey(heliProfile)) return CanCustomHeliTarget(heliAI, player, heliProfile);
            return null;
        }
        private object CanHelicopterTarget(PatrolHelicopterAI heliAI, BasePlayer player) {
            string heliProfile = heliAI?.helicopterBase._name;
            if (heliProfile == null) return null;
            if (config.heli.heliConfig.ContainsKey(heliProfile)) return CanCustomHeliTarget(heliAI, player, heliProfile);
            return null;
        }
        private object CanCustomHeliTarget(PatrolHelicopterAI heliAI, BasePlayer player, string heliProfile) {
            if (heliAI == null || player == null || heliProfile == null) return null;
            if (Vanish && (bool)Vanish?.Call("IsInvisible", player)) return null;
            PatrolHelicopter heli = heliAI?.helicopterBase;
            if (heli == null) return null;
            if (config.heli.heliConfig.ContainsKey(heliProfile)) {
                if (!config.heli.heliConfig[heliProfile].TargetOtherPlayers && !IsOwnerOrFriend(player.userID, heli.OwnerID)) {
                    HeliComponent heliComp = heli.GetComponent<HeliComponent>();
                    if (heliComp != null) {
                        heliAI.interestZoneOrigin = heliComp.calledPosition;
                        heliAI.hasInterestZone = true;
                    }
                    return false;
                }
            }
            if (config.heli.maxHitDistance > 0 && (Vector3.Distance(heli.transform.position, player.transform.position) > config.heli.maxHitDistance)) return false;
            return null;
        }
        private object OnHelicopterRetire(PatrolHelicopterAI heliAI) {
            PatrolHelicopter heli = heliAI?.helicopterBase;
            string heliProfile = heli?._name;
            if (heliProfile == null) return null;
            if (config.heli.heliConfig.ContainsKey(heliProfile) && heliAI.IsAlive()) {
                HeliComponent heliComp = heli.GetComponent<HeliComponent>();
                if (heliComp == null) return null;
                heliComp.isRetiring = true;
                heliAI.leftGun.maxTargetRange = 0f;
                heliAI.rightGun.maxTargetRange = 0f;
                if (heliComp.isWaveHeli) {
                    Message(heliComp.owner, "WaveRetired", heliProfile);
                }
                if (config.announce.reportChat && config.announce.reportRetire) {
                    var heliId = heli.net.ID.Value;
                    BasePlayer lastAttacker = HeliSignalData[heliId].LastAttacker;
                    if (lastAttacker != null) {
                        string topReport = string.Empty;
                        string ownerReport = string.Format(lang.GetMessage("DmgReportOwner", this, lastAttacker.UserIDString), config.heli.heliConfig[heliProfile].HeliName, heliComp.owner.displayName, "Retired");
                        int count = 1;
                        foreach (var key in HeliSignalData[heliId].Attackers.Keys.OrderByDescending(x => HeliSignalData[heliId].Attackers[x].DamageDealt)) {
                            if (count >= config.announce.maxReported) break;
                            string playerName = HeliSignalData[heliId].Attackers[key].Name;
                            float damageDealt = HeliSignalData[heliId].Attackers[key].DamageDealt;
                            int totalHits = HeliSignalData[heliId].Attackers[key].TotalHits;
                            int rotorHits = HeliSignalData[heliId].Attackers[key].RotorHits;
                            double rotorAccuracy = ((double)rotorHits / (double)totalHits) * 100;
                            topReport += string.Format(lang.GetMessage("DmgReportIndex", this, lastAttacker.UserIDString), count, playerName, Math.Round(damageDealt, 2), Math.Round(rotorAccuracy, 2));
                            count++;
                        }
                        var dmgReport = string.Format(lang.GetMessage("DmgReport", this, lastAttacker.UserIDString), ownerReport, topReport);
                        AnnounceToChat(lastAttacker, dmgReport);
                    }
                }
                if (config.discord.sendHeliRetire) {
                    var gridPos = PositionToGrid(heli.transform.position);
                    if (gridPos == null) gridPos = "Unknown";
                    BasePlayer player = FindPlayer(heli.OwnerID.ToString())?.Object as BasePlayer;
                    if (player == null) return null;
                    string discordMsg = string.Format(lang.GetMessage("DiscordRetire", this, player.UserIDString), heli._name, player.displayName, gridPos);
                    SendToDiscord(discordMsg);
                }
                timer.Once(60f, ()=> {
                    if (HeliSignalData.ContainsKey(heli.net.ID.Value)) HeliSignalData.Remove(heli.net.ID.Value);
                }
                );
            }
            return null;
        }
        private object CanLootEntity(BasePlayer player, LockedByEntCrate entity) {
            if (entity.OwnerID == 0) return null;
            string heliProfile = entity?._name;
            if (heliProfile == null) return null;
            if (config.heli.heliConfig.ContainsKey(heliProfile)) {
                if (config.heli.heliConfig[heliProfile].ProtectCrates) {
                    if (permission.UserHasPermission(player.UserIDString, permAdmin)) return null;
                    if (!IsOwnerOrFriend(player.userID, entity.OwnerID)) {
                        Message(player, "CannotLoot");
                        return false;

// ... [Code preview truncated due to length. Full source in attached file] ...

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