using Rust; using Rust.Ai; using Rust.Registry; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Network; using Network.Visibility; using Oxide.Core; using Oxide.Core.Configuration; using Oxide.Core.Plugins; using Oxide.Game.Rust.Cui; using Oxide.Plugins; using ProtoBuf; using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Text; using UnityEngine; using UnityEngine.AI; using Facepunch; namespace Oxide.Plugins { [Info("Bradley Guards", "Krungh Crow", "1.6.6", ResourceId = 183)] [Description("Bradley spawns A tank Crew when destroyed")] class BradleyGuards : RustPlugin { #region Changelogs and ToDo /******************************************************************************************* * * v1.1.2 : fixed Guard npc not carrying a weapon if kit is not existing * v1.1.3 : BradleyGuards and npc will not target each other * v1.1.4 : Patched for BradleyTiers * v1.1.5 : Added that Guards will ignore sleepers * : Improved Mono with extra waterchecks and removes the Guards if they happen to walk into water (submerged) * : Improved the spawning if in buildings and will find a new spawn location * : Some coding cleanup (regions) * : Guards will not recieve fireball damage from the bradley fires * v1.2.0 : Added ResourceID * : Performance Update * v1.2.1 : Fixed Bradley Guards despawn on plugin un/reload * : Fixed npc from targeting the Bradley Guards through global settings * v1.2.2 : Patched for december 2nd rust update. * v1.2.3 : Fixed oxide mixing up HumanNPC plugin(same name) and npc type * v1.3.0 : Fix for NPC attackrange * v1.3.1 : Patched various AI behaviour * : NPC now ignore players in safezone * : Fixed NPC being Idle after spawning * : Changed NPC spawnheight * : Switched from junkpile to roam scientists * : Skips HP and Crate settings if using Monument Bradley plugin * v1.3.2 : Added Navhit check on npc spawn * : Npc are forced on navmesh * : Added npc spawnradius (10 by default) in config * v1.3.3 : Patched for conflict with BotReSpawn (by steenamaroo) * v1.3.4 : if Bradley spawns with less then 100hp destoys it * v1.4.0 : Added support for Convoy * : Added MLRS rockets on lastditcheffort * Side effect samsites can target the rockets * : Removed Bradley health check and kill * : Added API : bool IsBradleyNpc(global::HumanNPC npc) * * object OnEntityDeath(global::HumanNPC npc, HitInfo info) { if (npc == null) return null; if (BradleyGuards.Call("IsBradleyNpc", npc)) { Puts($"Target : {npc} net.ID : [{npc.net.ID}] Event : BradleyGuards NPC"); } return null; } * v1.4.1 : Possible fix for the new nre * : Added better check if Convoy is installed * : Added (Bradley Crew Body to Bags) to destroy corpse and drops the npc loot * : Updated msg system (no need to redo language files) * : Fixed endless mlrs rockets when amount is set to 0 * : Fixed npc will despawn instead of die when life duration ends * : Fixed the Radio sound when npc are killed * v1.4.2 : Possible fix for runaway npc * : Added support for BetterNpcNames * v1.4.3 : Added support for ArmoredTrain * : Pre patched for ArmoredTrain plugin update * v1.4.4 : Hotfix for using same triggers * : Fixed Max crate spawns * : Fixed Health * : Fixed exploit npc corpses having their gears when using BetterNpcNames(v1.0.3) * v1.4.5 : Possible fix for Targeting when BG and ArmoredTrain is installed * : BG ignores max amount of bradleycrates to spawn when the bradley is ArmoredTrain APC * v1.4.6 : Static samsites will ignore the MLRS rockets * : Added MLRS rocket radius * : Added Last Ditch Effort Hardmode * : Repositioned console notification BG event started * v1.4.7 : Removed ownerid checks to avoid locked bradleys from other plugins * v1.4.8 : Fix for compile issues * v1.4.9 : Patched for 6/7/2023 Rust Update * v1.5.0 : Possible Roaming fix * v1.5.1 : Bradley ignores sleepers or players in safezone * : Removed admin perm * : Fixed permissions * : Possible fix for npc strip issue on Carbon Servers * v1.5.2 : Possible fix for runaway npc * : When going vanished npc should return roaming unless attacked first * : Fixed Bradley targeting players in Vanish when BradleyOptions is not loaded * : Replaced Fire rockets for the actual Molotovs * : Removed some redundant code * : Possible fix for NRE strip * : Molotovs will not spamm trigger the nades and mollotovs thrown by the bradley * v1.5.3 : Patch for bradleytargeting nre * v1.6.0 : External plugin cfg changed to use triggers incl npc spawning (true/false) * : Optimised checks for Convoy,ArmoredTrain and Satdish/HarborEvent * : Reworked the NPC spawn calls to be able to be used as Api for BradleyEvents/BradleyTiers * : Fixed APC target override for event/custom APC's * : Added Option to replace molotovs with firerockets * : Added support for BradleyEvents and BradleyDrops plugins * v1.6.1 : Optimised OnSamSiteTarget trigger * Updated API IsBradleyNpc now returns null or true * Added API : OnBradleyNPCDeath(global::HumanNPC npc, HitInfo info) * Added API : OnBradleyNPCGotHit(global::HumanNPC npc, HitInfo info) * v1.6.2 : Changed npc type to (scientistnpc_bradleyapc_monument) * v1.6.3 : Reverted back to scientistnpc_roam since new one was removed * v1.6.5 : Patched for dec rust update * v1.6.6 : Patched for fires to work with TruePVE (patched by Nivex) * *******************************************************************************************/ #endregion [PluginReference] Plugin ArmoredTrain ,BetterNpcNames, Bradley, BradleyTiers, BradleyEvents, Convoy, Kits; #region OnServerInitialized void OnServerInitialized() => instance = this; #endregion #region Variables private readonly List _Crew = new List(); const ulong chaticon = 76561198410558650; const string sci = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_roam.prefab"; //const string sci = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_bradley.prefab"; //const string sci = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_bradley_heavy.prefab"; const string bomb1 = "assets/prefabs/weapons/beancan grenade/grenade.beancan.deployed.prefab"; const string bomb2 = "assets/prefabs/weapons/f1 grenade/grenade.f1.deployed.prefab"; const string molotov = "assets/prefabs/weapons/molotov cocktail/grenade.molotov.deployed.prefab"; const string rocketfire = "assets/prefabs/ammo/rocket/rocket_fire.prefab"; const string MLRS = "assets/content/vehicles/mlrs/rocket_mlrs.prefab"; const string ShowMessages_Perm = "bradleyguards.ShowMessages"; const string ShowKillMessages_Perm = "bradleyguards.ShowKillMessages"; string prefix; bool NPCTarget; #endregion #region Mono public static BradleyGuards instance; public static Dictionary SpawnedCrew { get; set; } = new Dictionary(); void Unload() { RemoveAllNpc(); } public class BradleyCrew : FacepunchBehaviour { public global::HumanNPC npc; public bool ReturningToHome = false; public bool isRoaming = true; public Vector3 SpawnPoint; void Start() { npc = GetComponent(); InvokeRepeating("GoHome", 1.0f, 5.0f); Invoke(nameof(_UseBrain), 0.1f); } public void _UseBrain() { #region navigation npc.Brain.Navigator.Agent.agentTypeID = -1372625422; npc.Brain.Navigator.DefaultArea = "Walkable"; npc.Brain.Navigator.Agent.autoRepath = true; npc.Brain.Navigator.enabled = true; npc.Brain.Navigator.CanUseNavMesh = true; npc.Brain.Navigator.BestCoverPointMaxDistance = instance.configData.Event.CrewRoam /2; npc.Brain.Navigator.BestRoamPointMaxDistance = instance.configData.Event.CrewRoam; npc.Brain.Navigator.MaxRoamDistanceFromHome = instance.configData.Event.CrewRoam; npc.Brain.Navigator.Init(npc, npc.Brain.Navigator.Agent); npc.Brain.Navigator.SetDestination(SpawnPoint, BaseNavigator.NavigationSpeed.Slow, 0f, 0f); #endregion #region senses & Targeting npc.Brain.ForceSetAge(0); npc.Brain.AllowedToSleep = false; npc.Brain.sleeping = false; npc.Brain.SenseRange = 30f; npc.Brain.ListenRange = 40f; npc.Brain.TargetLostRange = 25f; npc.Brain.HostileTargetsOnly = false; npc.Brain.IgnoreSafeZonePlayers = true; #endregion } void GoHome() { if (npc == null || npc.IsDestroyed || npc.isMounted) return; if (!npc.HasBrain) return; if (npc.Brain.Senses.Memory.Targets.Count > 0) { for (var i = 0; i < npc.Brain.Senses.Memory.Targets.Count; i++) { BaseEntity target = npc.Brain.Senses.Memory.Targets[i]; BasePlayer player = target as BasePlayer; if (target == null || !player.IsAlive()) { WipeMemory(); ReturningToHome = true; isRoaming = false; return; } if (npc.Distance(player.transform.position) > 40f) { WipeMemory(); ReturningToHome = true; isRoaming = false; return; } } } var distanceHome = Vector3.Distance(npc.transform.position, SpawnPoint); if (ReturningToHome == false) { if (isRoaming == true && distanceHome > instance.configData.Event.CrewRoam) { ReturningToHome = true; isRoaming = false; return; } if (isRoaming == true && distanceHome < instance.configData.Event.CrewRoam) { Vector3 random = UnityEngine.Random.insideUnitCircle.normalized * 10f; Vector3 newPos = instance.GetNavPoint(SpawnPoint + new Vector3(random.x, 0f, random.y)); SettargetDestination(newPos); return; } } if (ReturningToHome && distanceHome > 2) { if (npc.Brain.Navigator.Destination == SpawnPoint) return; WipeMemory(); SettargetDestination(SpawnPoint); return; } ReturningToHome = false; isRoaming = true; } private void SettargetDestination(Vector3 position) { npc.Brain.Navigator.Destination = position; npc.Brain.Navigator.SetDestination(position, BaseNavigator.NavigationSpeed.Slow, 0f, 0f); } void WipeMemory() { if (!npc.HasBrain) return; npc.Brain.Senses.Players.Clear(); npc.Brain.Senses.Memory.Players.Clear(); npc.Brain.Senses.Memory.Targets.Clear(); npc.Brain.Senses.Memory.Threats.Clear(); npc.Brain.Senses.Memory.LOS.Clear(); npc.Brain.Senses.Memory.All.Clear(); } void OnDestroy() { if (npc != null && !npc.IsDestroyed) { npc.Kill(); } CancelInvoke("GoHome"); CancelInvoke(nameof(_UseBrain)); } } #endregion #region Configuration void Init() { if (!LoadConfigVariables()) { Puts("Config file issue detected. Please delete file, or check syntax and fix."); return; } permission.RegisterPermission(ShowMessages_Perm, this); permission.RegisterPermission(ShowKillMessages_Perm, this); NPCTarget = configData.NPCTarget; prefix = lang.GetMessage("Prefix", this); } private ConfigData configData; class ConfigData { [JsonProperty(PropertyName = "Global NPC dont target")] public bool NPCTarget = false; [JsonProperty(PropertyName = "External Plugins")] public SettingsExternal External = new SettingsExternal(); [JsonProperty(PropertyName = "Bradley Settings")] public SettingsBradley Bradley = new SettingsBradley(); [JsonProperty(PropertyName = "Bradley Loot")] public SettingsBradleyLoot BradleyLoot = new SettingsBradleyLoot(); [JsonProperty(PropertyName = "Bradley Canon")] public SettingsBradleyCanon BradleyCanon = new SettingsBradleyCanon(); [JsonProperty(PropertyName = "Bradley Machinegun")] public SettingsBradleyMachinegun BradleyMachineGun = new SettingsBradleyMachinegun(); [JsonProperty(PropertyName = "Event Settings")] public SettingsEvent Event = new SettingsEvent(); [JsonProperty(PropertyName = "Tank Crew Driver")] public TankCrewDriver TankCrewDriver = new TankCrewDriver(); [JsonProperty(PropertyName = "Tank Crew Guards")] public TankCrewGuards TankCrewGuards = new TankCrewGuards(); [JsonProperty(PropertyName = "Tank Crew Gunners")] public TankCrewGunner TankCrewGunner = new TankCrewGunner(); } class SettingsExternal { [JsonProperty(PropertyName = "Armored Train : Can trigger Events")] public bool CanTriggerTrain = false; [JsonProperty(PropertyName = "Convoy : Can trigger Events")] public bool CanTriggerConv = false; [JsonProperty(PropertyName = "SatDish/Harbor Event : Can trigger Events")] public bool CanTriggerSatdish = false; [JsonProperty(PropertyName = "BradleyDrops : Can trigger Events")] public bool CanTriggerBradleyDrops = false; [JsonProperty(PropertyName = "BetterNpcNames : Driver Title")] public string DriverTitle = "Driver"; [JsonProperty(PropertyName = "BetterNpcNames : Guard Title")] public string GuardTitle = "Commander"; [JsonProperty(PropertyName = "BetterNpcNames : Gunner Title")] public string GunnerTitle = "Gunner"; } class SettingsBradley { [JsonProperty(PropertyName = "Change Values")] public bool BSettingsUse = true; [JsonProperty(PropertyName = "Bradley Health")] public int BradleyHealth = 2000; [JsonProperty(PropertyName = "Bradley Max Fire Range")] public int BradleyMaxFireRange = 100; [JsonProperty(PropertyName = "Bradley Throttle Responce")] public float BradleySpeed = 1.0f; } class SettingsBradleyCanon { [JsonProperty(PropertyName = "Change Values")] public bool BCSettingsUse = true; [JsonProperty(PropertyName = "Bradley Canon Fire delay")] public float BradleyCanonFireDelay = 0.3f; [JsonProperty(PropertyName = "Bradley Canon Firerate")] public float BradleyCanonFireRate = 0.25f; } class SettingsBradleyLoot { [JsonProperty(PropertyName = "Change Values")] public bool LootSettingsUse = true; [JsonProperty(PropertyName = "Bradley Max crates after kill")] public int BradleyMaxCratesAfterKill = 4; } class SettingsBradleyMachinegun { [JsonProperty(PropertyName = "Change Values")] public bool BMGSettingsUse = true; [JsonProperty(PropertyName = "Bradley Machinegun Bullet Damage")] public int BradleyMachinegunBulletDamage = 15; [JsonProperty(PropertyName = "Bradley Machinegun Firerate")] public float BradleyMachinegunFirerate = 0.06667f; } class SettingsEvent { [JsonProperty(PropertyName = "Bradley Crew Max Spawn Distance")] public int CrewSpawnRadius = 10; [JsonProperty(PropertyName = "Bradley Crew Max Roam Distance")] public int CrewRoam = 50; [JsonProperty(PropertyName = "Bradley Crew Body to Bags")] public bool CrewBodybags = false; [JsonProperty(PropertyName = "Max throwing range of a Grenade")] public float MaxThrowingRangeOfAGrenade = 25.0f; [JsonProperty(PropertyName = "Max Grenades per trigger")] public int GrenadeAmount = 1; [JsonProperty(PropertyName = "Max throwing range of a Molotov")] public float MaxThrowingRangeOfAMolotov = 5.0f; [JsonProperty(PropertyName = "Max Molotovs per trigger")] public int MolotovAmount = 1; [JsonProperty(PropertyName = "Use Firerockets (instead of Molotovs)")] public bool UseFireRockets = false; [JsonProperty(PropertyName = "Hard Mode : Throws towards player (Grenades)")] public bool GrenadeHardMode = true; [JsonProperty(PropertyName = "Hard Mode : Max Grenades per trigger")] public int GrenadeAmountHM = 1; [JsonProperty(PropertyName = "Hard Mode : Max radius of a Grenade on player")] public float MaxThrowingRangeOfAGrenadeHM = 15.0f; [JsonProperty(PropertyName = "Hard Mode : Throws towards player (Molotovs)")] public bool MolotovHardMode = true; [JsonProperty(PropertyName = "Hard Mode : Max Molotovs per trigger")] public int MolotovAmountAmountHM = 1; [JsonProperty(PropertyName = "Hard Mode : Max radius of a Molotov on player")] public float MaxThrowingRangeOfAMolotovHM = 15.0f; [JsonProperty(PropertyName = "Napalm Support")] public bool DropSupportNapalmUse = true; [JsonProperty(PropertyName = "Napalm Support Area Radius")] public float DropSupportNapalmRange = 35.0f; [JsonProperty(PropertyName = "Napalm Support Rocket Amount")] public int DropSupportNapalmAmount = 3; [JsonProperty(PropertyName = "Napalm Support Rocket Height")] public int DropSupportNapalmHeight = 50; [JsonProperty(PropertyName = "Last Ditch Effort Rocket Amount")] public int LastDitchEffortNapalmAmount = 5; [JsonProperty(PropertyName = "Last Ditch Effort Grenade Amount")] public int LastDitchEffortGrenadeAmount = 5; [JsonProperty(PropertyName = "Last Ditch Effort MLRS rocket Radius")] public int LastDitchEffortMLRSRadius = 10; [JsonProperty(PropertyName = "Last Ditch Effort MLRS rocket Amount")] public int LastDitchEffortMLRSAmount = 5; [JsonProperty(PropertyName = "Last Ditch Effort Hard Mode : targets player location")] public bool LastDitchEffortHardMode = false; } class TankCrewDriver { [JsonProperty(PropertyName = "Tank Driver Health")] public float TankDriverHealth = 450.0f; [JsonProperty(PropertyName = "Tank Driver Lifetime (minutes)")] public float DriverLife = 10f; [JsonProperty(PropertyName = "Tank Driver Damage multiplier")] public float TankDriverDamageScale = 1.0f; [JsonProperty(PropertyName = "Tank Driver Spawn Chance 0-1")] public float TankDriverSpawnChance = 1.0f; [JsonProperty(PropertyName = "Tank Driver Spawn Amount")] public int TankDriverAmount = 1; [JsonProperty(PropertyName = "Tank Driver Use Outfit")] public bool UseOutfit1 = true; [JsonProperty(PropertyName = "Tank Driver Use other gun with outfit")] public bool UseOutfitG1 = false; [JsonProperty(PropertyName = "Tank Driver gun short prefabname")] public string UseOutfitGName1 = "smg.mp5"; [JsonProperty(PropertyName = "Tank Driver gun skin id")] public ulong UseOutfitGSkin1 = 0; [JsonProperty(PropertyName = "Tank Driver Use kit (clothing)")] public bool UseKit1 = false; [JsonProperty(PropertyName = "Tank Driver Kit ID")] public string KitName1 = ""; } class TankCrewGuards { [JsonProperty(PropertyName = "Tank Guards Health")] public float TankGuardsHealth = 800; [JsonProperty(PropertyName = "Tank Guards Lifetime (minutes)")] public float GuardsLife = 10f; [JsonProperty(PropertyName = "Tank Guards Damage multiplier")] public float TankGuardsDamageScale = 1.0f; [JsonProperty(PropertyName = "Tank Guards Spawn Chance 0-1")] public float TankGuardsSpawnChance = 1.0f; [JsonProperty(PropertyName = "Tank Guards Spawn Amount")] public int TankGuardsAmount = 2; [JsonProperty(PropertyName = "Tank Guards Use Outfit")] public bool UseOutfit2 = true; [JsonProperty(PropertyName = "Tank Guards Use other gun with outfit")] public bool UseOutfitG2 = false; [JsonProperty(PropertyName = "Tank Guards gun short prefabname")] public string UseOutfitGName2 = "smg.mp5"; [JsonProperty(PropertyName = "Tank Guards gun skin id")] public ulong UseOutfitGSkin2 = 0; [JsonProperty(PropertyName = "Tank Guards Use kit (clothing)")] public bool UseKit2 = false; [JsonProperty(PropertyName = "Tank Guards Kit ID")] public string KitName2 = ""; } class TankCrewGunner { [JsonProperty(PropertyName = "Tank Gunners Health")] public float TankGunnersHealth = 600; [JsonProperty(PropertyName = "Tank Gunners Lifetime (minutes)")] public float GunnersLife = 10f; [JsonProperty(PropertyName = "Tank Gunners Damage multiplier")] public float TankGunnersDamageScale = 1.0f; [JsonProperty(PropertyName = "Tank Gunners Spawn Chance 0-1")] public float TankGunnersSpawnChance = 1.0f; [JsonProperty(PropertyName = "Tank Gunners Spawn Amount")] public int TankGunnersAmount = 2; [JsonProperty(PropertyName = "Tank Gunners Use Outfit")] public bool UseOutfit3 = true; [JsonProperty(PropertyName = "Tank Gunners Use other gun with outfit")] public bool UseOutfitG3 = false; [JsonProperty(PropertyName = "Tank Gunners gun short prefabname")] public string UseOutfitGName3 = "smg.mp5"; [JsonProperty(PropertyName = "Tank Gunners gun skin id")] public ulong UseOutfitGSkin3 = 0; [JsonProperty(PropertyName = "Tank Gunners Use kit (clothing)")] public bool UseKit3 = false; [JsonProperty(PropertyName = "Tank Gunners Kit ID")] public string KitName3 = ""; } private bool LoadConfigVariables() { try { configData = Config.ReadObject(); } catch { return false; } SaveConf(); return true; } protected override void LoadDefaultConfig() { Puts("Fresh install detected Creating a new config file."); configData = new ConfigData(); SaveConf(); } void SaveConf() => Config.WriteObject(configData, true); #endregion #region LanguageAPI protected override void LoadDefaultMessages() { lang.RegisterMessages(new Dictionary { ["Prefix"] = "[BradleyGuards] ", ["InvalidInput"] = "Please enter a valid command!", ["Version"] = "Version : V", ["Info"] = "\nAvailable Commands\n/bgrespawncustom : Respawns all killed custom placed bradleys [RustEdit].", ["BradleyDriver"] = "Driver : Damnit i just washed it!", ["BradleyDriverBomb"] = "Driver : Catch this!", ["BradleyGuards"] = "Guard : Stay away from our Bradley!", ["BradleyGunner"] = "Gunner : Prepare to die!", ["BradleyGunnerFire"] = "Gunner : Fire in the hooole!", ["BradleyNapalmSupport"] = "Operator : Support incomming!", }, this); } #endregion #region Commands [ChatCommand("bginfo")] void cmdBgInfo(BasePlayer player, string cmd, string[] args) { Player.Message(player, msg("Version") + this.Version.ToString() + " By : " + this.Author.ToString() , chaticon); return; } #endregion #region External Hooks List BotReSpawns = new List(); void OnBotReSpawnNPCSpawned(ScientistNPC npc, string profilename, string group) => BotReSpawns.Add(npc.userID); object OnNpcKits(BasePlayer player) { if (_Crew.Contains(player.userID)) return true; return null; } #endregion #region Oxide Hooks private object OnNpcTarget(BasePlayer attacker, BasePlayer target) { if (attacker != null && _Crew.Contains(attacker.userID) && NPCTarget) { if (target.IsSleeping() || !target.userID.IsSteamId() || !target is BasePet) return true; } if (attacker != null && target != null && _Crew.Contains(target.userID) && NPCTarget) { return true; } return null; } private object OnSamSiteTarget(SamSite samsite , MLRSRocket target) { string ownerid = samsite.OwnerID.ToString(); if ((samsite.staticRespawn && ownerid == "0") && target.skinID == 29051978) return false; else if ((samsite.staticRespawn && ownerid != "0") && target.skinID == 29051978) return true; return null; } private void OnBradleyApcInitialize(BradleyAPC bradley) { if (Interface.CallHook("IsTrainBradley", bradley) != null && configData.External.CanTriggerTrain == false) { return; } if (Interface.CallHook("IsConvoyVehicle", bradley) != null && bradley.skinID == 755446 && configData.External.CanTriggerConv == false) { return; } if (Interface.CallHook("CanBradleyTiersEdit", bradley) != null && configData.External.CanTriggerSatdish == false) { return; } if (configData.Bradley.BSettingsUse) { if (BradleyTiers == false) { bradley._maxHealth = configData.Bradley.BradleyHealth; bradley.health = bradley._maxHealth; } bradley.viewDistance = configData.Bradley.BradleyMaxFireRange; bradley.searchRange = configData.Bradley.BradleyMaxFireRange; bradley.throttle = configData.Bradley.BradleySpeed; bradley.leftThrottle = bradley.throttle; bradley.rightThrottle = bradley.throttle; } if (configData.BradleyLoot.LootSettingsUse && (!BradleyTiers || bradley.skinID != 755446)) { bradley.maxCratesToSpawn = configData.BradleyLoot.BradleyMaxCratesAfterKill; } if (configData.BradleyMachineGun.BMGSettingsUse) { bradley.bulletDamage = configData.BradleyMachineGun.BradleyMachinegunBulletDamage; bradley.coaxFireRate = configData.BradleyMachineGun.BradleyMachinegunFirerate; } if (configData.BradleyCanon.BCSettingsUse) { bradley.topTurretFireRate = configData.BradleyCanon.BradleyCanonFireRate; bradley.nextTopTurretTime = configData.BradleyCanon.BradleyCanonFireDelay; } bradley.SendNetworkUpdate(); } void OnEntityKill(ScientistNPC npc) { if (npc == null) return; if (BotReSpawns.Contains(npc.userID)) BotReSpawns.Remove(npc.userID); } private object CanBradleyApcTarget(BradleyAPC bradley, BaseEntity target) { if (Interface.CallHook("IsTrainBradley" , bradley) != null && configData.External.CanTriggerTrain == false) { return null; } if (Interface.CallHook("IsConvoyVehicle" , bradley) != null && bradley.skinID == 755446 && configData.External.CanTriggerConv == false) { return null; } if (Interface.CallHook("CanBradleyTiersEdit" , bradley) != null && configData.External.CanTriggerSatdish == false) { return null; } var player = target as BasePlayer; if (player != null) { if (player is global::HumanNPC || player.IsSleeping() || player.InSafeZone()) { if (BotReSpawns.Contains(player.userID)) return null; return false; } Vector3 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; } return null; } void OnEntityDeath(BradleyAPC bradley, HitInfo info) { if (Interface.CallHook("IsTrainBradley", bradley) != null && configData.External.CanTriggerTrain == false) { return; } if (Interface.CallHook("IsConvoyVehicle", bradley) != null && bradley.skinID == 755446 && configData.External.CanTriggerConv == false) { return; } if (Interface.CallHook("CanBradleyTiersEdit", bradley) != null && configData.External.CanTriggerSatdish == false) { return; } if (Interface.CallHook("IsBradleyDrop" , bradley) != null && configData.External.CanTriggerBradleyDrops == false) { return; } if (plugins.Exists("BradleyEvents") && plugins.Exists("BradleyTiers")) { Puts("BradleyTiers and Events are running, skipping BG spawns"); return; } LogToFile("APCKills", $"{DateTime.Now:h:mm:ss tt}] {info.InitiatorPlayer} killed a BradleyAPC", this); var KillPosition = bradley.transform.position; BasePlayer player = info.InitiatorPlayer; if (UnityEngine.Random.Range(0f, 1f) <= configData.TankCrewDriver.TankDriverSpawnChance) { for (int i = 0; i < configData.TankCrewDriver.TankDriverAmount; i++) { SpawnDriver(KillPosition, configData.TankCrewDriver.TankDriverHealth, configData.TankCrewDriver.TankDriverDamageScale); } if (player != null && HasPerm(player, ShowKillMessages_Perm)) Player.Message(player, msg("BradleyDriver"), chaticon); LogToFile("APCKills", $"{DateTime.Now:h:mm:ss tt}] {info.InitiatorPlayer} {configData.TankCrewDriver.TankDriverAmount} Tank Driver(s) got out", this); } if (UnityEngine.Random.Range(0f, 1f) <= configData.TankCrewGuards.TankGuardsSpawnChance) { for (int i = 0; i < configData.TankCrewGuards.TankGuardsAmount; i++) { SpawnGuards(KillPosition, configData.TankCrewGuards.TankGuardsHealth,configData.TankCrewGuards.TankGuardsDamageScale); } if (player != null && HasPerm(player, ShowKillMessages_Perm)) Player.Message(player, msg("BradleyGuards"), chaticon); LogToFile("APCKills", $"{DateTime.Now:h:mm:ss tt}] {info.InitiatorPlayer} {configData.TankCrewGuards.TankGuardsAmount} Tank Guard(s) got out", this); } if (UnityEngine.Random.Range(0f, 1f) <= configData.TankCrewGunner.TankGunnersSpawnChance) { for (int i = 0; i < configData.TankCrewGunner.TankGunnersAmount; i++) { SpawnGunner(KillPosition,configData.TankCrewGunner.TankGunnersHealth,configData.TankCrewGunner.TankGunnersDamageScale); } if (player != null && HasPerm(player, ShowKillMessages_Perm)) Player.Message(player, msg("BradleyGunner"), chaticon); LogToFile("APCKills", $"{DateTime.Now:h:mm:ss tt}] {info.InitiatorPlayer} {configData.TankCrewGunner.TankGunnersAmount} Tank Gunner(s) got out", this); } Vector3 TargetLocation = bradley.transform.position; Puts($"{info.InitiatorPlayer} Killed the BradleyApc in grid {GetGrid(TargetLocation)} starting the MiniGame "); if (configData.Event.LastDitchEffortHardMode) TargetLocation = player.transform.position; LastDitchEffort(TargetLocation); } private void OnEntitySpawned(BaseNetworkable entity) { var corpse = entity as LootableCorpse; if (corpse == null) return; if (_Crew.Contains(corpse.playerSteamID)) { if (configData.Event.CrewBodybags) timer.Once(0.1f, () => { if (BetterNpcNames) corpse.containers[1].Clear();//wipe clothing if (BetterNpcNames) corpse.containers[2].Clear();//wipe beltbar corpse.Kill(); corpse.DropItems(); }); _Crew.Remove(corpse.playerSteamID); } } void OnEntityTakeDamage(BradleyAPC bradley, HitInfo info, MolotovCocktail molly) { BasePlayer player = info.InitiatorPlayer; try { if (info.WeaponPrefab == molly) { info.damageTypes = new DamageTypeList(); info.DoHitEffects = false; return; } if (info == null || !player || BradleyEvents) return; if (!player) return; if (Interface.CallHook("IsTrainBradley", bradley) != null && configData.External.CanTriggerTrain == false) { return; } if (Interface.CallHook("IsConvoyVehicle", bradley) != null && bradley.skinID == 755446 && configData.External.CanTriggerConv == false) { return; } if (Interface.CallHook("CanBradleyTiersEdit", bradley) != null && configData.External.CanTriggerSatdish == false) { return; } if (Interface.CallHook("IsBradleyDrop" , bradley) != null && configData.External.CanTriggerBradleyDrops == false) { return; } if (player.userID.IsSteamId()) { if (UnityEngine.Random.Range(0f, 1f) <= 0.05) { if (configData.Event.GrenadeHardMode) Spawnbombs(player.transform.position); else if (!configData.Event.GrenadeHardMode) Spawnbombs(bradley.transform.position); if (player != null && HasPerm(player, ShowMessages_Perm)) Player.Message(player, msg("BradleyDriverBomb"), chaticon); } if (UnityEngine.Random.Range(0f, 1f) <= 0.05) { if (configData.Event.MolotovHardMode) ThrowMolotov(player.transform.position); else if (!configData.Event.MolotovHardMode) ThrowMolotov(bradley.transform.position); if (player != null && HasPerm(player, ShowMessages_Perm)) Player.Message(player, msg("BradleyGunnerFire"), chaticon); } if (UnityEngine.Random.Range(0f, 1f) <= 0.01) { if (configData.Event.DropSupportNapalmUse) { SpawnSupportNapalm(player.transform.position); if (player != null && HasPerm(player, ShowMessages_Perm)) Player.Message(player, msg("BradleyNapalmSupport"), chaticon); } } return; } } catch { } return; } private void OnFireBallDamage(FireBall fire, global::HumanNPC npc, HitInfo info) { if(info.Initiator is FireBall && fire != null && _Crew.Contains(npc.userID)) { info.damageTypes = new DamageTypeList(); info.DoHitEffects = false; info.damageTypes.ScaleAll(0f); } return; } object OnEntityTakeDamage(global::HumanNPC npc, HitInfo info) { if (!(_Crew.Contains(npc.userID))) return null; BasePlayer player = info.InitiatorPlayer; if (player) { Interface.CallHook("OnBradleyNPCGotHit" , npc, info); } if (info.WeaponPrefab is MLRSRocket) { info.damageTypes = new DamageTypeList(); info.DoHitEffects = false; info.damageTypes.ScaleAll(0f); return true; } return null; } object OnPlayerDeath(global::HumanNPC npc , HitInfo info) { if (!(_Crew.Contains(npc.userID))) return null; BasePlayer player = info.InitiatorPlayer; if (player) { Interface.CallHook("OnBradleyNPCDeath" , npc , info); } return null; } #endregion #region API private object IsBradleyNpc(global::HumanNPC npc) { if (npc == null) return null; if (_Crew.Contains(npc.userID)) return true; return null; } #endregion #region Event Helpers private void RemoveAllNpc() { BradleyCrew[] BradleyCrew = UnityEngine.Object.FindObjectsOfType(); if (BradleyCrew != null) { foreach (BradleyCrew crew in BradleyCrew) UnityEngine.Object.Destroy(crew); } } public static Vector3 CheckPos(Vector3 pos) { pos.y = TerrainMeta.HeightMap.GetHeight(pos); NavMeshHit navMeshHit; if (!NavMesh.SamplePosition(pos, out navMeshHit, 1, 1)) pos = Vector3.zero; else if (WaterLevel.GetWaterDepth(pos, true, false) > 0) pos = Vector3.zero; else if (Physics.RaycastAll(navMeshHit.position + new Vector3(0, 100, 0), Vector3.down, 99f, 1235288065).Any()) pos = Vector3.zero; else pos = new Vector3(navMeshHit.position.x, TerrainMeta.HeightMap.GetHeight(navMeshHit.position), navMeshHit.position.z); return pos; } void SpawnDriver(Vector3 position, float Health , float DamageScale) { var pos = CheckPos(position); if (pos == Vector3.zero) return; int BGSR = configData.Event.CrewSpawnRadius; int x = UnityEngine.Random.Range(-BGSR, BGSR); int z = UnityEngine.Random.Range(-BGSR, BGSR); pos += new Vector3(x, 0, z); global::HumanNPC driver = (global::HumanNPC)GameManager.server.CreateEntity(sci, pos, new Quaternion(), true); driver.Spawn(); NextTick(() => { if (driver == null) return; var mono = driver.gameObject.AddComponent(); mono.SpawnPoint = pos; driver.startHealth = Health;//configData.TankCrewDriver.TankDriverHealth driver.InitializeHealth(Health, Health); driver.displayName = "Bradley Driver"; if (BetterNpcNames != null) driver.displayName = (BetterNpcNames.Call("GiveName",driver , configData.External.DriverTitle, true, true)); driver.damageScale = DamageScale;//configData.TankCrewDriver.TankDriverDamageScale (driver as ScientistNPC).radioChatterType = ScientistNPC.RadioChatterType.NONE; (driver as ScientistNPC).DeathEffects = new GameObjectRef[0]; if (configData.TankCrewDriver.UseOutfit1) { var inv_wear = driver.inventory.containerWear; Item kilt = ItemManager.CreateByName("roadsign.kilt", 1, 2120628865); Item chestplate = ItemManager.CreateByName("metal.plate.torso", 1, 2105505757); Item facemask = ItemManager.CreateByName("metal.facemask", 1, 2120628865); Item hoodie = ItemManager.CreateByName("hoodie", 1, 2080975449); Item gloves = ItemManager.CreateByName("burlap.gloves", 1, 2090790324); Item pants = ItemManager.CreateByName("pants", 1, 2080977144); Item boots = ItemManager.CreateByName("shoes.boots", 1, 2090776132); driver?.inventory?.Strip(); if (kilt != null) kilt.MoveToContainer(inv_wear); if (chestplate != null) chestplate.MoveToContainer(inv_wear); if (facemask != null) facemask.MoveToContainer(inv_wear); if (hoodie != null) hoodie.MoveToContainer(inv_wear); if (gloves != null) gloves.MoveToContainer(inv_wear); if (pants != null) pants.MoveToContainer(inv_wear); if (boots != null) boots.MoveToContainer(inv_wear); } if (configData.TankCrewDriver.UseOutfitG1) { var shortname = configData.TankCrewDriver.UseOutfitGName1; var skin = configData.TankCrewDriver.UseOutfitGSkin1; var inv_belt = driver.inventory.containerBelt; Item weapon = ItemManager.CreateByName(shortname, 1, skin); inv_belt.Clear(); if (weapon != null) weapon.MoveToContainer(inv_belt); } else { var inv_belt = driver.inventory.containerBelt; Item weapon = ItemManager.CreateByName("smg.mp5", 1, 0); inv_belt.Clear(); if (weapon != null) weapon.MoveToContainer(inv_belt); } if (configData.TankCrewDriver.UseKit1) { object checkKit1 = Kits?.CallHook("GetKitInfo", configData.TankCrewDriver.KitName1); if (checkKit1 == null) { PrintWarning($"Kit for Driver ({configData.TankCrewDriver.KitName1}) does not exist - Using a default Scientistsuit."); } else { driver?.inventory?.Strip(); Kits?.Call($"GiveKit", driver, configData.TankCrewDriver.KitName1); } } }); if (driver.IsHeadUnderwater()) { driver.Kill(); return; } if (!driver.IsOutside()) { driver.Kill(); SpawnDriver(pos,Health,DamageScale); return; } _Crew.Add(driver.userID); timer.Once(configData.TankCrewDriver.DriverLife * 60, () => { if (driver != null) { driver.Kill(); _Crew.Remove(driver.userID); //Puts("Driver [" + driver.userID + "] Died of Natural causes!!!"); } }); } void SpawnGuards(Vector3 position, float Health, float DamageScale) { var pos = CheckPos(position); if (pos == Vector3.zero) return; int BGSR = configData.Event.CrewSpawnRadius; int x = UnityEngine.Random.Range(-BGSR, BGSR); int z = UnityEngine.Random.Range(-BGSR, BGSR); pos += new Vector3(x, 0, z); global::HumanNPC Guard = (global::HumanNPC)GameManager.server.CreateEntity(sci, pos, new Quaternion(), true); Guard.Spawn(); NextTick(() => { if (Guard == null) return; var mono = Guard.gameObject.AddComponent(); mono.SpawnPoint = pos; Guard.startHealth = Health; Guard.InitializeHealth(Health, Health); Guard.displayName = "Bradley Guard"; if (BetterNpcNames != null) Guard.displayName = (BetterNpcNames.Call("GiveName", Guard, configData.External.GuardTitle, true, true)); Guard.damageScale = DamageScale; (Guard as ScientistNPC).radioChatterType = ScientistNPC.RadioChatterType.NONE; (Guard as ScientistNPC).DeathEffects = new GameObjectRef[0]; if (configData.TankCrewGuards.UseOutfit2) { var inv_wear = Guard.inventory.containerWear; Item kilt = ItemManager.CreateByName("roadsign.kilt", 1, 1915398061); Item chestplate = ItemManager.CreateByName("metal.plate.torso", 1, 1845931269); Item facemask = ItemManager.CreateByName("metal.facemask", 1, 1845950558); Item hoodie = ItemManager.CreateByName("hoodie", 1, 1883624383); Item gloves = ItemManager.CreateByName("burlap.gloves", 1, 1865178625); Item pants = ItemManager.CreateByName("pants", 1, 1883629284); Item boots = ItemManager.CreateByName("shoes.boots", 1, 1915397286); Guard?.inventory?.Strip(); if (kilt != null) kilt.MoveToContainer(inv_wear); if (chestplate != null) chestplate.MoveToContainer(inv_wear); if (facemask != null) facemask.MoveToContainer(inv_wear); if (hoodie != null) hoodie.MoveToContainer(inv_wear); if (gloves != null) gloves.MoveToContainer(inv_wear); if (pants != null) pants.MoveToContainer(inv_wear); if (boots != null) boots.MoveToContainer(inv_wear); } if (configData.TankCrewGuards.UseOutfitG2) { var shortname = configData.TankCrewGuards.UseOutfitGName2; var skin = configData.TankCrewGuards.UseOutfitGSkin2; var inv_belt = Guard.inventory.containerBelt; Item weapon = ItemManager.CreateByName(shortname, 1, skin); inv_belt.Clear(); if (weapon != null) weapon.MoveToContainer(inv_belt); } else { var inv_belt = Guard.inventory.containerBelt; Item weapon = ItemManager.CreateByName("smg.mp5", 1, 0); inv_belt.Clear(); if (weapon != null) weapon.MoveToContainer(inv_belt); } if (configData.TankCrewGuards.UseKit2) { object checkKit2 = Kits?.CallHook("GetKitInfo", configData.TankCrewGuards.KitName2); if (checkKit2 == null) { Guard?.inventory?.Strip(); var Outfit = ItemManager.CreateByName("scientistsuit_heavy", 1, 0); var inv_belt = Guard.inventory.containerBelt; Item weapon = ItemManager.CreateByName("smg.mp5", 1, 0); Outfit.MoveToContainer(Guard.inventory.containerWear); if (weapon != null) weapon.MoveToContainer(inv_belt); PrintWarning($"Kit for Guards ({configData.TankCrewGuards.KitName2}) does not exist - Using a default Heavy Scientistsuit."); } else { Guard?.inventory?.Strip(); Kits?.Call($"GiveKit", Guard, configData.TankCrewGuards.KitName2); } } if (!configData.TankCrewGuards.UseKit2 && !configData.TankCrewGuards.UseOutfit2) { var Outfit = ItemManager.CreateByName("scientistsuit_heavy", 1, 0); Outfit.MoveToContainer(Guard.inventory.containerWear); } if (Guard.IsHeadUnderwater()) { Guard.Kill(); return; } if (!Guard.IsOutside()) { Guard.Kill(); SpawnGuards(pos,Health, DamageScale); return; } _Crew.Add(Guard.userID); timer.Once(configData.TankCrewGuards.GuardsLife * 60, () => { if (Guard == null) return; Guard.Kill(); _Crew.Remove(Guard.userID); //Puts("Guard [" + Guard.userID + "] Died of Natural causes!!!"); }); }); } void SpawnGunner(Vector3 position, float Health, float DamageScale) { var pos = CheckPos(position); if (pos == Vector3.zero) return; int BGSR = configData.Event.CrewSpawnRadius; int x = UnityEngine.Random.Range(-BGSR, BGSR); int z = UnityEngine.Random.Range(-BGSR, BGSR); pos += new Vector3(x, 0, z); global::HumanNPC Gunner = (global::HumanNPC)GameManager.server.CreateEntity(sci, pos, new Quaternion(), true); Gunner.Spawn(); NextTick(() => { if (Gunner == null) return; var mono = Gunner.gameObject.AddComponent(); mono.SpawnPoint = pos; Gunner.startHealth = Health; Gunner.InitializeHealth(Health, Health); Gunner.displayName = "Bradley Gunner"; if (BetterNpcNames != null) Gunner.displayName = (BetterNpcNames.Call("GiveName", Gunner, configData.External.GunnerTitle, true, true)); Gunner.damageScale = DamageScale; (Gunner as ScientistNPC).radioChatterType = ScientistNPC.RadioChatterType.NONE; (Gunner as ScientistNPC).DeathEffects = new GameObjectRef[0]; if (configData.TankCrewGunner.UseOutfit3) { var inv_wear = Gunner.inventory.containerWear; Item kilt = ItemManager.CreateByName("roadsign.kilt", 1, 1915398061); Item chestplate = ItemManager.CreateByName("roadsign.jacket", 1, 933378476); Item facemask = ItemManager.CreateByName("metal.facemask", 1, 1338484467); Item shirt = ItemManager.CreateByName("tshirt", 1, 835273273); Item gloves = ItemManager.CreateByName("burlap.gloves", 1, 1101282019); Item pants = ItemManager.CreateByName("pants", 1, 1385326314); Item boots = ItemManager.CreateByName("shoes.boots", 1, 1915397286); Gunner?.inventory?.Strip(); if (kilt != null) kilt.MoveToContainer(inv_wear); if (chestplate != null) chestplate.MoveToContainer(inv_wear); if (facemask != null) facemask.MoveToContainer(inv_wear); if (shirt != null) shirt.MoveToContainer(inv_wear); if (gloves != null) gloves.MoveToContainer(inv_wear); if (pants != null) pants.MoveToContainer(inv_wear); if (boots != null) boots.MoveToContainer(inv_wear); } if (configData.TankCrewGunner.UseOutfitG3) { var shortname = configData.TankCrewGunner.UseOutfitGName3; var skin = configData.TankCrewGunner.UseOutfitGSkin3; var inv_belt = Gunner.inventory.containerBelt; Item weapon = ItemManager.CreateByName(shortname, 1, skin); inv_belt.Clear(); if (weapon != null) weapon.MoveToContainer(inv_belt); } else { var inv_belt = Gunner.inventory.containerBelt; Item weapon = ItemManager.CreateByName("smg.mp5", 1, 0); inv_belt.Clear(); if (weapon != null) weapon.MoveToContainer(inv_belt); } if (configData.TankCrewGunner.UseKit3) { object checkKit3 = Kits?.CallHook("GetKitInfo", configData.TankCrewGunner.KitName3); if (checkKit3 == null) { PrintWarning($"Kit for Gunner ({configData.TankCrewGunner.KitName3}) does not exist - Using a default Scientistsuit."); } else { Gunner?.inventory?.Strip(); Kits?.Call($"GiveKit", Gunner, configData.TankCrewGunner.KitName3); } } if (Gunner.IsHeadUnderwater()) { Gunner.Kill(); return; } if (!Gunner.IsOutside()) { Gunner.Kill(); SpawnGunner(pos, Health, DamageScale); return; } _Crew.Add(Gunner.userID); timer.Once(configData.TankCrewGunner.GunnersLife * 60, () => { if (Gunner != null) { Gunner.Kill(); _Crew.Remove(Gunner.userID); //Puts("Gunner [" + Gunner.userID + "] Died of Natural causes!!!"); } }); }); } private void LastDitchEffort(Vector3 pos) { float NapalmRange = configData.Event.DropSupportNapalmRange; BaseEntity Fire1 = GameManager.server.CreateEntity(molotov , pos + new Vector3(0 , 2 , 0) , new Quaternion() , true); Fire1.Spawn(); for (int ng = 0; ng < configData.Event.LastDitchEffortGrenadeAmount; ng++) { BaseEntity Fire2 = GameManager.server.CreateEntity(bomb1, pos + new Vector3(UnityEngine.Random.Range(-15f, 15f), 1, UnityEngine.Random.Range(-15f, 15f)), new Quaternion(), true); Fire2.creatorEntity = Fire2; Fire2.skinID = 29051978; Fire2.Spawn(); } if (configData.Event.UseFireRockets == true) { for (int n = 0; n < configData.Event.LastDitchEffortNapalmAmount; n++) { BaseEntity SupportNapalm = GameManager.server.CreateEntity(rocketfire , pos + new Vector3(UnityEngine.Random.Range(-(NapalmRange) , (NapalmRange)) , 50 , UnityEngine.Random.Range(-(NapalmRange) , (NapalmRange))) , new Quaternion() , true); SupportNapalm.creatorEntity = SupportNapalm; SupportNapalm.skinID = 29051978; SupportNapalm.Spawn(); } } if (configData.Event.UseFireRockets == false) { for (int n = 0; n < configData.Event.LastDitchEffortNapalmAmount; n++) { BaseEntity SupportNapalm = GameManager.server.CreateEntity(molotov , pos + new Vector3(UnityEngine.Random.Range(-(NapalmRange) , (NapalmRange)) , 50 , UnityEngine.Random.Range(-(NapalmRange) , (NapalmRange))) , new Quaternion() , true); SupportNapalm.creatorEntity = SupportNapalm; SupportNapalm.skinID = 29051978; SupportNapalm.Spawn(); } } int MLRSAmount = configData.Event.LastDitchEffortMLRSAmount; if (MLRSAmount == 0) return; NapalmRange = configData.Event.LastDitchEffortMLRSRadius; timer.Repeat(1.8f, MLRSAmount, () => { BaseEntity SupportMLRS = GameManager.server.CreateEntity(MLRS, pos + new Vector3(UnityEngine.Random.Range(-(NapalmRange), (NapalmRange)), 450, UnityEngine.Random.Range(-(NapalmRange), (NapalmRange))), new Quaternion(), true); SupportMLRS.creatorEntity = SupportMLRS; SupportMLRS.skinID = 29051978; SupportMLRS.Spawn(); }); } private object CanEntityTakeDamage(BasePlayer player, HitInfo info) { if (info == null || info.Initiator == null || player == null || _Crew.Contains(player.userID)) return null; if (info.Initiator.skinID == 29051978) return true; return null; } private void Spawnbombs(Vector3 pos) { float NadeRange = configData.Event.MaxThrowingRangeOfAGrenade; float NadeRangeHM = configData.Event.MaxThrowingRangeOfAGrenadeHM; if (configData.Event.GrenadeHardMode == false) { for (int b = 0; b < configData.Event.GrenadeAmount; b++) { BaseEntity Bomb = GameManager.server.CreateEntity(bomb2, pos + new Vector3(UnityEngine.Random.Range(-(NadeRange), (NadeRange)), 1, UnityEngine.Random.Range(-(NadeRange), (NadeRange))), new Quaternion(), true); Bomb.Spawn(); } } else if (configData.Event.GrenadeHardMode == true) { for (int b = 0; b < configData.Event.GrenadeAmountHM; b++) { BaseEntity Bomb = GameManager.server.CreateEntity(bomb2, pos + new Vector3(UnityEngine.Random.Range(-(NadeRangeHM), (NadeRangeHM)), 5, UnityEngine.Random.Range(-(NadeRangeHM), (NadeRangeHM))), new Quaternion(), true); Bomb.Spawn(); } } } private void ThrowMolotov(Vector3 pos) { float MLTVRange = configData.Event.MaxThrowingRangeOfAMolotov; float MLTVRangeHM = configData.Event.MaxThrowingRangeOfAMolotovHM; if (configData.Event.GrenadeHardMode == false) { for (int b = 0; b < configData.Event.GrenadeAmount; b++) { BaseEntity Fire = GameManager.server.CreateEntity(molotov, pos + new Vector3(UnityEngine.Random.Range(-(MLTVRange), (MLTVRange)), 5 , UnityEngine.Random.Range(-(MLTVRange), (MLTVRange))), new Quaternion(), true); Fire.Spawn(); } } else if (configData.Event.MolotovHardMode == true) { for (int b = 0; b < configData.Event.GrenadeAmountHM; b++) { BaseEntity Fire = GameManager.server.CreateEntity(molotov, pos + new Vector3(UnityEngine.Random.Range(-(MLTVRangeHM), (MLTVRangeHM)), 2, UnityEngine.Random.Range(-(MLTVRangeHM), (MLTVRangeHM))), new Quaternion(), true); Fire.Spawn(); } } } private void SpawnSupportNapalm(Vector3 pos) { float SPRTRange = configData.Event.DropSupportNapalmRange; if (configData.Event.UseFireRockets == true) { for (int n = 0; n < configData.Event.DropSupportNapalmAmount; n++) { BaseEntity SupportNapalm = GameManager.server.CreateEntity(rocketfire , pos + new Vector3(UnityEngine.Random.Range(-(SPRTRange) , (SPRTRange)) , 50 , UnityEngine.Random.Range(-(SPRTRange) , (SPRTRange))) , new Quaternion() , true); SupportNapalm.Spawn(); } return; } for (int n = 0; n < configData.Event.DropSupportNapalmAmount; n++) { BaseEntity SupportNapalm = GameManager.server.CreateEntity(molotov , pos + new Vector3(UnityEngine.Random.Range(-(SPRTRange) , (SPRTRange)) , (SPRTRange) , UnityEngine.Random.Range(-(SPRTRange) , (SPRTRange))) , new Quaternion() , true); SupportNapalm.Spawn(); } } public Vector3 GetNavPoint(Vector3 position) { NavMeshHit hit; if (!NavMesh.SamplePosition(position, out hit, 5, -1)) { return position; } else if (Physics.RaycastAll(hit.position + new Vector3(0, 100, 0), Vector3.down, 99f, 1235288065).Any()) { return position; } else if (hit.position.y < TerrainMeta.WaterMap.GetHeight(hit.position)) { return position; } position = hit.position; return position; } #endregion #region Message Helper private string msg(string key, string id = null) => prefix + lang.GetMessage(key, this, id); bool HasPerm(BasePlayer player, string perm) { return permission.UserHasPermission(player.UserIDString, perm); }//Check for permission private static string GetGrid(Vector3 position) => MapHelper.PositionToString(position); #endregion } }