NPCs die the moment the Chinook spawns.
Hello,
since the Wipe , the NPCs die the moment the Chinook spawns.

I got a fast fix made with claude 

Tested on our server [Nordic] 2-5x Solo/Duo/Trio – Treasure Hunt & DockMaster

What was wrong: the plugin put the guards in the Chinook's seats. The new Rust build throws seated NPCs out mid-flight ("invalid dismount point") and kills them, or they end up outside the map and are deleted. Every guard was gone before the Chinook landed.

How it works now:

  1. Bradley dies, and the Chinook flies to the landing zone and drops smoke, as before. No guards are seated in it.
  2. Once it has touched down, the guards are created on the ground in a ring 5 to 8 m around the landing spot. The number comes from your setting, up to 12, the same loadout, kits and NpcSpawn settings as before.
  3. A second later they walk to their posts around the crates. That's the same order they used to get when leaving the Chinook.
  4. After 5 seconds the Chinook takes off and leaves.
  5. Safety net: if the Chinook doesn't quite touch down, the guards are spawned anyway after 90 seconds, so an event is never left empty.

Unlocking and extinguishing the crates when the guards are dead, notifications and debug drawing are unchanged.

Test it: destroy Bradley at Launch Site again. You should see the Chinook land and the guards appear around it and spread out. The console shouldn't show any "invalid dismount point" or "Invalid NavAgent Position" lines for them. 

 

/*
 * Copyright (c) 2023 Bazz3l
 * 
 * Bradley Guards cannot be copied, edited and/or (re)distributed without the express permission of Bazz3l.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 * 
 */

using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Collections;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.IO;
using System;
using Oxide.Core.Configuration;
using Oxide.Core.Plugins;
using Oxide.Core;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using BradleyGuardsExt;
using UnityEngine;
using Rust;

namespace Oxide.Plugins
{
    [Info("Bradley Guards", "Bazz3l", "1.7.5")]
    [Description("Call in reinforcements when bradley is destroyed, guards fly in and protect the bradley apc wreckage.")]
    internal class BradleyGuards : RustPlugin
    {
        [PluginReference] private Plugin NpcSpawn, GUIAnnouncements;
        
        #region Fields
        
        private const string PERM_USE = "bradleyguards.use";
        private const float INITIALIZE_DELAY = 10f;
        
        private readonly Regex _strRegex = new Regex("[a-zA-Z0-9 _-]+");
        private readonly object _objTrue = true;
        private Coroutine _setupRoutine;
        private Datafile<StoredData> _storedData;
        private static ConfigData _configData;
        private static Func<string, string, string> _getMessage = null;
        private static Func<Vector3, JObject, ScientistNPC> _trySpawnNpc = null;
        private static Func<bool, bool> _trySubscribeToHooks = null;
        private static Func<string, string, string, BasePlayer, float, object> _sendGuiNotification = null;

        #endregion
        
        #region Local
        
        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
            {
                { LangKeys.NO_PERMISSION, "Sorry you don't have permission to do that." },
                { LangKeys.PREFIX, "<color=#8a916f>Bradley Guards</color>:<br>" },
                
                { LangKeys.EVENT_START, "Armed reinforcements en route to <color=#e7cf85>{0}</color> eliminate the guards to gain access to high-value loot." },
                { LangKeys.EVENT_ENDED, "Armed reinforcements have been eliminated at <color=#e7cf85>{0}</color>." },
                { LangKeys.EVENT_UPDATED, "Event updated, please reload the plugin to take effect." },
                { LangKeys.EVENT_NOT_FOUND, "Event not found, please make sure you have typed the correct name." },
                { LangKeys.EVENT_DEBUG, "Event debug information has been <color=#e7cf85>enabled</color> for <color=#e7cf85>{0}</color> seconds." },
                
                { LangKeys.INVALID_DISPLAY_NAME, "Invalid value provided, must be a string: \"Launch Site\"" },
                { LangKeys.INVALID_GUARD_AMOUNT, "Invalid value provided, must be a number: 2 - 10." },
                { LangKeys.INVALID_BOOLEAN, "Invalid value provided, must be a bool: true - false" },
                { LangKeys.INVALID_DURATION, "Invalid value provided, must be a number: 1 - 300." },
                { LangKeys.INVALID_INVENTORY, "Invalid inventory." },
                
                { LangKeys.HELP_EVENT_ENABLE, "<color=#e7cf85>/{0}</color> <color=#e7cf85><display-name></color> enable <color=#e7cf85><true|false></color><br>" },
                { LangKeys.HELP_EVENT_NAME, "<color=#e7cf85>/{0}</color> <color=#e7cf85><display-name></color> display <color=#e7cf85><name></color><br>" },
                { LangKeys.HELP_GUARD_AMOUNT, "<color=#e7cf85>/{0}</color> <color=#e7cf85><display-name></color> guard-amount <color=#e7cf85><number></color><br>" },
                { LangKeys.HELP_GUARD_LOADOUT, "<color=#e7cf85>/{0}</color> <color=#e7cf85><display-name></color> guard-loadout" },
                { LangKeys.HELP_EVENT_DEBUG, "<color=#e7cf85>/{0}</color> <color=#e7cf85><display-name></color> debug <color=#e7cf85><number></color><br>" },
            }, this);
        }

        private static class LangKeys
        {
            public const string PREFIX = "PREFIX";
            public const string NO_PERMISSION = "NO_PERMISSION";
            
            public const string EVENT_START = "EVENT_START";
            public const string EVENT_ENDED = "EVENT_ENDED";
            public const string EVENT_NOT_FOUND = "EVENT_NOT_FOUND";
            public const string EVENT_UPDATED = "EVENT_UPDATED";
            public const string EVENT_DEBUG = "EVENT_DEBUG";
            
            public const string INVALID_DISPLAY_NAME = "INVALID_DISPLAY_NAME";
            public const string INVALID_GUARD_AMOUNT = "INVALID_GUARD_AMOUNT";
            public const string INVALID_BOOLEAN = "INVALID_BOOLEAN";
            public const string INVALID_DURATION = "INVALID_DURATION";
            public const string INVALID_INVENTORY = "INVALID_INVENTORY";
            
            public const string HELP_EVENT_ENABLE = "HELP_EVENT_ENABLE";
            public const string HELP_EVENT_NAME = "HELP_EVENT_NAME";
            public const string HELP_EVENT_DEBUG = "HELP_EVENT_DEBUG";
            public const string HELP_GUARD_AMOUNT = "HELP_GUARD_AMOUNT";
            public const string HELP_GUARD_LOADOUT = "HELP_GUARD_LOADOUT";
        }
        
        #endregion
        
        #region Config

        protected override void LoadDefaultConfig()
        {
            _configData = ConfigData.DefaultConfig();
            _configData.Version = Version;
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();

            try
            {
                _configData = Config.ReadObject<ConfigData>();
                if (_configData == null) throw new Exception();

                bool wasUpdated = false;
                
                if (_configData.Version == null || _configData.Version < new VersionNumber(1, 7, 4))
                {
                    LoadDefaultConfig();
                    wasUpdated = true;
                }
                
                if (wasUpdated)
                {
                    SaveConfig();
                    PrintWarning("Config has been updated.");
                }
            }
            catch(Exception e)
            {
                LoadDefaultConfig();
                PrintWarning("Loaded default config: {0}", e.Message);
            }
        }

        protected override void SaveConfig() => Config.WriteObject(_configData, true);
        
        private class ConfigData
        {
            [JsonProperty("command name - (default: bguard)")]
            public string CommandName;
            
            [JsonProperty("auto unlock crates when guards are eliminated - (default: true)")]
            public bool EnableAutoUnlock;
            [JsonProperty("auto extinguish crates when guards are eliminated - (default: true)")]
            public bool EnableAutoExtinguish;
            
            [JsonProperty("amount of crates bradley should spawn when destroyed - (default: 4)")]
            public int BradleyCrates;
            [JsonProperty("amount of health bradley should spawn with - (default: 1000)")]
            public float BradleyHealth;
            
            [JsonProperty("amount of time debug messages will display for in seconds - (default: 30)")]
            public float DebugDuration;
            
            [JsonProperty("toast notification settings")]
            public ToastSetting ToastSetting;
            [JsonProperty("chat notification settings")]
            public ChatSetting ChatSetting;
            [JsonProperty("gui announcement notification settings - (https://umod.org/plugins/gui-announcements)")]
            public GuiaSetting GuiaSetting;

            [JsonProperty("current version number - (WARNING!!! do not change this value)")]
            public VersionNumber? Version;

            public static ConfigData DefaultConfig()
            {
                return new ConfigData
                {
                    CommandName = "bguard",
                    EnableAutoUnlock = true,
                    EnableAutoExtinguish = true,
                    BradleyCrates = 4,
                    BradleyHealth = 1000f,
                    DebugDuration = 30f,
                    ToastSetting = ToastSetting.CreateNew(),
                    ChatSetting = ChatSetting.CreateNew(),
                    GuiaSetting = GuiaSetting.CreateNew(),
                };
            }
        }
        
        private class ChatSetting
        {
            [JsonProperty("enabled - (default: true)")] 
            public bool Enabled;
            [JsonProperty("enable prefix - (default: true)")] 
            public bool EnablePrefix;
            [JsonProperty("chat icon (steam64) - (default: 76561199542824781)")]
            public ulong ChatIcon;
            
            public static ChatSetting CreateNew()
            {
                return new ChatSetting
                {
                    Enabled = true,
                    EnablePrefix = true,
                    ChatIcon = 76561199542824781,
                };
            }
        }
        
        private class ToastSetting
        {
            [JsonProperty("enabled - (default: false)")] 
            public bool Enabled;
            [JsonConverter(typeof(StringEnumConverter))]
            [JsonProperty("style - (default: Blue_Normal - options: Blue_Normal, Red_Normal, Server_Event)")] 
            public GameTip.Styles Style;
            
            public static ToastSetting CreateNew()
            {
                return new ToastSetting
                {
                    Enabled = false,
                    Style = GameTip.Styles.Blue_Normal
                };
            }
        }
        
        private class GuiaSetting
        {
            [JsonProperty("enabled - (default: false)")]
            public bool Enabled;
            [JsonProperty("text color - (default: white)")]
            public string TextColor;
            [JsonProperty("background color - (default: purple)")]
            public string BackgroundColor;
            
            public static GuiaSetting CreateNew()
            {
                return new GuiaSetting
                {
                    Enabled = false,
                    TextColor = "white",
                    BackgroundColor = "purple",
                };
            }
        }

        #endregion

        #region Storage

        private class Datafile<T> where T : new()
        {
            private readonly DynamicConfigFile _cfg;
            public T Data;

            public Datafile(params string[] paths)
            {
                string filepath = Path.Combine(paths);
                _cfg = Interface.Oxide.DataFileSystem.GetDatafile(filepath);
            }

            public void Load()
            {
                try
                {
                    Data = _cfg.ReadObject<T>() ?? throw new Exception();
                }
                catch (Exception e)
                {
                    Data = new T();
                    Interface.Oxide.LogDebug("Loaded default data: {0}", e.Message);
                }
            }

            public void Save()
            {
                if (Data == null)
                    return;
                
                _cfg.WriteObject(Data);
            }
        }

        private class StoredData
        {
            [JsonProperty("BradleyEventEntries")]
            public Dictionary<string, EventEntry> EventEntries = new(StringComparer.OrdinalIgnoreCase);
            
            [JsonIgnore]
            public bool IsValid => EventEntries?.Count > 0;
        }

        private class EventEntry
        {
            [JsonProperty("display name")]
            public string DisplayName;
            [JsonProperty("enabled")]
            public bool EnabledEvent;
            [JsonProperty("bounds center")]
            public Vector3 BoundsPosition;
            [JsonProperty("bounds size")]
            public Vector3 BoundsSize;
            [JsonProperty("landing position")]
            public Vector3 LandingPosition;
            [JsonProperty("landing rotation")]
            public Vector3 LandingRotation;
            [JsonProperty("chinook position")]
            public Vector3 ChinookPosition;
            [JsonProperty("guard spawn amount")]
            public int GuardAmount;
            [JsonProperty("guard spawn profile")]
            public GuardConfig GuardProfile;
            
            [JsonIgnore]
            public bool IsValid => GuardAmount > 0 && GuardProfile != null && GuardProfile.WearItems != null && GuardProfile.BeltItems != null;
            
            public static EventEntry CreateNew(string displayName, bool enabledEvent, Vector3 boundsPosition, Vector3 boundsSize, Vector3 landingPosition, Vector3 landingRotation, Vector3 chinookPosition, int guardAmount, GuardConfig guardProfile)
            {
                EventEntry entry = new EventEntry
                {
                    DisplayName = displayName,
                    EnabledEvent = enabledEvent,
                    BoundsPosition = boundsPosition,
                    BoundsSize = boundsSize,
                    LandingPosition = landingPosition,
                    LandingRotation = landingRotation,
                    ChinookPosition = chinookPosition,
                    GuardAmount = guardAmount,
                    GuardProfile = guardProfile
                };
                return entry;
            }
        }
        
        private class GuardConfig
        {
            public string Name;
            public string Kit;
            public float Health;
            public float RoamRange;
            public float ChaseRange;
            public float SenseRange;
            public float AttackRangeMultiplier;
            public bool CheckVisionCone;
            public float VisionCone;
            public float DamageScale;
            public float TurretDamageScale;
            public float AimConeScale;
            public bool DisableRadio;
            public bool CanRunAwayWater;
            public bool CanSleep;
            public float Speed;
            public int AreaMask;
            public int AgentTypeID;
            public float MemoryDuration;
            public List<WearEntry> WearItems;
            public List<BeltEntry> BeltItems; 

            [JsonIgnore]
            public string[] Kits;
            
            [JsonIgnore]
            public JObject Parsed;

            public class BeltEntry
            {
                public string ShortName;
                public ulong SkinID;
                public int Amount;
                public string Ammo;
                public List<string> Mods;

                public static List<BeltEntry> SaveItems(ItemContainer container)
                {
                    List<BeltEntry> items = new List<BeltEntry>();
                    
                    foreach (Item item in container.itemList)
                    {
                        BeltEntry beltEntry = new BeltEntry
                        {
                            ShortName = item.info.shortname,
                            SkinID = item.skin,
                            Amount = item.amount,
                            Mods = new List<string>()
                        };

                        if (item.GetHeldEntity() is BaseProjectile projectile && projectile?.primaryMagazine != null && projectile.primaryMagazine.ammoType != null)
                            beltEntry.Ammo = projectile.primaryMagazine.ammoType.shortname;

                        if (item?.contents?.itemList != null)
                        {
                            foreach (Item itemContent in item.contents.itemList)
                                beltEntry.Mods.Add(itemContent.info.shortname);
                        }
                        
                        items.Add(beltEntry);
                    }

                    return items;
                }
            }

            public class WearEntry
            {
                public string ShortName; 
                public ulong SkinID;

                public static List<WearEntry> SaveItems(ItemContainer container)
                {
                    List<WearEntry> items = new List<WearEntry>();
                    
                    foreach (Item item in container.itemList)
                    {
                        WearEntry wearEntry = new WearEntry
                        {
                            ShortName = item.info.shortname,
                            SkinID = item.skin
                        };
                        
                        items.Add(wearEntry);
                    }

                    return items;
                }
            }

            public void CacheConfig()
            {
                Kits = Kit?.Split(',') ?? Array.Empty<string>();
                
                JArray wearItems = new JArray();
                foreach (WearEntry wearEntry in WearItems)
                {
                    wearItems.Add(new JObject
                    {
                        ["ShortName"] = wearEntry.ShortName,
                        ["SkinID"] = wearEntry.SkinID
                    });
                }
                
                JArray beltItems = new JArray();
                foreach (BeltEntry beltEntry in BeltItems)
                {
                    beltItems.Add(new JObject
                    {
                        ["ShortName"] = beltEntry.ShortName, 
                        ["SkinID"] = beltEntry.SkinID, 
                        ["Amount"] = beltEntry.Amount, 
                        ["Ammo"] = beltEntry.Ammo, 
                        ["Mods"] = new JArray(beltEntry.Mods)
                    });
                }
                
                Parsed = new JObject
                {
                    ["Name"] = Name,
                    ["WearItems"] = wearItems,
                    ["BeltItems"] = beltItems,
                    ["Kit"] = Kit,
                    ["Health"] = Health,
                    ["RoamRange"] = RoamRange,
                    ["ChaseRange"] = ChaseRange,
                    ["SenseRange"] = SenseRange,
                    ["ListenRange"] = SenseRange / 2,
                    ["AttackRangeMultiplier"] = AttackRangeMultiplier,
                    ["CheckVisionCone"] = CheckVisionCone,
                    ["VisionCone"] = VisionCone,
                    ["DamageScale"] = DamageScale,
                    ["TurretDamageScale"] = TurretDamageScale,
                    ["AimConeScale"] = AimConeScale,
                    ["DisableRadio"] = DisableRadio,
                    ["CanRunAwayWater"] = CanRunAwayWater,
                    ["CanSleep"] = CanSleep,
                    ["Speed"] = Speed,
                    ["AreaMask"] = AreaMask,
                    ["AgentTypeID"] = AgentTypeID,
                    ["MemoryDuration"] = MemoryDuration,
                    ["States"] = new JArray(new HashSet<string> { "RoamState", "ChaseState", "CombatState" })
                };
            }
        }
        
        private void LoadData()
        {
            _storedData = new Datafile<StoredData>(Name);
            _storedData.Load();

            TryUpdateData();
        }

        private void SaveData()
        {
            if (_storedData == null) 
                return;
            
            _storedData.Save();
        }

        private void TryUpdateData()
        {
            if (_storedData.Data.IsValid)
                return;

            _storedData.Data.EventEntries = new Dictionary<string, EventEntry>
            {
                ["assets/bundled/prefabs/autospawn/monument/xlarge/launch_site_1.prefab"] = EventEntry.CreateNew(
                    "Launch Site",
                    true,
                    new Vector3(100f, 0f, 0f),
                    new Vector3(580f, 280f, 300f),
                    new Vector3(152.3f, 3f, 0f),
                    new Vector3(0f, 180f, 0f),
                    new Vector3(-195f, 150f, 25f),
                    10,
                    new GuardConfig
                    {
                        Name = "Launch Site Guard",
                        WearItems = new List<GuardConfig.WearEntry>
                        {
                            new()
                            {
                                ShortName = "hazmatsuit_scientist_peacekeeper",
                                SkinID = 0UL
                            }
                        },
                        BeltItems = new List<GuardConfig.BeltEntry>
                        {
                            new()
                            {
                                ShortName = "smg.mp5",
                                Amount = 1,
                                SkinID = 0UL,
                                Mods = new List<string>()
                            },
                            new()
                            {
                                ShortName = "syringe.medical",
                                Amount = 10,
                                SkinID = 0UL,
                                Mods = new List<string>()
                            },
                        },
                        Kit = "",
                        Health = 250f,
                        RoamRange = 25f,
                        ChaseRange = 40f,
                        SenseRange = 150f,
                        AttackRangeMultiplier = 8f,
                        CheckVisionCone = false,
                        VisionCone = 180f,
                        DamageScale = 1f,
                        TurretDamageScale = 0.25f,
                        AimConeScale = 0.35f,
                        DisableRadio = false,
                        CanRunAwayWater = true,
                        CanSleep = false,
                        Speed = 8.5f,
                        AreaMask = 1,
                        AgentTypeID = -1372625422,
                        MemoryDuration = 30f
                    }),
                ["assets/bundled/prefabs/autospawn/monument/large/airfield_1.prefab"] = EventEntry.CreateNew(
                    "Airfield Guard",
                    false,
                    new Vector3(0f, 0f, 0f),
                    new Vector3(340f, 260f, 300f),
                    new Vector3(0f, 0f, -28f),
                    new Vector3(0f, 0f, 0f),
                    new Vector3(-195f, 150f, 25f),
                    10,
                    new GuardConfig
                    {
                        Name = "Guarded Crate",
                        WearItems = new List<GuardConfig.WearEntry>
                        {
                            new()
                            {
                                ShortName = "hazmatsuit_scientist_peacekeeper",
                                SkinID = 0UL
                            }
                        },
                        BeltItems = new List<GuardConfig.BeltEntry>
                        {
                            new()
                            {
                                ShortName = "smg.mp5",
                                Amount = 1,
                                SkinID = 0UL,
                                Mods = new List<string>()
                            },
                            new()
                            {
                                ShortName = "syringe.medical",
                                Amount = 10,
                                SkinID = 0UL,
                                Mods = new List<string>()
                            },
                        },
                        Kit = "",
                        Health = 250f,
                        RoamRange = 25f,
                        ChaseRange = 40f,
                        SenseRange = 150f,
                        AttackRangeMultiplier = 8f,
                        CheckVisionCone = false,
                        VisionCone = 180f,
                        DamageScale = 1f,
                        TurretDamageScale = 0.25f,
                        AimConeScale = 0.35f,
                        DisableRadio = false,
                        CanRunAwayWater = true,
                        CanSleep = false,
                        Speed = 8.5f,
                        AreaMask = 1,
                        AgentTypeID = -1372625422,
                        MemoryDuration = 30f
                    })
            };
        }
        
        private EventEntry FindEventByDisplayName(string displayName)
        {
            foreach (EventEntry eventEntry in _storedData.Data.EventEntries.Values)
            {
                if (eventEntry.DisplayName.StartsWith(displayName, StringComparison.OrdinalIgnoreCase))
                    return eventEntry;
            }
            
            return null;
        }

        private EventEntry FindEntryByMonumentName(string monumentName)
        {
            _storedData.Data.EventEntries.TryGetValue(monumentName, out EventEntry eventEntry);
            return eventEntry;
        }
        
        #endregion
        
        #region Oxide Hooks

        private void OnServerInitialized()
        {
            EntityProtection.Initialize();
            PerformSetupRoutine();
            
            if (string.IsNullOrEmpty(_configData.CommandName))
                return;
            
            cmd.AddChatCommand(_configData.CommandName, this, nameof(EventCommands));
        }

        private void Init()
        {
            permission.RegisterPermission(PERM_USE, this);
            
            LoadData();
            
            _getMessage = (key, userId) => lang.GetMessage(key, this, userId);
            _trySpawnNpc = (position, config) => (ScientistNPC)NpcSpawn?.Call("SpawnNpc", position, config);
            _trySubscribeToHooks = SubscribeToHooks;
            _sendGuiNotification = (message, bgColor, textColor, player, duration) => GUIAnnouncements?.Call("CreateAnnouncement", message, bgColor, textColor, player, duration); 
        }
        
        private void Unload()
        {
            try
            {
                DestroySetupRoutine();
                BradleyGuardsEvent.OnUnload();
            }
            finally
            {
                EntityProtection.OnUnload();
                EntityCache.OnUnload();

                _configData = null;
            }
        }

        private void OnEntitySpawned(BradleyAPC bradley)
        {
            if (bradley == null || bradley.IsDestroyed)
                return;
            
            Vector3 spawnPosition = bradley.transform.position;
            if (spawnPosition == Vector3.zero)
                return;
            
            BradleyGuardsEvent closestEvent = BradleyGuardsEvent.GetClosest(spawnPosition);
            if (closestEvent == null)
                return;
            
            closestEvent.ResetEvent();
            bradley.maxCratesToSpawn = Math.Clamp(_configData.BradleyCrates, 1, 12);
            bradley.maxHealthOverride = bradley.startHealth = _configData.BradleyHealth;
            bradley._health = bradley._maxHealth = bradley.maxHealthOverride;
            bradley.health = bradley.maxHealthOverride;
            bradley.SendNetworkUpdate();
        }
        
        private void OnEntityDeath(BradleyAPC bradley, HitInfo info)
        {
            if (bradley == null || bradley.IsDestroyed || info?.InitiatorPlayer == null)
                return;
            
            Vector3 deathPosition = bradley.transform.position;
            if (deathPosition == Vector3.zero)
                return;
            
            BradleyGuardsEvent closestEvent = BradleyGuardsEvent.GetClosest(deathPosition);
            if (closestEvent == null || closestEvent.IsStarted()) 
                return;
                
            if (!NpcSpawn.IsReady())
            {
                PrintWarning("Missing dependency [NpcSpawn v2.4.8] this can be found over at codefling.com thanks to KpucTaJl");
                return;
            }

            closestEvent.StartEvent(deathPosition);
        }
        
        private void OnPlayerDeath(ScientistNPC npc, HitInfo info)
        {
            NetworkableId id = npc.net.ID;
            EntityCache.FindEventByEntity(id)?.OnGuardDeath(npc, info?.InitiatorPlayer);
        }
        
        private void OnEntityKill(ScientistNPC npc)
        {
            EntityCache.FindEventByEntity(npc.net.ID)
                ?.OnGuardDeath(npc, null);
        }
        
        private void OnEntityDismounted(BaseMountable mountable, ScientistNPC scientist)
        {
            CH47HelicopterAIController chinook = mountable.VehicleParent() as CH47HelicopterAIController;
            if (chinook == null || chinook.IsDestroyed || chinook.OwnerID != 111999)
                return;
            
            scientist.Brain.Navigator.ForceToGround();
            scientist.Brain.Navigator.SetDestination(scientist.finalDestination);
            scientist.Brain.SwitchToState(AIState.MoveToVector3, -1);

            if (chinook.NumMounted() != 1)
                return;
            
            chinook.Invoke(() =>
            {
                if (chinook.IsDestroyed)
                    return;
                
                chinook.ClearLandingTarget();
                chinook.SetMinHoverHeight(150f);
                chinook.EnableFacingOverride(false);
                chinook.SetMoveTarget(chinook.transform.position + Vector3.up * 100f);
                
                if (!chinook.TryGetComponent(out CH47AIBrain ch47AIBrain))
                    return;
                
                ch47AIBrain.ResetState();
                ch47AIBrain.SwitchToState(AIState.Egress, ch47AIBrain.AIDesign.DefaultStateContainerID);
                ch47AIBrain.Think(0.0f);
            }, 5f);
        }

        #endregion

        #region Event
        
        private enum EventState { Waiting, Started }

        private void PerformSetupRoutine()
        {
            DestroySetupRoutine();
            
            _setupRoutine = ServerMgr.Instance.StartCoroutine(SetupEventsRoutine());
        }

        private void DestroySetupRoutine()
        {
            if (_setupRoutine != null)
                ServerMgr.Instance.StopCoroutine(_setupRoutine);
            
            _setupRoutine = null;
        }
        
        private IEnumerator SetupEventsRoutine()
        {
            yield return null;
            
            Interface.Oxide.LogDebug("Initializing (Bradley Guard Events) in ({0})s.", INITIALIZE_DELAY);
            
            yield return CoroutineEx.waitForSeconds(INITIALIZE_DELAY);
            
            using (new DebugStopwatch("Finished initializing (Bradley Guard Events) in ({0})ms."))
            {
                foreach (MonumentInfo monumentInfo in TerrainMeta.Path.Monuments)
                {
                    if (string.IsNullOrEmpty(monumentInfo.name))
                        continue;
                    
                    EventEntry eventEntry = FindEntryByMonumentName(monumentInfo.name);
                    if (eventEntry == null || !eventEntry.EnabledEvent)
                        continue;

                    if (!eventEntry.IsValid)
                    {
                        PrintWarning("Skipping ({0}), invalid event settings", eventEntry.DisplayName);
                        continue;
                    }
                    
                    yield return BradleyGuardsEvent.CreateNew(monumentInfo.transform, eventEntry, _configData);
                }
            }
            
            _setupRoutine = null;
        }
        
        private class BradleyGuardsEvent : FacepunchBehaviour
        {
            private static readonly List<BradleyGuardsEvent> AllEvents = new();
            private bool _enableExtinguish;
            private bool _enableUnlocking;
            private GuardConfig _guardConfig;
            private int _guardAmount;
            private bool _guardsDeployed;        // guards are on the ground for this event
            private float _landingWaitSeconds;   // time spent waiting for the chinook to touch down
            private OBB _eventBounds;
            
            public List<BaseEntity> spawnInstances = new();
            public CH47HelicopterAIController chinookInstance = null;
            public CH47LandingZone eventLandingZone;
            public BasePlayer winningPlayer;
            public EventState eventState;
            public Vector3 eventSpawn;
            public Vector3 chinookPosition;
            public string displayName;
            
            public static BradleyGuardsEvent GetClosest(Vector3 position)
            {
                for (int i = 0; i < AllEvents.Count; i++)
                {
                    BradleyGuardsEvent component = AllEvents[i];
                    if (component._eventBounds.Contains(position)) 
                        return component;
                }

                return (BradleyGuardsEvent)null;
            }
            
            public static BradleyGuardsEvent GetByMonument(string displayName)
            {
                for (int i = 0; i < AllEvents.Count; i++)
                {
                    BradleyGuardsEvent component = AllEvents[i];
                    if (component.displayName.StartsWith(displayName, StringComparison.OrdinalIgnoreCase)) 
                        return component;
                }

                return (BradleyGuardsEvent)null;
            }
            
            public static IEnumerator CreateNew(Transform transform, EventEntry eventEntry, ConfigData configData)
            {
                Vector3 landingRotation = transform.TransformDirection(transform.rotation.eulerAngles - eventEntry.LandingRotation);
                Vector3 landingPosition = transform.TransformPoint(eventEntry.LandingPosition);
                Vector3 chinookPosition = transform.TransformPoint(eventEntry.ChinookPosition);
                
                if (eventEntry.GuardProfile.Parsed == null)
                    eventEntry.GuardProfile.CacheConfig();
                
                BradleyGuardsEvent component = Helpers.CreateObjectWithComponent<BradleyGuardsEvent>(landingPosition, Quaternion.Euler(landingRotation), "Bradley_Guards_Event");
                component.chinookPosition = chinookPosition;
                component.ConfigureEvent(eventEntry, configData);
                component.CreateLandingZone();
                
                yield return CoroutineEx.waitForEndOfFrame;
            }

            private void ConfigureEvent(EventEntry eventEntry, ConfigData configData)
            {
                displayName = eventEntry.DisplayName;
                _eventBounds = new OBB(transform.position, transform.rotation, new Bounds(eventEntry.BoundsPosition, eventEntry.BoundsSize));
                _guardConfig = eventEntry.GuardProfile;
                _guardAmount = eventEntry.GuardAmount;
                _enableExtinguish = configData.EnableAutoExtinguish;
                _enableUnlocking = configData.EnableAutoUnlock;
            }

            public static void OnUnload()
            {
                if (Rust.Application.isQuitting)
                    return;
                
                foreach (BradleyGuardsEvent component in new List<BradleyGuardsEvent>(AllEvents))
                {
                    if (component.IsUnityNull()) 
                        continue;
                    
                    component.ClearGuards();
                    component.ClearChinook();
                    UnityEngine.GameObject.Destroy(component.gameObject);
                }
                
                AllEvents.Clear();
            }
            
            #region Unity
            
            public void Awake()
            {
                BradleyGuardsEvent.AllEvents.Add(this);
            }

            public void OnDestroy()
            {
                BradleyGuardsEvent.AllEvents.Remove(this);   
            }

            #endregion
            
            #region Event Management
            
            public bool IsStarted() => eventState == EventState.Started;

            public void StartEvent(Vector3 position)
            {
                if (IsStarted())
                    return;
                
                winningPlayer = null;
                eventSpawn = position;
                _guardsDeployed = false;
                _landingWaitSeconds = 0f;
                eventState = EventState.Started;
                
                SpawnChinook();
                RemoveDamage();

                _trySubscribeToHooks(true);
                
                Notification.MessagePlayers(LangKeys.EVENT_START, displayName);
            }

            private void StopEvent()
            {
                eventState = EventState.Waiting;
                
                chinookInstance = null;
                
                _trySubscribeToHooks(false);
                
                Notification.MessagePlayers(LangKeys.EVENT_ENDED, displayName);
            }

            public void ResetEvent()
            {
                ClearGuards();
                ClearChinook();
                
                eventState = EventState.Waiting;
            }

            public void CheckEvent()
            {
                if (_enableExtinguish)
                    RemoveFlames();
                
                if (_enableUnlocking)
                    UnlockCrates();

                if (winningPlayer != null)
                    Interface.CallHook("OnBradleyGuardsEventEnded", winningPlayer);
                
                StopEvent();
            }

            private bool HasGuards() => spawnInstances.Count > 0;

            private void UnlockCrates()
            {
                List<LockedByEntCrate> list = Facepunch.Pool.Get<List<LockedByEntCrate>>();

                try
                {
                    Vis.Entities<LockedByEntCrate>(eventSpawn, 25f, list);
                    
                    foreach (LockedByEntCrate entity in list)
                    {
                        if (entity.IsValid() && !entity.IsDestroyed)
                            entity.SetLocked(false);
                    }
                }
                finally
                {
                    Facepunch.Pool.FreeUnmanaged(ref list);
                }
            }

            private void RemoveFlames()
            {
                List<FireBall> list = Facepunch.Pool.Get<List<FireBall>>();

                try
                {
                    Vis.Entities<FireBall>(eventSpawn, 25f, list);
                    
                    foreach (FireBall entity in list)
                    {
                        if (entity.IsValid() && !entity.IsDestroyed)
                            entity.Extinguish();
                    }
                }
                finally
                {
                    Facepunch.Pool.FreeUnmanaged(ref list);
                }
            }
            
            private void RemoveDamage()
            {
                List<FireBall> list = Facepunch.Pool.Get<List<FireBall>>();
                
                try
                {
                    Vis.Entities<FireBall>(eventSpawn, 25f, list);

                    foreach (FireBall fireBall in list)
                    {
                        if (fireBall.IsValid() && !fireBall.IsDestroyed)
                            fireBall.ignoreNPC = true;
                    }
                }
                finally
                {
                    Facepunch.Pool.FreeUnmanaged<FireBall>(ref list);
                }
            }

            #endregion

            #region Chinook

            private void SpawnChinook()
            {
                Vector3 position = eventLandingZone.transform.position;
                chinookInstance = Helpers.SpawnEntity<CH47HelicopterAIController>("assets/prefabs/npc/ch47/ch47scientists.entity.prefab", chinookPosition, Quaternion.identity);
                chinookInstance.transform.position = chinookPosition;
                chinookInstance.SetLandingTarget(position);
                chinookInstance.SetMinHoverHeight(0.0f);
                chinookInstance.OwnerID = 111999;
                chinookInstance.Spawn();
                chinookInstance.CancelInvoke(new Action(chinookInstance.CheckSpawnScientists));
                // Rust (Nov 2026) throws NPCs out of chinook seats mid-flight and kills them ("invalid dismount
                // point"), so the guards are no longer seated: they are spawned on the ground once it has landed.
                chinookInstance.InvokeRepeating(new Action(CheckChinookLanded), 1f, 0.5f);
                chinookInstance.Invoke(new Action(() => DropSmokeGrenade(position)), 1f);
                
                EntityProtection.ModifyProtection(chinookInstance);
            }

            private void ClearChinook()
            {
                if (chinookInstance != null && !chinookInstance.IsDestroyed)
                    chinookInstance.Kill();
                
                chinookInstance = null;
            }
            
            private void DropSmokeGrenade(Vector3 position)
            {
                SmokeGrenade entity = Helpers.SpawnEntity<SmokeGrenade>("assets/prefabs/tools/smoke grenade/grenade.smoke.deployed.prefab", position, Quaternion.identity).GetComponent<SmokeGrenade>();
                entity.smokeDuration = 120f;
                entity.Spawn();
            }

            #endregion

            #region Landing

            public void CreateLandingZone()
            {
                eventLandingZone = gameObject.AddComponent<CH47LandingZone>();
            }

            #endregion

            #region Guard
            
            private void CheckChinookLanded()
            {
                if (chinookInstance == null || chinookInstance.IsDestroyed || _guardsDeployed)
                    return;

                _landingWaitSeconds += 0.5f;
                Vector3 landing = eventLandingZone != null ? eventLandingZone.transform.position : eventSpawn;
                Vector3 heli = chinookInstance.transform.position;
                float flat = Vector2.Distance(new Vector2(heli.x, heli.z), new Vector2(landing.x, landing.z));
                bool touchedDown = flat <= 25f && heli.y - landing.y <= 8f;

                // fallback: never leave an event without guards, even if the chinook hovers instead of landing
                if (!touchedDown && _landingWaitSeconds < 90f)
                    return;

                _guardsDeployed = true;
                chinookInstance.CancelInvoke(new Action(CheckChinookLanded));
                DeployGuardsOnGround(landing);
                chinookInstance.Invoke(new Action(SendChinookAway), 5f);
            }

            private void DeployGuardsOnGround(Vector3 landing)
            {
                int num = Mathf.Clamp(_guardAmount, 1, 12);
                for (int i = 0; i < num; i++)
                {
                    Vector3 offset = Quaternion.Euler(0f, 360f * i / num, 0f) * Vector3.forward * UnityEngine.Random.Range(5f, 8f);
                    Vector3 position = landing + offset;
                    position.y = Mathf.Max(TerrainMeta.HeightMap.GetHeight(position), landing.y);
                    SpawnGroundGuard(position);
                }
            }

            private void SpawnGroundGuard(Vector3 position)
            {
                Vector3 homePosition = eventSpawn.GetPointAround(2f);
                _guardConfig.Parsed["HomePosition"] = homePosition.ToString();
                _guardConfig.Parsed["Kit"] = _guardConfig.Kits?.Length > 0 ? _guardConfig.Kits.GetRandom() : string.Empty;

                ScientistNPC entity = _trySpawnNpc(position, _guardConfig.Parsed);
                if (entity == null || entity.IsDestroyed)
                    return;

                entity.finalDestination = homePosition;
                CacheGuardInstance(entity);

                // same orders the guards used to get when they left the chinook; the brain needs a moment to start
                entity.Invoke(() =>
                {
                    if (entity == null || entity.IsDestroyed || entity.Brain == null)
                        return;
                    entity.Brain.Navigator.ForceToGround();
                    entity.Brain.Navigator.SetDestination(homePosition);
                    entity.Brain.SwitchToState(AIState.MoveToVector3, -1);
                }, 1f);
            }

            private void SendChinookAway()
            {
                CH47HelicopterAIController chinook = chinookInstance;
                if (chinook == null || chinook.IsDestroyed)
                    return;

                chinook.ClearLandingTarget();
                chinook.SetMinHoverHeight(150f);
                chinook.EnableFacingOverride(false);
                chinook.SetMoveTarget(chinook.transform.position + Vector3.up * 100f);

                if (!chinook.TryGetComponent(out CH47AIBrain ch47AIBrain))
                    return;

                ch47AIBrain.ResetState();
                ch47AIBrain.SwitchToState(AIState.Egress, ch47AIBrain.AIDesign.DefaultStateContainerID);
                ch47AIBrain.Think(0.0f);
            }

            private void SpawnGuards(CH47HelicopterAIController chinook, int numToSpawn)
            {
                int num = Mathf.Clamp(numToSpawn, 1, chinook.mountPoints.Count);
                
                for (int i = 0; i < 2; i++)
                    SpawnGuard(chinook, chinook.transform.position + chinook.transform.forward * 10f);

                num -= 2;
                
                if (num <= 0)
                    return;
                
                for (int i = 0; i < num; i++)
                    SpawnGuard(chinook, chinook.transform.position - chinook.transform.forward * 15f);
            }

            private void SpawnGuard(BaseMountable mountable, Vector3 position)
            {
                Vector3 homePosition = eventSpawn.GetPointAround(2f);
                _guardConfig.Parsed["HomePosition"] = homePosition.ToString();
                _guardConfig.Parsed["Kit"] = _guardConfig.Kits?.Length > 0 ? _guardConfig.Kits.GetRandom() : string.Empty;
                
                ScientistNPC entity = _trySpawnNpc(position, _guardConfig.Parsed);
                if (entity == null || entity.IsDestroyed)
                    return;
                
                entity.finalDestination = homePosition;
                
                CacheGuardInstance(entity);
                
                mountable.AttemptMount(entity, false);
            }
            
            public void ClearGuards()
            {
                for (int i = spawnInstances.Count - 1; i >= 0; i--)
                {
                    BaseEntity entity = spawnInstances[i];
                    if (entity != null && !entity.IsDestroyed)
                        entity.Kill();
                }
                
                spawnInstances.Clear();
            }
            
            #endregion
            
            #region Cache

            private void CacheGuardInstance(BaseEntity entity)
            {
                spawnInstances.Add(entity);
                EntityCache.CreateEntity(entity.net.ID, this);
            }

            private void RemoveGuardInstance(BaseEntity entity)
            {
                spawnInstances.Remove(entity);
                EntityCache.RemoveEntity(entity.net.ID);
            }

            #endregion
            
            #region Oxide Hooks
            
            public void OnGuardDeath(ScientistNPC npc, BasePlayer player)
            {
                RemoveGuardInstance(npc);
                
                if (HasGuards())
                    return;
                
                winningPlayer = player;
                CheckEvent();
            }
            
            #endregion
            
            #region Debug Info

            public void DisplayInfo(BasePlayer player, float duration)
            {
                const string landingPosText = "Landing Position";
                const string chinookPosText = "Chinook Position";
                const string boundsPosText = "Bounds Position";
                
                DebugDraw.WithTemporaryAdmin(player, x =>
                {
                    DebugDraw.Text(x, transform.position, landingPosText, Color.magenta, duration);
                    DebugDraw.Text(x, chinookPosition, chinookPosText, Color.green, duration);
                    DebugDraw.Line(x, chinookPosition, eventLandingZone.transform.position, Color.yellow, duration);
                    DebugDraw.Text(x, _eventBounds.position, boundsPosText, Color.cyan, duration);
                    DebugDraw.Cube(x, _eventBounds.position, _eventBounds.rotation, _eventBounds.extents, Color.blue, duration);
                });
            }

            #endregion
        }
        
        #endregion
        
        #region External Hooks

        private object? OnNpcRustEdit(ScientistNPC npc)
        {
            if (npc?.net == null)
                return null;
            
            return EntityCache.HasEntity(npc.net?.ID ?? default) ? _objTrue : null;
        }

        #endregion
        
        #region Entity Cache

        private static class EntityCache
        {
            public static Dictionary<NetworkableId, BradleyGuardsEvent> Entities { get; private set; } = new();
            
            public static void OnUnload() => Entities.Clear();
            
            public static BradleyGuardsEvent? FindEventByEntity(NetworkableId id)
            {
                Entities.TryGetValue(id, out BradleyGuardsEvent? component);
                return component;
            }
            
            public static bool HasEntity(NetworkableId id) => Entities.ContainsKey(id);

            public static void CreateEntity(NetworkableId id, BradleyGuardsEvent component) => Entities.Add(id, component);

            public static void RemoveEntity(NetworkableId id) => Entities.Remove(id);
        }

        #endregion
        
        #region Entity Protection

        private static class EntityProtection
        {
            public static ProtectionProperties Instance { get; private set;  }
            
            public static void Initialize()
            {
                Instance = ScriptableObject.CreateInstance<ProtectionProperties>();
                Instance.name = "Bradley_Guards_Protection";
                Instance.Add(1);
            }

            public static void OnUnload()
            {
                if (Instance == null)
                    return;
                
                UnityEngine.Object.Destroy(Instance);
                Instance = null;
            }

            public static void ModifyProtection(BaseCombatEntity combatEntity)
            {
                if (combatEntity != null && !combatEntity.IsDestroyed) 
                    combatEntity.baseProtection = Instance;
            }
        }

        #endregion
        
        #region Notification
        
        private static class Notification
        {
            public static string GetMessage(string langKey, string? userId = null, params object[] args)
            {
                string message = userId != null ? _getMessage(langKey, userId) : _getMessage(langKey, null);
                return args?.Length > 0 ? string.Format(message, args) : message;
            }

            public static void MessagePlayer(ConsoleSystem.Arg arg, string langKey, params object[] args)
            {
                if (arg == null) 
                    return;
                
                string message = GetMessage(langKey, null, args);
                arg.ReplyWith(message);
            }

            public static void MessagePlayer(BasePlayer player, string langKey, params object[] args)
            {
                if (player == null) 
                    return;
                
                string message = GetMessage(langKey, player.UserIDString, args);
                player.ChatMessage(message);
            }

            public static void MessagePlayers(string langKey, params object[] args)
            {
                StringBuilder sb = Facepunch.Pool.Get<StringBuilder>();

                try
                {
                    if (_configData.ChatSetting.EnablePrefix) 
                        sb.Append(GetMessage(LangKeys.PREFIX));
                    
                    if (args?.Length > 0) 
                        sb.AppendFormat(_getMessage(langKey, null), args);
                    else
                        sb.AppendFormat(_getMessage(langKey, null));
                    
                    string message = sb.ToString();
                    
                    if (_configData.ChatSetting.Enabled) 
                        ConsoleNetwork.BroadcastToAllClients("chat.add", 2, _configData.ChatSetting.ChatIcon, message);
                    
                    if (_configData.ToastSetting.Enabled) 
                        ConsoleNetwork.BroadcastToAllClients("gametip.showtoast_translated", (int)_configData.ToastSetting.Style, null, message, false);
                
                    if (!_configData.GuiaSetting.Enabled)
                        return;
                    
                    _sendGuiNotification(message, _configData.GuiaSetting.BackgroundColor, _configData.GuiaSetting.TextColor, null, 0.03f);
                }
                finally
                {
                    Facepunch.Pool.FreeUnmanaged(ref sb);
                }
            }
        }
        
        #endregion
        
        #region Chat Command
        
        private void EventCommands(BasePlayer player, string command, string[] args)
        {
            if (!permission.UserHasPermission(player.UserIDString, PERM_USE))
            {
                Notification.MessagePlayer(player, LangKeys.NO_PERMISSION);
                return;
            }
            
            if (args.Length < 2)
            {
                EventHelpText(player, command, _configData.DebugDuration);
                return;
            }
            
            string optionName = args[1];
            if (optionName.Equals("enable"))
            {
                if (args.Length != 3)
                {
                    EventHelpText(player, command, _configData.DebugDuration);
                    return;
                }
                
                EventEntry eventEntry = FindEventByDisplayName(args[0]);
                if (eventEntry == null)
                {
                    Notification.MessagePlayer(player, LangKeys.EVENT_NOT_FOUND);
                    return;
                }
                
                if (!bool.TryParse(args[2], out bool value))
                {
                    Notification.MessagePlayer(player, LangKeys.INVALID_BOOLEAN);
                    return;
                }
                
                eventEntry.EnabledEvent = value;
                SaveData();
                
                Notification.MessagePlayer(player, LangKeys.EVENT_UPDATED);
                return;
            }
            
            if (optionName.Equals("display"))
            {
                if (args.Length < 3)
                {
                    EventHelpText(player, command, _configData.DebugDuration);
                    return;
                }
                
                EventEntry eventEntry = FindEventByDisplayName(args[0]);
                if (eventEntry == null)
                {
                    Notification.MessagePlayer(player, LangKeys.EVENT_NOT_FOUND);
                    return;
                }

                string displayName = string.Join(" ", args.Skip(2));
                if (string.IsNullOrEmpty(displayName))
                {
                    Notification.MessagePlayer(player, LangKeys.INVALID_DISPLAY_NAME);
                    return;
                }
                Match match = _strRegex.Match(displayName);
                if (!match.Success)
                {
                    Notification.MessagePlayer(player, LangKeys.INVALID_DISPLAY_NAME);
                    return;
                }
                
                eventEntry.DisplayName = match.Value;
                SaveData();
                
                Notification.MessagePlayer(player, LangKeys.EVENT_UPDATED);
                return;
            }
            
            if (optionName.Equals("guard-amount"))
            {
                if (args.Length < 3)
                {
                    EventHelpText(player, command, _configData.DebugDuration);
                    return;
                }
                
                EventEntry eventEntry = FindEventByDisplayName(args[0]);
                if (eventEntry == null)
                {
                    Notification.MessagePlayer(player, LangKeys.EVENT_NOT_FOUND);
                    return;
                }
                
                if (!int.TryParse(args[3], out int value))
                {
                    Notification.MessagePlayer(player, LangKeys.INVALID_GUARD_AMOUNT);
                    return;
                }
                
                eventEntry.GuardAmount = Math.Clamp(value, 2, 10);
                SaveData();
                
                Notification.MessagePlayer(player, LangKeys.EVENT_UPDATED);
                return;
            }
            
            if (optionName.Equals("guard-loadout"))
            {
                EventEntry eventEntry = FindEventByDisplayName(args[0]);
                if (eventEntry == null)
                {
                    Notification.MessagePlayer(player, LangKeys.EVENT_NOT_FOUND);
                    return;
                }
                
                eventEntry.GuardProfile.BeltItems = GuardConfig.BeltEntry.SaveItems(player.inventory.containerBelt);
                eventEntry.GuardProfile.WearItems = GuardConfig.WearEntry.SaveItems(player.inventory.containerWear);
                eventEntry.GuardProfile.CacheConfig();
                SaveData();
                
                Notification.MessagePlayer(player, LangKeys.EVENT_UPDATED);
                return;
            }
            
            if (optionName.Equals("debug"))
            {
                BradleyGuardsEvent guardsEvent = BradleyGuardsEvent.GetByMonument(args[0]);
                if (guardsEvent == null)
                {
                    Notification.MessagePlayer(player, LangKeys.EVENT_NOT_FOUND);
                    return;
                }
                
                float duration = args?.Length == 3 && float.TryParse(args[2], out float value) ? Math.Clamp(value, 1f, 300f) : _configData.DebugDuration;
                
                guardsEvent.DisplayInfo(player, duration);
                
                Notification.MessagePlayer(player, LangKeys.EVENT_DEBUG, duration);
                return;
            }
            
            EventHelpText(player, command, _configData.DebugDuration);
        }

        private void EventHelpText(BasePlayer player, string command, float duration)
        {
            StringBuilder sb = Facepunch.Pool.Get<StringBuilder>();
            
            try
            {
                sb.Clear();
                sb.AppendFormat(lang.GetMessage(LangKeys.PREFIX, this, player.UserIDString))
                    .AppendFormat(lang.GetMessage(LangKeys.HELP_EVENT_ENABLE, this, player.UserIDString), command)
                    .AppendFormat(lang.GetMessage(LangKeys.HELP_EVENT_NAME, this, player.UserIDString), command)
                    .AppendFormat(lang.GetMessage(LangKeys.HELP_EVENT_DEBUG, this, player.UserIDString), command, duration)
                    .AppendFormat(lang.GetMessage(LangKeys.HELP_GUARD_AMOUNT, this, player.UserIDString), command)
                    .AppendFormat(lang.GetMessage(LangKeys.HELP_GUARD_LOADOUT, this, player.UserIDString), command);
            
                player.ChatMessage(sb.ToString());
            }
            finally
            {
                sb.Clear();
                Facepunch.Pool.FreeUnmanaged(ref sb);
            }
        }

        #endregion
        
        #region Hook Subscribing

        private bool SubscribeToHooks(bool shouldSub)
        {
            if (shouldSub)
            {
                Subscribe(nameof(OnEntityDismounted));
                return true;
            }
            
            Unsubscribe(nameof(OnEntityDismounted));
            return false;
        }

        #endregion

        #region Debug Stopwatch

        private class DebugStopwatch : IDisposable
        {
            private Stopwatch _stopwatch;
            private string _format;

            public DebugStopwatch(string format)
            {
                _format = format;
                
                _stopwatch = Facepunch.Pool.Get<Stopwatch>();
                _stopwatch.Start();
            }

            public void Dispose()
            {
                float elapsed = _stopwatch.ElapsedMilliseconds;
                
                Interface.Oxide.LogDebug(_format, elapsed);
                
                _stopwatch.Stop();
                Facepunch.Pool.FreeUnmanaged(ref _stopwatch);
            }
        }

        #endregion

        #region Helpers

        private static class Helpers
        {
            public static T CreateObjectWithComponent<T>(Vector3 position, Quaternion rotation, string name) where T : MonoBehaviour
            {
                return new GameObject(name)
                {
                    layer = (int)Layer.Reserved1,
                    transform =
                    {
                        position = position,
                        rotation = rotation

I have the same problem—there are no soldiers, and it says they've been eliminated.

see my patch

Ludek

I have the same problem—there are no soldiers, and it says they've been eliminated.

MNdwpVT1OAcDNc1.jpg gertKaapo

see my patch

Isn't something missing here?
13:13:11 Error while compiling BradleyGuards: } expected | Line: 1636, Pos: 44
Error while compiling BradleyGuards: } expected | Line: 1636, Pos: 44

Ludek

Isn't something missing here?
13:13:11 Error while compiling BradleyGuards: } expected | Line: 1636, Pos: 44
Error while compiling BradleyGuards: } expected | Line: 1636, Pos: 44

Correction: If I just replace this part with the original version, it works. I thought it was the entire plugin. Thanks

Yes you are right . 

the editor cuts the whole code pasting good you made it work 

Ludek

Correction: If I just replace this part with the original version, it works. I thought it was the entire plugin. Thanks