C#:
using System;
using System.Linq;
using System.Reflection;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Plugins;
using Rust;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("BradleyOptions" , "Krungh Crow" , "2.3.4" , ResourceId = 157)]
[Description("Bradley Reworked Configurations")]
class BradleyOptions : RustPlugin
{
[PluginReference] Plugin ArmoredTrain, BradleyGuards, BradleyTiers, Convoy, Paratroopers;
#region Variables
Dictionary<string , CooldownTimer> CoolDowns = new Dictionary<string , CooldownTimer>();
const ulong chaticon = 76561199090290915;
const string Admin_Perm = "bradleyoptions.Admin";
const string prefix = "<color=yellow>[Bradley Options]</color> ";
const string MLRS = "assets/content/vehicles/mlrs/rocket_mlrs.prefab";
const string MLRSFX = "assets/content/vehicles/mlrs/effects/pfx_mlrs_rocket_explosion_ground.prefab";
private bool IsBradleyGuardsB;
private bool IsBradleyGuardsK;
private static readonly FieldInfo TooHotUntilField = FindField(typeof(HelicopterDebris) , "tooHotUntil");
public class CooldownTimer
{
public Timer timer;
public float start;
public float countdown;
}
#endregion
#region Configuration
void Init()
{
if (!LoadConfigVariables())
{
Puts("Config file issue detected. Please delete file, or check syntax and fix.");
return;
}
permission.RegisterPermission(Admin_Perm , this);
}
private ConfigData configData;
class ConfigData
{
[JsonProperty(PropertyName = "Bonus")]
public BonusSettings Bonus = new BonusSettings();
[JsonProperty(PropertyName = "Spawn settings")]
public SettingsSpawn Spawn = new SettingsSpawn();
[JsonProperty(PropertyName = "Cooldowns")]
public SettingsCooldown CooldownChecks = new SettingsCooldown();
[JsonProperty(PropertyName = "Avoid BradleyOptions override settings for other plugins")]
public SettingsPluginchecks PluginChecks = new SettingsPluginchecks();
[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();
}
class BonusSettings
{
[JsonProperty(PropertyName = "Realistic explosion when Bradley is killed")]
public bool RealExplo = true;
}
class SettingsCooldown
{
[JsonProperty(PropertyName = "use cooldown between Bradley Kills")]
public bool CooldownUse = false;
[JsonProperty(PropertyName = "Show Gametip on bradleycooldown command")]
public bool CooldownTipUse = true;
[JsonProperty(PropertyName = "cooldown between Bradley kills (minutes)")]
public int Cooldown = 120;
}
class SettingsSpawn
{
[JsonProperty(PropertyName = "Enable Launchsite respawn")]
public bool EnableLaunchsiteRespawn = false;
[JsonProperty(PropertyName = "Launchsite min respawn time (minutes)")]
public float LaunchsiteMinRespawn = 5.0f;
[JsonProperty(PropertyName = "Launchsite max respawn time (minutes)")]
public float LaunchsiteMaxRespawn = 5.0f;
[JsonProperty(PropertyName = "Enable Custom Map respawn")]
public bool EnableCustomRespawn = false;
[JsonProperty(PropertyName = "Custom Map respawn check (minutes)")]
public float CustomRespawnTimer = 15.0f;
}
class SettingsPluginchecks
{
[JsonProperty(PropertyName = "Using Only BradleyOptions")]
public bool BOCF = true;
[JsonProperty(PropertyName = "Using BradleyGuards/ParaTroopers (Umod)")]
public bool BGU = false;
[JsonProperty(PropertyName = "Using BradleyGuards (Codefling)")]
public bool BGCF = false;
}
class SettingsSpawnchecksVanilla
{
[JsonProperty(PropertyName = "Respawn Use (Launchsite Bradley ,use only when spawn checks are disabled)")]
public bool respawnvanillalaunch = false;
[JsonProperty(PropertyName = "Min respawn time (minutes)")]
public float respawntimelaunchmin = 5.0f;
[JsonProperty(PropertyName = "Max respawn time (minutes)")]
public float respawntimelaunchmax = 5.0f;
}
class SettingsBradleyLoot
{
[JsonProperty(PropertyName = "Max crates after kill")]
public int BradleyMaxCratesAfterKill = 4;
[JsonProperty(PropertyName = "Remove Napalm")]
public bool Instantfire = false;
[JsonProperty(PropertyName = "Remove Gibs")]
public bool KillGibs = false;
[JsonProperty(PropertyName = "Instantly unlock crates")]
public bool InstantUnlock = false;
[JsonProperty(PropertyName = "Instantly unlock Gibs")]
public bool InstantUnlockGibs = false;
}
class SettingsBradley
{
[JsonProperty(PropertyName = "Enabled (will not spawn when false)")]
public bool BradleyEnabled = true;
[JsonProperty(PropertyName = "Change Health (If only using BradleyOptions)")]
public bool BradleyHealthChange = true;
[JsonProperty(PropertyName = "Health")]
public int BradleyHealth = 2000;
[JsonProperty(PropertyName = "Max Fire Range")]
public int BradleyMaxFireRange = 100;
[JsonProperty(PropertyName = "Throttle Responce")]
public float BradleyThrotle = 1.0f;
[JsonProperty(PropertyName = "Hostile timer")]
public float BradleyMemory = 20.0f;
[JsonProperty(PropertyName = "Ignores sleepers")]
public bool sleepersafe = true;
[JsonProperty(PropertyName = "Ignores admins")]
public bool adminsafe = false;
}
class SettingsBradleyCanon
{
[JsonProperty(PropertyName = "Canon Fire delay")]
public float BradleyCanonFireDelay = 0.3f;
[JsonProperty(PropertyName = "Canon Firerate")]
public float BradleyCanonFireRate = 0.25f;
}
class SettingsBradleyMachinegun
{
[JsonProperty(PropertyName = "Machinegun Bullet Damage")]
public int BradleyMachinegunBulletDamage = 15;
[JsonProperty(PropertyName = "Machinegun Firerate")]
public float BradleyMachinegunFirerate = 0.06667f;
[JsonProperty(PropertyName = "Machinegun Burst Duration")]
public int BradleyMachinegunBurstDuration = 10;
}
private bool LoadConfigVariables()
{
try
{
configData = Config.ReadObject<ConfigData>();
}
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<string , string>
{
["CooldownMsg"] = "You have <color=green>{0}</color> minute(s) cooldown left and have to wait to take on the Bradley again!!" ,
["CooldownTip"] = "You have {0} minute(s) left to take on the Bradley again!!" ,
["CooldownEnded"] = "Your Cooldown ended you can take on the Bradley again!!" ,
["InvalidInput"] = "<color=red>Please enter a valid command!</color>" ,
["Prefix"] = "<color=yellow>[Bradley Options]</color> " ,
["Version"] = "\nVersion : V" ,
["Info"] = "\n<color=green>Available Commands</color>\n<color=green>/bradley info</color> : Shows info on version/author and commands" ,
["InfoRespawn"] = "\n<color=green>/bradley quickrespawn</color> : Respawns the Launchsite bradley." ,
["InfoRespawnCustom"] = "\n<color=green>/bradley custom</color> : Respawns custom bradleys <color=purple>[RustEdit]</color>." ,
["RespawnAll"] = "<color=green>Respawned all Bradleys on custom locations</color> [RustEdit]" ,
["RespawnLaunch"] = "<color=green>Respawned The Bradley on Launchsite" ,
["NoPermission"] = "<color=green>You do not have permission to use that command!</color>" ,
} , this);
}
#endregion
#region Commands
[ChatCommand("bradleycooldown")]
private void cmdBradleycooldown(BasePlayer player , string command , string[] args)
{
string prefix = lang.GetMessage("Prefix" , this);
{
if (CoolDowns.ContainsKey(player.UserIDString))
{
string timesince = Math.Floor((CoolDowns[player.UserIDString].start + CoolDowns[player.UserIDString].countdown - Time.realtimeSinceStartup) / 60).ToString();
if (configData.CooldownChecks.CooldownTipUse == false)
{
Player.Message(player , prefix + string.Format(msg($"CooldownMsg" , player.UserIDString) , timesince) , chaticon);
return;
}
else
{
TIP(player , msg($"You have {timesince} minute(s) left to take on the Bradley again!!") , 20f);
return;
}
return;
}
else
{
if (configData.CooldownChecks.CooldownTipUse == false)
{
Player.Message(player , prefix + string.Format(msg("CooldownEnded" , player.UserIDString)) , chaticon);
return;
}
else
{
TIP(player , msg("CooldownEnded") , 20f);
return;
}
return;
}
}
}
[ChatCommand("bradley")]
private void cmdBradley(BasePlayer player , string command , string[] args)
{
if (!permission.UserHasPermission(player.UserIDString , Admin_Perm))
{
Player.Message(player , prefix + string.Format(msg("NoPermission" , player.UserIDString)) , chaticon);
return;
}
if (args.Length == 0)
{
Player.Message(player , prefix + string.Format(msg("InvalidInput" , player.UserIDString)) , chaticon);
}
else
{
if (args[0].ToLower() == "info")
{
Player.Message(player , prefix + string.Format(msg("Version" , player.UserIDString)) + this.Version.ToString() + " By : " + this.Author.ToString()
+ msg("Info")
+ msg("InfoRespawn")
+ msg("InfoRespawnCustom")
+ msg("\n\n<color=green>BradleyAPC's</color> : <color=purple>") + BaseNetworkable.serverEntities.OfType<BradleyAPC>().Count().ToString() + msg("</color> ")
, chaticon);
}
if (args[0].ToLower() == "custom")
{
string prefix = lang.GetMessage("Prefix" , this);
if (permission.UserHasPermission(player.UserIDString , Admin_Perm))
{
this.Server.Command("rustedit.apc.respawn");
{
Player.Message(player , prefix + string.Format(msg("RespawnAll" , player.UserIDString))
+ msg(" <color=green>BradleyAPC's in Total </color> : <color=purple>") + BaseNetworkable.serverEntities.OfType<BradleyAPC>().Count().ToString() + msg("</color> ")
, chaticon);
}
}
else
{
Player.Message(player , prefix + string.Format(msg("NoPermission" , player.UserIDString)) , chaticon);
}
}
if (args[0].ToLower() == "quickrespawn")
{
string prefix = lang.GetMessage("Prefix" , this);
if (permission.UserHasPermission(player.UserIDString , Admin_Perm))
{
BradleySpawner bradleySpawner = BradleySpawner.singleton;
if (bradleySpawner == null)
{
Debug.LogWarning("No Spawner");
return;
}
if (bradleySpawner.spawned) return;
{
Puts("A bradley spawned succesfully at launchsite!");
}
bradleySpawner.spawned = null;
bradleySpawner.DoRespawn();
Player.Message(player , prefix + string.Format(msg("RespawnLaunch" , player.UserIDString))
+ msg(" <color=green>BradleyAPC's in Total </color> : <color=purple>") + BaseNetworkable.serverEntities.OfType<BradleyAPC>().Count().ToString() + msg("</color> ")
, chaticon);
}
else
{
Player.Message(player , prefix + string.Format(msg("NoPermission" , player.UserIDString)) , chaticon);
}
}
}
}
#endregion
#region Oxide Hooks
void OnServerInitialized()
{
IsBradleyGuardsB = BradleyGuards != null && BradleyGuards.Author.Contains("Bazz3l");
IsBradleyGuardsK = BradleyGuards != null && BradleyGuards.Author.Contains("Krungh");
timer.Once(3f , () =>
{
if (BradleyTiers)
{
Puts("BradleyTiers installed skipping HP and Crate amount settings!");
}
});
if (configData.Spawn.EnableLaunchsiteRespawn)
{
BradleySpawner.singleton.minRespawnTimeMinutes = configData.Spawn.LaunchsiteMinRespawn;
BradleySpawner.singleton.maxRespawnTimeMinutes = configData.Spawn.LaunchsiteMaxRespawn;
}
if (configData.Spawn.EnableCustomRespawn)
{
timer.Every(configData.Spawn.CustomRespawnTimer * 60 , () =>
{
this.Server.Command("rustedit.apc.respawn");
Puts("A bradley spawn check for custom locations (rustedit) !");
});
}
}
private void OnBradleyApcInitialize(BradleyAPC bradley)
{
if (bradley == null) return;
if (Interface.CallHook("IsTrainBradley" , bradley) != null) return;
if (Interface.CallHook("IsConvoyVehicle" , bradley) != null) return;
if (Interface.CallHook("CanBradleyTiersEdit" , bradley) != null) return;
if (Interface.CallHook("CanBradleyOptionsEdit" , bradley) != null) return;
if (configData.PluginChecks.BOCF)
{
if (configData.Bradley.BradleyHealthChange && (!IsBradleyGuardsK || !IsBradleyGuardsB || !BradleyTiers))
{
bradley._maxHealth = configData.Bradley.BradleyHealth;
bradley.health = bradley._maxHealth;
}
bradley.throttle = configData.Bradley.BradleyThrotle;
bradley.leftThrottle = bradley.throttle;
bradley.rightThrottle = bradley.throttle;
if (!BradleyTiers || !IsBradleyGuardsK || !IsBradleyGuardsK || !Convoy || !ArmoredTrain)
{
bradley.maxCratesToSpawn = configData.BradleyLoot.BradleyMaxCratesAfterKill;
}
bradley.viewDistance = configData.Bradley.BradleyMaxFireRange;
bradley.searchRange = configData.Bradley.BradleyMaxFireRange;
bradley.bulletDamage = configData.BradleyMachineGun.BradleyMachinegunBulletDamage;
bradley.coaxFireRate = configData.BradleyMachineGun.BradleyMachinegunFirerate;
bradley.coaxBurstLength = configData.BradleyMachineGun.BradleyMachinegunBurstDuration;
bradley.topTurretFireRate = configData.BradleyCanon.BradleyCanonFireRate;
bradley.nextTopTurretTime = configData.BradleyCanon.BradleyCanonFireDelay;
bradley.memoryDuration = configData.Bradley.BradleyMemory;
bradley.SendNetworkUpdate();
}
if (IsBradleyGuardsK && configData.PluginChecks.BGCF)
{
bradley.memoryDuration = configData.Bradley.BradleyMemory;
bradley.coaxBurstLength = configData.BradleyMachineGun.BradleyMachinegunBurstDuration;
}
if (configData.PluginChecks.BGU && (!IsBradleyGuardsB || !Paratroopers))
{
bradley.throttle = configData.Bradley.BradleyThrotle;
bradley.leftThrottle = bradley.throttle;
bradley.rightThrottle = bradley.throttle;
bradley.viewDistance = configData.Bradley.BradleyMaxFireRange;
bradley.searchRange = configData.Bradley.BradleyMaxFireRange;
bradley.bulletDamage = configData.BradleyMachineGun.BradleyMachinegunBulletDamage;
bradley.coaxFireRate = configData.BradleyMachineGun.BradleyMachinegunFirerate;
bradley.coaxBurstLength = configData.BradleyMachineGun.BradleyMachinegunBurstDuration;
bradley.topTurretFireRate = configData.BradleyCanon.BradleyCanonFireRate;
bradley.nextTopTurretTime = configData.BradleyCanon.BradleyCanonFireDelay;
bradley.memoryDuration = configData.Bradley.BradleyMemory;
}
if (bradley.health <= 100)
{
bradley._maxHealth = configData.Bradley.BradleyHealth;
bradley.health = bradley._maxHealth;
bradley.SendNetworkUpdate();
Puts($"Updated the HP to {bradley.health}/{bradley.health}");
}
bradley.SendNetworkUpdate();
if (!configData.Bradley.BradleyEnabled)
{
Puts($"Spawning disabled in cfg destroyed the APC!");
bradley.Kill();
return;
}
}
private object CanBradleyApcTarget(BradleyAPC bradley , BaseEntity target)
{
if (bradley == null || target == null)
return null;
BasePlayer player = target as BasePlayer;
if (target is NPCPlayer || target is global::HumanNPC)
return false;
if (player == null || !player.userID.IsSteamId())
return false;
object result = Interface.CallHook("BradleyOptions_CanTarget" , bradley , target);
if (result != null)
return result;
if (Interface.CallHook("IsTrainBradley" , bradley) != null) return null;
if (Interface.CallHook("IsConvoyVehicle" , bradley) != null) return null;
if (Interface.CallHook("CanBradleyTiersEdit" , bradley) != null) return null;
Vector3 turretPos = bradley.mainTurret?.transform?.position ?? bradley.transform.position;
if (!(player.IsVisible(turretPos , bradley.CenterPoint()) ||
player.IsVisible(turretPos , player.eyes.position) ||
player.IsVisible(turretPos , player.transform.position)))
{
return false;
}
if (configData.Bradley.sleepersafe && player.IsSleeping())
return false;
if (configData.Bradley.adminsafe && player.IsAdmin)
return false;
return null;
}
void OnEntityTakeDamage(BradleyAPC bradley , HitInfo info)
{
try
{
BasePlayer player = info.InitiatorPlayer;
if (Interface.CallHook("IsTrainBradley" , bradley) != null) return;
if (Interface.CallHook("IsConvoyVehicle" , bradley) != null) return;
if (Interface.CallHook("CanBradleyTiersEdit" , bradley) != null) return;
if (configData.CooldownChecks.CooldownUse == true)
{
if (player != null)
{
if (CoolDowns.ContainsKey(player.UserIDString))
{
string prefix = lang.GetMessage("Prefix" , this);
string timesince = Math.Floor((CoolDowns[player.UserIDString].start + CoolDowns[player.UserIDString].countdown - Time.realtimeSinceStartup) / 60).ToString();
Player.Message(player , prefix + string.Format(msg($"CooldownMsg" , player.UserIDString) , timesince) , chaticon);
info.damageTypes.ScaleAll(0);
return;
}
}
return;
}
}
catch { }
return;
}
private void OnEntitySpawned(FireBall fireball)
{
List<BaseEntity> gibs = new List<BaseEntity>();
Vis.Entities<BaseEntity>(fireball.transform.position , 1f , gibs);
if (fireball is MolotovCocktail) return;
foreach (var gib in gibs)
{
if (gib == null || gib.name == null)
continue;
if (gib.name.Contains("servergibs_bradley"))
{
NextTick(() =>
{
try
{
if (!fireball.IsDestroyed && configData.BradleyLoot.Instantfire)
fireball.Kill();
}
catch
{
}
});
}
}
}
private void OnEntitySpawned(HelicopterDebris debris)
{
if (debris.name.Contains("servergibs_bradley") && configData.BradleyLoot.InstantUnlockGibs == true)
{
if (debris == null || debris.name == null) return;
NextTick(() =>
{
SetDebrisCool(debris);
debris.SendNetworkUpdate();
if (configData.BradleyLoot.KillGibs)
{
debris.Kill();
}
return;
});
return;
}
return;
}
private void OnEntityDeath(BradleyAPC apc , HitInfo info)
{
if (Interface.CallHook("IsTrainBradley" , apc) != null) return;
if (Interface.CallHook("IsConvoyVehicle" , apc) != null) return;
if (Interface.CallHook("CanBradleyTiersEdit" , apc) != null) return;
var pos = apc.transform.position;
if (configData.Bonus.RealExplo)
{
timer.Once(0.5f , () =>
{
BaseEntity RealisticExplosion = GameManager.server.CreateEntity(MLRS , pos + new Vector3(0 , 1 , 0) , new Quaternion() , true);
RealisticExplosion.Spawn();
});
}
BasePlayer player = info.InitiatorPlayer;
if (!player)
{
return;
}
if (!CoolDowns.ContainsKey(player.UserIDString))
{
string id = player.UserIDString;
var Cooldown = new CooldownTimer();
Cooldown.timer = timer.Once((float)configData.CooldownChecks.Cooldown * 60 , () =>
{
CoolDowns.Remove(id);
string prefix = lang.GetMessage("Prefix" , this);
if (player != null) Player.Message(player , prefix + string.Format(msg("CooldownEnded" , player.UserIDString)) , chaticon);
});
Cooldown.start = Time.realtimeSinceStartup;
Cooldown.countdown = configData.CooldownChecks.Cooldown * 60;
CoolDowns.Add(id , Cooldown);
}
if (configData.CooldownChecks.CooldownUse == true)
{
string prefix = lang.GetMessage("Prefix" , this);
Player.Message(player , prefix + string.Format(msg("You now have <color=red>" , player.UserIDString)) + configData.CooldownChecks.Cooldown + msg("</color> minutes Cooldown till you can attack again!!") , chaticon);
}
if (configData.BradleyLoot.InstantUnlock)
{
NextTick(() => UnlockTheCrates(pos));
}
return;
}
#endregion
#region helpers
private string msg(string key , string id = null) => lang.GetMessage(key , this , id);
private static FieldInfo FindField(Type type , string fieldName)
{
while (type != null)
{
FieldInfo field = type.GetField(fieldName ,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
if (field != null)
return field;
type = type.BaseType;
}
return null;
}
private void SetDebrisCool(HelicopterDebris debris)
{
if (debris == null || debris.IsDestroyed)
return;
if (TooHotUntilField == null)
{
PrintWarning("HelicopterDebris.tooHotUntil could not be found; instant gib cooling is unavailable on this Rust build.");
return;
}
TooHotUntilField.SetValue(debris , -1f);
}
private void UnlockTheCrates(Vector3 pos)
{
List<LockedByEntCrate> crates = new List<LockedByEntCrate>();
Vis.Entities(pos , 30f , crates);
foreach (var crate in crates)
{
crate.SetLocked(false);
}
}
void TIP(BasePlayer player , string message , float dur)
{
if (player == null) return;
player.SendConsoleCommand("gametip.showgametip" , message);
timer.Once(dur , () => player?.SendConsoleCommand("gametip.hidegametip"));
}
#endregion
#region API
object CanBradleyOptionsEdit(BradleyAPC bradley)
{
return null;
}
#endregion
}
}