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

FREE BradleyDrops : 1.1.16 1.1.16

Нет прав для скачивания
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.RegularExpressions;
using UnityEngine;
using Time = UnityEngine.Time;
using Random = UnityEngine.Random;

/* Changelog

1.1.16
 - Fixed: For Rust Update
 
1.1.15
 - Fixed: OnEntitySpawned (Object reference not set to an instance of an object) error on bradley cannon fire
 - Fixed: Loot items not stacking correctly with other loot items of the same type
 
1.1.14
 - Fixed: Entity is NULL but is still in saveList - not destroyed properly? error.1.1.13
 - Fixed: "ArgumentNullException: Value cannot be null.Parameter name: key" error.- Added: Added balloon delivery method for now, Chinook delivery will be on the proper full update

1.1.12
 - Fixed: Reward points not being correctly issued since Rust update

1.1.11
 - Fixed: Occasional CanHackCrate error
 - Added: Config option to prevent players calling in monuments

1.1.10
 - Fixed: Hackable crates not giving correct loot in some cases when enabled in the config

1.1.9
 - Fixed: Bradley Signals are now blocked in monuments

1.1.8
 - 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.7
 - Fixed: OnEntityDestroy NRE when one or more bradley 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 bradley with auto turret
 - Fixed: AlphaLoot not being able to populate hackable crates
 - Added: Custom chat icon config option

1.1.6
 - Fixed: Language defaulting always to English (Fixed this time)

1.1.5
 - Fixed: Player limit not resetting after player using despawn command
 - Fixed: Occasional OnEntityTakeDamage NRE spam in console (hopefully)
 - Added: Config option to destroy/remove entities placed in the landing zone after signal thrown

1.1.4
 - 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 Bradley profile triggering as well as bot profile set in BradleyDrops config
 - Added: BP chance & max BPs to loot table config
 - Added: Config option to announce to player/team only or global chat
 - Added: Check to allow players with admin perm to override crate and gibs protection

1.1.3
 - Fixed: report command not using custom command if edited in the config
 - Added: Clear cooldown admin command (bdclearcd) requires admin perm
 - Added: Seperate cooldowns for each Bradley tier/profile
 - Added: Config option to enable per tier cooldown or not
 - Added: Player Bradley 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: NRE when bradley receives damage from fireball
 - Fixed: NRE when players shoot bradley with remote Auto Turrets
 - Added: Config option to allow/disallow damage to bradley by remote Auto Turret
 - Added: Report command is now usable by players for their owned bradleys (admin perm allows all bradleys)
 - Added: Config option to specify custom report command (default = bdreport)
 - Updated: Re-write of some methods for improvements in damage handling and code efficiency
 - Info: Code cleanup

1.0.32
 - Added example items to loot tables
 - 
1.0.31
 - Fixed: Hackable locked crate not despawning at time specified in config
 - Fixed: Occasional NullReferenceException error on CanStackItem
 - Added: Hackable locked crate loot table options

 */
namespace Oxide.Plugins
{
    [Info("Bradley Drops", "ZEODE", "1.1.16")]
    [Description("Call a Bradley APC to your location with custom supply signals.")]
    public class BradleyDrops: RustPlugin
    {
        #region Plugin References
        
        [PluginReference] Plugin Friends, Clans, FancyDrop, RewardPlugin, Vanish, NoEscape, BotReSpawn, DynamicPVP;
        
        #endregion Plugin References

        #region Constants

        private static BradleyDrops Instance;
        private static System.Random random = new System.Random();

        private const string permAdmin = "bradleydrops.admin";
        private const string permBuy = "bradleydrops.buy";
        private const string permBypasscooldown = "bradleydrops.bypasscooldown";

        private const string bradleyPrefab = "assets/prefabs/npc/m2bradley/bradleyapc.prefab";
        private const string balloonPrefab = "assets/prefabs/deployable/hot air balloon/hotairballoon.prefab";
        private const string planePrefab = "assets/prefabs/npc/cargo plane/cargo_plane.prefab";
        private const string bradleyExplosion = "assets/prefabs/npc/m2bradley/effects/bradley_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 balloonExplosion = "assets/content/vehicles/minicopter/effects/mincopter_explosion.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
        private const ulong easySkinID = 2905355269;
        private const ulong medSkinID = 2905355312;
        private const ulong hardSkinID = 2905355296;
        private const ulong eliteSkinID = 2911864795;

        // Default config item names
        private const string easyDrop = "Bradley Drop (Easy)";
        private const string medDrop = "Bradley Drop (Medium)";
        private const string hardDrop = "Bradley Drop (Hard)";
        private const string eliteDrop = "Bradley Drop (Elite)";
        
        #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>/bdgive <type> <SteamID/PlayerName> <amount></color>",
                ["SyntaxConsole"] = "Invalid syntax, use: bdgive <type> <SteamID/PlayerName> <amount>",
                ["ClearSyntaxPlayer"] = "<color=red>Invalid syntax</color>, use:\n\n<color=green>/bdclearcd</color> (clears all cooldowns)\n\nOr\n\n<color=green>/bdclearcd <SteamID/PlayerName></color>",
                ["ClearSyntaxConsole"] = "Invalid syntax, use: \"bdclearcd\" (clears all cooldowns) or \"bdclearcd <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>!",
                ["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 Bradley APCs is reached, please try again later",
                ["PlayerLimit"] = "Player limit of {0} active Bradley APCs 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",
                ["NotOnGround"] = "<color=orange>{0}</color> must be thrown onto the floor, signal refunded, check inventory.",
                ["InMonument"] = "You cannot call <color=orange>{0}</color> in a <color=red>monument</color>, signal refunded, check inventory.",
                ["UnderWater"] = "<color=orange>{0}</color> was thrown too near <color=blue>water</color> and was refunded, check inventory.",
                ["IntoWater"] = "<color=orange>{0}</color> went into deep <color=blue>water</color> and was destroyed.",
                ["InSafeZone"] = "<color=orange>{0}</color> was thrown in a <color=green>Safe Zone</color> and was refunded, check inventory.",
                ["IntoSafeZone"] = "<color=orange>{0}</color> moved into a <color=green>Safe Zone</color> and was destroyed.",
                ["BuildingPriv"] = "<color=orange>{0}</color> was thrown too close to a players base and was refunded, check inventory.",
                ["NearCollider"] = "<color=orange>{0}</color> was thrown too close to a object, please throw in more open ground.",
                ["LZCleared"] = "Entities placed near the landing zone of <color=orange>{0}</color> have been destroyed.",
                ["Inside"] = "<color=orange>{0}</color> was thrown inside and was refunded, check inventory.",
                ["InvalidDrop"] = "Drop 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!",
                ["CannotMine"] = "You cannot mine this because it is not yours!",
                ["BuyCmdSyntax"] = "Useage:\n\n/{0} {1}",
                ["NoBuy"] = "Buy Command for <color=orange>{0}</color> Is Not Enabled!",
                ["BuyPermission"] = "You do not have permission to buy Bradley Drop \"<color=orange>{0}</color>\".",
                ["PriceList"] = "Bradley Drop Prices:\n\n{0}",
                ["BradleyKilledTime"] = "<color=orange>{0}</color> killed by <color=green>{1}</color> in grid <color=green>{2}</color> (Time Taken: {3})",
                ["BradleyCalled"] = "<color=green>{0}</color> just called in a <color=orange>{1}</color> to their location in grid <color=green>{2}</color>",
                ["RewardGiven"] = "<color=green>{0} {1}</color> points received for destroying <color=orange>{2}</color>!",
                ["ScrapGiven"] = "<color=green>{0}</color> Scrap received for destroying <color=orange>{1}</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> given! No inventory space!",
                ["NotLanded"] = "You <color=red>Cannot</color> damage <color=orange>{0}</color> until it's landed!",
                ["ApcReportTitle"] = "There are currently <color=orange>{0}</color> active dropped Bradley APCs",
                ["ApcReportItem"] = "<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>)\n</size>",
                ["ApcReportTitleCon"] = "There are currently {0} active dropped Bradley APCs",
                ["ApcReportItemCon"] = "{0}/{1} - {2} (Owner: {3} Grid: {4} Health: {5})\n",
                ["ApcReportList"] = "{0}",
                ["DespawnApc"] = "<color=orange>{0}</color> is despawning, you were warned! <color=red>{1}</color>/<color=red>{2}</color>",
                ["DespawnWarn"] = "<color=red>Damage Blocked!</color> You may only attack from a base with TC auth.If you continue, the <color=orange>{0}</color> will despawn.Warning Level: <color=red>{1}</color>/<color=red>{2}</color>",
                ["DamageReport"] = "<color=orange>Damage Report</color>\n\n{0}",
                ["DamageReportIndex"] = "<size=11>{0}.<color=green>{1}</color> -> {2} HP\n</size>",
                ["DiscordCall"] = "**{0}** just called a **{1}** to their location in grid **{2}**",
                ["DiscordKill"] = "**{0}** just destroyed a **{1}** in grid **{2}**",
                ["DiscordDespawn"] = "**{0}** called by **{1}** just despawned at grid **{2}**",
                ["DespawnedBradleys"] = "You have retired ALL your (your teams) called Bradley APCs",
                ["CooldownsCleared"] = "All player cooldowns have been cleared!",
                ["PlayerCooldownCleared"] = "Cooldown cleared for player {0} ({1})",
                ["PlayerNoCooldown"] = "No active cooldown for player {0} ({1})"
            }, 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;
            CheckRewardPlugin();

            if (!config.options.useStacking)
            {
                Unsubscribe(nameof(CanStackItem));
                Unsubscribe(nameof(CanCombineDroppedItem));
            }

            if (config.options.noVanillaApc)
            {
                ConVar.Bradley.enabled = false;
                Puts($"INFO: Vanilla Bradley APC server event at Launch Site is disabled");
            }
        }

        private void Init()
        {
            permission.RegisterPermission(permAdmin, this);
            permission.RegisterPermission(permBuy, this);
            permission.RegisterPermission(permBypasscooldown, this);

            config.rewards.RegisterPermissions(permission, this);
            config.bradley.RegisterPermissions(permission, this);

            foreach (var key in config.bradley.apcConfig.Keys)
            {
                var permSuffix = config.bradley.apcConfig[key].GiveItemCommand.ToLower();
                var perm = $"{Name.ToLower()}.{permSuffix}";
                permission.RegisterPermission(perm, this);
                DropTypes.Add(config.bradley.apcConfig[key].GiveItemCommand);
                BradleyProfileCache.Add(config.bradley.apcConfig[key].SignalSkinID, key);
            }

            AddCovalenceCommand(config.options.reportCommand, nameof(CmdReport));
            AddCovalenceCommand(config.purchasing.buyCommand, nameof(CmdBuyDrop));
            AddCovalenceCommand(config.bradley.despawnCommand, nameof(CmdDespawnApc));
            AddCovalenceCommand("bdgive", nameof(CmdGiveDrop));
            AddCovalenceCommand("bdclearcd", nameof(CmdClearCooldown));
        }

        private void Unload()
        {
            foreach (var netId in BradleyDropData.Keys)
            {
                var apc = BaseNetworkable.serverEntities.Find(new NetworkableId(netId)) as BradleyAPC;
                if (apc != null)
                {
                    var bradleyComp = apc.gameObject.GetComponent<BradleyDrop>();
                    if (bradleyComp != null)
                        UnityEngine.Object.DestroyImmediate(bradleyComp);
                    
                    apc.Kill();
                }
            }

            foreach (var ent in CargoPlaneList)
            {
                if (ent != null)
                {
                    var planeComp = ent.gameObject.GetComponent<BradleyDropPlane>();
                    if (planeComp != null)
                        UnityEngine.Object.DestroyImmediate(planeComp);
                    
                    ent.Kill();
                }
            }

            if (config.options.noVanillaApc)
            {
                ConVar.Bradley.enabled = true;
                Puts($"Vanilla Bradley APC event at Launch Site has been re-enabled");
            }

            BradleyDropData.Clear();
            CargoPlaneList.Clear();
            PlayerCooldowns.Clear();
            TierCooldowns.Clear();
            DropTypes.Clear();
            BradleyProfileCache.Clear();
            RewardPlugin = null;
            Instance = 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)
                NextTick(()=> FixSignalInfo(item));
        }

        private void OnExplosiveThrown(BasePlayer player, SupplySignal entity, ThrownWeapon item)
        {
            var signal = item.GetItem();
            if (signal == null) return;
            
            if (BradleyProfileCache.ContainsKey(signal.skin))
            {
                entity.EntityToCreate = null;
                entity.CancelInvoke(entity.Explode);
                entity.skinID = signal.skin;
                BradleySignalThrown(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(BaseEntity entity)
        {
			NextTick(()=>
            {
                if (entity == null)
                    return;
                
            	if (entity.ShortPrefabName.Contains("maincannonshell"))
            	{
                    if (BradleyDropData.Count == 0)
                        return;
                    
                    TimedExplosive shellEnt = entity as TimedExplosive;
                    BradleyAPC bradley = shellEnt.creatorEntity as BradleyAPC;
                    string apcProfile = bradley?._name;
                    if (shellEnt == null || apcProfile == null)
                    	return;
                        
                    if (!config.bradley.apcConfig.ContainsKey(apcProfile))
                        return;
                        
                    shellEnt.OwnerID = bradley.OwnerID;
                    SetDamageScale(shellEnt, config.bradley.apcConfig[apcProfile].ShellDamageScale);
            	}
            	else if (entity.ShortPrefabName.Equals("oilfireballsmall"))
            	{
                    // Set the owner ID & name of fire on Bradley crates to stop NRE from
                    // OnEntityTakeDamage since LockedEnt crate fires arent assigned this.BaseEntity parentEnt = entity.GetParentEntity();
                    if (parentEnt != null)
                    {
                        BaseEntity baseEnt = entity as BaseEntity;
                        baseEnt.OwnerID = parentEnt.OwnerID;
                        baseEnt._name = parentEnt._name;
                    }
            	}
            });
        }

        private object OnEntityTakeDamage(BradleyAPC bradley, HitInfo info)
        {
            var Initiator = info?.Initiator;
            if (Initiator == null || Initiator == bradley)
                return null;

            var apcProfile = bradley._name;
            if (apcProfile == null)
                return null;

            if (!config.bradley.apcConfig.ContainsKey(apcProfile))
                return null;
            
            // If bradley touches fireball, allow normal damage and stop NRE
            if (Initiator.ShortPrefabName.Equals("fireball_small"))
                return null;
            
            BradleyDrop bradComp = bradley.GetComponent<BradleyDrop>();
            if (bradComp == null)
                return null;

            if (bradComp.isDespawning)
            {
                info.damageTypes.ScaleAll(0);
                return true;
            }

            var apcName = config.bradley.apcConfig[apcProfile].APCName;
            BasePlayer attacker = Initiator as BasePlayer;
            if (Initiator is BasePlayer)
            {
                attacker = Initiator as BasePlayer;
            }
            else if (Initiator is AutoTurret)
            {
                AutoTurret turret = Initiator as AutoTurret;
                ulong playerId = turret.ControllingViewerId.GetValueOrDefault().SteamId;
                attacker = BasePlayer.FindByID(playerId);
                if (attacker == null)
                    return null;
                
                if (!config.bradley.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", apcName);
                    return true;
                }
            }

            if (!bradComp.hasLanded && config.bradley.apcConfig[apcProfile].ChuteProtected)
            {
                info.damageTypes.ScaleAll(0);
                Message(attacker, "NotLanded", apcName);
                return true;
            }

            if (config.bradley.apcConfig[apcProfile].OwnerDamage && !IsOwnerOrFriend(attacker.userID, bradley.OwnerID))
            {
                info.damageTypes.ScaleAll(0);
                Message(attacker, "CannotDamage", apcName);
                return true;
            }

            var dist = Vector3.Distance(bradley.transform.position, attacker.transform.position);
            var maxDist = config.bradley.maxHitDistance;
            if (maxDist > 0 && dist > maxDist)
            {
                info.damageTypes.ScaleAll(0);
                Message(attacker, "TooFarAway", apcName, maxDist);
                return true;
            }

            var bradleyId = bradley.net.ID.Value;
            if (config.bradley.DespawnWarning && attacker.IsBuildingBlocked() && IsOwnerOrFriend(attacker.userID, bradley.OwnerID))
            {
                BradleyDropData[bradleyId].WarningLevel++;
                if (!bradComp.isDespawning && BradleyDropData[bradleyId].WarningLevel >= config.bradley.WarningThreshold)
                {
                    bradComp.isDespawning = true;
                    info.damageTypes.ScaleAll(0);
                    DespawnAPC(bradley);
                    Message(attacker, "DespawnApc", apcName, BradleyDropData[bradleyId].WarningLevel, config.bradley.WarningThreshold);
                    return true;
                }

                info.damageTypes.ScaleAll(0);
                Message(attacker, "DespawnWarn", apcName, BradleyDropData[bradleyId].WarningLevel, config.bradley.WarningThreshold);
                return true;
            }

            if (!BradleyDropData.ContainsKey(bradleyId))
                BradleyDropData.Add(bradleyId, new ApcStats());

            if (!BradleyDropData[bradleyId].Attackers.ContainsKey(attacker.userID))
            {
                BradleyDropData[bradleyId].Attackers.Add(attacker.userID, new AttackersStats());
                BradleyDropData[bradleyId].Attackers[attacker.userID].Name = attacker.displayName;
            }

            BradleyDropData[bradleyId].Attackers[attacker.userID].DamageDealt += info.damageTypes.Total();
            BradleyDropData[bradleyId].LastAttacker = attacker;

            return null;
        }

        private object OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info)
        {
            var Initiator = info?.Initiator;
            if (Initiator == null)
                return null;

            if (Initiator is BradleyAPC)
            {
                BradleyAPC bradley = Initiator as BradleyAPC;
                if (bradley == null)
                    return null;
                
                if (!BradleyDropData.ContainsKey(bradley.net.ID.Value))
                    return null;

                string apcProfile = bradley._name;
                if (apcProfile == null)
                    return null;

                if (config.bradley.apcConfig.ContainsKey(apcProfile))
                {
                    if (entity is BasePlayer)
                    {
                        BasePlayer player = entity as BasePlayer;
                        if (player == null)
                            return null;
                        
                        if (config.bradley.apcConfig[apcProfile].BlockPlayerDamage && !IsOwnerOrFriend(bradley.OwnerID, player.userID))
                        {
                            info.damageTypes.ScaleAll(0);
                            return true;
                        }
                        else if (info.damageTypes.GetMajorityDamageType() == DamageType.Bullet)
                        {
                            info.damageTypes.ScaleAll(config.bradley.apcConfig[apcProfile].GunDamage);
                            float hitProb = (float)random.Next(1, 100);
                            if (config.bradley.apcConfig[apcProfile].GunAccuracy < hitProb)
                            {
                                info.damageTypes.ScaleAll(0);
                                return true;
                            }
                        }
                    }
                    else if (entity.OwnerID.IsSteamId())
                    {
                        if (config.bradley.apcConfig[apcProfile].BlockOtherDamage && !IsOwnerOrFriend(bradley.OwnerID, entity.OwnerID))
                        {
                            info.damageTypes.ScaleAll(0);
                            return true;
                        }
                        if (config.bradley.apcConfig[apcProfile].BlockOwnerDamage && IsOwnerOrFriend(bradley.OwnerID, entity.OwnerID))
                        {
                            info.damageTypes.ScaleAll(0);
                            return true;
                        }
                    }
                }
            }
            else if (Initiator.ShortPrefabName.Equals("oilfireballsmall"))
            {
                string apcProfile = Initiator?._name;
                if (apcProfile == null)
                    return null;

                if (!config.bradley.apcConfig.ContainsKey(apcProfile))
                    return null;

                var apcOwner = Initiator.OwnerID;
                if (apcOwner == null)
                    return null;
                
                if (entity is BasePlayer)
                {
                    BasePlayer player = entity as BasePlayer;
                    if (player == null)
                        return null;
                    
                    if (config.bradley.apcConfig[apcProfile].BlockPlayerDamage && !IsOwnerOrFriend(apcOwner, player.userID))
                    {
                        info.damageTypes.ScaleAll(0);
                        return true;
                    }
                }
                else if (entity.OwnerID.IsSteamId())
                {
                    if (config.bradley.apcConfig[apcProfile].BlockOtherDamage && !IsOwnerOrFriend(apcOwner, entity.OwnerID))
                    {
                        info.damageTypes.ScaleAll(0);
                        return true;
                    }
                    else if (config.bradley.apcConfig[apcProfile].BlockOwnerDamage && IsOwnerOrFriend(apcOwner, entity.OwnerID))
                    {
                        info.damageTypes.ScaleAll(0);
                        return true;
                    }
                }
            }
            return null;
        }

        private object OnEntityDestroy(BradleyAPC bradley)
        {
            if (bradley == null || !BradleyDropData.ContainsKey(bradley.net.ID.Value))
                return null;

            var skinId = bradley.skinID;
            var position = bradley.transform.position;
            var ownerId = bradley.OwnerID;
            var apcProfile = bradley._name;
            var bradleyId = bradley.net.ID.Value;

            var gridPos = PositionToGrid(position);
            if (gridPos == null)
                gridPos = "Unknown";

            BasePlayer lastAttacker = BradleyDropData[bradleyId].LastAttacker;
            if (lastAttacker == null)
                return null;

            var totalReward = config.bradley.apcConfig[apcProfile].RewardPoints;
            var totalScrap = config.bradley.apcConfig[apcProfile].ScrapReward;
            float damageThreshold = config.bradley.apcConfig[apcProfile].DamageThreshold;

            if (config.rewards.enableRewards && totalReward > 0)
            {
                if (plugins.Find(config.rewards.rewardPlugin))
                {
                    if (config.rewards.shareRewards)
                    {
                        foreach (var playerId in BradleyDropData[bradleyId].Attackers.Keys)
                        {
                            float damageDealt = BradleyDropData[bradleyId].Attackers[playerId].DamageDealt;
                            if (damageDealt >= damageThreshold)
                            {
                                var amount = totalReward / BradleyDropData[bradleyId].Attackers.Count(key => key.Value.DamageDealt >= damageThreshold);
                                NextTick(()=> GiveReward(playerId, amount, apcProfile));
                            }
                        }
                    }
                    else
                    {
                        NextTick(()=> GiveReward(ownerId, totalReward, apcProfile));
                    }
                }
            }

            if (config.rewards.enableScrap && totalScrap > 0)
            {
                if (config.rewards.shareScrap)
                {
                    foreach (var playerId in BradleyDropData[bradleyId].Attackers.Keys)
                    {
                        float damageDealt = BradleyDropData[bradleyId].Attackers[playerId].DamageDealt;
                        if (damageDealt >= damageThreshold)
                        {
                            var amount = totalScrap / BradleyDropData[bradleyId].Attackers.Count(key => key.Value.DamageDealt >= damageThreshold);
                            NextTick(()=> GiveScrap(playerId, amount, apcProfile));
                        }
                    }
                }
                else
                {
                    NextTick(()=> GiveScrap(ownerId, totalScrap, apcProfile));
                }
            }

            if (config.announce.killChat)
            {
                TimeSpan timeSpan = TimeSpan.FromSeconds(UnityEngine.Time.realtimeSinceStartup - BradleyDropData[bradleyId].StartTime);
                string time = timeSpan.ToString(@"hh\:mm\:ss");
                var apcDisplayName = config.bradley.apcConfig[apcProfile].APCName;

                var message = string.Format(lang.GetMessage("BradleyKilledTime", this), apcDisplayName, lastAttacker.displayName, gridPos, time);
                AnnounceToChat(lastAttacker, message);
            }

            if (config.announce.reportChat)
            {
                string topReport = string.Empty;
                int count = 1;
                foreach (var key in BradleyDropData[bradleyId].Attackers.Keys.OrderByDescending(x => BradleyDropData[bradleyId].Attackers[x].DamageDealt))
                {
                    if (count >= config.announce.maxReported)
                        break;
                    
                    string playerName = BradleyDropData[bradleyId].Attackers[key].Name;
                    float damageDealt = BradleyDropData[bradleyId].Attackers[key].DamageDealt;
                    topReport += string.Format(lang.GetMessage("DamageReportIndex", this, lastAttacker.UserIDString), count, playerName, Math.Round(damageDealt, 2));
                    count++;
                }

                var dmgReport = string.Format(lang.GetMessage("DamageReport", this, lastAttacker.UserIDString), topReport);
                AnnounceToChat(lastAttacker, dmgReport);
            }

            if (config.discord.sendApcKill)
            {
                string discordMsg = string.Format(lang.GetMessage("DiscordKill", this, lastAttacker.UserIDString), lastAttacker.displayName, apcProfile, gridPos);
                SendToDiscord(discordMsg);
            }

            if (config.bradley.apcConfig[apcProfile].LockedCratesToSpawn > 0)
                SpawnLockedCrates(ownerId, skinId, apcProfile, position);

            NextTick(() =>
            {
                List<BaseEntity> ents = new List<BaseEntity>();
                Vis.Entities(position, 15f, ents);
                foreach (var ent in ents)
                {
                    if ((ent is HelicopterDebris) || (ent is LockedByEntCrate) || (ent is FireBall))
                    {
                        ent.OwnerID = ownerId;
                        ent.skinID = skinId;
                        ent._name = apcProfile;
                        
                        ProcessBradleyEnt(ent);
                    }
                }
            });

            if (BotReSpawn && BotReSpawn.IsLoaded)
            {
                var botReSpawnProfile = config.bradley.apcConfig[apcProfile].BotReSpawnProfile;
                if (botReSpawnProfile != string.Empty)
                    BotReSpawn?.Call("AddGroupSpawn", position, botReSpawnProfile, $"{botReSpawnProfile}Group", 1);
            }

            timer.Once(5f, () =>
            {
                if (BradleyDropData.ContainsKey(bradleyId))
                    BradleyDropData.Remove(bradleyId);
            });

            return null;
        }
    
        private object CanLootEntity(BasePlayer player, LockedByEntCrate entity)
        {
            if (entity.OwnerID == 0)
                return null;

            string apcProfile = entity?._name;
            if (apcProfile == null)
                return null;

            if (config.bradley.apcConfig.ContainsKey(apcProfile))
            {
                if (config.bradley.apcConfig[apcProfile].ProtectCrates)
                {
                    if (permission.UserHasPermission(player.UserIDString, permAdmin))
                        return null;
                    
                    if (!IsOwnerOrFriend(player.userID, entity.OwnerID))
                    {
                        Message(player, "CannotLoot");
                        return true;
                    }
                }
            }
            return null;
        }

        private object OnPlayerAttack(BasePlayer attacker, HitInfo info)
        {
            BaseEntity entity = info?.HitEntity;
            if (entity == null)
                return null;

            if (entity.OwnerID == 0)
                return null;

            if (entity is ServerGib)
            {
                var apcProfile = entity._name;
                if (apcProfile == null)
                    return null;
                
                if (config.bradley.apcConfig.ContainsKey(apcProfile))
                {
                    if (config.bradley.apcConfig[apcProfile].ProtectGibs)
                    {
                        if (permission.UserHasPermission(attacker.UserIDString, permAdmin))
                            return null;
                        
                        if (!IsOwnerOrFriend(attacker.userID, entity.OwnerID))
                        {
                            info.damageTypes.ScaleAll(0);
                            Message(attacker, "CannotMine");
                            return true;
                        }
                    }
                }
            }
            return null;
        }

        private void OnLootSpawn(LootContainer lootContainer)
        {
            timer.Once(2f, () =>
            {
                var apcProfile = lootContainer?._name;
                if (apcProfile == null)
                    return;

                if (config.bradley.apcConfig.ContainsKey(apcProfile))
                {
                    if (lootContainer.ShortPrefabName.Contains("bradley_crate") && config.bradley.apcConfig[apcProfile].Loot.UseCustomLoot)
                        SpawnBradleyCrateLoot(lootContainer, apcProfile);

                    else if (lootContainer.ShortPrefabName.Contains("bradley_crate") && config.bradley.apcConfig[apcProfile].ExtraLoot.UseExtraLoot)
                        AddExtraBradleyCrateLoot(lootContainer, apcProfile);

                    else if (lootContainer.ShortPrefabName.Contains("codelockedhackablecrate") && config.bradley.apcConfig[apcProfile].LockedCrateLoot.UseLockedCrateLoot)
                        SpawnLockedCrateLoot(lootContainer, apcProfile);
                }
            });
        }

        // private string PositionToGrid(Vector3 position) => PhoneController.PositionToGridCoord(position);
        
        private string PositionToGrid(Vector3 pos)
        {
			char letter = 'A';
			var x = Mathf.Floor((pos.x+(ConVar.Server.worldsize/2)) / 146.3f)%26;
			var z = (Mathf.Floor(ConVar.Server.worldsize/146.3f))-Mathf.Floor((pos.z+(ConVar.Server.worldsize/2)) / 146.3f);
			letter = (char)(((int)letter)+x);
			return $"{letter}{z}";
        }

        private void OnSupplyDropDropped(SupplyDrop supplyDrop, CargoPlane plane)
        {
            if (plane != null)
            {
                var planeComp = plane.gameObject.GetComponent<BradleyDropPlane>();
                if (planeComp != null)
                {
                    var position = supplyDrop.transform.position;
                    supplyDrop.Kill();
                    SpawnBradleyDrop(position, plane.transform.eulerAngles, planeComp.player, planeComp.skinId, planeComp.apcProfile);
                    GameManager.DestroyImmediate(planeComp);

                    if (CargoPlaneList.Contains(plane))
                        CargoPlaneList.Remove(plane);
                }
            }
        }

        private object CanBradleyApcTarget(BradleyAPC bradley, BaseEntity target)
        {
            var apcProfile = bradley._name;
            if (apcProfile == null)
                return null;
            
            if (!config.bradley.apcConfig.ContainsKey(apcProfile))
                return null;

            if (target.IsNpc)
                return false;

            BasePlayer player = target as BasePlayer;
            if (player != null)
            {
                if (Vanish && (bool)Vanish?.Call("IsInvisible", player))
                    return false;

                if (!config.bradley.apcConfig[apcProfile].TargetSleepers && player.IsSleeping())
                    return false;
                
                if (!config.bradley.apcConfig[apcProfile].AttackOwner && IsOwnerOrFriend(player.userID, bradley.OwnerID))
                    return false;

                if (!config.bradley.apcConfig[apcProfile].TargetOtherPlayers && !IsOwnerOrFriend(player.userID, bradley.OwnerID))
                    return false;

                var mainTurretPosition = bradley.mainTurret.transform.position;
                if (!(player.IsVisible(mainTurretPosition, bradley.CenterPoint()) || player.IsVisible(mainTurretPosition, player.eyes.position) || player.IsVisible(mainTurretPosition, player.transform.position)))
                    return false;
            }
            return null;
        }

        private object OnBradleyApcInitialize(BradleyAPC bradley)
        {
            var apcProfile = bradley._name;
            if (apcProfile == null)
                return null;

            if (config.bradley.apcConfig.ContainsKey(apcProfile))
            {
                bradley._maxHealth = config.bradley.apcConfig[apcProfile].Health;
                bradley.health = bradley._maxHealth;
                bradley.viewDistance = 0f;  // Set to 0 so APC doesn't target while parachuting
                bradley.searchRange = 0f;   // Set to 0 so APC doesn't target while parachuting
            }
            return null;
        }

        #endregion Oxide Hooks

        #region Core

        private void BradleySignalThrown(BasePlayer player, SupplySignal entity, Item signal)
        {
            if (player == null || entity == null || signal == null)
                return;

            var skinId = signal.skin;
            var apcProfile = signal.name;
            var permSuffix = config.bradley.apcConfig[apcProfile].GiveItemCommand.ToLower();
            var perm = $"{Name.ToLower()}.{permSuffix}";

            if (string.IsNullOrEmpty(apcProfile))
            {
                BradleyProfileCache.TryGetValue(skinId, out apcProfile);
                if (string.IsNullOrEmpty(apcProfile))
                {
                    if (entity != null) entity.Kill();
                    return;
                }
            }

            if (!permission.UserHasPermission(player.UserIDString, perm))
            {
                Message(player, "Permission", apcProfile);
                NextTick(() =>
                {
                    if (entity != null) entity.Kill();
                });
                GiveBradleyDrop(player, skinId, apcProfile, 1, "refund");
                return;
            }

            if (config.bradley.useNoEscape && NoEscape)
            {
                if ((bool)NoEscape.CallHook("IsRaidBlocked", player))
                {
                    Message(player, "RaidBlocked", apcProfile);
                    NextTick(() =>
                    {
                        if (entity != null) entity.Kill();
                    });
                    GiveBradleyDrop(player, skinId, apcProfile, 1, "refund");
                    return;
                }
                else if ((bool)NoEscape.CallHook("IsCombatBlocked", player))
                {
                    Message(player, "CombatBlocked", apcProfile);
                    NextTick(() =>
                    {
                        if (entity != null) entity.Kill();
                    });
                    GiveBradleyDrop(player, skinId, apcProfile, 1, "refund");
                    return;
                }
            }

            if (config.bradley.playerCooldown > 0f && !permission.UserHasPermission(player.UserIDString, permBypasscooldown))
            {
                float cooldown;
                ulong userId = player.userID;
                if (!config.bradley.tierCooldowns)
                {
                    if (PlayerCooldowns.TryGetValue(player.userID, out cooldown))
                    {
                        TimeSpan time = TimeSpan.FromSeconds(cooldown - UnityEngine.Time.time);
                        Message(player, "CooldownTime", time.ToString(@"hh\:mm\:ss"));
                        NextTick(() =>
                        {
                            if (entity != null) entity.Kill();
                        });
                        GiveBradleyDrop(player, skinId, apcProfile, 1, "refund");
                        return;
                    }
                    else if (config.bradley.teamCooldown)
                    {
                        foreach (var playerId in PlayerCooldowns.Keys)
                        {
                            if (PlayerCooldowns.TryGetValue(playerId, out cooldown) && IsOwnerOrFriend(player.userID, playerId))
                            {
                                TimeSpan time = TimeSpan.FromSeconds(cooldown - UnityEngine.Time.time);
                                Message(player, "TeamCooldownTime", time.ToString(@"hh\:mm\:ss"));
                                NextTick(() =>
                                {
                                    if (entity != null) entity.Kill();
                                });
                                GiveBradleyDrop(player, skinId, apcProfile, 1, "refund");
                                return;
                            }
                        }
                    }
                }
                else
                {
                    if (TierCooldowns.ContainsKey(userId))
                    {
                        if (TierCooldowns[userId].TryGetValue(apcProfile, out cooldown))
                        {
                            TimeSpan time = TimeSpan.FromSeconds(cooldown - UnityEngine.Time.time);
                            Message(player, "CooldownTime", time.ToString(@"hh\:mm\:ss"));
                            NextTick(() =>
                            {
                                if (entity != null) entity.Kill();
                            });
                            GiveBradleyDrop(player, skinId, apcProfile, 1, "refund");
                            return;
                        }
                        else if (config.bradley.teamCooldown)
                        {
                            foreach (var playerId in TierCooldowns.Keys)
                            {
                                if (TierCooldowns[userId].TryGetValue(apcProfile, out cooldown) && IsOwnerOrFriend(userId, playerId))
                                {
                                    TimeSpan time = TimeSpan.FromSeconds(cooldown - UnityEngine.Time.time);
                                    Message(player, "TeamCooldownTime", time.ToString(@"hh\:mm\:ss"));
                     
// ... [Code preview truncated due to length. Full source in attached file] ...

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